diff --git a/applets/taskmanager/CMakeLists.txt b/applets/taskmanager/CMakeLists.txt --- a/applets/taskmanager/CMakeLists.txt +++ b/applets/taskmanager/CMakeLists.txt @@ -6,6 +6,8 @@ plugin/backend.cpp plugin/draghelper.cpp plugin/taskmanagerplugin.cpp + plugin/globalshortcuts.cpp + plugin/globalshortcutsbackend.cpp plugin/smartlaunchers/smartlauncherbackend.cpp plugin/smartlaunchers/smartlauncheritem.cpp @@ -23,6 +25,7 @@ Qt5::Quick KF5::Activities KF5::ActivitiesStats + KF5::GlobalAccel KF5::I18n KF5::KIOCore KF5::KIOWidgets diff --git a/applets/taskmanager/package/contents/code/tools.js b/applets/taskmanager/package/contents/code/tools.js --- a/applets/taskmanager/package/contents/code/tools.js +++ b/applets/taskmanager/package/contents/code/tools.js @@ -85,7 +85,7 @@ tasksModel.requestActivate(target); } -function activateTask(index, model, modifiers) { +function activateTask(index, model, modifiers, task) { if (modifiers & Qt.ShiftModifier) { tasksModel.requestNewInstance(index); } else if (model.IsGroupParent === true) { diff --git a/applets/taskmanager/package/contents/config/main.xml b/applets/taskmanager/package/contents/config/main.xml --- a/applets/taskmanager/package/contents/config/main.xml +++ b/applets/taskmanager/package/contents/config/main.xml @@ -70,6 +70,14 @@ true + + + + + + + 0 + diff --git a/applets/taskmanager/package/contents/ui/ConfigGeneral.qml b/applets/taskmanager/package/contents/ui/ConfigGeneral.qml --- a/applets/taskmanager/package/contents/ui/ConfigGeneral.qml +++ b/applets/taskmanager/package/contents/ui/ConfigGeneral.qml @@ -23,6 +23,8 @@ import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.private.taskmanager 0.1 as TaskManagerApplet + Item { width: childrenRect.width height: childrenRect.height @@ -34,6 +36,7 @@ property alias cfg_wheelEnabled: wheelEnabled.checked property alias cfg_highlightWindows: highlightWindows.checked property alias cfg_smartLaunchersEnabled: smartLaunchers.checked + property int cfg_globalShortcuts property alias cfg_maxStripes: maxStripes.value property alias cfg_groupingStrategy: groupingStrategy.currentIndex property alias cfg_middleClickAction: middleClickAction.currentIndex @@ -46,6 +49,19 @@ property alias cfg_showOnlyCurrentActivity: showOnlyCurrentActivity.checked property alias cfg_showOnlyMinimized: showOnlyMinimized.checked + function saveConfig() { + if (cfg_globalShortcuts === TaskManagerApplet.GlobalShortcuts.Enabled) { + globalShortcuts.makeOwner(); + } else if (cfg_globalShortcuts === TaskManagerApplet.GlobalShortcuts.Disabled) { + globalShortcuts.clearOwner(); + } + } + + TaskManagerApplet.GlobalShortcuts { + id: globalShortcuts + appletId: plasmoid.id + } + ColumnLayout { GroupBox { Layout.fillWidth: true @@ -106,6 +122,20 @@ text: i18n("Show progress and status information in task buttons") } + Label { + Layout.fillWidth: true + text: i18n("Global shortcuts only work with one Task Manager applet at a time.") + visible: globalShortcuts.taskManagerAppletsCount > 1 + } + + CheckBox { + id: globalShortcutsCheckBox + Layout.fillWidth: true + text: i18n("Activate tasks using Meta + number shortcuts") + checked: cfg_globalShortcuts === TaskManagerApplet.GlobalShortcuts.Enabled + onCheckedChanged: cfg_globalShortcuts = TaskManagerApplet.GlobalShortcuts[checked ? "Enabled" : "Disabled"] + } + RowLayout { Label { text: i18n("On middle-click:") diff --git a/applets/taskmanager/package/contents/ui/Task.qml b/applets/taskmanager/package/contents/ui/Task.qml --- a/applets/taskmanager/package/contents/ui/Task.qml +++ b/applets/taskmanager/package/contents/ui/Task.qml @@ -111,7 +111,7 @@ tasksModel.requestToggleMinimized(modelIndex()); } } else if (mouse.button == Qt.LeftButton) { - TaskTools.activateTask(modelIndex(), model, mouse.modifiers); + TaskTools.activateTask(modelIndex(), model, mouse.modifiers, task); } } @@ -153,7 +153,7 @@ } } - Keys.onReturnPressed: TaskTools.activateTask(modelIndex(), model, event.modifiers) + Keys.onReturnPressed: TaskTools.activateTask(modelIndex(), model, event.modifiers, task) Keys.onEnterPressed: Keys.onReturnPressed(event); function modelIndex() { diff --git a/applets/taskmanager/package/contents/ui/main.qml b/applets/taskmanager/package/contents/ui/main.qml --- a/applets/taskmanager/package/contents/ui/main.qml +++ b/applets/taskmanager/package/contents/ui/main.qml @@ -340,11 +340,35 @@ dragSource = null; } + function createContextMenu(task) { + return tasks.contextMenuComponent.createObject(task, { + visualParent: task, + mpris2Source: mpris2Source + }); + } + Component.onCompleted: { tasks.requestLayout.connect(layoutTimer.restart); tasks.requestLayout.connect(iconGeometryTimer.restart); tasks.windowsHovered.connect(backend.windowsHovered); tasks.presentWindows.connect(backend.presentWindows); dragHelper.dropped.connect(resetDragSource); + + globalShortcuts.registerApplet(); + + // If set to EnableWhenIsOwner (the default) and no other applet is there yet, enabled global shortcuts. + if (plasmoid.configuration.globalShortcuts === TaskManagerApplet.GlobalShortcuts.Enabled + || (globalShortcuts.taskManagerAppletsCount === 1 && plasmoid.configuration.globalShortcuts === TaskManagerApplet.GlobalShortcuts.EnableWhenIsOwner)) { + + globalShortcuts.makeOwner(); + + plasmoid.configuration.globalShortcuts = TaskManagerApplet.GlobalShortcuts.Enabled; + } else { + plasmoid.configuration.globalShortcuts = TaskManagerApplet.GlobalShortcuts.Disabled; + } + } + + Component.onDestruction: { + globalShortcuts.unregisterApplet(); } } diff --git a/applets/taskmanager/plugin/globalshortcuts.h b/applets/taskmanager/plugin/globalshortcuts.h new file mode 100644 --- /dev/null +++ b/applets/taskmanager/plugin/globalshortcuts.h @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2016 Kai Uwe Broulik * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +#pragma once + +#include +#include +#include + +#include "globalshortcutsbackend.h" + +class GlobalShortcuts : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString appletId READ appletId WRITE setAppletId NOTIFY appletIdChanged) + + Q_PROPERTY(bool isOwner READ isOwner NOTIFY isOwnerChanged) + Q_PROPERTY(int taskManagerAppletsCount READ taskManagerAppletsCount NOTIFY taskManagerAppletsCountChanged) + +public: + explicit GlobalShortcuts(QObject *parent = nullptr); + ~GlobalShortcuts() override = default; + + enum EnabledEnum { + EnableWhenIsOwner, + Disabled, + Enabled + }; + Q_ENUM(EnabledEnum) + + QString appletId() const; + void setAppletId(const QString &appletId); + + bool isOwner() const; + int taskManagerAppletsCount() const; + + Q_INVOKABLE void makeOwner(); + Q_INVOKABLE void clearOwner(); + + Q_INVOKABLE void registerApplet(); + Q_INVOKABLE void unregisterApplet(); + +signals: + void appletIdChanged(); + + void isOwnerChanged(); + void taskManagerAppletsCountChanged(); + + void activateItemAtIndex(int index); + +private: + static QWeakPointer s_backend; + + QSharedPointer m_backendPtr; + + QString m_appletId; + +}; diff --git a/applets/taskmanager/plugin/globalshortcuts.cpp b/applets/taskmanager/plugin/globalshortcuts.cpp new file mode 100644 --- /dev/null +++ b/applets/taskmanager/plugin/globalshortcuts.cpp @@ -0,0 +1,98 @@ +/*************************************************************************** + * Copyright (C) 2016 Kai Uwe Broulik * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +#include "globalshortcuts.h" + +#include + +GlobalShortcuts::GlobalShortcuts(QObject *parent) : QObject(parent) +{ + m_backendPtr = s_backend.toStrongRef(); + if (!m_backendPtr) { + QSharedPointer backendSharedPtr(new GlobalShortcutsBackend); + s_backend = backendSharedPtr; + m_backendPtr = s_backend.toStrongRef(); + } + + connect(m_backendPtr.data(), &GlobalShortcutsBackend::taskManagerAppletsCountChanged, + this, &GlobalShortcuts::taskManagerAppletsCountChanged); + connect(m_backendPtr.data(), &GlobalShortcutsBackend::ownerChanged, + this, &GlobalShortcuts::isOwnerChanged); + + connect(m_backendPtr.data(), &GlobalShortcutsBackend::activated, this, [this](int index) { + if (m_backendPtr->owner() == m_appletId) { + emit activateItemAtIndex(index); + } + }); +} + +QWeakPointer GlobalShortcuts::s_backend; + +QString GlobalShortcuts::appletId() const +{ + return m_appletId; +} + +void GlobalShortcuts::setAppletId(const QString &appletId) +{ + if (m_appletId != appletId) { + const bool wasOwner = isOwner(); + + m_appletId = appletId; + emit appletIdChanged(); + + if (wasOwner != isOwner()) { + isOwnerChanged(); + } + } +} + +bool GlobalShortcuts::isOwner() const +{ + const QString &owner = m_backendPtr->owner(); + return !m_appletId.isEmpty() && !owner.isEmpty() && owner == m_appletId; +} + +int GlobalShortcuts::taskManagerAppletsCount() const +{ + return m_backendPtr->taskManagerAppletsCount(); +} + +void GlobalShortcuts::makeOwner() +{ + Q_ASSERT(!m_appletId.isEmpty()); + m_backendPtr->makeOwner(m_appletId); +} + +void GlobalShortcuts::clearOwner() +{ + m_backendPtr->makeOwner(QString()); +} + +void GlobalShortcuts::registerApplet() +{ + Q_ASSERT(!m_appletId.isEmpty()); + m_backendPtr->registerApplet(m_appletId); +} + +void GlobalShortcuts::unregisterApplet() +{ + Q_ASSERT(!m_appletId.isEmpty()); + m_backendPtr->unregisterApplet(m_appletId); +} diff --git a/applets/taskmanager/plugin/globalshortcutsbackend.h b/applets/taskmanager/plugin/globalshortcutsbackend.h new file mode 100644 --- /dev/null +++ b/applets/taskmanager/plugin/globalshortcutsbackend.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2016 Kai Uwe Broulik * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +#pragma once + +#include +#include +#include + +class GlobalShortcutsBackend : public QObject +{ + Q_OBJECT + +public: + explicit GlobalShortcutsBackend(QObject *parent = nullptr); + ~GlobalShortcutsBackend() override = default; + + int taskManagerAppletsCount() const; + QString owner() const; + + void registerApplet(const QString &appletId); + void unregisterApplet(const QString &appletId); + + void makeOwner(const QString &appletId); + +signals: + int taskManagerAppletsCountChanged(); + void ownerChanged(); + + void activated(int index); + +private: + void initShortcuts(); + + QSet m_taskManagerAppletIds; + QString m_owner; + + bool m_initialized = false; + +}; diff --git a/applets/taskmanager/plugin/globalshortcutsbackend.cpp b/applets/taskmanager/plugin/globalshortcutsbackend.cpp new file mode 100644 --- /dev/null +++ b/applets/taskmanager/plugin/globalshortcutsbackend.cpp @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2016 Kai Uwe Broulik * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +#include "globalshortcutsbackend.h" + +#include + +#include +#include + +GlobalShortcutsBackend::GlobalShortcutsBackend(QObject *parent) : QObject(parent) +{ + +} + +int GlobalShortcutsBackend::taskManagerAppletsCount() const +{ + return m_taskManagerAppletIds.count(); +} + +QString GlobalShortcutsBackend::owner() const +{ + return m_owner; +} + +void GlobalShortcutsBackend::makeOwner(const QString &appletId) +{ + if (m_owner != appletId) { + m_owner = appletId; + + if (!m_owner.isEmpty()) { + initShortcuts(); + } + + emit ownerChanged(); + } +} + +void GlobalShortcutsBackend::registerApplet(const QString &appletId) +{ + m_taskManagerAppletIds.insert(appletId); + emit taskManagerAppletsCountChanged(); +} + +void GlobalShortcutsBackend::unregisterApplet(const QString &appletId) +{ + if (m_taskManagerAppletIds.remove(appletId)) { + emit taskManagerAppletsCountChanged(); + } +} + +void GlobalShortcutsBackend::initShortcuts() +{ + if (m_initialized) { + return; + } + + const QString componentName = QStringLiteral("taskmanager"); + const QString componentDisplayName = i18nc("Name for task manager global shortcuts category", "Task Manager"); + + for (int i = 0; i < 10; ++i) { + const int entryNumber = i + 1; + const Qt::Key key = static_cast(Qt::Key_0 + (entryNumber % 10)); + + QAction *action = new QAction(i18n("Launch Entry %1", entryNumber), this); + action->setObjectName(QStringLiteral("launch_%1").arg(QString::number(entryNumber))); + // Those properties are usually set by KActionCollection and read by KGlobalAccel. + action->setProperty("componentName", componentName); + action->setProperty("componentDisplayName", componentDisplayName); + KGlobalAccel::setGlobalShortcut(action, QKeySequence(Qt::META + key)); + connect(action, &QAction::triggered, this, [this, i] { + emit activated(i); + }); + } + + m_initialized = true; +} diff --git a/applets/taskmanager/plugin/taskmanagerplugin.cpp b/applets/taskmanager/plugin/taskmanagerplugin.cpp --- a/applets/taskmanager/plugin/taskmanagerplugin.cpp +++ b/applets/taskmanager/plugin/taskmanagerplugin.cpp @@ -38,6 +38,7 @@ #include "taskmanagerplugin.h" #include "backend.h" #include "draghelper.h" +#include "globalshortcuts.h" #include "smartlaunchers/smartlauncheritem.h" @@ -49,6 +50,7 @@ Q_ASSERT(uri == QLatin1String("org.kde.plasma.private.taskmanager")); qmlRegisterType(uri, 0, 1, "Backend"); qmlRegisterType(uri, 0, 1, "DragHelper"); + qmlRegisterType(uri, 0, 1, "GlobalShortcuts"); qmlRegisterType(uri, 0, 1, "SmartLauncherItem"); }