Selaa lähdekoodia

WindowServer+Keymap+LibGUI: Add widget to display current keymap

Timur Sultanov 3 vuotta sitten
vanhempi
commit
b9c558f6c6

+ 1 - 1
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

+ 1 - 0
Userland/Applets/CMakeLists.txt

@@ -3,3 +3,4 @@ add_subdirectory(ClipboardHistory)
 add_subdirectory(Network)
 add_subdirectory(ResourceGraph)
 add_subdirectory(WorkspacePicker)
+add_subdirectory(Keymap)

+ 13 - 0
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)

+ 44 - 0
Userland/Applets/Keymap/KeymapStatusWindow.cpp

@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2021, Timur Sultanov <SultanovTS@yandex.ru>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "KeymapStatusWindow.h"
+#include <LibGUI/Painter.h>
+#include <LibGUI/WindowManagerServerConnection.h>
+#include <LibKeyboard/CharacterMap.h>
+
+KeymapStatusWindow::KeymapStatusWindow()
+{
+    set_window_type(GUI::WindowType::Applet);
+    set_has_alpha_channel(true);
+    m_label = &set_main_widget<GUI::Label>();
+
+    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<GUI::WMKeymapChangedEvent&>(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));
+}

+ 27 - 0
Userland/Applets/Keymap/KeymapStatusWindow.h

@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2021, Timur Sultanov <SultanovTS@yandex.ru>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibGUI/Label.h>
+#include <LibGUI/Window.h>
+
+class KeymapStatusWidget;
+
+class KeymapStatusWindow final : public GUI::Window {
+    C_OBJECT(KeymapStatusWindow)
+public:
+    virtual ~KeymapStatusWindow() override;
+
+private:
+    void wm_event(GUI::WMEvent&) override;
+
+    KeymapStatusWindow();
+
+    RefPtr<GUI::Label> m_label;
+
+    void set_keymap_text(String const& keymap);
+};

+ 30 - 0
Userland/Applets/Keymap/main.cpp

@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2021, Timur Sultanov <SultanovTS@yandex.ru>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "KeymapStatusWindow.h"
+#include <LibCore/System.h>
+#include <LibGUI/Application.h>
+#include <LibGUI/WindowManagerServerConnection.h>
+#include <LibMain/Main.h>
+#include <WindowServer/Window.h>
+
+ErrorOr<int> 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();
+}

+ 15 - 0
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<Gfx::IntRect, 32> rects, Gfx::IntSize const& window_size)

+ 6 - 0
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<WMWorkspaceChangedEvent>(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<WMKeymapChangedEvent>(wm_id, keymap));
+}
+
 }

+ 1 - 0
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;
 };
 
 }

+ 3 - 13
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);
 }
 
 }

+ 5 - 3
Userland/Services/WindowServer/KeymapSwitcher.h

@@ -11,27 +11,29 @@
 #include <AK/WeakPtr.h>
 #include <LibCore/Object.h>
 #include <LibKeyboard/CharacterMap.h>
+#include <WindowServer/WMClientConnection.h>
 
 namespace WindowServer {
 
 class KeymapSwitcher final : public Core::Object {
     C_OBJECT(KeymapSwitcher)
 public:
-    static KeymapSwitcher& the();
-
     virtual ~KeymapSwitcher() override;
 
     void refresh();
 
     void next_keymap();
 
+    Function<void(String const& keymap)> on_keymap_change;
+
+    String get_current_keymap() const;
+
 private:
     KeymapSwitcher();
 
     Vector<AK::String> m_keymaps;
 
     void setkeymap(AK::String const&);
-    String get_current_keymap() const;
 };
 
 }

+ 1 - 0
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 {

+ 12 - 0
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({});
 }
 

+ 1 - 0
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) =|
 }