diff --git a/Base/etc/WindowServer.ini b/Base/etc/WindowServer.ini index c672e28612..82c4c6170b 100644 --- a/Base/etc/WindowServer.ini +++ b/Base/etc/WindowServer.ini @@ -32,7 +32,7 @@ DoubleClickSpeed=250 Mode=stretch [Applet] -Order=WorkspacePicker,CPUGraph,MemoryGraph,Network,ClipboardHistory,Audio +Order=WorkspacePicker,CPUGraph,MemoryGraph,Network,ClipboardHistory,Audio,Keymap [Workspaces] Rows=2 diff --git a/Userland/Applets/CMakeLists.txt b/Userland/Applets/CMakeLists.txt index af8611cd3f..eccd5ee5b8 100644 --- a/Userland/Applets/CMakeLists.txt +++ b/Userland/Applets/CMakeLists.txt @@ -3,3 +3,4 @@ add_subdirectory(ClipboardHistory) add_subdirectory(Network) add_subdirectory(ResourceGraph) add_subdirectory(WorkspacePicker) +add_subdirectory(Keymap) diff --git a/Userland/Applets/Keymap/CMakeLists.txt b/Userland/Applets/Keymap/CMakeLists.txt new file mode 100644 index 0000000000..2092d2de68 --- /dev/null +++ b/Userland/Applets/Keymap/CMakeLists.txt @@ -0,0 +1,13 @@ +serenity_component( + Keymap.Applet + REQUIRED + TARGETS Keymap.Applet +) + +set(SOURCES + KeymapStatusWindow.cpp + main.cpp +) + +serenity_bin(Keymap.Applet) +target_link_libraries(Keymap.Applet LibGUI LibCore LibGfx LibMain LibKeyboard) diff --git a/Userland/Applets/Keymap/KeymapStatusWindow.cpp b/Userland/Applets/Keymap/KeymapStatusWindow.cpp new file mode 100644 index 0000000000..e8db0d0b0f --- /dev/null +++ b/Userland/Applets/Keymap/KeymapStatusWindow.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021, Timur Sultanov + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "KeymapStatusWindow.h" +#include +#include +#include + +KeymapStatusWindow::KeymapStatusWindow() +{ + set_window_type(GUI::WindowType::Applet); + set_has_alpha_channel(true); + m_label = &set_main_widget(); + + auto current_keymap = MUST(Keyboard::CharacterMap::fetch_system_map()); + auto current_keymap_name = current_keymap.character_map_name(); + m_label->set_tooltip(current_keymap_name); + m_label->set_text(current_keymap_name.substring(0, 2)); +} + +KeymapStatusWindow::~KeymapStatusWindow() +{ +} + +void KeymapStatusWindow::wm_event(GUI::WMEvent& event) +{ + if (event.type() == GUI::WMEvent::WM_KeymapChanged) { + auto& keymap_event = static_cast(event); + auto keymap = keymap_event.keymap(); + set_keymap_text(keymap); + } +} + +void KeymapStatusWindow::set_keymap_text(const String& keymap) +{ + GUI::Painter painter(*m_label); + painter.clear_rect(m_label->rect(), Color::from_rgba(0)); + + m_label->set_tooltip(keymap); + m_label->set_text(keymap.substring(0, 2)); +} diff --git a/Userland/Applets/Keymap/KeymapStatusWindow.h b/Userland/Applets/Keymap/KeymapStatusWindow.h new file mode 100644 index 0000000000..8f460c1026 --- /dev/null +++ b/Userland/Applets/Keymap/KeymapStatusWindow.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021, Timur Sultanov + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +class KeymapStatusWidget; + +class KeymapStatusWindow final : public GUI::Window { + C_OBJECT(KeymapStatusWindow) +public: + virtual ~KeymapStatusWindow() override; + +private: + void wm_event(GUI::WMEvent&) override; + + KeymapStatusWindow(); + + RefPtr m_label; + + void set_keymap_text(String const& keymap); +}; diff --git a/Userland/Applets/Keymap/main.cpp b/Userland/Applets/Keymap/main.cpp new file mode 100644 index 0000000000..0dc68e811d --- /dev/null +++ b/Userland/Applets/Keymap/main.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021, Timur Sultanov + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "KeymapStatusWindow.h" +#include +#include +#include +#include +#include + +ErrorOr serenity_main(Main::Arguments arguments) +{ + TRY(Core::System::pledge("stdio recvfd sendfd rpath unix getkeymap")); + + auto app = TRY(GUI::Application::try_create(arguments)); + + auto window = TRY(KeymapStatusWindow::try_create()); + window->set_has_alpha_channel(true); + window->set_title("Keymap"); + window->resize(16, 16); + window->show(); + window->make_window_manager(WindowServer::WMEventMask::KeymapChanged); + + TRY(Core::System::pledge("stdio recvfd sendfd rpath getkeymap")); + + return app->exec(); +} diff --git a/Userland/Libraries/LibGUI/Event.h b/Userland/Libraries/LibGUI/Event.h index 517650493e..b386858195 100644 --- a/Userland/Libraries/LibGUI/Event.h +++ b/Userland/Libraries/LibGUI/Event.h @@ -67,6 +67,7 @@ public: WM_SuperKeyPressed, WM_SuperSpaceKeyPressed, WM_WorkspaceChanged, + WM_KeymapChanged, __End_WM_Events, }; @@ -228,6 +229,20 @@ private: const unsigned m_current_column; }; +class WMKeymapChangedEvent : public WMEvent { +public: + explicit WMKeymapChangedEvent(int client_id, String const& keymap) + : WMEvent(Event::Type::WM_KeymapChanged, client_id, 0) + , m_keymap(keymap) + { + } + + String const& keymap() const { return m_keymap; } + +private: + const String m_keymap; +}; + class MultiPaintEvent final : public Event { public: explicit MultiPaintEvent(Vector rects, Gfx::IntSize const& window_size) diff --git a/Userland/Libraries/LibGUI/WindowManagerServerConnection.cpp b/Userland/Libraries/LibGUI/WindowManagerServerConnection.cpp index 8b68978cb1..9d894ab43b 100644 --- a/Userland/Libraries/LibGUI/WindowManagerServerConnection.cpp +++ b/Userland/Libraries/LibGUI/WindowManagerServerConnection.cpp @@ -70,4 +70,10 @@ void WindowManagerServerConnection::workspace_changed(i32 wm_id, u32 row, u32 co Core::EventLoop::current().post_event(*window, make(wm_id, row, column)); } +void WindowManagerServerConnection::keymap_changed(i32 wm_id, String const& keymap) +{ + if (auto* window = Window::from_window_id(wm_id)) + Core::EventLoop::current().post_event(*window, make(wm_id, keymap)); +} + } diff --git a/Userland/Libraries/LibGUI/WindowManagerServerConnection.h b/Userland/Libraries/LibGUI/WindowManagerServerConnection.h index f4f2750bf8..78c2e4ce3e 100644 --- a/Userland/Libraries/LibGUI/WindowManagerServerConnection.h +++ b/Userland/Libraries/LibGUI/WindowManagerServerConnection.h @@ -35,6 +35,7 @@ private: virtual void super_key_pressed(i32) override; virtual void super_space_key_pressed(i32) override; virtual void workspace_changed(i32, u32, u32) override; + virtual void keymap_changed(i32, String const&) override; }; } diff --git a/Userland/Services/WindowServer/KeymapSwitcher.cpp b/Userland/Services/WindowServer/KeymapSwitcher.cpp index e34fdb3e0c..f35543d8f7 100644 --- a/Userland/Services/WindowServer/KeymapSwitcher.cpp +++ b/Userland/Services/WindowServer/KeymapSwitcher.cpp @@ -12,17 +12,8 @@ namespace WindowServer { -static KeymapSwitcher* s_the; - -KeymapSwitcher& KeymapSwitcher::the() -{ - VERIFY(s_the); - return *s_the; -} - KeymapSwitcher::KeymapSwitcher() { - s_the = this; } KeymapSwitcher::~KeymapSwitcher() @@ -80,10 +71,7 @@ String KeymapSwitcher::get_current_keymap() const auto json = JsonValue::from_string(proc_keymap->read_all()).release_value_but_fixme_should_propagate_errors(); auto const& keymap_object = json.as_object(); VERIFY(keymap_object.has("keymap")); - auto keymap = keymap_object.get("keymap").to_string(); - dbgln("Current keymap is: {}", keymap); - - return keymap; + return keymap_object.get("keymap").to_string(); } void KeymapSwitcher::setkeymap(const AK::String& keymap) @@ -94,6 +82,8 @@ void KeymapSwitcher::setkeymap(const AK::String& keymap) perror("posix_spawn"); dbgln("Failed to call /bin/keymap, error: {} ({})", errno, strerror(errno)); } + if (on_keymap_change) + on_keymap_change(keymap); } } diff --git a/Userland/Services/WindowServer/KeymapSwitcher.h b/Userland/Services/WindowServer/KeymapSwitcher.h index c9f6a0b77c..04dfb09b61 100644 --- a/Userland/Services/WindowServer/KeymapSwitcher.h +++ b/Userland/Services/WindowServer/KeymapSwitcher.h @@ -11,27 +11,29 @@ #include #include #include +#include namespace WindowServer { class KeymapSwitcher final : public Core::Object { C_OBJECT(KeymapSwitcher) public: - static KeymapSwitcher& the(); - virtual ~KeymapSwitcher() override; void refresh(); void next_keymap(); + Function on_keymap_change; + + String get_current_keymap() const; + private: KeymapSwitcher(); Vector m_keymaps; void setkeymap(AK::String const&); - String get_current_keymap() const; }; } diff --git a/Userland/Services/WindowServer/Window.h b/Userland/Services/WindowServer/Window.h index 11348b23cd..3dfbfaa1ef 100644 --- a/Userland/Services/WindowServer/Window.h +++ b/Userland/Services/WindowServer/Window.h @@ -36,6 +36,7 @@ enum WMEventMask { WindowIconChanges = 1 << 2, WindowRemovals = 1 << 3, WorkspaceChanges = 1 << 4, + KeymapChanged = 1 << 5, }; enum class WindowTileType { diff --git a/Userland/Services/WindowServer/WindowManager.cpp b/Userland/Services/WindowServer/WindowManager.cpp index b9b8db61fc..084c6465f0 100644 --- a/Userland/Services/WindowServer/WindowManager.cpp +++ b/Userland/Services/WindowServer/WindowManager.cpp @@ -53,6 +53,18 @@ WindowManager::WindowManager(Gfx::PaletteImpl const& palette) reload_config(); + m_keymap_switcher->on_keymap_change = [&](String const& keymap) { + for_each_window_manager([&keymap](WMClientConnection& conn) { + if (!(conn.event_mask() & WMEventMask::KeymapChanged)) + return IterationDecision::Continue; + if (conn.window_id() < 0) + return IterationDecision::Continue; + + conn.async_keymap_changed(conn.window_id(), keymap); + return IterationDecision::Continue; + }); + }; + Compositor::the().did_construct_window_manager({}); } diff --git a/Userland/Services/WindowServer/WindowManagerClient.ipc b/Userland/Services/WindowServer/WindowManagerClient.ipc index d422085eed..d22a934e79 100644 --- a/Userland/Services/WindowServer/WindowManagerClient.ipc +++ b/Userland/Services/WindowServer/WindowManagerClient.ipc @@ -10,4 +10,5 @@ endpoint WindowManagerClient super_key_pressed(i32 wm_id) =| super_space_key_pressed(i32 wm_id) =| workspace_changed(i32 wm_id, u32 row, u32 column) =| + keymap_changed(i32 wm_id, [UTF8] String keymap) =| }