diff --git a/docs/changelog.rst b/docs/changelog.rst index 0cab22ad2..88f9aeb66 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -174,6 +174,8 @@ Detailed list of changes - macOS: Performance and power usage improvements of about 5-10% (:pull:`9131`) +- macOS: Add an item to the global menu to Cycle through OS windows + - Wayland: Fix ``center-sized`` panels not working on smithay based compositors (:pull:`9117`) - Wayland: Fix scrolling using some mouse wheels that produce "VALUE120" based diff --git a/kitty/boss.py b/kitty/boss.py index f9fb707ee..5ae5f92fc 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -91,6 +91,7 @@ from .fast_data_types import ( grab_keyboard, is_layer_shell_supported, last_focused_os_window_id, + macos_cycle_through_os_windows, mark_os_window_for_close, monitor_pid, monotonic, @@ -1315,6 +1316,10 @@ class Boss: def toggle_macos_secure_keyboard_entry(self) -> None: toggle_secure_input() + @ac('misc', 'Cycle through OS windows on macOS') + def macos_cycle_through_os_windows(self) -> None: + macos_cycle_through_os_windows() + @ac('misc', 'Hide macOS kitty application') def hide_macos_app(self) -> None: cocoa_hide_app() @@ -3370,3 +3375,5 @@ class Boss: @ac('misc', 'Ungrab the keyboard if it was previously grabbed') def ungrab_keyboard(self) -> None: grab_keyboard(False) + + diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index e8ef17715..a13511914 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -1240,6 +1240,7 @@ process_cocoa_pending_actions(void) { if (cocoa_pending_actions[CLEAR_LAST_COMMAND]) { call_boss(clear_terminal, "sO", "last_command", Py_True ); } if (cocoa_pending_actions[RELOAD_CONFIG]) { call_boss(load_config_file, NULL); } if (cocoa_pending_actions[TOGGLE_MACOS_SECURE_KEYBOARD_ENTRY]) { call_boss(toggle_macos_secure_keyboard_entry, NULL); } + if (cocoa_pending_actions[MACOS_CYCLE_THROUGH_OS_WINDOWS]) { call_boss(macos_cycle_through_os_windows, NULL); } if (cocoa_pending_actions[TOGGLE_FULLSCREEN]) { call_boss(toggle_fullscreen, NULL); } if (cocoa_pending_actions[OPEN_KITTY_WEBSITE]) { call_boss(open_kitty_website, NULL); } if (cocoa_pending_actions[HIDE]) { call_boss(hide_macos_app, NULL); } diff --git a/kitty/cocoa_window.h b/kitty/cocoa_window.h index 7f11516df..a723c5a53 100644 --- a/kitty/cocoa_window.h +++ b/kitty/cocoa_window.h @@ -30,6 +30,7 @@ typedef enum { CLEAR_LAST_COMMAND, RELOAD_CONFIG, TOGGLE_MACOS_SECURE_KEYBOARD_ENTRY, + MACOS_CYCLE_THROUGH_OS_WINDOWS, TOGGLE_FULLSCREEN, OPEN_KITTY_WEBSITE, HIDE, @@ -50,6 +51,7 @@ void cocoa_system_beep(const char*); void cocoa_set_activation_policy(bool); bool cocoa_alt_option_key_pressed(unsigned long); void cocoa_toggle_secure_keyboard_entry(void); +void cocoa_cycle_through_os_windows(void); void cocoa_hide(void); void cocoa_clear_global_shortcuts(void); void cocoa_hide_others(void); diff --git a/kitty/cocoa_window.m b/kitty/cocoa_window.m index 365a62c43..9ec07e30b 100644 --- a/kitty/cocoa_window.m +++ b/kitty/cocoa_window.m @@ -258,6 +258,7 @@ PENDING(clear_screen, CLEAR_SCREEN) PENDING(clear_last_command, CLEAR_LAST_COMMAND) PENDING(reload_config, RELOAD_CONFIG) PENDING(toggle_macos_secure_keyboard_entry, TOGGLE_MACOS_SECURE_KEYBOARD_ENTRY) +PENDING(macos_cycle_through_os_windows, MACOS_CYCLE_THROUGH_OS_WINDOWS) PENDING(toggle_fullscreen, TOGGLE_FULLSCREEN) PENDING(open_kitty_website, OPEN_KITTY_WEBSITE) PENDING(hide_macos_app, HIDE) @@ -319,6 +320,7 @@ typedef struct { GlobalShortcut clear_terminal_and_scrollback, clear_screen, clear_scrollback, clear_last_command; GlobalShortcut toggle_macos_secure_keyboard_entry, toggle_fullscreen, open_kitty_website; GlobalShortcut hide_macos_app, hide_macos_other_apps, minimize_macos_window, quit; + GlobalShortcut macos_cycle_through_os_windows; } GlobalShortcuts; static GlobalShortcuts global_shortcuts; @@ -336,7 +338,7 @@ cocoa_set_global_shortcut(PyObject *self UNUSED, PyObject *args) { else Q(clear_terminal_and_scrollback); else Q(clear_scrollback); else Q(clear_screen); else Q(clear_last_command); else Q(reload_config); else Q(toggle_macos_secure_keyboard_entry); else Q(toggle_fullscreen); else Q(open_kitty_website); else Q(hide_macos_app); else Q(hide_macos_other_apps); - else Q(minimize_macos_window); else Q(quit); + else Q(minimize_macos_window); else Q(quit); else Q(macos_cycle_through_os_windows); #undef Q if (gs == NULL) { PyErr_SetString(PyExc_KeyError, "Unknown shortcut name"); return NULL; } int cocoa_mods; @@ -805,6 +807,8 @@ cocoa_create_global_menu(void) { action:@selector(performZoom:) keyEquivalent:@""]; [windowMenu addItem:[NSMenuItem separatorItem]]; + MENU_ITEM(windowMenu, @"Cycle Through OS Windows", macos_cycle_through_os_windows); + [windowMenu addItem:[NSMenuItem separatorItem]]; [windowMenu addItemWithTitle:@"Bring All to Front" action:@selector(arrangeInFront:) keyEquivalent:@""]; @@ -920,6 +924,20 @@ cocoa_toggle_secure_keyboard_entry(void) { [[NSUserDefaults standardUserDefaults] setBool:k.isDesired forKey:@"SecureKeyboardEntry"]; } +void +cocoa_cycle_through_os_windows(void) { + NSArray *windows = [NSApp orderedWindows]; + if (windows.count < 2) return; + + NSWindow *keyWindow = [NSApp keyWindow]; + NSUInteger index = [windows indexOfObject:keyWindow]; + NSUInteger nextIndex = (index + 1) % windows.count; + + NSWindow *nextWindow = windows[nextIndex]; + [nextWindow makeKeyAndOrderFront:nil]; +} + + void cocoa_hide(void) { [[NSApplication sharedApplication] performSelectorOnMainThread:@selector(hide:) withObject:nil waitUntilDone:NO]; diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 31ef21b6a..d3d6006a3 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -948,6 +948,10 @@ def toggle_secure_input() -> None: pass +def macos_cycle_through_os_windows() -> None: + pass + + def start_profiler(path: str) -> None: pass diff --git a/kitty/glfw.c b/kitty/glfw.c index 5f5a2a359..49afde4b2 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -1920,6 +1920,15 @@ toggle_secure_input(PYNOARG) { Py_RETURN_NONE; } +static PyObject* +macos_cycle_through_os_windows(PYNOARG) { +#ifdef __APPLE__ + cocoa_cycle_through_os_windows(); +#endif + Py_RETURN_NONE; +} + + static PyObject* cocoa_hide_app(PYNOARG) { #ifdef __APPLE__ @@ -2606,6 +2615,7 @@ static PyMethodDef module_methods[] = { METHODB(set_clipboard_data_types, METH_VARARGS), METHODB(get_clipboard_mime, METH_VARARGS), METHODB(toggle_secure_input, METH_NOARGS), + METHODB(macos_cycle_through_os_windows, METH_NOARGS), METHODB(get_content_scale_for_window, METH_NOARGS), METHODB(ring_bell, METH_VARARGS), METHODB(toggle_fullscreen, METH_VARARGS), diff --git a/kitty/main.py b/kitty/main.py index 71ea1a168..f862659d2 100644 --- a/kitty/main.py +++ b/kitty/main.py @@ -192,7 +192,8 @@ def set_cocoa_global_shortcuts(opts: Options) -> dict[str, SingleKey]: func_map[parts].append(single_key) for ac in ('new_os_window', 'close_os_window', 'close_tab', 'edit_config_file', 'previous_tab', - 'next_tab', 'new_tab', 'new_window', 'close_window', 'toggle_macos_secure_keyboard_entry', 'toggle_fullscreen', + 'next_tab', 'new_tab', 'new_window', 'close_window', 'toggle_macos_secure_keyboard_entry', + 'toggle_fullscreen', 'macos_cycle_through_os_windows', 'hide_macos_app', 'hide_macos_other_apps', 'minimize_macos_window', 'quit'): val = get_macos_shortcut_for(func_map, ac) if val is not None: diff --git a/kitty/options/definition.py b/kitty/options/definition.py index 887485575..0544a413b 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -4428,6 +4428,8 @@ map('Toggle macOS secure keyboard entry', only='macos', ) +map('macOS Cycle through OS Windows', 'macos_cycle_through_os_windows cmd+` macos_cycle_through_os_windows', only='macos') + map('Unicode input', 'input_unicode_character kitty_mod+u kitten unicode_input', ) diff --git a/kitty/options/types.py b/kitty/options/types.py index b21848ef9..61ca32c37 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -1005,6 +1005,7 @@ if is_macos: defaults.map.append(KeyDefinition(trigger=SingleKey(mods=8, key=48), definition='change_font_size all 0')) defaults.map.append(KeyDefinition(trigger=SingleKey(mods=12, key=102), definition='toggle_fullscreen')) defaults.map.append(KeyDefinition(trigger=SingleKey(mods=10, key=115), definition='toggle_macos_secure_keyboard_entry')) + defaults.map.append(KeyDefinition(trigger=SingleKey(mods=8, key=96), definition='macos_cycle_through_os_windows')) defaults.map.append(KeyDefinition(trigger=SingleKey(mods=12, key=32), definition='kitten unicode_input')) defaults.map.append(KeyDefinition(trigger=SingleKey(mods=8, key=44), definition='edit_config_file')) defaults.map.append(KeyDefinition(trigger=SingleKey(mods=10, key=114), definition='clear_terminal reset active'))