diff --git a/docs/changelog.rst b/docs/changelog.rst index 720bda3c1..bd8d005eb 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -97,6 +97,8 @@ Detailed list of changes 0.42.0 [future] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- launch: Allow creating desktop panels such as those created by the :doc:`panel kitten ` (:iss:`8459`) + - Allow configuring the mouse unhide behavior when using :opt:`mouse_hide_wait` (:pull:`8508`) - diff kitten: Add half page and full page scroll vim-like bindings (:pull:`8514`) @@ -109,6 +111,7 @@ Detailed list of changes - panel kitten: Allow specifying panel size in pixels in addition to cells + 0.41.1 [2025-04-03] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 018105366..f78ff2f54 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -1446,6 +1446,9 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) if (window->wl.xdg.surface) xdg_surface_destroy(window->wl.xdg.surface); + if (window->wl.layer_shell.zwlr_layer_surface_v1) + zwlr_layer_surface_v1_destroy(window->wl.layer_shell.zwlr_layer_surface_v1); + if (window->wl.surface) wl_surface_destroy(window->wl.surface); diff --git a/kitty/boss.py b/kitty/boss.py index b6d4d304a..89ac62fcd 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -86,6 +86,7 @@ from .fast_data_types import ( get_options, get_os_window_size, global_font_size, + is_layer_shell_supported, last_focused_os_window_id, mark_os_window_for_close, monitor_pid, @@ -120,7 +121,7 @@ from .os_window_size import initial_window_size_func from .session import Session, create_sessions, get_os_window_sizing_data from .shaders import load_shader_programs from .tabs import SpecialWindow, SpecialWindowInstance, Tab, TabDict, TabManager -from .types import _T, AsyncResponse, SingleInstanceData, WindowSystemMouseEvent, ac +from .types import _T, AsyncResponse, LayerShellConfig, SingleInstanceData, WindowSystemMouseEvent, ac from .typing import PopenType, TypedDict from .utils import ( cleanup_ssh_control_masters, @@ -455,6 +456,18 @@ class Boss: self.os_window_map[os_window_id] = tm return os_window_id + def add_os_panel(self, cfg: LayerShellConfig, wclass: str | None = appname, wname: str | None = appname) -> int: + if is_macos or not is_wayland() or not is_layer_shell_supported(): + raise RuntimeError('Creating desktop panels is not supported on this platform') + wclass = wclass or appname + wname = wname or appname + size_data = get_os_window_sizing_data(get_options(), None) + os_window_id = create_os_window( + initial_window_size_func(size_data, {}), lambda *a: None, appname, wname, wclass, None, layer_shell_config=cfg) + tm = TabManager(os_window_id, self.args, wclass, wname, None) + self.os_window_map[os_window_id] = tm + return os_window_id + def list_os_windows( self, self_window: Window | None = None, tab_filter: Callable[[Tab], bool] | None = None, diff --git a/kitty/launch.py b/kitty/launch.py index e7c10233e..c29b8bcd5 100644 --- a/kitty/launch.py +++ b/kitty/launch.py @@ -16,7 +16,7 @@ from .clipboard import set_clipboard_string, set_primary_selection from .fast_data_types import add_timer, get_boss, get_options, get_os_window_title, patch_color_profiles from .options.utils import env as parse_env from .tabs import Tab, TabManager -from .types import OverlayType, run_once +from .types import LayerShellConfig, OverlayType, run_once from .utils import get_editor, log_error, resolve_custom_file, which from .window import CwdRequest, CwdRequestType, Watchers, Window @@ -81,7 +81,7 @@ of the active window in the tab is used as the tab title. The special value --type type=choices default=window -choices=window,tab,os-window,overlay,overlay-main,background,clipboard,primary +choices=window,tab,os-window,os-panel,overlay,overlay-main,background,clipboard,primary Where to launch the child process: :code:`window` @@ -116,6 +116,11 @@ Where to launch the child process: These two are meant to work with :option:`--stdin-source ` to copy data to the :italic:`system clipboard` or :italic:`primary selection`. +:code:`os-panel` + Similar to :code:`os-window`, except that it creates the new OS Window as a desktop panel. + Only works on platforms that support this, such as Wayand compositors that support the layer + shell protocol. Use the :option:`kitten @ launch --os-panel` option to configure the panel. + #placeholder_for_formatting# @@ -378,6 +383,15 @@ the section on watchers in the launch command documentation: :ref:`watchers`. Relative paths are resolved relative to the :ref:`kitty config directory `. Global watchers for all windows can be specified with :opt:`watcher` in :file:`kitty.conf`. + + +--os-panel +type=list +Options to control the creation of desktop panels. Takes the same settings +as the :doc:`panel kitten `. Can be specified multiple times. +For example, to create a desktop panel at the bottom of the screen two lines high:: + + launch --type os-panel --os-panel lines=2 --os-panel edge=bottom sh -c "echo; echo; echo hello; sleep 5s" """ @@ -402,15 +416,25 @@ def get_env(opts: LaunchCLIOptions, active_child: Child | None = None, base_env: return env +def layer_shell_config_from_panel_opts(panel_opts: Iterable[str]) -> LayerShellConfig: + from kittens.panel.main import layer_shell_config, parse_panel_args + args = [('' if x.startswith('--') else '--') + x for x in panel_opts] + opts, _ = parse_panel_args(args) + return layer_shell_config(opts) + + def tab_for_window(boss: Boss, opts: LaunchCLIOptions, target_tab: Tab | None, next_to: Window | None) -> Tab: def create_tab(tm: TabManager | None = None) -> Tab: if tm is None: - oswid = boss.add_os_window( - wclass=opts.os_window_class, - wname=opts.os_window_name, - window_state=opts.os_window_state, - override_title=opts.os_window_title or None) + if opts.type == 'os-panel': + oswid = boss.add_os_panel(layer_shell_config_from_panel_opts(opts.os_panel), opts.os_window_class, opts.os_window_name) + else: + oswid = boss.add_os_window( + wclass=opts.os_window_class, + wname=opts.os_window_name, + window_state=opts.os_window_state, + override_title=opts.os_window_title or None) tm = boss.os_window_map[oswid] tab = tm.new_tab(empty_tab=True, location=opts.location) if opts.tab_title: @@ -424,7 +448,7 @@ def tab_for_window(boss: Boss, opts: LaunchCLIOptions, target_tab: Tab | None, n if target_tab is not None: tm = target_tab.tab_manager_ref() or tm tab = create_tab(tm) - elif opts.type == 'os-window': + elif opts.type in ('os-window', 'os-panel'): tab = create_tab() else: if target_tab is not None: diff --git a/kitty/rc/launch.py b/kitty/rc/launch.py index 6f6097cf9..37f95129d 100644 --- a/kitty/rc/launch.py +++ b/kitty/rc/launch.py @@ -26,8 +26,9 @@ class Launch(RemoteCommand): cwd/str: Working directory for the new window env/list.str: List of environment variables of the form NAME=VALUE var/list.str: List of user variables of the form NAME=VALUE + os_panel/list.str: List of panel settings tab_title/str: Title for the new tab - type/choices.window.tab.os-window.overlay.overlay-main.background.clipboard.primary: The type of window to open + type/choices.window.tab.os-window.os-panel.overlay.overlay-main.background.clipboard.primary: The type of window to open keep_focus/bool: Boolean indicating whether the current window should retain focus or not copy_colors/bool: Boolean indicating whether to copy the colors from the current window copy_cmdline/bool: Boolean indicating whether to copy the cmdline from the current window