diff --git a/glfw/glfw.py b/glfw/glfw.py index a8ce3c441..96475ac9b 100755 --- a/glfw/glfw.py +++ b/glfw/glfw.py @@ -315,6 +315,7 @@ def generate_wrappers(glfw_header: str) -> None: bool glfwWaylandSetTitlebarColor(GLFWwindow *handle, uint32_t color, bool use_system_color) void glfwWaylandRedrawCSDWindowTitle(GLFWwindow *handle) void glfwWaylandSetupLayerShellForNextWindow(GLFWLayerShellConfig c) + pid_t glfwWaylandCompositorPID(void) unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, \ const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data) void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler) diff --git a/glfw/wl_init.c b/glfw/wl_init.c index cea8e62c4..f4fb7b9bd 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -41,6 +41,7 @@ #include #include #include +#include #include // Needed for the BTN_* defines #ifdef __has_include @@ -815,6 +816,19 @@ GLFWAPI int glfwGetCurrentSystemColorTheme(void) { return glfw_current_system_color_theme(); } +GLFWAPI pid_t glfwWaylandCompositorPID(void) { + if (!_glfw.wl.display) return -1; + int fd = wl_display_get_fd(_glfw.wl.display); + if (fd < 0) return -1; + struct ucred ucred; + socklen_t len = sizeof(struct ucred); + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1) { + perror("getsockopt failed"); + return -1; + } + return ucred.pid; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// diff --git a/kitty/debug_config.py b/kitty/debug_config.py index d765ce096..f7d82b487 100644 --- a/kitty/debug_config.py +++ b/kitty/debug_config.py @@ -14,9 +14,10 @@ from kittens.tui.operations import colored, styled +from .child import cmdline_of_pid from .cli import version from .constants import extensions_dir, is_macos, is_wayland, kitty_base_dir, kitty_exe, shell_path -from .fast_data_types import Color, SingleKey, num_users +from .fast_data_types import Color, SingleKey, num_users, wayland_compositor_pid from .options.types import Options as KittyOpts from .options.types import defaults from .options.utils import KeyboardMode, KeyDefinition @@ -193,6 +194,22 @@ def format_tty_name(raw: str) -> str: return re.sub(r'^/dev/([^/]+)/([^/]+)$', r'\1\2', raw) +def compositor_name() -> str: + ans = 'X11' + if is_wayland(): + ans = 'Wayland' + pid = wayland_compositor_pid() + if pid > -1: + with suppress(Exception): + cmdline = cmdline_of_pid(pid) + exe = cmdline[0] + with suppress(Exception): + import subprocess + exe = subprocess.check_output([exe, '--version']).decode().strip().splitlines()[0] + ans += f' ({exe})' + return ans + + def debug_config(opts: KittyOpts) -> str: from io import StringIO out = StringIO() @@ -219,7 +236,7 @@ def debug_config(opts: KittyOpts) -> str: with open('/etc/lsb-release', encoding='utf-8', errors='replace') as f: p(f.read().strip()) if not is_macos: - p('Running under:', green('Wayland' if is_wayland() else 'X11')) + p('Running under:', green(compositor_name())) p(green('Frozen:'), 'True' if getattr(sys, 'frozen', False) else 'False') p(green('Paths:')) p(yellow(' kitty:'), os.path.realpath(kitty_exe())) diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 695c37b77..257867db1 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -1573,3 +1573,4 @@ def replace_c0_codes_except_nl_space_tab(text: str) -> str:... @overload def replace_c0_codes_except_nl_space_tab(text: Union[bytes, memoryview, bytearray]) -> bytes:... def terminfo_data() -> bytes:... +def wayland_compositor_pid() -> int:... diff --git a/kitty/glfw-wrapper.c b/kitty/glfw-wrapper.c index b6c38a7ad..ceb1855b5 100644 --- a/kitty/glfw-wrapper.c +++ b/kitty/glfw-wrapper.c @@ -482,6 +482,9 @@ load_glfw(const char* path) { *(void **) (&glfwWaylandSetupLayerShellForNextWindow_impl) = dlsym(handle, "glfwWaylandSetupLayerShellForNextWindow"); if (glfwWaylandSetupLayerShellForNextWindow_impl == NULL) dlerror(); // clear error indicator + *(void **) (&glfwWaylandCompositorPID_impl) = dlsym(handle, "glfwWaylandCompositorPID"); + if (glfwWaylandCompositorPID_impl == NULL) dlerror(); // clear error indicator + *(void **) (&glfwDBusUserNotify_impl) = dlsym(handle, "glfwDBusUserNotify"); if (glfwDBusUserNotify_impl == NULL) dlerror(); // clear error indicator diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index 5a10de78b..d5b8e7678 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -2312,6 +2312,10 @@ typedef void (*glfwWaylandSetupLayerShellForNextWindow_func)(GLFWLayerShellConfi GFW_EXTERN glfwWaylandSetupLayerShellForNextWindow_func glfwWaylandSetupLayerShellForNextWindow_impl; #define glfwWaylandSetupLayerShellForNextWindow glfwWaylandSetupLayerShellForNextWindow_impl +typedef pid_t (*glfwWaylandCompositorPID_func)(void); +GFW_EXTERN glfwWaylandCompositorPID_func glfwWaylandCompositorPID_impl; +#define glfwWaylandCompositorPID glfwWaylandCompositorPID_impl + typedef unsigned long long (*glfwDBusUserNotify_func)(const char*, const char*, const char*, const char*, const char*, int32_t, GLFWDBusnotificationcreatedfun, void*); GFW_EXTERN glfwDBusUserNotify_func glfwDBusUserNotify_impl; #define glfwDBusUserNotify glfwDBusUserNotify_impl diff --git a/kitty/glfw.c b/kitty/glfw.c index 0be5268aa..65be2725d 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -1836,6 +1836,16 @@ x11_display(PYNOARG) { Py_RETURN_NONE; } +static PyObject* +wayland_compositor_pid(PYNOARG) { + pid_t ans = -1; + if (global_state.is_wayland && glfwWaylandCompositorPID) { + ans = glfwWaylandCompositorPID(); + } + long long x = ans; + return PyLong_FromLongLong(x); +} + static PyObject* x11_window_id(PyObject UNUSED *self, PyObject *os_wid) { OSWindow *w = os_window_for_id(PyLong_AsUnsignedLongLong(os_wid)); @@ -2216,6 +2226,7 @@ static PyMethodDef module_methods[] = { METHODB(change_os_window_state, METH_VARARGS), METHODB(glfw_window_hint, METH_VARARGS), METHODB(x11_display, METH_NOARGS), + METHODB(wayland_compositor_pid, METH_NOARGS), METHODB(get_click_interval, METH_NOARGS), METHODB(x11_window_id, METH_O), METHODB(make_x11_window_a_dock_window, METH_VARARGS),