Merge pull request #40205 from bruvzg/click-through-3
[3.2] Add mouse event pass-through support for window.
This commit is contained in:
commit
4ad74609ce
11 changed files with 128 additions and 0 deletions
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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];
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue