diff --git a/Servers/WindowServer/ClientConnection.cpp b/Servers/WindowServer/ClientConnection.cpp index c201f56b1e..5d4dc7ca90 100644 --- a/Servers/WindowServer/ClientConnection.cpp +++ b/Servers/WindowServer/ClientConnection.cpp @@ -683,6 +683,25 @@ OwnPtr ClientConnection::handle(const return make(true); } +OwnPtr 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(); +} + +OwnPtr ClientConnection::handle(const Messages::WindowServer::SetSystemTheme& message) +{ + bool success = WindowManager::the().update_theme(message.theme_path(), message.theme_name()); + return make(success); +} + void ClientConnection::boost() { if (set_process_boost(client_pid(), 10) < 0) diff --git a/Servers/WindowServer/ClientConnection.h b/Servers/WindowServer/ClientConnection.h index eca1798efe..c0c60a5b6e 100644 --- a/Servers/WindowServer/ClientConnection.h +++ b/Servers/WindowServer/ClientConnection.h @@ -114,6 +114,8 @@ private: virtual OwnPtr handle(const Messages::WindowServer::SetWindowIconBitmap&) override; virtual void handle(const Messages::WindowServer::WM_SetWindowTaskbarRect&) override; virtual OwnPtr handle(const Messages::WindowServer::StartDrag&) override; + virtual OwnPtr handle(const Messages::WindowServer::SetSystemMenu&) override; + virtual OwnPtr handle(const Messages::WindowServer::SetSystemTheme&) override; HashMap> m_windows; HashMap> m_menubars; diff --git a/Servers/WindowServer/MenuItem.cpp b/Servers/WindowServer/MenuItem.cpp index c0861ab350..b062a47d9d 100644 --- a/Servers/WindowServer/MenuItem.cpp +++ b/Servers/WindowServer/MenuItem.cpp @@ -74,9 +74,8 @@ void MenuItem::set_checked(bool checked) Menu* MenuItem::submenu() { ASSERT(is_submenu()); - if (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); + ASSERT(m_menu.client()); + return m_menu.client()->find_menu_by_id(m_submenu_id); } Gfx::Rect MenuItem::rect() const diff --git a/Servers/WindowServer/MenuManager.cpp b/Servers/WindowServer/MenuManager.cpp index abbfcd5443..878febccb8 100644 --- a/Servers/WindowServer/MenuManager.cpp +++ b/Servers/WindowServer/MenuManager.cpp @@ -54,132 +54,6 @@ MenuManager::MenuManager() s_the = this; m_needs_window_resize = true; - HashTable 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 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(*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 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(*m_system_menu, app_identifier++, app.name, String(), true, false, false, icon)); - } - - m_system_menu->add_item(make(*m_system_menu, MenuItem::Separator)); - - m_themes_menu = Menu::construct(nullptr, 9000, "Themes"); - - auto themes_menu_item = make(*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(*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(*m_system_menu, MenuItem::Separator)); - m_system_menu->add_item(make(*m_system_menu, 100, "Reload WM Config File")); - - m_system_menu->add_item(make(*m_system_menu, MenuItem::Separator)); - m_system_menu->add_item(make(*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(*m_system_menu, MenuItem::Separator)); - m_system_menu->add_item(make(*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(); +} + } diff --git a/Servers/WindowServer/MenuManager.h b/Servers/WindowServer/MenuManager.h index 0b7bfefa95..eca2e9eca6 100644 --- a/Servers/WindowServer/MenuManager.h +++ b/Servers/WindowServer/MenuManager.h @@ -69,9 +69,16 @@ public: void close_all_menus_from_client(Badge, 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 void for_each_active_menubar_menu(Callback callback) { - if (callback(system_menu()) == IterationDecision::Break) - return; + 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 m_current_menu; Vector> m_open_menu_stack; + WeakPtr 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 m_apps; - - HashMap> m_app_category_menus; - - struct ThemeMetadata { - String name; - String path; - }; - - RefPtr m_system_menu; Color m_menu_selection_color; int m_theme_index { 0 }; - Vector m_themes; - RefPtr m_themes_menu; WeakPtr m_current_menubar; }; diff --git a/Servers/WindowServer/WindowManager.cpp b/Servers/WindowServer/WindowManager.cpp index d6a611bddf..918852c806 100644 --- a/Servers/WindowServer/WindowManager.cpp +++ b/Servers/WindowServer/WindowManager.cpp @@ -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; } } diff --git a/Servers/WindowServer/WindowManager.h b/Servers/WindowServer/WindowManager.h index a09fdd0941..4d198bf0a8 100644 --- a/Servers/WindowServer/WindowManager.h +++ b/Servers/WindowServer/WindowManager.h @@ -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); diff --git a/Servers/WindowServer/WindowServer.ipc b/Servers/WindowServer/WindowServer.ipc index 0916bade53..a483896d82 100644 --- a/Servers/WindowServer/WindowServer.ipc +++ b/Servers/WindowServer/WindowServer.ipc @@ -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) }