diff --git a/.gitignore b/.gitignore index a938fac05e..c05815d8e4 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ cmake-build-debug* /compile_commands.json .clangd .cache +*.qmlls.ini diff --git a/kcms/gamecontroller/CMakeLists.txt b/kcms/gamecontroller/CMakeLists.txt index b8cbd3cef2..cfe9c32d86 100644 --- a/kcms/gamecontroller/CMakeLists.txt +++ b/kcms/gamecontroller/CMakeLists.txt @@ -44,5 +44,6 @@ target_link_libraries(kcm_gamecontroller PRIVATE Qt6::Quick Qt6::QuickWidgets SDL2::SDL2 + Qt::DBus UDev::UDev ) diff --git a/kcms/gamecontroller/kcm.cpp b/kcms/gamecontroller/kcm.cpp index 3208400a5d..56758b9987 100644 --- a/kcms/gamecontroller/kcm.cpp +++ b/kcms/gamecontroller/kcm.cpp @@ -2,13 +2,20 @@ SPDX-FileCopyrightText: 2023 Joshua Goins SPDX-FileCopyrightText: 2023 Jeremy Whiting SPDX-FileCopyrightText: 2023 Niccolò Venerandi + SPDX-FileCopyrightText: 2025 Yelsin Sepulveda + SPDX-FileCopyrightText: 2025 Jakob Petsovits SPDX-License-Identifier: GPL-2.0-or-later */ #include "kcm.h" +#include #include +#include +#include +#include +#include #include "axesmodel.h" #include "axesproxymodel.h" @@ -18,13 +25,16 @@ K_PLUGIN_CLASS_WITH_JSON(KCMGameController, "kcm_gamecontroller.json") +static const QString s_kwinPluginId = QStringLiteral("gamecontroller"); + KCMGameController::KCMGameController(QObject *parent, const KPluginMetaData &metaData) - : KQuickManagedConfigModule(parent, metaData) + : KQuickConfigModule(parent, metaData) { setButtons(Help); constexpr const char *uri{"org.kde.plasma.gamecontroller.kcm"}; + qmlRegisterUncreatableType(uri, 1, 0, "KCMGameController", QString()); qmlRegisterType(uri, 1, 0, "DeviceModel"); qmlRegisterType(uri, 1, 0, "AxesModel"); qmlRegisterType(uri, 1, 0, "AxesProxyModel"); @@ -36,6 +46,36 @@ KCMGameController::~KCMGameController() { } +bool KCMGameController::isPluginEnabled() const +{ + KConfigGroup plugins(KSharedConfig::openConfig("kwinrc"), QStringLiteral("Plugins")); + return plugins.readEntry(s_kwinPluginId + QStringLiteral("Enabled"), true); +} + +void KCMGameController::setPluginEnabled(bool enabled) +{ + KConfigGroup plugins(KSharedConfig::openConfig("kwinrc"), QStringLiteral("Plugins")); + plugins.writeEntry(s_kwinPluginId + QStringLiteral("Enabled"), enabled, KConfig::Notify); + plugins.sync(); + + QDBusMessage message; + if (enabled) { + message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KWin"), + QStringLiteral("/Plugins"), + QStringLiteral("org.kde.KWin.Plugins"), + QStringLiteral("LoadPlugin")); + message << s_kwinPluginId; + } else { + message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KWin"), + QStringLiteral("/Plugins"), + QStringLiteral("org.kde.KWin.Plugins"), + QStringLiteral("UnloadPlugin")); + message << s_kwinPluginId; + } + QDBusConnection::sessionBus().asyncCall(message); + Q_EMIT pluginEnabledChanged(); +} + #include "kcm.moc" #include "moc_kcm.cpp" diff --git a/kcms/gamecontroller/kcm.h b/kcms/gamecontroller/kcm.h index 110007a041..3082065d7e 100644 --- a/kcms/gamecontroller/kcm.h +++ b/kcms/gamecontroller/kcm.h @@ -2,19 +2,27 @@ SPDX-FileCopyrightText: 2023 Joshua Goins SPDX-FileCopyrightText: 2023 Jeremy Whiting SPDX-FileCopyrightText: 2023 Niccolò Venerandi + SPDX-FileCopyrightText: 2025 Yelsin Sepulveda SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once -#include +#include -class KCMGameController : public KQuickManagedConfigModule +class KCMGameController : public KQuickConfigModule { Q_OBJECT + Q_PROPERTY(bool pluginEnabled READ isPluginEnabled WRITE setPluginEnabled NOTIFY pluginEnabledChanged FINAL) public: KCMGameController(QObject *parent, const KPluginMetaData &metaData); ~KCMGameController() override; + + bool isPluginEnabled() const; + void setPluginEnabled(bool enabled); + +Q_SIGNALS: + void pluginEnabledChanged(); }; diff --git a/kcms/gamecontroller/ui/main.qml b/kcms/gamecontroller/ui/main.qml index b95720c971..dfff84d640 100644 --- a/kcms/gamecontroller/ui/main.qml +++ b/kcms/gamecontroller/ui/main.qml @@ -1,5 +1,7 @@ /* SPDX-FileCopyrightText: 2023 Joshua Goins + SPDX-FileCopyrightText: 2025 Yelsin Sepulveda + SPDX-FileCopyrightText: 2025 Jakob Petsovits SPDX-License-Identifier: GPL-2.0-or-later */ @@ -20,6 +22,30 @@ KCM.SimpleKCM { readonly property var deviceType: device?.type ?? "" readonly property var deviceControllerType: device?.controllerTypeName ?? "" readonly property var deviceConnectionType: device?.connectionType ?? "" + readonly property bool kwinPluginEnabled: KCM.ConfigModule.pluginEnabled + + actions: [ + Kirigami.Action { + displayComponent: RowLayout { + spacing: Kirigami.Units.smallSpacing + Layout.fillWidth: true + + QQC2.Switch { + id: plasmaIntegrationSwitch + text: i18nc("@option:check Allow using game controllers as a pointer and keyboard", "Allow using as pointer and keyboard") + checked: kwinPluginEnabled + + onToggled: { + KCM.ConfigModule.pluginEnabled = checked + } + } + + Kirigami.ContextualHelpButton { + toolTipText: xi18nc("@info:tooltip", "Allow game controllers to act like pointer and keyboard devices in Plasma and non-game applications.Games can always use the controller.") + } + } + } + ] Kirigami.PlaceholderMessage { icon.name: "input-gamepad" @@ -47,6 +73,16 @@ KCM.SimpleKCM { } } + headerPaddingEnabled: false // Let the InlineMessages touch the edges + header: Kirigami.InlineMessage { + Layout.fillWidth: true + visible: kwinPluginEnabled && deviceCombo.count !== 0 + type: Kirigami.MessageType.Warning + position: Kirigami.InlineMessage.Position.Header + showCloseButton: true + text: i18nc("@info:usagetip", "The system may automatically go to sleep or lock the screen while the controller is in use. Consider manually blocking them while using the controller, or enable automatic blocking by allowing the use as pointer and keyboard.") + } + ColumnLayout { anchors.fill: parent @@ -90,7 +126,7 @@ KCM.SimpleKCM { text: deviceType } } - + RowLayout { spacing: Kirigami.Units.largeSpacing @@ -122,6 +158,7 @@ KCM.SimpleKCM { text: deviceConnectionType } } + RowLayout { spacing: Kirigami.Units.largeSpacing @@ -201,5 +238,6 @@ KCM.SimpleKCM { } } } + Item { Layout.fillHeight: true } } }