[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [kglobalaccel] /: Launch jumplist actions via KGlobalAccel
From: Marco Martin <notmart () gmail ! com>
Date: 2016-08-04 12:58:41
Message-ID: E1bVIET-0001Es-Uj () code ! kde ! org
[Download RAW message or body]
Git commit e5fa5cbc4fa7ebb96a2ec7803e2963038e3bf1a6 by Marco Martin.
Committed on 04/08/2016 at 12:58.
Pushed by mart into branch 'master'.
Launch jumplist actions via KGlobalAccel
Summary:
make the kglobalaccel daemon capable of launching applications
from their desktop file or to launch a particular action defined by
their jumplist action entries in their desktop file
In order to be enabled by default, the application would have
to install a copy of its desktop file (which has extra X-KDE-Shortcuts entry)
in prefix/share/kglobalaccel
from the kcm side the user will be able to add shortcuts to launch any
app that has a desktop file (or any action defined by it) making
possible to drop khotkeys and its kcm
Reviewers: graesslin
Reviewed By: graesslin
Differential Revision: https://phabricator.kde.org/D2103
M +2 -0 CMakeLists.txt
M +3 -0 src/runtime/CMakeLists.txt
M +35 -27 src/runtime/component.cpp
M +14 -2 src/runtime/component.h
M +41 -12 src/runtime/globalshortcutsregistry.cpp
M +16 -7 src/runtime/kglobalacceld.cpp
A +109 -0 src/runtime/kserviceactioncomponent.cpp [License: LGPL (v2+)]
A +61 -0 src/runtime/kserviceactioncomponent.h [License: LGPL (v2+)]
http://commits.kde.org/kglobalaccel/e5fa5cbc4fa7ebb96a2ec7803e2963038e3bf1a6
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2816703..c30d4fc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -40,6 +40,8 @@ find_package(KF5CoreAddons ${KF5_DEP_VERSION} REQUIRED)
find_package(KF5Crash ${KF5_DEP_VERSION} REQUIRED)
find_package(KF5DBusAddons ${KF5_DEP_VERSION} REQUIRED)
find_package(KF5WindowSystem ${KF5_DEP_VERSION} REQUIRED)
+find_package(KF5Service ${KF5_DEP_VERSION} REQUIRED)
+find_package(KF5KIO ${KF5_DEP_VERSION} REQUIRED)
# no X11 stuff on mac
if (NOT APPLE)
diff --git a/src/runtime/CMakeLists.txt b/src/runtime/CMakeLists.txt
index cb286d0..bc7c3f8 100644
--- a/src/runtime/CMakeLists.txt
+++ b/src/runtime/CMakeLists.txt
@@ -7,6 +7,7 @@ remove_definitions(-DQT_NO_CAST_FROM_ASCII)
set(kglobalaccelprivate_SRCS
kglobalacceld.cpp
kglobalaccel_interface.cpp
+ kserviceactioncomponent.cpp
component.cpp
logging.cpp
globalshortcut.cpp
@@ -29,6 +30,8 @@ target_link_libraries(KF5GlobalAccelPrivate
KF5::WindowSystem # KKeyServer
KF5::CoreAddons # KAboutData
KF5::ConfigCore
+ KF5::Service
+ KF5::KIOWidgets
)
set_target_properties(KF5GlobalAccelPrivate PROPERTIES VERSION \
${KGLOBALACCEL_VERSION_STRING}
diff --git a/src/runtime/component.cpp b/src/runtime/component.cpp
index 35b1b5c..3b4dfad 100644
--- a/src/runtime/component.cpp
+++ b/src/runtime/component.cpp
@@ -174,11 +174,10 @@ bool Component::cleanUp()
}
}
- if (changed)
- {
+ if (changed) {
_registry->writeSettings();
// We could be destroyed after this call!
- }
+ }
return changed;
}
@@ -354,6 +353,35 @@ bool Component::isShortcutAvailable(
return true;
}
+GlobalShortcut *Component::registerShortcut(const QString &uniqueName, const QString \
&friendlyName, const QString &shortcutString, const QString &defaultShortcutString) + \
{ + // The shortcut will register itself with us
+ GlobalShortcut *shortcut = new GlobalShortcut(
+ uniqueName,
+ friendlyName,
+ currentContext());
+
+ QList<int> keys = keysFromString(shortcutString);
+ shortcut->setDefaultKeys(keysFromString(defaultShortcutString));
+ shortcut->setIsFresh(false);
+
+ Q_FOREACH (int key, keys)
+ {
+ if (key != 0)
+ {
+ if (GlobalShortcutsRegistry::self()->getShortcutByKey(key))
+ {
+ // The shortcut is already used. The config file is
+ // broken. Ignore the request.
+ keys.removeAll(key);
+ qCWarning(KGLOBALACCELD) << "Shortcut found twice in \
kglobalshortcutsrc."<<key; + }
+ }
+ }
+ shortcut->setKeys(keys);
+ return shortcut;
+ }
+
void Component::loadSettings(KConfigGroup &configGroup)
{
@@ -366,30 +394,10 @@ void Component::loadSettings(KConfigGroup &configGroup)
continue;
}
- // The shortcut will register itself with us
- GlobalShortcut *shortcut = new GlobalShortcut(
- confKey,
- entry[2],
- _current);
-
- QList<int> keys = keysFromString(entry[0]);
- shortcut->setDefaultKeys(keysFromString(entry[1]));
- shortcut->setIsFresh(false);
-
- Q_FOREACH (int key, keys)
- {
- if (key != 0)
- {
- if (GlobalShortcutsRegistry::self()->getShortcutByKey(key))
- {
- // The shortcut is already used. The config file is
- // broken. Ignore the request.
- keys.removeAll(key);
- qCWarning(KGLOBALACCELD) << "Shortcut found twice in \
kglobalshortcutsrc.";
- }
- }
- }
- shortcut->setKeys(keys);
+ GlobalShortcut *shortcut = registerShortcut(confKey, entry[2], entry[0], \
entry[1]); + if (configGroup.name().endsWith(QLatin1String(".desktop"))) {
+ shortcut->setIsPresent(true);
+ }
}
}
diff --git a/src/runtime/component.h b/src/runtime/component.h
index 66881e3..b08736d 100644
--- a/src/runtime/component.h
+++ b/src/runtime/component.h
@@ -118,6 +118,18 @@ public:
void writeSettings(KConfigGroup &config) const;
+protected:
+ /**
+ * Create a new globalShortcut by its name
+ * @param uniqueName internal unique name to identify the shortcut
+ * @param friendlyName name for the shortcut to be presented to the user
+ * @param shortcutString string representation of the shortcut, such as "CTRL+S"
+ * @param defaultShortcutString string representation of the default shortcut,
+ * such as "CTRL+S", when the user choses to reset to default
+ * the keyboard shortcut will return to this one.
+ */
+ GlobalShortcut *registerShortcut(const QString &uniqueName, const QString \
&friendlyName, const QString &shortcutString, const QString &defaultShortcutString); \
+ public Q_SLOTS:
// For dbus Q_SCRIPTABLE has to be on slots. Scriptable methods are not
@@ -134,7 +146,7 @@ public Q_SLOTS:
*
* @return @c true if a change was made, @c false if not.
*/
- Q_SCRIPTABLE bool cleanUp();
+ Q_SCRIPTABLE virtual bool cleanUp();
/**
* Check if the component is currently active.
@@ -153,7 +165,7 @@ public Q_SLOTS:
//! Returns the shortcut contexts available for the component.
Q_SCRIPTABLE QStringList getShortcutContexts() const;
- void emitGlobalShortcutPressed(const GlobalShortcut &shortcut);
+ virtual void emitGlobalShortcutPressed(const GlobalShortcut &shortcut);
Q_SCRIPTABLE void invokeShortcut(const QString &shortcutName, const QString \
&context = "default");
diff --git a/src/runtime/globalshortcutsregistry.cpp \
b/src/runtime/globalshortcutsregistry.cpp index c61f59f..7cc712b 100644
--- a/src/runtime/globalshortcutsregistry.cpp
+++ b/src/runtime/globalshortcutsregistry.cpp
@@ -18,17 +18,21 @@
#include "globalshortcutsregistry.h"
#include "component.h"
+#include "kserviceactioncomponent.h"
#include "globalshortcut.h"
#include "globalshortcutcontext.h"
#include <config-kglobalaccel.h>
#include "logging_p.h"
#include "kglobalaccel_interface.h"
+#include <QDir>
+#include <QStandardPaths>
#include <QGuiApplication>
#include <QDebug>
#include <QJsonArray>
#include <KPluginLoader>
#include <KPluginMetaData>
+#include <KDesktopFile>
#include <QKeySequence>
#include <QDBusConnection>
@@ -271,23 +275,21 @@ void GlobalShortcutsRegistry::loadSettings()
// We previously stored the friendly name in a separate group. migrate
// that
- QString friendlyName;
- KConfigGroup friendlyGroup(&configGroup, "Friendly Name");
- if (friendlyGroup.isValid())
- {
- friendlyName = friendlyGroup.readEntry("Friendly Name");
- friendlyGroup.deleteGroup();
- }
- else
- {
- friendlyName = configGroup.readEntry("_k_friendly_name");
- }
+ const QString friendlyName = configGroup.readEntry("_k_friendly_name");
// Create the component
- KdeDGlobalAccel::Component *component = new KdeDGlobalAccel::Component(
+ KdeDGlobalAccel::Component *component = nullptr;
+ if (groupName.endsWith(QLatin1String(".desktop"))) {
+ component = new KdeDGlobalAccel::KServiceActionComponent(
groupName,
friendlyName,
this);
+ } else {
+ component = new KdeDGlobalAccel::Component(
+ groupName,
+ friendlyName,
+ this);
+ }
// Now load the contexts
Q_FOREACH(const QString& context, configGroup.groupList())
@@ -306,6 +308,33 @@ void GlobalShortcutsRegistry::loadSettings()
component->activateGlobalShortcutContext("default");
component->loadSettings(configGroup);
}
+
+ // Load the configured KServiceActions
+ const QStringList desktopPaths = \
QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, \
QStringLiteral("kglobalaccel"), QStandardPaths::LocateDirectory); + foreach \
(const QString &path, desktopPaths) { + QDir dir(path);
+ if (!dir.exists()) {
+ continue;
+ }
+ const QStringList patterns = {QStringLiteral("*.desktop")};
+ foreach (const QString &desktopFile, dir.entryList(patterns)) {
+ if (_components.contains(desktopFile)) {
+ continue;
+ }
+
+ KDesktopFile f(dir.filePath(desktopFile));
+ if (f.noDisplay()) {
+ continue;
+ }
+
+ KdeDGlobalAccel::KServiceActionComponent *component = new \
KdeDGlobalAccel::KServiceActionComponent( + desktopFile,
+ f.readName(),
+ this);
+ component->activateGlobalShortcutContext(QStringLiteral("default"));
+ component->loadFromService();
+ }
+ }
}
diff --git a/src/runtime/kglobalacceld.cpp b/src/runtime/kglobalacceld.cpp
index b8e172e..07e7e2b 100644
--- a/src/runtime/kglobalacceld.cpp
+++ b/src/runtime/kglobalacceld.cpp
@@ -27,6 +27,7 @@
#include "globalshortcutcontext.h"
#include "globalshortcutsregistry.h"
#include "logging_p.h"
+#include "kserviceactioncomponent.h"
#include <QtCore/QTimer>
#include <QtCore/QMetaMethod>
@@ -146,14 +147,22 @@ KdeDGlobalAccel::Component \
*KGlobalAccelDPrivate::component(const QStringList &a {
// Get the component for the action. If we have none create a new one
KdeDGlobalAccel::Component *component = \
GlobalShortcutsRegistry::self()->getComponent(actionId.at(KGlobalAccel::ComponentUnique));
- if (!component)
- {
- component = new KdeDGlobalAccel::Component(
- actionId.at(KGlobalAccel::ComponentUnique),
- actionId.at(KGlobalAccel::ComponentFriendly),
- GlobalShortcutsRegistry::self());
- Q_ASSERT(component);
+ if (!component) {
+ if (actionId.at(KGlobalAccel::ComponentUnique).endsWith(QLatin1String(".desktop"))) \
{ + component = new KdeDGlobalAccel::KServiceActionComponent(
+ actionId.at(KGlobalAccel::ComponentUnique),
+ actionId.at(KGlobalAccel::ComponentFriendly),
+ GlobalShortcutsRegistry::self());
+ component->activateGlobalShortcutContext(QStringLiteral("default"));
+ static_cast<KdeDGlobalAccel::KServiceActionComponent \
*>(component)->loadFromService(); + } else {
+ component = new KdeDGlobalAccel::Component(
+ actionId.at(KGlobalAccel::ComponentUnique),
+ actionId.at(KGlobalAccel::ComponentFriendly),
+ GlobalShortcutsRegistry::self());
}
+ Q_ASSERT(component);
+ }
return component;
}
diff --git a/src/runtime/kserviceactioncomponent.cpp \
b/src/runtime/kserviceactioncomponent.cpp new file mode 100644
index 0000000..c64bf15
--- /dev/null
+++ b/src/runtime/kserviceactioncomponent.cpp
@@ -0,0 +1,109 @@
+/* Copyright (C) 2008 Michael Jansen <kde@michael-jansen.biz>
+ Copyright (C) 2016 Marco Martin <mart@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kserviceactioncomponent.h"
+#include "globalshortcutcontext.h"
+#include "logging_p.h"
+
+#include <KRun>
+
+#include <QDebug>
+#include <QProcess>
+#include <QDir>
+
+
+namespace KdeDGlobalAccel {
+
+KServiceActionComponent::KServiceActionComponent(
+ const QString &serviceStorageId,
+ const QString &friendlyName,
+ GlobalShortcutsRegistry *registry)
+ : Component(serviceStorageId, friendlyName, registry),
+ m_serviceStorageId(serviceStorageId),
+ m_desktopFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, \
QStringLiteral("kglobalaccel/") + serviceStorageId)) + {
+ }
+
+
+KServiceActionComponent::~KServiceActionComponent()
+ {
+ }
+
+void KServiceActionComponent::emitGlobalShortcutPressed( const GlobalShortcut \
&shortcut ) + {
+ if (shortcut.uniqueName() == QStringLiteral("_launch"))
+ {
+ KRun::run(m_desktopFile.desktopGroup().readEntry(QStringLiteral("Exec"), \
QString()), {}, nullptr); + return;
+ }
+ foreach(const QString &action, m_desktopFile.readActions())
+ {
+ if (action == shortcut.uniqueName())
+ {
+ KRun::run(m_desktopFile.actionGroup(action).readEntry(QStringLiteral("Exec"), \
QString()), {}, nullptr); + return;
+ }
+ }
+ }
+
+
+
+void KServiceActionComponent::loadFromService()
+ {
+
+ QString shortcutString;
+
+ QStringList shortcuts = \
m_desktopFile.desktopGroup().readEntry(QStringLiteral("X-KDE-Shortcuts"), \
QString()).split(QChar(',')); + if (shortcuts.size() > 0) {
+ shortcutString = shortcuts.join(QChar('\\'));
+ }
+
+ GlobalShortcut *shortcut = registerShortcut(QStringLiteral("_launch"), \
m_desktopFile.readName(), shortcutString, shortcutString); + \
shortcut->setIsPresent(true); +
+ foreach(const QString &action, m_desktopFile.readActions())
+ {
+ shortcuts = \
m_desktopFile.actionGroup(action).readEntry(QStringLiteral("X-KDE-Shortcuts"), \
QString()).split(QChar(',')); + if (shortcuts.size() > 0)
+ {
+ shortcutString = shortcuts.join(QChar('\\'));
+ }
+
+ GlobalShortcut *shortcut = registerShortcut(action, \
m_desktopFile.actionGroup(action).readEntry(QStringLiteral("Name")), shortcutString, \
shortcutString); + shortcut->setIsPresent(true);
+ }
+ }
+
+bool KServiceActionComponent::cleanUp()
+{
+ qCDebug(KGLOBALACCELD) << "Disabling desktop file";
+
+ for (GlobalShortcut *shortcut : allShortcuts()) {
+ shortcut->setIsPresent(false);
+ }
+
+ m_desktopFile.desktopGroup().writeEntry("NoDisplay", true);
+ m_desktopFile.desktopGroup().sync();
+
+ return Component::cleanUp();
+}
+
+} // namespace KdeDGlobalAccel
+
+#include "moc_kserviceactioncomponent.cpp"
diff --git a/src/runtime/kserviceactioncomponent.h \
b/src/runtime/kserviceactioncomponent.h new file mode 100644
index 0000000..c9f27f2
--- /dev/null
+++ b/src/runtime/kserviceactioncomponent.h
@@ -0,0 +1,61 @@
+#ifndef KSERVICEACTIONCOMPONENT_H
+#define KSERVICEACTIONCOMPONENT_H
+/* Copyright (C) 2008 Michael Jansen <kde@michael-jansen.biz>
+ Copyright (C) 2016 Marco Martin <mart@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "component.h"
+
+#include <KDesktopFile>
+
+namespace KdeDGlobalAccel {
+
+/**
+ * @author Michael Jansen <kde@michael-jansen.biz>
+ */
+class KServiceActionComponent : public Component
+{
+ Q_OBJECT
+
+public:
+
+ //! Creates a new component. The component will be registered with @p
+ //! registry if specified and registered with dbus.
+ KServiceActionComponent(
+ const QString &serviceStorageId,
+ const QString &friendlyName,
+ GlobalShortcutsRegistry *registry = NULL);
+
+ ~KServiceActionComponent();
+
+ void loadFromService();
+ void emitGlobalShortcutPressed(const GlobalShortcut &shortcut) Q_DECL_OVERRIDE;
+
+ bool cleanUp() Q_DECL_OVERRIDE;
+
+private:
+ QString m_serviceStorageId;
+ KDesktopFile m_desktopFile;
+};
+
+
+
+}
+
+
+#endif /* #ifndef COMPONENT_H */
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic