mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
internal/glfw, interna/cglfw, internal/goglfw: add MousePassthrough
Work in progress Updates #2511
This commit is contained in:
parent
777c575638
commit
c8d38f7f25
@ -917,6 +917,9 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (wndconfig->mousePassthrough)
|
||||
_glfwPlatformSetWindowMousePassthrough(window, GLFW_TRUE);
|
||||
|
||||
if (window->monitor)
|
||||
{
|
||||
_glfwPlatformShowWindow(window);
|
||||
@ -1435,6 +1438,13 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
|
||||
} // autoreleasepool
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool enabled)
|
||||
{
|
||||
@autoreleasepool {
|
||||
[window->ns.object setIgnoresMouseEvents:enabled];
|
||||
}
|
||||
}
|
||||
|
||||
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
|
||||
{
|
||||
@autoreleasepool {
|
||||
|
@ -721,6 +721,13 @@ extern "C" {
|
||||
*/
|
||||
#define GLFW_FOCUS_ON_SHOW 0x0002000C
|
||||
|
||||
/*! @brief Mouse input transparency window hint and attribute
|
||||
*
|
||||
* Mouse input transparency [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).
|
||||
|
@ -169,6 +169,7 @@ struct _GLFWwndconfig
|
||||
GLFWbool maximized;
|
||||
GLFWbool centerCursor;
|
||||
GLFWbool focusOnShow;
|
||||
GLFWbool mousePassthrough;
|
||||
GLFWbool scaleToMonitor;
|
||||
struct {
|
||||
GLFWbool retina;
|
||||
@ -276,6 +277,7 @@ struct _GLFWwindow
|
||||
GLFWbool autoIconify;
|
||||
GLFWbool floating;
|
||||
GLFWbool focusOnShow;
|
||||
GLFWbool mousePassthrough;
|
||||
GLFWbool shouldClose;
|
||||
void* userPointer;
|
||||
GLFWbool doublebuffer;
|
||||
@ -504,6 +506,7 @@ void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled);
|
||||
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled);
|
||||
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled);
|
||||
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity);
|
||||
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool enabled);
|
||||
|
||||
void _glfwPlatformPollEvents(void);
|
||||
void _glfwPlatformWaitEvents(void);
|
||||
|
@ -175,13 +175,14 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
|
||||
window->videoMode.blueBits = fbconfig.blueBits;
|
||||
window->videoMode.refreshRate = _glfw.hints.refreshRate;
|
||||
|
||||
window->monitor = (_GLFWmonitor*) monitor;
|
||||
window->resizable = wndconfig.resizable;
|
||||
window->decorated = wndconfig.decorated;
|
||||
window->autoIconify = wndconfig.autoIconify;
|
||||
window->floating = wndconfig.floating;
|
||||
window->focusOnShow = wndconfig.focusOnShow;
|
||||
window->cursorMode = GLFW_CURSOR_NORMAL;
|
||||
window->monitor = (_GLFWmonitor*) monitor;
|
||||
window->resizable = wndconfig.resizable;
|
||||
window->decorated = wndconfig.decorated;
|
||||
window->autoIconify = wndconfig.autoIconify;
|
||||
window->floating = wndconfig.floating;
|
||||
window->focusOnShow = wndconfig.focusOnShow;
|
||||
window->mousePassthrough = wndconfig.mousePassthrough;
|
||||
window->cursorMode = GLFW_CURSOR_NORMAL;
|
||||
|
||||
window->doublebuffer = fbconfig.doublebuffer;
|
||||
|
||||
@ -331,6 +332,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;
|
||||
@ -796,6 +800,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:
|
||||
@ -874,6 +880,11 @@ 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)
|
||||
{
|
||||
window->mousePassthrough = value;
|
||||
_glfwPlatformSetWindowMousePassthrough(window, value);
|
||||
}
|
||||
else
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib);
|
||||
}
|
||||
|
@ -820,6 +820,37 @@ static GLFWbool initExtensions(void)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
_glfw.x11.xshape.handle = _glfw_dlopen("libXext-6.so");
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.x11.xshape.handle = _glfw_dlopen("libXext.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");
|
||||
_glfw.x11.xshape.ShapeCombineMask = (PFN_XShapeCombineMask)
|
||||
_glfw_dlsym(_glfw.x11.xshape.handle, "XShapeCombineMask");
|
||||
|
||||
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.
|
||||
|
@ -27,6 +27,9 @@
|
||||
// The XInput extension provides raw mouse motion input
|
||||
#include <X11/extensions/XInput2.h>
|
||||
|
||||
// The Shape extension provides custom window shapes
|
||||
#include <X11/extensions/shape.h>
|
||||
|
||||
typedef XRRCrtcGamma* (* PFN_XRRAllocGamma)(int);
|
||||
typedef void (* PFN_XRRFreeCrtcInfo)(XRRCrtcInfo*);
|
||||
typedef void (* PFN_XRRFreeGamma)(XRRCrtcGamma*);
|
||||
@ -109,6 +112,16 @@ 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);
|
||||
typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int);
|
||||
|
||||
#define XShapeQueryExtension _glfw.x11.xshape.QueryExtension
|
||||
#define XShapeQueryVersion _glfw.x11.xshape.QueryVersion
|
||||
#define XShapeCombineRegion _glfw.x11.xshape.ShapeCombineRegion
|
||||
#define XShapeCombineMask _glfw.x11.xshape.ShapeCombineMask
|
||||
|
||||
#include "posix_thread.h"
|
||||
#include "posix_time_linbsd.h"
|
||||
#include "xkb_unicode_linbsd.h"
|
||||
@ -365,6 +378,19 @@ typedef struct _GLFWlibraryX11
|
||||
PFN_XRenderQueryVersion QueryVersion;
|
||||
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;
|
||||
PFN_XShapeCombineMask ShapeCombineMask;
|
||||
} xshape;
|
||||
} _GLFWlibraryX11;
|
||||
|
||||
// X11-specific per-monitor data
|
||||
|
@ -2056,6 +2056,9 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (wndconfig->mousePassthrough)
|
||||
_glfwPlatformSetWindowMousePassthrough(window, GLFW_TRUE);
|
||||
|
||||
if (window->monitor)
|
||||
{
|
||||
_glfwPlatformShowWindow(window);
|
||||
@ -2741,6 +2744,25 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
|
||||
XFlush(_glfw.x11.display);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool enabled)
|
||||
{
|
||||
if (!_glfw.x11.xshape.available)
|
||||
return;
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
Region region = XCreateRegion();
|
||||
XShapeCombineRegion(_glfw.x11.display, window->x11.handle,
|
||||
ShapeInput, 0, 0, region, ShapeSet);
|
||||
XDestroyRegion(region);
|
||||
}
|
||||
else
|
||||
{
|
||||
XShapeCombineMask(_glfw.x11.display, window->x11.handle,
|
||||
ShapeInput, 0, 0, None, ShapeSet);
|
||||
}
|
||||
}
|
||||
|
||||
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
|
||||
{
|
||||
float opacity = 1.f;
|
||||
|
@ -70,6 +70,7 @@ const (
|
||||
FocusOnShow = Hint(0x0002000C)
|
||||
Iconified = Hint(0x00020002)
|
||||
Maximized = Hint(0x00020008)
|
||||
MousePassthrough = Hint(0x0002000D)
|
||||
OpenGLForwardCompatible = Hint(0x00022006)
|
||||
OpenGLProfile = Hint(0x00022008)
|
||||
Resizable = Hint(0x00020003)
|
||||
|
@ -333,6 +333,7 @@ const (
|
||||
_WS_EX_LAYERED = 0x00080000
|
||||
_WS_EX_OVERLAPPEDWINDOW = _WS_EX_WINDOWEDGE | _WS_EX_CLIENTEDGE
|
||||
_WS_EX_TOPMOST = 0x00000008
|
||||
_WS_EX_TRANSPARENT = 0x00000020
|
||||
_WS_EX_WINDOWEDGE = 0x00000100
|
||||
_WS_MAXIMIZE = 0x01000000
|
||||
_WS_MAXIMIZEBOX = 0x00010000
|
||||
|
@ -155,6 +155,10 @@ func (w *Window) platformSetWindowFloating(enabled bool) error {
|
||||
panic("goglfw: Window.platformSetWindowFloating is not implemented yet")
|
||||
}
|
||||
|
||||
func (w *Window) platformSetWindowMousePassthrough(enabled bool) error {
|
||||
panic("goglfw: Window.platformSetWindowMousePassthrough is not implemented yet")
|
||||
}
|
||||
|
||||
func (w *Window) platformGetWindowOpacity() (float32, error) {
|
||||
// cocoa_window.m:L1462
|
||||
panic("goglfw: Window.platformGetWindowOpacity is not implemented yet")
|
||||
|
@ -58,6 +58,7 @@ const (
|
||||
TransparentFramebuffer Hint = 0x0002000A
|
||||
Hovered Hint = 0x0002000B
|
||||
FocusOnShow Hint = 0x0002000C
|
||||
MousePassthrough Hint = 0x0002000D
|
||||
|
||||
RedBits Hint = 0x00021001
|
||||
GreenBits Hint = 0x00021002
|
||||
|
@ -23,19 +23,20 @@ type initconfig struct {
|
||||
}
|
||||
|
||||
type wndconfig struct {
|
||||
width int
|
||||
height int
|
||||
title string
|
||||
resizable bool
|
||||
visible bool
|
||||
decorated bool
|
||||
focused bool
|
||||
autoIconify bool
|
||||
floating bool
|
||||
maximized bool
|
||||
centerCursor bool
|
||||
focusOnShow bool
|
||||
scaleToMonitor bool
|
||||
width int
|
||||
height int
|
||||
title string
|
||||
resizable bool
|
||||
visible bool
|
||||
decorated bool
|
||||
focused bool
|
||||
autoIconify bool
|
||||
floating bool
|
||||
maximized bool
|
||||
centerCursor bool
|
||||
focusOnShow bool
|
||||
mousePassthrough bool
|
||||
scaleToMonitor bool
|
||||
}
|
||||
|
||||
type ctxconfig struct {
|
||||
@ -118,17 +119,18 @@ type (
|
||||
)
|
||||
|
||||
type Window struct {
|
||||
resizable bool
|
||||
decorated bool
|
||||
autoIconify bool
|
||||
floating bool
|
||||
focusOnShow bool
|
||||
shouldClose bool
|
||||
userPointer unsafe.Pointer
|
||||
doublebuffer bool
|
||||
videoMode VidMode
|
||||
monitor *Monitor
|
||||
cursor *Cursor
|
||||
resizable bool
|
||||
decorated bool
|
||||
autoIconify bool
|
||||
floating bool
|
||||
focusOnShow bool
|
||||
mousePassthrough bool
|
||||
shouldClose bool
|
||||
userPointer unsafe.Pointer
|
||||
doublebuffer bool
|
||||
videoMode VidMode
|
||||
monitor *Monitor
|
||||
cursor *Cursor
|
||||
|
||||
minwidth int
|
||||
minheight int
|
||||
|
@ -1409,6 +1409,12 @@ func (w *Window) platformCreateWindow(wndconfig *wndconfig, ctxconfig *ctxconfig
|
||||
}
|
||||
}
|
||||
|
||||
if wndconfig.mousePassthrough {
|
||||
if err := w.platformSetWindowMousePassthrough(true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if w.monitor != nil {
|
||||
w.platformShowWindow()
|
||||
if err := w.platformFocusWindow(); err != nil {
|
||||
@ -1972,6 +1978,49 @@ func (w *Window) platformSetWindowFloating(enabled bool) error {
|
||||
return _SetWindowPos(w.platform.handle, after, 0, 0, 0, 0, _SWP_NOACTIVATE|_SWP_NOMOVE|_SWP_NOSIZE)
|
||||
}
|
||||
|
||||
func (w *Window) platformSetWindowMousePassthrough(enabled bool) error {
|
||||
exStyle, err := _GetWindowLongW(w.platform.handle, _GWL_EXSTYLE)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var key _COLORREF
|
||||
var alpha byte
|
||||
var flags uint32
|
||||
if exStyle&_WS_EX_LAYERED != 0 {
|
||||
var err error
|
||||
key, alpha, flags, err = _GetLayeredWindowAttributes(w.platform.handle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if enabled {
|
||||
exStyle |= _WS_EX_TRANSPARENT | _WS_EX_LAYERED
|
||||
} else {
|
||||
exStyle &^= _WS_EX_TRANSPARENT
|
||||
// NOTE: Window opacity also needs the layered window style so do not
|
||||
// remove it if the window is alpha blended
|
||||
if exStyle&_WS_EX_LAYERED != 0 {
|
||||
if flags&_LWA_ALPHA == 0 {
|
||||
exStyle &^= _WS_EX_LAYERED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := _SetWindowLongW(w.platform.handle, _GWL_EXSTYLE, exStyle); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if enabled {
|
||||
if err := _SetLayeredWindowAttributes(w.platform.handle, key, alpha, flags); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Window) platformGetWindowOpacity() (float32, error) {
|
||||
style, err := _GetWindowLongW(w.platform.handle, _GWL_EXSTYLE)
|
||||
if err != nil {
|
||||
|
@ -120,13 +120,14 @@ func CreateWindow(width, height int, title string, monitor *Monitor, share *Wind
|
||||
RefreshRate: _glfw.hints.refreshRate,
|
||||
},
|
||||
|
||||
monitor: monitor,
|
||||
resizable: wndconfig.resizable,
|
||||
decorated: wndconfig.decorated,
|
||||
autoIconify: wndconfig.autoIconify,
|
||||
floating: wndconfig.floating,
|
||||
focusOnShow: wndconfig.focusOnShow,
|
||||
cursorMode: CursorNormal,
|
||||
monitor: monitor,
|
||||
resizable: wndconfig.resizable,
|
||||
decorated: wndconfig.decorated,
|
||||
autoIconify: wndconfig.autoIconify,
|
||||
floating: wndconfig.floating,
|
||||
focusOnShow: wndconfig.focusOnShow,
|
||||
mousePassthrough: wndconfig.mousePassthrough,
|
||||
cursorMode: CursorNormal,
|
||||
|
||||
doublebuffer: fbconfig.doublebuffer,
|
||||
|
||||
@ -252,6 +253,8 @@ func WindowHint(hint Hint, value int) error {
|
||||
_glfw.hints.window.centerCursor = intToBool(value)
|
||||
case FocusOnShow:
|
||||
_glfw.hints.window.focusOnShow = intToBool(value)
|
||||
case MousePassthrough:
|
||||
_glfw.hints.window.mousePassthrough = intToBool(value)
|
||||
case ClientAPI:
|
||||
_glfw.hints.context.client = value
|
||||
case ContextCreationAPI:
|
||||
@ -597,6 +600,8 @@ func (w *Window) GetAttrib(attrib Hint) (int, error) {
|
||||
return boolToInt(b), nil
|
||||
case FocusOnShow:
|
||||
return boolToInt(w.focusOnShow), nil
|
||||
case MousePassthrough:
|
||||
return boolToInt(w.mousePassthrough), nil
|
||||
case TransparentFramebuffer:
|
||||
return boolToInt(w.platformFramebufferTransparent()), nil
|
||||
case Resizable:
|
||||
@ -681,6 +686,12 @@ func (w *Window) SetAttrib(attrib Hint, value int) error {
|
||||
case FocusOnShow:
|
||||
w.focusOnShow = bValue
|
||||
return nil
|
||||
case MousePassthrough:
|
||||
w.mousePassthrough = bValue
|
||||
if err := w.platformSetWindowMousePassthrough(bValue); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("goglfw: invalid window attribute 0x%08X: %w", attrib, InvalidEnum)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user