Merge pull request #40205 from bruvzg/click-through-3

[3.2] Add mouse event pass-through support for window.
This commit is contained in:
Rémi Verschelde 2020-10-01 13:58:24 +02:00 committed by GitHub
commit 4ad74609ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 128 additions and 0 deletions

View file

@ -215,6 +215,11 @@ void _OS::set_window_title(const String &p_title) {
OS::get_singleton()->set_window_title(p_title); OS::get_singleton()->set_window_title(p_title);
} }
void _OS::set_window_mouse_passthrough(const PoolVector2Array &p_region) {
OS::get_singleton()->set_window_mouse_passthrough(p_region);
}
int _OS::get_mouse_button_state() const { int _OS::get_mouse_button_state() const {
return OS::get_singleton()->get_mouse_button_state(); return OS::get_singleton()->get_mouse_button_state();
@ -1307,6 +1312,7 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_touchscreen_ui_hint"), &_OS::has_touchscreen_ui_hint); ClassDB::bind_method(D_METHOD("has_touchscreen_ui_hint"), &_OS::has_touchscreen_ui_hint);
ClassDB::bind_method(D_METHOD("set_window_title", "title"), &_OS::set_window_title); ClassDB::bind_method(D_METHOD("set_window_title", "title"), &_OS::set_window_title);
ClassDB::bind_method(D_METHOD("set_window_mouse_passthrough", "region"), &_OS::set_window_mouse_passthrough);
ClassDB::bind_method(D_METHOD("set_low_processor_usage_mode", "enable"), &_OS::set_low_processor_usage_mode); ClassDB::bind_method(D_METHOD("set_low_processor_usage_mode", "enable"), &_OS::set_low_processor_usage_mode);
ClassDB::bind_method(D_METHOD("is_in_low_processor_usage_mode"), &_OS::is_in_low_processor_usage_mode); ClassDB::bind_method(D_METHOD("is_in_low_processor_usage_mode"), &_OS::is_in_low_processor_usage_mode);

View file

@ -150,6 +150,7 @@ public:
Point2 get_mouse_position() const; Point2 get_mouse_position() const;
void set_window_title(const String &p_title); void set_window_title(const String &p_title);
void set_window_mouse_passthrough(const PoolVector2Array &p_region);
int get_mouse_button_state() const; int get_mouse_button_state() const;
void set_clipboard(const String &p_text); void set_clipboard(const String &p_text);

View file

@ -174,6 +174,7 @@ public:
virtual Point2 get_mouse_position() const = 0; virtual Point2 get_mouse_position() const = 0;
virtual int get_mouse_button_state() const = 0; virtual int get_mouse_button_state() const = 0;
virtual void set_window_title(const String &p_title) = 0; virtual void set_window_title(const String &p_title) = 0;
virtual void set_window_mouse_passthrough(const PoolVector2Array &p_region){};
virtual void set_clipboard(const String &p_text); virtual void set_clipboard(const String &p_text);
virtual String get_clipboard() const; virtual String get_clipboard() const;

View file

@ -966,6 +966,28 @@
[b]Note:[/b] This method is implemented on Linux, macOS and Windows. [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
</description> </description>
</method> </method>
<method name="set_window_mouse_passthrough">
<return type="void">
</return>
<argument index="0" name="region" type="PoolVector2Array">
</argument>
<description>
Sets a polygonal region of the window which accepts mouse events. Mouse events outside the region will be passed through.
Passing an empty array will disable passthrough support (all mouse events will be intercepted by the window, which is the default behavior).
[codeblock]
# Set region, using Path2D node.
OS.set_window_mouse_passthrough($Path2D.curve.get_baked_points())
# Set region, using Polygon2D node.
OS.set_window_mouse_passthrough($Polygon2D.polygon)
# Reset region to default.
OS.set_window_mouse_passthrough([])
[/codeblock]
[b]Note:[/b] On Windows, the portion of a window that lies outside the region is not drawn, while on Linux and macOS it is.
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
</description>
</method>
<method name="set_window_title"> <method name="set_window_title">
<return type="void"> <return type="void">
</return> </return>

View file

@ -114,6 +114,7 @@ public:
NSOpenGLPixelFormat *pixelFormat; NSOpenGLPixelFormat *pixelFormat;
NSOpenGLContext *context; NSOpenGLContext *context;
Vector<Vector2> mpath;
bool layered_window; bool layered_window;
CursorShape cursor_shape; CursorShape cursor_shape;
@ -208,6 +209,7 @@ public:
virtual int get_mouse_button_state() const; virtual int get_mouse_button_state() const;
void update_real_mouse_position(); void update_real_mouse_position();
virtual void set_window_title(const String &p_title); virtual void set_window_title(const String &p_title);
virtual void set_window_mouse_passthrough(const PoolVector2Array &p_region);
virtual Size2 get_window_size() const; virtual Size2 get_window_size() const;
virtual Size2 get_real_window_size() const; virtual Size2 get_real_window_size() const;

View file

@ -30,6 +30,7 @@
#include "os_osx.h" #include "os_osx.h"
#include "core/math/geometry.h"
#include "core/os/keyboard.h" #include "core/os/keyboard.h"
#include "core/print_string.h" #include "core/print_string.h"
#include "core/version_generated.gen.h" #include "core/version_generated.gen.h"
@ -2136,6 +2137,13 @@ void OS_OSX::set_window_title(const String &p_title) {
[window_object setTitle:[NSString stringWithUTF8String:p_title.utf8().get_data()]]; [window_object setTitle:[NSString stringWithUTF8String:p_title.utf8().get_data()]];
} }
void OS_OSX::set_window_mouse_passthrough(const PoolVector2Array &p_region) {
mpath.clear();
for (int i = 0; i < p_region.size(); i++) {
mpath.push_back(p_region[i]);
}
}
void OS_OSX::set_native_icon(const String &p_filename) { void OS_OSX::set_native_icon(const String &p_filename) {
FileAccess *f = FileAccess::open(p_filename, FileAccess::READ); FileAccess *f = FileAccess::open(p_filename, FileAccess::READ);
@ -3053,6 +3061,23 @@ void OS_OSX::process_events() {
} }
process_key_events(); process_key_events();
if (mpath.size() > 0) {
const Vector2 mpos = get_mouse_pos([window_object mouseLocationOutsideOfEventStream]);
if (Geometry::is_point_in_polygon(mpos, mpath)) {
if ([window_object ignoresMouseEvents]) {
[window_object setIgnoresMouseEvents:NO];
}
} else {
if (![window_object ignoresMouseEvents]) {
[window_object setIgnoresMouseEvents:YES];
}
}
} else {
if ([window_object ignoresMouseEvents]) {
[window_object setIgnoresMouseEvents:NO];
}
}
[autoreleasePool drain]; [autoreleasePool drain];
autoreleasePool = [[NSAutoreleasePool alloc] init]; autoreleasePool = [[NSAutoreleasePool alloc] init];

View file

@ -34,6 +34,7 @@
#include "os_windows.h" #include "os_windows.h"
#include "core/io/marshalls.h" #include "core/io/marshalls.h"
#include "core/math/geometry.h"
#include "core/version_generated.gen.h" #include "core/version_generated.gen.h"
#include "drivers/gles2/rasterizer_gles2.h" #include "drivers/gles2/rasterizer_gles2.h"
#include "drivers/gles3/rasterizer_gles3.h" #include "drivers/gles3/rasterizer_gles3.h"
@ -1952,6 +1953,36 @@ void OS_Windows::set_window_title(const String &p_title) {
SetWindowTextW(hWnd, p_title.c_str()); SetWindowTextW(hWnd, p_title.c_str());
} }
void OS_Windows::set_window_mouse_passthrough(const PoolVector2Array &p_region) {
mpath.clear();
for (int i = 0; i < p_region.size(); i++) {
mpath.push_back(p_region[i]);
}
_update_window_mouse_passthrough();
}
void OS_Windows::_update_window_mouse_passthrough() {
if (mpath.size() == 0) {
SetWindowRgn(hWnd, NULL, TRUE);
} else {
POINT *points = (POINT *)memalloc(sizeof(POINT) * mpath.size());
for (int i = 0; i < mpath.size(); i++) {
if (video_mode.borderless_window) {
points[i].x = mpath[i].x;
points[i].y = mpath[i].y;
} else {
points[i].x = mpath[i].x + GetSystemMetrics(SM_CXSIZEFRAME);
points[i].y = mpath[i].y + GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYCAPTION);
}
}
HRGN region = CreatePolygonRgn(points, mpath.size(), ALTERNATE);
SetWindowRgn(hWnd, region, TRUE);
DeleteObject(region);
memfree(points);
}
}
void OS_Windows::set_video_mode(const VideoMode &p_video_mode, int p_screen) { void OS_Windows::set_video_mode(const VideoMode &p_video_mode, int p_screen) {
} }
@ -2339,6 +2370,7 @@ void OS_Windows::set_borderless_window(bool p_borderless) {
preserve_window_size = true; preserve_window_size = true;
_update_window_style(); _update_window_style();
_update_window_mouse_passthrough();
} }
bool OS_Windows::get_borderless_window() { bool OS_Windows::get_borderless_window() {

View file

@ -309,6 +309,8 @@ class OS_Windows : public OS {
int pressrc; int pressrc;
HINSTANCE hInstance; // Holds The Instance Of The Application HINSTANCE hInstance; // Holds The Instance Of The Application
HWND hWnd; HWND hWnd;
Vector<Vector2> mpath;
Point2 last_pos; Point2 last_pos;
bool layered_window; bool layered_window;
@ -371,6 +373,7 @@ class OS_Windows : public OS {
void _touch_event(bool p_pressed, float p_x, float p_y, int idx); void _touch_event(bool p_pressed, float p_x, float p_y, int idx);
void _update_window_style(bool p_repaint = true, bool p_maximized = false); void _update_window_style(bool p_repaint = true, bool p_maximized = false);
void _update_window_mouse_passthrough();
void _set_mouse_mode_impl(MouseMode p_mode); void _set_mouse_mode_impl(MouseMode p_mode);
@ -422,6 +425,7 @@ public:
void update_real_mouse_position(); void update_real_mouse_position();
virtual int get_mouse_button_state() const; virtual int get_mouse_button_state() const;
virtual void set_window_title(const String &p_title); virtual void set_window_title(const String &p_title);
virtual void set_window_mouse_passthrough(const PoolVector2Array &p_region);
virtual void set_video_mode(const VideoMode &p_video_mode, int p_screen = 0); virtual void set_video_mode(const VideoMode &p_video_mode, int p_screen = 0);
virtual VideoMode get_video_mode(int p_screen = 0) const; virtual VideoMode get_video_mode(int p_screen = 0) const;

View file

@ -36,6 +36,11 @@ def can_build():
print("xinerama not found.. x11 disabled.") print("xinerama not found.. x11 disabled.")
return False return False
x11_error = os.system("pkg-config xext --modversion > /dev/null ")
if x11_error:
print("xext not found.. x11 disabled.")
return False
x11_error = os.system("pkg-config xrandr --modversion > /dev/null ") x11_error = os.system("pkg-config xrandr --modversion > /dev/null ")
if x11_error: if x11_error:
print("xrandr not found.. x11 disabled.") print("xrandr not found.. x11 disabled.")
@ -213,6 +218,7 @@ def configure(env):
env.ParseConfig("pkg-config x11 --cflags --libs") env.ParseConfig("pkg-config x11 --cflags --libs")
env.ParseConfig("pkg-config xcursor --cflags --libs") env.ParseConfig("pkg-config xcursor --cflags --libs")
env.ParseConfig("pkg-config xinerama --cflags --libs") env.ParseConfig("pkg-config xinerama --cflags --libs")
env.ParseConfig("pkg-config xext --cflags --libs")
env.ParseConfig("pkg-config xrandr --cflags --libs") env.ParseConfig("pkg-config xrandr --cflags --libs")
env.ParseConfig("pkg-config xrender --cflags --libs") env.ParseConfig("pkg-config xrender --cflags --libs")
env.ParseConfig("pkg-config xi --cflags --libs") env.ParseConfig("pkg-config xi --cflags --libs")

View file

@ -52,6 +52,7 @@
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <X11/extensions/Xinerama.h> #include <X11/extensions/Xinerama.h>
#include <X11/extensions/shape.h>
// ICCCM // ICCCM
#define WM_NormalState 1L // window normal state #define WM_NormalState 1L // window normal state
@ -996,6 +997,33 @@ void OS_X11::set_window_title(const String &p_title) {
XChangeProperty(x11_display, x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)p_title.utf8().get_data(), p_title.utf8().length()); XChangeProperty(x11_display, x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)p_title.utf8().get_data(), p_title.utf8().length());
} }
void OS_X11::set_window_mouse_passthrough(const PoolVector2Array &p_region) {
int event_base, error_base;
const Bool ext_okay = XShapeQueryExtension(x11_display, &event_base, &error_base);
if (ext_okay) {
Region region;
if (p_region.size() == 0) {
region = XCreateRegion();
XRectangle rect;
rect.x = 0;
rect.y = 0;
rect.width = get_real_window_size().x;
rect.height = get_real_window_size().y;
XUnionRectWithRegion(&rect, region, region);
} else {
XPoint *points = (XPoint *)memalloc(sizeof(XPoint) * p_region.size());
for (int i = 0; i < p_region.size(); i++) {
points[i].x = p_region[i].x;
points[i].y = p_region[i].y;
}
region = XPolygonRegion(points, p_region.size(), EvenOddRule);
memfree(points);
}
XShapeCombineRegion(x11_display, x11_window, ShapeInput, 0, 0, region, ShapeSet);
XDestroyRegion(region);
}
}
void OS_X11::set_video_mode(const VideoMode &p_video_mode, int p_screen) { void OS_X11::set_video_mode(const VideoMode &p_video_mode, int p_screen) {
} }

View file

@ -254,6 +254,7 @@ public:
virtual Point2 get_mouse_position() const; virtual Point2 get_mouse_position() const;
virtual int get_mouse_button_state() const; virtual int get_mouse_button_state() const;
virtual void set_window_title(const String &p_title); virtual void set_window_title(const String &p_title);
virtual void set_window_mouse_passthrough(const PoolVector2Array &p_region);
virtual void set_icon(const Ref<Image> &p_icon); virtual void set_icon(const Ref<Image> &p_icon);