From 5ae9eee4a37a473ef768a2fe8d95d84202443cbe Mon Sep 17 00:00:00 2001 From: Peter Elliott Date: Thu, 30 Jul 2020 19:52:45 -0600 Subject: [PATCH] LibGUI+WindowServer: Provide default placement to windows This prevents windows from being opened directly on top of eachother, and provides default behavior for when window position is not specified. The new behavior is as follows: - Windows that have been created without a set position are assigned one by WindowServer. - The assigned position is either offset from the last window that is still in an assigned position, or a default position if no such window is available. --- Libraries/LibGUI/Window.cpp | 7 ++++- Libraries/LibGUI/Window.h | 1 + Services/WindowServer/ClientConnection.cpp | 11 ++++++- Services/WindowServer/Window.cpp | 5 ++-- Services/WindowServer/Window.h | 4 +++ Services/WindowServer/WindowManager.cpp | 35 ++++++++++++++++++++++ Services/WindowServer/WindowManager.h | 2 ++ Services/WindowServer/WindowServer.ipc | 1 + 8 files changed, 62 insertions(+), 4 deletions(-) diff --git a/Libraries/LibGUI/Window.cpp b/Libraries/LibGUI/Window.cpp index f590184ff2..9add84eebf 100644 --- a/Libraries/LibGUI/Window.cpp +++ b/Libraries/LibGUI/Window.cpp @@ -62,7 +62,7 @@ Window::Window(Core::Object* parent) : Core::Object(parent) { all_windows->set(this); - m_rect_when_windowless = { 100, 400, 140, 140 }; + m_rect_when_windowless = { -5000, -5000, 140, 140 }; m_title_when_windowless = "GUI::Window"; } @@ -95,6 +95,7 @@ void Window::show() m_override_cursor = StandardCursor::None; auto response = WindowServerConnection::the().send_sync( m_rect_when_windowless, + !m_moved_by_client, m_has_alpha_channel, m_modal, m_minimizable, @@ -192,6 +193,10 @@ Gfx::IntRect Window::rect() const void Window::set_rect(const Gfx::IntRect& a_rect) { + if (a_rect.location() != m_rect_when_windowless.location()) { + m_moved_by_client = true; + } + m_rect_when_windowless = a_rect; if (!is_visible()) { if (m_main_widget) diff --git a/Libraries/LibGUI/Window.h b/Libraries/LibGUI/Window.h index 64542e6dbb..94de9fa5d8 100644 --- a/Libraries/LibGUI/Window.h +++ b/Libraries/LibGUI/Window.h @@ -262,6 +262,7 @@ private: bool m_visible_for_timer_purposes { true }; bool m_visible { false }; bool m_accessory { false }; + bool m_moved_by_client { false }; }; } diff --git a/Services/WindowServer/ClientConnection.cpp b/Services/WindowServer/ClientConnection.cpp index ee7ffbd76a..154b7e0c3b 100644 --- a/Services/WindowServer/ClientConnection.cpp +++ b/Services/WindowServer/ClientConnection.cpp @@ -407,6 +407,10 @@ OwnPtr ClientConnection::handle(c dbg() << "ClientConnection: Ignoring SetWindowRect request for fullscreen window"; return nullptr; } + + if (message.rect().location() != window.rect().location()) { + window.set_default_positioned(false); + } auto normalized_rect = normalize_window_rect(message.rect(), window.type()); window.set_rect(normalized_rect); window.request_update(normalized_rect); @@ -460,7 +464,12 @@ OwnPtr ClientConnection::handle(co window->set_has_alpha_channel(message.has_alpha_channel()); window->set_title(message.title()); if (!message.fullscreen()) { - auto normalized_rect = normalize_window_rect(message.rect(), window->type()); + auto rect = message.rect(); + if (message.auto_position() && window->type() == WindowType::Normal) { + rect = { WindowManager::the().get_recommended_window_position({ 100, 100 }), message.rect().size() }; + window->set_default_positioned(true); + } + auto normalized_rect = normalize_window_rect(rect, window->type()); window->set_rect(normalized_rect); } if (window->type() == WindowType::Desktop) { diff --git a/Services/WindowServer/Window.cpp b/Services/WindowServer/Window.cpp index c3bd001f50..fdeb542e42 100644 --- a/Services/WindowServer/Window.cpp +++ b/Services/WindowServer/Window.cpp @@ -273,6 +273,7 @@ void Window::set_maximized(bool maximized) } m_frame.did_set_maximized({}, maximized); Core::EventLoop::current().post_event(*this, make(old_rect, m_rect)); + set_default_positioned(false); } void Window::set_resizable(bool resizable) @@ -398,7 +399,7 @@ Window* Window::is_blocked_by_modal_window() if (window && !window->is_destroyed()) { if (window->is_modal()) return window; - + if (auto* blocking_modal_window = window->is_blocked_by_modal_window()) return blocking_modal_window; } @@ -601,7 +602,7 @@ bool Window::is_accessory() const return false; if (parent_window() != nullptr) return true; - + // If accessory window was unparented, convert to a regular window const_cast(this)->set_accessory(false); return false; diff --git a/Services/WindowServer/Window.h b/Services/WindowServer/Window.h index 1a1696b452..5e0d582dd7 100644 --- a/Services/WindowServer/Window.h +++ b/Services/WindowServer/Window.h @@ -259,6 +259,9 @@ public: bool is_destroyed() const { return m_destroyed; } void destroy(); + bool default_positioned() const { return m_default_positioned; } + void set_default_positioned(bool p) { m_default_positioned = p; } + private: void handle_mouse_event(const MouseEvent&); void update_menu_item_text(PopupMenuItem item); @@ -293,6 +296,7 @@ private: bool m_fullscreen { false }; bool m_accessory { false }; bool m_destroyed { false }; + bool m_default_positioned { false }; WindowTileType m_tiled { WindowTileType::None }; Gfx::IntRect m_untiled_rect; bool m_occluded { false }; diff --git a/Services/WindowServer/WindowManager.cpp b/Services/WindowServer/WindowManager.cpp index 60e88cfc43..7ecda2b073 100644 --- a/Services/WindowServer/WindowManager.cpp +++ b/Services/WindowServer/WindowManager.cpp @@ -442,6 +442,7 @@ void WindowManager::start_window_move(Window& window, const MouseEvent& event) #endif move_to_front_and_make_active(window); m_move_window = window.make_weak_ptr(); + m_move_window->set_default_positioned(false); m_move_origin = event.position(); m_move_window_origin = window.position(); window.invalidate(); @@ -479,6 +480,10 @@ void WindowManager::start_window_resize(Window& window, const Gfx::IntPoint& pos m_resize_window_original_rect = window.rect(); window.invalidate(); + + if (hot_area_row == 0 || hot_area_column == 0) { + m_resize_window->set_default_positioned(false); + } } void WindowManager::start_window_resize(Window& window, const MouseEvent& event) @@ -1428,4 +1433,34 @@ void WindowManager::maximize_windows(Window& window, bool maximized) }); } +Gfx::IntPoint WindowManager::get_recommended_window_position(const Gfx::IntPoint& desired) +{ + // FIXME: Find a better source for the width and height to shift by. + Gfx::IntPoint shift(8, palette().window_title_height() + 10); + + // FIXME: Find a better source for this. + int taskbar_height = 28; + int menubar_height = MenuManager::the().menubar_rect().height(); + + const Window* overlap_window = nullptr; + for_each_visible_window_of_type_from_front_to_back(WindowType::Normal, [&](Window& window) { + if (window.default_positioned() && (!overlap_window || overlap_window->window_id() < window.window_id())) { + overlap_window = &window; + } + return IterationDecision::Continue; + }); + + Gfx::IntPoint point; + if (overlap_window) { + point = overlap_window->position() + shift; + point = { point.x() % Screen::the().width(), + (point.y() >= (Screen::the().height() - taskbar_height)) + ? menubar_height + palette().window_title_height() + : point.y() }; + } else { + point = desired; + } + + return point; +} } diff --git a/Services/WindowServer/WindowManager.h b/Services/WindowServer/WindowManager.h index f1c351b1da..ec1306a7cc 100644 --- a/Services/WindowServer/WindowManager.h +++ b/Services/WindowServer/WindowManager.h @@ -212,6 +212,8 @@ public: } } + Gfx::IntPoint get_recommended_window_position(const Gfx::IntPoint& desired); + private: NonnullRefPtr get_cursor(const String& name); NonnullRefPtr get_cursor(const String& name, const Gfx::IntPoint& hotspot); diff --git a/Services/WindowServer/WindowServer.ipc b/Services/WindowServer/WindowServer.ipc index b06ac6de3c..6f472cbab3 100644 --- a/Services/WindowServer/WindowServer.ipc +++ b/Services/WindowServer/WindowServer.ipc @@ -32,6 +32,7 @@ endpoint WindowServer = 2 CreateWindow( Gfx::IntRect rect, + bool auto_position, bool has_alpha_channel, bool modal, bool minimizable,