From 511cb7b0b9d5d2463539ca3d0cc438f7f1dce572 Mon Sep 17 00:00:00 2001 From: Aleksei Gmitron Date: Thu, 11 Jun 2026 09:28:02 +0400 Subject: [PATCH] wip: add `--layer=shell` for menu bars --- glfw/cocoa_window.m | 4 +--- glfw/glfw3.h | 2 +- glfw/wl_window.c | 3 ++- glfw/x11_window.c | 4 ++-- kittens/panel/main.py | 2 ++ kitty/glfw-wrapper.h | 2 +- kitty/glfw.c | 4 ++-- kitty/simple_cli_definitions.py | 7 ++++--- 8 files changed, 15 insertions(+), 13 deletions(-) diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index 04bba77c6..d2a24592e 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -2698,13 +2698,11 @@ _glfwPlatformSetLayerShellConfig(_GLFWwindow* window, const GLFWLayerShellConfig // See: https://stackoverflow.com/questions/4982584/how-do-i-draw-the-desktop-on-mac-os-x/4982619#4982619 level = kCGDesktopWindowLevel; break; + case GLFW_LAYER_SHELL_DESKTOP_SHELL: level = kCGBackstopMenuLevel; break; case GLFW_LAYER_SHELL_OVERLAY: case GLFW_LAYER_SHELL_NONE: break; case GLFW_LAYER_SHELL_PANEL: level = NSNormalWindowLevel - 1; break; case GLFW_LAYER_SHELL_TOP: level--; break; } - if (config.use_physical_screen_frame && config.type == GLFW_LAYER_SHELL_OVERLAY && config.edge == GLFW_EDGE_TOP) { - level = NSMainMenuWindowLevel + 1; - } if (config.type != GLFW_LAYER_SHELL_BACKGROUND && config.edge != GLFW_EDGE_CENTER) { double panel_height = spacing_y + ysz / yscale, panel_width = spacing_x + xsz / xscale; switch (config.edge) { diff --git a/glfw/glfw3.h b/glfw/glfw3.h index 07e975d60..e9ee195e9 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -1349,7 +1349,7 @@ typedef struct GLFWkeyevent bool fake_event_on_focus_change; } GLFWkeyevent; -typedef enum { GLFW_LAYER_SHELL_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL, GLFW_LAYER_SHELL_TOP, GLFW_LAYER_SHELL_OVERLAY } GLFWLayerShellType; +typedef enum { GLFW_LAYER_SHELL_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL, GLFW_LAYER_SHELL_TOP, GLFW_LAYER_SHELL_DESKTOP_SHELL, GLFW_LAYER_SHELL_OVERLAY } GLFWLayerShellType; typedef enum { GLFW_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT, GLFW_EDGE_CENTER, GLFW_EDGE_NONE, GLFW_EDGE_CENTER_SIZED } GLFWEdge; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index d8cc01a6a..af5e3accc 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -1020,7 +1020,7 @@ get_layer_shell_layer(const _GLFWwindow *window) { case GLFW_LAYER_SHELL_BACKGROUND: case GLFW_LAYER_SHELL_NONE: break; case GLFW_LAYER_SHELL_PANEL: which_layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; break; case GLFW_LAYER_SHELL_TOP: which_layer = ZWLR_LAYER_SHELL_V1_LAYER_TOP; break; - case GLFW_LAYER_SHELL_OVERLAY: which_layer = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; break; + case GLFW_LAYER_SHELL_DESKTOP_SHELL: case GLFW_LAYER_SHELL_OVERLAY: which_layer = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; break; } return which_layer; } @@ -1043,6 +1043,7 @@ layer_set_properties(const _GLFWwindow *window, bool during_creation, uint32_t w case GLFW_LAYER_SHELL_NONE: break; case GLFW_LAYER_SHELL_BACKGROUND: exclusive_zone = -1; break; case GLFW_LAYER_SHELL_TOP: + case GLFW_LAYER_SHELL_DESKTOP_SHELL: case GLFW_LAYER_SHELL_OVERLAY: case GLFW_LAYER_SHELL_PANEL: switch (config.edge) { diff --git a/glfw/x11_window.c b/glfw/x11_window.c index 8fa76f53b..b3ea14e07 100644 --- a/glfw/x11_window.c +++ b/glfw/x11_window.c @@ -644,7 +644,7 @@ calculate_layer_geometry(_GLFWwindow *window) { double xsz = config.x_size_in_pixels ? (unsigned)(config.x_size_in_pixels * xscale) : (cell_width * config.x_size_in_cells); double ysz = config.y_size_in_pixels ? (unsigned)(config.y_size_in_pixels * yscale) : (cell_height * config.y_size_in_cells); ans.width = (int)(1. + spacing_x + xsz); ans.height = (int)(1. + spacing_y + ysz); - GeometryRect m = config.type == GLFW_LAYER_SHELL_TOP || config.type == GLFW_LAYER_SHELL_OVERLAY ? mg.workarea : mg.full; + GeometryRect m = config.type == GLFW_LAYER_SHELL_TOP || config.type == GLFW_LAYER_SHELL_DESKTOP_SHELL || config.type == GLFW_LAYER_SHELL_OVERLAY ? mg.workarea : mg.full; static const struct { unsigned left, right, top, bottom, left_start_y, left_end_y, right_start_y, right_end_y, top_start_x, top_end_x, bottom_start_x, bottom_end_x; } s = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; @@ -762,7 +762,7 @@ update_wm_hints(_GLFWwindow *window, const WindowGeometry *wg, const _GLFWwndcon // i3 does not support NET_WM_STATE_BELOW but panels work without it if (_glfw.x11.NET_WM_STATE_BELOW) { S(NET_WM_STATE_BELOW); } break; - case GLFW_LAYER_SHELL_TOP: case GLFW_LAYER_SHELL_OVERLAY: S(NET_WM_STATE_ABOVE); break; + case GLFW_LAYER_SHELL_TOP: case GLFW_LAYER_SHELL_DESKTOP_SHELL: case GLFW_LAYER_SHELL_OVERLAY: S(NET_WM_STATE_ABOVE); break; } #undef S } else if (wndconfig) { diff --git a/kittens/panel/main.py b/kittens/panel/main.py index 2720463dc..895800385 100644 --- a/kittens/panel/main.py +++ b/kittens/panel/main.py @@ -26,6 +26,7 @@ from kitty.fast_data_types import ( GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_OVERLAY, GLFW_LAYER_SHELL_PANEL, + GLFW_LAYER_SHELL_DESKTOP_SHELL, GLFW_LAYER_SHELL_TOP, layer_shell_config_for_os_window, set_layer_shell_config, @@ -69,6 +70,7 @@ def layer_shell_config(opts: PanelCLIOptions) -> LayerShellConfig: 'background': GLFW_LAYER_SHELL_BACKGROUND, 'bottom': GLFW_LAYER_SHELL_PANEL, 'top': GLFW_LAYER_SHELL_TOP, + 'shell': GLFW_LAYER_SHELL_DESKTOP_SHELL, 'overlay': GLFW_LAYER_SHELL_OVERLAY }.get(opts.layer, GLFW_LAYER_SHELL_PANEL) ltype = GLFW_LAYER_SHELL_BACKGROUND if opts.edge == 'background' else ltype diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index ffb9398e8..ed1149ae1 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -1077,7 +1077,7 @@ typedef struct GLFWkeyevent bool fake_event_on_focus_change; } GLFWkeyevent; -typedef enum { GLFW_LAYER_SHELL_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL, GLFW_LAYER_SHELL_TOP, GLFW_LAYER_SHELL_OVERLAY } GLFWLayerShellType; +typedef enum { GLFW_LAYER_SHELL_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL, GLFW_LAYER_SHELL_TOP, GLFW_LAYER_SHELL_DESKTOP_SHELL, GLFW_LAYER_SHELL_OVERLAY } GLFWLayerShellType; typedef enum { GLFW_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT, GLFW_EDGE_CENTER, GLFW_EDGE_NONE, GLFW_EDGE_CENTER_SIZED } GLFWEdge; diff --git a/kitty/glfw.c b/kitty/glfw.c index 1d78bc71b..362f766ee 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -1372,7 +1372,7 @@ toggle_fullscreen_for_os_window(OSWindow *w) { if (!prev) return false; GLFWLayerShellConfig lsc; memcpy(&lsc, prev, sizeof(lsc)); - if (prev->type == GLFW_LAYER_SHELL_OVERLAY || prev->type == GLFW_LAYER_SHELL_TOP) { + if (prev->type == GLFW_LAYER_SHELL_OVERLAY || prev->type == GLFW_LAYER_SHELL_DESKTOP_SHELL || prev->type == GLFW_LAYER_SHELL_TOP) { if (prev->was_toggled_to_fullscreen) { lsc.edge = prev->previous.edge; lsc.requested_bottom_margin = prev->previous.requested_bottom_margin; @@ -3262,7 +3262,7 @@ init_glfw(PyObject *m) { ADDC(GLFW_REPEAT); ADDC(true); ADDC(false); ADDC(GLFW_PRIMARY_SELECTION); ADDC(GLFW_CLIPBOARD); - ADDC(GLFW_LAYER_SHELL_NONE); ADDC(GLFW_LAYER_SHELL_PANEL); ADDC(GLFW_LAYER_SHELL_BACKGROUND); ADDC(GLFW_LAYER_SHELL_TOP); ADDC(GLFW_LAYER_SHELL_OVERLAY); + ADDC(GLFW_LAYER_SHELL_NONE); ADDC(GLFW_LAYER_SHELL_PANEL); ADDC(GLFW_LAYER_SHELL_BACKGROUND); ADDC(GLFW_LAYER_SHELL_TOP); ADDC(GLFW_LAYER_SHELL_DESKTOP_SHELL); ADDC(GLFW_LAYER_SHELL_OVERLAY); ADDC(GLFW_FOCUS_NOT_ALLOWED); ADDC(GLFW_FOCUS_EXCLUSIVE); ADDC(GLFW_FOCUS_ON_DEMAND); ADDC(GLFW_EDGE_TOP); ADDC(GLFW_EDGE_BOTTOM); ADDC(GLFW_EDGE_LEFT); ADDC(GLFW_EDGE_RIGHT); ADDC(GLFW_EDGE_CENTER); ADDC(GLFW_EDGE_NONE); ADDC(GLFW_EDGE_CENTER_SIZED); diff --git a/kitty/simple_cli_definitions.py b/kitty/simple_cli_definitions.py index 78a305418..b5b41d46b 100644 --- a/kitty/simple_cli_definitions.py +++ b/kitty/simple_cli_definitions.py @@ -639,19 +639,20 @@ that the panel is centered instead of in the top left corner and the margins hav --layer -choices=background,bottom,top,overlay +choices=background,bottom,top,shell,overlay default={layer} On a Wayland compositor that supports the wlr layer shell protocol, specifies the layer on which the panel should be drawn. This parameter is ignored and set to :code:`background` if :option:`--edge` is set to :code:`background`. On macOS, maps -these to appropriate NSWindow *levels*. +these to appropriate NSWindow *levels*. On macOS, :code:`shell` places the panel +above normal application windows but below native system UI such as the menu bar. --use-physical-screen-frame type=bool-set default={use_physical_screen_frame} On macOS, use the physical screen frame rather than the visible frame when placing the panel. -This allows top overlay panels to draw over the native menu bar. Ignored on other platforms. +This allows panels to draw in areas reserved for the native menu bar or dock. Ignored on other platforms. --config -c