mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 16:52:43 +00:00 
			
		
		
		
	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. :^)
This commit is contained in:
		
							parent
							
								
									da475ce3f5
								
							
						
					
					
						commit
						2e9cc75d11
					
				
					 10 changed files with 92 additions and 35 deletions
				
			
		|  | @ -1,20 +1,8 @@ | |||
| #include "TaskbarButton.h" | ||||
| #include <LibGUI/GAction.h> | ||||
| #include <LibGUI/GEventLoop.h> | ||||
| #include <LibGUI/GMenu.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) | ||||
|     : GButton(parent) | ||||
|     , m_identifier(identifier) | ||||
|  | @ -27,22 +15,10 @@ TaskbarButton::~TaskbarButton() | |||
| 
 | ||||
| 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); | ||||
| } | ||||
|  |  | |||
|  | @ -11,8 +11,5 @@ public: | |||
| private: | ||||
|     virtual void context_menu_event(GContextMenuEvent&) override; | ||||
| 
 | ||||
|     GMenu& ensure_menu(); | ||||
| 
 | ||||
|     WindowIdentifier m_identifier; | ||||
|     OwnPtr<GMenu> m_menu; | ||||
| }; | ||||
|  |  | |||
|  | @ -222,6 +222,7 @@ struct WSAPI_ClientMessage { | |||
|         WM_SetActiveWindow, | ||||
|         WM_SetWindowMinimized, | ||||
|         WM_StartWindowResize, | ||||
|         WM_PopupWindowMenu, | ||||
|         PopupMenu, | ||||
|         DismissMenu, | ||||
|         SetWindowIcon, | ||||
|  | @ -251,6 +252,7 @@ struct WSAPI_ClientMessage { | |||
|             int client_id; | ||||
|             int window_id; | ||||
|             bool minimized; | ||||
|             WSAPI_Point position; | ||||
|         } wm; | ||||
|         struct { | ||||
|             int menubar_id; | ||||
|  |  | |||
|  | @ -695,6 +695,22 @@ void WSClientConnection::handle_request(const WSWMAPISetActiveWindowRequest& req | |||
|     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) | ||||
| { | ||||
|     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)); | ||||
|     case WSEvent::WMAPIStartWindowResizeRequest: | ||||
|         return handle_request(static_cast<const WSWMAPIStartWindowResizeRequest&>(request)); | ||||
|     case WSEvent::WMAPIPopupWindowMenuRequest: | ||||
|         return handle_request(static_cast<const WSWMAPIPopupWindowMenuRequest&>(request)); | ||||
|     case WSEvent::APIPopupMenuRequest: | ||||
|         return handle_request(static_cast<const WSAPIPopupMenuRequest&>(request)); | ||||
|     case WSEvent::APIDismissMenuRequest: | ||||
|  |  | |||
|  | @ -77,6 +77,7 @@ private: | |||
|     void handle_request(const WSWMAPISetActiveWindowRequest&); | ||||
|     void handle_request(const WSWMAPISetWindowMinimizedRequest&); | ||||
|     void handle_request(const WSWMAPIStartWindowResizeRequest&); | ||||
|     void handle_request(const WSWMAPIPopupWindowMenuRequest&); | ||||
|     void handle_request(const WSAPIPopupMenuRequest&); | ||||
|     void handle_request(const WSAPIDismissMenuRequest&); | ||||
|     void handle_request(const WSAPISetWindowHasAlphaChannelRequest&); | ||||
|  |  | |||
|  | @ -67,6 +67,7 @@ public: | |||
|         WMAPISetActiveWindowRequest, | ||||
|         WMAPISetWindowMinimizedRequest, | ||||
|         WMAPIStartWindowResizeRequest, | ||||
|         WMAPIPopupWindowMenuRequest, | ||||
|         APIPopupMenuRequest, | ||||
|         APIDismissMenuRequest, | ||||
|         __End_API_Client_Requests, | ||||
|  | @ -129,6 +130,26 @@ private: | |||
|     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 { | ||||
| public: | ||||
|     WSWMAPISetActiveWindowRequest(int client_id, int target_client_id, int target_window_id) | ||||
|  |  | |||
|  | @ -312,6 +312,9 @@ bool WSEventLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessag | |||
|     case WSAPI_ClientMessage::Type::WM_StartWindowResize: | ||||
|         post_event(client, make<WSWMAPIStartWindowResizeRequest>(client_id, message.wm.client_id, message.wm.window_id)); | ||||
|         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: | ||||
|         post_event(client, make<WSAPIMoveWindowToFrontRequest>(client_id, message.window_id)); | ||||
|         break; | ||||
|  |  | |||
|  | @ -314,3 +314,34 @@ void WSWindow::request_update(const Rect& 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); | ||||
| } | ||||
|  |  | |||
|  | @ -21,6 +21,9 @@ public: | |||
|     WSWindow(CObject&, WSWindowType); | ||||
|     virtual ~WSWindow() override; | ||||
| 
 | ||||
|     void popup_window_menu(const Point&); | ||||
|     void request_close(); | ||||
| 
 | ||||
|     unsigned wm_event_mask() const { return m_wm_event_mask; } | ||||
|     void set_wm_event_mask(unsigned mask) { m_wm_event_mask = mask; } | ||||
| 
 | ||||
|  | @ -177,4 +180,5 @@ private: | |||
|     unsigned m_wm_event_mask { 0 }; | ||||
|     DisjointRectSet m_pending_paint_rects; | ||||
|     Rect m_unmaximized_rect; | ||||
|     OwnPtr<WSMenu> m_window_menu; | ||||
| }; | ||||
|  |  | |||
|  | @ -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(); | ||||
| 
 | ||||
|     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()) { | ||||
|  | @ -271,6 +270,11 @@ 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())) { | ||||
|         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,
 | ||||
|     // so that mouse events between the title bar and window contents don't act like
 | ||||
|     // mouse events on the border.
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling