Skip to content

Commit 3b4239d

Browse files
committed
Merge pull request godotengine#111288 from bruvzg/move_input
[Window] Add unfiltered input handler signal for custom decorations.
2 parents 62edbc2 + 101fbbb commit 3b4239d

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
@@ -1727,6 +1727,15 @@ real_t Window::get_content_scale_factor() const {
17271727
return content_scale_factor;
17281728
}
17291729

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

18191828
if (exclusive_child != nullptr) {
1829+
if (nonclient_area.has_area() && is_inside_tree()) {
1830+
Ref<InputEventMouse> me = p_ev;
1831+
if (me.is_valid() && nonclient_area.has_point(me->get_position())) {
1832+
emit_signal(SceneStringName(nonclient_window_input), p_ev);
1833+
}
1834+
}
18201835
if (!is_embedding_subwindows()) { // Not embedding, no need for event.
18211836
return;
18221837
}
@@ -3222,6 +3237,9 @@ void Window::_bind_methods() {
32223237
ClassDB::bind_method(D_METHOD("set_content_scale_stretch", "stretch"), &Window::set_content_scale_stretch);
32233238
ClassDB::bind_method(D_METHOD("get_content_scale_stretch"), &Window::get_content_scale_stretch);
32243239

3240+
ClassDB::bind_method(D_METHOD("set_nonclient_area", "area"), &Window::set_nonclient_area);
3241+
ClassDB::bind_method(D_METHOD("get_nonclient_area"), &Window::get_nonclient_area);
3242+
32253243
ClassDB::bind_method(D_METHOD("set_keep_title_visible", "title_visible"), &Window::set_keep_title_visible);
32263244
ClassDB::bind_method(D_METHOD("get_keep_title_visible"), &Window::get_keep_title_visible);
32273245

@@ -3326,6 +3344,7 @@ void Window::_bind_methods() {
33263344
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position");
33273345
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
33283346
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_current_screen", "get_current_screen");
3347+
ADD_PROPERTY(PropertyInfo(Variant::RECT2I, "nonclient_area", PROPERTY_HINT_NONE, ""), "set_nonclient_area", "get_nonclient_area");
33293348

33303349
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "mouse_passthrough_polygon"), "set_mouse_passthrough_polygon", "get_mouse_passthrough_polygon");
33313350

@@ -3375,6 +3394,7 @@ void Window::_bind_methods() {
33753394
ADD_PROPERTY(PropertyInfo(Variant::STRING, "theme_type_variation", PROPERTY_HINT_ENUM_SUGGESTION), "set_theme_type_variation", "get_theme_type_variation");
33763395

33773396
ADD_SIGNAL(MethodInfo("window_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
3397+
ADD_SIGNAL(MethodInfo("nonclient_window_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
33783398
ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files")));
33793399
ADD_SIGNAL(MethodInfo("mouse_entered"));
33803400
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)