macOS: Add menu items to close the OS window and the current tab
Fixes #3246
This commit is contained in:
parent
4c9bd368c6
commit
aa63bf71cf
@ -27,7 +27,7 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||
|
||||
- Panel kitten: Allow setting WM_CLASS (:iss:`3233`)
|
||||
|
||||
- macOS: Add a menu item to close the OS window (:pull:`3240`)
|
||||
- macOS: Add menu items to close the OS window and the current tab (:pull:`3240`, :iss:`3246`)
|
||||
|
||||
|
||||
0.19.3 [2020-12-19]
|
||||
|
||||
@ -141,7 +141,7 @@ class Boss:
|
||||
opts: Options,
|
||||
args: CLIOptions,
|
||||
cached_values: Dict[str, Any],
|
||||
new_os_window_trigger: Optional[SingleKey]
|
||||
global_shortcuts: Dict[str, SingleKey]
|
||||
):
|
||||
set_layout_options(opts)
|
||||
self.clipboard_buffers: Dict[str, str] = {}
|
||||
@ -168,8 +168,8 @@ class Boss:
|
||||
set_boss(self)
|
||||
self.opts, self.args = opts, args
|
||||
self.keymap = self.opts.keymap.copy()
|
||||
if new_os_window_trigger is not None:
|
||||
self.keymap.pop(new_os_window_trigger, None)
|
||||
for sc in global_shortcuts.values():
|
||||
self.keymap.pop(sc, None)
|
||||
if is_macos:
|
||||
from .fast_data_types import (
|
||||
cocoa_set_notification_activated_callback
|
||||
|
||||
@ -968,6 +968,8 @@ process_global_state(void *data) {
|
||||
if (cocoa_pending_actions) {
|
||||
if (cocoa_pending_actions & PREFERENCES_WINDOW) { call_boss(edit_config_file, NULL); }
|
||||
if (cocoa_pending_actions & NEW_OS_WINDOW) { call_boss(new_os_window, NULL); }
|
||||
if (cocoa_pending_actions & CLOSE_OS_WINDOW) { call_boss(close_os_window, NULL); }
|
||||
if (cocoa_pending_actions & CLOSE_TAB) { call_boss(close_tab, NULL); }
|
||||
if (cocoa_pending_actions_wd) {
|
||||
if (cocoa_pending_actions & NEW_OS_WINDOW_WITH_WD) { call_boss(new_os_window_with_wd, "s", cocoa_pending_actions_wd); }
|
||||
if (cocoa_pending_actions & NEW_TAB_WITH_WD) { call_boss(new_tab_with_wd, "s", cocoa_pending_actions_wd); }
|
||||
|
||||
@ -87,6 +87,16 @@ find_app_name(void) {
|
||||
set_cocoa_pending_action(NEW_OS_WINDOW, NULL);
|
||||
}
|
||||
|
||||
- (void) close_os_window:(id)sender {
|
||||
(void)sender;
|
||||
set_cocoa_pending_action(CLOSE_OS_WINDOW, NULL);
|
||||
}
|
||||
|
||||
- (void)close_tab:(id)sender {
|
||||
(void)sender;
|
||||
set_cocoa_pending_action(CLOSE_TAB, NULL);
|
||||
}
|
||||
|
||||
- (void)open_kitty_website_url:(id)sender {
|
||||
(void)sender;
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://sw.kovidgoyal.net/kitty/"]];
|
||||
@ -106,18 +116,30 @@ find_app_name(void) {
|
||||
|
||||
@end
|
||||
|
||||
static char new_window_key[32] = {0};
|
||||
static NSEventModifierFlags new_window_mods = 0;
|
||||
typedef struct {
|
||||
char key[32];
|
||||
NSEventModifierFlags mods;
|
||||
} GlobalShortcut;
|
||||
typedef struct {
|
||||
GlobalShortcut new_os_window, close_os_window, close_tab;
|
||||
} GlobalShortcuts;
|
||||
static GlobalShortcuts global_shortcuts;
|
||||
|
||||
static PyObject*
|
||||
cocoa_set_new_window_trigger(PyObject *self UNUSED, PyObject *args) {
|
||||
cocoa_set_global_shortcut(PyObject *self UNUSED, PyObject *args) {
|
||||
int mods;
|
||||
unsigned int key;
|
||||
if (!PyArg_ParseTuple(args, "iI", &mods, &key)) return NULL;
|
||||
int nwm;
|
||||
get_cocoa_key_equivalent(key, mods, new_window_key, sizeof(new_window_key), &nwm);
|
||||
new_window_mods = nwm;
|
||||
if (new_window_key[0]) Py_RETURN_TRUE;
|
||||
const char *name;
|
||||
if (!PyArg_ParseTuple(args, "siI", &name, &mods, &key)) return NULL;
|
||||
GlobalShortcut *gs = NULL;
|
||||
if (strcmp(name, "new_os_window") == 0) gs = &global_shortcuts.new_os_window;
|
||||
else if (strcmp(name, "close_os_window") == 0) gs = &global_shortcuts.close_os_window;
|
||||
else if (strcmp(name, "close_tab") == 0) gs = &global_shortcuts.close_tab;
|
||||
if (gs == NULL) { PyErr_SetString(PyExc_KeyError, "Unknown shortcut name"); return NULL; }
|
||||
int cocoa_mods;
|
||||
get_cocoa_key_equivalent(key, mods, gs->key, 32, &cocoa_mods);
|
||||
gs->mods = cocoa_mods;
|
||||
if (gs->key[0]) Py_RETURN_TRUE;
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
@ -358,8 +380,8 @@ cocoa_create_global_menu(void) {
|
||||
NSMenuItem* new_os_window_menu_item =
|
||||
[appMenu addItemWithTitle:@"New OS window"
|
||||
action:@selector(new_os_window:)
|
||||
keyEquivalent:@(new_window_key)];
|
||||
[new_os_window_menu_item setKeyEquivalentModifierMask:new_window_mods];
|
||||
keyEquivalent:@(global_shortcuts.new_os_window.key)];
|
||||
[new_os_window_menu_item setKeyEquivalentModifierMask:global_shortcuts.new_os_window.mods];
|
||||
[new_os_window_menu_item setTarget:global_menu_target];
|
||||
|
||||
|
||||
@ -396,10 +418,6 @@ cocoa_create_global_menu(void) {
|
||||
NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
|
||||
[windowMenuItem setSubmenu:windowMenu];
|
||||
|
||||
[windowMenu addItemWithTitle:@"Close"
|
||||
action:@selector(performClose:)
|
||||
keyEquivalent:@"w"];
|
||||
|
||||
[windowMenu addItemWithTitle:@"Minimize"
|
||||
action:@selector(performMiniaturize:)
|
||||
keyEquivalent:@"m"];
|
||||
@ -411,6 +429,20 @@ cocoa_create_global_menu(void) {
|
||||
action:@selector(arrangeInFront:)
|
||||
keyEquivalent:@""];
|
||||
|
||||
[windowMenu addItem:[NSMenuItem separatorItem]];
|
||||
NSMenuItem* close_tab_item =
|
||||
[windowMenu addItemWithTitle:@"Close Tab"
|
||||
action:@selector(close_tab:)
|
||||
keyEquivalent:@(global_shortcuts.close_tab.key)];
|
||||
[close_tab_item setKeyEquivalentModifierMask:global_shortcuts.close_tab.mods];
|
||||
[close_tab_item setTarget:global_menu_target];
|
||||
NSMenuItem* close_os_window_menu_item =
|
||||
[windowMenu addItemWithTitle:@"Close OS Window"
|
||||
action:@selector(close_os_window:)
|
||||
keyEquivalent:@(global_shortcuts.close_os_window.key)];
|
||||
[close_os_window_menu_item setKeyEquivalentModifierMask:global_shortcuts.close_os_window.mods];
|
||||
[close_os_window_menu_item setTarget:global_menu_target];
|
||||
|
||||
[windowMenu addItem:[NSMenuItem separatorItem]];
|
||||
[[windowMenu addItemWithTitle:@"Enter Full Screen"
|
||||
action:@selector(toggleFullScreen:)
|
||||
@ -627,7 +659,7 @@ cocoa_system_beep(void) {
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"cocoa_get_lang", (PyCFunction)cocoa_get_lang, METH_NOARGS, ""},
|
||||
{"cocoa_set_new_window_trigger", (PyCFunction)cocoa_set_new_window_trigger, METH_VARARGS, ""},
|
||||
{"cocoa_set_global_shortcut", (PyCFunction)cocoa_set_global_shortcut, METH_VARARGS, ""},
|
||||
{"cocoa_send_notification", (PyCFunction)cocoa_send_notification, METH_VARARGS, ""},
|
||||
{"cocoa_set_notification_activated_callback", (PyCFunction)set_notification_activated_callback, METH_O, ""},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
@ -635,6 +667,7 @@ static PyMethodDef module_methods[] = {
|
||||
|
||||
bool
|
||||
init_cocoa(PyObject *module) {
|
||||
memset(&global_shortcuts, 0, sizeof(global_shortcuts));
|
||||
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||
if (Py_AtExit(cleanup) != 0) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Failed to register the cocoa_window at exit handler");
|
||||
|
||||
@ -640,7 +640,7 @@ def cocoa_set_notification_activated_callback(identifier: Callable[[str], None])
|
||||
pass
|
||||
|
||||
|
||||
def cocoa_set_new_window_trigger(mods: int, key: int) -> bool:
|
||||
def cocoa_set_global_shortcut(name: str, mods: int, key: int) -> bool:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import os
|
||||
import shutil
|
||||
import sys
|
||||
from contextlib import contextmanager, suppress
|
||||
from typing import Generator, List, Mapping, Optional, Sequence
|
||||
from typing import Dict, Generator, List, Mapping, Optional, Sequence
|
||||
|
||||
from .borders import load_borders_program
|
||||
from .boss import Boss
|
||||
@ -104,26 +104,30 @@ def init_glfw(opts: OptionsStub, debug_keyboard: bool = False) -> str:
|
||||
return glfw_module
|
||||
|
||||
|
||||
def get_new_os_window_trigger(opts: OptionsStub) -> Optional[SingleKey]:
|
||||
new_os_window_trigger = None
|
||||
if is_macos:
|
||||
new_os_window_shortcuts = []
|
||||
for k, v in opts.keymap.items():
|
||||
if v.func == 'new_os_window':
|
||||
new_os_window_shortcuts.append(k)
|
||||
if new_os_window_shortcuts:
|
||||
from .fast_data_types import cocoa_set_new_window_trigger
|
||||
def get_macos_shortcut_for(opts: OptionsStub, function: str = 'new_os_window') -> Optional[SingleKey]:
|
||||
ans = None
|
||||
candidates = []
|
||||
for k, v in opts.keymap.items():
|
||||
if v.func == function:
|
||||
candidates.append(k)
|
||||
if candidates:
|
||||
from .fast_data_types import cocoa_set_global_shortcut
|
||||
|
||||
# Reverse list so that later defined keyboard shortcuts take priority over earlier defined ones
|
||||
for candidate in reversed(new_os_window_shortcuts):
|
||||
if cocoa_set_new_window_trigger(candidate[0], candidate[2]):
|
||||
new_os_window_trigger = candidate
|
||||
break
|
||||
return new_os_window_trigger
|
||||
# Reverse list so that later defined keyboard shortcuts take priority over earlier defined ones
|
||||
for candidate in reversed(candidates):
|
||||
if cocoa_set_global_shortcut(function, candidate[0], candidate[2]):
|
||||
ans = candidate
|
||||
break
|
||||
return ans
|
||||
|
||||
|
||||
def _run_app(opts: OptionsStub, args: CLIOptions, bad_lines: Sequence[BadLine] = ()) -> None:
|
||||
new_os_window_trigger = get_new_os_window_trigger(opts)
|
||||
global_shortcuts: Dict[str, SingleKey] = {}
|
||||
if is_macos:
|
||||
for ac in ('new_os_window', 'close_os_window', 'close_tab'):
|
||||
val = get_macos_shortcut_for(opts, ac)
|
||||
if val is not None:
|
||||
global_shortcuts[ac] = val
|
||||
if is_macos and opts.macos_custom_beam_cursor:
|
||||
set_custom_ibeam_cursor()
|
||||
if not is_wayland() and not is_macos: # no window icons on wayland
|
||||
@ -137,7 +141,7 @@ def _run_app(opts: OptionsStub, args: CLIOptions, bad_lines: Sequence[BadLine] =
|
||||
pre_show_callback,
|
||||
args.title or appname, args.name or args.cls or appname,
|
||||
args.cls or appname, load_all_shaders)
|
||||
boss = Boss(opts, args, cached_values, new_os_window_trigger)
|
||||
boss = Boss(opts, args, cached_values, global_shortcuts)
|
||||
boss.start(window_id)
|
||||
if bad_lines:
|
||||
boss.show_bad_config_lines(bad_lines)
|
||||
|
||||
@ -263,7 +263,9 @@ typedef enum {
|
||||
PREFERENCES_WINDOW = 1,
|
||||
NEW_OS_WINDOW = 2,
|
||||
NEW_OS_WINDOW_WITH_WD = 4,
|
||||
NEW_TAB_WITH_WD = 8
|
||||
NEW_TAB_WITH_WD = 8,
|
||||
CLOSE_OS_WINDOW = 16,
|
||||
CLOSE_TAB = 32
|
||||
} CocoaPendingAction;
|
||||
void set_cocoa_pending_action(CocoaPendingAction action, const char*);
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user