X11: Add support for custom window icon

This commit is contained in:
Ben Blank
2023-07-15 22:24:27 -07:00
parent 5d3ba9d35e
commit b1f557d98b
3 changed files with 57 additions and 32 deletions

View File

@@ -56,8 +56,10 @@ from .utils import (
cleanup_ssh_control_masters, cleanup_ssh_control_masters,
detach, detach,
expandvars, expandvars,
get_custom_window_icon,
log_error, log_error,
parse_os_window_state, parse_os_window_state,
safe_mtime,
single_instance, single_instance,
startup_notification_handler, startup_notification_handler,
unix_socket_paths, unix_socket_paths,
@@ -170,40 +172,43 @@ def get_macos_shortcut_for(
return ans return ans
def safe_mtime(path: str) -> Optional[float]:
with suppress(OSError):
return os.path.getmtime(path)
return None
def set_macos_app_custom_icon() -> None: def set_macos_app_custom_icon() -> None:
for name in ('kitty.app.icns', 'kitty.app.png'): custom_icon_mtime, custom_icon_path = get_custom_window_icon()
icon_path = os.path.join(config_dir, name) if custom_icon_mtime is not None and custom_icon_path is not None:
custom_icon_mtime = safe_mtime(icon_path) from .fast_data_types import cocoa_set_app_icon, cocoa_set_dock_icon
if custom_icon_mtime is not None: krd = getattr(sys, 'kitty_run_data')
from .fast_data_types import cocoa_set_app_icon, cocoa_set_dock_icon bundle_path = os.path.dirname(os.path.dirname(krd.get('bundle_exe_dir')))
krd = getattr(sys, 'kitty_run_data') icon_sentinel = os.path.join(bundle_path, 'Icon\r')
bundle_path = os.path.dirname(os.path.dirname(krd.get('bundle_exe_dir'))) sentinel_mtime = safe_mtime(icon_sentinel)
icon_sentinel = os.path.join(bundle_path, 'Icon\r') if sentinel_mtime is None or sentinel_mtime < custom_icon_mtime:
sentinel_mtime = safe_mtime(icon_sentinel) try:
if sentinel_mtime is None or sentinel_mtime < custom_icon_mtime: cocoa_set_app_icon(custom_icon_path, bundle_path)
try: except (FileNotFoundError, OSError) as e:
cocoa_set_app_icon(icon_path, bundle_path) log_error(str(e))
except (FileNotFoundError, OSError) as e: log_error('Failed to set custom app icon, ignoring')
log_error(str(e)) # macOS Dock does not reload icons until it is restarted, so we set
log_error('Failed to set custom app icon, ignoring') # the application icon here. This will revert when kitty quits, but
# macOS Dock does not reload icons until it is restarted, so we set # can't be helped since there appears to be no way to get the dock
# the application icon here. This will revert when kitty quits, but # to reload short of killing it.
# can't be helped since there appears to be no way to get the dock cocoa_set_dock_icon(custom_icon_path)
# to reload short of killing it.
cocoa_set_dock_icon(icon_path)
break def get_icon128_path(base_path: str) -> str:
# max icon size on X11 64bits is 128x128
path, ext = os.path.splitext(base_path)
return f'{path}-128{ext}'
def set_x11_window_icon() -> None: def set_x11_window_icon() -> None:
# max icon size on X11 64bits is 128x128 custom_icon_path = get_custom_window_icon()[1]
path, ext = os.path.splitext(logo_png_file) if custom_icon_path is not None:
set_default_window_icon(f'{path}-128{ext}') custom_icon128_path = get_icon128_path(custom_icon_path)
if safe_mtime(custom_icon128_path) is None:
set_default_window_icon(custom_icon_path)
else:
set_default_window_icon(custom_icon128_path)
else:
set_default_window_icon(get_icon128_path(logo_png_file))
def _run_app(opts: Options, args: CLIOptions, bad_lines: Sequence[BadLine] = ()) -> None: def _run_app(opts: Options, args: CLIOptions, bad_lines: Sequence[BadLine] = ()) -> None:

View File

@@ -10,7 +10,7 @@ from typing import Callable, Dict, Optional
from .constants import is_macos, logo_png_file from .constants import is_macos, logo_png_file
from .fast_data_types import get_boss from .fast_data_types import get_boss
from .types import run_once from .types import run_once
from .utils import log_error from .utils import get_custom_window_icon, log_error
NotifyImplementation = Callable[[str, str, str], None] NotifyImplementation = Callable[[str, str, str], None]
@@ -57,7 +57,7 @@ else:
) -> None: ) -> None:
icf = '' icf = ''
if icon is True: if icon is True:
icf = logo_png_file icf = get_custom_window_icon()[1] or logo_png_file
alloc_id = dbus_send_notification(application, icf, title, body, 'Click to see changes', timeout) alloc_id = dbus_send_notification(application, icf, title, body, 'Click to see changes', timeout)
if alloc_id and identifier is not None: if alloc_id and identifier is not None:
alloc_map[alloc_id] = identifier alloc_map[alloc_id] = identifier

View File

@@ -1183,3 +1183,23 @@ def cmdline_for_hold(cmd: Sequence[str] = (), opts: Optional['Options'] = None)
import shlex import shlex
shell = shlex.join(resolved_shell(opts)) shell = shlex.join(resolved_shell(opts))
return [kitten_exe(), 'run-shell', f'--shell={shell}', f'--shell-integration={ksi}'] + list(cmd) return [kitten_exe(), 'run-shell', f'--shell={shell}', f'--shell-integration={ksi}'] + list(cmd)
def safe_mtime(path: str) -> Optional[float]:
with suppress(OSError):
return os.path.getmtime(path)
return None
@run_once
def get_custom_window_icon() -> Union[Tuple[float, str], Tuple[None, None]]:
filenames = ['kitty.app.png']
if is_macos:
# On macOS, prefer icns to png.
filenames.insert(0, 'kitty.app.icns')
for name in filenames:
custom_icon_path = os.path.join(config_dir, name)
custom_icon_mtime = safe_mtime(custom_icon_path)
if custom_icon_mtime is not None:
return custom_icon_mtime, custom_icon_path
return None, None