Add support for mouse input transparency

This adds the GLFW_MOUSE_PASSTHROUGH window hint and attribute for
controlling whether mouse input passes through the window to whatever
window is behind it.

Fixes #1236.
Closes #1568.
This commit is contained in:
Rokas Kupstys 2019-09-30 15:44:43 +03:00 committed by Camilla Löwy
parent 6c031af245
commit d285a9fdeb
10 changed files with 148 additions and 0 deletions

View File

@ -895,6 +895,13 @@ extern "C" {
*/
#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 Framebuffer bit depth hint.
*
* Framebuffer bit depth [hint](@ref GLFW_RED_BITS).
@ -3656,6 +3663,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.

View File

@ -1371,6 +1371,14 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
} // autoreleasepool
}
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool enabled)
{
window->mousePassthrough = enabled;
@autoreleasepool {
[window->ns.object setIgnoresMouseEvents:enabled];
}
}
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
{
@autoreleasepool {

View File

@ -270,6 +270,7 @@ struct _GLFWwndconfig
GLFWbool maximized;
GLFWbool centerCursor;
GLFWbool focusOnShow;
GLFWbool mousePassthrough;
GLFWbool scaleToMonitor;
struct {
GLFWbool retina;
@ -380,6 +381,7 @@ struct _GLFWwindow
GLFWbool autoIconify;
GLFWbool floating;
GLFWbool focusOnShow;
GLFWbool mousePassthrough;
GLFWbool shouldClose;
void* userPointer;
GLFWvidmode videoMode;
@ -678,6 +680,7 @@ float _glfwPlatformGetWindowOpacity(_GLFWwindow* window);
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled);
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled);
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled);
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool enabled);
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity);
void _glfwPlatformPollEvents(void);

View File

@ -362,6 +362,10 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
window->null.floating = enabled;
}
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool enabled)
{
}
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
{
return window->null.opacity;

View File

@ -1201,6 +1201,13 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
DragFinish(drop);
return 0;
}
case WM_NCHITTEST:
{
if (window->mousePassthrough)
return HTTRANSPARENT;
break;
}
}
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
@ -1854,6 +1861,11 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
}
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool enabled)
{
window->mousePassthrough = enabled;
}
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
{
BYTE alpha;

View File

@ -243,6 +243,8 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
}
}
_glfwPlatformSetWindowMousePassthrough(window, wndconfig.mousePassthrough);
return (GLFWwindow*) window;
}
@ -378,6 +380,9 @@ GLFWAPI void glfwWindowHint(int hint, int value)
case GLFW_FOCUS_ON_SHOW:
_glfw.hints.window.focusOnShow = value ? GLFW_TRUE : GLFW_FALSE;
return;
case GLFW_MOUSE_PASSTHROUGH:
_glfw.hints.window.mousePassthrough = value ? GLFW_TRUE : GLFW_FALSE;
return;
case GLFW_CLIENT_API:
_glfw.hints.context.client = value;
return;
@ -822,6 +827,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_RESIZABLE:
@ -900,6 +907,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);
}

View File

@ -1127,6 +1127,23 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
"Wayland: Window attribute setting not implemented yet");
}
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool 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)
{
return 1.f;

View File

@ -851,6 +851,33 @@ static GLFWbool 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.x11.xshape.QueryExtension = (PFN_XShapeQueryExtension)
_glfw_dlsym(_glfw.x11.xshape.handle, "XShapeQueryExtension");
_glfw.x11.xshape.ShapeCombineRegion = (PFN_XShapeCombineRegion)
_glfw_dlsym(_glfw.x11.xshape.handle, "XShapeCombineRegion");
_glfw.x11.xshape.QueryVersion = (PFN_XShapeQueryVersion)
_glfw_dlsym(_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 = GLFW_TRUE;
}
}
}
// Update the key code LUT
// FIXME: We should listen to XkbMapNotify events to track changes to
// the keyboard mapping.
@ -1122,6 +1149,8 @@ int _glfwPlatformInit(void)
_glfw_dlsym(_glfw.x11.xlib.handle, "XCreateFontCursor");
_glfw.x11.xlib.CreateIC = (PFN_XCreateIC)
_glfw_dlsym(_glfw.x11.xlib.handle, "XCreateIC");
_glfw.x11.xlib.CreateRegion = (PFN_XCreateRegion)
_glfw_dlsym(_glfw.x11.xlib.handle, "XCreateRegion");
_glfw.x11.xlib.CreateWindow = (PFN_XCreateWindow)
_glfw_dlsym(_glfw.x11.xlib.handle, "XCreateWindow");
_glfw.x11.xlib.DefineCursor = (PFN_XDefineCursor)
@ -1132,6 +1161,8 @@ int _glfwPlatformInit(void)
_glfw_dlsym(_glfw.x11.xlib.handle, "XDeleteProperty");
_glfw.x11.xlib.DestroyIC = (PFN_XDestroyIC)
_glfw_dlsym(_glfw.x11.xlib.handle, "XDestroyIC");
_glfw.x11.xlib.DestroyRegion = (PFN_XDestroyRegion)
_glfw_dlsym(_glfw.x11.xlib.handle, "XDestroyRegion");
_glfw.x11.xlib.DestroyWindow = (PFN_XDestroyWindow)
_glfw_dlsym(_glfw.x11.xlib.handle, "XDestroyWindow");
_glfw.x11.xlib.DisplayKeycodes = (PFN_XDisplayKeycodes)
@ -1254,6 +1285,8 @@ int _glfwPlatformInit(void)
_glfw_dlsym(_glfw.x11.xlib.handle, "XUndefineCursor");
_glfw.x11.xlib.UngrabPointer = (PFN_XUngrabPointer)
_glfw_dlsym(_glfw.x11.xlib.handle, "XUngrabPointer");
_glfw.x11.xlib.UnionRectWithRegion = (PFN_XUnionRectWithRegion)
_glfw_dlsym(_glfw.x11.xlib.handle, "XUnionRectWithRegion");
_glfw.x11.xlib.UnmapWindow = (PFN_XUnmapWindow)
_glfw_dlsym(_glfw.x11.xlib.handle, "XUnmapWindow");
_glfw.x11.xlib.UnsetICFocus = (PFN_XUnsetICFocus)

View File

@ -61,11 +61,13 @@ typedef int (* PFN_XConvertSelection)(Display*,Atom,Atom,Atom,Window,Time);
typedef Colormap (* PFN_XCreateColormap)(Display*,Window,Visual*,int);
typedef Cursor (* PFN_XCreateFontCursor)(Display*,unsigned int);
typedef XIC (* PFN_XCreateIC)(XIM,...);
typedef Region (* PFN_XCreateRegion)(void);
typedef Window (* PFN_XCreateWindow)(Display*,Window,int,int,unsigned int,unsigned int,unsigned int,int,unsigned int,Visual*,unsigned long,XSetWindowAttributes*);
typedef int (* PFN_XDefineCursor)(Display*,Window,Cursor);
typedef int (* PFN_XDeleteContext)(Display*,XID,XContext);
typedef int (* PFN_XDeleteProperty)(Display*,Window,Atom);
typedef void (* PFN_XDestroyIC)(XIC);
typedef int (* PFN_XDestroyRegion)(Region);
typedef int (* PFN_XDestroyWindow)(Display*,Window);
typedef int (* PFN_XDisplayKeycodes)(Display*,int*,int*);
typedef int (* PFN_XEventsQueued)(Display*,int);
@ -127,6 +129,7 @@ typedef int (* PFN_XSync)(Display*,Bool);
typedef Bool (* PFN_XTranslateCoordinates)(Display*,Window,Window,int,int,int*,int*,Window*);
typedef int (* PFN_XUndefineCursor)(Display*,Window);
typedef int (* PFN_XUngrabPointer)(Display*,Time);
typedef int (* PFN_XUnionRectWithRegion)(XRectangle*,Region,Region);
typedef int (* PFN_XUnmapWindow)(Display*,Window);
typedef void (* PFN_XUnsetICFocus)(XIC);
typedef VisualID (* PFN_XVisualIDFromVisual)(Visual*);
@ -161,11 +164,13 @@ typedef void (* PFN_Xutf8SetWMProperties)(Display*,Window,const char*,const char
#define XCreateColormap _glfw.x11.xlib.CreateColormap
#define XCreateFontCursor _glfw.x11.xlib.CreateFontCursor
#define XCreateIC _glfw.x11.xlib.CreateIC
#define XCreateRegion _glfw.x11.xlib.CreateRegion
#define XCreateWindow _glfw.x11.xlib.CreateWindow
#define XDefineCursor _glfw.x11.xlib.DefineCursor
#define XDeleteContext _glfw.x11.xlib.DeleteContext
#define XDeleteProperty _glfw.x11.xlib.DeleteProperty
#define XDestroyIC _glfw.x11.xlib.DestroyIC
#define XDestroyRegion _glfw.x11.xlib.DestroyRegion
#define XDestroyWindow _glfw.x11.xlib.DestroyWindow
#define XDisplayKeycodes _glfw.x11.xlib.DisplayKeycodes
#define XEventsQueued _glfw.x11.xlib.EventsQueued
@ -227,6 +232,7 @@ typedef void (* PFN_Xutf8SetWMProperties)(Display*,Window,const char*,const char
#define XTranslateCoordinates _glfw.x11.xlib.TranslateCoordinates
#define XUndefineCursor _glfw.x11.xlib.UndefineCursor
#define XUngrabPointer _glfw.x11.xlib.UngrabPointer
#define XUnionRectWithRegion _glfw.x11.xlib.UnionRectWithRegion
#define XUnmapWindow _glfw.x11.xlib.UnmapWindow
#define XUnsetICFocus _glfw.x11.xlib.UnsetICFocus
#define XVisualIDFromVisual _glfw.x11.xlib.VisualIDFromVisual
@ -331,6 +337,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;
@ -515,11 +528,13 @@ typedef struct _GLFWlibraryX11
PFN_XCreateColormap CreateColormap;
PFN_XCreateFontCursor CreateFontCursor;
PFN_XCreateIC CreateIC;
PFN_XCreateRegion CreateRegion;
PFN_XCreateWindow CreateWindow;
PFN_XDefineCursor DefineCursor;
PFN_XDeleteContext DeleteContext;
PFN_XDeleteProperty DeleteProperty;
PFN_XDestroyIC DestroyIC;
PFN_XDestroyRegion DestroyRegion;
PFN_XDestroyWindow DestroyWindow;
PFN_XDisplayKeycodes DisplayKeycodes;
PFN_XEventsQueued EventsQueued;
@ -581,6 +596,7 @@ typedef struct _GLFWlibraryX11
PFN_XTranslateCoordinates TranslateCoordinates;
PFN_XUndefineCursor UndefineCursor;
PFN_XUngrabPointer UngrabPointer;
PFN_XUnionRectWithRegion UnionRectWithRegion;
PFN_XUnmapWindow UnmapWindow;
PFN_XUnsetICFocus UnsetICFocus;
PFN_XVisualIDFromVisual VisualIDFromVisual;
@ -720,6 +736,18 @@ typedef struct _GLFWlibraryX11
PFN_XRenderFindVisualFormat FindVisualFormat;
} xrender;
struct {
GLFWbool available;
void* handle;
int major;
int minor;
int eventBase;
int errorBase;
PFN_XShapeQueryExtension QueryExtension;
PFN_XShapeCombineRegion ShapeCombineRegion;
PFN_XShapeQueryVersion QueryVersion;
} xshape;
} _GLFWlibraryX11;
// X11-specific per-monitor data

View File

@ -2702,6 +2702,32 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
XFlush(_glfw.x11.display);
}
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool 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;