1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 16:57:35 +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:
Andreas Kling 2020-02-17 20:05:14 +01:00
parent 189fa68c0b
commit 84520d8b59
8 changed files with 63 additions and 165 deletions

View file

@ -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)

View file

@ -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;

View file

@ -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

View file

@ -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();
}
}

View file

@ -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;
};

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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)
}