From 197cb4e7718034aba35832a547477dfc858a7280 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Wed, 25 Mar 2020 11:16:19 -0300 Subject: [PATCH] Fixes to X11, still pretty broken --- platform/linuxbsd/display_server_x11.cpp | 139 ++++++++++++++++++----- platform/linuxbsd/display_server_x11.h | 1 + scene/gui/menu_button.cpp | 7 ++ scene/main/window.cpp | 26 ++--- scene/main/window.h | 8 +- servers/display_server.cpp | 4 +- 6 files changed, 138 insertions(+), 47 deletions(-) diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index d847270e64f..f284a5f92d4 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -862,11 +862,10 @@ Point2i DisplayServerX11::window_get_position(WindowID p_window) const { ERR_FAIL_COND_V(!windows.has(p_window), Point2i()); 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); - return Point2i(x, y); + + return wd.position; } + void DisplayServerX11::window_set_position(const Point2i &p_position, WindowID p_window) { _THREAD_SAFE_METHOD_ @@ -991,9 +990,14 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); + + Size2i size = p_size; + size.x = MAX(1, size.x); + size.y = MAX(1, size.y); + WindowData &wd = windows[p_window]; - if (wd.size.width == p_size.width && wd.size.height == p_size.height) + if (wd.size.width == size.width && wd.size.height == size.height) return; XWindowAttributes xwa; @@ -1007,10 +1011,10 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) { xsh = XAllocSizeHints(); if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { xsh->flags = PMinSize | PMaxSize; - xsh->min_width = p_size.x; - xsh->max_width = p_size.x; - xsh->min_height = p_size.y; - xsh->max_height = p_size.y; + 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()) { @@ -1028,10 +1032,10 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) { XFree(xsh); // Resize the window - XResizeWindow(x11_display, wd.x11_window, p_size.x, p_size.y); + XResizeWindow(x11_display, wd.x11_window, size.x, size.y); // Update our videomode width and height - wd.size = p_size; + wd.size = size; for (int timeout = 0; timeout < 50; ++timeout) { XSync(x11_display, False); @@ -1348,7 +1352,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) { XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); } break; case WINDOW_MODE_FULLSCREEN: { - wd.last_position_before_fs = window_get_position(p_window); + wd.last_position_before_fs = wd.position; if (window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window)) { _set_wm_maximized(p_window, true); } @@ -2229,22 +2233,35 @@ void DisplayServerX11::_window_changed(XEvent *event) { } } + Rect2i new_rect; + WindowData &wd = windows[window_id]; - if (wd.x11_window != event->xany.window) { // Check if the correct window + if (wd.x11_window != event->xany.window) { // Check if the correct window, in case it was not main window or anything else return; } + { + //the position in xconfigure is not useful here, obtain it manually + int x, y; + Window child; + XTranslateCoordinates(x11_display, wd.x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child); + new_rect.position.x = x; + new_rect.position.y = y; + + new_rect.size.width = event->xconfigure.width; + new_rect.size.height = event->xconfigure.height; + } + + if (new_rect == Rect2i(wd.position, wd.size)) { + return; + } if (wd.xic) { // Not portable. window_set_ime_position(Point2(0, 1)); } - if ((event->xconfigure.width == wd.size.width) && - (event->xconfigure.height == wd.size.height)) - return; - - wd.size.width = event->xconfigure.width; - wd.size.height = event->xconfigure.height; + wd.position = new_rect.position; + wd.size = new_rect.size; #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { @@ -2252,8 +2269,12 @@ void DisplayServerX11::_window_changed(XEvent *event) { } #endif + print_line("DisplayServer::_window_changed: " + itos(window_id) + " rect: " + new_rect); if (!wd.rect_changed_callback.is_null()) { - Variant rect = Rect2i(wd.im_position, wd.size); + Rect2i r = new_rect; + + Variant rect = r; + Variant *rectp = ▭ Variant ret; Callable::CallError ce; @@ -3122,7 +3143,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u WindowID id; { WindowData wd; - wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), p_rect.position.x, p_rect.position.y, p_rect.size.width, p_rect.size.height, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes); + wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes); XMapWindow(x11_display, wd.x11_window); @@ -3206,14 +3227,74 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u windows[id] = wd; - if (id != MAIN_WINDOW_ID) { - //this is a sub window, don't let the window manager put it wherever it wants - for (int i = 0; i < WINDOW_FLAG_MAX; i++) { - if (p_flags & (1 << i)) { - window_set_flag(WindowFlags(i), true, id); - } + { + + 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; + + if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) { + Hints hints; + Atom property; + hints.flags = 2; + hints.decorations = 0; + property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); + XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + + make_utility = true; + } + if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) { + make_utility = true; + } + + if (make_utility) { + //this one seems to disable the fade animations for regular windows + //but has the drawback that will not get focus by default, so + //we need fo force it, unless no focus requested + + Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_UTILITY", False); + Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False); + + XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1); + + if (!(p_flags & WINDOW_FLAG_NO_FOCUS_BIT)) { + //but as utility appears unfocused, it needs to be forcefuly focused, unless no focus requested + XEvent xev; + Atom net_active_window = XInternAtom(x11_display, "_NET_ACTIVE_WINDOW", False); + + memset(&xev, 0, sizeof(xev)); + xev.type = ClientMessage; + xev.xclient.window = wd.x11_window; + xev.xclient.message_type = net_active_window; + xev.xclient.format = 32; + xev.xclient.data.l[0] = 1; + xev.xclient.data.l[1] = CurrentTime; + + XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + } + } else { + Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_NORMAL", False); + Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False); + + XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1); + } + } + + if (id != MAIN_WINDOW_ID) { + XSizeHints my_hints = XSizeHints(); my_hints.flags = PPosition | PSize; /* I want to specify position and size */ @@ -3253,10 +3334,12 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u XSync(x11_display, False); XGetWindowAttributes(x11_display, wd.x11_window, &xwa); + wd.position.x = xwa.x; + wd.position.y = xwa.y; wd.size.width = xwa.width; wd.size.height = xwa.height; - print_line("created at rect: " + p_rect + " but at rect " + Rect2i(xwa.x, xwa.y, xwa.width, xwa.height)); + print_line("DisplayServer::_create_window " + itos(id) + " want rect: " + p_rect + " got rect " + Rect2i(xwa.x, xwa.y, xwa.width, xwa.height)); } //set cursor diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index 10067671e72..46d33fbe7da 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -118,6 +118,7 @@ class DisplayServerX11 : public DisplayServer { Size2i min_size; Size2i max_size; + Point2i position; Size2i size; Point2i im_position; bool im_active = false; diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index ba1f651b5cb..a7d1f64e93b 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -53,10 +53,17 @@ void MenuButton::_unhandled_key_input(Ref p_event) { void MenuButton::pressed() { + { + Window *w = Object::cast_to(get_viewport()); + if (w && !w->is_embedding_subwindows()) { + print_line("windowpos: " + w->get_position()); + } + } Size2 size = get_size(); Point2 gp = get_screen_position(); + print_line("screenpos: " + gp); gp.y += get_size().y; popup->set_position(gp); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 6c2e2f1d312..5054e18a7ae 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -932,7 +932,7 @@ Window *Window::get_parent_visible_window() const { return window; } -void Window::popup_on_parent(const Rect2 &p_parent_rect) { +void Window::popup_on_parent(const Rect2i &p_parent_rect) { ERR_FAIL_COND(!is_inside_tree()); ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window."); @@ -943,14 +943,14 @@ void Window::popup_on_parent(const Rect2 &p_parent_rect) { if (!window) { popup(p_parent_rect); } else { - popup(Rect2(window->get_position() + p_parent_rect.position, p_parent_rect.size)); + popup(Rect2i(window->get_position() + p_parent_rect.position, p_parent_rect.size)); } } else { popup(p_parent_rect); } } -void Window::popup_centered_clamped(const Size2 &p_size, float p_fallback_ratio) { +void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio) { ERR_FAIL_COND(!is_inside_tree()); ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window."); @@ -966,16 +966,16 @@ void Window::popup_centered_clamped(const Size2 &p_size, float p_fallback_ratio) parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen); } - Vector2 size_ratio = parent_rect.size * p_fallback_ratio; + Vector2i size_ratio = parent_rect.size * p_fallback_ratio; - Rect2 popup_rect; - popup_rect.size = Vector2(MIN(size_ratio.x, p_size.x), MIN(size_ratio.y, p_size.y)); + Rect2i popup_rect; + popup_rect.size = Vector2i(MIN(size_ratio.x, p_size.x), MIN(size_ratio.y, p_size.y)); popup_rect.position = (parent_rect.size - popup_rect.size) / 2; popup(popup_rect); } -void Window::popup_centered(const Size2 &p_minsize) { +void Window::popup_centered(const Size2i &p_minsize) { ERR_FAIL_COND(!is_inside_tree()); ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window."); @@ -990,8 +990,8 @@ void Window::popup_centered(const Size2 &p_minsize) { parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen); } - Rect2 popup_rect; - if (p_minsize == Size2()) { + Rect2i popup_rect; + if (p_minsize == Size2i()) { popup_rect.size = _get_contents_minimum_size(); } else { popup_rect.size = p_minsize; @@ -1006,7 +1006,7 @@ void Window::popup_centered_ratio(float p_ratio) { ERR_FAIL_COND(!is_inside_tree()); ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window."); - Rect2 parent_rect; + Rect2i parent_rect; if (is_embedded()) { parent_rect = get_parent_viewport()->get_visible_rect(); @@ -1017,18 +1017,18 @@ void Window::popup_centered_ratio(float p_ratio) { parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen); } - Rect2 popup_rect; + Rect2i popup_rect; popup_rect.size = parent_rect.size * p_ratio; popup_rect.position = (parent_rect.size - popup_rect.size) / 2; popup(popup_rect); } -void Window::popup(const Rect2 &p_screen_rect) { +void Window::popup(const Rect2i &p_screen_rect) { emit_signal("about_to_popup"); - if (p_screen_rect != Rect2()) { + if (p_screen_rect != Rect2i()) { set_position(p_screen_rect.position); set_size(p_screen_rect.size); } diff --git a/scene/main/window.h b/scene/main/window.h index df67cabeaad..be07762f20a 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -221,11 +221,11 @@ public: Window *get_parent_visible_window() const; Viewport *get_parent_viewport() const; - void popup(const Rect2 &p_rect = Rect2()); - void popup_on_parent(const Rect2 &p_parent_rect); + void popup(const Rect2i &p_rect = Rect2i()); + void popup_on_parent(const Rect2i &p_parent_rect); void popup_centered_ratio(float p_ratio = 0.8); - void popup_centered(const Size2 &p_minsize = Size2()); - void popup_centered_clamped(const Size2 &p_size = Size2(), float p_fallback_ratio = 0.75); + void popup_centered(const Size2i &p_minsize = Size2i()); + void popup_centered_clamped(const Size2i &p_size = Size2i(), float p_fallback_ratio = 0.75); void set_theme(const Ref &p_theme); Ref get_theme() const; diff --git a/servers/display_server.cpp b/servers/display_server.cpp index f2103a2856d..29d46b90fd0 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -284,8 +284,8 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("window_set_input_text_callback", "callback", "window_id"), &DisplayServer::window_set_input_text_callback, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_set_drop_files_callback", "callback", "window_id"), &DisplayServer::window_set_drop_files_callback, DEFVAL(MAIN_WINDOW_ID)); - ClassDB::bind_method(D_METHOD("window_attach_instance_id", "instance_id", "window_id"), &DisplayServer::window_get_max_size, DEFVAL(MAIN_WINDOW_ID)); - ClassDB::bind_method(D_METHOD("window_get_attached_instance_id", "window_id"), &DisplayServer::window_get_max_size, DEFVAL(MAIN_WINDOW_ID)); + ClassDB::bind_method(D_METHOD("window_attach_instance_id", "instance_id", "window_id"), &DisplayServer::window_attach_instance_id, DEFVAL(MAIN_WINDOW_ID)); + ClassDB::bind_method(D_METHOD("window_get_attached_instance_id", "window_id"), &DisplayServer::window_get_attached_instance_id, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_get_max_size", "window_id"), &DisplayServer::window_get_max_size, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_set_max_size", "max_size", "window_id"), &DisplayServer::window_set_max_size, DEFVAL(MAIN_WINDOW_ID));