mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 16:17:45 +00:00
WindowServer: Make way for the out-of-process system menu
This patch removes the internal system menu from WindowServer and replaces it with two IPC API's: SetSystemMenu(menu_id) SetSystemTheme(theme_path, theme_name) These API's will allow us to complete the SystemMenu program and move it entirely out of process.
This commit is contained in:
parent
189fa68c0b
commit
84520d8b59
8 changed files with 63 additions and 165 deletions
|
@ -683,6 +683,25 @@ OwnPtr<Messages::WindowServer::StartDragResponse> ClientConnection::handle(const
|
|||
return make<Messages::WindowServer::StartDragResponse>(true);
|
||||
}
|
||||
|
||||
OwnPtr<Messages::WindowServer::SetSystemMenuResponse> ClientConnection::handle(const Messages::WindowServer::SetSystemMenu& message)
|
||||
{
|
||||
auto it = m_menus.find(message.menu_id());
|
||||
if (it == m_menus.end()) {
|
||||
did_misbehave("SetSystemMenu called with invalid menu ID");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto& menu = it->value;
|
||||
MenuManager::the().set_system_menu(menu);
|
||||
return make<Messages::WindowServer::SetSystemMenuResponse>();
|
||||
}
|
||||
|
||||
OwnPtr<Messages::WindowServer::SetSystemThemeResponse> ClientConnection::handle(const Messages::WindowServer::SetSystemTheme& message)
|
||||
{
|
||||
bool success = WindowManager::the().update_theme(message.theme_path(), message.theme_name());
|
||||
return make<Messages::WindowServer::SetSystemThemeResponse>(success);
|
||||
}
|
||||
|
||||
void ClientConnection::boost()
|
||||
{
|
||||
if (set_process_boost(client_pid(), 10) < 0)
|
||||
|
|
|
@ -114,6 +114,8 @@ private:
|
|||
virtual OwnPtr<Messages::WindowServer::SetWindowIconBitmapResponse> handle(const Messages::WindowServer::SetWindowIconBitmap&) override;
|
||||
virtual void handle(const Messages::WindowServer::WM_SetWindowTaskbarRect&) override;
|
||||
virtual OwnPtr<Messages::WindowServer::StartDragResponse> handle(const Messages::WindowServer::StartDrag&) override;
|
||||
virtual OwnPtr<Messages::WindowServer::SetSystemMenuResponse> handle(const Messages::WindowServer::SetSystemMenu&) override;
|
||||
virtual OwnPtr<Messages::WindowServer::SetSystemThemeResponse> handle(const Messages::WindowServer::SetSystemTheme&) override;
|
||||
|
||||
HashMap<int, NonnullRefPtr<Window>> m_windows;
|
||||
HashMap<int, NonnullOwnPtr<MenuBar>> m_menubars;
|
||||
|
|
|
@ -74,9 +74,8 @@ void MenuItem::set_checked(bool checked)
|
|||
Menu* MenuItem::submenu()
|
||||
{
|
||||
ASSERT(is_submenu());
|
||||
if (m_menu.client())
|
||||
ASSERT(m_menu.client());
|
||||
return m_menu.client()->find_menu_by_id(m_submenu_id);
|
||||
return MenuManager::the().find_internal_menu_by_id(m_submenu_id);
|
||||
}
|
||||
|
||||
Gfx::Rect MenuItem::rect() const
|
||||
|
|
|
@ -54,132 +54,6 @@ MenuManager::MenuManager()
|
|||
s_the = this;
|
||||
m_needs_window_resize = true;
|
||||
|
||||
HashTable<String> seen_app_categories;
|
||||
{
|
||||
Core::DirIterator dt("/res/apps", Core::DirIterator::SkipDots);
|
||||
while (dt.has_next()) {
|
||||
auto af_name = dt.next_path();
|
||||
auto af_path = String::format("/res/apps/%s", af_name.characters());
|
||||
auto af = Core::ConfigFile::open(af_path);
|
||||
if (!af->has_key("App", "Name") || !af->has_key("App", "Executable"))
|
||||
continue;
|
||||
auto app_name = af->read_entry("App", "Name");
|
||||
auto app_executable = af->read_entry("App", "Executable");
|
||||
auto app_category = af->read_entry("App", "Category");
|
||||
auto app_icon_path = af->read_entry("Icons", "16x16");
|
||||
m_apps.append({ app_executable, app_name, app_icon_path, app_category });
|
||||
seen_app_categories.set(app_category);
|
||||
}
|
||||
}
|
||||
|
||||
Vector<String> sorted_app_categories;
|
||||
for (auto& category : seen_app_categories)
|
||||
sorted_app_categories.append(category);
|
||||
quick_sort(sorted_app_categories.begin(), sorted_app_categories.end(), [](auto& a, auto& b) { return a < b; });
|
||||
|
||||
u8 system_menu_name[] = { 0xc3, 0xb8, 0 };
|
||||
m_system_menu = Menu::construct(nullptr, -1, String((const char*)system_menu_name));
|
||||
|
||||
// First we construct all the necessary app category submenus.
|
||||
for (const auto& category : sorted_app_categories) {
|
||||
|
||||
if (m_app_category_menus.contains(category))
|
||||
continue;
|
||||
auto category_menu = Menu::construct(nullptr, 5000 + m_app_category_menus.size(), category);
|
||||
category_menu->on_item_activation = [this](auto& item) {
|
||||
if (item.identifier() >= 1 && item.identifier() <= 1u + m_apps.size() - 1) {
|
||||
if (fork() == 0) {
|
||||
const auto& bin = m_apps[item.identifier() - 1].executable;
|
||||
execl(bin.characters(), bin.characters(), nullptr);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
};
|
||||
auto item = make<MenuItem>(*m_system_menu, -1, category);
|
||||
item->set_submenu_id(category_menu->menu_id());
|
||||
m_system_menu->add_item(move(item));
|
||||
m_app_category_menus.set(category, move(category_menu));
|
||||
}
|
||||
|
||||
// Then we create and insert all the app menu items into the right place.
|
||||
int app_identifier = 1;
|
||||
for (const auto& app : m_apps) {
|
||||
RefPtr<Gfx::Bitmap> icon;
|
||||
if (!app.icon_path.is_empty())
|
||||
icon = Gfx::Bitmap::load_from_file(app.icon_path);
|
||||
|
||||
auto parent_menu = m_app_category_menus.get(app.category).value_or(*m_system_menu);
|
||||
parent_menu->add_item(make<MenuItem>(*m_system_menu, app_identifier++, app.name, String(), true, false, false, icon));
|
||||
}
|
||||
|
||||
m_system_menu->add_item(make<MenuItem>(*m_system_menu, MenuItem::Separator));
|
||||
|
||||
m_themes_menu = Menu::construct(nullptr, 9000, "Themes");
|
||||
|
||||
auto themes_menu_item = make<MenuItem>(*m_system_menu, 100, "Themes");
|
||||
themes_menu_item->set_submenu_id(m_themes_menu->menu_id());
|
||||
m_system_menu->add_item(move(themes_menu_item));
|
||||
|
||||
{
|
||||
Core::DirIterator dt("/res/themes", Core::DirIterator::SkipDots);
|
||||
while (dt.has_next()) {
|
||||
auto theme_name = dt.next_path();
|
||||
auto theme_path = String::format("/res/themes/%s", theme_name.characters());
|
||||
m_themes.append({ FileSystemPath(theme_name).title(), theme_path });
|
||||
}
|
||||
quick_sort(m_themes.begin(), m_themes.end(), [](auto& a, auto& b) { return a.name < b.name; });
|
||||
}
|
||||
|
||||
{
|
||||
int theme_identifier = 9000;
|
||||
for (auto& theme : m_themes) {
|
||||
m_themes_menu->add_item(make<MenuItem>(*m_themes_menu, theme_identifier++, theme.name));
|
||||
}
|
||||
}
|
||||
|
||||
m_themes_menu->on_item_activation = [this](MenuItem& item) {
|
||||
auto& theme = m_themes[(int)item.identifier() - 9000];
|
||||
WindowManager::the().update_theme(theme.path, theme.name);
|
||||
++m_theme_index;
|
||||
};
|
||||
|
||||
m_system_menu->add_item(make<MenuItem>(*m_system_menu, MenuItem::Separator));
|
||||
m_system_menu->add_item(make<MenuItem>(*m_system_menu, 100, "Reload WM Config File"));
|
||||
|
||||
m_system_menu->add_item(make<MenuItem>(*m_system_menu, MenuItem::Separator));
|
||||
m_system_menu->add_item(make<MenuItem>(*m_system_menu, 200, "About...", String(), true, false, false, Gfx::Bitmap::load_from_file("/res/icons/16x16/ladybug.png")));
|
||||
m_system_menu->add_item(make<MenuItem>(*m_system_menu, MenuItem::Separator));
|
||||
m_system_menu->add_item(make<MenuItem>(*m_system_menu, 300, "Shutdown..."));
|
||||
m_system_menu->on_item_activation = [this](MenuItem& item) {
|
||||
if (item.identifier() >= 1 && item.identifier() <= 1u + m_apps.size() - 1) {
|
||||
if (fork() == 0) {
|
||||
const auto& bin = m_apps[item.identifier() - 1].executable;
|
||||
execl(bin.characters(), bin.characters(), nullptr);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
switch (item.identifier()) {
|
||||
case 100:
|
||||
WindowManager::the().reload_config(true);
|
||||
break;
|
||||
case 200:
|
||||
if (fork() == 0) {
|
||||
execl("/bin/About", "/bin/About", nullptr);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
return;
|
||||
case 300:
|
||||
if (fork() == 0) {
|
||||
execl("/bin/SystemDialog", "/bin/SystemDialog", "--shutdown", nullptr);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
return;
|
||||
}
|
||||
#ifdef DEBUG_MENUS
|
||||
dbg() << "Menu 1 item activated: " << item.text();
|
||||
#endif
|
||||
};
|
||||
|
||||
// NOTE: This ensures that the system menu has the correct dimensions.
|
||||
set_current_menubar(nullptr);
|
||||
|
||||
|
@ -493,17 +367,6 @@ Gfx::Rect MenuManager::menubar_rect() const
|
|||
return { 0, 0, Screen::the().rect().width(), 18 };
|
||||
}
|
||||
|
||||
Menu* MenuManager::find_internal_menu_by_id(int menu_id)
|
||||
{
|
||||
if (m_themes_menu->menu_id() == menu_id)
|
||||
return m_themes_menu.ptr();
|
||||
for (auto& it : m_app_category_menus) {
|
||||
if (menu_id == it.value->menu_id())
|
||||
return it.value;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void MenuManager::set_current_menubar(MenuBar* menubar)
|
||||
{
|
||||
if (menubar)
|
||||
|
@ -532,4 +395,16 @@ void MenuManager::close_menubar(MenuBar& menubar)
|
|||
set_current_menubar(nullptr);
|
||||
}
|
||||
|
||||
void MenuManager::set_system_menu(Menu& menu)
|
||||
{
|
||||
m_system_menu = menu.make_weak_ptr();
|
||||
set_current_menubar(m_current_menubar);
|
||||
}
|
||||
|
||||
void MenuManager::did_change_theme()
|
||||
{
|
||||
++m_theme_index;
|
||||
refresh();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -69,9 +69,16 @@ public:
|
|||
|
||||
void close_all_menus_from_client(Badge<ClientConnection>, ClientConnection&);
|
||||
|
||||
void toggle_system_menu()
|
||||
{
|
||||
if (m_system_menu)
|
||||
toggle_menu(*m_system_menu);
|
||||
}
|
||||
|
||||
Menu* system_menu() { return m_system_menu; }
|
||||
void set_system_menu(Menu&);
|
||||
|
||||
Color menu_selection_color() const { return m_menu_selection_color; }
|
||||
Menu& system_menu() { return *m_system_menu; }
|
||||
Menu* find_internal_menu_by_id(int);
|
||||
int theme_index() const { return m_theme_index; }
|
||||
|
||||
Window& window() { return *m_window; }
|
||||
|
@ -79,12 +86,16 @@ public:
|
|||
template<typename Callback>
|
||||
void for_each_active_menubar_menu(Callback callback)
|
||||
{
|
||||
if (callback(system_menu()) == IterationDecision::Break)
|
||||
if (system_menu()) {
|
||||
if (callback(*system_menu()) == IterationDecision::Break)
|
||||
return;
|
||||
}
|
||||
if (m_current_menubar)
|
||||
m_current_menubar->for_each_menu(callback);
|
||||
}
|
||||
|
||||
void did_change_theme();
|
||||
|
||||
private:
|
||||
const Gfx::Font& menu_font() const;
|
||||
const Gfx::Font& app_menu_font() const;
|
||||
|
@ -104,30 +115,14 @@ private:
|
|||
WeakPtr<Menu> m_current_menu;
|
||||
Vector<WeakPtr<Menu>> m_open_menu_stack;
|
||||
|
||||
WeakPtr<Menu> m_system_menu;
|
||||
|
||||
bool m_needs_window_resize { false };
|
||||
bool m_bar_open { false };
|
||||
|
||||
struct AppMetadata {
|
||||
String executable;
|
||||
String name;
|
||||
String icon_path;
|
||||
String category;
|
||||
};
|
||||
Vector<AppMetadata> m_apps;
|
||||
|
||||
HashMap<String, NonnullRefPtr<Menu>> m_app_category_menus;
|
||||
|
||||
struct ThemeMetadata {
|
||||
String name;
|
||||
String path;
|
||||
};
|
||||
|
||||
RefPtr<Menu> m_system_menu;
|
||||
Color m_menu_selection_color;
|
||||
|
||||
int m_theme_index { 0 };
|
||||
Vector<ThemeMetadata> m_themes;
|
||||
RefPtr<Menu> m_themes_menu;
|
||||
|
||||
WeakPtr<MenuBar> m_current_menubar;
|
||||
};
|
||||
|
|
|
@ -933,7 +933,7 @@ void WindowManager::event(Core::Event& event)
|
|||
if (key_event.key() == Key_Logo) {
|
||||
if (key_event.type() == Event::KeyUp) {
|
||||
if (!m_moved_or_resized_since_logo_keydown && !m_switcher.is_visible() && !m_move_window && !m_resize_window) {
|
||||
MenuManager::the().toggle_menu(MenuManager::the().system_menu());
|
||||
MenuManager::the().toggle_system_menu();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1225,9 +1225,11 @@ Gfx::Rect WindowManager::dnd_rect() const
|
|||
return Gfx::Rect(location, { width, height }).inflated(4, 4);
|
||||
}
|
||||
|
||||
void WindowManager::update_theme(String theme_path, String theme_name)
|
||||
bool WindowManager::update_theme(String theme_path, String theme_name)
|
||||
{
|
||||
auto new_theme = Gfx::load_system_theme(theme_path);
|
||||
if (!new_theme)
|
||||
return false;
|
||||
ASSERT(new_theme);
|
||||
Gfx::set_system_theme(*new_theme);
|
||||
m_palette = Gfx::PaletteImpl::create_with_shared_buffer(*new_theme);
|
||||
|
@ -1241,10 +1243,12 @@ void WindowManager::update_theme(String theme_path, String theme_name)
|
|||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
MenuManager::the().did_change_theme();
|
||||
auto wm_config = Core::ConfigFile::open("/etc/WindowServer/WindowServer.ini");
|
||||
wm_config->write_entry("Theme", "Name", theme_name);
|
||||
wm_config->sync();
|
||||
invalidate();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ public:
|
|||
const Window* active_fullscreen_window() const { return (m_active_window && m_active_window->is_fullscreen()) ? m_active_window : nullptr; }
|
||||
Window* active_fullscreen_window() { return (m_active_window && m_active_window->is_fullscreen()) ? m_active_window : nullptr; }
|
||||
|
||||
void update_theme(String theme_path, String theme_name);
|
||||
bool update_theme(String theme_path, String theme_name);
|
||||
|
||||
void set_hovered_window(Window*);
|
||||
void deliver_mouse_event(Window& window, MouseEvent& event);
|
||||
|
|
|
@ -11,6 +11,8 @@ endpoint WindowServer = 2
|
|||
AddMenuToMenubar(i32 menubar_id, i32 menu_id) => ()
|
||||
SetApplicationMenubar(i32 menubar_id) => ()
|
||||
|
||||
SetSystemMenu(i32 menu_id) => ()
|
||||
|
||||
AddMenuItem(
|
||||
i32 menu_id,
|
||||
i32 identifier,
|
||||
|
@ -79,4 +81,6 @@ endpoint WindowServer = 2
|
|||
SetWindowOverrideCursor(i32 window_id, i32 cursor_type) => ()
|
||||
|
||||
StartDrag(String text, String data_type, String data, i32 bitmap_id, Gfx::Size bitmap_size) => (bool started)
|
||||
|
||||
SetSystemTheme(String theme_path, String theme_name) => (bool success)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue