From d0c6ce9fd794dbd788b90f61bba344ee88c0ca67 Mon Sep 17 00:00:00 2001 From: Luflosi Date: Thu, 16 Jul 2020 21:15:00 +0200 Subject: [PATCH] GLFW: Add support for mouse input transparency From upstream: https://github.com/glfw/glfw/commit/d285a9fdeb5e7f4688ebbd8f8fa8f101b01b5bea. --- glfw/cocoa_window.m | 6 ++++++ glfw/glfw3.h | 11 ++++++++++- glfw/internal.h | 3 +++ glfw/null_window.c | 4 ++++ glfw/window.c | 9 +++++++++ glfw/wl_window.c | 17 +++++++++++++++++ glfw/x11_init.c | 24 ++++++++++++++++++++++++ glfw/x11_platform.h | 19 +++++++++++++++++++ glfw/x11_window.c | 26 ++++++++++++++++++++++++++ kitty/glfw-wrapper.h | 10 +++++++++- 10 files changed, 127 insertions(+), 2 deletions(-) diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index 3a905be5c..60e427ebe 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -1854,6 +1854,12 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled) [window->ns.object setLevel:NSNormalWindowLevel]; } +void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, bool enabled) +{ + window->mousePassthrough = enabled; + [window->ns.object setIgnoresMouseEvents:enabled]; +} + float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { return (float) [window->ns.object alphaValue]; diff --git a/glfw/glfw3.h b/glfw/glfw3.h index c537b9356..a146d9eeb 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -932,11 +932,19 @@ extern "C" { * [window attribute](@ref GLFW_FOCUS_ON_SHOW_attrib). */ #define GLFW_FOCUS_ON_SHOW 0x0002000C + +/*! @brief Forward mouse input to window behind. + * + * Mouse input forwarding[window hint](@ref GLFW_MOUSE_PASSTHROUGH_hint) or + * [window attribute](@ref GLFW_MOUSE_PASSTHROUGH_attrib). + */ +#define GLFW_MOUSE_PASSTHROUGH 0x0002000D + /*! @brief Occlusion window attribute * * Occlusion [window attribute](@ref GLFW_OCCLUDED_attrib). */ -#define GLFW_OCCLUDED 0x0002000D +#define GLFW_OCCLUDED 0x0002000E /*! @brief Framebuffer bit depth hint. * * Framebuffer bit depth [hint](@ref GLFW_RED_BITS). @@ -3741,6 +3749,7 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); * [GLFW_FLOATING](@ref GLFW_FLOATING_attrib), * [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib) and * [GLFW_FOCUS_ON_SHOW](@ref GLFW_FOCUS_ON_SHOW_attrib). + * [GLFW_MOUSE_PASSTHROUGH](@ref GLFW_MOUSE_PASSTHROUGH_attrib) * * Some of these attributes are ignored for full screen windows. The new * value will take effect if the window is later made windowed. diff --git a/glfw/internal.h b/glfw/internal.h index 227458151..f6f849d16 100644 --- a/glfw/internal.h +++ b/glfw/internal.h @@ -303,6 +303,7 @@ struct _GLFWwndconfig bool maximized; bool centerCursor; bool focusOnShow; + bool mousePassthrough; bool scaleToMonitor; struct { bool retina; @@ -413,6 +414,7 @@ struct _GLFWwindow bool autoIconify; bool floating; bool focusOnShow; + bool mousePassthrough; bool shouldClose; void* userPointer; GLFWid id; @@ -717,6 +719,7 @@ float _glfwPlatformGetWindowOpacity(_GLFWwindow* window); void _glfwPlatformSetWindowResizable(_GLFWwindow* window, bool enabled); void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled); void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled); +void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, bool enabled); void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity); void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c, int d); diff --git a/glfw/null_window.c b/glfw/null_window.c index 7fdd2ef9a..564b19a43 100644 --- a/glfw/null_window.c +++ b/glfw/null_window.c @@ -372,6 +372,10 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled) window->null.floating = enabled; } +void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window UNUSED, bool enabled UNUSED) +{ +} + float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { return window->null.opacity; diff --git a/glfw/window.c b/glfw/window.c index cb2f254c8..b7453f09a 100644 --- a/glfw/window.c +++ b/glfw/window.c @@ -290,6 +290,8 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, } } + _glfwPlatformSetWindowMousePassthrough(window, wndconfig.mousePassthrough); + return (GLFWwindow*) window; } @@ -422,6 +424,9 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_FOCUS_ON_SHOW: _glfw.hints.window.focusOnShow = value ? true : false; return; + case GLFW_MOUSE_PASSTHROUGH: + _glfw.hints.window.mousePassthrough = value ? true : false; + return; case GLFW_CLIENT_API: _glfw.hints.context.client = value; return; @@ -905,6 +910,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return _glfwPlatformWindowHovered(window); case GLFW_FOCUS_ON_SHOW: return window->focusOnShow; + case GLFW_MOUSE_PASSTHROUGH: + return window->mousePassthrough; case GLFW_TRANSPARENT_FRAMEBUFFER: return _glfwPlatformFramebufferTransparent(window); case GLFW_OCCLUDED: @@ -985,6 +992,8 @@ GLFWAPI void glfwSetWindowAttrib(GLFWwindow* handle, int attrib, int value) } else if (attrib == GLFW_FOCUS_ON_SHOW) window->focusOnShow = value; + else if (attrib == GLFW_MOUSE_PASSTHROUGH) + _glfwPlatformSetWindowMousePassthrough(window, value); else _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); } diff --git a/glfw/wl_window.c b/glfw/wl_window.c index ef9f87cb9..6d35f5de9 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -1269,6 +1269,23 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window UNUSED, bool enabled UNU "Wayland: Window attribute setting not implemented yet"); } +void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, bool enabled) +{ + if (enabled == window->mousePassthrough) + return; + + if (enabled) + { + struct wl_region* region = wl_compositor_create_region(_glfw.wl.compositor); + wl_surface_set_input_region(window->wl.surface, region); + wl_region_destroy(region); + } + else + wl_surface_set_input_region(window->wl.surface, 0); + wl_surface_commit(window->wl.surface); + window->mousePassthrough = enabled; +} + float _glfwPlatformGetWindowOpacity(_GLFWwindow* window UNUSED) { return 1.f; diff --git a/glfw/x11_init.c b/glfw/x11_init.c index b0bc43129..4252f4490 100644 --- a/glfw/x11_init.c +++ b/glfw/x11_init.c @@ -327,6 +327,30 @@ static bool initExtensions(void) } } +#if defined(__CYGWIN__) + _glfw.x11.xshape.handle = _glfw_dlopen("libXext-6.so"); +#else + _glfw.x11.xshape.handle = _glfw_dlopen("libXext.so.6"); +#endif + if (_glfw.x11.xshape.handle) + { + glfw_dlsym(_glfw.x11.xshape.QueryExtension, _glfw.x11.xshape.handle, "XShapeQueryExtension"); + glfw_dlsym(_glfw.x11.xshape.ShapeCombineRegion, _glfw.x11.xshape.handle, "XShapeCombineRegion"); + glfw_dlsym(_glfw.x11.xshape.QueryVersion, _glfw.x11.xshape.handle, "XShapeQueryVersion"); + + if (XShapeQueryExtension(_glfw.x11.display, + &_glfw.x11.xshape.errorBase, + &_glfw.x11.xshape.eventBase)) + { + if (XShapeQueryVersion(_glfw.x11.display, + &_glfw.x11.xshape.major, + &_glfw.x11.xshape.minor)) + { + _glfw.x11.xshape.available = true; + } + } + } + _glfw.x11.xkb.major = 1; _glfw.x11.xkb.minor = 0; _glfw.x11.xkb.available = XkbQueryExtension(_glfw.x11.display, diff --git a/glfw/x11_platform.h b/glfw/x11_platform.h index eeb647552..94ab2a835 100644 --- a/glfw/x11_platform.h +++ b/glfw/x11_platform.h @@ -125,6 +125,13 @@ typedef XRenderPictFormat* (* PFN_XRenderFindVisualFormat)(Display*,Visual const #define XRenderQueryVersion _glfw.x11.xrender.QueryVersion #define XRenderFindVisualFormat _glfw.x11.xrender.FindVisualFormat +typedef Bool (* PFN_XShapeQueryExtension)(Display*,int*,int*); +typedef Status (* PFN_XShapeQueryVersion)(Display*dpy,int*,int*); +typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int); +#define XShapeQueryExtension _glfw.x11.xshape.QueryExtension +#define XShapeQueryVersion _glfw.x11.xshape.QueryVersion +#define XShapeCombineRegion _glfw.x11.xshape.ShapeCombineRegion + typedef VkFlags VkXlibSurfaceCreateFlagsKHR; typedef VkFlags VkXcbSurfaceCreateFlagsKHR; @@ -377,6 +384,18 @@ typedef struct _GLFWlibraryX11 PFN_XRenderFindVisualFormat FindVisualFormat; } xrender; + struct { + bool available; + void* handle; + int major; + int minor; + int eventBase; + int errorBase; + PFN_XShapeQueryExtension QueryExtension; + PFN_XShapeCombineRegion ShapeCombineRegion; + PFN_XShapeQueryVersion QueryVersion; + } xshape; + EventLoopData eventLoopData; } _GLFWlibraryX11; diff --git a/glfw/x11_window.c b/glfw/x11_window.c index 273749180..44626f306 100644 --- a/glfw/x11_window.c +++ b/glfw/x11_window.c @@ -2586,6 +2586,32 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled) XFlush(_glfw.x11.display); } +void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, bool enabled) +{ + if (!_glfw.x11.xshape.available) + return; + + if (enabled == window->mousePassthrough) + return; + + int width = 0; + int height = 0; + if (!enabled) + _glfwPlatformGetWindowSize(window, &width, &height); + + XRectangle rect; + rect.x = 0; + rect.y = 0; + rect.width = (unsigned short)width; + rect.height = (unsigned short)height; + + Region region = XCreateRegion(); + XUnionRectWithRegion(&rect, region, region); + XShapeCombineRegion(_glfw.x11.display, window->x11.handle, 2/*ShapeInput*/, 0, 0, region, 0/*ShapeSet*/); + XDestroyRegion(region); + window->mousePassthrough = enabled; +} + float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) { float opacity = 1.f; diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index a32a727a7..b2c2e85c7 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -670,11 +670,19 @@ * [window attribute](@ref GLFW_FOCUS_ON_SHOW_attrib). */ #define GLFW_FOCUS_ON_SHOW 0x0002000C + +/*! @brief Forward mouse input to window behind. + * + * Mouse input forwarding[window hint](@ref GLFW_MOUSE_PASSTHROUGH_hint) or + * [window attribute](@ref GLFW_MOUSE_PASSTHROUGH_attrib). + */ +#define GLFW_MOUSE_PASSTHROUGH 0x0002000D + /*! @brief Occlusion window attribute * * Occlusion [window attribute](@ref GLFW_OCCLUDED_attrib). */ -#define GLFW_OCCLUDED 0x0002000D +#define GLFW_OCCLUDED 0x0002000E /*! @brief Framebuffer bit depth hint. * * Framebuffer bit depth [hint](@ref GLFW_RED_BITS).