diff --git a/docs/changelog.rst b/docs/changelog.rst index accdaf9d5..720bda3c1 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -107,6 +107,8 @@ Detailed list of changes `__ protocol use it to play the default bell sound +- panel kitten: Allow specifying panel size in pixels in addition to cells + 0.41.1 [2025-04-03] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/kittens/panel/main.py b/kittens/panel/main.py index c1b83c497..9336fcacd 100644 --- a/kittens/panel/main.py +++ b/kittens/panel/main.py @@ -3,6 +3,7 @@ import sys from collections.abc import Callable +from contextlib import suppress from typing import Any from kitty.cli import parse_args @@ -31,42 +32,42 @@ from kitty.typing import EdgeLiteral OPTIONS = r''' --lines -type=int default=1 The number of lines shown in the panel. Ignored for background, centered, and vertical panels. +If it has the suffix :code:`px` then it sets the height of the panel in pixels instead of lines. --columns -type=int default=1 The number of columns shown in the panel. Ignored for background, centered, and horizontal panels. +If it has the suffix :code:`px` then it sets the width of the panel in pixels instead of columns. --margin-top type=int default=0 -Request a given top margin to the compositor. +Set the top margin for the panel, in pixels. Has no effect for bottom edge panels. 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. +Set the left margin for the panel, in pixels. Has no effect for right edge panels. 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. +Set the bottom margin for the panel, in pixels. Has no effect for top edge panels. 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. +Set the right margin for the panel, in pixels. Has no effect for left edge panels. Only works on a Wayland compositor that supports the wlr layer shell protocol. @@ -214,27 +215,41 @@ def initial_window_size_func(opts: WindowSizeData, cached_values: dict[str, Any] xscale = yscale = 1 global window_width, window_height monitor_width, monitor_height = glfw_primary_monitor_size() + x = dual_distance(args.columns, min_cell_value_if_no_pixels=1) + rwidth = x[1] if x[1] else (x[0] * cell_width / xscale) + x = dual_distance(args.lines, min_cell_value_if_no_pixels=1) + rheight = x[1] if x[1] else (x[0] * cell_width / yscale) if args.edge in {'left', 'right'}: spacing = es('left') + es('right') - window_width = int(cell_width * args.columns / xscale + (dpi_x / 72) * spacing + 1) + window_width = int(rwidth + (dpi_x / 72) * spacing + 1) window_height = monitor_height elif args.edge in {'top', 'bottom'}: spacing = es('top') + es('bottom') - window_height = int(cell_height * args.lines / yscale + (dpi_y / 72) * spacing + 1) + window_height = int(rheight + (dpi_y / 72) * spacing + 1) window_width = monitor_width elif args.edge in {'background', 'center'}: window_width, window_height = monitor_width, monitor_height else: x_spacing = es('left') + es('right') - window_width = int(cell_width * args.columns / xscale + (dpi_x / 72) * x_spacing + 1) + window_width = int(rwidth + (dpi_x / 72) * x_spacing + 1) y_spacing = es('top') + es('bottom') - window_height = int(cell_height * args.lines / yscale + (dpi_y / 72) * y_spacing + 1) + window_height = int(rheight + (dpi_y / 72) * y_spacing + 1) return window_width, window_height return initial_window_size +def dual_distance(spec: str, min_cell_value_if_no_pixels: int = 0) -> tuple[int, int]: + with suppress(Exception): + return int(spec), 0 + if spec.endswith('px'): + return min_cell_value_if_no_pixels, int(spec[:-2]) + if spec.endswith('c'): + return int(spec[:-1]), 0 + return min_cell_value_if_no_pixels, 0 + + def layer_shell_config(opts: PanelCLIOptions) -> LayerShellConfig: ltype = {'background': GLFW_LAYER_SHELL_BACKGROUND, 'bottom': GLFW_LAYER_SHELL_PANEL, @@ -247,10 +262,11 @@ def layer_shell_config(opts: PanelCLIOptions) -> LayerShellConfig: 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) + x, y = dual_distance(opts.columns, min_cell_value_if_no_pixels=1), dual_distance(opts.lines, min_cell_value_if_no_pixels=1) return LayerShellConfig(type=ltype, edge=edge, - x_size_in_cells=max(1, opts.columns), - y_size_in_cells=max(1, opts.lines), + x_size_in_cells=x[0], x_size_in_pixels=x[1], + y_size_in_cells=y[0], y_size_in_pixels=y[1], requested_top_margin=max(0, opts.margin_top), requested_left_margin=max(0, opts.margin_left), requested_bottom_margin=max(0, opts.margin_bottom), diff --git a/kitty/glfw.c b/kitty/glfw.c index a3a323744..f1b97dae7 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -1141,8 +1141,8 @@ calculate_layer_shell_window_size( OSWindow *os_window = os_window_for_glfw_window(window); debug("Calculating layer shell window size at scale: %f\n", xscale); FONTS_DATA_HANDLE fonts_data = load_fonts_data(os_window ? os_window->fonts_data->font_sz_in_pts : OPT(font_size), xdpi, ydpi); - const unsigned xsz = config->x_size_in_pixels ? config->x_size_in_pixels : (fonts_data->fcm.cell_width * config->x_size_in_cells); - const unsigned ysz = config->y_size_in_pixels ? config->y_size_in_pixels : (fonts_data->fcm.cell_height * config->y_size_in_cells); + const unsigned xsz = config->x_size_in_pixels ? (unsigned)(config->x_size_in_pixels * xscale) : (fonts_data->fcm.cell_width * config->x_size_in_cells); + const unsigned ysz = config->y_size_in_pixels ? (unsigned)(config->y_size_in_pixels * yscale) : (fonts_data->fcm.cell_height * config->y_size_in_cells); if (config->edge == GLFW_EDGE_LEFT || config->edge == GLFW_EDGE_RIGHT) { if (!*height) *height = monitor_height; double spacing = edge_spacing(GLFW_EDGE_LEFT) + edge_spacing(GLFW_EDGE_RIGHT); @@ -1180,6 +1180,8 @@ 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(x_size_in_pixels, PyLong_Check, PyLong_AsLong); + A(y_size_in_pixels, 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); diff --git a/kitty/types.py b/kitty/types.py index 8830586cd..8a2bc3382 100644 --- a/kitty/types.py +++ b/kitty/types.py @@ -72,6 +72,8 @@ class LayerShellConfig(NamedTuple): edge: int = 0 focus_policy: int = 0 output_name: str = '' + x_size_in_pixels: int = 0 + y_size_in_pixels: int = 0 x_size_in_cells: int = 0 y_size_in_cells: int = 0 requested_top_margin: int = 0