From 74ae6ac94b990037ae5ef412781e74e4c896af2f Mon Sep 17 00:00:00 2001 From: Jami Kettunen Date: Sat, 4 Jan 2020 15:14:36 +0200 Subject: [PATCH] WindowServer: Various window pop-up menu fixes & QoL tweaks --- Servers/WindowServer/WSMenu.h | 11 ++++++- Servers/WindowServer/WSWindow.cpp | 39 +++++++++++++++++++++--- Servers/WindowServer/WSWindow.h | 7 +++++ Servers/WindowServer/WSWindowFrame.cpp | 14 +++++++-- Servers/WindowServer/WSWindowManager.cpp | 12 +++++++- 5 files changed, 74 insertions(+), 9 deletions(-) diff --git a/Servers/WindowServer/WSMenu.h b/Servers/WindowServer/WSMenu.h index 7f9afb946a..0240aaca09 100644 --- a/Servers/WindowServer/WSMenu.h +++ b/Servers/WindowServer/WSMenu.h @@ -5,12 +5,13 @@ #include #include #include +#include #include +#include class WSClientConnection; class WSMenuBar; class WSEvent; -class WSWindow; class Font; class WSMenu final : public CObject { @@ -30,6 +31,7 @@ public: bool is_empty() const { return m_items.is_empty(); } int item_count() const { return m_items.size(); } const WSMenuItem& item(int index) const { return m_items.at(index); } + WSMenuItem& item(int index) { return m_items.at(index); } void add_item(NonnullOwnPtr&& item) { m_items.append(move(item)); } @@ -51,6 +53,11 @@ public: WSWindow* menu_window() { return m_menu_window.ptr(); } WSWindow& ensure_menu_window(); + WSWindow* window_menu_of() { return m_window_menu_of; } + void set_window_menu_of(WSWindow& window) { m_window_menu_of = window.make_weak_ptr(); } + bool is_window_menu_open() { return m_is_window_menu_open; } + void set_window_menu_open(bool is_open) { m_is_window_menu_open = is_open; } + int width() const; int height() const; @@ -94,5 +101,7 @@ private: WSMenuItem* m_hovered_item { nullptr }; NonnullOwnPtrVector m_items; RefPtr m_menu_window; + WeakPtr m_window_menu_of; + bool m_is_window_menu_open = { false }; int m_theme_index_at_last_paint { -1 }; }; diff --git a/Servers/WindowServer/WSWindow.cpp b/Servers/WindowServer/WSWindow.cpp index edafb89d8b..4cdec58970 100644 --- a/Servers/WindowServer/WSWindow.cpp +++ b/Servers/WindowServer/WSWindow.cpp @@ -99,6 +99,23 @@ void WSWindow::handle_mouse_event(const WSMouseEvent& event) } } +void WSWindow::update_menu_item_text(PopupMenuItem item) +{ + if (m_window_menu) { + m_window_menu->item((int)item).set_text(item == PopupMenuItem::Minimize ? + (m_minimized ? "Unminimize" : "Minimize") : (m_maximized ? "Restore" : "Maximize")); + m_window_menu->redraw(); + } +} + +void WSWindow::update_menu_item_enabled(PopupMenuItem item) +{ + if (m_window_menu) { + m_window_menu->item((int)item).set_enabled(item == PopupMenuItem::Minimize ? m_minimizable : m_resizable); + m_window_menu->redraw(); + } +} + void WSWindow::set_minimized(bool minimized) { if (m_minimized == minimized) @@ -106,6 +123,7 @@ void WSWindow::set_minimized(bool minimized) if (minimized && !m_minimizable) return; m_minimized = minimized; + update_menu_item_text(PopupMenuItem::Minimize); start_minimize_animation(); if (!minimized) request_update({ {}, size() }); @@ -118,6 +136,7 @@ void WSWindow::set_minimizable(bool minimizable) if (m_minimizable == minimizable) return; m_minimizable = minimizable; + update_menu_item_enabled(PopupMenuItem::Minimize); // TODO: Hide/show (or alternatively change enabled state of) window minimize button dynamically depending on value of m_minimizable } @@ -144,6 +163,7 @@ void WSWindow::set_maximized(bool maximized) if (maximized && !is_resizable()) return; m_maximized = maximized; + update_menu_item_text(PopupMenuItem::Maximize); auto old_rect = m_rect; if (maximized) { m_unmaximized_rect = m_rect; @@ -160,6 +180,7 @@ void WSWindow::set_resizable(bool resizable) if (m_resizable == resizable) return; m_resizable = resizable; + update_menu_item_enabled(PopupMenuItem::Maximize); // TODO: Hide/show (or alternatively change enabled state of) window maximize button dynamically depending on value of is_resizable() } @@ -271,18 +292,28 @@ void WSWindow::popup_window_menu(const Point& position) { if (!m_window_menu) { m_window_menu = WSMenu::construct(nullptr, -1, "(Window Menu)"); - m_window_menu->add_item(make(*m_window_menu, 1, "Minimize")); - m_window_menu->add_item(make(*m_window_menu, 2, "Unminimize")); + m_window_menu->set_window_menu_of(*this); + + m_window_menu->add_item(make(*m_window_menu, 1, m_minimized ? "Unminimize" : "Minimize")); + m_window_menu->add_item(make(*m_window_menu, 2, m_maximized ? "Restore" : "Maximize")); m_window_menu->add_item(make(*m_window_menu, WSMenuItem::Type::Separator)); m_window_menu->add_item(make(*m_window_menu, 3, "Close")); + m_window_menu->item((int)PopupMenuItem::Minimize).set_enabled(m_minimizable); + m_window_menu->item((int)PopupMenuItem::Maximize).set_enabled(m_resizable); + m_window_menu->on_item_activation = [&](auto& item) { switch (item.identifier()) { case 1: - set_minimized(true); + set_minimized(!m_minimized); + if (!m_minimized) + WSWindowManager::the().move_to_front_and_make_active(*this); break; case 2: - set_minimized(false); + set_maximized(!m_maximized); + if (m_minimized) + set_minimized(false); + WSWindowManager::the().move_to_front_and_make_active(*this); break; case 3: request_close(); diff --git a/Servers/WindowServer/WSWindow.h b/Servers/WindowServer/WSWindow.h index cb6a53b39e..eeb9f42856 100644 --- a/Servers/WindowServer/WSWindow.h +++ b/Servers/WindowServer/WSWindow.h @@ -27,6 +27,11 @@ enum class WindowTileType { Right, }; +enum class PopupMenuItem { + Minimize = 0, + Maximize, +}; + class WSWindow final : public CObject , public InlineLinkedListNode { C_OBJECT(WSWindow) @@ -190,6 +195,8 @@ public: private: void handle_mouse_event(const WSMouseEvent&); + void update_menu_item_text(PopupMenuItem item); + void update_menu_item_enabled(PopupMenuItem item); WSClientConnection* m_client { nullptr }; String m_title; diff --git a/Servers/WindowServer/WSWindowFrame.cpp b/Servers/WindowServer/WSWindowFrame.cpp index fbfe5b1db3..afb2f60508 100644 --- a/Servers/WindowServer/WSWindowFrame.cpp +++ b/Servers/WindowServer/WSWindowFrame.cpp @@ -284,7 +284,9 @@ void WSWindowFrame::on_mouse_event(const WSMouseEvent& event) if (m_window.type() != WSWindowType::Normal) return; - if (event.type() == WSEvent::MouseDown && event.button() == MouseButton::Left && title_bar_icon_rect().contains(event.position())) { + if (event.type() == WSEvent::MouseDown && (event.button() == MouseButton::Left || event.button() == MouseButton::Right) && + title_bar_icon_rect().contains(event.position())) { + wm.move_to_front_and_make_active(m_window); m_window.popup_window_menu(event.position().translated(rect().location())); return; } @@ -305,8 +307,14 @@ void WSWindowFrame::on_mouse_event(const WSMouseEvent& event) if (button.relative_rect().contains(event.position())) return button.on_mouse_event(event.translated(-button.relative_rect().location())); } - if (event.type() == WSEvent::MouseDown && event.button() == MouseButton::Left) - wm.start_window_move(m_window, event.translated(rect().location())); + if (event.type() == WSEvent::MouseDown) { + if (event.button() == MouseButton::Right) { + m_window.popup_window_menu(event.position().translated(rect().location())); + return; + } + if (event.button() == MouseButton::Left) + wm.start_window_move(m_window, event.translated(rect().location())); + } return; } diff --git a/Servers/WindowServer/WSWindowManager.cpp b/Servers/WindowServer/WSWindowManager.cpp index 8918b41357..6b770c32a3 100644 --- a/Servers/WindowServer/WSWindowManager.cpp +++ b/Servers/WindowServer/WSWindowManager.cpp @@ -883,8 +883,18 @@ void WSWindowManager::process_mouse_event(WSMouseEvent& event, WSWindow*& hovere if (!event_is_inside_current_menu) { if (topmost_menu->hovered_item()) topmost_menu->clear_hovered_item(); - if (event.type() == WSEvent::MouseDown || event.type() == WSEvent::MouseUp) + if (event.type() == WSEvent::MouseDown || event.type() == WSEvent::MouseUp) { + auto* window_menu_of = topmost_menu->window_menu_of(); + if (window_menu_of) { + bool event_is_inside_taskbar_button = window_menu_of->taskbar_rect().contains(event.position()); + if (event_is_inside_taskbar_button && !topmost_menu->is_window_menu_open()) { + topmost_menu->set_window_menu_open(true); + return; + } + } m_menu_manager.close_bar(); + topmost_menu->set_window_menu_open(false); + } if (event.type() == WSEvent::MouseMove) { for (auto& menu : m_menu_manager.open_menu_stack()) { if (!menu)