mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-13 01:59:14 +03: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
Notes:
sideshowbarker
2024-07-19 13:32:29 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/2e9cc75d11d
@ -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…
Reference in New Issue
Block a user