Browse Source

WindowServer+Taskbar: Let WindowServer manage the "window menus".

Taskbar now simply asks the WindowServer to popup a window menu when right
clicking on a taskbar button.

This patch also implements the "close" menu item, and furthermore makes the
window menu show up when you left-click a window's titlebar icon. :^)
Andreas Kling 6 years ago
parent
commit
2e9cc75d11

+ 6 - 30
Applications/Taskbar/TaskbarButton.cpp

@@ -1,20 +1,8 @@
 #include "TaskbarButton.h"
 #include "TaskbarButton.h"
 #include <LibGUI/GAction.h>
 #include <LibGUI/GAction.h>
 #include <LibGUI/GEventLoop.h>
 #include <LibGUI/GEventLoop.h>
-#include <LibGUI/GMenu.h>
 #include <WindowServer/WSAPITypes.h>
 #include <WindowServer/WSAPITypes.h>
 
 
-static void set_window_minimized_state(const WindowIdentifier& identifier, bool minimized)
-{
-    WSAPI_ClientMessage message;
-    message.type = WSAPI_ClientMessage::Type::WM_SetWindowMinimized;
-    message.wm.client_id = identifier.client_id();
-    message.wm.window_id = identifier.window_id();
-    message.wm.minimized = minimized;
-    bool success = GEventLoop::post_message_to_server(message);
-    ASSERT(success);
-}
-
 TaskbarButton::TaskbarButton(const WindowIdentifier& identifier, GWidget* parent)
 TaskbarButton::TaskbarButton(const WindowIdentifier& identifier, GWidget* parent)
     : GButton(parent)
     : GButton(parent)
     , m_identifier(identifier)
     , m_identifier(identifier)
@@ -27,22 +15,10 @@ TaskbarButton::~TaskbarButton()
 
 
 void TaskbarButton::context_menu_event(GContextMenuEvent&)
 void TaskbarButton::context_menu_event(GContextMenuEvent&)
 {
 {
-    ensure_menu().popup(screen_relative_rect().location());
-}
-
-GMenu& TaskbarButton::ensure_menu()
-{
-    if (!m_menu) {
-        m_menu = make<GMenu>("");
-        m_menu->add_action(GAction::create("Minimize", [this](auto&) {
-            set_window_minimized_state(m_identifier, true);
-        }));
-        m_menu->add_action(GAction::create("Unminimize", [this](auto&) {
-            set_window_minimized_state(m_identifier, false);
-        }));
-        m_menu->add_action(GAction::create("Close", [this](auto&) {
-            dbgprintf("FIXME: Close!\n");
-        }));
-    }
-    return *m_menu;
+    WSAPI_ClientMessage request;
+    request.type = WSAPI_ClientMessage::Type::WM_PopupWindowMenu;
+    request.wm.client_id = m_identifier.client_id();
+    request.wm.window_id = m_identifier.window_id();
+    request.wm.position = screen_relative_rect().location();
+    GEventLoop::post_message_to_server(request);
 }
 }

+ 0 - 3
Applications/Taskbar/TaskbarButton.h

@@ -11,8 +11,5 @@ public:
 private:
 private:
     virtual void context_menu_event(GContextMenuEvent&) override;
     virtual void context_menu_event(GContextMenuEvent&) override;
 
 
-    GMenu& ensure_menu();
-
     WindowIdentifier m_identifier;
     WindowIdentifier m_identifier;
-    OwnPtr<GMenu> m_menu;
 };
 };

+ 2 - 0
Servers/WindowServer/WSAPITypes.h

@@ -222,6 +222,7 @@ struct WSAPI_ClientMessage {
         WM_SetActiveWindow,
         WM_SetActiveWindow,
         WM_SetWindowMinimized,
         WM_SetWindowMinimized,
         WM_StartWindowResize,
         WM_StartWindowResize,
+        WM_PopupWindowMenu,
         PopupMenu,
         PopupMenu,
         DismissMenu,
         DismissMenu,
         SetWindowIcon,
         SetWindowIcon,
@@ -251,6 +252,7 @@ struct WSAPI_ClientMessage {
             int client_id;
             int client_id;
             int window_id;
             int window_id;
             bool minimized;
             bool minimized;
+            WSAPI_Point position;
         } wm;
         } wm;
         struct {
         struct {
             int menubar_id;
             int menubar_id;

+ 18 - 0
Servers/WindowServer/WSClientConnection.cpp

@@ -695,6 +695,22 @@ void WSClientConnection::handle_request(const WSWMAPISetActiveWindowRequest& req
     WSWindowManager::the().move_to_front_and_make_active(window);
     WSWindowManager::the().move_to_front_and_make_active(window);
 }
 }
 
 
+void WSClientConnection::handle_request(const WSWMAPIPopupWindowMenuRequest& request)
+{
+    auto* client = WSClientConnection::from_client_id(request.target_client_id());
+    if (!client) {
+        post_error("WSWMAPIPopupWindowMenuRequest: Bad client ID");
+        return;
+    }
+    auto it = client->m_windows.find(request.target_window_id());
+    if (it == client->m_windows.end()) {
+        post_error("WSWMAPIPopupWindowMenuRequest: Bad window ID");
+        return;
+    }
+    auto& window = *(*it).value;
+    window.popup_window_menu(request.position());
+}
+
 void WSClientConnection::handle_request(const WSWMAPIStartWindowResizeRequest& request)
 void WSClientConnection::handle_request(const WSWMAPIStartWindowResizeRequest& request)
 {
 {
     auto* client = WSClientConnection::from_client_id(request.target_client_id());
     auto* client = WSClientConnection::from_client_id(request.target_client_id());
@@ -792,6 +808,8 @@ void WSClientConnection::on_request(const WSAPIClientRequest& request)
         return handle_request(static_cast<const WSWMAPISetWindowMinimizedRequest&>(request));
         return handle_request(static_cast<const WSWMAPISetWindowMinimizedRequest&>(request));
     case WSEvent::WMAPIStartWindowResizeRequest:
     case WSEvent::WMAPIStartWindowResizeRequest:
         return handle_request(static_cast<const WSWMAPIStartWindowResizeRequest&>(request));
         return handle_request(static_cast<const WSWMAPIStartWindowResizeRequest&>(request));
+    case WSEvent::WMAPIPopupWindowMenuRequest:
+        return handle_request(static_cast<const WSWMAPIPopupWindowMenuRequest&>(request));
     case WSEvent::APIPopupMenuRequest:
     case WSEvent::APIPopupMenuRequest:
         return handle_request(static_cast<const WSAPIPopupMenuRequest&>(request));
         return handle_request(static_cast<const WSAPIPopupMenuRequest&>(request));
     case WSEvent::APIDismissMenuRequest:
     case WSEvent::APIDismissMenuRequest:

+ 1 - 0
Servers/WindowServer/WSClientConnection.h

@@ -77,6 +77,7 @@ private:
     void handle_request(const WSWMAPISetActiveWindowRequest&);
     void handle_request(const WSWMAPISetActiveWindowRequest&);
     void handle_request(const WSWMAPISetWindowMinimizedRequest&);
     void handle_request(const WSWMAPISetWindowMinimizedRequest&);
     void handle_request(const WSWMAPIStartWindowResizeRequest&);
     void handle_request(const WSWMAPIStartWindowResizeRequest&);
+    void handle_request(const WSWMAPIPopupWindowMenuRequest&);
     void handle_request(const WSAPIPopupMenuRequest&);
     void handle_request(const WSAPIPopupMenuRequest&);
     void handle_request(const WSAPIDismissMenuRequest&);
     void handle_request(const WSAPIDismissMenuRequest&);
     void handle_request(const WSAPISetWindowHasAlphaChannelRequest&);
     void handle_request(const WSAPISetWindowHasAlphaChannelRequest&);

+ 21 - 0
Servers/WindowServer/WSEvent.h

@@ -67,6 +67,7 @@ public:
         WMAPISetActiveWindowRequest,
         WMAPISetActiveWindowRequest,
         WMAPISetWindowMinimizedRequest,
         WMAPISetWindowMinimizedRequest,
         WMAPIStartWindowResizeRequest,
         WMAPIStartWindowResizeRequest,
+        WMAPIPopupWindowMenuRequest,
         APIPopupMenuRequest,
         APIPopupMenuRequest,
         APIDismissMenuRequest,
         APIDismissMenuRequest,
         __End_API_Client_Requests,
         __End_API_Client_Requests,
@@ -129,6 +130,26 @@ private:
     int m_target_window_id;
     int m_target_window_id;
 };
 };
 
 
+class WSWMAPIPopupWindowMenuRequest : public WSAPIClientRequest {
+public:
+    WSWMAPIPopupWindowMenuRequest(int client_id, int target_client_id, int target_window_id, const Point& position)
+        : WSAPIClientRequest(WSEvent::WMAPIPopupWindowMenuRequest, client_id)
+        , m_target_client_id(target_client_id)
+        , m_target_window_id(target_window_id)
+        , m_position(position)
+    {
+    }
+
+    int target_client_id() const { return m_target_client_id; }
+    int target_window_id() const { return m_target_window_id; }
+    Point position() const { return m_position; }
+
+private:
+    int m_target_client_id;
+    int m_target_window_id;
+    Point m_position;
+};
+
 class WSWMAPISetActiveWindowRequest : public WSAPIClientRequest {
 class WSWMAPISetActiveWindowRequest : public WSAPIClientRequest {
 public:
 public:
     WSWMAPISetActiveWindowRequest(int client_id, int target_client_id, int target_window_id)
     WSWMAPISetActiveWindowRequest(int client_id, int target_client_id, int target_window_id)

+ 3 - 0
Servers/WindowServer/WSEventLoop.cpp

@@ -312,6 +312,9 @@ bool WSEventLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessag
     case WSAPI_ClientMessage::Type::WM_StartWindowResize:
     case WSAPI_ClientMessage::Type::WM_StartWindowResize:
         post_event(client, make<WSWMAPIStartWindowResizeRequest>(client_id, message.wm.client_id, message.wm.window_id));
         post_event(client, make<WSWMAPIStartWindowResizeRequest>(client_id, message.wm.client_id, message.wm.window_id));
         break;
         break;
+    case WSAPI_ClientMessage::Type::WM_PopupWindowMenu:
+        post_event(client, make<WSWMAPIPopupWindowMenuRequest>(client_id, message.wm.client_id, message.wm.window_id, message.wm.position));
+        break;
     case WSAPI_ClientMessage::Type::MoveWindowToFront:
     case WSAPI_ClientMessage::Type::MoveWindowToFront:
         post_event(client, make<WSAPIMoveWindowToFrontRequest>(client_id, message.window_id));
         post_event(client, make<WSAPIMoveWindowToFrontRequest>(client_id, message.window_id));
         break;
         break;

+ 31 - 0
Servers/WindowServer/WSWindow.cpp

@@ -314,3 +314,34 @@ void WSWindow::request_update(const Rect& rect)
     }
     }
     m_pending_paint_rects.add(rect);
     m_pending_paint_rects.add(rect);
 }
 }
+
+void WSWindow::popup_window_menu(const Point& position)
+{
+    if (!m_window_menu) {
+        m_window_menu = make<WSMenu>(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->add_item(make<WSMenuItem>(*m_window_menu, 3, "Close"));
+
+        m_window_menu->on_item_activation = [&](auto& item) {
+            switch (item.identifier()) {
+            case 1:
+                set_minimized(true);
+                break;
+            case 2:
+                set_minimized(false);
+                break;
+            case 3:
+                request_close();
+                break;
+            }
+        };
+    }
+    m_window_menu->popup(position);
+}
+
+void WSWindow::request_close()
+{
+    WSEvent close_request(WSEvent::WindowCloseRequest);
+    event(close_request);
+}

+ 4 - 0
Servers/WindowServer/WSWindow.h

@@ -21,6 +21,9 @@ public:
     WSWindow(CObject&, WSWindowType);
     WSWindow(CObject&, WSWindowType);
     virtual ~WSWindow() override;
     virtual ~WSWindow() override;
 
 
+    void popup_window_menu(const Point&);
+    void request_close();
+
     unsigned wm_event_mask() const { return m_wm_event_mask; }
     unsigned wm_event_mask() const { return m_wm_event_mask; }
     void set_wm_event_mask(unsigned mask) { m_wm_event_mask = mask; }
     void set_wm_event_mask(unsigned mask) { m_wm_event_mask = mask; }
 
 
@@ -177,4 +180,5 @@ private:
     unsigned m_wm_event_mask { 0 };
     unsigned m_wm_event_mask { 0 };
     DisjointRectSet m_pending_paint_rects;
     DisjointRectSet m_pending_paint_rects;
     Rect m_unmaximized_rect;
     Rect m_unmaximized_rect;
+    OwnPtr<WSMenu> m_window_menu;
 };
 };

+ 6 - 2
Servers/WindowServer/WSWindowFrame.cpp

@@ -91,8 +91,7 @@ WSWindowFrame::WSWindowFrame(WSWindow& window)
         s_unmaximize_button_bitmap = &CharacterBitmap::create_from_ascii(s_unmaximize_button_bitmap_data, s_unmaximize_button_bitmap_width, s_unmaximize_button_bitmap_height).leak_ref();
         s_unmaximize_button_bitmap = &CharacterBitmap::create_from_ascii(s_unmaximize_button_bitmap_data, s_unmaximize_button_bitmap_width, s_unmaximize_button_bitmap_height).leak_ref();
 
 
     m_buttons.append(make<WSButton>(*this, *s_close_button_bitmap, [this](auto&) {
     m_buttons.append(make<WSButton>(*this, *s_close_button_bitmap, [this](auto&) {
-        WSEvent close_request(WSEvent::WindowCloseRequest);
-        m_window.event(close_request);
+        m_window.request_close();
     }));
     }));
 
 
     if (window.is_resizable()) {
     if (window.is_resizable()) {
@@ -271,6 +270,11 @@ void WSWindowFrame::on_mouse_event(const WSMouseEvent& event)
     if (m_window.type() != WSWindowType::Normal)
     if (m_window.type() != WSWindowType::Normal)
         return;
         return;
 
 
+    if (event.type() == WSEvent::MouseDown && event.button() == MouseButton::Left && title_bar_icon_rect().contains(event.position())) {
+        m_window.popup_window_menu(event.position().translated(rect().location()));
+        return;
+    }
+
     // This is slightly hackish, but expand the title bar rect by one pixel downwards,
     // This is slightly hackish, but expand the title bar rect by one pixel downwards,
     // so that mouse events between the title bar and window contents don't act like
     // so that mouse events between the title bar and window contents don't act like
     // mouse events on the border.
     // mouse events on the border.