From 4eb8e6052f165b32ce7dc7d3f13c25bfff4263f2 Mon Sep 17 00:00:00 2001 From: Robin Carlier <57142648+robin-carlier@users.noreply.github.com> Date: Sat, 23 Nov 2024 15:28:49 +0100 Subject: [PATCH 1/5] Panel: choose the display layer --- glfw/glfw3.h | 2 +- glfw/wl_window.c | 11 +++++++++-- kittens/panel/main.py | 16 +++++++++++++++- kitty/fast_data_types.pyi | 2 ++ kitty/glfw-wrapper.h | 2 +- kitty/glfw.c | 2 +- 6 files changed, 29 insertions(+), 6 deletions(-) diff --git a/glfw/glfw3.h b/glfw/glfw3.h index 446032b6e..f68c34cb8 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -1300,7 +1300,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 } GLFWLayerShellType; +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_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT } GLFWEdge; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index c791a42f6..7910f3295 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -974,6 +974,8 @@ layer_set_properties(_GLFWwindow *window) { int panel_width = 0, panel_height = 0; switch (window->wl.layer_shell.config.type) { case GLFW_LAYER_SHELL_BACKGROUND: break; case GLFW_LAYER_SHELL_NONE: break; + case GLFW_LAYER_SHELL_TOP: + case GLFW_LAYER_SHELL_OVERLAY: case GLFW_LAYER_SHELL_PANEL: switch (window->wl.layer_shell.config.edge) { case GLFW_EDGE_TOP: @@ -1057,8 +1059,13 @@ create_layer_shell_surface(_GLFWwindow *window) { } window->decorated = false; // shell windows must not have decorations struct wl_output *wl_output = find_output_by_name(window->wl.layer_shell.config.output_name); - enum zwlr_layer_shell_v1_layer which_layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND; - if (window->wl.layer_shell.config.type == GLFW_LAYER_SHELL_PANEL) which_layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; + enum zwlr_layer_shell_v1_layer which_layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND; // Default to background + switch (window->wl.layer_shell.config.type) { + case GLFW_LAYER_SHELL_BACKGROUND: break; 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; + } #define ls window->wl.layer_shell.zwlr_layer_surface_v1 ls = zwlr_layer_shell_v1_get_layer_surface( _glfw.wl.zwlr_layer_shell_v1, window->wl.surface, wl_output, which_layer, "kitty"); diff --git a/kittens/panel/main.py b/kittens/panel/main.py index ee64126cb..f2a0b62af 100644 --- a/kittens/panel/main.py +++ b/kittens/panel/main.py @@ -14,6 +14,8 @@ GLFW_EDGE_TOP, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL, + GLFW_LAYER_SHELL_TOP, + GLFW_LAYER_SHELL_OVERLAY, glfw_primary_monitor_size, make_x11_window_a_dock_window, ) @@ -39,6 +41,14 @@ kitten. +--layer +choices=background, bottom, top, overlay +default=bottom +On a 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 --edge is set to :code:`background`. + + --config -c type=list Path to config file to use for kitty when drawing the panel. @@ -150,7 +160,11 @@ def initial_window_size(cell_width: int, cell_height: int, dpi_x: float, dpi_y: def layer_shell_config(opts: PanelCLIOptions) -> LayerShellConfig: - ltype = GLFW_LAYER_SHELL_BACKGROUND if opts.edge == 'background' else GLFW_LAYER_SHELL_PANEL + ltype = {'background': GLFW_LAYER_SHELL_BACKGROUND, + 'bottom': GLFW_LAYER_SHELL_PANEL, + 'top': GLFW_LAYER_SHELL_TOP, + 'overlay': GLFW_LAYER_SHELL_OVERLAY}.get(opts.layer, GLFW_LAYER_SHELL_PANEL) + ltype = GLFW_LAYER_SHELL_BACKGROUND if opts.edge == 'background' else ltype edge = {'top': GLFW_EDGE_TOP, 'bottom': GLFW_EDGE_BOTTOM, 'left': GLFW_EDGE_LEFT, 'right': GLFW_EDGE_RIGHT}.get(opts.edge, GLFW_EDGE_TOP) return LayerShellConfig(type=ltype, edge=edge, size_in_cells=max(1, opts.lines), output_name=opts.output_name or '') diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index acb4cb126..d41313f34 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -14,6 +14,8 @@ from kitty.typing import EdgeLiteral, NotRequired, ReadableBuffer, WriteableBuff # Constants {{{ GLFW_LAYER_SHELL_NONE: int GLFW_LAYER_SHELL_PANEL: int +GLFW_LAYER_SHELL_TOP: int +GLFW_LAYER_SHELL_OVERLAY: int GLFW_LAYER_SHELL_BACKGROUND: int GLFW_EDGE_TOP: int GLFW_EDGE_BOTTOM: int diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index dfc38b6a8..67f6ef698 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -1038,7 +1038,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 } GLFWLayerShellType; +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_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT } GLFWEdge; diff --git a/kitty/glfw.c b/kitty/glfw.c index 01911e630..2a5edc591 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -2351,7 +2351,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_NONE); ADDC(GLFW_LAYER_SHELL_PANEL); ADDC(GLFW_LAYER_SHELL_BACKGROUND); ADDC(GLFW_LAYER_SHELL_TOP); 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_COLOR_SCHEME_NO_PREFERENCE); ADDC(GLFW_COLOR_SCHEME_DARK); ADDC(GLFW_COLOR_SCHEME_LIGHT); From ce2bcbb92da6080e7fff06b13a5e9b443932b7d1 Mon Sep 17 00:00:00 2001 From: Robin Carlier <57142648+robin-carlier@users.noreply.github.com> Date: Sat, 23 Nov 2024 17:31:39 +0100 Subject: [PATCH 2/5] Panel: add a edge=none option --- glfw/glfw3.h | 5 +++-- glfw/wl_window.c | 4 ++++ kittens/panel/main.py | 17 ++++++++++++----- kitty/fast_data_types.pyi | 1 + kitty/glfw-wrapper.h | 5 +++-- kitty/glfw.c | 21 ++++++++++++++++----- kitty/types.py | 3 ++- 7 files changed, 41 insertions(+), 15 deletions(-) diff --git a/glfw/glfw3.h b/glfw/glfw3.h index f68c34cb8..2a7613f9f 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -1302,7 +1302,7 @@ typedef struct 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_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT } GLFWEdge; +typedef enum { GLFW_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT, GLFW_EDGE_NONE } GLFWEdge; typedef enum { GLFW_FOCUS_NOT_ALLOWED, GLFW_FOCUS_EXCLUSIVE, GLFW_FOCUS_ON_DEMAND} GLFWFocusPolicy; @@ -1311,7 +1311,8 @@ typedef struct GLFWLayerShellConfig { GLFWEdge edge; char output_name[64]; GLFWFocusPolicy focus_policy; - unsigned size_in_cells; + unsigned x_size_in_cells; + unsigned y_size_in_cells; void (*size_callback)(GLFWwindow *window, const struct GLFWLayerShellConfig *config, unsigned monitor_width, unsigned monitor_height, uint32_t *width, uint32_t *height); } GLFWLayerShellConfig; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 7910f3295..0eb1be6a0 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -998,6 +998,10 @@ layer_set_properties(_GLFWwindow *window) { panel_width = window->wl.width; exclusive_zone = window->wl.width; break; + case GLFW_EDGE_NONE: + panel_width = window->wl.width; + panel_width = window->wl.height; + break; } } #define surface window->wl.layer_shell.zwlr_layer_surface_v1 diff --git a/kittens/panel/main.py b/kittens/panel/main.py index f2a0b62af..f4a27531f 100644 --- a/kittens/panel/main.py +++ b/kittens/panel/main.py @@ -12,6 +12,7 @@ GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT, GLFW_EDGE_TOP, + GLFW_EDGE_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL, GLFW_LAYER_SHELL_TOP, @@ -24,14 +25,20 @@ from kitty.typing import EdgeLiteral OPTIONS = r''' ---lines --columns +--lines type=int default=1 -The number of lines shown in the panel if horizontal otherwise the number of columns shown in the panel. Ignored for background panels. +The number of lines shown in the panel if horizontal. Ignored for background panels. + + +--columns +type=int +default=1 +The number of columns shown in the panel if vertical. Ignored for background panels. --edge -choices=top,bottom,left,right,background +choices=top,bottom,left,right,background,none default=top Which edge of the screen to place the panel on. Note that some window managers (such as i3) do not support placing docked windows on the left and right edges. @@ -165,8 +172,8 @@ def layer_shell_config(opts: PanelCLIOptions) -> LayerShellConfig: 'top': GLFW_LAYER_SHELL_TOP, 'overlay': GLFW_LAYER_SHELL_OVERLAY}.get(opts.layer, GLFW_LAYER_SHELL_PANEL) ltype = GLFW_LAYER_SHELL_BACKGROUND if opts.edge == 'background' else ltype - edge = {'top': GLFW_EDGE_TOP, 'bottom': GLFW_EDGE_BOTTOM, 'left': GLFW_EDGE_LEFT, 'right': GLFW_EDGE_RIGHT}.get(opts.edge, GLFW_EDGE_TOP) - return LayerShellConfig(type=ltype, edge=edge, size_in_cells=max(1, opts.lines), output_name=opts.output_name or '') + edge = {'top': GLFW_EDGE_TOP, 'bottom': GLFW_EDGE_BOTTOM, 'left': GLFW_EDGE_LEFT, 'right': GLFW_EDGE_RIGHT, 'none': GLFW_EDGE_NONE}.get(opts.edge, GLFW_EDGE_TOP) + return LayerShellConfig(type=ltype, edge=edge, x_size_in_cells=max(1, opts.columns), y_size_in_cells=max(1, opts.lines), output_name=opts.output_name or '') def main(sys_args: List[str]) -> None: diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index d41313f34..122ebb0a1 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -21,6 +21,7 @@ GLFW_EDGE_TOP: int GLFW_EDGE_BOTTOM: int GLFW_EDGE_LEFT: int GLFW_EDGE_RIGHT: int +GLFW_EDGE_NONE: int GLFW_FOCUS_NOT_ALLOWED: int GLFW_FOCUS_EXCLUSIVE: int GLFW_FOCUS_ON_DEMAND: int diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index 67f6ef698..7a71c34c7 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -1040,7 +1040,7 @@ typedef struct 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_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT } GLFWEdge; +typedef enum { GLFW_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT, GLFW_EDGE_NONE } GLFWEdge; typedef enum { GLFW_FOCUS_NOT_ALLOWED, GLFW_FOCUS_EXCLUSIVE, GLFW_FOCUS_ON_DEMAND} GLFWFocusPolicy; @@ -1049,7 +1049,8 @@ typedef struct GLFWLayerShellConfig { GLFWEdge edge; char output_name[64]; GLFWFocusPolicy focus_policy; - unsigned size_in_cells; + unsigned x_size_in_cells; + unsigned y_size_in_cells; void (*size_callback)(GLFWwindow *window, const struct GLFWLayerShellConfig *config, unsigned monitor_width, unsigned monitor_height, uint32_t *width, uint32_t *height); } GLFWLayerShellConfig; diff --git a/kitty/glfw.c b/kitty/glfw.c index 2a5edc591..af761bcf8 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -1029,6 +1029,7 @@ edge_spacing(GLFWEdge which) { case GLFW_EDGE_BOTTOM: edge = "bottom"; break; case GLFW_EDGE_LEFT: edge = "left"; break; case GLFW_EDGE_RIGHT: edge = "right"; break; + case GLFW_EDGE_NONE: edge = "top"; break; } if (!edge_spacing_func) { log_error("Attempt to call edge_spacing() without first setting edge_spacing_func"); @@ -1059,14 +1060,23 @@ calculate_layer_shell_window_size( if (!*height) *height = monitor_height; double spacing = edge_spacing(GLFW_EDGE_LEFT) + edge_spacing(GLFW_EDGE_RIGHT); spacing *= xdpi / 72.; - spacing += (fonts_data->cell_width * config->size_in_cells) / xscale; + spacing += (fonts_data->cell_width * config->x_size_in_cells) / xscale; *width = (uint32_t)(1. + spacing); - } else { + } else if (config->edge == GLFW_EDGE_TOP || config->edge == GLFW_EDGE_BOTTOM) { if (!*width) *width = monitor_width; double spacing = edge_spacing(GLFW_EDGE_TOP) + edge_spacing(GLFW_EDGE_BOTTOM); spacing *= ydpi / 72.; - spacing += (fonts_data->cell_height * config->size_in_cells) / yscale; + spacing += (fonts_data->cell_height * config->y_size_in_cells) / yscale; *height = (uint32_t)(1. + spacing); + } else { + double spacing_x = edge_spacing(GLFW_EDGE_LEFT) + edge_spacing(GLFW_EDGE_RIGHT); + spacing_x *= xdpi / 72.; + spacing_x += (fonts_data->cell_width * config->x_size_in_cells) / xscale; + double spacing_y = edge_spacing(GLFW_EDGE_TOP) + edge_spacing(GLFW_EDGE_BOTTOM); + spacing_y *= ydpi / 72.; + spacing_y += (fonts_data->cell_height * config->y_size_in_cells) / yscale; + *width = (uint32_t)(1. + spacing_x); + *height = (uint32_t)(1. + spacing_y); } } @@ -1078,7 +1088,8 @@ translate_layer_shell_config(PyObject *p, GLFWLayerShellConfig *ans) { A(type, PyLong_Check, PyLong_AsLong); A(edge, PyLong_Check, PyLong_AsLong); A(focus_policy, PyLong_Check, PyLong_AsLong); - A(size_in_cells, PyLong_Check, PyLong_AsLong); + A(x_size_in_cells, PyLong_Check, PyLong_AsLong); + A(y_size_in_cells, PyLong_Check, PyLong_AsLong); #undef A #define A(attr) { \ RAII_PyObject(attr, PyObject_GetAttrString(p, #attr)); if (attr == NULL) return false; \ @@ -2353,7 +2364,7 @@ init_glfw(PyObject *m) { 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_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_TOP); ADDC(GLFW_EDGE_BOTTOM); ADDC(GLFW_EDGE_LEFT); ADDC(GLFW_EDGE_RIGHT); ADDC(GLFW_EDGE_NONE) ADDC(GLFW_COLOR_SCHEME_NO_PREFERENCE); ADDC(GLFW_COLOR_SCHEME_DARK); ADDC(GLFW_COLOR_SCHEME_LIGHT); /* start glfw functional keys (auto generated by gen-key-constants.py do not edit) */ diff --git a/kitty/types.py b/kitty/types.py index 3626f1a3d..abf1a2639 100644 --- a/kitty/types.py +++ b/kitty/types.py @@ -72,7 +72,8 @@ class LayerShellConfig(NamedTuple): edge: int = 0 focus_policy: int = 0 output_name: str = '' - size_in_cells: int = 0 + x_size_in_cells: int = 0 + y_size_in_cells: int = 0 def mod_to_names(mods: int, has_kitty_mod: bool = False, kitty_mod: int = 0) -> Iterator[str]: From 5f1c603220e6f9c117832c68288d018de4d770f1 Mon Sep 17 00:00:00 2001 From: Robin Carlier <57142648+robin-carlier@users.noreply.github.com> Date: Sat, 23 Nov 2024 19:16:03 +0100 Subject: [PATCH 3/5] Panel: add options for margin --- glfw/glfw3.h | 4 ++++ glfw/wl_window.c | 3 ++- kittens/panel/main.py | 43 ++++++++++++++++++++++++++++++++++++++----- kitty/glfw-wrapper.h | 4 ++++ kitty/glfw.c | 10 +++++++--- kitty/types.py | 4 ++++ 6 files changed, 59 insertions(+), 9 deletions(-) diff --git a/glfw/glfw3.h b/glfw/glfw3.h index 2a7613f9f..1976ea8c7 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -1313,6 +1313,10 @@ typedef struct GLFWLayerShellConfig { GLFWFocusPolicy focus_policy; unsigned x_size_in_cells; unsigned y_size_in_cells; + unsigned requested_top_margin; + unsigned requested_left_margin; + unsigned requested_bottom_margin; + unsigned requested_right_margin; void (*size_callback)(GLFWwindow *window, const struct GLFWLayerShellConfig *config, unsigned monitor_width, unsigned monitor_height, uint32_t *width, uint32_t *height); } GLFWLayerShellConfig; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 0eb1be6a0..ac32e91a3 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -999,6 +999,7 @@ layer_set_properties(_GLFWwindow *window) { exclusive_zone = window->wl.width; break; case GLFW_EDGE_NONE: + which_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; // None is anchored to "top left" panel_width = window->wl.width; panel_width = window->wl.height; break; @@ -1010,7 +1011,7 @@ layer_set_properties(_GLFWwindow *window) { debug("Compositor will be informed that layer size: %dx%d viewport: %dx%d at next surface commit\n", panel_width, panel_height, window->wl.width, window->wl.height); zwlr_layer_surface_v1_set_anchor(surface, which_anchor); zwlr_layer_surface_v1_set_exclusive_zone(surface, exclusive_zone); - zwlr_layer_surface_v1_set_margin(surface, 0, 0, 0, 0); + zwlr_layer_surface_v1_set_margin(surface, window->wl.layer_shell.config.requested_top_margin, window->wl.layer_shell.config.requested_right_margin, window->wl.layer_shell.config.requested_bottom_margin, window->wl.layer_shell.config.requested_left_margin); zwlr_layer_surface_v1_set_keyboard_interactivity(surface, focus_policy); #undef surface } diff --git a/kittens/panel/main.py b/kittens/panel/main.py index f4a27531f..a102a83cd 100644 --- a/kittens/panel/main.py +++ b/kittens/panel/main.py @@ -28,13 +28,37 @@ --lines type=int default=1 -The number of lines shown in the panel if horizontal. Ignored for background panels. +The number of lines shown in the panel. Ignored for background and vertical panels. --columns type=int default=1 -The number of columns shown in the panel if vertical. Ignored for background panels. +The number of columns shown in the panel. Ignored for background and horizontal panels. + + +--margin-top +type=int +default=0 +Request a given top margin to the compositor. + + +--margin-left +type=int +default=0 +Request a given left margin to the compositor. + + +--margin-bottom +type=int +default=0 +Request a given bottom margin to the compositor. + + +--margin-right +type=int +default=0 +Request a given right margin to the compositor. --edge @@ -45,7 +69,8 @@ The value :code:`background` means make the panel the "desktop wallpaper". This is only supported on Wayland, not X11 and note that when using sway if you set a background in your sway config it will cover the background drawn using this -kitten. +kitten. The value :code:`none` allow free placement of the window +when combined with explicit margin parameters. --layer @@ -53,7 +78,7 @@ default=bottom On a 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 --edge is set to :code:`background`. +:code:`background` if :option:`--edge` is set to :code:`background`. --config -c @@ -173,7 +198,15 @@ def layer_shell_config(opts: PanelCLIOptions) -> LayerShellConfig: 'overlay': GLFW_LAYER_SHELL_OVERLAY}.get(opts.layer, GLFW_LAYER_SHELL_PANEL) ltype = GLFW_LAYER_SHELL_BACKGROUND if opts.edge == 'background' else ltype edge = {'top': GLFW_EDGE_TOP, 'bottom': GLFW_EDGE_BOTTOM, 'left': GLFW_EDGE_LEFT, 'right': GLFW_EDGE_RIGHT, 'none': GLFW_EDGE_NONE}.get(opts.edge, GLFW_EDGE_TOP) - return LayerShellConfig(type=ltype, edge=edge, x_size_in_cells=max(1, opts.columns), y_size_in_cells=max(1, opts.lines), output_name=opts.output_name or '') + return LayerShellConfig(type=ltype, + edge=edge, + x_size_in_cells=max(1, opts.columns), + y_size_in_cells=max(1, opts.lines), + requested_top_margin=max(0, opts.margin-top), + requested_left_margin=max(0, opts.margin-left), + requested_bottom_margin=max(0, opts.margin-bottom), + requested_right_margin=max(0,opts.margin-right), + output_name=opts.output_name or '') def main(sys_args: List[str]) -> None: diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index 7a71c34c7..8f97338cd 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -1051,6 +1051,10 @@ typedef struct GLFWLayerShellConfig { GLFWFocusPolicy focus_policy; unsigned x_size_in_cells; unsigned y_size_in_cells; + unsigned requested_top_margin; + unsigned requested_left_margin; + unsigned requested_bottom_margin; + unsigned requested_right_margin; void (*size_callback)(GLFWwindow *window, const struct GLFWLayerShellConfig *config, unsigned monitor_width, unsigned monitor_height, uint32_t *width, uint32_t *height); } GLFWLayerShellConfig; diff --git a/kitty/glfw.c b/kitty/glfw.c index af761bcf8..dccaa4934 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -1029,7 +1029,7 @@ edge_spacing(GLFWEdge which) { case GLFW_EDGE_BOTTOM: edge = "bottom"; break; case GLFW_EDGE_LEFT: edge = "left"; break; case GLFW_EDGE_RIGHT: edge = "right"; break; - case GLFW_EDGE_NONE: edge = "top"; break; + case GLFW_EDGE_NONE: edge = "left"; break; // GLFW_EDGE_NONE is considered as "top left" } if (!edge_spacing_func) { log_error("Attempt to call edge_spacing() without first setting edge_spacing_func"); @@ -1069,10 +1069,10 @@ calculate_layer_shell_window_size( spacing += (fonts_data->cell_height * config->y_size_in_cells) / yscale; *height = (uint32_t)(1. + spacing); } else { - double spacing_x = edge_spacing(GLFW_EDGE_LEFT) + edge_spacing(GLFW_EDGE_RIGHT); + double spacing_x = edge_spacing(GLFW_EDGE_LEFT); spacing_x *= xdpi / 72.; spacing_x += (fonts_data->cell_width * config->x_size_in_cells) / xscale; - double spacing_y = edge_spacing(GLFW_EDGE_TOP) + edge_spacing(GLFW_EDGE_BOTTOM); + double spacing_y = edge_spacing(GLFW_EDGE_TOP); spacing_y *= ydpi / 72.; spacing_y += (fonts_data->cell_height * config->y_size_in_cells) / yscale; *width = (uint32_t)(1. + spacing_x); @@ -1090,6 +1090,10 @@ translate_layer_shell_config(PyObject *p, GLFWLayerShellConfig *ans) { A(focus_policy, PyLong_Check, PyLong_AsLong); A(x_size_in_cells, PyLong_Check, PyLong_AsLong); A(y_size_in_cells, PyLong_Check, PyLong_AsLong); + A(requested_top_margin, PyLong_Check, PyLong_AsLong); + A(requested_left_margin, PyLong_Check, PyLong_AsLong); + A(requested_bottom_margin, PyLong_Check, PyLong_AsLong); + A(requested_right_margin, PyLong_Check, PyLong_AsLong); #undef A #define A(attr) { \ RAII_PyObject(attr, PyObject_GetAttrString(p, #attr)); if (attr == NULL) return false; \ diff --git a/kitty/types.py b/kitty/types.py index abf1a2639..4f306c5f6 100644 --- a/kitty/types.py +++ b/kitty/types.py @@ -74,6 +74,10 @@ class LayerShellConfig(NamedTuple): output_name: str = '' x_size_in_cells: int = 0 y_size_in_cells: int = 0 + requested_top_margin: int = 0 + requested_left_margin: int = 0 + requested_bottom_margin: int = 0 + requested_right_margin: int = 0 def mod_to_names(mods: int, has_kitty_mod: bool = False, kitty_mod: int = 0) -> Iterator[str]: From 00d67a655749fea33f361d2167d279c81525eaed Mon Sep 17 00:00:00 2001 From: Robin Carlier <57142648+robin-carlier@users.noreply.github.com> Date: Sat, 23 Nov 2024 21:00:13 +0100 Subject: [PATCH 4/5] Panel: add focus-policy option --- kittens/panel/main.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/kittens/panel/main.py b/kittens/panel/main.py index a102a83cd..33c0743bb 100644 --- a/kittens/panel/main.py +++ b/kittens/panel/main.py @@ -17,6 +17,9 @@ GLFW_LAYER_SHELL_PANEL, GLFW_LAYER_SHELL_TOP, GLFW_LAYER_SHELL_OVERLAY, + GLFW_FOCUS_NOT_ALLOWED, + GLFW_FOCUS_EXCLUSIVE, + GLFW_FOCUS_ON_DEMAND, glfw_primary_monitor_size, make_x11_window_a_dock_window, ) @@ -74,7 +77,7 @@ --layer -choices=background, bottom, top, overlay +choices=background,bottom,top,overlay default=bottom On a 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 @@ -110,6 +113,13 @@ Set the name part of the :italic:`WM_CLASS` property (defaults to using the value from :option:`{appname} --class`) +--focus-policy +choices=not-allowed,exclusive,on-demand +default=not-allowed +On a Wayland compositor that supports the wlr layer shell protocol, specify the focus policy for keyboard +interactivity with the panel. Please refer to the wlr layer shell protocol documentation for more details. + + --debug-rendering type=bool-set For internal debugging use. @@ -198,14 +208,16 @@ def layer_shell_config(opts: PanelCLIOptions) -> LayerShellConfig: 'overlay': GLFW_LAYER_SHELL_OVERLAY}.get(opts.layer, GLFW_LAYER_SHELL_PANEL) ltype = GLFW_LAYER_SHELL_BACKGROUND if opts.edge == 'background' else ltype edge = {'top': GLFW_EDGE_TOP, 'bottom': GLFW_EDGE_BOTTOM, 'left': GLFW_EDGE_LEFT, 'right': GLFW_EDGE_RIGHT, 'none': GLFW_EDGE_NONE}.get(opts.edge, GLFW_EDGE_TOP) + focus_policy = {'not-allowed': GLFW_FOCUS_NOT_ALLOWED, 'exclusive': GLFW_FOCUS_EXCLUSIVE, 'on-demand': GLFW_FOCUS_ON_DEMAND}.get(opts.focus_policy, GLFW_FOCUS_NOT_ALLOWED); return LayerShellConfig(type=ltype, edge=edge, x_size_in_cells=max(1, opts.columns), y_size_in_cells=max(1, opts.lines), - requested_top_margin=max(0, opts.margin-top), - requested_left_margin=max(0, opts.margin-left), - requested_bottom_margin=max(0, opts.margin-bottom), - requested_right_margin=max(0,opts.margin-right), + requested_top_margin=max(0, opts.margin_top), + requested_left_margin=max(0, opts.margin_left), + requested_bottom_margin=max(0, opts.margin_bottom), + requested_right_margin=max(0, opts.margin_right), + focus_policy=focus_policy, output_name=opts.output_name or '') From 2005069f905bb262987e02c30a1ab5d024cbfa71 Mon Sep 17 00:00:00 2001 From: Robin Carlier <57142648+robin-carlier@users.noreply.github.com> Date: Sun, 24 Nov 2024 10:38:51 +0100 Subject: [PATCH 5/5] Panel: fix height, exclusive zone flag, better helptext --- glfw/glfw3.h | 2 ++ glfw/wl_window.c | 15 ++++++++------- kittens/panel/main.py | 29 ++++++++++++++++++++++++++--- kitty/glfw-wrapper.h | 2 ++ kitty/glfw.c | 2 ++ kitty/types.py | 2 ++ 6 files changed, 42 insertions(+), 10 deletions(-) diff --git a/glfw/glfw3.h b/glfw/glfw3.h index 1976ea8c7..f1a30cbcb 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -1317,6 +1317,8 @@ typedef struct GLFWLayerShellConfig { unsigned requested_left_margin; unsigned requested_bottom_margin; unsigned requested_right_margin; + int requested_exclusive_zone; + unsigned override_exclusive_zone; void (*size_callback)(GLFWwindow *window, const struct GLFWLayerShellConfig *config, unsigned monitor_width, unsigned monitor_height, uint32_t *width, uint32_t *height); } GLFWLayerShellConfig; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index ac32e91a3..210e365a7 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -964,7 +964,7 @@ find_output_by_name(const char* name) { static void layer_set_properties(_GLFWwindow *window) { enum zwlr_layer_surface_v1_anchor which_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; - int exclusive_zone = -1; + int exclusive_zone = window->wl.layer_shell.config.requested_exclusive_zone; enum zwlr_layer_surface_v1_keyboard_interactivity focus_policy = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; switch(window->wl.layer_shell.config.focus_policy) { case GLFW_FOCUS_NOT_ALLOWED: focus_policy = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; break; @@ -973,7 +973,8 @@ layer_set_properties(_GLFWwindow *window) { } int panel_width = 0, panel_height = 0; switch (window->wl.layer_shell.config.type) { - case GLFW_LAYER_SHELL_BACKGROUND: break; case GLFW_LAYER_SHELL_NONE: break; + case GLFW_LAYER_SHELL_NONE: break; + case GLFW_LAYER_SHELL_BACKGROUND: exclusive_zone = -1; break; case GLFW_LAYER_SHELL_TOP: case GLFW_LAYER_SHELL_OVERLAY: case GLFW_LAYER_SHELL_PANEL: @@ -981,27 +982,27 @@ layer_set_properties(_GLFWwindow *window) { case GLFW_EDGE_TOP: which_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; panel_height = window->wl.height; - exclusive_zone = window->wl.height; + if (!window->wl.layer_shell.config.override_exclusive_zone) exclusive_zone = window->wl.height; break; case GLFW_EDGE_BOTTOM: which_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; panel_height = window->wl.height; - exclusive_zone = window->wl.height; + if (!window->wl.layer_shell.config.override_exclusive_zone) exclusive_zone = window->wl.height; break; case GLFW_EDGE_LEFT: which_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; panel_width = window->wl.width; - exclusive_zone = window->wl.width; + if (!window->wl.layer_shell.config.override_exclusive_zone) exclusive_zone = window->wl.width; break; case GLFW_EDGE_RIGHT: which_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; panel_width = window->wl.width; - exclusive_zone = window->wl.width; + if (!window->wl.layer_shell.config.override_exclusive_zone) exclusive_zone = window->wl.width; break; case GLFW_EDGE_NONE: which_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; // None is anchored to "top left" panel_width = window->wl.width; - panel_width = window->wl.height; + panel_height = window->wl.height; break; } } diff --git a/kittens/panel/main.py b/kittens/panel/main.py index 33c0743bb..7ff512c64 100644 --- a/kittens/panel/main.py +++ b/kittens/panel/main.py @@ -44,24 +44,28 @@ type=int default=0 Request a given top margin to the compositor. +Only works on a Wayland compositor that supports the wlr layer shell protocol. --margin-left type=int default=0 Request a given left margin to the compositor. +Only works on a Wayland compositor that supports the wlr layer shell protocol. --margin-bottom type=int default=0 Request a given bottom margin to the compositor. +Only works on a Wayland compositor that supports the wlr layer shell protocol. --margin-right type=int default=0 Request a given right margin to the compositor. +Only works on a Wayland compositor that supports the wlr layer shell protocol. --edge @@ -72,14 +76,15 @@ The value :code:`background` means make the panel the "desktop wallpaper". This is only supported on Wayland, not X11 and note that when using sway if you set a background in your sway config it will cover the background drawn using this -kitten. The value :code:`none` allow free placement of the window -when combined with explicit margin parameters. +kitten. +The value :code:`none` anchors the panel to the top left corner by default +and the panel should be placed using margins parameters. --layer choices=background,bottom,top,overlay default=bottom -On a compositor that supports the wlr layer shell protocol, specifies the 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`. @@ -120,6 +125,22 @@ interactivity with the panel. Please refer to the wlr layer shell protocol documentation for more details. +--exclusive-zone +type=int +default=-1 +On a Wayland compositor that supports the wlr layer shell protocol, request a given exclusive zone for the panel. +Please refer to the wlr layer shell documentation for more details on the meaning of exclusive and its value. +If :option:`--edge` is set to anything else than :code:`none`, this flag will not have any effect unless +the flag :option:`--override-exclusive-zone` is also set. +If :option:`--edge` is set to :code:`background`, this option has no effect. + + +--override-exclusive-zone +type=bool-set +On a Wayland compositor that supports the wlr layer shell protocol, override the default exclusive zone. +This has effect only if :option:`--edge` is set to :code:`top`, :code:`left`, :code:`bottom` or :code:`right`. + + --debug-rendering type=bool-set For internal debugging use. @@ -218,6 +239,8 @@ def layer_shell_config(opts: PanelCLIOptions) -> LayerShellConfig: requested_bottom_margin=max(0, opts.margin_bottom), requested_right_margin=max(0, opts.margin_right), focus_policy=focus_policy, + requested_exclusive_zone=opts.exclusive_zone, + override_exclusive_zone=opts.override_exclusive_zone, output_name=opts.output_name or '') diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index 8f97338cd..8b2a0a991 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -1055,6 +1055,8 @@ typedef struct GLFWLayerShellConfig { unsigned requested_left_margin; unsigned requested_bottom_margin; unsigned requested_right_margin; + int requested_exclusive_zone; + unsigned override_exclusive_zone; void (*size_callback)(GLFWwindow *window, const struct GLFWLayerShellConfig *config, unsigned monitor_width, unsigned monitor_height, uint32_t *width, uint32_t *height); } GLFWLayerShellConfig; diff --git a/kitty/glfw.c b/kitty/glfw.c index dccaa4934..6882a70ad 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -1094,6 +1094,8 @@ translate_layer_shell_config(PyObject *p, GLFWLayerShellConfig *ans) { A(requested_left_margin, PyLong_Check, PyLong_AsLong); A(requested_bottom_margin, PyLong_Check, PyLong_AsLong); A(requested_right_margin, PyLong_Check, PyLong_AsLong); + A(requested_exclusive_zone, PyLong_Check, PyLong_AsLong); + A(override_exclusive_zone, PyBool_Check, PyLong_AsLong); #undef A #define A(attr) { \ RAII_PyObject(attr, PyObject_GetAttrString(p, #attr)); if (attr == NULL) return false; \ diff --git a/kitty/types.py b/kitty/types.py index 4f306c5f6..16f908f8b 100644 --- a/kitty/types.py +++ b/kitty/types.py @@ -78,6 +78,8 @@ class LayerShellConfig(NamedTuple): requested_left_margin: int = 0 requested_bottom_margin: int = 0 requested_right_margin: int = 0 + requested_exclusive_zone: int = -1 + override_exclusive_zone: bool = False def mod_to_names(mods: int, has_kitty_mod: bool = False, kitty_mod: int = 0) -> Iterator[str]: