mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-06 09:15:57 +02:00
Implement single-instance for panel kitten
This commit is contained in:
@@ -100,6 +100,8 @@ Detailed list of changes
|
||||
- **Behavior change**: Now kitty does full grapheme segmentation following the
|
||||
Unicode 16 spec when splitting text into cells (:iss:`8533`)
|
||||
|
||||
- panel kitten: Allow using :option:`kitty +kitten panel --single-instance` to create multiple panels in one process (:iss:`8549`)
|
||||
|
||||
- launch: Allow creating desktop panels such as those created by the :doc:`panel kitten </kittens/panel>` (:iss:`8549`)
|
||||
|
||||
- Allow configuring the mouse unhide behavior when using :opt:`mouse_hide_wait` (:pull:`8508`)
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
import sys
|
||||
from collections.abc import Callable
|
||||
from contextlib import suppress
|
||||
from typing import Any
|
||||
from functools import partial
|
||||
from typing import Any, Mapping, Sequence
|
||||
|
||||
from kitty.cli import parse_args
|
||||
from kitty.cli_stub import PanelCLIOptions
|
||||
from kitty.constants import appname, is_macos, is_wayland
|
||||
from kitty.constants import appname, is_macos, is_wayland, kitten_exe
|
||||
from kitty.fast_data_types import (
|
||||
GLFW_EDGE_BOTTOM,
|
||||
GLFW_EDGE_CENTER,
|
||||
@@ -28,7 +29,7 @@ from kitty.fast_data_types import (
|
||||
)
|
||||
from kitty.os_window_size import WindowSizeData, edge_spacing
|
||||
from kitty.types import LayerShellConfig
|
||||
from kitty.typing import EdgeLiteral
|
||||
from kitty.typing import BossType, EdgeLiteral
|
||||
|
||||
OPTIONS = r'''
|
||||
--lines
|
||||
@@ -147,6 +148,19 @@ On a Wayland compositor that supports the wlr layer shell protocol, override the
|
||||
This has effect only if :option:`--edge` is set to :code:`top`, :code:`left`, :code:`bottom` or :code:`right`.
|
||||
|
||||
|
||||
--single-instance -1
|
||||
type=bool-set
|
||||
If specified only a single instance of the panel will run. New
|
||||
invocations will instead create a new top-level window in the existing
|
||||
panel instance.
|
||||
|
||||
|
||||
--instance-group
|
||||
Used in combination with the :option:`--single-instance` option. All
|
||||
panel invocations with the same :option:`--instance-group` will result
|
||||
in new panels being created in the first panel instance within that group.
|
||||
|
||||
|
||||
--debug-rendering
|
||||
type=bool-set
|
||||
For internal debugging use.
|
||||
@@ -277,6 +291,18 @@ def layer_shell_config(opts: PanelCLIOptions) -> LayerShellConfig:
|
||||
output_name=opts.output_name or '')
|
||||
|
||||
|
||||
def handle_single_instance_command(boss: BossType, sys_args: Sequence[str], environ: Mapping[str, str], notify_on_os_window_death: str | None = '') -> None:
|
||||
from kitty.tabs import SpecialWindow
|
||||
args, items = parse_panel_args(list(sys_args[1:]))
|
||||
items = items or [kitten_exe(), 'run-shell']
|
||||
lsc = layer_shell_config(args)
|
||||
os_window_id = boss.add_os_panel(lsc, args.cls, args.name)
|
||||
if notify_on_os_window_death:
|
||||
boss.os_window_death_actions[os_window_id] = partial(boss.notify_on_os_window_death, notify_on_os_window_death)
|
||||
tm = boss.os_window_map[os_window_id]
|
||||
tm.new_tab(SpecialWindow(cmd=items, env=dict(environ)))
|
||||
|
||||
|
||||
def main(sys_args: list[str]) -> None:
|
||||
global args
|
||||
if is_macos:
|
||||
@@ -295,6 +321,8 @@ def main(sys_args: list[str]) -> None:
|
||||
for override in args.override:
|
||||
sys.argv.extend(('--override', override))
|
||||
sys.argv.append('--override=linux_display_server=auto')
|
||||
if args.single_instance:
|
||||
sys.argv.append('--single-instance')
|
||||
sys.argv.extend(items)
|
||||
from kitty.main import main as real_main
|
||||
from kitty.main import run_app
|
||||
|
||||
@@ -841,6 +841,10 @@ class Boss:
|
||||
log_error('Malformed command received over single instance socket, ignoring')
|
||||
return None
|
||||
if isinstance(data, dict) and data.get('cmd') == 'new_instance':
|
||||
if data['args'][0] == 'panel':
|
||||
from kittens.panel.main import handle_single_instance_command
|
||||
handle_single_instance_command(self, data['args'], data['environ'], data.get('notify_on_os_window_death', ''))
|
||||
return None
|
||||
from .cli_stub import CLIOptions
|
||||
startup_id = data['environ'].get('DESKTOP_STARTUP_ID', '')
|
||||
activation_token = data['environ'].get('XDG_ACTIVATION_TOKEN', '')
|
||||
@@ -864,7 +868,7 @@ class Boss:
|
||||
focused_os_window = os_window_id = 0
|
||||
for session in create_sessions(opts, args, respect_cwd=True):
|
||||
if not session.has_non_background_processes:
|
||||
# background only do not create and OS Window
|
||||
# background only do not create an OS Window
|
||||
from .launch import LaunchSpec, launch
|
||||
for tab in session.tabs:
|
||||
for window in tab.windows:
|
||||
|
||||
@@ -352,13 +352,6 @@ exec_kitten(int argc, char *argv[], char *exe_dir) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
delegate_to_kitten_if_possible(int argc, char *argv[], char* exe_dir) {
|
||||
if (argc > 1 && argv[1][0] == '@') exec_kitten(argc, argv, exe_dir);
|
||||
if (argc > 2 && strcmp(argv[1], "+kitten") == 0 && is_wrapped_kitten(argv[2])) exec_kitten(argc - 1, argv + 1, exe_dir);
|
||||
if (argc > 3 && strcmp(argv[1], "+") == 0 && strcmp(argv[2], "kitten") == 0 && is_wrapped_kitten(argv[3])) exec_kitten(argc - 2, argv + 2, exe_dir);
|
||||
}
|
||||
|
||||
static bool
|
||||
is_boolean_flag(const char *x) {
|
||||
static const char *all_boolean_options = KITTY_CLI_BOOL_OPTIONS;
|
||||
@@ -368,7 +361,7 @@ is_boolean_flag(const char *x) {
|
||||
}
|
||||
|
||||
static void
|
||||
handle_fast_commandline(int argc, char *argv[]) {
|
||||
handle_fast_commandline(int argc, char *argv[], const char *instance_group_prefix) {
|
||||
char current_option_expecting_argument[128] = {0};
|
||||
CLIOptions opts = {0};
|
||||
int first_arg = 1;
|
||||
@@ -436,7 +429,36 @@ handle_option_value:
|
||||
exit(0);
|
||||
}
|
||||
unsetenv("KITTY_SI_DATA");
|
||||
if (opts.single_instance) single_instance_main(argc, argv, &opts);
|
||||
if (opts.single_instance) {
|
||||
char igbuf[256];
|
||||
if (instance_group_prefix && instance_group_prefix[0]) {
|
||||
if (opts.instance_group && opts.instance_group[0]) {
|
||||
snprintf(igbuf, sizeof(igbuf), "%s-%s", instance_group_prefix, opts.instance_group ? opts.instance_group : "");
|
||||
opts.instance_group = igbuf;
|
||||
} opts.instance_group = instance_group_prefix;
|
||||
}
|
||||
single_instance_main(argc, argv, &opts);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
delegate_to_kitten_if_possible(int argc, char *argv[], char* exe_dir) {
|
||||
if (argc > 1 && argv[1][0] == '@') exec_kitten(argc, argv, exe_dir);
|
||||
if (argc > 2 && strcmp(argv[1], "+kitten") == 0) {
|
||||
if (is_wrapped_kitten(argv[2])) exec_kitten(argc - 1, argv + 1, exe_dir);
|
||||
if (strcmp(argv[2], "panel") == 0) {
|
||||
handle_fast_commandline(argc - 2, argv + 2, "panel");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (argc > 3 && strcmp(argv[1], "+") == 0 && strcmp(argv[2], "kitten") == 0) {
|
||||
if (is_wrapped_kitten(argv[3])) exec_kitten(argc - 2, argv + 2, exe_dir);
|
||||
if (strcmp(argv[3], "panel") == 0) {
|
||||
handle_fast_commandline(argc - 3, argv + 3, "panel");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[], char* envp[]) {
|
||||
@@ -452,8 +474,7 @@ int main(int argc, char *argv[], char* envp[]) {
|
||||
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);
|
||||
delegate_to_kitten_if_possible(argc, argv, exe_dir);
|
||||
handle_fast_commandline(argc, argv);
|
||||
if (!delegate_to_kitten_if_possible(argc, argv, exe_dir)) handle_fast_commandline(argc, argv, NULL);
|
||||
int num, ret=0;
|
||||
char lib[PATH_MAX+1] = {0};
|
||||
if (KITTY_LIB_PATH[0] == '/') {
|
||||
|
||||
Reference in New Issue
Block a user