You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-08 12:40:44 +00:00
Add window click-through support.
This commit is contained in:
@@ -901,6 +901,30 @@
|
|||||||
<description>
|
<description>
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="window_set_mouse_passthrough">
|
||||||
|
<return type="void">
|
||||||
|
</return>
|
||||||
|
<argument index="0" name="region" type="PackedVector2Array">
|
||||||
|
</argument>
|
||||||
|
<argument index="1" name="window_id" type="int" default="0">
|
||||||
|
</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.
|
||||||
|
DisplayServer.window_set_mouse_passthrough($Path2D.curve.get_baked_points())
|
||||||
|
|
||||||
|
# Set region, using Polygon2D node.
|
||||||
|
DisplayServer.window_set_mouse_passthrough($Polygon2D.polygon)
|
||||||
|
|
||||||
|
# Reset region to default.
|
||||||
|
DisplayServer.window_set_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="window_set_position">
|
<method name="window_set_position">
|
||||||
<return type="void">
|
<return type="void">
|
||||||
</return>
|
</return>
|
||||||
|
|||||||
@@ -35,6 +35,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.")
|
||||||
@@ -194,6 +199,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")
|
||||||
|
|||||||
@@ -50,6 +50,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
|
||||||
@@ -782,6 +783,38 @@ void DisplayServerX11::window_set_title(const String &p_title, WindowID p_window
|
|||||||
XChangeProperty(x11_display, wd.x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)p_title.utf8().get_data(), p_title.utf8().length());
|
XChangeProperty(x11_display, wd.x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)p_title.utf8().get_data(), p_title.utf8().length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisplayServerX11::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) {
|
||||||
|
_THREAD_SAFE_METHOD_
|
||||||
|
|
||||||
|
ERR_FAIL_COND(!windows.has(p_window));
|
||||||
|
const WindowData &wd = windows[p_window];
|
||||||
|
|
||||||
|
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 = window_get_real_size(p_window).x;
|
||||||
|
rect.height = window_get_real_size(p_window).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, wd.x11_window, ShapeInput, 0, 0, region, ShapeSet);
|
||||||
|
XDestroyRegion(region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DisplayServerX11::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
|
void DisplayServerX11::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
|
||||||
_THREAD_SAFE_METHOD_
|
_THREAD_SAFE_METHOD_
|
||||||
|
|
||||||
|
|||||||
@@ -291,6 +291,8 @@ public:
|
|||||||
virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const;
|
virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const;
|
||||||
|
|
||||||
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
|
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
|
||||||
virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
|
virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
|
virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
|
virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ public:
|
|||||||
id window_object;
|
id window_object;
|
||||||
id window_view;
|
id window_view;
|
||||||
|
|
||||||
|
Vector<Vector2> mpath;
|
||||||
|
|
||||||
#if defined(OPENGL_ENABLED)
|
#if defined(OPENGL_ENABLED)
|
||||||
ContextGL_OSX *context_gles2 = nullptr;
|
ContextGL_OSX *context_gles2 = nullptr;
|
||||||
#endif
|
#endif
|
||||||
@@ -240,6 +242,7 @@ public:
|
|||||||
virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||||
|
|
||||||
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override;
|
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||||
|
virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||||
|
|
||||||
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override;
|
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||||
virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) override;
|
virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "os_osx.h"
|
#include "os_osx.h"
|
||||||
|
|
||||||
#include "core/io/marshalls.h"
|
#include "core/io/marshalls.h"
|
||||||
|
#include "core/math/geometry_2d.h"
|
||||||
#include "core/os/keyboard.h"
|
#include "core/os/keyboard.h"
|
||||||
#include "main/main.h"
|
#include "main/main.h"
|
||||||
#include "scene/resources/texture.h"
|
#include "scene/resources/texture.h"
|
||||||
@@ -2404,6 +2405,15 @@ void DisplayServerOSX::window_set_title(const String &p_title, WindowID p_window
|
|||||||
[wd.window_object setTitle:[NSString stringWithUTF8String:p_title.utf8().get_data()]];
|
[wd.window_object setTitle:[NSString stringWithUTF8String:p_title.utf8().get_data()]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisplayServerOSX::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) {
|
||||||
|
_THREAD_SAFE_METHOD_
|
||||||
|
|
||||||
|
ERR_FAIL_COND(!windows.has(p_window));
|
||||||
|
WindowData &wd = windows[p_window];
|
||||||
|
|
||||||
|
wd.mpath = p_region;
|
||||||
|
}
|
||||||
|
|
||||||
void DisplayServerOSX::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
|
void DisplayServerOSX::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
|
||||||
_THREAD_SAFE_METHOD_
|
_THREAD_SAFE_METHOD_
|
||||||
|
|
||||||
@@ -3356,6 +3366,26 @@ void DisplayServerOSX::process_events() {
|
|||||||
Input::get_singleton()->flush_accumulated_events();
|
Input::get_singleton()->flush_accumulated_events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
|
||||||
|
WindowData &wd = E->get();
|
||||||
|
if (wd.mpath.size() > 0) {
|
||||||
|
const Vector2 mpos = _get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]);
|
||||||
|
if (Geometry2D::is_point_in_polygon(mpos, wd.mpath)) {
|
||||||
|
if ([wd.window_object ignoresMouseEvents]) {
|
||||||
|
[wd.window_object setIgnoresMouseEvents:NO];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (![wd.window_object ignoresMouseEvents]) {
|
||||||
|
[wd.window_object setIgnoresMouseEvents:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ([wd.window_object ignoresMouseEvents]) {
|
||||||
|
[wd.window_object setIgnoresMouseEvents:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[autoreleasePool drain];
|
[autoreleasePool drain];
|
||||||
autoreleasePool = [[NSAutoreleasePool alloc] init];
|
autoreleasePool = [[NSAutoreleasePool alloc] init];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,9 @@
|
|||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
#include "display_server_windows.h"
|
#include "display_server_windows.h"
|
||||||
|
|
||||||
#include "core/io/marshalls.h"
|
#include "core/io/marshalls.h"
|
||||||
|
#include "core/math/geometry_2d.h"
|
||||||
#include "main/main.h"
|
#include "main/main.h"
|
||||||
#include "os_windows.h"
|
#include "os_windows.h"
|
||||||
#include "scene/resources/texture.h"
|
#include "scene/resources/texture.h"
|
||||||
@@ -597,6 +599,36 @@ void DisplayServerWindows::window_set_title(const String &p_title, WindowID p_wi
|
|||||||
SetWindowTextW(windows[p_window].hWnd, (LPCWSTR)(p_title.utf16().get_data()));
|
SetWindowTextW(windows[p_window].hWnd, (LPCWSTR)(p_title.utf16().get_data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisplayServerWindows::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) {
|
||||||
|
_THREAD_SAFE_METHOD_
|
||||||
|
|
||||||
|
ERR_FAIL_COND(!windows.has(p_window));
|
||||||
|
windows[p_window].mpath = p_region;
|
||||||
|
_update_window_mouse_passthrough(p_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayServerWindows::_update_window_mouse_passthrough(WindowID p_window) {
|
||||||
|
if (windows[p_window].mpath.size() == 0) {
|
||||||
|
SetWindowRgn(windows[p_window].hWnd, nullptr, TRUE);
|
||||||
|
} else {
|
||||||
|
POINT *points = (POINT *)memalloc(sizeof(POINT) * windows[p_window].mpath.size());
|
||||||
|
for (int i = 0; i < windows[p_window].mpath.size(); i++) {
|
||||||
|
if (windows[p_window].borderless) {
|
||||||
|
points[i].x = windows[p_window].mpath[i].x;
|
||||||
|
points[i].y = windows[p_window].mpath[i].y;
|
||||||
|
} else {
|
||||||
|
points[i].x = windows[p_window].mpath[i].x + GetSystemMetrics(SM_CXSIZEFRAME);
|
||||||
|
points[i].y = windows[p_window].mpath[i].y + GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYCAPTION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HRGN region = CreatePolygonRgn(points, windows[p_window].mpath.size(), ALTERNATE);
|
||||||
|
SetWindowRgn(windows[p_window].hWnd, region, TRUE);
|
||||||
|
DeleteObject(region);
|
||||||
|
memfree(points);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int DisplayServerWindows::window_get_current_screen(WindowID p_window) const {
|
int DisplayServerWindows::window_get_current_screen(WindowID p_window) const {
|
||||||
_THREAD_SAFE_METHOD_
|
_THREAD_SAFE_METHOD_
|
||||||
|
|
||||||
@@ -1010,6 +1042,7 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W
|
|||||||
case WINDOW_FLAG_BORDERLESS: {
|
case WINDOW_FLAG_BORDERLESS: {
|
||||||
wd.borderless = p_enabled;
|
wd.borderless = p_enabled;
|
||||||
_update_window_style(p_window);
|
_update_window_style(p_window);
|
||||||
|
_update_window_mouse_passthrough(p_window);
|
||||||
} break;
|
} break;
|
||||||
case WINDOW_FLAG_ALWAYS_ON_TOP: {
|
case WINDOW_FLAG_ALWAYS_ON_TOP: {
|
||||||
ERR_FAIL_COND_MSG(wd.transient_parent != INVALID_WINDOW_ID && p_enabled, "Transient windows can't become on top");
|
ERR_FAIL_COND_MSG(wd.transient_parent != INVALID_WINDOW_ID && p_enabled, "Transient windows can't become on top");
|
||||||
|
|||||||
@@ -323,6 +323,8 @@ private:
|
|||||||
HWND hWnd;
|
HWND hWnd;
|
||||||
//layered window
|
//layered window
|
||||||
|
|
||||||
|
Vector<Vector2> mpath;
|
||||||
|
|
||||||
bool preserve_window_size = false;
|
bool preserve_window_size = false;
|
||||||
bool pre_fs_valid = false;
|
bool pre_fs_valid = false;
|
||||||
RECT pre_fs_rect;
|
RECT pre_fs_rect;
|
||||||
@@ -416,6 +418,7 @@ private:
|
|||||||
void _touch_event(WindowID p_window, bool p_pressed, float p_x, float p_y, int idx);
|
void _touch_event(WindowID p_window, bool p_pressed, float p_x, float p_y, int idx);
|
||||||
|
|
||||||
void _update_window_style(WindowID p_window, bool p_repaint = true, bool p_maximized = false);
|
void _update_window_style(WindowID p_window, bool p_repaint = true, bool p_maximized = false);
|
||||||
|
void _update_window_mouse_passthrough(WindowID p_window);
|
||||||
|
|
||||||
void _update_real_mouse_position(WindowID p_window);
|
void _update_real_mouse_position(WindowID p_window);
|
||||||
|
|
||||||
@@ -477,6 +480,7 @@ public:
|
|||||||
virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
|
virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
|
||||||
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
|
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
|
||||||
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const;
|
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const;
|
||||||
virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID);
|
virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
|||||||
@@ -194,6 +194,10 @@ void DisplayServer::delete_sub_window(WindowID p_id) {
|
|||||||
ERR_FAIL_MSG("Sub-windows not supported by this display server.");
|
ERR_FAIL_MSG("Sub-windows not supported by this display server.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisplayServer::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) {
|
||||||
|
ERR_FAIL_MSG("Mouse passthrough not supported by this display server.");
|
||||||
|
}
|
||||||
|
|
||||||
void DisplayServer::window_set_ime_active(const bool p_active, WindowID p_window) {
|
void DisplayServer::window_set_ime_active(const bool p_active, WindowID p_window) {
|
||||||
WARN_PRINT("IME not supported by this display server.");
|
WARN_PRINT("IME not supported by this display server.");
|
||||||
}
|
}
|
||||||
@@ -412,6 +416,7 @@ void DisplayServer::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("delete_sub_window", "window_id"), &DisplayServer::delete_sub_window);
|
ClassDB::bind_method(D_METHOD("delete_sub_window", "window_id"), &DisplayServer::delete_sub_window);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("window_set_title", "title", "window_id"), &DisplayServer::window_set_title, DEFVAL(MAIN_WINDOW_ID));
|
ClassDB::bind_method(D_METHOD("window_set_title", "title", "window_id"), &DisplayServer::window_set_title, DEFVAL(MAIN_WINDOW_ID));
|
||||||
|
ClassDB::bind_method(D_METHOD("window_set_mouse_passthrough", "region", "window_id"), &DisplayServer::window_set_mouse_passthrough, DEFVAL(MAIN_WINDOW_ID));
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("window_get_current_screen", "window_id"), &DisplayServer::window_get_current_screen, DEFVAL(MAIN_WINDOW_ID));
|
ClassDB::bind_method(D_METHOD("window_get_current_screen", "window_id"), &DisplayServer::window_get_current_screen, DEFVAL(MAIN_WINDOW_ID));
|
||||||
ClassDB::bind_method(D_METHOD("window_set_current_screen", "screen", "window_id"), &DisplayServer::window_set_current_screen, DEFVAL(MAIN_WINDOW_ID));
|
ClassDB::bind_method(D_METHOD("window_set_current_screen", "screen", "window_id"), &DisplayServer::window_set_current_screen, DEFVAL(MAIN_WINDOW_ID));
|
||||||
|
|||||||
@@ -247,6 +247,8 @@ public:
|
|||||||
|
|
||||||
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) = 0;
|
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) = 0;
|
||||||
|
|
||||||
|
virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID);
|
||||||
|
|
||||||
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const = 0;
|
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const = 0;
|
||||||
virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) = 0;
|
virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) = 0;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user