diff --git a/glfw/glfw.py b/glfw/glfw.py index 27453c8fd..6b18a8592 100755 --- a/glfw/glfw.py +++ b/glfw/glfw.py @@ -172,6 +172,8 @@ class Arg: while self.name.startswith('*'): self.name = self.name[1:] self.type = self.type + '*' + if '[' in self.name: + self.type += '[' + self.name.partition('[')[-1] def __repr__(self) -> str: return f'Arg({self.type}, {self.name})' @@ -253,6 +255,7 @@ const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callbac void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler) int glfwSetX11LaunchCommand(GLFWwindow *handle, char **argv, int argc) void glfwSetX11WindowAsDock(int32_t x11_window_id) + void glfwSetX11WindowStrut(int32_t x11_window_id, uint32_t dimensions[12]) '''.splitlines(): if line: functions.append(Function(line.strip(), check_fail=False)) diff --git a/glfw/x11_init.c b/glfw/x11_init.c index dde569f54..40524d0ab 100644 --- a/glfw/x11_init.c +++ b/glfw/x11_init.c @@ -149,6 +149,8 @@ static void detectEWMH(void) getAtomIfSupported(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS"); _glfw.x11.NET_REQUEST_FRAME_EXTENTS = getAtomIfSupported(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS"); + _glfw.x11.NET_WM_STRUT_PARTIAL = + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STRUT_PARTIAL"); XFree(supportedAtoms); } diff --git a/glfw/x11_platform.h b/glfw/x11_platform.h index f2a4621ac..0583a8aa1 100644 --- a/glfw/x11_platform.h +++ b/glfw/x11_platform.h @@ -269,6 +269,7 @@ typedef struct _GLFWlibraryX11 Atom NET_ACTIVE_WINDOW; Atom NET_FRAME_EXTENTS; Atom NET_REQUEST_FRAME_EXTENTS; + Atom NET_WM_STRUT_PARTIAL; Atom MOTIF_WM_HINTS; // Xdnd (drag and drop) atoms diff --git a/glfw/x11_window.c b/glfw/x11_window.c index b979296fc..0cb195c39 100644 --- a/glfw/x11_window.c +++ b/glfw/x11_window.c @@ -3205,3 +3205,10 @@ GLFWAPI void glfwSetX11WindowAsDock(int32_t x11_window_id) { _glfw.x11.NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char*) &type, 1); } + +GLFWAPI void glfwSetX11WindowStrut(int32_t x11_window_id, uint32_t dimensions[12]) { + _GLFW_REQUIRE_INIT(); + XChangeProperty(_glfw.x11.display, x11_window_id, + _glfw.x11.NET_WM_STRUT_PARTIAL, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*) dimensions, 12); +} diff --git a/kittens/panel/main.py b/kittens/panel/main.py index 5cf4a8b98..7c48da032 100644 --- a/kittens/panel/main.py +++ b/kittens/panel/main.py @@ -2,8 +2,6 @@ # License: GPL v3 Copyright: 2018, Kovid Goyal import os -import shutil -import subprocess import sys from typing import Any, Callable, Dict, List, Tuple @@ -66,14 +64,7 @@ def parse_panel_args(args: List[str]) -> Tuple[PanelCLIOptions, List[str]]: return parse_args(args, OPTIONS, usage, help_text, 'kitty +kitten panel', result_class=PanelCLIOptions) -def call_xprop(*cmd: str, silent: bool = False) -> None: - cmd_ = ['xprop'] + list(cmd) - try: - cp = subprocess.run(cmd_, stdout=subprocess.DEVNULL if silent else None) - except FileNotFoundError: - raise SystemExit('You must have the xprop program installed') - if cp.returncode != 0: - raise SystemExit(cp.returncode) +Strut = Tuple[int, int, int, int, int, int, int, int, int, int, int, int] def create_strut( @@ -81,40 +72,33 @@ def create_strut( left: int = 0, right: int = 0, top: int = 0, bottom: int = 0, left_start_y: int = 0, left_end_y: int = 0, right_start_y: int = 0, right_end_y: int = 0, top_start_x: int = 0, top_end_x: int = 0, bottom_start_x: int = 0, bottom_end_x: int = 0 -) -> None: - call_xprop( - '-id', - str(int(win_id)), '-format', '_NET_WM_STRUT_PARTIAL', '32cccccccccccc', - '-set', '_NET_WM_STRUT_PARTIAL', - f'{left},{right},{top},{bottom},' - f'{left_start_y},{left_end_y},{right_start_y},{right_end_y},' - f'{top_start_x},{top_end_x},{bottom_start_x},{bottom_end_x}' - ) +) -> Strut: + return 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 -def create_top_strut(win_id: int, width: int, height: int) -> None: - create_strut(win_id, top=height, top_end_x=width) +def create_top_strut(win_id: int, width: int, height: int) -> Strut: + return create_strut(win_id, top=height, top_end_x=width) -def create_bottom_strut(win_id: int, width: int, height: int) -> None: - create_strut(win_id, bottom=height, bottom_end_x=width) +def create_bottom_strut(win_id: int, width: int, height: int) -> Strut: + return create_strut(win_id, bottom=height, bottom_end_x=width) -def create_left_strut(win_id: int, width: int, height: int) -> None: - create_strut(win_id, left=width, left_end_y=height) +def create_left_strut(win_id: int, width: int, height: int) -> Strut: + return create_strut(win_id, left=width, left_end_y=height) -def create_right_strut(win_id: int, width: int, height: int) -> None: - create_strut(win_id, right=width, right_end_y=height) +def create_right_strut(win_id: int, width: int, height: int) -> Strut: + return create_strut(win_id, right=width, right_end_y=height) window_width = window_height = 0 def setup_x11_window(win_id: int) -> None: - make_x11_window_a_dock_window(win_id) func = globals()[f'create_{args.edge}_strut'] - func(win_id, window_width, window_height) + strut = func(win_id, window_width, window_height) + make_x11_window_a_dock_window(win_id, strut) def initial_window_size_func(opts: WindowSizeData, cached_values: Dict[str, Any]) -> Callable[[int, int, float, float, float, float], Tuple[int, int]]: @@ -138,8 +122,6 @@ def main(sys_args: List[str]) -> None: global args if is_macos or not os.environ.get('DISPLAY'): raise SystemExit('Currently the panel kitten is supported only on X11 desktops') - if not shutil.which('xprop'): - raise SystemExit('The xprop program is required for the panel kitten') args, items = parse_panel_args(sys_args[1:]) if not items: raise SystemExit('You must specify the program to run') diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 3a76946ac..63dabfa96 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -1475,4 +1475,4 @@ def clearenv() -> None: ... def set_clipboard_data_types(ct: int, mime_types: Tuple[str, ...]) -> None: ... def get_clipboard_mime(ct: int, mime: Optional[str], callback: Callable[[bytes], None]) -> None: ... def run_with_activation_token(func: Callable[[str], None]) -> None: ... -def make_x11_window_a_dock_window(x11_window_id: int) -> None: ... +def make_x11_window_a_dock_window(x11_window_id: int, strut: Tuple[int, int, int, int, int, int, int, int, int, int, int, int]) -> None: ... diff --git a/kitty/glfw-wrapper.c b/kitty/glfw-wrapper.c index 16ec6038e..4c76622cc 100644 --- a/kitty/glfw-wrapper.c +++ b/kitty/glfw-wrapper.c @@ -470,6 +470,9 @@ load_glfw(const char* path) { *(void **) (&glfwSetX11WindowAsDock_impl) = dlsym(handle, "glfwSetX11WindowAsDock"); if (glfwSetX11WindowAsDock_impl == NULL) dlerror(); // clear error indicator + *(void **) (&glfwSetX11WindowStrut_impl) = dlsym(handle, "glfwSetX11WindowStrut"); + if (glfwSetX11WindowStrut_impl == NULL) dlerror(); // clear error indicator + return NULL; } diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index c3dcb1637..70ec8f30b 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -2234,4 +2234,8 @@ typedef void (*glfwSetX11WindowAsDock_func)(int32_t); GFW_EXTERN glfwSetX11WindowAsDock_func glfwSetX11WindowAsDock_impl; #define glfwSetX11WindowAsDock glfwSetX11WindowAsDock_impl +typedef void (*glfwSetX11WindowStrut_func)(int32_t, uint32_t[12]); +GFW_EXTERN glfwSetX11WindowStrut_func glfwSetX11WindowStrut_impl; +#define glfwSetX11WindowStrut glfwSetX11WindowStrut_impl + const char* load_glfw(const char* path); diff --git a/kitty/glfw.c b/kitty/glfw.c index 9cf2d5af0..3fa0bc236 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -1690,9 +1690,15 @@ get_clipboard_mime(PyObject *self UNUSED, PyObject *args) { static PyObject* make_x11_window_a_dock_window(PyObject *self UNUSED, PyObject *args UNUSED) { int x11_window_id; - if (!PyArg_ParseTuple(args, "i", &x11_window_id)) return NULL; + PyObject *dims; + if (!PyArg_ParseTuple(args, "iO!", &x11_window_id, &PyTuple_Type, &dims)) return NULL; + if (PyTuple_GET_SIZE(dims) != 12 ) { PyErr_SetString(PyExc_TypeError, "dimesions must be a tuple of length 12"); return NULL; } if (!glfwSetX11WindowAsDock) { PyErr_SetString(PyExc_RuntimeError, "Failed to load glfwGetX11Window"); return NULL; } + uint32_t dimensions[12]; + for (Py_ssize_t i = 0; i < 12; i++) dimensions[i] = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(dims, i)); + if (PyErr_Occurred()) return NULL; glfwSetX11WindowAsDock(x11_window_id); + glfwSetX11WindowStrut(x11_window_id, dimensions); Py_RETURN_NONE; }