Get the quake terminal working on macOS
This commit is contained in:
parent
610d6b8654
commit
189d78283c
15 changed files with 127 additions and 39 deletions
|
|
@ -12,6 +12,7 @@
|
|||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
import time
|
||||
from functools import lru_cache, partial
|
||||
from typing import Any, Callable, Dict, Iterable, Iterator, List, Tuple
|
||||
|
|
@ -30,6 +31,7 @@
|
|||
from kitty.conf.types import Definition, expand_opt_references # noqa
|
||||
from kitty.constants import str_version, website_url # noqa
|
||||
from kitty.fast_data_types import Shlex, TEXT_SIZE_CODE # noqa
|
||||
from kittens.panel.main import default_quake_cmdline # noqa
|
||||
|
||||
# config {{{
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
|
@ -120,6 +122,9 @@ def go_version(go_mod_path: str) -> str: # {{{
|
|||
'_kitty_install_cmd': 'curl -L https://sw.kovidgoyal.net/kitty/installer.sh | sh /dev/stdin',
|
||||
'_build_go_version': go_version('../go.mod'),
|
||||
'_text_size_code': str(TEXT_SIZE_CODE),
|
||||
'_default_quake_cmdline': textwrap.fill(
|
||||
default_quake_cmdline, break_on_hyphens=False, break_long_words=False, initial_indent=' ' * 4, subsequent_indent=' ' * 8, width=77,
|
||||
).replace('\n', ' \\\n'),
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -352,7 +357,7 @@ def format_cmd(p: Callable[..., None], name: str, cmd: RemoteCommand) -> None:
|
|||
|
||||
def replace_string(app: Any, docname: str, source: List[str]) -> None: # {{{
|
||||
src = source[0]
|
||||
for k, v in app.config.string_replacements.items():
|
||||
for k, v in string_replacements.items():
|
||||
src = src.replace(k, v)
|
||||
source[0] = src
|
||||
# }}}
|
||||
|
|
@ -769,7 +774,6 @@ def setup(app: Any) -> None:
|
|||
write_remote_control_protocol_docs()
|
||||
write_color_names_table()
|
||||
write_conf_docs(app, kn)
|
||||
app.add_config_value('string_replacements', {}, True)
|
||||
app.connect('source-read', replace_string)
|
||||
app.add_config_value('analytics_id', '', 'env')
|
||||
app.connect('html-page-context', add_html_context)
|
||||
|
|
|
|||
|
|
@ -75,12 +75,11 @@ Make a Quake like quick access terminal
|
|||
Support for quake mode, works only on macOS and Wayland, except for GNOME.
|
||||
|
||||
This kitten can be used to make a quick access terminal, that appears and
|
||||
disappears at a key press. To do so use the following command::
|
||||
disappears at a key press. To do so use the following command:
|
||||
|
||||
kitty +kitten panel --edge=top --layer=overlay --lines=15 \
|
||||
--focus-policy=exclusive --exclusive-zone=0 --override-exclusive-zone \
|
||||
-o background_opacity=0.8 --toggle-visibility --single-instance \
|
||||
--instance-group=quake --detach
|
||||
.. code-block:: sh
|
||||
|
||||
_default_quake_cmdline
|
||||
|
||||
Run this command in a terminal, and a quick access kitty panel will show up at
|
||||
the top of your screen. Run it again, and the panel will be hidden.
|
||||
|
|
|
|||
|
|
@ -358,8 +358,7 @@ - (void)applicationWillFinishLaunching:(NSNotification *)notification
|
|||
else
|
||||
createMenuBar();
|
||||
}
|
||||
if (finish_launching_callback)
|
||||
finish_launching_callback();
|
||||
if (finish_launching_callback) finish_launching_callback(false);
|
||||
}
|
||||
|
||||
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
|
||||
|
|
@ -410,6 +409,7 @@ - (void)application:(NSApplication *)sender openURLs:(NSArray<NSURL *> *)urls
|
|||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
if (finish_launching_callback) finish_launching_callback(true);
|
||||
(void)notification;
|
||||
[NSApp stop:nil];
|
||||
|
||||
|
|
|
|||
2
glfw/cocoa_platform.h
vendored
2
glfw/cocoa_platform.h
vendored
|
|
@ -67,7 +67,7 @@ typedef void* id;
|
|||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int, unsigned long);
|
||||
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||
typedef bool (* GLFWhandleurlopen)(const char*);
|
||||
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
|
||||
typedef void (* GLFWapplicationwillfinishlaunchingfun)(bool);
|
||||
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
||||
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
|
||||
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ def generate_wrappers(glfw_header: str) -> None:
|
|||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int,unsigned long);
|
||||
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||
typedef bool (* GLFWhandleurlopen)(const char*);
|
||||
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
|
||||
typedef void (* GLFWapplicationwillfinishlaunchingfun)(bool);
|
||||
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
||||
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
|
||||
typedef void (*GLFWwaylandframecallbackfunc)(unsigned long long id);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,13 @@
|
|||
from kitty.typing import BossType, EdgeLiteral
|
||||
from kitty.utils import log_error
|
||||
|
||||
quake = (
|
||||
'kitty +kitten panel --edge=top --layer=overlay --lines=25 --focus-policy=exclusive'
|
||||
' -o background_opacity=0.8 --toggle-visibility --single-instance --instance-group=quake'
|
||||
)
|
||||
default_quake_cmdline = f'{quake} --exclusive-zone=0 --override-exclusive-zone --detach'
|
||||
default_macos_quake_cmdline = f'{quake}'
|
||||
|
||||
OPTIONS = r'''
|
||||
--lines
|
||||
default=1
|
||||
|
|
@ -363,6 +370,8 @@ def main(sys_args: list[str]) -> None:
|
|||
sys.argv.extend(('--override', override))
|
||||
sys.argv.append('--override=linux_display_server=auto')
|
||||
sys.argv.append('--override=macos_quit_when_last_window_closed=yes')
|
||||
sys.argv.append('--override=macos_hide_from_tasks=yes')
|
||||
sys.argv.append('--override=macos_window_resizable=no')
|
||||
if args.single_instance:
|
||||
sys.argv.append('--single-instance')
|
||||
if args.instance_group:
|
||||
|
|
@ -378,7 +387,7 @@ def main(sys_args: list[str]) -> None:
|
|||
if not is_macos:
|
||||
run_app.first_window_callback = setup_x11_window
|
||||
run_app.initial_window_size_func = initial_window_size_func
|
||||
real_main()
|
||||
real_main(called_from_panel=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@
|
|||
thread_write,
|
||||
toggle_fullscreen,
|
||||
toggle_maximized,
|
||||
toggle_os_window_visibility,
|
||||
toggle_secure_input,
|
||||
wrapped_kitten_names,
|
||||
)
|
||||
|
|
@ -900,6 +901,10 @@ def peer_message_received(self, msg_bytes: bytes, peer_id: int, is_remote_contro
|
|||
log_error('Unknown message received over single instance socket, ignoring')
|
||||
return None
|
||||
|
||||
def quick_access_terminal_invoked(self) -> None:
|
||||
for os_window_id in self.os_window_map:
|
||||
toggle_os_window_visibility(os_window_id)
|
||||
|
||||
def handle_remote_cmd(self, cmd: memoryview, window: Window | None = None) -> None:
|
||||
response = self._handle_remote_command(cmd, window)
|
||||
if response is not None and not isinstance(response, AsyncResponse) and window is not None:
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ typedef enum {
|
|||
|
||||
void cocoa_focus_window(void *w);
|
||||
long cocoa_window_number(void *w);
|
||||
void cocoa_create_global_menu(void);
|
||||
void cocoa_application_lifecycle_event(bool);
|
||||
void cocoa_recreate_global_menu(void);
|
||||
void cocoa_system_beep(const char*);
|
||||
void cocoa_set_activation_policy(bool);
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
CFArrayRef CGSCopySpacesForWindows(CGSConnectionID Connection, CGSSpaceSelector Type, CFArrayRef Windows);
|
||||
|
||||
static NSMenuItem* title_menu = NULL;
|
||||
static bool application_has_finished_launching = false;
|
||||
|
||||
|
||||
static NSString*
|
||||
|
|
@ -679,6 +680,12 @@ - (BOOL)openFileURLs:(NSPasteboard*)pasteboard
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (void)quickAccessTerminal:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error {
|
||||
// we ignore event during application launch as it will cause the window to be shown and hidden
|
||||
static bool is_first_event = true;
|
||||
if (is_first_event) is_first_event = false;
|
||||
else { call_boss(quick_access_terminal_invoked, NULL) }
|
||||
}
|
||||
@end
|
||||
|
||||
// global menu {{{
|
||||
|
|
@ -712,7 +719,7 @@ - (BOOL)openFileURLs:(NSPasteboard*)pasteboard
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
cocoa_create_global_menu(void) {
|
||||
NSString* app_name = find_app_name();
|
||||
NSMenu* bar = [[NSMenu alloc] init];
|
||||
|
|
@ -844,6 +851,13 @@ - (BOOL)openFileURLs:(NSPasteboard*)pasteboard
|
|||
#undef MENU_ITEM
|
||||
}
|
||||
|
||||
void
|
||||
cocoa_application_lifecycle_event(bool application_launch_finished) {
|
||||
if (application_launch_finished) { // applicationDidFinishLaunching
|
||||
application_has_finished_launching = true;
|
||||
} else cocoa_create_global_menu(); // applicationWillFinishLaunching
|
||||
}
|
||||
|
||||
void
|
||||
cocoa_update_menu_bar_title(PyObject *pytitle) {
|
||||
if (!pytitle) return;
|
||||
|
|
|
|||
|
|
@ -31,10 +31,12 @@ class Version(NamedTuple):
|
|||
RC_ENCRYPTION_PROTOCOL_VERSION = '1'
|
||||
website_base_url = 'https://sw.kovidgoyal.net/kitty/'
|
||||
default_pager_for_help = ('less', '-iRXF')
|
||||
launched_by_launch_services = getattr(sys, 'kitty_run_data', {}).get('launched_by_launch_services', False)
|
||||
kitty_run_data: dict[str, Any] = getattr(sys, 'kitty_run_data', {})
|
||||
launched_by_launch_services = kitty_run_data.get('launched_by_launch_services', False)
|
||||
is_quick_access_terminal_app = kitty_run_data.get('is_quick_access_terminal_app', False)
|
||||
|
||||
if getattr(sys, 'frozen', False):
|
||||
extensions_dir: str = getattr(sys, 'kitty_run_data')['extensions_dir']
|
||||
extensions_dir: str = kitty_run_data['extensions_dir']
|
||||
|
||||
def get_frozen_base() -> str:
|
||||
global is_running_from_develop
|
||||
|
|
@ -66,7 +68,7 @@ def get_frozen_base() -> str:
|
|||
|
||||
@run_once
|
||||
def kitty_exe() -> str:
|
||||
rpath = getattr(sys, 'kitty_run_data').get('bundle_exe_dir')
|
||||
rpath = kitty_run_data.get('bundle_exe_dir')
|
||||
if not rpath:
|
||||
items = os.environ.get('PATH', '').split(os.pathsep) + [os.path.join(kitty_base_dir, 'kitty', 'launcher')]
|
||||
seen: set[str] = set()
|
||||
|
|
@ -87,7 +89,7 @@ def kitten_exe() -> str:
|
|||
|
||||
|
||||
def _get_config_dir() -> str:
|
||||
cdir = getattr(sys, 'kitty_run_data', {}).get('config_dir', '')
|
||||
cdir = kitty_run_data.get('config_dir', '')
|
||||
if cdir:
|
||||
return str(cdir)
|
||||
import atexit
|
||||
|
|
@ -276,7 +278,7 @@ def clear_handled_signals(*a: Any) -> None:
|
|||
def local_docs() -> str:
|
||||
d = os.path.dirname
|
||||
base = d(d(kitty_exe()))
|
||||
from_source = getattr(sys, 'kitty_run_data').get('from_source')
|
||||
from_source = kitty_run_data.get('from_source')
|
||||
if is_macos and from_source and '/kitty.app/Contents/' in kitty_exe():
|
||||
base = d(d(d(base)))
|
||||
subdir = os.path.join('doc', 'kitty', 'html')
|
||||
|
|
|
|||
2
kitty/glfw-wrapper.h
generated
2
kitty/glfw-wrapper.h
generated
|
|
@ -1710,7 +1710,7 @@ typedef struct GLFWgamepadstate
|
|||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int,unsigned long);
|
||||
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||
typedef bool (* GLFWhandleurlopen)(const char*);
|
||||
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
|
||||
typedef void (* GLFWapplicationwillfinishlaunchingfun)(bool);
|
||||
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
||||
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
|
||||
typedef void (*GLFWwaylandframecallbackfunc)(unsigned long long id);
|
||||
|
|
|
|||
|
|
@ -1299,7 +1299,7 @@ create_os_window(PyObject UNUSED *self, PyObject *args, PyObject *kw) {
|
|||
cocoa_set_activation_policy(OPT(macos_hide_from_tasks) || lsc != NULL);
|
||||
glfwWindowHint(GLFW_COCOA_GRAPHICS_SWITCHING, true);
|
||||
glfwSetApplicationShouldHandleReopen(on_application_reopen);
|
||||
glfwSetApplicationWillFinishLaunching(cocoa_create_global_menu);
|
||||
glfwSetApplicationWillFinishLaunching(cocoa_application_lifecycle_event);
|
||||
#endif
|
||||
}
|
||||
if (OPT(hide_window_decorations) & 1) glfwWindowHint(GLFW_DECORATED, false);
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ typedef struct {
|
|||
const char *exe, *exe_dir, *lc_ctype, *lib_dir, *config_dir;
|
||||
char **argv;
|
||||
int argc;
|
||||
bool launched_by_launch_services;
|
||||
bool launched_by_launch_services, is_quick_access_terminal;
|
||||
} RunData;
|
||||
|
||||
static bool
|
||||
|
|
@ -70,6 +70,9 @@ set_kitty_run_data(RunData *run_data, bool from_source, wchar_t *extensions_dir)
|
|||
PyObject *lbls = run_data->launched_by_launch_services ? Py_True : Py_False;
|
||||
Py_INCREF(lbls);
|
||||
S(launched_by_launch_services, lbls);
|
||||
lbls = run_data->is_quick_access_terminal ? Py_True : Py_False;
|
||||
Py_INCREF(lbls);
|
||||
S(is_quick_access_terminal_app, lbls);
|
||||
|
||||
char buf[PATH_MAX + 1];
|
||||
if (run_data->config_dir == NULL) {
|
||||
|
|
@ -438,19 +441,33 @@ delegate_to_kitten_if_possible(int argc, char *argv[], char* exe_dir) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
endswith(const char *str, const char *suffix) {
|
||||
size_t strLen = strlen(str);
|
||||
size_t suffixLen = strlen(suffix);
|
||||
if (suffixLen > strLen) return false;
|
||||
return strcmp(str + strLen - suffixLen, suffix) == 0;
|
||||
}
|
||||
|
||||
int main(int argc_, char *argv_[], char* envp[]) {
|
||||
if (argc_ < 1 || !argv_) { fprintf(stderr, "Invalid argc/argv\n"); return 1; }
|
||||
if (!ensure_working_stdio()) return 1;
|
||||
char exe[PATH_MAX+1] = {0};
|
||||
if (!read_exe_path(exe, sizeof(exe))) return 1;
|
||||
char exe_dir_buf[PATH_MAX+1] = {0};
|
||||
strncpy(exe_dir_buf, exe, sizeof(exe_dir_buf));
|
||||
char *exe_dir = dirname(exe_dir_buf);
|
||||
|
||||
RAII_ALLOC(const char, lc_ctype, NULL);
|
||||
bool launched_by_launch_services = false;
|
||||
const char *config_dir = NULL;
|
||||
bool is_quick_access_terminal = false;
|
||||
argv_array argva = {.argv = argv_, .count = argc_};
|
||||
#ifdef __APPLE__
|
||||
lc_ctype = getenv("LC_CTYPE");
|
||||
if (lc_ctype) lc_ctype = strdup(lc_ctype);
|
||||
char abuf[PATH_MAX+1];
|
||||
is_quick_access_terminal = endswith(exe, "/kitty-quick-access");
|
||||
if (getenv("KITTY_LAUNCHED_BY_LAUNCH_SERVICES")) {
|
||||
launched_by_launch_services = true;
|
||||
unsetenv("KITTY_LAUNCHED_BY_LAUNCH_SERVICES");
|
||||
|
|
@ -462,11 +479,10 @@ int main(int argc_, char *argv_[], char* envp[]) {
|
|||
if (!get_argv_from(cbuf, argva.argv[0], &argva)) exit(1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)endswith;
|
||||
#endif
|
||||
(void)read_full_file;
|
||||
if (!read_exe_path(exe, sizeof(exe))) return 1;
|
||||
strncpy(exe_dir_buf, exe, sizeof(exe_dir_buf));
|
||||
char *exe_dir = dirname(exe_dir_buf);
|
||||
if (!delegate_to_kitten_if_possible(argva.count, argva.argv, exe_dir)) handle_fast_commandline(argva.count, argva.argv, NULL);
|
||||
int ret=0;
|
||||
char lib[PATH_MAX+1] = {0};
|
||||
|
|
@ -477,7 +493,7 @@ int main(int argc_, char *argv_[], char* envp[]) {
|
|||
}
|
||||
RunData run_data = {
|
||||
.exe = exe, .exe_dir = exe_dir, .lib_dir = lib, .argc = argva.count, .argv = argva.argv, .lc_ctype = lc_ctype,
|
||||
.launched_by_launch_services=launched_by_launch_services, .config_dir = config_dir,
|
||||
.launched_by_launch_services=launched_by_launch_services, .config_dir = config_dir, .is_quick_access_terminal=is_quick_access_terminal,
|
||||
};
|
||||
ret = run_embedded(&run_data);
|
||||
free_argv_array(&argva);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
clear_handled_signals,
|
||||
glfw_path,
|
||||
is_macos,
|
||||
is_quick_access_terminal_app,
|
||||
is_wayland,
|
||||
kitten_exe,
|
||||
kitty_exe,
|
||||
|
|
@ -62,6 +63,7 @@
|
|||
log_error,
|
||||
parse_os_window_state,
|
||||
safe_mtime,
|
||||
shlex_split,
|
||||
startup_notification_handler,
|
||||
)
|
||||
|
||||
|
|
@ -451,13 +453,10 @@ def set_locale() -> None:
|
|||
set_LANG_in_default_env(old_lang)
|
||||
|
||||
|
||||
def _main() -> None:
|
||||
def kitty_main() -> None:
|
||||
running_in_kitty(True)
|
||||
|
||||
args = sys.argv[1:]
|
||||
if is_macos and launched_by_launch_services:
|
||||
os.chdir(os.path.expanduser('~'))
|
||||
set_use_os_log(True)
|
||||
try:
|
||||
cwd_ok = os.path.isdir(os.getcwd())
|
||||
except Exception:
|
||||
|
|
@ -495,6 +494,8 @@ def _main() -> None:
|
|||
return
|
||||
bad_lines: list[BadLine] = []
|
||||
opts = create_opts(cli_opts, accumulate_bad_lines=bad_lines)
|
||||
if is_quick_access_terminal_app:
|
||||
opts.macos_hide_from_tasks = True
|
||||
setup_environment(opts, cli_opts)
|
||||
|
||||
# set_locale on macOS uses cocoa APIs when LANG is not set, so we have to
|
||||
|
|
@ -524,9 +525,20 @@ def _main() -> None:
|
|||
cleanup_ssh_control_masters()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
||||
def main(called_from_panel: bool = False) -> None:
|
||||
global redirected_for_quick_access
|
||||
try:
|
||||
_main()
|
||||
if is_macos and launched_by_launch_services and not called_from_panel:
|
||||
with suppress(OSError):
|
||||
os.chdir(os.path.expanduser('~'))
|
||||
set_use_os_log(True)
|
||||
if is_quick_access_terminal_app:
|
||||
from kittens.panel.main import default_macos_quake_cmdline
|
||||
from kittens.panel.main import main as panel_main
|
||||
panel_main(list(shlex_split(default_macos_quake_cmdline))[2:])
|
||||
return
|
||||
kitty_main()
|
||||
except Exception:
|
||||
import traceback
|
||||
tb = traceback.format_exc()
|
||||
|
|
|
|||
41
setup.py
41
setup.py
|
|
@ -1486,14 +1486,14 @@ def create_linux_bundle_gunk(ddir: str, args: Options) -> None:
|
|||
os.symlink(os.path.relpath(launcher, os.path.dirname(in_src_launcher)), in_src_launcher)
|
||||
|
||||
|
||||
def macos_info_plist() -> bytes:
|
||||
def macos_info_plist(for_quake: bool = False, quake_desc: str = f'Quick access to {appname}') -> bytes:
|
||||
import plistlib
|
||||
VERSION = '.'.join(map(str, version))
|
||||
|
||||
def access(what: str, verb: str = 'would like to access') -> str:
|
||||
return f'A program running inside kitty {verb} {what}'
|
||||
|
||||
docs = [
|
||||
docs = [] if for_quake else [
|
||||
{
|
||||
'CFBundleTypeName': 'Terminal scripts',
|
||||
'CFBundleTypeExtensions': ['command', 'sh', 'zsh', 'bash', 'fish', 'tool'],
|
||||
|
|
@ -1531,7 +1531,7 @@ def access(what: str, verb: str = 'would like to access') -> str:
|
|||
},
|
||||
]
|
||||
|
||||
url_schemes = [
|
||||
url_schemes = [] if for_quake else [
|
||||
{
|
||||
'CFBundleURLName': 'File URL',
|
||||
'CFBundleURLSchemes': ['file'],
|
||||
|
|
@ -1585,6 +1585,12 @@ def access(what: str, verb: str = 'would like to access') -> str:
|
|||
]
|
||||
|
||||
services = [
|
||||
{
|
||||
'NSMenuItem': {'default': quake_desc},
|
||||
'NSMessage': 'quickAccessTerminal',
|
||||
'NSRequiredContext': {'NSServiceCategory': 'None'},
|
||||
},
|
||||
] if for_quake else [
|
||||
{
|
||||
'NSMenuItem': {'default': f'New {appname} Tab Here'},
|
||||
'NSMessage': 'openTab',
|
||||
|
|
@ -1607,10 +1613,10 @@ def access(what: str, verb: str = 'would like to access') -> str:
|
|||
|
||||
pl = dict(
|
||||
# Naming
|
||||
CFBundleName=appname,
|
||||
CFBundleDisplayName=appname,
|
||||
CFBundleName=f'{appname}-quick-access' if for_quake else appname,
|
||||
CFBundleDisplayName=f'{appname}-quick-access' if for_quake else appname,
|
||||
# Identification
|
||||
CFBundleIdentifier=f'net.kovidgoyal.{appname}',
|
||||
CFBundleIdentifier=f'net.kovidgoyal.{appname}' + ('-quick-access' if for_quake else ''),
|
||||
# Bundle Version Info
|
||||
CFBundleVersion=VERSION,
|
||||
CFBundleShortVersionString=VERSION,
|
||||
|
|
@ -1624,7 +1630,7 @@ def access(what: str, verb: str = 'would like to access') -> str:
|
|||
CFBundleSignature='????',
|
||||
LSApplicationCategoryType='public.app-category.utilities',
|
||||
# App Execution
|
||||
CFBundleExecutable=appname,
|
||||
CFBundleExecutable='kitty-quick-access' if for_quake else appname,
|
||||
LSEnvironment={'KITTY_LAUNCHED_BY_LAUNCH_SERVICES': '1'},
|
||||
LSRequiresNativeExecution=True,
|
||||
NSSupportsSuddenTermination=False,
|
||||
|
|
@ -1670,6 +1676,9 @@ def access(what: str, verb: str = 'would like to access') -> str:
|
|||
# Speech
|
||||
NSSpeechRecognitionUsageDescription=access('speech recognition.'),
|
||||
)
|
||||
if for_quake:
|
||||
# exclude from dock and menubar
|
||||
pl['LSBackgroundOnly'] = True
|
||||
return plistlib.dumps(pl)
|
||||
|
||||
|
||||
|
|
@ -1694,6 +1703,22 @@ def create_macos_app_icon(where: str = 'Resources') -> None:
|
|||
]])
|
||||
|
||||
|
||||
def create_quick_access_bundle(kapp: str) -> None:
|
||||
qapp = os.path.join(kapp, 'Contents', 'kitty-quick-access.app')
|
||||
base_exe_dir = os.path.join(kapp, 'Contents/MacOS')
|
||||
if os.path.exists(qapp):
|
||||
shutil.rmtree(qapp)
|
||||
bin_dir = os.path.join(qapp, 'Contents/MacOS')
|
||||
os.makedirs(bin_dir)
|
||||
with open(os.path.join(qapp, 'Contents/Info.plist'), 'wb') as f:
|
||||
f.write(macos_info_plist(for_quake=True, quake_desc=f'Quick access to {appname} built from source'))
|
||||
for exe in os.listdir(base_exe_dir):
|
||||
os.symlink(f'../../../MacOS/{exe}', os.path.join(bin_dir, exe))
|
||||
shutil.copy2(os.path.join(base_exe_dir, 'kitty'), os.path.join(bin_dir, 'kitty-quick-access'))
|
||||
for x in ('Frameworks', 'Resources'):
|
||||
os.symlink(f'../../{x}', os.path.join(qapp, 'Contents', x))
|
||||
|
||||
|
||||
def create_minimal_macos_bundle(args: Options, launcher_dir: str, relocate: bool = False) -> None:
|
||||
kapp = os.path.join(launcher_dir, 'kitty.app')
|
||||
if os.path.exists(kapp):
|
||||
|
|
@ -1715,6 +1740,7 @@ def create_minimal_macos_bundle(args: Options, launcher_dir: str, relocate: bool
|
|||
os.remove(kitty_exe)
|
||||
os.symlink(os.path.join(os.path.relpath(bin_dir, launcher_dir), appname), kitty_exe)
|
||||
create_macos_app_icon(resources_dir)
|
||||
create_quick_access_bundle(kapp)
|
||||
|
||||
|
||||
def create_macos_bundle_gunk(dest: str, for_freeze: bool, args: Options) -> str:
|
||||
|
|
@ -1741,6 +1767,7 @@ def create_macos_bundle_gunk(dest: str, for_freeze: bool, args: Options) -> str:
|
|||
raise SystemExit('kitten not built cannot create macOS bundle')
|
||||
os.symlink(os.path.relpath(kitten_exe, os.path.dirname(in_src_launcher)),
|
||||
os.path.join(os.path.dirname(in_src_launcher), os.path.basename(kitten_exe)))
|
||||
create_quick_access_bundle(dest)
|
||||
return str(kitty_exe)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue