From 9906f41e016994b35a05239550fe96e519442f26 Mon Sep 17 00:00:00 2001 From: Timur Sultanov Date: Sun, 3 Apr 2022 02:06:35 +0300 Subject: [PATCH] Keymap+WindowServer: Add context menu to keymap applet Adding a context menu which lists configured keymaps and allows setting the active keymap --- Userland/Applets/Keymap/CMakeLists.txt | 1 + .../Applets/Keymap/KeymapStatusWidget.cpp | 73 +++++++++++++++++++ Userland/Applets/Keymap/KeymapStatusWidget.h | 34 +++++++++ .../Applets/Keymap/KeymapStatusWindow.cpp | 18 +---- Userland/Applets/Keymap/KeymapStatusWindow.h | 6 +- .../Services/WindowServer/KeymapSwitcher.cpp | 8 +- .../Services/WindowServer/KeymapSwitcher.h | 4 +- .../WindowServer/WMConnectionFromClient.cpp | 5 ++ .../WindowServer/WMConnectionFromClient.h | 1 + .../Services/WindowServer/WindowManager.h | 2 + .../WindowServer/WindowManagerServer.ipc | 1 + 11 files changed, 126 insertions(+), 27 deletions(-) create mode 100644 Userland/Applets/Keymap/KeymapStatusWidget.cpp create mode 100644 Userland/Applets/Keymap/KeymapStatusWidget.h diff --git a/Userland/Applets/Keymap/CMakeLists.txt b/Userland/Applets/Keymap/CMakeLists.txt index 2092d2de686..ded34f89131 100644 --- a/Userland/Applets/Keymap/CMakeLists.txt +++ b/Userland/Applets/Keymap/CMakeLists.txt @@ -6,6 +6,7 @@ serenity_component( set(SOURCES KeymapStatusWindow.cpp + KeymapStatusWidget.cpp main.cpp ) diff --git a/Userland/Applets/Keymap/KeymapStatusWidget.cpp b/Userland/Applets/Keymap/KeymapStatusWidget.cpp new file mode 100644 index 00000000000..382cd0de83e --- /dev/null +++ b/Userland/Applets/Keymap/KeymapStatusWidget.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "KeymapStatusWidget.h" +#include "LibGUI/ActionGroup.h" +#include +#include +#include +#include +#include +#include + +void KeymapStatusWidget::mousedown_event(GUI::MouseEvent& event) +{ + Gfx::IntPoint point(event.x(), event.y()); + MUST(refresh_menu()); + m_context_menu->popup(point.translated(this->screen_relative_rect().location())); +} + +ErrorOr KeymapStatusWidget::refresh_menu() +{ + m_keymaps_group.for_each_action([&](auto& action) { + m_keymaps_group.remove_action(action); + return IterationDecision::Continue; + }); + + m_context_menu = GUI::Menu::construct(); + + auto mapper_config = TRY(Core::ConfigFile::open("/etc/Keyboard.ini")); + auto keymaps_string = mapper_config->read_entry("Mapping", "Keymaps", ""); + auto keymaps = keymaps_string.split(','); + + for (auto& keymap : keymaps) { + auto action = GUI::Action::create_checkable(keymap, [=](auto&) { + GUI::ConnectionToWindowManagerServer::the().async_set_keymap(keymap); + }); + + action->set_checked(keymap == m_current_keymap); + + m_keymaps_group.add_action(action); + m_context_menu->add_action(action); + } + + m_keymaps_group.set_exclusive(true); + + m_context_menu->add_separator(); + + auto settings_icon = TRY(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/settings.png"sv)); + + m_context_menu->add_action(GUI::Action::create("&Settings", + settings_icon, + [&](auto&) { + GUI::Process::spawn_or_show_error(window(), "/bin/KeyboardSettings"sv); + })); + + return {}; +} + +void KeymapStatusWidget::set_current_keymap(String const& keymap, ClearBackground clear_background) +{ + if (clear_background == ClearBackground::Yes) { + GUI::Painter painter(*this); + painter.clear_rect(rect(), Color::Transparent); + } + + m_current_keymap = keymap; + + set_tooltip(keymap); + set_text(keymap.substring(0, 2)); +} diff --git a/Userland/Applets/Keymap/KeymapStatusWidget.h b/Userland/Applets/Keymap/KeymapStatusWidget.h new file mode 100644 index 00000000000..3e3e0fa54e3 --- /dev/null +++ b/Userland/Applets/Keymap/KeymapStatusWidget.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +enum class ClearBackground { + No, + Yes +}; + +class KeymapStatusWidget : public GUI::Label { + C_OBJECT(KeymapStatusWidget); + + virtual void mousedown_event(GUI::MouseEvent& event) override; + + void set_current_keymap(String const& keymap, ClearBackground clear_background = ClearBackground::Yes); + +private: + RefPtr m_context_menu; + String m_current_keymap; + + ErrorOr refresh_menu(); + + GUI::ActionGroup m_keymaps_group; +}; diff --git a/Userland/Applets/Keymap/KeymapStatusWindow.cpp b/Userland/Applets/Keymap/KeymapStatusWindow.cpp index a0e42759c91..69248141a15 100644 --- a/Userland/Applets/Keymap/KeymapStatusWindow.cpp +++ b/Userland/Applets/Keymap/KeymapStatusWindow.cpp @@ -6,19 +6,10 @@ */ #include "KeymapStatusWindow.h" -#include #include #include #include -void KeymapStatusWidget::mousedown_event(GUI::MouseEvent& event) -{ - if (event.button() != GUI::MouseButton::Primary) - return; - - GUI::Process::spawn_or_show_error(window(), "/bin/KeyboardSettings"sv); -} - KeymapStatusWindow::KeymapStatusWindow() { set_window_type(GUI::WindowType::Applet); @@ -27,8 +18,7 @@ KeymapStatusWindow::KeymapStatusWindow() auto current_keymap = MUST(Keyboard::CharacterMap::fetch_system_map()); auto current_keymap_name = current_keymap.character_map_name(); - m_status_widget->set_tooltip(current_keymap_name); - m_status_widget->set_text(current_keymap_name.substring(0, 2)); + m_status_widget->set_current_keymap(current_keymap_name, ClearBackground::No); } void KeymapStatusWindow::wm_event(GUI::WMEvent& event) @@ -42,9 +32,5 @@ void KeymapStatusWindow::wm_event(GUI::WMEvent& event) void KeymapStatusWindow::set_keymap_text(String const& keymap) { - GUI::Painter painter(*m_status_widget); - painter.clear_rect(m_status_widget->rect(), Color::from_argb(0)); - - m_status_widget->set_tooltip(keymap); - m_status_widget->set_text(keymap.substring(0, 2)); + m_status_widget->set_current_keymap(keymap); } diff --git a/Userland/Applets/Keymap/KeymapStatusWindow.h b/Userland/Applets/Keymap/KeymapStatusWindow.h index 4a2a5b1fdd9..a4f4d3a1627 100644 --- a/Userland/Applets/Keymap/KeymapStatusWindow.h +++ b/Userland/Applets/Keymap/KeymapStatusWindow.h @@ -7,14 +7,10 @@ #pragma once +#include "KeymapStatusWidget.h" #include #include -class KeymapStatusWidget : public GUI::Label { - C_OBJECT(KeymapStatusWidget); - - virtual void mousedown_event(GUI::MouseEvent& event) override; -}; class KeymapStatusWindow final : public GUI::Window { C_OBJECT(KeymapStatusWindow) public: diff --git a/Userland/Services/WindowServer/KeymapSwitcher.cpp b/Userland/Services/WindowServer/KeymapSwitcher.cpp index 11a21c7c6ba..3290395ea09 100644 --- a/Userland/Services/WindowServer/KeymapSwitcher.cpp +++ b/Userland/Services/WindowServer/KeymapSwitcher.cpp @@ -53,7 +53,7 @@ void KeymapSwitcher::refresh() on_keymap_change(current_keymap); if (m_keymaps.find(current_keymap).is_end()) { - setkeymap(m_keymaps.first()); + set_keymap(m_keymaps.first()); } } @@ -75,7 +75,7 @@ void KeymapSwitcher::next_keymap() if (it.is_end()) { auto first_keymap = m_keymaps.first(); dbgln("Cannot find current keymap in the keymap list - setting first available ({})", first_keymap); - setkeymap(first_keymap); + set_keymap(first_keymap); } else { it++; @@ -84,7 +84,7 @@ void KeymapSwitcher::next_keymap() } dbgln("Setting system keymap to: {}", *it); - setkeymap(*it); + set_keymap(*it); } } @@ -100,7 +100,7 @@ String KeymapSwitcher::get_current_keymap() const return keymap_object.get("keymap"sv).to_string(); } -void KeymapSwitcher::setkeymap(const AK::String& keymap) +void KeymapSwitcher::set_keymap(const AK::String& keymap) { if (Core::Process::spawn("/bin/keymap"sv, Array { "-m", keymap.characters() }).is_error()) dbgln("Failed to call /bin/keymap, error: {} ({})", errno, strerror(errno)); diff --git a/Userland/Services/WindowServer/KeymapSwitcher.h b/Userland/Services/WindowServer/KeymapSwitcher.h index fde86465c94..8ac598d6a6f 100644 --- a/Userland/Services/WindowServer/KeymapSwitcher.h +++ b/Userland/Services/WindowServer/KeymapSwitcher.h @@ -27,6 +27,8 @@ public: String get_current_keymap() const; + void set_keymap(AK::String const&); + private: void refresh(); @@ -34,8 +36,6 @@ private: Vector m_keymaps; - void setkeymap(AK::String const&); - RefPtr m_file_watcher; char const* m_keyboard_config = "/etc/Keyboard.ini"; diff --git a/Userland/Services/WindowServer/WMConnectionFromClient.cpp b/Userland/Services/WindowServer/WMConnectionFromClient.cpp index 0ce4a6e7a6f..df213a50472 100644 --- a/Userland/Services/WindowServer/WMConnectionFromClient.cpp +++ b/Userland/Services/WindowServer/WMConnectionFromClient.cpp @@ -183,4 +183,9 @@ void WMConnectionFromClient::set_window_taskbar_rect(i32 client_id, i32 window_i window.set_taskbar_rect(rect); } +void WMConnectionFromClient::set_keymap(String const& keymap) +{ + WindowManager::the().keymap_switcher()->set_keymap(keymap); +} + } diff --git a/Userland/Services/WindowServer/WMConnectionFromClient.h b/Userland/Services/WindowServer/WMConnectionFromClient.h index 231f8fe57ce..ba93603fadf 100644 --- a/Userland/Services/WindowServer/WMConnectionFromClient.h +++ b/Userland/Services/WindowServer/WMConnectionFromClient.h @@ -31,6 +31,7 @@ public: virtual void set_event_mask(u32) override; virtual void set_manager_window(i32) override; virtual void set_workspace(u32, u32) override; + virtual void set_keymap(String const&) override; unsigned event_mask() const { return m_event_mask; } int window_id() const { return m_window_id; } diff --git a/Userland/Services/WindowServer/WindowManager.h b/Userland/Services/WindowServer/WindowManager.h index bfd1e8d01e9..3c205c278c0 100644 --- a/Userland/Services/WindowServer/WindowManager.h +++ b/Userland/Services/WindowServer/WindowManager.h @@ -336,6 +336,8 @@ public: bool is_cursor_highlight_enabled() const { return m_cursor_highlight_radius > 0 && m_cursor_highlight_enabled; } + RefPtr keymap_switcher() { return m_keymap_switcher; } + private: explicit WindowManager(Gfx::PaletteImpl const&); diff --git a/Userland/Services/WindowServer/WindowManagerServer.ipc b/Userland/Services/WindowServer/WindowManagerServer.ipc index 6d189fdbfbf..cb7e215e751 100644 --- a/Userland/Services/WindowServer/WindowManagerServer.ipc +++ b/Userland/Services/WindowServer/WindowManagerServer.ipc @@ -13,4 +13,5 @@ endpoint WindowManagerServer set_window_taskbar_rect(i32 client_id, i32 window_id, Gfx::IntRect rect) =| set_applet_area_position(Gfx::IntPoint position) =| set_workspace(u32 row, u32 column) =| + set_keymap([UTF8] String keymap) =| }