Bladeren bron

Merge pull request #42117 from nekomatata/x11-get-window-screen

Fix window_get_current_screen for X11 display server
Rémi Verschelde 3 jaren geleden
bovenliggende
commit
9fb9b99cab
2 gewijzigde bestanden met toevoegingen van 51 en 26 verwijderingen
  1. 49 26
      platform/linuxbsd/display_server_x11.cpp
  2. 2 0
      platform/linuxbsd/display_server_x11.h

+ 49 - 26
platform/linuxbsd/display_server_x11.cpp

@@ -683,35 +683,49 @@ int DisplayServerX11::get_screen_count() const {
 	return count;
 }
 
-Point2i DisplayServerX11::screen_get_position(int p_screen) const {
-	_THREAD_SAFE_METHOD_
+Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const {
+	Rect2i rect(0, 0, 0, 0);
 
 	if (p_screen == SCREEN_OF_MAIN_WINDOW) {
 		p_screen = window_get_current_screen();
 	}
 
-	// Using Xinerama Extension
-	int event_base, error_base;
-	const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
-	if (!ext_okay) {
-		return Point2i(0, 0);
-	}
+	ERR_FAIL_COND_V(p_screen < 0, rect);
 
-	int count;
-	XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
+	// Using Xinerama Extension.
+	int event_base, error_base;
+	if (XineramaQueryExtension(x11_display, &event_base, &error_base)) {
+		int count;
+		XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
+
+		// Check if screen is valid.
+		if (p_screen < count) {
+			rect.position.x = xsi[p_screen].x_org;
+			rect.position.y = xsi[p_screen].y_org;
+			rect.size.width = xsi[p_screen].width;
+			rect.size.height = xsi[p_screen].height;
+		} else {
+			ERR_PRINT("Invalid screen index: " + itos(p_screen) + "(count: " + itos(count) + ").");
+		}
 
-	// Check if screen is valid
-	ERR_FAIL_INDEX_V(p_screen, count, Point2i(0, 0));
+		if (xsi) {
+			XFree(xsi);
+		}
+	}
 
-	Point2i position = Point2i(xsi[p_screen].x_org, xsi[p_screen].y_org);
+	return rect;
+}
 
-	XFree(xsi);
+Point2i DisplayServerX11::screen_get_position(int p_screen) const {
+	_THREAD_SAFE_METHOD_
 
-	return position;
+	return _screen_get_rect(p_screen).position;
 }
 
 Size2i DisplayServerX11::screen_get_size(int p_screen) const {
-	return screen_get_usable_rect(p_screen).size;
+	_THREAD_SAFE_METHOD_
+
+	return _screen_get_rect(p_screen).size;
 }
 
 Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
@@ -1011,22 +1025,31 @@ void DisplayServerX11::window_set_drop_files_callback(const Callable &p_callable
 int DisplayServerX11::window_get_current_screen(WindowID p_window) const {
 	_THREAD_SAFE_METHOD_
 
-	ERR_FAIL_COND_V(!windows.has(p_window), -1);
+	int count = get_screen_count();
+	if (count < 2) {
+		// Early exit with single monitor.
+		return 0;
+	}
+
+	ERR_FAIL_COND_V(!windows.has(p_window), 0);
 	const WindowData &wd = windows[p_window];
 
-	int x, y;
-	Window child;
-	XTranslateCoordinates(x11_display, wd.x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
+	const Rect2i window_rect(wd.position, wd.size);
 
-	int count = get_screen_count();
+	// Find which monitor has the largest overlap with the given window.
+	int screen_index = 0;
+	int max_area = 0;
 	for (int i = 0; i < count; i++) {
-		Point2i pos = screen_get_position(i);
-		Size2i size = screen_get_size(i);
-		if ((x >= pos.x && x < pos.x + size.width) && (y >= pos.y && y < pos.y + size.height)) {
-			return i;
+		Rect2i screen_rect = _screen_get_rect(i);
+		Rect2i intersection = screen_rect.intersection(window_rect);
+		int area = intersection.get_area();
+		if (area > max_area) {
+			max_area = area;
+			screen_index = i;
 		}
 	}
-	return 0;
+
+	return screen_index;
 }
 
 void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window) {

+ 2 - 0
platform/linuxbsd/display_server_x11.h

@@ -197,6 +197,8 @@ class DisplayServerX11 : public DisplayServer {
 
 	bool _refresh_device_info();
 
+	Rect2i _screen_get_rect(int p_screen) const;
+
 	MouseButton _get_mouse_button_state(MouseButton p_x11_button, int p_x11_type);
 	void _get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state);
 	void _flush_mouse_motion();