From 7c6d40fa0c417fa45e03659db344b1876ce26477 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 27 Jun 2023 14:56:35 +0530 Subject: [PATCH] Implement background blur for KDE on X11 as well --- glfw/glfw.py | 1 + glfw/glfw3.h | 1 + glfw/internal.h | 1 + glfw/window.c | 4 ++++ glfw/x11_init.c | 1 + glfw/x11_platform.h | 2 ++ glfw/x11_window.c | 27 ++++++++++++++++++++++++++- kitty/glfw-wrapper.c | 3 +++ kitty/glfw-wrapper.h | 5 +++++ kitty/glfw.c | 11 ++++++----- kitty/options/definition.py | 3 ++- 11 files changed, 52 insertions(+), 7 deletions(-) diff --git a/glfw/glfw.py b/glfw/glfw.py index d8d4888b8..e77c2dd69 100755 --- a/glfw/glfw.py +++ b/glfw/glfw.py @@ -250,6 +250,7 @@ def generate_wrappers(glfw_header: str) -> None: uint32_t glfwGetCocoaKeyEquivalent(uint32_t glfw_key, int glfw_mods, int* cocoa_mods) void glfwCocoaRequestRenderFrame(GLFWwindow *w, GLFWcocoarenderframefun callback) int glfwCocoaSetBackgroundBlur(GLFWwindow *w, int blur_radius) + bool glfwSetX11WindowBlurred(GLFWwindow *w, bool enable_blur) void* glfwGetX11Display(void) int32_t glfwGetX11Window(GLFWwindow* window) void glfwSetPrimarySelectionString(GLFWwindow* window, const char* string) diff --git a/glfw/glfw3.h b/glfw/glfw3.h index 6ad185df9..ae78fcc71 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -1047,6 +1047,7 @@ typedef enum { * [window hint](@ref GLFW_X11_CLASS_NAME_hint). */ #define GLFW_X11_INSTANCE_NAME 0x00024002 +#define GLFW_X11_BLUR 0x00024003 #define GLFW_WAYLAND_APP_ID 0x00025001 /*! @} */ diff --git a/glfw/internal.h b/glfw/internal.h index 53c777748..a26b043ac 100644 --- a/glfw/internal.h +++ b/glfw/internal.h @@ -319,6 +319,7 @@ struct _GLFWwndconfig struct { char className[256]; char instanceName[256]; + int enable_blur; } x11; struct { char appId[256]; diff --git a/glfw/window.c b/glfw/window.c index 18eb5c723..6899d5751 100644 --- a/glfw/window.c +++ b/glfw/window.c @@ -336,6 +336,7 @@ void glfwDefaultWindowHints(void) _glfw.hints.window.ns.color_space = 0; // no blur _glfw.hints.window.ns.blur_radius = 0; + _glfw.hints.window.x11.enable_blur = 0; } GLFWAPI void glfwWindowHint(int hint, int value) @@ -422,6 +423,9 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_COCOA_BLUR_RADIUS: _glfw.hints.window.ns.blur_radius = value; return; + case GLFW_X11_BLUR: + _glfw.hints.window.x11.enable_blur = value; + return; case GLFW_COCOA_GRAPHICS_SWITCHING: _glfw.hints.context.nsgl.offline = value ? true : false; return; diff --git a/glfw/x11_init.c b/glfw/x11_init.c index 75e6c1a79..fdec2a4ec 100644 --- a/glfw/x11_init.c +++ b/glfw/x11_init.c @@ -651,6 +651,7 @@ int _glfwPlatformInit(void) _glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen); _glfw.x11.context = XUniqueContext(); _glfw.x11.RESOURCE_MANAGER = XInternAtom(_glfw.x11.display, "RESOURCE_MANAGER", True); + _glfw.x11._KDE_NET_WM_BLUR_BEHIND_REGION = None; XSelectInput(_glfw.x11.display, _glfw.x11.root, PropertyChangeMask); _glfwGetSystemContentScaleX11(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY, false); diff --git a/glfw/x11_platform.h b/glfw/x11_platform.h index 0583a8aa1..24ca14fce 100644 --- a/glfw/x11_platform.h +++ b/glfw/x11_platform.h @@ -299,6 +299,8 @@ typedef struct _GLFWlibraryX11 // XRM database atom Atom RESOURCE_MANAGER; + // KDE window blur + Atom _KDE_NET_WM_BLUR_BEHIND_REGION; // Atoms for MIME types AtomArray mime_atoms, clipboard_atoms, primary_atoms; diff --git a/glfw/x11_window.c b/glfw/x11_window.c index 137c69b2b..f4f95224a 100644 --- a/glfw/x11_window.c +++ b/glfw/x11_window.c @@ -64,6 +64,7 @@ // covers GLX functions // static unsigned _glfwDispatchX11Events(void); +GLFWAPI bool glfwSetX11WindowBlurred(GLFWwindow *w, bool enable_blur); static void handleEvents(monotonic_t timeout) { @@ -713,6 +714,10 @@ static bool createNativeWindow(_GLFWwindow* window, _glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos); _glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height); + if (_glfw.hints.window.x11.enable_blur) { + glfwSetX11WindowBlurred((GLFWwindow*)window, 1); + } + return true; } @@ -2687,7 +2692,7 @@ _glfwDispatchX11Events(void) { if (window->x11.lastCursorPosX != width / 2 || window->x11.lastCursorPosY != height / 2) { - _glfwPlatformSetCursorPos(window, width / 2, height / 2); + _glfwPlatformSetCursorPos(window, width / 2.f, height / 2.f); } } @@ -3215,6 +3220,26 @@ GLFWAPI void glfwSetX11WindowAsDock(int32_t x11_window_id) { PropModeReplace, (unsigned char*) &type, 1); } +GLFWAPI bool glfwSetX11WindowBlurred(GLFWwindow *w, bool enable_blur) { + _GLFW_REQUIRE_INIT_OR_RETURN(0); + _GLFWwindow *window = (_GLFWwindow*)w; + if (_glfw.x11._KDE_NET_WM_BLUR_BEHIND_REGION == None) { + _glfw.x11._KDE_NET_WM_BLUR_BEHIND_REGION = XInternAtom(_glfw.x11.display, "_KDE_NET_WM_BLUR_BEHIND_REGION", False); + } + if (_glfw.x11._KDE_NET_WM_BLUR_BEHIND_REGION != None) { + uint32_t data = 0; + if (enable_blur) { + XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11._KDE_NET_WM_BLUR_BEHIND_REGION, + XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &data, 1); + } else { + XDeleteProperty(_glfw.x11.display, window->x11.handle, _glfw.x11._KDE_NET_WM_BLUR_BEHIND_REGION); + } + return true; + } + return false; +} + + GLFWAPI void glfwSetX11WindowStrut(int32_t x11_window_id, uint32_t dimensions[12]) { _GLFW_REQUIRE_INIT(); XChangeProperty(_glfw.x11.display, x11_window_id, diff --git a/kitty/glfw-wrapper.c b/kitty/glfw-wrapper.c index 90227fdc4..281940403 100644 --- a/kitty/glfw-wrapper.c +++ b/kitty/glfw-wrapper.c @@ -446,6 +446,9 @@ load_glfw(const char* path) { *(void **) (&glfwCocoaSetBackgroundBlur_impl) = dlsym(handle, "glfwCocoaSetBackgroundBlur"); if (glfwCocoaSetBackgroundBlur_impl == NULL) dlerror(); // clear error indicator + *(void **) (&glfwSetX11WindowBlurred_impl) = dlsym(handle, "glfwSetX11WindowBlurred"); + if (glfwSetX11WindowBlurred_impl == NULL) dlerror(); // clear error indicator + *(void **) (&glfwGetX11Display_impl) = dlsym(handle, "glfwGetX11Display"); if (glfwGetX11Display_impl == NULL) dlerror(); // clear error indicator diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index ccaa5ed1a..9d7c7913b 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -785,6 +785,7 @@ typedef enum { * [window hint](@ref GLFW_X11_CLASS_NAME_hint). */ #define GLFW_X11_INSTANCE_NAME 0x00024002 +#define GLFW_X11_BLUR 0x00024003 #define GLFW_WAYLAND_APP_ID 0x00025001 /*! @} */ @@ -2224,6 +2225,10 @@ typedef int (*glfwCocoaSetBackgroundBlur_func)(GLFWwindow*, int); GFW_EXTERN glfwCocoaSetBackgroundBlur_func glfwCocoaSetBackgroundBlur_impl; #define glfwCocoaSetBackgroundBlur glfwCocoaSetBackgroundBlur_impl +typedef bool (*glfwSetX11WindowBlurred_func)(GLFWwindow*, bool); +GFW_EXTERN glfwSetX11WindowBlurred_func glfwSetX11WindowBlurred_impl; +#define glfwSetX11WindowBlurred glfwSetX11WindowBlurred_impl + typedef void* (*glfwGetX11Display_func)(void); GFW_EXTERN glfwGetX11Display_func glfwGetX11Display_impl; #define glfwGetX11Display glfwGetX11Display_impl diff --git a/kitty/glfw.c b/kitty/glfw.c index 4b79881ac..651352a86 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -900,14 +900,16 @@ create_os_window(PyObject UNUSED *self, PyObject *args, PyObject *kw) { #endif } + const bool set_blur = OPT(background_blur) > 0 && OPT(background_opacity) < 1.f; #ifdef __APPLE__ glfwWindowHint(GLFW_COCOA_COLOR_SPACE, OPT(macos_colorspace)); - if (OPT(background_blur) > 0 && OPT(background_opacity) < 1.f) { + if (set_blur) { glfwWindowHint(GLFW_COCOA_BLUR_RADIUS, MIN(OPT(background_blur), 128)); } else { glfwWindowHint(GLFW_COCOA_BLUR_RADIUS, 0); } #else + if (!global_state.is_wayland) glfwWindowHint(GLFW_X11_BLUR, set_blur); glfwWindowHintString(GLFW_X11_INSTANCE_NAME, wm_class_name); glfwWindowHintString(GLFW_X11_CLASS_NAME, wm_class_class); glfwWindowHintString(GLFW_WAYLAND_APP_ID, wm_class_class); @@ -1088,12 +1090,11 @@ os_window_update_size_increments(OSWindow *window) { void update_background_blur(OSWindow *os_window) { + const bool should_blur = os_window->background_opacity < 1.f && OPT(background_blur) > 0 && os_window->is_semi_transparent; #ifdef __APPLE__ - int new_blur_radius = 0; - if (os_window->background_opacity < 1.f && OPT(background_blur) > -1) new_blur_radius = OPT(background_blur); - glfwCocoaSetBackgroundBlur(os_window->handle, new_blur_radius); + glfwCocoaSetBackgroundBlur(os_window->handle, should_blur ? OPT(background_blur) : 0); #else - (void)os_window; + if (!global_state.is_wayland) glfwSetX11WindowBlurred(os_window->handle, should_blur); #endif } diff --git a/kitty/options/definition.py b/kitty/options/definition.py index 5a152d210..1b1739248 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -1379,7 +1379,8 @@ when :opt:`background_opacity` is less than one. On macOS, this will also control the :italic:`blur radius` (amount of blurring). Setting it to too high a value will cause severe performance issues and/or rendering artifacts. Usually, values up to 64 work well. Note that this might cause performance issues, -depending on how the platform implements it, so use with care. +depending on how the platform implements it, so use with care. Currently supported +on macOS and KDE/X11. ''') opt('background_image', 'none',