From 64b5d2d187dc2212ea42835ec3bb35b1843ccfc0 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 21 Apr 2025 12:32:20 +0530 Subject: [PATCH] More precise error on resize panel attempt --- glfw/glfw.py | 1 + glfw/glfw3.h | 4 ++-- glfw/wl_window.c | 4 ++++ kitty/boss.py | 7 +++++-- kitty/fast_data_types.pyi | 1 + kitty/glfw-wrapper.c | 3 +++ kitty/glfw-wrapper.h | 8 ++++++-- kitty/glfw.c | 11 +++++++---- kitty/rc/resize_os_window.py | 12 ++++++++---- kitty/state.c | 4 ++-- kitty/state.h | 1 + 11 files changed, 40 insertions(+), 16 deletions(-) diff --git a/glfw/glfw.py b/glfw/glfw.py index d0585b5d0..34665dd6b 100755 --- a/glfw/glfw.py +++ b/glfw/glfw.py @@ -325,6 +325,7 @@ def generate_wrappers(glfw_header: str) -> None: void glfwWaylandRedrawCSDWindowTitle(GLFWwindow *handle) bool glfwWaylandIsWindowFullyCreated(GLFWwindow *handle) bool glfwWaylandBeep(GLFWwindow *handle) + GLFWLayerShellConfig* glfwWaylandLayerShellConfig(GLFWwindow *handle) void glfwWaylandSetupLayerShellForNextWindow(const GLFWLayerShellConfig *c) pid_t glfwWaylandCompositorPID(void) unsigned long long glfwDBusUserNotify(const GLFWDBUSNotificationData *n, GLFWDBusnotificationcreatedfun callback, void *data) diff --git a/glfw/glfw3.h b/glfw/glfw3.h index 76b53de29..5517e5fbd 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -1311,8 +1311,8 @@ typedef struct GLFWLayerShellConfig { GLFWEdge edge; char output_name[64]; GLFWFocusPolicy focus_policy; - unsigned x_size_in_cells; - unsigned y_size_in_cells; + unsigned x_size_in_cells, x_size_in_pixels; + unsigned y_size_in_cells, y_size_in_pixels; unsigned requested_top_margin; unsigned requested_left_margin; unsigned requested_bottom_margin; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index e07725845..749bfbc68 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -2830,6 +2830,10 @@ GLFWAPI void glfwWaylandSetupLayerShellForNextWindow(const GLFWLayerShellConfig layer_shell_config_for_next_window = *c; } +GLFWAPI GLFWLayerShellConfig* glfwWaylandLayerShellConfig(GLFWwindow *handle) { + return &((_GLFWwindow*)handle)->wl.layer_shell.config; +} + GLFWAPI bool glfwWaylandIsWindowFullyCreated(GLFWwindow *handle) { return handle != NULL && ((_GLFWwindow*)handle)->wl.window_fully_created; } void diff --git a/kitty/boss.py b/kitty/boss.py index 591379007..b6d4d304a 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -147,6 +147,7 @@ from .window import CommandOutput, CwdRequest, Window if TYPE_CHECKING: + from .fast_data_types import OSWindowSize from .rc.base import ResponseType # }}} @@ -1582,12 +1583,14 @@ class Boss: return None return tab.resize_window_by(window.id, increment, is_horizontal) - def resize_os_window(self, os_window_id: int, width: int, height: int, unit: str, incremental: bool = False) -> None: + def resize_os_window(self, os_window_id: int, width: int, height: int, unit: str, incremental: bool = False, metrics: 'None | OSWindowSize' = None) -> None: if not incremental and (width < 0 or height < 0): return - metrics = get_os_window_size(os_window_id) + metrics = get_os_window_size(os_window_id) if metrics is None else metrics if metrics is None: return + if metrics['is_layer_shell']: + raise TypeError(f'The OS Window {os_window_id} is a panel and cannot be resized') has_window_scaling = is_macos or is_wayland() w, h = get_new_os_window_size(metrics, width, height, unit, incremental, has_window_scaling) set_os_window_size(os_window_id, w, h) diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 0144d3a74..c5c09133b 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -1545,6 +1545,7 @@ class OSWindowSize(TypedDict): ydpi: float cell_width: int cell_height: int + is_layer_shell: bool def mark_os_window_dirty(os_window_id: int) -> None: diff --git a/kitty/glfw-wrapper.c b/kitty/glfw-wrapper.c index b9d3644f2..2e12750a8 100644 --- a/kitty/glfw-wrapper.c +++ b/kitty/glfw-wrapper.c @@ -491,6 +491,9 @@ load_glfw(const char* path) { *(void **) (&glfwWaylandBeep_impl) = dlsym(handle, "glfwWaylandBeep"); if (glfwWaylandBeep_impl == NULL) dlerror(); // clear error indicator + *(void **) (&glfwWaylandLayerShellConfig_impl) = dlsym(handle, "glfwWaylandLayerShellConfig"); + if (glfwWaylandLayerShellConfig_impl == NULL) dlerror(); // clear error indicator + *(void **) (&glfwWaylandSetupLayerShellForNextWindow_impl) = dlsym(handle, "glfwWaylandSetupLayerShellForNextWindow"); if (glfwWaylandSetupLayerShellForNextWindow_impl == NULL) dlerror(); // clear error indicator diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index 2e1832c14..248260bab 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -1049,8 +1049,8 @@ typedef struct GLFWLayerShellConfig { GLFWEdge edge; char output_name[64]; GLFWFocusPolicy focus_policy; - unsigned x_size_in_cells; - unsigned y_size_in_cells; + unsigned x_size_in_cells, x_size_in_pixels; + unsigned y_size_in_cells, y_size_in_pixels; unsigned requested_top_margin; unsigned requested_left_margin; unsigned requested_bottom_margin; @@ -2348,6 +2348,10 @@ typedef bool (*glfwWaylandBeep_func)(GLFWwindow*); GFW_EXTERN glfwWaylandBeep_func glfwWaylandBeep_impl; #define glfwWaylandBeep glfwWaylandBeep_impl +typedef GLFWLayerShellConfig* (*glfwWaylandLayerShellConfig_func)(GLFWwindow*); +GFW_EXTERN glfwWaylandLayerShellConfig_func glfwWaylandLayerShellConfig_impl; +#define glfwWaylandLayerShellConfig glfwWaylandLayerShellConfig_impl + typedef void (*glfwWaylandSetupLayerShellForNextWindow_func)(const GLFWLayerShellConfig*); GFW_EXTERN glfwWaylandSetupLayerShellForNextWindow_func glfwWaylandSetupLayerShellForNextWindow_impl; #define glfwWaylandSetupLayerShellForNextWindow glfwWaylandSetupLayerShellForNextWindow_impl diff --git a/kitty/glfw.c b/kitty/glfw.c index 134a2d481..a3a323744 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -1141,17 +1141,19 @@ 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); 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); spacing *= xdpi / 72.; - spacing += (fonts_data->fcm.cell_width * config->x_size_in_cells) / xscale; + spacing += xsz / xscale; *width = (uint32_t)(1. + spacing); } 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->fcm.cell_height * config->y_size_in_cells) / yscale; + spacing += ysz / yscale; *height = (uint32_t)(1. + spacing); } else if (config->edge == GLFW_EDGE_CENTER) { if (!*width) *width = monitor_width; @@ -1159,10 +1161,10 @@ calculate_layer_shell_window_size( } else { double spacing_x = edge_spacing(GLFW_EDGE_LEFT) + edge_spacing(GLFW_EDGE_RIGHT); spacing_x *= xdpi / 72.; - spacing_x += (fonts_data->fcm.cell_width * config->x_size_in_cells) / xscale; + spacing_x += xsz / xscale; double spacing_y = edge_spacing(GLFW_EDGE_TOP) + edge_spacing(GLFW_EDGE_BOTTOM); spacing_y *= ydpi / 72.; - spacing_y += (fonts_data->fcm.cell_height * config->y_size_in_cells) / yscale; + spacing_y += ysz / yscale; *width = (uint32_t)(1. + spacing_x); *height = (uint32_t)(1. + spacing_y); } @@ -1355,6 +1357,7 @@ create_os_window(PyObject UNUSED *self, PyObject *args, PyObject *kw) { OSWindow *w = add_os_window(); w->handle = glfw_window; w->disallow_title_changes = disallow_override_title; + w->is_layer_shell = is_layer_shell; update_os_window_references(); if (!is_layer_shell) { for (size_t i = 0; i < global_state.num_os_windows; i++) { diff --git a/kitty/rc/resize_os_window.py b/kitty/rc/resize_os_window.py index ca2024416..d2573c43e 100644 --- a/kitty/rc/resize_os_window.py +++ b/kitty/rc/resize_os_window.py @@ -3,6 +3,8 @@ from typing import TYPE_CHECKING +from kitty.fast_data_types import get_os_window_size + from .base import ( MATCH_WINDOW_OPTION, ArgsType, @@ -88,17 +90,19 @@ using this option means that you will not be notified of failures. } def response_from_kitty(self, boss: Boss, window: Window | None, payload_get: PayloadGetType) -> ResponseType: - from kitty.main import is_panel_kitten - if is_panel_kitten(): - raise RemoteControlErrorWithoutTraceback('Resizing of panels created by the panel kitten is not supported') windows = self.windows_for_match_payload(boss, window, payload_get) if windows: ac = payload_get('action') for os_window_id in {w.os_window_id for w in windows if w}: + metrics = get_os_window_size(os_window_id) + if metrics is None: + raise RemoteControlErrorWithoutTraceback(f'The OS Window {os_window_id} does not exist') + if metrics['is_layer_shell']: + raise RemoteControlErrorWithoutTraceback(f'The OS Window {os_window_id} is a panel and cannot be resized') if ac == 'resize': boss.resize_os_window( os_window_id, width=payload_get('width'), height=payload_get('height'), - unit=payload_get('unit'), incremental=payload_get('incremental') + unit=payload_get('unit'), incremental=payload_get('incremental'), metrics=metrics, ) elif ac == 'toggle-fullscreen': boss.toggle_fullscreen(os_window_id) diff --git a/kitty/state.c b/kitty/state.c index 7570d611e..0db978292 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -1123,10 +1123,10 @@ PYWRAP1(get_os_window_size) { get_os_window_size(os_window, &width, &height, &fw, &fh); get_os_window_content_scale(os_window, &xdpi, &ydpi, &xscale, &yscale); unsigned int cell_width = os_window->fonts_data->fcm.cell_width, cell_height = os_window->fonts_data->fcm.cell_height; - return Py_BuildValue("{si si si si sf sf sd sd sI sI}", + return Py_BuildValue("{si si si si sf sf sd sd sI sI sO}", "width", width, "height", height, "framebuffer_width", fw, "framebuffer_height", fh, "xscale", xscale, "yscale", yscale, "xdpi", xdpi, "ydpi", ydpi, - "cell_width", cell_width, "cell_height", cell_height); + "cell_width", cell_width, "cell_height", cell_height, "is_layer_shell", os_window->is_layer_shell ? Py_True : Py_False); END_WITH_OS_WINDOW Py_RETURN_NONE; } diff --git a/kitty/state.h b/kitty/state.h index b192aed2a..5c135219f 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -312,6 +312,7 @@ typedef struct { uint64_t render_calls; id_type last_focused_counter; CloseRequest close_request; + bool is_layer_shell; } OSWindow;