Skip to content

Commit

Permalink
Wayland KDE: Add support for background_blur under kwin using a kwin …
Browse files Browse the repository at this point in the history
…private Wayland protocol
  • Loading branch information
kovidgoyal committed Mar 22, 2024
1 parent 9df7460 commit 1c9f9a7
Show file tree
Hide file tree
Showing 16 changed files with 149 additions and 100 deletions.
2 changes: 2 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ Detailed list of changes

- Wayland: Support preferred integer scales

- Wayland KDE: Support :opt:`background_blur`

- A new option :opt:`terminfo_type` to allow passing the terminfo database embedded into the :envvar:`TERMINFO` env var directly instead of via a file

- Mouse reporting: Fix drag release event outside the window not being reported in legacy mouse reporting modes (:iss:`7244`)
Expand Down
30 changes: 14 additions & 16 deletions glfw/cocoa_window.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@

#define debug(...) if (_glfw.hints.init.debugRendering) fprintf(stderr, __VA_ARGS__);

GLFWAPI int glfwCocoaSetBackgroundBlur(GLFWwindow *w, int radius);

static const char*
polymorphic_string_as_utf8(id string) {
if (string == nil) return "(nil)";
Expand Down Expand Up @@ -1868,7 +1866,7 @@ static bool createNativeWindow(_GLFWwindow* window,

_glfwPlatformGetWindowSize(window, &window->ns.width, &window->ns.height);
_glfwPlatformGetFramebufferSize(window, &window->ns.fbWidth, &window->ns.fbHeight);
if (wndconfig->ns.blur_radius > 0) glfwCocoaSetBackgroundBlur((GLFWwindow*)window, wndconfig->ns.blur_radius);
if (wndconfig->blur_radius > 0) _glfwPlatformSetWindowBlur(window, wndconfig->blur_radius);

return true;
}
Expand Down Expand Up @@ -2986,6 +2984,18 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
#endif
}

int
_glfwPlatformSetWindowBlur(_GLFWwindow *window, int radius) {
int orig = window->ns.blur_radius;
if (radius > -1 && radius != window->ns.blur_radius) {
extern OSStatus CGSSetWindowBackgroundBlurRadius(void* connection, NSInteger windowNumber, int radius);
extern void* CGSDefaultConnectionForThread(void);
CGSSetWindowBackgroundBlurRadius(CGSDefaultConnectionForThread(), [window->ns.object windowNumber], radius);
window->ns.blur_radius = radius;
}
return orig;
}


//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
Expand Down Expand Up @@ -3025,18 +3035,6 @@ GLFWAPI void glfwCocoaRequestRenderFrame(GLFWwindow *w, GLFWcocoarenderframefun
requestRenderFrame((_GLFWwindow*)w, callback);
}

GLFWAPI int glfwCocoaSetBackgroundBlur(GLFWwindow *w, int radius) {
_GLFWwindow* window = (_GLFWwindow*)w;
int orig = window->ns.blur_radius;
if (radius > -1 && radius != window->ns.blur_radius) {
extern OSStatus CGSSetWindowBackgroundBlurRadius(void* connection, NSInteger windowNumber, int radius);
extern void* CGSDefaultConnectionForThread(void);
CGSSetWindowBackgroundBlurRadius(CGSDefaultConnectionForThread(), [window->ns.object windowNumber], radius);
window->ns.blur_radius = radius;
}
return orig;
}

GLFWAPI GLFWcocoarenderframefun glfwCocoaSetWindowResizeCallback(GLFWwindow *w, GLFWcocoarenderframefun cb) {
_GLFWwindow* window = (_GLFWwindow*)w;
GLFWcocoarenderframefun current = window->ns.resizeCallback;
Expand Down Expand Up @@ -3078,7 +3076,7 @@ GLFWAPI void glfwCocoaSetWindowChrome(GLFWwindow *w, unsigned int color, bool us
}
[window->ns.object setBackgroundColor:background];
[window->ns.object setAppearance:appearance];
glfwCocoaSetBackgroundBlur(w, background_blur);
_glfwPlatformSetWindowBlur(w, background_blur);
bool has_shadow = false;
const char *decorations_desc = "full";
window->ns.titlebar_hidden = false;
Expand Down
13 changes: 8 additions & 5 deletions glfw/glfw.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,14 @@ def build_wayland_protocols(
) -> None:
items = []
for protocol in env.wayland_protocols:
src = os.path.join(env.wayland_packagedir, protocol)
if not os.path.exists(src):
raise SystemExit(f'The wayland-protocols package on your system is missing the {protocol} protocol definition file')
if '/' in protocol:
src = os.path.join(env.wayland_packagedir, protocol)
if not os.path.exists(src):
raise SystemExit(f'The wayland-protocols package on your system is missing the {protocol} protocol definition file')
else:
src = os.path.join(os.path.dirname(os.path.abspath(__file__)), protocol)
if not os.path.exists(src):
raise SystemExit(f'The local Wayland protocol {protocol} is missing from kitty sources')
for ext in 'hc':
dest = wayland_protocol_file_name(src, ext)
dest = os.path.join(dest_dir, dest)
Expand Down Expand Up @@ -297,8 +302,6 @@ 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)
GLFWcocoarenderframefun glfwCocoaSetWindowResizeCallback(GLFWwindow *w, GLFWcocoarenderframefun callback)
int glfwCocoaSetBackgroundBlur(GLFWwindow *w, int blur_radius)
bool glfwSetX11WindowBlurred(GLFWwindow *w, bool enable_blur)
void* glfwGetX11Display(void)
unsigned long glfwGetX11Window(GLFWwindow* window)
void glfwSetPrimarySelectionString(GLFWwindow* window, const char* string)
Expand Down
8 changes: 4 additions & 4 deletions glfw/glfw3.h
Original file line number Diff line number Diff line change
Expand Up @@ -1034,10 +1034,10 @@ typedef enum {
SRGB_COLORSPACE = 1,
DISPLAY_P3_COLORSPACE = 2,
} GlfwCocoaColorSpaces;
/*! @brief macOS specific
* [window hint](@ref GLFW_COCOA_BLUR_RADIUS_hint).
/*! @brief Blur Radius. On macOS the actual radius is used. On Linux it is treated as a bool.
* [window hint](@ref GLFW_BLUR_RADIUS).
*/
#define GLFW_COCOA_BLUR_RADIUS 0x00023005
#define GLFW_BLUR_RADIUS 0x0002305

/*! @brief X11 specific
* [window hint](@ref GLFW_X11_CLASS_NAME_hint).
Expand All @@ -1047,7 +1047,6 @@ 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
/*! @} */
Expand Down Expand Up @@ -3800,6 +3799,7 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib);
* @ingroup window
*/
GLFWAPI void glfwSetWindowAttrib(GLFWwindow* window, int attrib, int value);
GLFWAPI int glfwSetWindowBlur(GLFWwindow* window, int value);

/*! @brief Sets the user pointer of the specified window.
*
Expand Down
4 changes: 2 additions & 2 deletions glfw/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,16 +310,15 @@ struct _GLFWwndconfig
bool focusOnShow;
bool mousePassthrough;
bool scaleToMonitor;
int blur_radius;
struct {
bool retina;
int color_space;
int blur_radius;
char frameName[256];
} ns;
struct {
char className[256];
char instanceName[256];
int enable_blur;
} x11;
struct {
char appId[256];
Expand Down Expand Up @@ -865,6 +864,7 @@ void _glfwPlatformStopMainLoop(void);
unsigned long long _glfwPlatformAddTimer(monotonic_t interval, bool repeats, GLFWuserdatafun callback, void *callback_data, GLFWuserdatafun free_callback);
void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled);
void _glfwPlatformRemoveTimer(unsigned long long timer_id);
int _glfwPlatformSetWindowBlur(_GLFWwindow* handle, int value);

char* _glfw_strdup(const char* source);

Expand Down
28 changes: 28 additions & 0 deletions glfw/kwin-blur-v1.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="blur">
<copyright><![CDATA[
SPDX-FileCopyrightText: 2015 Martin Gräßlin
SPDX-FileCopyrightText: 2015 Marco Martin
SPDX-License-Identifier: LGPL-2.1-or-later
]]></copyright>
<interface name="org_kde_kwin_blur_manager" version="1">
<request name="create">
<arg name="id" type="new_id" interface="org_kde_kwin_blur"/>
<arg name="surface" type="object" interface="wl_surface"/>
</request>
<request name="unset">
<arg name="surface" type="object" interface="wl_surface"/>
</request>
</interface>
<interface name="org_kde_kwin_blur" version="1">
<request name="commit">
</request>
<request name="set_region">
<arg name="region" type="object" interface="wl_region" allow-null="true"/>
</request>
<request name="release" type="destructor">
<description summary="release the blur object"/>
</request>
</interface>
</protocol>
4 changes: 3 additions & 1 deletion glfw/source-info.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@
"staging/xdg-activation/xdg-activation-v1.xml",
"unstable/tablet/tablet-unstable-v2.xml",
"staging/cursor-shape/cursor-shape-v1.xml",
"staging/fractional-scale/fractional-scale-v1.xml"
"staging/fractional-scale/fractional-scale-v1.xml",

"kwin-blur-v1.xml"
],
"sources": [
"wl_init.c",
Expand Down
22 changes: 13 additions & 9 deletions glfw/window.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <float.h>


//////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -315,6 +314,7 @@ void glfwDefaultWindowHints(void)
_glfw.hints.window.autoIconify = true;
_glfw.hints.window.centerCursor = true;
_glfw.hints.window.focusOnShow = true;
_glfw.hints.window.blur_radius = 0;

// The default is 24 bits of color, 24 bits of depth and 8 bits of stencil,
// double buffered
Expand All @@ -334,9 +334,6 @@ void glfwDefaultWindowHints(void)
_glfw.hints.window.ns.retina = true;
// use the default colorspace assigned by the system
_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)
Expand Down Expand Up @@ -420,11 +417,8 @@ GLFWAPI void glfwWindowHint(int hint, int value)
case GLFW_COCOA_COLOR_SPACE:
_glfw.hints.window.ns.color_space = value;
return;
case GLFW_COCOA_BLUR_RADIUS:
_glfw.hints.window.ns.blur_radius = value;
return;
case GLFW_X11_BLUR:
_glfw.hints.window.x11.enable_blur = value;
case GLFW_BLUR_RADIUS:
_glfw.hints.window.blur_radius = value;
return;
case GLFW_COCOA_GRAPHICS_SWITCHING:
_glfw.hints.context.nsgl.offline = value ? true : false;
Expand Down Expand Up @@ -1018,6 +1012,16 @@ GLFWAPI void glfwSetWindowAttrib(GLFWwindow* handle, int attrib, int value)
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib);
}

GLFWAPI int glfwSetWindowBlur(GLFWwindow* handle, int value)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);

_GLFW_REQUIRE_INIT_OR_RETURN(0);
return _glfwPlatformSetWindowBlur(window, value);
}


GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
Expand Down
5 changes: 5 additions & 0 deletions glfw/wl_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,9 @@ static void registryHandleGlobal(void* data UNUSED,
else if (is(wp_viewporter)) {
_glfw.wl.wp_viewporter = wl_registry_bind(registry, name, &wp_viewporter_interface, 1);
}
else if (is(org_kde_kwin_blur_manager)) {
_glfw.wl.org_kde_kwin_blur_manager = wl_registry_bind(registry, name, &org_kde_kwin_blur_manager_interface, 1);
}
#undef is
}

Expand Down Expand Up @@ -975,6 +978,8 @@ void _glfwPlatformTerminate(void)
wp_viewporter_destroy(_glfw.wl.wp_viewporter);
if (_glfw.wl.wp_fractional_scale_manager_v1)
wp_fractional_scale_manager_v1_destroy(_glfw.wl.wp_fractional_scale_manager_v1);
if (_glfw.wl.org_kde_kwin_blur_manager)
org_kde_kwin_blur_manager_destroy(_glfw.wl.org_kde_kwin_blur_manager);

if (_glfw.wl.registry)
wl_registry_destroy(_glfw.wl.registry);
Expand Down
4 changes: 4 additions & 0 deletions glfw/wl_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
#include "wayland-cursor-shape-v1-client-protocol.h"
#include "wayland-fractional-scale-v1-client-protocol.h"
#include "wayland-viewporter-client-protocol.h"
#include "wayland-kwin-blur-v1-client-protocol.h"

#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
#define _glfw_dlclose(handle) dlclose(handle)
Expand Down Expand Up @@ -165,6 +166,8 @@ typedef struct _GLFWwindowWayland
} xdg;
struct wp_fractional_scale_v1 *wp_fractional_scale_v1;
struct wp_viewport *wp_viewport;
struct org_kde_kwin_blur *org_kde_kwin_blur;
bool has_blur;

_GLFWcursor* currentCursor;
double cursorPosX, cursorPosY, allCursorPosX, allCursorPosY;
Expand Down Expand Up @@ -295,6 +298,7 @@ typedef struct _GLFWlibraryWayland
struct wp_cursor_shape_device_v1* wp_cursor_shape_device_v1;
struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1;
struct wp_viewporter *wp_viewporter;
struct org_kde_kwin_blur_manager *org_kde_kwin_blur_manager;

int compositorVersion;
int seatVersion;
Expand Down
46 changes: 33 additions & 13 deletions glfw/wl_window.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,18 +307,22 @@ commit_window_surface_if_safe(_GLFWwindow *window) {
}
}

// Makes the surface considered as XRGB instead of ARGB.
static void setOpaqueRegion(_GLFWwindow* window, bool commit_surface)
{
struct wl_region* region;

region = wl_compositor_create_region(_glfw.wl.compositor);
if (!region)
return;

static void
update_regions(_GLFWwindow* window) {
if (window->wl.transparent && !window->wl.org_kde_kwin_blur) return;
struct wl_region* region = wl_compositor_create_region(_glfw.wl.compositor);
if (!region) return;
wl_region_add(region, 0, 0, window->wl.width, window->wl.height);
wl_surface_set_opaque_region(window->wl.surface, region);
if (commit_surface) commit_window_surface_if_safe(window);
// Makes the surface considered as XRGB instead of ARGB.
if (!window->wl.transparent) wl_surface_set_opaque_region(window->wl.surface, region);

// Set blur region
if (window->wl.org_kde_kwin_blur) {
org_kde_kwin_blur_set_region(window->wl.org_kde_kwin_blur, window->wl.has_blur ? region: NULL);
org_kde_kwin_blur_commit(window->wl.org_kde_kwin_blur);
}

wl_region_destroy(region);
}

Expand All @@ -344,7 +348,7 @@ resizeFramebuffer(_GLFWwindow* window) {
debug("Resizing framebuffer to: %dx%d window size: %dx%d at scale: %.2f\n",
scaled_width, scaled_height, window->wl.width, window->wl.height, scale);
wl_egl_window_resize(window->wl.native, scaled_width, scaled_height, 0, 0);
if (!window->wl.transparent) setOpaqueRegion(window, false);
update_regions(window);
window->wl.waiting_for_swap_to_commit = true;
_glfwInputFramebufferSize(window, scaled_width, scaled_height);
}
Expand Down Expand Up @@ -543,6 +547,7 @@ static bool createSurface(_GLFWwindow* window,
window->wl.wp_viewport = wp_viewporter_get_viewport(_glfw.wl.wp_viewporter, window->wl.surface);
wp_fractional_scale_v1_add_listener(window->wl.wp_fractional_scale_v1, &fractional_scale_listener, window);
}
if (_glfw.wl.org_kde_kwin_blur_manager && wndconfig->blur_radius > 0) _glfwPlatformSetWindowBlur(window, wndconfig->blur_radius);

window->wl.integer_scale.deduced = scale;
if (_glfw.wl.has_preferred_buffer_scale) { scale = 1; window->wl.integer_scale.preferred = 1; }
Expand All @@ -558,8 +563,7 @@ static bool createSurface(_GLFWwindow* window,
window->wl.user_requested_content_size.height = wndconfig->height;


if (!window->wl.transparent)
setOpaqueRegion(window, false);
update_regions(window);

wl_surface_set_buffer_scale(window->wl.surface, scale);
return true;
Expand Down Expand Up @@ -1065,6 +1069,8 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
wp_fractional_scale_v1_destroy(window->wl.wp_fractional_scale_v1);
if (window->wl.wp_viewport)
wp_viewport_destroy(window->wl.wp_viewport);
if (window->wl.org_kde_kwin_blur)
org_kde_kwin_blur_release(window->wl.org_kde_kwin_blur);

if (window->context.destroy)
window->context.destroy(window);
Expand Down Expand Up @@ -2331,6 +2337,20 @@ _glfwPlatformChangeCursorTheme(void) {

}

int
_glfwPlatformSetWindowBlur(_GLFWwindow *window, int blur_radius) {
if (!window->wl.transparent) return 0;
bool has_blur = window->wl.has_blur;
bool new_has_blur = blur_radius > 0;
if (new_has_blur != has_blur) {
if (!window->wl.org_kde_kwin_blur)
window->wl.org_kde_kwin_blur = org_kde_kwin_blur_manager_create(_glfw.wl.org_kde_kwin_blur_manager, window->wl.surface);
window->wl.has_blur = new_has_blur;
update_regions(window);
}
return has_blur ? 1 : 0;
}

//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
Expand Down
Loading

0 comments on commit 1c9f9a7

Please sign in to comment.