1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-06-19 17:22:06 +00:00

WindowServer: Various window pop-up menu fixes & QoL tweaks

This commit is contained in:
Jami Kettunen 2020-01-04 15:14:36 +02:00 committed by Andreas Kling
parent eab34a7de3
commit 74ae6ac94b
5 changed files with 74 additions and 9 deletions

View file

@ -5,12 +5,13 @@
#include <AK/WeakPtr.h>
#include <LibCore/CObject.h>
#include <LibDraw/Rect.h>
#include <WindowServer/WSCursor.h>
#include <WindowServer/WSMenuItem.h>
#include <WindowServer/WSWindow.h>
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<WSMenuItem>&& 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<WSMenuItem> m_items;
RefPtr<WSWindow> m_menu_window;
WeakPtr<WSWindow> m_window_menu_of;
bool m_is_window_menu_open = { false };
int m_theme_index_at_last_paint { -1 };
};

View file

@ -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<WSMenuItem>(*m_window_menu, 1, "Minimize"));
m_window_menu->add_item(make<WSMenuItem>(*m_window_menu, 2, "Unminimize"));
m_window_menu->set_window_menu_of(*this);
m_window_menu->add_item(make<WSMenuItem>(*m_window_menu, 1, m_minimized ? "Unminimize" : "Minimize"));
m_window_menu->add_item(make<WSMenuItem>(*m_window_menu, 2, m_maximized ? "Restore" : "Maximize"));
m_window_menu->add_item(make<WSMenuItem>(*m_window_menu, WSMenuItem::Type::Separator));
m_window_menu->add_item(make<WSMenuItem>(*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_maximized(!m_maximized);
if (m_minimized)
set_minimized(false);
WSWindowManager::the().move_to_front_and_make_active(*this);
break;
case 3:
request_close();

View file

@ -27,6 +27,11 @@ enum class WindowTileType {
Right,
};
enum class PopupMenuItem {
Minimize = 0,
Maximize,
};
class WSWindow final : public CObject
, public InlineLinkedListNode<WSWindow> {
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;

View file

@ -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)
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;
}

View file

@ -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)