diff --git a/Servers/WindowServer/WSWindowFrame.cpp b/Servers/WindowServer/WSWindowFrame.cpp index ab6b70d6c14..5d33c6a09b4 100644 --- a/Servers/WindowServer/WSWindowFrame.cpp +++ b/Servers/WindowServer/WSWindowFrame.cpp @@ -234,6 +234,8 @@ void WSWindowFrame::on_mouse_event(const WSMouseEvent& event) if (m_window.type() != WSWindowType::Normal) return; if (title_bar_rect().contains(event.position())) { + wm.clear_resize_candidate(); + if (event.type() == WSMessage::MouseDown) wm.move_to_front_and_make_active(m_window); @@ -243,5 +245,26 @@ void WSWindowFrame::on_mouse_event(const WSMouseEvent& event) } if (event.type() == WSMessage::MouseDown && event.button() == MouseButton::Left) wm.start_window_drag(m_window, event.translated(rect().location())); + return; } + + if (event.type() == WSMessage::MouseMove && event.buttons() == 0) { + constexpr ResizeDirection direction_for_hot_area[3][3] = { + { ResizeDirection::UpLeft, ResizeDirection::Up, ResizeDirection::UpRight }, + { ResizeDirection::Left, ResizeDirection::None, ResizeDirection::Right }, + { ResizeDirection::DownLeft, ResizeDirection::Down, ResizeDirection::DownRight }, + }; + Rect outer_rect = { { }, rect().size() }; + ASSERT(outer_rect.contains(event.position())); + int window_relative_x = event.x() - outer_rect.x(); + int window_relative_y = event.y() - outer_rect.y(); + int hot_area_row = min(2, window_relative_y / (outer_rect.height() / 3)); + int hot_area_column = min(2, window_relative_x / (outer_rect.width() / 3)); + wm.set_resize_candidate(m_window, direction_for_hot_area[hot_area_row][hot_area_column]); + wm.invalidate_cursor(); + return; + } + + if (event.button() == MouseButton::Left) + wm.start_window_resize(m_window, event.translated(rect().location())); } diff --git a/Servers/WindowServer/WSWindowManager.cpp b/Servers/WindowServer/WSWindowManager.cpp index aef4667396e..bb2624bca10 100644 --- a/Servers/WindowServer/WSWindowManager.cpp +++ b/Servers/WindowServer/WSWindowManager.cpp @@ -488,6 +488,7 @@ void WSWindowManager::start_window_resize(WSWindow& window, const WSMouseEvent& #ifdef RESIZE_DEBUG printf("[WM] Begin resizing WSWindow{%p}\n", &window); #endif + m_resizing_mouse_button = event.button(); m_resize_window = window.make_weak_ptr();; m_resize_origin = event.position(); m_resize_window_original_rect = window.rect(); @@ -525,13 +526,14 @@ bool WSWindowManager::process_ongoing_window_resize(const WSMouseEvent& event, W if (!m_resize_window) return false; - if (event.type() == WSMessage::MouseUp && event.button() == MouseButton::Right) { + if (event.type() == WSMessage::MouseUp && event.button() == m_resizing_mouse_button) { #ifdef RESIZE_DEBUG printf("[WM] Finish resizing WSWindow{%p}\n", m_resize_window.ptr()); #endif WSMessageLoop::the().post_message(*m_resize_window, make(m_resize_window->rect(), m_resize_window->rect())); invalidate(*m_resize_window); m_resize_window = nullptr; + m_resizing_mouse_button = MouseButton::None; return true; } @@ -669,10 +671,16 @@ void WSWindowManager::process_mouse_event(const WSMouseEvent& event, WSWindow*& } } + WSWindow* event_window_with_frame = nullptr; + for_each_visible_window_from_front_to_back([&] (WSWindow& window) { auto window_frame_rect = window.frame().rect(); if (!window_frame_rect.contains(event.position())) return IterationDecision::Continue; + + if (&window != m_resize_candidate.ptr()) + clear_resize_candidate(); + // First check if we should initiate a drag or resize (Logo+LMB or Logo+RMB). // In those cases, the event is swallowed by the window manager. if (window.type() == WSWindowType::Normal) { @@ -697,8 +705,19 @@ void WSWindowManager::process_mouse_event(const WSMouseEvent& event, WSWindow*& // We are hitting the frame, pass the event along to WSWindowFrame. window.frame().on_mouse_event(event.translated(-window_frame_rect.location())); + event_window_with_frame = &window; return IterationDecision::Abort; }); + + if (event_window_with_frame != m_resize_candidate.ptr()) + clear_resize_candidate(); +} + +void WSWindowManager::clear_resize_candidate() +{ + if (m_resize_candidate) + invalidate_cursor(); + m_resize_candidate = nullptr; } void WSWindowManager::compose() @@ -1095,7 +1114,7 @@ const WSCursor& WSWindowManager::active_cursor() const if (m_drag_window) return *m_move_cursor; - if (m_resize_window) { + if (m_resize_window || m_resize_candidate) { switch (m_resize_direction) { case ResizeDirection::Up: case ResizeDirection::Down: @@ -1110,7 +1129,7 @@ const WSCursor& WSWindowManager::active_cursor() const case ResizeDirection::DownLeft: return *m_resize_diagonally_bltr_cursor; case ResizeDirection::None: - ASSERT_NOT_REACHED(); + break; } } @@ -1124,3 +1143,9 @@ void WSWindowManager::set_hovered_button(WSButton* button) { m_hovered_button = button ? button->make_weak_ptr() : nullptr; } + +void WSWindowManager::set_resize_candidate(WSWindow& window, ResizeDirection direction) +{ + m_resize_candidate = window.make_weak_ptr(); + m_resize_direction = direction; +} diff --git a/Servers/WindowServer/WSWindowManager.h b/Servers/WindowServer/WSWindowManager.h index 9c1c74d0e61..b38524b15df 100644 --- a/Servers/WindowServer/WSWindowManager.h +++ b/Servers/WindowServer/WSWindowManager.h @@ -14,6 +14,7 @@ #include #include #include +#include #include class WSAPIClientRequest; @@ -103,6 +104,9 @@ public: void set_cursor_tracking_button(WSButton*); void set_hovered_button(WSButton*); + void set_resize_candidate(WSWindow&, ResizeDirection); + void clear_resize_candidate(); + private: void process_mouse_event(const WSMouseEvent&, WSWindow*& event_window); bool process_ongoing_window_resize(const WSMouseEvent&, WSWindow*& event_window); @@ -161,6 +165,8 @@ private: Point m_drag_window_origin; WeakPtr m_resize_window; + WeakPtr m_resize_candidate; + MouseButton m_resizing_mouse_button { MouseButton::None }; Rect m_resize_window_original_rect; Point m_resize_origin; ResizeDirection m_resize_direction { ResizeDirection::None };