Implement window transparency to mouse events (#1236)

This commit is contained in:
Rokas Kupstys 2019-09-30 15:44:43 +03:00
parent 243b1bc292
commit c2913ad879
10 changed files with 133 additions and 0 deletions

View File

@ -832,6 +832,13 @@ extern "C" {
*/
#define GLFW_FOCUS_ON_SHOW 0x0002000C
/*! @brief Forward mouse input to window behind.
*
* Mouse input forwarding[window hint](@ref GLFW_MOUSE_PASSTHRU_hint) or
* [window attribute](@ref GLFW_MOUSE_PASSTHRU_attrib).
*/
#define GLFW_MOUSE_PASSTHRU 0x0002000D
/*! @brief Framebuffer bit depth hint.
*
* Framebuffer bit depth [hint](@ref GLFW_RED_BITS).
@ -3499,6 +3506,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_PASSTHRU](@ref GLFW_MOUSE_PASSTHRU_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

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

View File

@ -265,6 +265,7 @@ struct _GLFWwndconfig
GLFWbool maximized;
GLFWbool centerCursor;
GLFWbool focusOnShow;
GLFWbool mousePassthru;
GLFWbool scaleToMonitor;
struct {
GLFWbool retina;
@ -372,6 +373,7 @@ struct _GLFWwindow
GLFWbool autoIconify;
GLFWbool floating;
GLFWbool focusOnShow;
GLFWbool mousePassthru;
GLFWbool shouldClose;
void* userPointer;
GLFWvidmode videoMode;
@ -669,6 +671,7 @@ float _glfwPlatformGetWindowOpacity(_GLFWwindow* window);
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled);
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled);
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled);
void _glfwPlatformSetWindowMousePassthru(_GLFWwindow* window, GLFWbool enabled);
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity);
void _glfwPlatformPollEvents(void);

View File

@ -189,6 +189,10 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
{
}
void _glfwPlatformSetWindowMousePassthru(_GLFWwindow* window, GLFWbool enabled)
{
}
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
{
return 1.f;

View File

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

View File

@ -243,6 +243,8 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
}
}
_glfwPlatformSetWindowMousePassthru(window, wndconfig.mousePassthru);
return (GLFWwindow*) window;
}
@ -375,6 +377,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_PASSTHRU:
_glfw.hints.window.mousePassthru = value ? GLFW_TRUE : GLFW_FALSE;
return;
case GLFW_CLIENT_API:
_glfw.hints.context.client = value;
return;
@ -819,6 +824,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib)
return _glfwPlatformWindowHovered(window);
case GLFW_FOCUS_ON_SHOW:
return window->focusOnShow;
case GLFW_MOUSE_PASSTHRU:
return window->mousePassthru;
case GLFW_TRANSPARENT_FRAMEBUFFER:
return _glfwPlatformFramebufferTransparent(window);
case GLFW_RESIZABLE:
@ -897,6 +904,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_PASSTHRU)
_glfwPlatformSetWindowMousePassthru(window, value);
else
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib);
}

View File

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

View File

@ -707,6 +707,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.

View File

@ -123,6 +123,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;
@ -404,6 +411,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

@ -2630,6 +2630,32 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
XFlush(_glfw.x11.display);
}
void _glfwPlatformSetWindowMousePassthru(_GLFWwindow* window, GLFWbool enabled)
{
if (!_glfw.x11.xshape.available)
return;
if (enabled == window->mousePassthru)
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->mousePassthru = enabled;
}
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
{
float opacity = 1.f;