Skip to content

Commit 101fbbb

Browse files
committed
[Window] Add unfiltered input handler signal for custom decorations.
1 parent cb7cd81 commit 101fbbb

File tree

5 files changed

+96
-47
lines changed

5 files changed

+96
-47
lines changed

doc/classes/Window.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,9 @@
691691
[b]Note:[/b] On Windows, the portion of a window that lies outside the region is not drawn, while on Linux (X11) and macOS it is.
692692
[b]Note:[/b] This property is implemented on Linux (X11), macOS and Windows.
693693
</member>
694+
<member name="nonclient_area" type="Rect2i" setter="set_nonclient_area" getter="get_nonclient_area" default="Rect2i(0, 0, 0, 0)">
695+
If set, defines the window's custom decoration area which will receive mouse input, even if normal input to the window is blocked (such as when it has an exclusive child opened). See also [signal nonclient_window_input].
696+
</member>
694697
<member name="popup_window" type="bool" setter="set_flag" getter="get_flag" default="false">
695698
If [code]true[/code], the [Window] will be considered a popup. Popups are sub-windows that don't show as separate windows in system's window manager's window list and will send close request when anything is clicked outside of them (unless [member exclusive] is enabled).
696699
</member>
@@ -803,6 +806,12 @@
803806
Emitted when the mouse cursor leaves the [Window]'s visible area, that is not occluded behind other [Control]s or windows, provided its [member Viewport.gui_disable_input] is [code]false[/code] and regardless if it's currently focused or not.
804807
</description>
805808
</signal>
809+
<signal name="nonclient_window_input">
810+
<param index="0" name="event" type="InputEvent" />
811+
<description>
812+
Emitted when the mouse event is received by the custom decoration area defined by [member nonclient_area], and normal input to the window is blocked (such as when it has an exclusive child opened). [param event]'s position is in the embedder's coordinate system.
813+
</description>
814+
</signal>
806815
<signal name="theme_changed">
807816
<description>
808817
Emitted when the [constant NOTIFICATION_THEME_CHANGED] notification is sent.

editor/gui/editor_title_bar.cpp

Lines changed: 61 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -89,57 +89,71 @@ Control *EditorTitleBar::get_center_control() const {
8989
}
9090

9191
void EditorTitleBar::_notification(int p_what) {
92-
if (!center_control || p_what != NOTIFICATION_SORT_CHILDREN) {
93-
return;
94-
}
95-
96-
Control *prev = nullptr;
97-
Control *base = nullptr;
98-
Control *next = nullptr;
99-
100-
bool rtl = is_layout_rtl();
101-
102-
int start;
103-
int end;
104-
int delta;
105-
if (rtl) {
106-
start = get_child_count() - 1;
107-
end = -1;
108-
delta = -1;
109-
} else {
110-
start = 0;
111-
end = get_child_count();
112-
delta = +1;
113-
}
114-
115-
for (int i = start; i != end; i += delta) {
116-
Control *c = as_sortable_control(get_child(i));
117-
if (!c) {
118-
continue;
119-
}
120-
if (base) {
121-
next = c;
122-
break;
123-
}
124-
if (c != center_control) {
125-
prev = c;
126-
continue;
92+
switch (p_what) {
93+
case NOTIFICATION_EXIT_TREE: {
94+
SceneTree::get_singleton()->get_root()->disconnect(SceneStringName(nonclient_window_input), callable_mp(this, &EditorTitleBar::gui_input));
95+
get_window()->set_nonclient_area(Rect2i());
96+
} break;
97+
case NOTIFICATION_ENTER_TREE: {
98+
SceneTree::get_singleton()->get_root()->connect(SceneStringName(nonclient_window_input), callable_mp(this, &EditorTitleBar::gui_input));
99+
[[fallthrough]];
127100
}
128-
base = c;
129-
}
130-
if (base && prev && next) {
131-
Size2i title_size = get_size();
132-
Size2i c_size = base->get_combined_minimum_size();
101+
case NOTIFICATION_RESIZED: {
102+
get_window()->set_nonclient_area(get_global_transform().xform(Rect2i(get_position(), get_size())));
103+
} break;
104+
case NOTIFICATION_SORT_CHILDREN: {
105+
if (!center_control) {
106+
break;
107+
}
108+
Control *prev = nullptr;
109+
Control *base = nullptr;
110+
Control *next = nullptr;
111+
112+
bool rtl = is_layout_rtl();
113+
114+
int start;
115+
int end;
116+
int delta;
117+
if (rtl) {
118+
start = get_child_count() - 1;
119+
end = -1;
120+
delta = -1;
121+
} else {
122+
start = 0;
123+
end = get_child_count();
124+
delta = +1;
125+
}
133126

134-
int min_offset = prev->get_position().x + prev->get_combined_minimum_size().x;
135-
int max_offset = next->get_position().x + next->get_size().x - next->get_combined_minimum_size().x - c_size.x;
127+
for (int i = start; i != end; i += delta) {
128+
Control *c = as_sortable_control(get_child(i));
129+
if (!c) {
130+
continue;
131+
}
132+
if (base) {
133+
next = c;
134+
break;
135+
}
136+
if (c != center_control) {
137+
prev = c;
138+
continue;
139+
}
140+
base = c;
141+
}
142+
if (base && prev && next) {
143+
Size2i title_size = get_size();
144+
Size2i c_size = base->get_combined_minimum_size();
136145

137-
int offset = (title_size.width - c_size.width) / 2;
138-
offset = CLAMP(offset, min_offset, max_offset);
146+
int min_offset = prev->get_position().x + prev->get_combined_minimum_size().x;
147+
int max_offset = next->get_position().x + next->get_size().x - next->get_combined_minimum_size().x - c_size.x;
139148

140-
fit_child_in_rect(prev, Rect2i(prev->get_position().x, 0, offset - prev->get_position().x, title_size.height));
141-
fit_child_in_rect(base, Rect2i(offset, 0, c_size.width, title_size.height));
142-
fit_child_in_rect(next, Rect2i(offset + c_size.width, 0, next->get_position().x + next->get_size().x - (offset + c_size.width), title_size.height));
149+
int offset = (title_size.width - c_size.width) / 2;
150+
offset = CLAMP(offset, min_offset, max_offset);
151+
152+
fit_child_in_rect(prev, Rect2i(prev->get_position().x, 0, offset - prev->get_position().x, title_size.height));
153+
fit_child_in_rect(base, Rect2i(offset, 0, c_size.width, title_size.height));
154+
fit_child_in_rect(next, Rect2i(offset + c_size.width, 0, next->get_position().x + next->get_size().x - (offset + c_size.width), title_size.height));
155+
}
156+
} break;
143157
}
144158
}
145159

scene/main/window.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,6 +1726,15 @@ real_t Window::get_content_scale_factor() const {
17261726
return content_scale_factor;
17271727
}
17281728

1729+
void Window::set_nonclient_area(const Rect2i &p_rect) {
1730+
ERR_MAIN_THREAD_GUARD;
1731+
nonclient_area = p_rect;
1732+
}
1733+
1734+
Rect2i Window::get_nonclient_area() const {
1735+
return nonclient_area;
1736+
}
1737+
17291738
DisplayServer::WindowID Window::get_window_id() const {
17301739
ERR_READ_THREAD_GUARD_V(DisplayServer::INVALID_WINDOW_ID);
17311740
if (get_embedder()) {
@@ -1816,6 +1825,12 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) {
18161825
ERR_MAIN_THREAD_GUARD;
18171826

18181827
if (exclusive_child != nullptr) {
1828+
if (nonclient_area.has_area() && is_inside_tree()) {
1829+
Ref<InputEventMouse> me = p_ev;
1830+
if (me.is_valid() && nonclient_area.has_point(me->get_position())) {
1831+
emit_signal(SceneStringName(nonclient_window_input), p_ev);
1832+
}
1833+
}
18191834
if (!is_embedding_subwindows()) { // Not embedding, no need for event.
18201835
return;
18211836
}
@@ -3227,6 +3242,9 @@ void Window::_bind_methods() {
32273242
ClassDB::bind_method(D_METHOD("set_content_scale_stretch", "stretch"), &Window::set_content_scale_stretch);
32283243
ClassDB::bind_method(D_METHOD("get_content_scale_stretch"), &Window::get_content_scale_stretch);
32293244

3245+
ClassDB::bind_method(D_METHOD("set_nonclient_area", "area"), &Window::set_nonclient_area);
3246+
ClassDB::bind_method(D_METHOD("get_nonclient_area"), &Window::get_nonclient_area);
3247+
32303248
ClassDB::bind_method(D_METHOD("set_keep_title_visible", "title_visible"), &Window::set_keep_title_visible);
32313249
ClassDB::bind_method(D_METHOD("get_keep_title_visible"), &Window::get_keep_title_visible);
32323250

@@ -3331,6 +3349,7 @@ void Window::_bind_methods() {
33313349
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position");
33323350
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
33333351
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_current_screen", "get_current_screen");
3352+
ADD_PROPERTY(PropertyInfo(Variant::RECT2I, "nonclient_area", PROPERTY_HINT_NONE, ""), "set_nonclient_area", "get_nonclient_area");
33343353

33353354
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "mouse_passthrough_polygon"), "set_mouse_passthrough_polygon", "get_mouse_passthrough_polygon");
33363355

@@ -3380,6 +3399,7 @@ void Window::_bind_methods() {
33803399
ADD_PROPERTY(PropertyInfo(Variant::STRING, "theme_type_variation", PROPERTY_HINT_ENUM_SUGGESTION), "set_theme_type_variation", "get_theme_type_variation");
33813400

33823401
ADD_SIGNAL(MethodInfo("window_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
3402+
ADD_SIGNAL(MethodInfo("nonclient_window_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
33833403
ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files")));
33843404
ADD_SIGNAL(MethodInfo("mouse_entered"));
33853405
ADD_SIGNAL(MethodInfo("mouse_exited"));

scene/main/window.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ class Window : public Viewport {
171171

172172
Size2i max_size_used;
173173

174+
Rect2i nonclient_area;
175+
174176
Size2i _clamp_limit_size(const Size2i &p_limit_size);
175177
Size2i _clamp_window_size(const Size2i &p_size);
176178
void _validate_limit_size();
@@ -391,6 +393,9 @@ class Window : public Viewport {
391393
void set_content_scale_factor(real_t p_factor);
392394
real_t get_content_scale_factor() const;
393395

396+
void set_nonclient_area(const Rect2i &p_rect);
397+
Rect2i get_nonclient_area() const;
398+
394399
void set_mouse_passthrough_polygon(const Vector<Vector2> &p_region);
395400
Vector<Vector2> get_mouse_passthrough_polygon() const;
396401

scene/scene_string_names.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class SceneStringNames {
5353
const StringName input_event = "input_event";
5454
const StringName gui_input = "gui_input";
5555
const StringName window_input = "window_input";
56+
const StringName nonclient_window_input = "nonclient_window_input";
5657

5758
const StringName tree_entered = "tree_entered";
5859
const StringName tree_exiting = "tree_exiting";

0 commit comments

Comments
 (0)