diff --git a/applets/CMakeLists.txt b/applets/CMakeLists.txt index c93043d84..0486c8430 100644 --- a/applets/CMakeLists.txt +++ b/applets/CMakeLists.txt @@ -5,4 +5,5 @@ add_subdirectory(dde-am) add_subdirectory(dde-appearance) add_subdirectory(dde-apps) +add_subdirectory(dde-key-notify) add_subdirectory(dde-shutdown) diff --git a/applets/dde-key-notify/CMakeLists.txt b/applets/dde-key-notify/CMakeLists.txt new file mode 100644 index 000000000..bf02afea6 --- /dev/null +++ b/applets/dde-key-notify/CMakeLists.txt @@ -0,0 +1,30 @@ +# SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +# +# SPDX-License-Identifier: GPL-3.0-or-later + +find_package(TreelandProtocols REQUIRED) + +set(TREELAND_KEYBOARD_STATE_NOTIFY_PROTOCOL + ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-keyboard-state-notify-unstable-v1.xml +) + +add_library(dde-key-notify SHARED + keynotifyapplet.cpp + keynotifyapplet.h + treelandkeynotify.cpp + treelandkeynotify.h +) + +qt_generate_wayland_protocol_client_sources(dde-key-notify + NO_INCLUDE_CORE_ONLY + FILES + ${TREELAND_KEYBOARD_STATE_NOTIFY_PROTOCOL} +) + +target_link_libraries(dde-key-notify PRIVATE + dde-shell-frame + Qt${QT_VERSION_MAJOR}::DBus + Qt${QT_VERSION_MAJOR}::WaylandClient +) + +ds_install_package(PACKAGE org.deepin.ds.dde-key-notify TARGET dde-key-notify) diff --git a/applets/dde-key-notify/keynotifyapplet.cpp b/applets/dde-key-notify/keynotifyapplet.cpp new file mode 100644 index 000000000..e069e4415 --- /dev/null +++ b/applets/dde-key-notify/keynotifyapplet.cpp @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "keynotifyapplet.h" + +#include "pluginfactory.h" +#include "treelandkeynotify.h" + +#include +#include + +DCORE_USE_NAMESPACE + +DS_BEGIN_NAMESPACE +namespace keynotify +{ + +KeyNotifyApplet::KeyNotifyApplet(QObject *parent) + : DApplet(parent) +{ +} + +KeyNotifyApplet::~KeyNotifyApplet() = default; + +bool KeyNotifyApplet::load() +{ + if (!Dtk::Gui::DGuiApplicationHelper::testAttribute(Dtk::Gui::DGuiApplicationHelper::IsWaylandPlatform)) { + return DApplet::load(); + } + + m_keyNotify = new TreelandKeyNotify(this); + connect(m_keyNotify, &TreelandKeyNotify::capsLockChanged, this, &KeyNotifyApplet::showCapsLockOsd); + connect(m_keyNotify, &TreelandKeyNotify::numLockChanged, this, &KeyNotifyApplet::showNumLockOsd); + initConfig(); + m_keyNotify->setCapsLockEnabled(m_config->value(QStringLiteral("capslockToggle")).toBool()); + return DApplet::load(); +} + +void KeyNotifyApplet::showCapsLockOsd(bool locked) +{ + sendOsd(locked ? QStringLiteral("CapsLockOn") : QStringLiteral("CapsLockOff")); +} + +void KeyNotifyApplet::showNumLockOsd(bool locked) +{ + sendOsd(locked ? QStringLiteral("NumLockOn") : QStringLiteral("NumLockOff")); +} + +void KeyNotifyApplet::updateCapsLockToggle(const QString &key) +{ + if (key != QStringLiteral("capslockToggle")) { + return; + } + + m_keyNotify->setCapsLockEnabled(m_config->value(key).toBool()); +} + +void KeyNotifyApplet::sendOsd(const QString &osdType) +{ + DDBusSender().service("org.deepin.dde.shell").path("/org/deepin/dde/shell/osd").interface("org.deepin.dde.shell.osd").method("ShowOSD").arg(osdType).call(); +} + +void KeyNotifyApplet::initConfig() +{ + m_config = Dtk::Core::DConfig::create(QStringLiteral("org.deepin.dde.daemon"), QStringLiteral("org.deepin.dde.daemon.keyboard"), QString(), this); + connect(m_config, &Dtk::Core::DConfig::valueChanged, this, &KeyNotifyApplet::updateCapsLockToggle); +} + +D_APPLET_CLASS(KeyNotifyApplet) + +} +DS_END_NAMESPACE + +#include "keynotifyapplet.moc" diff --git a/applets/dde-key-notify/keynotifyapplet.h b/applets/dde-key-notify/keynotifyapplet.h new file mode 100644 index 000000000..1f664e622 --- /dev/null +++ b/applets/dde-key-notify/keynotifyapplet.h @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "applet.h" + +#include + +#include + +DS_BEGIN_NAMESPACE +namespace keynotify +{ + +class TreelandKeyNotify; + +class KeyNotifyApplet : public DApplet +{ + Q_OBJECT + +public: + explicit KeyNotifyApplet(QObject *parent = nullptr); + ~KeyNotifyApplet() override; + + bool load() override; + +private Q_SLOTS: + void showCapsLockOsd(bool locked); + void showNumLockOsd(bool locked); + void updateCapsLockToggle(const QString &key); + +private: + void sendOsd(const QString &osdType); + void initConfig(); + +private: + QPointer m_keyNotify; + Dtk::Core::DConfig *m_config = nullptr; +}; + +} +DS_END_NAMESPACE diff --git a/applets/dde-key-notify/package/metadata.json b/applets/dde-key-notify/package/metadata.json new file mode 100644 index 000000000..5fd63c575 --- /dev/null +++ b/applets/dde-key-notify/package/metadata.json @@ -0,0 +1,7 @@ +{ + "Plugin": { + "Version": "1.0", + "Id": "org.deepin.ds.dde-key-notify", + "Category": "DDE" + } +} diff --git a/applets/dde-key-notify/treelandkeynotify.cpp b/applets/dde-key-notify/treelandkeynotify.cpp new file mode 100644 index 000000000..1fda99bb8 --- /dev/null +++ b/applets/dde-key-notify/treelandkeynotify.cpp @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "treelandkeynotify.h" + +#include "wayland-treeland-keyboard-state-notify-unstable-v1-client-protocol.h" + +DS_BEGIN_NAMESPACE +namespace keynotify +{ + +TreelandKeyNotify::TreelandKeyNotify(QObject *parent) + : QWaylandClientExtensionTemplate(treeland_keyboard_state_notify_manager_v1_interface.version) +{ + setParent(parent); + connect(this, &TreelandKeyNotify::activeChanged, this, &TreelandKeyNotify::updateWatcher); +} + +void TreelandKeyNotify::setCapsLockEnabled(bool enabled) +{ + if (m_capsLockEnabled == enabled) { + return; + } + + m_capsLockEnabled = enabled; + updateWatcher(); +} + +void TreelandKeyNotify::updateWatcher() +{ + if (!isActive()) { + if (m_watcher) { + m_watcher->deleteLater(); + m_watcher = nullptr; + } + return; + } + + if (!m_watcher) { + m_watcher = createWatcher(this); + if (!m_watcher) { + return; + } + + connect(m_watcher, &TreelandKeyWatcher::stateChanged, this, [this](uint32_t modifier, uint32_t state) { + if (modifier == TreelandKeyWatcher::modifier_caps_lock) { + if (state == TreelandKeyWatcher::modifier_state_locked) { + Q_EMIT capsLockChanged(true); + } else if (state == TreelandKeyWatcher::modifier_state_unlocked) { + Q_EMIT capsLockChanged(false); + } + } else if (modifier == TreelandKeyWatcher::modifier_num_lock) { + if (state == TreelandKeyWatcher::modifier_state_locked) { + Q_EMIT numLockChanged(true); + } else if (state == TreelandKeyWatcher::modifier_state_unlocked) { + Q_EMIT numLockChanged(false); + } + } + }); + } + + m_watcher->watchLocks(m_capsLockEnabled); +} + +TreelandKeyWatcher *TreelandKeyNotify::createWatcher(QObject *parent) +{ + if (!isActive()) { + return nullptr; + } + + auto *watcher = get_keyboard_state_watcher(nullptr); + if (!watcher) { + return nullptr; + } + + return new TreelandKeyWatcher(watcher, parent); +} + +TreelandKeyWatcher::TreelandKeyWatcher(struct ::treeland_keyboard_state_watcher_v1 *object, QObject *parent) + : QObject(parent) + , QtWayland::treeland_keyboard_state_watcher_v1(object) +{ +} + +void TreelandKeyWatcher::watchLocks(bool watchCapsLock) +{ + set_modifiers(watchCapsLock ? modifier_caps_lock | modifier_num_lock : modifier_num_lock); + set_flags(watch_flag_locked | watch_flag_unlocked); + apply(); +} + +void TreelandKeyWatcher::treeland_keyboard_state_watcher_v1_state_changed(uint32_t modifier, uint32_t state) +{ + Q_EMIT stateChanged(modifier, state); +} + +} +DS_END_NAMESPACE diff --git a/applets/dde-key-notify/treelandkeynotify.h b/applets/dde-key-notify/treelandkeynotify.h new file mode 100644 index 000000000..7ddd78fa7 --- /dev/null +++ b/applets/dde-key-notify/treelandkeynotify.h @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "dsglobal.h" +#include "qwayland-treeland-keyboard-state-notify-unstable-v1.h" + +#include +#include + +struct treeland_keyboard_state_watcher_v1; + +DS_BEGIN_NAMESPACE +namespace keynotify +{ + +class TreelandKeyWatcher; + +class TreelandKeyNotify : public QWaylandClientExtensionTemplate, public QtWayland::treeland_keyboard_state_notify_manager_v1 +{ + Q_OBJECT + +public: + explicit TreelandKeyNotify(QObject *parent = nullptr); + + void setCapsLockEnabled(bool enabled); + +Q_SIGNALS: + void capsLockChanged(bool locked); + void numLockChanged(bool locked); + +private Q_SLOTS: + void updateWatcher(); + +private: + TreelandKeyWatcher *createWatcher(QObject *parent = nullptr); + +private: + bool m_capsLockEnabled = false; + QPointer m_watcher; +}; + +class TreelandKeyWatcher : public QObject, public QtWayland::treeland_keyboard_state_watcher_v1 +{ + Q_OBJECT + +public: + explicit TreelandKeyWatcher(struct ::treeland_keyboard_state_watcher_v1 *object, QObject *parent = nullptr); + + void watchLocks(bool watchCapsLock); + +Q_SIGNALS: + void stateChanged(uint32_t modifier, uint32_t state); + +protected: + void treeland_keyboard_state_watcher_v1_state_changed(uint32_t modifier, uint32_t state) override; +}; + +} +DS_END_NAMESPACE diff --git a/debian/control b/debian/control index b98ab6b1c..80383de34 100644 --- a/debian/control +++ b/debian/control @@ -40,7 +40,7 @@ Build-Depends: qt6-wayland-dev-tools, qt6-wayland-private-dev, systemd, - treeland-protocols (>= 0.5.7), + treeland-protocols (>> 0.5.7), wayland-protocols, Standards-Version: 4.6.2 Homepage: https://github.com/linuxdeepin/dde-shell diff --git a/debian/dde-shell.install b/debian/dde-shell.install index 228149a31..c85ddeb6b 100644 --- a/debian/dde-shell.install +++ b/debian/dde-shell.install @@ -2,6 +2,7 @@ usr/bin/* usr/lib/*/dde-shell/org.deepin.ds.dde-am* usr/lib/*/dde-shell/org.deepin.ds.dde-appearance* usr/lib/*/dde-shell/org.deepin.ds.dde-apps* +usr/lib/*/dde-shell/org.deepin.ds.dde-key-notify* usr/lib/*/dde-shell/org.deepin.ds.dde-shutdown* usr/lib/*/dde-shell/org.deepin.ds.dock* usr/lib/*/dde-shell/org.deepin.ds.notification* @@ -19,6 +20,7 @@ usr/share/dde-shell/*/translations usr/share/dde-shell/org.deepin.ds.dde-am*/ usr/share/dde-shell/org.deepin.ds.dde-appearance*/ usr/share/dde-shell/org.deepin.ds.dde-apps*/ +usr/share/dde-shell/org.deepin.ds.dde-key-notify*/ usr/share/dde-shell/org.deepin.ds.dde-shutdown*/ usr/share/dde-shell/org.deepin.ds.dock*/ usr/share/dde-shell/org.deepin.ds.notification*/