Merge pull request #40922 from opl-/fix/x11-size-hints

Fix losing X11 window normal size hint properties
This commit is contained in:
Rémi Verschelde 2020-07-31 21:42:50 +02:00 committed by GitHub
commit be435608b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 154 deletions

View File

@ -881,6 +881,46 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent
} }
} }
// Helper method. Assumes that the window id has already been checked and exists.
void DisplayServerX11::_update_size_hints(WindowID p_window) {
WindowData &wd = windows[p_window];
WindowMode window_mode = window_get_mode(p_window);
XSizeHints *xsh = XAllocSizeHints();
// Always set the position and size hints - they should be synchronized with the actual values after the window is mapped anyway
xsh->flags |= PPosition | PSize;
xsh->x = wd.position.x;
xsh->y = wd.position.y;
xsh->width = wd.size.width;
xsh->height = wd.size.height;
if (window_mode == WINDOW_MODE_FULLSCREEN) {
// Do not set any other hints to prevent the window manager from ignoring the fullscreen flags
} else if (window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) {
// If resizing is disabled, use the forced size
xsh->flags |= PMinSize | PMaxSize;
xsh->min_width = wd.size.x;
xsh->max_width = wd.size.x;
xsh->min_height = wd.size.y;
xsh->max_height = wd.size.y;
} else {
// Otherwise, just respect min_size and max_size
if (wd.min_size != Size2i()) {
xsh->flags |= PMinSize;
xsh->min_width = wd.min_size.x;
xsh->min_height = wd.min_size.y;
}
if (wd.max_size != Size2i()) {
xsh->flags |= PMaxSize;
xsh->max_width = wd.max_size.x;
xsh->max_height = wd.max_size.y;
}
}
XSetWMNormalHints(x11_display, wd.x11_window, xsh);
XFree(xsh);
}
Point2i DisplayServerX11::window_get_position(WindowID p_window) const { Point2i DisplayServerX11::window_get_position(WindowID p_window) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
@ -934,25 +974,8 @@ void DisplayServerX11::window_set_max_size(const Size2i p_size, WindowID p_windo
} }
wd.max_size = p_size; wd.max_size = p_size;
if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { _update_size_hints(p_window);
XSizeHints *xsh; XFlush(x11_display);
xsh = XAllocSizeHints();
xsh->flags = 0L;
if (wd.min_size != Size2i()) {
xsh->flags |= PMinSize;
xsh->min_width = wd.min_size.x;
xsh->min_height = wd.min_size.y;
}
if (wd.max_size != Size2i()) {
xsh->flags |= PMaxSize;
xsh->max_width = wd.max_size.x;
xsh->max_height = wd.max_size.y;
}
XSetWMNormalHints(x11_display, wd.x11_window, xsh);
XFree(xsh);
XFlush(x11_display);
}
} }
Size2i DisplayServerX11::window_get_max_size(WindowID p_window) const { Size2i DisplayServerX11::window_get_max_size(WindowID p_window) const {
@ -976,25 +999,8 @@ void DisplayServerX11::window_set_min_size(const Size2i p_size, WindowID p_windo
} }
wd.min_size = p_size; wd.min_size = p_size;
if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { _update_size_hints(p_window);
XSizeHints *xsh; XFlush(x11_display);
xsh = XAllocSizeHints();
xsh->flags = 0L;
if (wd.min_size != Size2i()) {
xsh->flags |= PMinSize;
xsh->min_width = wd.min_size.x;
xsh->min_height = wd.min_size.y;
}
if (wd.max_size != Size2i()) {
xsh->flags |= PMaxSize;
xsh->max_width = wd.max_size.x;
xsh->max_height = wd.max_size.y;
}
XSetWMNormalHints(x11_display, wd.x11_window, xsh);
XFree(xsh);
XFlush(x11_display);
}
} }
Size2i DisplayServerX11::window_get_min_size(WindowID p_window) const { Size2i DisplayServerX11::window_get_min_size(WindowID p_window) const {
@ -1027,37 +1033,15 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
int old_w = xwa.width; int old_w = xwa.width;
int old_h = xwa.height; int old_h = xwa.height;
// If window resizable is disabled we need to update the attributes first // Update our videomode width and height
XSizeHints *xsh; wd.size = size;
xsh = XAllocSizeHints();
if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { // Update the size hints first to make sure the window size can be set
xsh->flags = PMinSize | PMaxSize; _update_size_hints(p_window);
xsh->min_width = size.x;
xsh->max_width = size.x;
xsh->min_height = size.y;
xsh->max_height = size.y;
} else {
xsh->flags = 0L;
if (wd.min_size != Size2i()) {
xsh->flags |= PMinSize;
xsh->min_width = wd.min_size.x;
xsh->min_height = wd.min_size.y;
}
if (wd.max_size != Size2i()) {
xsh->flags |= PMaxSize;
xsh->max_width = wd.max_size.x;
xsh->max_height = wd.max_size.y;
}
}
XSetWMNormalHints(x11_display, wd.x11_window, xsh);
XFree(xsh);
// Resize the window // Resize the window
XResizeWindow(x11_display, wd.x11_window, size.x, size.y); XResizeWindow(x11_display, wd.x11_window, size.x, size.y);
// Update our videomode width and height
wd.size = size;
for (int timeout = 0; timeout < 50; ++timeout) { for (int timeout = 0; timeout < 50; ++timeout) {
XSync(x11_display, False); XSync(x11_display, False);
XGetWindowAttributes(x11_display, wd.x11_window, &xwa); XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
@ -1213,14 +1197,9 @@ void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) {
XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
} }
if (p_enabled && window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { if (p_enabled) {
// Set the window as resizable to prevent window managers to ignore the fullscreen state flag. // Set the window as resizable to prevent window managers to ignore the fullscreen state flag.
XSizeHints *xsh; _update_size_hints(p_window);
xsh = XAllocSizeHints();
xsh->flags = 0L;
XSetWMNormalHints(x11_display, wd.x11_window, xsh);
XFree(xsh);
} }
// Using EWMH -- Extended Window Manager Hints // Using EWMH -- Extended Window Manager Hints
@ -1248,30 +1227,7 @@ void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) {
if (!p_enabled) { if (!p_enabled) {
// Reset the non-resizable flags if we un-set these before. // Reset the non-resizable flags if we un-set these before.
Size2i size = window_get_size(p_window); _update_size_hints(p_window);
XSizeHints *xsh;
xsh = XAllocSizeHints();
if (window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) {
xsh->flags = PMinSize | PMaxSize;
xsh->min_width = size.x;
xsh->max_width = size.x;
xsh->min_height = size.y;
xsh->max_height = size.y;
} else {
xsh->flags = 0L;
if (wd.min_size != Size2i()) {
xsh->flags |= PMinSize;
xsh->min_width = wd.min_size.x;
xsh->min_height = wd.min_size.y;
}
if (wd.max_size != Size2i()) {
xsh->flags |= PMaxSize;
xsh->max_width = wd.max_size.x;
xsh->max_height = wd.max_size.y;
}
}
XSetWMNormalHints(x11_display, wd.x11_window, xsh);
XFree(xsh);
// put back or remove decorations according to the last set borderless state // put back or remove decorations according to the last set borderless state
Hints hints; Hints hints;
@ -1329,13 +1285,13 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
} break; } break;
case WINDOW_MODE_FULLSCREEN: { case WINDOW_MODE_FULLSCREEN: {
//Remove full-screen //Remove full-screen
wd.fullscreen = false;
_set_wm_fullscreen(p_window, false); _set_wm_fullscreen(p_window, false);
//un-maximize required for always on top //un-maximize required for always on top
bool on_top = window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window); bool on_top = window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window);
wd.fullscreen = false;
window_set_position(wd.last_position_before_fs, p_window); window_set_position(wd.last_position_before_fs, p_window);
if (on_top) { if (on_top) {
@ -1381,15 +1337,16 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
} break; } break;
case WINDOW_MODE_FULLSCREEN: { case WINDOW_MODE_FULLSCREEN: {
wd.last_position_before_fs = wd.position; wd.last_position_before_fs = wd.position;
if (window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window)) { if (window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window)) {
_set_wm_maximized(p_window, true); _set_wm_maximized(p_window, true);
} }
_set_wm_fullscreen(p_window, true);
wd.fullscreen = true; wd.fullscreen = true;
_set_wm_fullscreen(p_window, true);
} break; } break;
case WINDOW_MODE_MAXIMIZED: { case WINDOW_MODE_MAXIMIZED: {
_set_wm_maximized(p_window, true); _set_wm_maximized(p_window, true);
} break; } break;
} }
} }
@ -1456,37 +1413,11 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo
switch (p_flag) { switch (p_flag) {
case WINDOW_FLAG_RESIZE_DISABLED: { case WINDOW_FLAG_RESIZE_DISABLED: {
XSizeHints *xsh;
xsh = XAllocSizeHints();
if (p_enabled) {
Size2i size = window_get_size(p_window);
xsh->flags = PMinSize | PMaxSize;
xsh->min_width = size.x;
xsh->max_width = size.x;
xsh->min_height = size.y;
xsh->max_height = size.y;
} else {
xsh->flags = 0L;
if (wd.min_size != Size2i()) {
xsh->flags |= PMinSize;
xsh->min_width = wd.min_size.x;
xsh->min_height = wd.min_size.y;
}
if (wd.max_size != Size2i()) {
xsh->flags |= PMaxSize;
xsh->max_width = wd.max_size.x;
xsh->max_height = wd.max_size.y;
}
}
XSetWMNormalHints(x11_display, wd.x11_window, xsh);
XFree(xsh);
wd.resize_disabled = p_enabled; wd.resize_disabled = p_enabled;
XFlush(x11_display); _update_size_hints(p_window);
XFlush(x11_display);
} break; } break;
case WINDOW_FLAG_BORDERLESS: { case WINDOW_FLAG_BORDERLESS: {
Hints hints; Hints hints;
@ -3305,20 +3236,6 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
windows[id] = wd; windows[id] = wd;
{ {
if (p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT) {
XSizeHints *xsh;
xsh = XAllocSizeHints();
xsh->flags = PMinSize | PMaxSize;
xsh->min_width = p_rect.size.width;
xsh->max_width = p_rect.size.width;
xsh->min_height = p_rect.size.height;
xsh->max_height = p_rect.size.height;
XSetWMNormalHints(x11_display, wd.x11_window, xsh);
XFree(xsh);
}
bool make_utility = false; bool make_utility = false;
if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) { if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) {
@ -3368,18 +3285,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
} }
} }
if (id != MAIN_WINDOW_ID) { _update_size_hints(id);
XSizeHints my_hints = XSizeHints();
my_hints.flags = PPosition | PSize; /* I want to specify position and size */
my_hints.x = p_rect.position.x; /* The origin and size coords I want */
my_hints.y = p_rect.position.y;
my_hints.width = p_rect.size.width;
my_hints.height = p_rect.size.height;
XSetNormalHints(x11_display, wd.x11_window, &my_hints);
XMoveWindow(x11_display, wd.x11_window, p_rect.position.x, p_rect.position.y);
}
#if defined(VULKAN_ENABLED) #if defined(VULKAN_ENABLED)
if (context_vulkan) { if (context_vulkan) {

View File

@ -235,6 +235,7 @@ class DisplayServerX11 : public DisplayServer {
void _update_real_mouse_position(const WindowData &wd); void _update_real_mouse_position(const WindowData &wd);
bool _window_maximize_check(WindowID p_window, const char *p_atom_name) const; bool _window_maximize_check(WindowID p_window, const char *p_atom_name) const;
void _update_size_hints(WindowID p_window);
void _set_wm_fullscreen(WindowID p_window, bool p_enabled); void _set_wm_fullscreen(WindowID p_window, bool p_enabled);
void _set_wm_maximized(WindowID p_window, bool p_enabled); void _set_wm_maximized(WindowID p_window, bool p_enabled);