WindowServer: Refactor more of the menu APIs to be message-based.

This is all pretty verbose but I can whittle it down later. :^)
This commit is contained in:
Andreas Kling 2019-02-13 18:48:22 +01:00
parent fbbf57b61c
commit cf432b4c3d
Notes: sideshowbarker 2024-07-19 15:45:29 +09:00
13 changed files with 229 additions and 171 deletions

View file

@ -70,6 +70,10 @@ struct GUI_ServerMessage {
MenuItemActivated,
DidCreateMenubar,
DidDestroyMenubar,
DidCreateMenu,
DidDestroyMenu,
DidAddMenuToMenubar,
DidSetApplicationMenubar,
};
Type type { Invalid };
int window_id { -1 };
@ -104,6 +108,10 @@ struct GUI_ClientMessage {
Invalid,
CreateMenubar,
DestroyMenubar,
CreateMenu,
DestroyMenu,
AddMenuToMenubar,
SetApplicationMenubar,
};
Type type { Invalid };
int window_id { -1 };
@ -112,6 +120,9 @@ struct GUI_ClientMessage {
struct {
int menubar_id;
int menu_id;
unsigned identifier;
unsigned text_length;
char text[256];
} menu;
};
};

View file

@ -292,23 +292,6 @@ DisplayInfo Process::set_video_resolution(int width, int height)
return info;
}
int Process::gui$menubar_add_menu(int menubar_id, int menu_id)
{
return WSWindowManager::the().api$menubar_add_menu(menubar_id, menu_id);
}
int Process::gui$menu_create(const char* name)
{
if (!validate_read_str(name))
return -EFAULT;
return WSWindowManager::the().api$menu_create(String(name));
}
int Process::gui$menu_destroy(int menu_id)
{
return WSWindowManager::the().api$menu_destroy(menu_id);
}
int Process::gui$menu_add_separator(int menu_id)
{
return WSWindowManager::the().api$menu_add_separator(menu_id);
@ -320,8 +303,3 @@ int Process::gui$menu_add_item(int menu_id, unsigned identifier, const char* tex
return -EFAULT;
return WSWindowManager::the().api$menu_add_item(menu_id, identifier, String(text));
}
int Process::gui$set_menubar(int menubar_id)
{
return WSWindowManager::the().api$app_set_menubar(menubar_id);
}

View file

@ -223,18 +223,10 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
return current->sys$rmdir((const char*)arg1);
case Syscall::SC_chmod:
return current->sys$chmod((const char*)arg1, (mode_t)arg2);
case Syscall::SC_gui_menubar_add_menu:
return current->gui$menubar_add_menu((int)arg1, (int)arg2);
case Syscall::SC_gui_menu_create:
return current->gui$menu_create((const char*)arg1);
case Syscall::SC_gui_menu_destroy:
return current->gui$menu_destroy((int)arg1);
case Syscall::SC_gui_menu_add_separator:
return current->gui$menu_add_separator((int)arg1);
case Syscall::SC_gui_menu_add_item:
return current->gui$menu_add_item((int)arg1, (unsigned)arg2, (const char*)arg3);
case Syscall::SC_gui_app_set_menubar:
return current->gui$set_menubar((int)arg1);
default:
kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
break;

View file

@ -85,12 +85,8 @@
__ENUMERATE_SYSCALL(rmdir) \
__ENUMERATE_SYSCALL(chmod) \
__ENUMERATE_SYSCALL(usleep) \
__ENUMERATE_SYSCALL(gui_menubar_add_menu) \
__ENUMERATE_SYSCALL(gui_menu_create) \
__ENUMERATE_SYSCALL(gui_menu_destroy) \
__ENUMERATE_SYSCALL(gui_menu_add_separator) \
__ENUMERATE_SYSCALL(gui_menu_add_item) \
__ENUMERATE_SYSCALL(gui_app_set_menubar) \
#ifdef SERENITY

View file

@ -69,24 +69,6 @@ int gui_set_global_cursor_tracking_enabled(int window_id, bool enabled)
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int gui_menubar_add_menu(int menubar_id, int menu_id)
{
int rc = syscall(SC_gui_menubar_add_menu, menubar_id, menu_id);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int gui_menu_create(const char* name)
{
int rc = syscall(SC_gui_menu_create, name);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int gui_menu_destroy(int menu_id)
{
int rc = syscall(SC_gui_menu_destroy, menu_id);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int gui_menu_add_separator(int menu_id)
{
int rc = syscall(SC_gui_menu_add_separator, menu_id);
@ -98,9 +80,3 @@ int gui_menu_add_item(int menu_id, unsigned identifier, const char* text)
int rc = syscall(SC_gui_menu_add_item, menu_id, identifier, text);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
int gui_app_set_menubar(int menubar_id)
{
int rc = syscall(SC_gui_app_set_menubar, menubar_id);
__RETURN_WITH_ERRNO(rc, rc, -1);
}

View file

@ -16,12 +16,8 @@ int gui_set_window_title(int window_id, const char*, size_t);
int gui_get_window_rect(int window_id, GUI_Rect*);
int gui_set_window_rect(int window_id, const GUI_Rect*);
int gui_set_global_cursor_tracking_enabled(int window_id, bool);
int gui_menubar_add_menu(int menubar_id, int menu_id);
int gui_menu_create(const char* name);
int gui_menu_destroy(int menu_id);
int gui_menu_add_separator(int menu_id);
int gui_menu_add_item(int menu_id, unsigned identifier, const char* text);
int gui_app_set_menubar(int menubar_id);
__END_DECLS

View file

@ -1,5 +1,6 @@
#include <LibGUI/GAction.h>
#include <LibGUI/GMenu.h>
#include <LibGUI/GEventLoop.h>
#include <LibC/gui.h>
#include <AK/HashMap.h>
@ -26,11 +27,7 @@ GMenu::GMenu(const String& name)
GMenu::~GMenu()
{
if (m_menu_id) {
all_menus().remove(m_menu_id);
gui_menu_destroy(m_menu_id);
m_menu_id = 0;
}
unrealize_menu();
}
void GMenu::add_action(OwnPtr<GAction>&& action)
@ -45,7 +42,15 @@ void GMenu::add_separator()
int GMenu::realize_menu()
{
m_menu_id = gui_menu_create(m_name.characters());
GUI_ClientMessage request;
request.type = GUI_ClientMessage::Type::CreateMenu;
ASSERT(m_name.length() < sizeof(request.menu.text));
strcpy(request.menu.text, m_name.characters());
request.menu.text_length = m_name.length();
auto response = GEventLoop::main().sync_request(request, GUI_ServerMessage::Type::DidCreateMenu);
m_menu_id = response.menu.menu_id;
ASSERT(m_menu_id > 0);
for (size_t i = 0; i < m_items.size(); ++i) {
auto& item = *m_items[i];
@ -62,6 +67,18 @@ int GMenu::realize_menu()
return m_menu_id;
}
void GMenu::unrealize_menu()
{
if (!m_menu_id)
return;
all_menus().remove(m_menu_id);
GUI_ClientMessage request;
request.type = GUI_ClientMessage::Type::DestroyMenu;
request.menu.menu_id = m_menu_id;
GEventLoop::main().sync_request(request, GUI_ServerMessage::Type::DidDestroyMenu);
m_menu_id = 0;
}
GAction* GMenu::action_at(size_t index)
{
if (index >= m_items.size())

View file

@ -24,6 +24,7 @@ private:
friend class GMenuBar;
int menu_id() const { return m_menu_id; }
int realize_menu();
void unrealize_menu();
int m_menu_id { 0 };
String m_name;

View file

@ -44,10 +44,16 @@ void GMenuBar::notify_added_to_application(Badge<GApplication>)
ASSERT(menu);
int menu_id = menu->realize_menu();
ASSERT(menu_id > 0);
int rc = gui_menubar_add_menu(m_menubar_id, menu_id);
ASSERT(rc == 0);
GUI_ClientMessage request;
request.type = GUI_ClientMessage::Type::AddMenuToMenubar;
request.menu.menubar_id = m_menubar_id;
request.menu.menu_id = menu_id;
GEventLoop::main().sync_request(request, GUI_ServerMessage::Type::DidAddMenuToMenubar);
}
gui_app_set_menubar(m_menubar_id);
GUI_ClientMessage request;
request.type = GUI_ClientMessage::Type::SetApplicationMenubar;
request.menu.menubar_id = m_menubar_id;
GEventLoop::main().sync_request(request, GUI_ServerMessage::Type::DidSetApplicationMenubar);
}
void GMenuBar::notify_removed_from_application(Badge<GApplication>)

View file

@ -27,6 +27,10 @@ public:
__Begin_API_Client_Requests,
APICreateMenubarRequest,
APIDestroyMenubarRequest,
APIAddMenuToMenubarRequest,
APISetApplicationMenubarRequest,
APICreateMenuRequest,
APIDestroyMenuRequest,
__End_API_Client_Requests,
};
@ -80,6 +84,66 @@ private:
int m_menubar_id { 0 };
};
class WSAPISetApplicationMenubarRequest : public WSAPIClientRequest {
public:
WSAPISetApplicationMenubarRequest(int client_id, int menubar_id)
: WSAPIClientRequest(WSMessage::APISetApplicationMenubarRequest, client_id)
, m_menubar_id(menubar_id)
{
}
int menubar_id() const { return m_menubar_id; }
private:
int m_menubar_id { 0 };
};
class WSAPIAddMenuToMenubarRequest : public WSAPIClientRequest {
public:
WSAPIAddMenuToMenubarRequest(int client_id, int menubar_id, int menu_id)
: WSAPIClientRequest(WSMessage::APIAddMenuToMenubarRequest, client_id)
, m_menubar_id(menubar_id)
, m_menu_id(menu_id)
{
}
int menubar_id() const { return m_menubar_id; }
int menu_id() const { return m_menu_id; }
private:
int m_menubar_id { 0 };
int m_menu_id { 0 };
};
class WSAPICreateMenuRequest : public WSAPIClientRequest {
public:
WSAPICreateMenuRequest(int client_id, const String& text)
: WSAPIClientRequest(WSMessage::APICreateMenuRequest, client_id)
, m_text(text)
{
}
String text() const { return m_text; }
private:
String m_text;
};
class WSAPIDestroyMenuRequest : public WSAPIClientRequest {
public:
WSAPIDestroyMenuRequest(int client_id, int menu_id)
: WSAPIClientRequest(WSMessage::APIDestroyMenuRequest, client_id)
, m_menu_id(menu_id)
{
}
int menu_id() const { return m_menu_id; }
private:
int m_menu_id { 0 };
};
class WSClientFinishedPaintMessage final : public WSMessage {
public:
explicit WSClientFinishedPaintMessage(const Rect& rect = Rect())

View file

@ -274,6 +274,19 @@ ssize_t WSMessageLoop::on_receive_from_client(int client_id, const byte* data, s
case GUI_ClientMessage::Type::DestroyMenubar:
post_message(&WSWindowManager::the(), make<WSAPIDestroyMenubarRequest>(client_id, message.menu.menubar_id));
break;
case GUI_ClientMessage::Type::SetApplicationMenubar:
post_message(&WSWindowManager::the(), make<WSAPISetApplicationMenubarRequest>(client_id, message.menu.menubar_id));
break;
case GUI_ClientMessage::Type::AddMenuToMenubar:
post_message(&WSWindowManager::the(), make<WSAPIAddMenuToMenubarRequest>(client_id, message.menu.menubar_id, message.menu.menu_id));
break;
case GUI_ClientMessage::Type::CreateMenu:
ASSERT(message.menu.text_length < sizeof(message.menu.text));
post_message(&WSWindowManager::the(), make<WSAPICreateMenuRequest>(client_id, String(message.menu.text, message.menu.text_length)));
break;
case GUI_ClientMessage::Type::DestroyMenu:
post_message(&WSWindowManager::the(), make<WSAPIDestroyMenuRequest>(client_id, message.menu.menu_id));
break;
}
return size;
}

View file

@ -734,39 +734,109 @@ void WSWindowManager::on_message(WSMessage& message)
return;
}
if (message.is_client_request()) {
auto& request = static_cast<WSAPIClientRequest&>(message);
switch (request.type()) {
case WSMessage::APICreateMenubarRequest: {
int menubar_id = m_next_menubar_id++;
auto menubar = make<WSMenuBar>(menubar_id, *WSMessageLoop::process_from_client_id(request.client_id()));
m_menubars.set(menubar_id, move(menubar));
GUI_ServerMessage response;
response.type = GUI_ServerMessage::Type::DidCreateMenubar;
response.menu.menubar_id = menubar_id;
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
break;
if (message.is_client_request())
handle_client_request(static_cast<WSAPIClientRequest&>(message));
}
void WSWindowManager::handle_client_request(WSAPIClientRequest& request)
{
switch (request.type()) {
case WSMessage::APICreateMenubarRequest: {
int menubar_id = m_next_menubar_id++;
auto menubar = make<WSMenuBar>(menubar_id, *WSMessageLoop::process_from_client_id(request.client_id()));
m_menubars.set(menubar_id, move(menubar));
GUI_ServerMessage response;
response.type = GUI_ServerMessage::Type::DidCreateMenubar;
response.menu.menubar_id = menubar_id;
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
break;
}
case WSMessage::APIDestroyMenubarRequest: {
int menubar_id = static_cast<WSAPIDestroyMenubarRequest&>(request).menubar_id();
auto it = m_menubars.find(menubar_id);
if (it == m_menubars.end()) {
ASSERT_NOT_REACHED();
// FIXME: Send an error.
return;
}
case WSMessage::APIDestroyMenubarRequest: {
int menubar_id = static_cast<WSAPIDestroyMenubarRequest&>(request).menubar_id();
auto it = m_menubars.find(menubar_id);
if (it == m_menubars.end()) {
ASSERT_NOT_REACHED();
// FIXME: Send an error.
return;
}
auto& menubar = *(*it).value;
if (&menubar == m_current_menubar)
set_current_menubar(nullptr);
m_menubars.remove(it);
GUI_ServerMessage response;
response.type = GUI_ServerMessage::Type::DidDestroyMenubar;
response.menu.menubar_id = menubar_id;
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
auto& menubar = *(*it).value;
if (&menubar == m_current_menubar)
set_current_menubar(nullptr);
m_menubars.remove(it);
GUI_ServerMessage response;
response.type = GUI_ServerMessage::Type::DidDestroyMenubar;
response.menu.menubar_id = menubar_id;
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
break;
}
case WSMessage::APICreateMenuRequest: {
int menu_id = m_next_menu_id++;
auto menu = make<WSMenu>(*WSMessageLoop::process_from_client_id(request.client_id()), menu_id, static_cast<WSAPICreateMenuRequest&>(request).text());
m_menus.set(menu_id, move(menu));
GUI_ServerMessage response;
response.type = GUI_ServerMessage::Type::DidCreateMenu;
response.menu.menu_id = menu_id;
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
break;
}
case WSMessage::APIDestroyMenuRequest: {
int menu_id = static_cast<WSAPIDestroyMenuRequest&>(request).menu_id();
auto it = m_menus.find(menu_id);
if (it == m_menus.end()) {
ASSERT_NOT_REACHED();
// FIXME: Send an error.
return;
}
default:
break;
auto& menu = *(*it).value;
close_menu(menu);
m_menus.remove(it);
GUI_ServerMessage response;
response.type = GUI_ServerMessage::Type::DidDestroyMenu;
response.menu.menu_id = menu_id;
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
break;
}
case WSMessage::APISetApplicationMenubarRequest: {
int menubar_id = static_cast<WSAPISetApplicationMenubarRequest&>(request).menubar_id();
auto it = m_menubars.find(menubar_id);
if (it == m_menubars.end()) {
ASSERT_NOT_REACHED();
// FIXME: Send an error.
return;
}
auto& menubar = *(*it).value;
m_app_menubars.set(request.client_id(), &menubar);
if (active_client_id() == request.client_id())
set_current_menubar(&menubar);
invalidate();
GUI_ServerMessage response;
response.type = GUI_ServerMessage::Type::DidSetApplicationMenubar;
response.menu.menubar_id = menubar_id;
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
break;
}
case WSMessage::APIAddMenuToMenubarRequest: {
int menubar_id = static_cast<WSAPIAddMenuToMenubarRequest&>(request).menubar_id();
int menu_id = static_cast<WSAPIAddMenuToMenubarRequest&>(request).menu_id();
auto it = m_menubars.find(menubar_id);
auto jt = m_menus.find(menu_id);
if (it == m_menubars.end() || jt == m_menus.end()) {
ASSERT_NOT_REACHED();
// FIXME: Send an error.
return;
}
auto& menubar = *(*it).value;
auto& menu = *(*jt).value;
menubar.add_menu(&menu);
GUI_ServerMessage response;
response.type = GUI_ServerMessage::Type::DidAddMenuToMenubar;
response.menu.menubar_id = menubar_id;
response.menu.menu_id = menu_id;
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
break;
}
default:
break;
}
}
@ -786,7 +856,7 @@ void WSWindowManager::set_active_window(WSWindow* window)
invalidate(*m_active_window);
ASSERT(window->process());
auto it = m_app_menubars.find(window->process());
auto it = m_app_menubars.find(window->process()->gui_client_id());
if (it != m_app_menubars.end()) {
auto* menubar = (*it).value;
if (menubar != m_current_menubar)
@ -880,51 +950,6 @@ void WSWindowManager::close_menu(WSMenu& menu)
close_current_menu();
}
WSMenu& WSWindowManager::create_menu(String&& name)
{
LOCKER(m_lock);
int menu_id = m_next_menu_id++;
auto menu = make<WSMenu>(*current, menu_id, move(name));
auto* menu_ptr = menu.ptr();
m_menus.set(menu_id, move(menu));
return *menu_ptr;
}
int WSWindowManager::api$menubar_add_menu(int menubar_id, int menu_id)
{
LOCKER(m_lock);
auto it = m_menubars.find(menubar_id);
if (it == m_menubars.end())
return -EBADMENUBAR;
auto& menubar = *(*it).value;
auto jt = m_menus.find(menu_id);
if (jt == m_menus.end())
return -EBADMENU;
auto& menu = *(*jt).value;
menubar.add_menu(&menu);
return 0;
}
int WSWindowManager::api$menu_create(String&& name)
{
LOCKER(m_lock);
return create_menu(move(name)).menu_id();
}
int WSWindowManager::api$menu_destroy(int menu_id)
{
LOCKER(m_lock);
auto it = m_menus.find(menu_id);
if (it == m_menus.end())
return -EBADMENU;
auto& menu = *(*it).value;
close_menu(menu);
m_menus.remove(it);
return 0;
}
int WSWindowManager::api$menu_add_separator(int menu_id)
{
LOCKER(m_lock);
@ -947,24 +972,10 @@ int WSWindowManager::api$menu_add_item(int menu_id, unsigned identifier, String&
return 0;
}
const Process* WSWindowManager::active_process() const
int WSWindowManager::active_client_id() const
{
if (m_active_window)
return m_active_window->process();
return nullptr;
}
int WSWindowManager::api$app_set_menubar(int menubar_id)
{
LOCKER(m_lock);
auto it = m_menubars.find(menubar_id);
if (it == m_menubars.end())
return -EBADMENUBAR;
auto& menubar = *(*it).value;
m_app_menubars.set(current, &menubar);
if (active_process() == current)
set_current_menubar(&menubar);
invalidate();
return m_active_window->process()->gui_client_id();
return 0;
}
@ -996,5 +1007,5 @@ void WSWindowManager::destroy_all_menus(Process& process)
set_current_menubar(nullptr);
for (int menubar_id : menubar_ids)
m_menubars.remove(menubar_id);
m_app_menubars.remove(&process);
m_app_menubars.remove(process.gui_client_id());
}

View file

@ -12,6 +12,7 @@
#include "WSMenuBar.h"
#include <WindowServer/WSWindowType.h>
class WSAPIClientRequest;
class WSScreen;
class WSMenuBar;
class WSMouseEvent;
@ -32,7 +33,7 @@ public:
void notify_rect_changed(WSWindow&, const Rect& oldRect, const Rect& newRect);
WSWindow* active_window() { return m_active_window.ptr(); }
const Process* active_process() const;
int active_client_id() const;
void move_to_front(WSWindow&);
@ -59,12 +60,8 @@ public:
Color menu_selection_color() const { return m_menu_selection_color; }
int menubar_menu_margin() const;
int api$menubar_add_menu(int menubar_id, int menu_id);
int api$menu_create(String&&);
int api$menu_destroy(int menu_id);
int api$menu_add_separator(int menu_id);
int api$menu_add_item(int menu_id, unsigned identifier, String&& text);
int api$app_set_menubar(int menubar_id);
void destroy_all_menus(Process&);
private:
@ -76,6 +73,7 @@ private:
void handle_menubar_mouse_event(WSMenuBar&, WSMouseEvent&);
void handle_titlebar_mouse_event(WSWindow&, WSMouseEvent&);
void handle_close_button_mouse_event(WSWindow&, WSMouseEvent&);
void handle_client_request(WSAPIClientRequest&);
void set_active_window(WSWindow*);
template<typename Callback> IterationDecision for_each_visible_window_of_type_from_back_to_front(WSWindowType, Callback);
@ -84,7 +82,6 @@ private:
template<typename Callback> IterationDecision for_each_visible_window_from_back_to_front(Callback);
template<typename Callback> void for_each_active_menubar_menu(Callback);
void close_current_menu();
WSMenu& create_menu(String&& name);
virtual void on_message(WSMessage&) override;
@ -156,5 +153,5 @@ private:
WSMenu* m_current_menu { nullptr };
HashMap<int, OwnPtr<WSMenuBar>> m_menubars;
HashMap<int, OwnPtr<WSMenu>> m_menus;
HashMap<const Process*, WSMenuBar*> m_app_menubars;
HashMap<int, WSMenuBar*> m_app_menubars;
};