diff --git a/docs/changelog.rst b/docs/changelog.rst index 014aebfee..a56c968cd 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -38,9 +38,10 @@ Detailed list of changes 0.26.4 [future] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- macOS: Allow changing the kitty icon by placing a custom icon in the kitty config folder (:pull:`5464`) + - X11: Fix a regression in the previous release that caused pasting from GTK based applications to have extra newlines (:iss:`5528`) -- macOS: Allow to set custom app icon automatically (:pull:`5464`) 0.26.3 [2022-09-22] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/faq.rst b/docs/faq.rst index db916a128..61170b84c 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -289,12 +289,16 @@ homepage: On macOS you can put :file:`kitty.app.icns` or :file:`kitty.app.png` in the :ref:`kitty configuration directory `, and this icon will be applied -automatically at startup if the :file:`kitty.app` bundle has no custom icon. This is -convenient because updates under macOS replace the entire :file:`kitty.app` bundle -and the custom icon will be removed as well. To automatically update a new icon -at startup, you need to remove the custom icon on :file:`kitty.app` first. +automatically at startup. Unfortunately, Apple's Dock does not change its +cached icon so the custom icon will revert when kitty is quit. Run the +following to force the Dock to update its cached icons: -You can set custom icon via CLI, which can be used in shell scripts: +.. code-block:: sh + + rm /var/folders/*/*/*/com.apple.dock.iconcache; killall Dock + +If you prefer not to keep a custom icon in the kitty config folder, you can +also set it with the following command: .. code-block:: sh @@ -308,9 +312,11 @@ You can also change the icon manually by following the steps: #. Find :file:`kitty.app` in the Applications folder, select it and press :kbd:`⌘+I` #. Drag :file:`kitty.icns` onto the application icon in the kitty info pane -#. Delete the icon cache and restart Dock:: +#. Delete the icon cache and restart Dock: - $ rm /var/folders/*/*/*/com.apple.dock.iconcache; killall Dock +.. code-block:: sh + + rm /var/folders/*/*/*/com.apple.dock.iconcache; killall Dock How do I map key presses in kitty to different keys in the terminal program? diff --git a/kitty/cocoa_window.m b/kitty/cocoa_window.m index 11ec6bcc8..32d761c67 100644 --- a/kitty/cocoa_window.m +++ b/kitty/cocoa_window.m @@ -862,39 +862,6 @@ cocoa_set_url_handler(PyObject UNUSED *self, PyObject *args) { } // autoreleasepool } -static PyObject* -cocoa_app_has_custom_icon(PyObject UNUSED *self, PyObject *args) { - @autoreleasepool { - - const char *app_path = NULL; - if (!PyArg_ParseTuple(args, "|z", &app_path)) return NULL; - NSString *bundle_path; - if (app_path && app_path[0] != '\0') bundle_path = [NSString stringWithUTF8String:app_path]; - else bundle_path = [[NSBundle mainBundle] bundlePath]; - if (!bundle_path || bundle_path.length == 0) bundle_path = @"/Applications/kitty.app"; - - // These APIs have been marked as deprecated. - // However support for NSURLCustomIconKey has never been implemented by Apple (so far, macOS 12.5.x and below). - // so the following NSImage icon_image will be nil even if a custom icon is set: - // [[NSURL fileURLWithPath:bundle_path] getResourceValue:&icon_image forKey:NSURLCustomIconKey error:nil] -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - FSRef ref; - FSCatalogInfo catalog_info; - OSStatus err = FSPathMakeRef((const UInt8 *)[bundle_path fileSystemRepresentation], &ref, NULL); - if (err == noErr) { - err = FSGetCatalogInfo(&ref, kFSCatInfoFinderInfo, &catalog_info, NULL, NULL, NULL); - if (err == noErr) { - FileInfo *file_info = (FileInfo *)(&catalog_info.finderInfo); - if ((file_info->finderFlags & kHasCustomIcon) != 0) Py_RETURN_TRUE; - } - } -#pragma clang diagnostic pop - Py_RETURN_FALSE; - - } // autoreleasepool -} - static PyObject* cocoa_set_app_icon(PyObject UNUSED *self, PyObject *args) { @autoreleasepool { @@ -1015,7 +982,6 @@ static PyMethodDef module_methods[] = { {"cocoa_send_notification", (PyCFunction)cocoa_send_notification, METH_VARARGS, ""}, {"cocoa_set_notification_activated_callback", (PyCFunction)set_notification_activated_callback, METH_O, ""}, {"cocoa_set_url_handler", (PyCFunction)cocoa_set_url_handler, METH_VARARGS, ""}, - {"cocoa_app_has_custom_icon", (PyCFunction)cocoa_app_has_custom_icon, METH_VARARGS, ""}, {"cocoa_set_app_icon", (PyCFunction)cocoa_set_app_icon, METH_VARARGS, ""}, {"cocoa_set_dock_icon", (PyCFunction)cocoa_set_dock_icon, METH_VARARGS, ""}, {NULL, NULL, 0, NULL} /* Sentinel */ diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 6b00983c4..8f2717a81 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -734,10 +734,6 @@ def cocoa_set_url_handler(url_scheme: str, bundle_id: Optional[str] = None) -> N pass -def cocoa_app_has_custom_icon(app_path: Optional[str] = None) -> bool: - pass - - def cocoa_set_app_icon(icon_path: str, app_path: Optional[str] = None) -> None: pass diff --git a/kitty/main.py b/kitty/main.py index b29968760..e49a6c539 100644 --- a/kitty/main.py +++ b/kitty/main.py @@ -16,14 +16,13 @@ from .cli_stub import CLIOptions from .conf.utils import BadLine from .config import cached_values_for from .constants import ( - appname, beam_cursor_data_file, clear_handled_signals, config_dir, - glfw_path, is_macos, is_wayland, kitty_exe, logo_png_file, - running_in_kitty, website_url + appname, beam_cursor_data_file, clear_handled_signals, config_dir, glfw_path, + is_macos, is_wayland, kitty_exe, logo_png_file, running_in_kitty, website_url, ) from .fast_data_types import ( - GLFW_IBEAM_CURSOR, GLFW_MOD_ALT, GLFW_MOD_SHIFT, SingleKey, - create_os_window, free_font_data, glfw_init, glfw_terminate, load_png_data, - set_custom_cursor, set_default_window_icon, set_options + GLFW_IBEAM_CURSOR, GLFW_MOD_ALT, GLFW_MOD_SHIFT, SingleKey, create_os_window, + free_font_data, glfw_init, glfw_terminate, load_png_data, set_custom_cursor, + set_default_window_icon, set_options, ) from .fonts.box_drawing import set_scale from .fonts.render import set_font_family @@ -33,8 +32,8 @@ from .os_window_size import initial_window_size_func from .prewarm import PrewarmProcess, fork_prewarm_process from .session import create_sessions, get_os_window_sizing_data from .utils import ( - cleanup_ssh_control_masters, detach, expandvars, log_error, - single_instance, startup_notification_handler, unix_socket_paths + cleanup_ssh_control_masters, detach, expandvars, log_error, single_instance, + startup_notification_handler, unix_socket_paths, ) from .window import load_shader_programs @@ -135,17 +134,29 @@ def get_macos_shortcut_for( 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: for name in ('kitty.app.icns', 'kitty.app.png'): icon_path = os.path.join(config_dir, name) - if os.path.exists(icon_path): - from .fast_data_types import cocoa_app_has_custom_icon, cocoa_set_app_icon, cocoa_set_dock_icon - if not cocoa_app_has_custom_icon(): + custom_icon_mtime = safe_mtime(icon_path) + if custom_icon_mtime is not None: + from .fast_data_types import cocoa_set_app_icon, cocoa_set_dock_icon + krd = getattr(sys, 'kitty_run_data') + bundle_path = os.path.dirname(os.path.dirname(krd.get('bundle_exe_dir'))) + icon_sentinel = os.path.join(bundle_path, 'Icon\r') + sentinel_mtime = safe_mtime(icon_sentinel) + if sentinel_mtime is None or sentinel_mtime < custom_icon_mtime: cocoa_set_app_icon(icon_path) - # kitty dock icon doesn't refresh automatically, so set it explicitly - # This has the drawback that the dock icon reverts to the original icon after exiting the application, - # even if the custom icon has been successfully updated, until the next launch. - cocoa_set_dock_icon(icon_path) + # macOS Dock does not reload icons until it is restarted, so we set + # the application icon here. This will revert when kitty quits, but + # cant be helped since there appears to be no way to get the dock + # to reload short of killing it. + cocoa_set_dock_icon(icon_path) break @@ -225,7 +236,7 @@ class AppRunner: free_font_data() # must free font data before glfw/freetype/fontconfig/opengl etc are finalized if is_macos: from kitty.fast_data_types import ( - cocoa_set_notification_activated_callback + cocoa_set_notification_activated_callback, ) cocoa_set_notification_activated_callback(None)