launch: Allow creating desktop panels

Now users can use mappings or remote control to popup new desktop panels
on Wayland in addition to new desktop windows.

Fixes #8549
This commit is contained in:
Kovid Goyal 2025-04-21 14:55:16 +05:30
parent a8693e45ef
commit 3ce734ce9c
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
5 changed files with 54 additions and 10 deletions

View file

@ -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 </kittens/panel>` (: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]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

3
glfw/wl_window.c vendored
View file

@ -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);

View file

@ -86,6 +86,7 @@
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 .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 @@ def add_os_window(
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,

View file

@ -16,7 +16,7 @@
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 @@ def options_spec() -> str:
--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 @@ def options_spec() -> str:
These two are meant to work with :option:`--stdin-source <launch --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 @@ def options_spec() -> str:
Relative paths are resolved relative to the :ref:`kitty config directory
<confloc>`. 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 </kittens/panel>`. 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 create_tab(tm: TabManager | None = None) -> Tab:
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:

View file

@ -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