diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 8a43134c..163261f2 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -927,6 +927,13 @@ extern "C" { */ #define GLFW_MOUSE_PASSTHROUGH 0x0002000D +/*! @brief Blur behind window hint and attribute + * + * Blur behind [window hint](@ref GLFW_BLURRED_hint) or + * [window attribute](@ref GLFW_BLURRED_attrib). + */ +#define GLFW_BLURRED 0x0002000E + /*! @brief Framebuffer bit depth hint. * * Framebuffer bit depth [hint](@ref GLFW_RED_BITS). diff --git a/src/internal.h b/src/internal.h index 8d576d1d..0796abc0 100644 --- a/src/internal.h +++ b/src/internal.h @@ -410,6 +410,7 @@ struct _GLFWwndconfig GLFWbool focusOnShow; GLFWbool mousePassthrough; GLFWbool scaleToMonitor; + GLFWbool blurred; struct { GLFWbool retina; char frameName[256]; @@ -534,6 +535,7 @@ struct _GLFWwindow GLFWbool focusOnShow; GLFWbool mousePassthrough; GLFWbool shouldClose; + GLFWbool blurred; void* userPointer; GLFWbool doublebuffer; GLFWvidmode videoMode; @@ -752,6 +754,7 @@ struct _GLFWplatform void (*getRequiredInstanceExtensions)(char**); GLFWbool (*getPhysicalDevicePresentationSupport)(VkInstance,VkPhysicalDevice,uint32_t); VkResult (*createWindowSurface)(VkInstance,_GLFWwindow*,const VkAllocationCallbacks*,VkSurfaceKHR*); + void (*setWindowBlur)(_GLFWwindow*,GLFWbool); }; // Library global data diff --git a/src/null_init.c b/src/null_init.c index de4b28f3..d010e6c2 100644 --- a/src/null_init.c +++ b/src/null_init.c @@ -112,6 +112,7 @@ GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform) _glfwGetRequiredInstanceExtensionsNull, _glfwGetPhysicalDevicePresentationSupportNull, _glfwCreateWindowSurfaceNull, + _glfwSetWindowBlurNull, }; *platform = null; diff --git a/src/null_platform.h b/src/null_platform.h index b646acb3..1bcaef6a 100644 --- a/src/null_platform.h +++ b/src/null_platform.h @@ -51,6 +51,7 @@ typedef struct _GLFWwindowNull GLFWbool floating; GLFWbool transparent; float opacity; + GLFWbool blurred; } _GLFWwindowNull; // Null-specific per-monitor data @@ -111,6 +112,7 @@ void _glfwSetWindowFloatingNull(_GLFWwindow* window, GLFWbool enabled); void _glfwSetWindowMousePassthroughNull(_GLFWwindow* window, GLFWbool enabled); float _glfwGetWindowOpacityNull(_GLFWwindow* window); void _glfwSetWindowOpacityNull(_GLFWwindow* window, float opacity); +void _glfwSetWindowBlurNull(_GLFWwindow* window, GLFWbool enabled); void _glfwSetRawMouseMotionNull(_GLFWwindow *window, GLFWbool enabled); GLFWbool _glfwRawMouseMotionSupportedNull(void); void _glfwShowWindowNull(_GLFWwindow* window); diff --git a/src/null_window.c b/src/null_window.c index 8a7cae41..7ebdc6dc 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -409,6 +409,11 @@ void _glfwSetWindowOpacityNull(_GLFWwindow* window, float opacity) window->null.opacity = opacity; } +void _glfwSetWindowBlurNull(_GLFWwindow* window, GLFWbool enable) +{ + window->null.blurred = enable; +} + void _glfwSetRawMouseMotionNull(_GLFWwindow *window, GLFWbool enabled) { } diff --git a/src/window.c b/src/window.c index f740580a..9864607b 100644 --- a/src/window.c +++ b/src/window.c @@ -389,6 +389,9 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_MOUSE_PASSTHROUGH: _glfw.hints.window.mousePassthrough = value ? GLFW_TRUE : GLFW_FALSE; return; + case GLFW_BLURRED: + _glfw.hints.window.blurred = value ? GLFW_TRUE : GLFW_FALSE; + return; case GLFW_CLIENT_API: _glfw.hints.context.client = value; return; @@ -860,6 +863,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return window->focusOnShow; case GLFW_MOUSE_PASSTHROUGH: return window->mousePassthrough; + case GLFW_BLURRED: + return window->blurred; case GLFW_TRANSPARENT_FRAMEBUFFER: return _glfw.platform.framebufferTransparent(window); case GLFW_RESIZABLE: @@ -941,6 +946,11 @@ GLFWAPI void glfwSetWindowAttrib(GLFWwindow* handle, int attrib, int value) window->mousePassthrough = value; _glfw.platform.setWindowMousePassthrough(window, value); return; + + case GLFW_BLURRED: + window->blurred = value; + _glfw.platform.setWindowBlur(window, value); + return; } _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); diff --git a/src/x11_init.c b/src/x11_init.c index 11aeb9e5..049fcb63 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -973,6 +973,8 @@ static GLFWbool initExtensions(void) XInternAtom(_glfw.x11.display, "_NET_WM_WINDOW_OPACITY", False); _glfw.x11.MOTIF_WM_HINTS = XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False); + _glfw.x11.KDE_NET_WM_BLUR_BEHIND_REGION = + XInternAtom(_glfw.x11.display, "_KDE_NET_WM_BLUR_BEHIND_REGION", False); // The compositing manager selection name contains the screen number { @@ -1246,6 +1248,7 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform) _glfwGetRequiredInstanceExtensionsX11, _glfwGetPhysicalDevicePresentationSupportX11, _glfwCreateWindowSurfaceX11, + _glfwSetWindowBlurX11, }; // HACK: If the application has left the locale as "C" then both wide diff --git a/src/x11_platform.h b/src/x11_platform.h index ecaa0fa4..21a82e44 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -616,6 +616,7 @@ typedef struct _GLFWlibraryX11 Atom NET_FRAME_EXTENTS; Atom NET_REQUEST_FRAME_EXTENTS; Atom MOTIF_WM_HINTS; + Atom KDE_NET_WM_BLUR_BEHIND_REGION; // Xdnd (drag and drop) atoms Atom XdndAware; @@ -935,6 +936,7 @@ void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled); float _glfwGetWindowOpacityX11(_GLFWwindow* window); void _glfwSetWindowOpacityX11(_GLFWwindow* window, float opacity); void _glfwSetWindowMousePassthroughX11(_GLFWwindow* window, GLFWbool enabled); +void _glfwSetWindowBlurX11(_GLFWwindow* window, GLFWbool enabled); void _glfwSetRawMouseMotionX11(_GLFWwindow *window, GLFWbool enabled); GLFWbool _glfwRawMouseMotionSupportedX11(void); diff --git a/src/x11_window.c b/src/x11_window.c index 4f605771..0d5c3133 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -619,6 +619,9 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, if (!wndconfig->decorated) _glfwSetWindowDecoratedX11(window, GLFW_FALSE); + if (wndconfig->blurred) + _glfwSetWindowBlurX11(window, GLFW_TRUE); + if (_glfw.x11.NET_WM_STATE && !window->monitor) { Atom states[3]; @@ -2718,6 +2721,17 @@ void _glfwSetWindowOpacityX11(_GLFWwindow* window, float opacity) PropModeReplace, (unsigned char*) &value, 1); } +void _glfwSetWindowBlurX11(_GLFWwindow* window, GLFWbool enable) +{ + if (enable) + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.KDE_NET_WM_BLUR_BEHIND_REGION, XA_CARDINAL, 32, + PropModeReplace, NULL, 0); + else + XDeleteProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.KDE_NET_WM_BLUR_BEHIND_REGION); +} + void _glfwSetRawMouseMotionX11(_GLFWwindow *window, GLFWbool enabled) { if (!_glfw.x11.xi.available) diff --git a/tests/window.c b/tests/window.c index 83baff46..49303df3 100644 --- a/tests/window.c +++ b/tests/window.c @@ -406,6 +406,10 @@ int main(int argc, char** argv) if (nk_checkbox_label(nk, "Auto Iconify", &auto_iconify)) glfwSetWindowAttrib(window, GLFW_AUTO_ICONIFY, auto_iconify); + int blurred = glfwGetWindowAttrib(window, GLFW_BLURRED); + if (nk_checkbox_label(nk, "Blur", &blurred)) + glfwSetWindowAttrib(window, GLFW_BLURRED, blurred); + nk_value_bool(nk, "Focused", glfwGetWindowAttrib(window, GLFW_FOCUSED)); nk_value_bool(nk, "Hovered", glfwGetWindowAttrib(window, GLFW_HOVERED)); nk_value_bool(nk, "Visible", glfwGetWindowAttrib(window, GLFW_VISIBLE));