Skip to content

Commit

Permalink
Fix window_get_current_screen for X11 display server
Browse files Browse the repository at this point in the history
This method used to check which screen contains the top-left corner of
the window (and default to the first screen in case none is found),
which is not accurate in some cases.

Now the area of overlap with each screen is calculated, so we can get
the best candidate based on the window's position.

This makes window_get_current_screen consistent with Windows platform,
and fixes an issue where popups appear on the main screen when the main
window is slightly moved outside of the desktop on the top or left.
  • Loading branch information
pouleyKetchoupp committed Oct 28, 2021
1 parent e2deec6 commit b34480b
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 26 deletions.
75 changes: 49 additions & 26 deletions platform/linuxbsd/display_server_x11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions platform/linuxbsd/display_server_x11.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit b34480b

Please sign in to comment.