Browse Source

Window management improvements.

[macOS] Fix transient windows not working in the full-screen mode.
[macOS] Fix moving transient windows to the other screen than parent window.
[macOS] Fix popup menu switch on hover.
[macOS] Use content origin rect for windows position (to ensure `DS.mouse_get_position` is equal to `DS.window_get_position` + mouse position from the input events).
[macOS] Fix incorrect input coordinates, when external display with different scaling in connected/disconnected.
[macOS/Windows] Fix moving fullscreen windows between the screens.
Add auto refocusing of the parent window, when the focused transient window is closed.
Remove redundant `DS.mouse_get_absolute_position` function (returns mouse position in the screen coordinates, same as `DS.mouse_get_position`).
bruvzg 3 years ago
parent
commit
d62ca0c9c0

+ 0 - 5
doc/classes/DisplayServer.xml

@@ -321,11 +321,6 @@
 				[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="mouse_get_absolute_position" qualifiers="const">
-			<return type="Vector2i" />
-			<description>
-			</description>
-		</method>
 		<method name="mouse_get_button_state" qualifiers="const">
 		<method name="mouse_get_button_state" qualifiers="const">
 			<return type="int" enum="MouseButton" />
 			<return type="int" enum="MouseButton" />
 			<description>
 			<description>

+ 0 - 15
platform/linuxbsd/display_server_x11.cpp

@@ -365,21 +365,6 @@ void DisplayServerX11::mouse_warp_to_position(const Point2i &p_to) {
 }
 }
 
 
 Point2i DisplayServerX11::mouse_get_position() const {
 Point2i DisplayServerX11::mouse_get_position() const {
-	int root_x, root_y;
-	int win_x, win_y;
-	unsigned int mask_return;
-	Window window_returned;
-
-	Bool result = XQueryPointer(x11_display, RootWindow(x11_display, DefaultScreen(x11_display)), &window_returned,
-			&window_returned, &root_x, &root_y, &win_x, &win_y,
-			&mask_return);
-	if (result == True) {
-		return Point2i(root_x, root_y);
-	}
-	return Point2i();
-}
-
-Point2i DisplayServerX11::mouse_get_absolute_position() const {
 	int number_of_screens = XScreenCount(x11_display);
 	int number_of_screens = XScreenCount(x11_display);
 	for (int i = 0; i < number_of_screens; i++) {
 	for (int i = 0; i < number_of_screens; i++) {
 		Window root, child;
 		Window root, child;

+ 0 - 1
platform/linuxbsd/display_server_x11.h

@@ -289,7 +289,6 @@ public:
 
 
 	virtual void mouse_warp_to_position(const Point2i &p_to) override;
 	virtual void mouse_warp_to_position(const Point2i &p_to) override;
 	virtual Point2i mouse_get_position() const override;
 	virtual Point2i mouse_get_position() const override;
-	virtual Point2i mouse_get_absolute_position() const override;
 	virtual MouseButton mouse_get_button_state() const override;
 	virtual MouseButton mouse_get_button_state() const override;
 
 
 	virtual void clipboard_set(const String &p_text) override;
 	virtual void clipboard_set(const String &p_text) override;

+ 2 - 1
platform/osx/display_server_osx.h

@@ -98,6 +98,8 @@ public:
 	NSTimeInterval last_warp = 0;
 	NSTimeInterval last_warp = 0;
 	bool ignore_warp = false;
 	bool ignore_warp = false;
 
 
+	float display_max_scale = 1.f;
+
 	Vector<KeyEvent> key_event_buffer;
 	Vector<KeyEvent> key_event_buffer;
 	int key_event_pos;
 	int key_event_pos;
 
 
@@ -214,7 +216,6 @@ public:
 
 
 	virtual void mouse_warp_to_position(const Point2i &p_to) override;
 	virtual void mouse_warp_to_position(const Point2i &p_to) override;
 	virtual Point2i mouse_get_position() const override;
 	virtual Point2i mouse_get_position() const override;
-	virtual Point2i mouse_get_absolute_position() const override;
 	virtual MouseButton mouse_get_button_state() const override;
 	virtual MouseButton mouse_get_button_state() const override;
 
 
 	virtual void clipboard_set(const String &p_text) override;
 	virtual void clipboard_set(const String &p_text) override;

+ 38 - 25
platform/osx/display_server_osx.mm

@@ -158,12 +158,7 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
 	}
 	}
 
 
 	if (wd.transient_parent != DisplayServerOSX::INVALID_WINDOW_ID) {
 	if (wd.transient_parent != DisplayServerOSX::INVALID_WINDOW_ID) {
-		DisplayServerOSX::WindowData &pwd = DS_OSX->windows[wd.transient_parent];
-		[pwd.window_object makeKeyAndOrderFront:nil]; // Move focus back to parent.
 		DS_OSX->window_set_transient(window_id, DisplayServerOSX::INVALID_WINDOW_ID);
 		DS_OSX->window_set_transient(window_id, DisplayServerOSX::INVALID_WINDOW_ID);
-	} else if ((window_id != DisplayServerOSX::MAIN_WINDOW_ID) && (DS_OSX->windows.size() == 1)) {
-		DisplayServerOSX::WindowData &pwd = DS_OSX->windows[DisplayServerOSX::MAIN_WINDOW_ID];
-		[pwd.window_object makeKeyAndOrderFront:nil]; // Move focus back to main window if there is no parent or other windows left.
 	}
 	}
 
 
 #if defined(GLES3_ENABLED)
 #if defined(GLES3_ENABLED)
@@ -2001,10 +1996,6 @@ void DisplayServerOSX::mouse_warp_to_position(const Point2i &p_to) {
 }
 }
 
 
 Point2i DisplayServerOSX::mouse_get_position() const {
 Point2i DisplayServerOSX::mouse_get_position() const {
-	return last_mouse_pos;
-}
-
-Point2i DisplayServerOSX::mouse_get_absolute_position() const {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 
 
 	const NSPoint mouse_pos = [NSEvent mouseLocation];
 	const NSPoint mouse_pos = [NSEvent mouseLocation];
@@ -2071,10 +2062,8 @@ int DisplayServerOSX::get_screen_count() const {
 // to convert between OS X native screen coordinates and the ones expected by Godot
 // to convert between OS X native screen coordinates and the ones expected by Godot
 
 
 static bool displays_arrangement_dirty = true;
 static bool displays_arrangement_dirty = true;
-static bool displays_scale_dirty = true;
 static void displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info) {
 static void displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info) {
 	displays_arrangement_dirty = true;
 	displays_arrangement_dirty = true;
-	displays_scale_dirty = true;
 }
 }
 
 
 Point2i DisplayServerOSX::_get_screens_origin() const {
 Point2i DisplayServerOSX::_get_screens_origin() const {
@@ -2185,15 +2174,8 @@ float DisplayServerOSX::screen_get_scale(int p_screen) const {
 float DisplayServerOSX::screen_get_max_scale() const {
 float DisplayServerOSX::screen_get_max_scale() const {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 
 
-	static float scale = 1.f;
-	if (displays_scale_dirty) {
-		int screen_count = get_screen_count();
-		for (int i = 0; i < screen_count; i++) {
-			scale = fmax(scale, screen_get_scale(i));
-		}
-		displays_scale_dirty = false;
-	}
-	return scale;
+	// Note: Do not update max display scale on screen configuration change, existing editor windows can't be rescaled on the fly.
+	return display_max_scale;
 }
 }
 
 
 Rect2i DisplayServerOSX::screen_get_usable_rect(int p_screen) const {
 Rect2i DisplayServerOSX::screen_get_usable_rect(int p_screen) const {
@@ -2380,8 +2362,24 @@ int DisplayServerOSX::window_get_current_screen(WindowID p_window) const {
 
 
 void DisplayServerOSX::window_set_current_screen(int p_screen, WindowID p_window) {
 void DisplayServerOSX::window_set_current_screen(int p_screen, WindowID p_window) {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
+
+	ERR_FAIL_COND(!windows.has(p_window));
+	WindowData &wd = windows[p_window];
+
+	bool was_fullscreen = false;
+	if (wd.fullscreen) {
+		// Temporary exit fullscreen mode to move window.
+		[wd.window_object toggleFullScreen:nil];
+		was_fullscreen = true;
+	}
+
 	Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
 	Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
 	window_set_position(wpos + screen_get_position(p_screen), p_window);
 	window_set_position(wpos + screen_get_position(p_screen), p_window);
+
+	if (was_fullscreen) {
+		// Re-enter fullscreen mode.
+		[wd.window_object toggleFullScreen:nil];
+	}
 }
 }
 
 
 void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent) {
 void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent) {
@@ -2404,7 +2402,7 @@ void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent
 		wd_window.transient_parent = INVALID_WINDOW_ID;
 		wd_window.transient_parent = INVALID_WINDOW_ID;
 		wd_parent.transient_children.erase(p_window);
 		wd_parent.transient_children.erase(p_window);
 
 
-		[wd_parent.window_object removeChildWindow:wd_window.window_object];
+		[wd_window.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
 	} else {
 	} else {
 		ERR_FAIL_COND(!windows.has(p_parent));
 		ERR_FAIL_COND(!windows.has(p_parent));
 		ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
 		ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
@@ -2413,7 +2411,7 @@ void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent
 		wd_window.transient_parent = p_parent;
 		wd_window.transient_parent = p_parent;
 		wd_parent.transient_children.insert(p_window);
 		wd_parent.transient_children.insert(p_window);
 
 
-		[wd_parent.window_object addChildWindow:wd_window.window_object ordered:NSWindowAbove];
+		[wd_window.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
 	}
 	}
 }
 }
 
 
@@ -2423,7 +2421,9 @@ Point2i DisplayServerOSX::window_get_position(WindowID p_window) const {
 	ERR_FAIL_COND_V(!windows.has(p_window), Point2i());
 	ERR_FAIL_COND_V(!windows.has(p_window), Point2i());
 	const WindowData &wd = windows[p_window];
 	const WindowData &wd = windows[p_window];
 
 
-	NSRect nsrect = [wd.window_object frame];
+	// Use content rect position (without titlebar / window border).
+	const NSRect contentRect = [wd.window_view frame];
+	const NSRect nsrect = [wd.window_object convertRectToScreen:contentRect];
 	Point2i pos;
 	Point2i pos;
 
 
 	// Return the position of the top-left corner, for OS X the y starts at the bottom
 	// Return the position of the top-left corner, for OS X the y starts at the bottom
@@ -2451,7 +2451,16 @@ void DisplayServerOSX::window_set_position(const Point2i &p_position, WindowID p
 	position += _get_screens_origin();
 	position += _get_screens_origin();
 	position /= screen_get_max_scale();
 	position /= screen_get_max_scale();
 
 
-	[wd.window_object setFrameTopLeftPoint:NSMakePoint(position.x, position.y)];
+	// Remove titlebar / window border size.
+	const NSRect contentRect = [wd.window_view frame];
+	const NSRect windowRect = [wd.window_object frame];
+	const NSRect nsrect = [wd.window_object convertRectToScreen:contentRect];
+	Point2i offset;
+	offset.x = (nsrect.origin.x - windowRect.origin.x);
+	offset.y = (nsrect.origin.y + nsrect.size.height);
+	offset.y -= (windowRect.origin.y + windowRect.size.height);
+
+	[wd.window_object setFrameTopLeftPoint:NSMakePoint(position.x - offset.x, position.y - offset.y)];
 
 
 	_update_window(wd);
 	_update_window(wd);
 	_get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]);
 	_get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]);
@@ -3699,7 +3708,11 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
 
 
 	keyboard_layout_dirty = true;
 	keyboard_layout_dirty = true;
 	displays_arrangement_dirty = true;
 	displays_arrangement_dirty = true;
-	displays_scale_dirty = true;
+
+	int screen_count = get_screen_count();
+	for (int i = 0; i < screen_count; i++) {
+		display_max_scale = fmax(display_max_scale, screen_get_scale(i));
+	}
 
 
 	// Register to be notified on keyboard layout changes
 	// Register to be notified on keyboard layout changes
 	CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(),
 	CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(),

+ 14 - 2
platform/windows/display_server_windows.cpp

@@ -674,8 +674,20 @@ void DisplayServerWindows::window_set_current_screen(int p_screen, WindowID p_wi
 	ERR_FAIL_COND(!windows.has(p_window));
 	ERR_FAIL_COND(!windows.has(p_window));
 	ERR_FAIL_INDEX(p_screen, get_screen_count());
 	ERR_FAIL_INDEX(p_screen, get_screen_count());
 
 
-	Vector2 ofs = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
-	window_set_position(ofs + screen_get_position(p_screen), p_window);
+	const WindowData &wd = windows[p_window];
+	if (wd.fullscreen) {
+		int cs = window_get_current_screen(p_window);
+		if (cs == p_screen) {
+			return;
+		}
+		Point2 pos = screen_get_position(p_screen);
+		Size2 size = screen_get_size(p_screen);
+
+		MoveWindow(wd.hWnd, pos.x, pos.y, size.width, size.height, TRUE);
+	} else {
+		Vector2 ofs = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
+		window_set_position(ofs + screen_get_position(p_screen), p_window);
+	}
 }
 }
 
 
 Point2i DisplayServerWindows::window_get_position(WindowID p_window) const {
 Point2i DisplayServerWindows::window_get_position(WindowID p_window) const {

+ 5 - 0
scene/main/window.cpp

@@ -281,6 +281,11 @@ void Window::_clear_window() {
 	DisplayServer::get_singleton()->delete_sub_window(window_id);
 	DisplayServer::get_singleton()->delete_sub_window(window_id);
 	window_id = DisplayServer::INVALID_WINDOW_ID;
 	window_id = DisplayServer::INVALID_WINDOW_ID;
 
 
+	// If closing window was focused and has a parent, return focus.
+	if (focused && transient_parent) {
+		transient_parent->grab_focus();
+	}
+
 	_update_viewport_size();
 	_update_viewport_size();
 	RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
 	RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
 }
 }

+ 0 - 5
servers/display_server.cpp

@@ -139,10 +139,6 @@ void DisplayServer::mouse_warp_to_position(const Point2i &p_to) {
 	WARN_PRINT("Mouse warping is not supported by this display server.");
 	WARN_PRINT("Mouse warping is not supported by this display server.");
 }
 }
 
 
-Point2i DisplayServer::mouse_get_absolute_position() const {
-	ERR_FAIL_V_MSG(Point2i(), "Mouse is not supported by this display server.");
-}
-
 Point2i DisplayServer::mouse_get_position() const {
 Point2i DisplayServer::mouse_get_position() const {
 	ERR_FAIL_V_MSG(Point2i(), "Mouse is not supported by this display server.");
 	ERR_FAIL_V_MSG(Point2i(), "Mouse is not supported by this display server.");
 }
 }
@@ -359,7 +355,6 @@ void DisplayServer::_bind_methods() {
 
 
 	ClassDB::bind_method(D_METHOD("mouse_warp_to_position", "position"), &DisplayServer::mouse_warp_to_position);
 	ClassDB::bind_method(D_METHOD("mouse_warp_to_position", "position"), &DisplayServer::mouse_warp_to_position);
 	ClassDB::bind_method(D_METHOD("mouse_get_position"), &DisplayServer::mouse_get_position);
 	ClassDB::bind_method(D_METHOD("mouse_get_position"), &DisplayServer::mouse_get_position);
-	ClassDB::bind_method(D_METHOD("mouse_get_absolute_position"), &DisplayServer::mouse_get_absolute_position);
 	ClassDB::bind_method(D_METHOD("mouse_get_button_state"), &DisplayServer::mouse_get_button_state);
 	ClassDB::bind_method(D_METHOD("mouse_get_button_state"), &DisplayServer::mouse_get_button_state);
 
 
 	ClassDB::bind_method(D_METHOD("clipboard_set", "clipboard"), &DisplayServer::clipboard_set);
 	ClassDB::bind_method(D_METHOD("clipboard_set", "clipboard"), &DisplayServer::clipboard_set);

+ 0 - 1
servers/display_server.h

@@ -156,7 +156,6 @@ public:
 
 
 	virtual void mouse_warp_to_position(const Point2i &p_to);
 	virtual void mouse_warp_to_position(const Point2i &p_to);
 	virtual Point2i mouse_get_position() const;
 	virtual Point2i mouse_get_position() const;
-	virtual Point2i mouse_get_absolute_position() const;
 	virtual MouseButton mouse_get_button_state() const;
 	virtual MouseButton mouse_get_button_state() const;
 
 
 	virtual void clipboard_set(const String &p_text);
 	virtual void clipboard_set(const String &p_text);