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,