From 7d7344a983878749c85bedd3b15a7a5ef6ab38b3 Mon Sep 17 00:00:00 2001 From: Jin Liu Date: Wed, 28 Feb 2024 11:23:21 +0000 Subject: [PATCH] plugins: add a "hidecursor" effect This hides the mouse cursor on inactivity or keypress (configurable in the KCM). BUG: 465119 --- src/plugins/CMakeLists.txt | 1 + src/plugins/hidecursor/CMakeLists.txt | 34 ++++++ src/plugins/hidecursor/hidecursor.cpp | 107 ++++++++++++++++++ src/plugins/hidecursor/hidecursor.h | 47 ++++++++ src/plugins/hidecursor/hidecursor_config.cpp | 43 +++++++ src/plugins/hidecursor/hidecursor_config.h | 30 +++++ src/plugins/hidecursor/hidecursor_config.ui | 31 +++++ src/plugins/hidecursor/hidecursorconfig.kcfg | 15 +++ src/plugins/hidecursor/hidecursorconfig.kcfgc | 8 ++ src/plugins/hidecursor/main.cpp | 18 +++ src/plugins/hidecursor/metadata.json | 10 ++ 11 files changed, 344 insertions(+) create mode 100644 src/plugins/hidecursor/CMakeLists.txt create mode 100644 src/plugins/hidecursor/hidecursor.cpp create mode 100644 src/plugins/hidecursor/hidecursor.h create mode 100644 src/plugins/hidecursor/hidecursor_config.cpp create mode 100644 src/plugins/hidecursor/hidecursor_config.h create mode 100644 src/plugins/hidecursor/hidecursor_config.ui create mode 100644 src/plugins/hidecursor/hidecursorconfig.kcfg create mode 100644 src/plugins/hidecursor/hidecursorconfig.kcfgc create mode 100644 src/plugins/hidecursor/main.cpp create mode 100644 src/plugins/hidecursor/metadata.json diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 05e0ad3a6c..0a8de26c15 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -66,6 +66,7 @@ add_subdirectory(fallapart) add_subdirectory(frozenapp) add_subdirectory(fullscreen) add_subdirectory(glide) +add_subdirectory(hidecursor) add_subdirectory(highlightwindow) add_subdirectory(idletime) add_subdirectory(invert) diff --git a/src/plugins/hidecursor/CMakeLists.txt b/src/plugins/hidecursor/CMakeLists.txt new file mode 100644 index 0000000000..cf5747c109 --- /dev/null +++ b/src/plugins/hidecursor/CMakeLists.txt @@ -0,0 +1,34 @@ +kwin_add_builtin_effect(hidecursor) + +target_sources(hidecursor PRIVATE + hidecursor.cpp + main.cpp +) + +kconfig_add_kcfg_files(hidecursor + hidecursorconfig.kcfgc +) + +target_link_libraries(hidecursor PRIVATE + kwin + + KF6::ConfigGui +) + +####################################### +# Config +if (KWIN_BUILD_KCMS) + set(kwin_hidecursor_config_SRCS hidecursor_config.cpp) + ki18n_wrap_ui(kwin_hidecursor_config_SRCS hidecursor_config.ui) + kconfig_add_kcfg_files(kwin_hidecursor_config_SRCS hidecursorconfig.kcfgc) + + kwin_add_effect_config(kwin_hidecursor_config ${kwin_hidecursor_config_SRCS}) + + target_link_libraries(kwin_hidecursor_config + KF6::KCMUtils + KF6::CoreAddons + KF6::I18n + KF6::XmlGui + KWinEffectsInterface + ) +endif() diff --git a/src/plugins/hidecursor/hidecursor.cpp b/src/plugins/hidecursor/hidecursor.cpp new file mode 100644 index 0000000000..44179588fc --- /dev/null +++ b/src/plugins/hidecursor/hidecursor.cpp @@ -0,0 +1,107 @@ +/* + SPDX-FileCopyrightText: 2024 Jin Liu + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "hidecursor.h" +#include "cursor.h" +#include "effect/effecthandler.h" +#include "hidecursorconfig.h" +#include "input_event.h" + +namespace KWin +{ + +HideCursorEffect::HideCursorEffect() + : m_cursor(Cursors::self()->mouse()) +{ + input()->installInputEventSpy(this); + + m_inactivityTimer.setSingleShot(true); + connect(&m_inactivityTimer, &QTimer::timeout, this, [this]() { + hideCursor(); + }); + + HideCursorConfig::instance(effects->config()); + reconfigure(ReconfigureAll); +} + +HideCursorEffect::~HideCursorEffect() +{ + showCursor(); +} + +bool HideCursorEffect::supported() +{ + return effects->waylandDisplay(); +} + +void HideCursorEffect::reconfigure(ReconfigureFlags flags) +{ + HideCursorConfig::self()->read(); + m_inactivityDuration = HideCursorConfig::inactivityDuration() * 1000; + m_hideOnTyping = HideCursorConfig::hideOnTyping(); + + m_inactivityTimer.stop(); + showCursor(); + if (m_inactivityDuration > 0) { + m_inactivityTimer.start(m_inactivityDuration); + } +} + +bool HideCursorEffect::isActive() const +{ + return false; +} + +void HideCursorEffect::pointerEvent(MouseEvent *event) +{ + showCursor(); + if (m_inactivityDuration > 0) { + m_inactivityTimer.start(m_inactivityDuration); + } +} + +void HideCursorEffect::keyEvent(KeyEvent *event) +{ + if (m_hideOnTyping && event->type() == QEvent::KeyPress) { + auto key = event->key(); + switch (key) { + case Qt::Key_Shift: + case Qt::Key_Control: + case Qt::Key_Meta: + case Qt::Key_Alt: + case Qt::Key_AltGr: + case Qt::Key_Super_L: + case Qt::Key_Super_R: + case Qt::Key_Hyper_L: + case Qt::Key_Hyper_R: + case Qt::Key_Escape: + break; + + default: + hideCursor(); + } + } +} + +void HideCursorEffect::showCursor() +{ + if (m_cursorHidden) { + effects->showCursor(); + m_cursorHidden = false; + } +} + +void HideCursorEffect::hideCursor() +{ + if (!m_cursorHidden) { + effects->hideCursor(); + m_cursorHidden = true; + } +} + +} // namespace KWin + +#include "moc_hidecursor.cpp" diff --git a/src/plugins/hidecursor/hidecursor.h b/src/plugins/hidecursor/hidecursor.h new file mode 100644 index 0000000000..90b8cb2cf0 --- /dev/null +++ b/src/plugins/hidecursor/hidecursor.h @@ -0,0 +1,47 @@ +/* + SPDX-FileCopyrightText: 2024 Jin Liu + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +#include "effect/effect.h" +#include "input_event_spy.h" + +#include + +namespace KWin +{ + +class Cursor; + +class HideCursorEffect : public Effect, public InputEventSpy +{ + Q_OBJECT + +public: + HideCursorEffect(); + ~HideCursorEffect() override; + + static bool supported(); + + void reconfigure(ReconfigureFlags flags) override; + bool isActive() const override; + + void pointerEvent(MouseEvent *event) override; + void keyEvent(KeyEvent *event) override; + +private: + void showCursor(); + void hideCursor(); + + int m_inactivityDuration; + bool m_hideOnTyping; + + Cursor *m_cursor; + bool m_cursorHidden = false; + QTimer m_inactivityTimer; +}; + +} // namespace KWin diff --git a/src/plugins/hidecursor/hidecursor_config.cpp b/src/plugins/hidecursor/hidecursor_config.cpp new file mode 100644 index 0000000000..44f899a73a --- /dev/null +++ b/src/plugins/hidecursor/hidecursor_config.cpp @@ -0,0 +1,43 @@ +/* + SPDX-FileCopyrightText: 2024 Jin Liu + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#include "hidecursor_config.h" + +#include + +// KConfigSkeleton +#include "hidecursorconfig.h" + +#include +#include + +K_PLUGIN_CLASS(KWin::HideCursorEffectConfig) + +namespace KWin +{ + +HideCursorEffectConfig::HideCursorEffectConfig(QObject *parent, const KPluginMetaData &data) + : KCModule(parent, data) +{ + HideCursorConfig::instance(KWIN_CONFIG); + m_ui.setupUi(widget()); + + addConfig(HideCursorConfig::self(), widget()); +} + +void HideCursorEffectConfig::save() +{ + KCModule::save(); + OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), + QStringLiteral("/Effects"), + QDBusConnection::sessionBus()); + interface.reconfigureEffect(QStringLiteral("hidecursor")); +} + +} // namespace + +#include "hidecursor_config.moc" + +#include "moc_hidecursor_config.cpp" diff --git a/src/plugins/hidecursor/hidecursor_config.h b/src/plugins/hidecursor/hidecursor_config.h new file mode 100644 index 0000000000..d6597e339f --- /dev/null +++ b/src/plugins/hidecursor/hidecursor_config.h @@ -0,0 +1,30 @@ +/* + SPDX-FileCopyrightText: 2024 Jin Liu + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +#include + +#include "ui_hidecursor_config.h" + +class KActionCollection; + +namespace KWin +{ +class HideCursorEffectConfig : public KCModule +{ + Q_OBJECT +public: + explicit HideCursorEffectConfig(QObject *parent, const KPluginMetaData &data); + +public Q_SLOTS: + void save() override; + +private: + Ui::HideCursorEffectConfig m_ui; +}; + +} // namespace diff --git a/src/plugins/hidecursor/hidecursor_config.ui b/src/plugins/hidecursor/hidecursor_config.ui new file mode 100644 index 0000000000..ec89600424 --- /dev/null +++ b/src/plugins/hidecursor/hidecursor_config.ui @@ -0,0 +1,31 @@ + + + HideCursorEffectConfig + + + + + + Inactivity duration (seconds): + + + + + + + 1 + + + + + + + Hide cursor on typing + + + + + + + + diff --git a/src/plugins/hidecursor/hidecursorconfig.kcfg b/src/plugins/hidecursor/hidecursorconfig.kcfg new file mode 100644 index 0000000000..fdd75ca72c --- /dev/null +++ b/src/plugins/hidecursor/hidecursorconfig.kcfg @@ -0,0 +1,15 @@ + + + + + + 5 + + + false + + + diff --git a/src/plugins/hidecursor/hidecursorconfig.kcfgc b/src/plugins/hidecursor/hidecursorconfig.kcfgc new file mode 100644 index 0000000000..d18632335b --- /dev/null +++ b/src/plugins/hidecursor/hidecursorconfig.kcfgc @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: 2024 Jin Liu +# +# SPDX-License-Identifier: GPL-2.0-or-later + +File=hidecursorconfig.kcfg +ClassName=HideCursorConfig +NameSpace=KWin +Singleton=true diff --git a/src/plugins/hidecursor/main.cpp b/src/plugins/hidecursor/main.cpp new file mode 100644 index 0000000000..8cde766336 --- /dev/null +++ b/src/plugins/hidecursor/main.cpp @@ -0,0 +1,18 @@ +/* + SPDX-FileCopyrightText: 2024 Jin Liu + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "hidecursor.h" + +namespace KWin +{ + +KWIN_EFFECT_FACTORY_SUPPORTED(HideCursorEffect, + "metadata.json.stripped", + return HideCursorEffect::supported();) + +} // namespace KWin + +#include "main.moc" diff --git a/src/plugins/hidecursor/metadata.json b/src/plugins/hidecursor/metadata.json new file mode 100644 index 0000000000..c6ad955dd2 --- /dev/null +++ b/src/plugins/hidecursor/metadata.json @@ -0,0 +1,10 @@ +{ + "KPlugin": { + "Category": "Accessibility", + "Description": "Hide mouse cursor on inactivity or keyboard input", + "EnabledByDefault": false, + "License": "GPL", + "Name": "Hide Cursor" + }, + "X-KDE-ConfigModule": "kwin_hidecursor_config" +}