
As a consequence, move to use an explicit handshake() method rather than calling virtuals from the constructor. This seemed to not bother AClientConnection, but LibGUI crashes (rightfully) because of it.
140 lines
4.3 KiB
C++
140 lines
4.3 KiB
C++
#include <AK/HashMap.h>
|
|
#include <LibGUI/GAction.h>
|
|
#include <LibGUI/GEventLoop.h>
|
|
#include <LibGUI/GMenu.h>
|
|
|
|
//#define GMENU_DEBUG
|
|
|
|
static HashMap<int, GMenu*>& all_menus()
|
|
{
|
|
static HashMap<int, GMenu*>* map;
|
|
if (!map)
|
|
map = new HashMap<int, GMenu*>();
|
|
return *map;
|
|
}
|
|
|
|
GMenu* GMenu::from_menu_id(int menu_id)
|
|
{
|
|
auto it = all_menus().find(menu_id);
|
|
if (it == all_menus().end())
|
|
return nullptr;
|
|
return (*it).value;
|
|
}
|
|
|
|
GMenu::GMenu(const StringView& name)
|
|
: m_name(name)
|
|
{
|
|
}
|
|
|
|
GMenu::~GMenu()
|
|
{
|
|
unrealize_menu();
|
|
}
|
|
|
|
void GMenu::add_action(NonnullRefPtr<GAction> action)
|
|
{
|
|
m_items.append(make<GMenuItem>(m_menu_id, move(action)));
|
|
#ifdef GMENU_DEBUG
|
|
dbgprintf("GMenu::add_action(): MenuItem Menu ID: %d\n", m_menu_id);
|
|
#endif
|
|
}
|
|
|
|
void GMenu::add_separator()
|
|
{
|
|
m_items.append(make<GMenuItem>(m_menu_id, GMenuItem::Separator));
|
|
}
|
|
|
|
void GMenu::popup(const Point& screen_position)
|
|
{
|
|
if (m_menu_id == -1)
|
|
realize_menu();
|
|
WSAPI_ClientMessage request;
|
|
request.type = WSAPI_ClientMessage::Type::PopupMenu;
|
|
request.menu.menu_id = m_menu_id;
|
|
request.menu.position = screen_position;
|
|
GEventLoop::current().connection().post_message_to_server(request);
|
|
}
|
|
|
|
void GMenu::dismiss()
|
|
{
|
|
if (m_menu_id == -1)
|
|
return;
|
|
WSAPI_ClientMessage request;
|
|
request.type = WSAPI_ClientMessage::Type::DismissMenu;
|
|
request.menu.menu_id = m_menu_id;
|
|
GEventLoop::current().connection().post_message_to_server(request);
|
|
}
|
|
|
|
int GMenu::realize_menu()
|
|
{
|
|
WSAPI_ClientMessage request;
|
|
request.type = WSAPI_ClientMessage::Type::CreateMenu;
|
|
ASSERT(m_name.length() < (ssize_t)sizeof(request.text));
|
|
strcpy(request.text, m_name.characters());
|
|
request.text_length = m_name.length();
|
|
auto response = GEventLoop::current().connection().sync_request(request, WSAPI_ServerMessage::Type::DidCreateMenu);
|
|
m_menu_id = response.menu.menu_id;
|
|
|
|
#ifdef GMENU_DEBUG
|
|
dbgprintf("GMenu::realize_menu(): New menu ID: %d\n", m_menu_id);
|
|
#endif
|
|
ASSERT(m_menu_id > 0);
|
|
for (int i = 0; i < m_items.size(); ++i) {
|
|
auto& item = *m_items[i];
|
|
item.set_menu_id({}, m_menu_id);
|
|
item.set_identifier({}, i);
|
|
if (item.type() == GMenuItem::Separator) {
|
|
WSAPI_ClientMessage request;
|
|
request.type = WSAPI_ClientMessage::Type::AddMenuSeparator;
|
|
request.menu.menu_id = m_menu_id;
|
|
GEventLoop::current().connection().sync_request(request, WSAPI_ServerMessage::Type::DidAddMenuSeparator);
|
|
continue;
|
|
}
|
|
if (item.type() == GMenuItem::Action) {
|
|
auto& action = *item.action();
|
|
WSAPI_ClientMessage request;
|
|
request.type = WSAPI_ClientMessage::Type::AddMenuItem;
|
|
request.menu.menu_id = m_menu_id;
|
|
request.menu.identifier = i;
|
|
request.menu.enabled = action.is_enabled();
|
|
request.menu.checkable = action.is_checkable();
|
|
if (action.is_checkable())
|
|
request.menu.checked = action.is_checked();
|
|
ASSERT(action.text().length() < (ssize_t)sizeof(request.text));
|
|
strcpy(request.text, action.text().characters());
|
|
request.text_length = action.text().length();
|
|
|
|
if (action.shortcut().is_valid()) {
|
|
auto shortcut_text = action.shortcut().to_string();
|
|
ASSERT(shortcut_text.length() < (ssize_t)sizeof(request.menu.shortcut_text));
|
|
strcpy(request.menu.shortcut_text, shortcut_text.characters());
|
|
request.menu.shortcut_text_length = shortcut_text.length();
|
|
} else {
|
|
request.menu.shortcut_text_length = 0;
|
|
}
|
|
|
|
GEventLoop::current().connection().sync_request(request, WSAPI_ServerMessage::Type::DidAddMenuItem);
|
|
}
|
|
}
|
|
all_menus().set(m_menu_id, this);
|
|
return m_menu_id;
|
|
}
|
|
|
|
void GMenu::unrealize_menu()
|
|
{
|
|
if (m_menu_id == -1)
|
|
return;
|
|
all_menus().remove(m_menu_id);
|
|
WSAPI_ClientMessage request;
|
|
request.type = WSAPI_ClientMessage::Type::DestroyMenu;
|
|
request.menu.menu_id = m_menu_id;
|
|
GEventLoop::current().connection().sync_request(request, WSAPI_ServerMessage::Type::DidDestroyMenu);
|
|
m_menu_id = 0;
|
|
}
|
|
|
|
GAction* GMenu::action_at(int index)
|
|
{
|
|
if (index >= m_items.size())
|
|
return nullptr;
|
|
return m_items[index]->action();
|
|
}
|