Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -40,6 +40,8 @@ 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) Index: src/runtime/CMakeLists.txt =================================================================== --- src/runtime/CMakeLists.txt +++ src/runtime/CMakeLists.txt @@ -7,6 +7,7 @@ set(kglobalaccelprivate_SRCS kglobalacceld.cpp kglobalaccel_interface.cpp + kserviceactioncomponent.cpp component.cpp logging.cpp globalshortcut.cpp @@ -29,6 +30,8 @@ KF5::WindowSystem # KKeyServer KF5::CoreAddons # KAboutData KF5::ConfigCore + KF5::Service + KF5::KIOWidgets ) set_target_properties(KF5GlobalAccelPrivate PROPERTIES VERSION ${KGLOBALACCEL_VERSION_STRING} Index: src/runtime/component.h =================================================================== --- src/runtime/component.h +++ src/runtime/component.h @@ -118,6 +118,9 @@ void writeSettings(KConfigGroup &config) const; +protected: + 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 +137,7 @@ * * @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 +156,7 @@ //! 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"); Index: src/runtime/component.cpp =================================================================== --- src/runtime/component.cpp +++ src/runtime/component.cpp @@ -174,11 +174,10 @@ } } - if (changed) - { + if (changed) { _registry->writeSettings(); // We could be destroyed after this call! - } + } return changed; } @@ -354,6 +353,35 @@ 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 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."<setKeys(keys); + return shortcut; + } + void Component::loadSettings(KConfigGroup &configGroup) { @@ -366,30 +394,11 @@ continue; } - // The shortcut will register itself with us - GlobalShortcut *shortcut = new GlobalShortcut( - confKey, - entry[2], - _current); - - QList keys = keysFromString(entry[0]); - shortcut->setDefaultKeys(keysFromString(entry[1])); - shortcut->setIsFresh(false); - - Q_FOREACH (int key, keys) + GlobalShortcut *shortcut = registerShortcut(confKey, entry[2], entry[0], entry[1]); + if (configGroup.name().endsWith(QStringLiteral(".desktop"))) { - 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->setIsPresent(true); } - shortcut->setKeys(keys); } } Index: src/runtime/globalshortcutsregistry.cpp =================================================================== --- src/runtime/globalshortcutsregistry.cpp +++ src/runtime/globalshortcutsregistry.cpp @@ -18,17 +18,21 @@ #include "globalshortcutsregistry.h" #include "component.h" +#include "kserviceactioncomponent.h" #include "globalshortcut.h" #include "globalshortcutcontext.h" #include #include "logging_p.h" #include "kglobalaccel_interface.h" +#include +#include #include #include #include #include #include +#include #include #include @@ -271,23 +275,21 @@ // 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(QStringLiteral(".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,32 @@ 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; + } + foreach (const QString &desktopFile, dir.entryList({"*.desktop"})) { + 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("default"); + component->loadFromService(); + } + } } Index: src/runtime/kglobalacceld.cpp =================================================================== --- src/runtime/kglobalacceld.cpp +++ src/runtime/kglobalacceld.cpp @@ -27,6 +27,7 @@ #include "globalshortcutcontext.h" #include "globalshortcutsregistry.h" #include "logging_p.h" +#include "kserviceactioncomponent.h" #include #include @@ -146,14 +147,22 @@ { // 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(QStringLiteral(".desktop"))) { + component = new KdeDGlobalAccel::KServiceActionComponent( + actionId.at(KGlobalAccel::ComponentUnique), + actionId.at(KGlobalAccel::ComponentFriendly), + GlobalShortcutsRegistry::self()); + component->activateGlobalShortcutContext("default"); + static_cast(component)->loadFromService(); + } else { + component = new KdeDGlobalAccel::Component( + actionId.at(KGlobalAccel::ComponentUnique), + actionId.at(KGlobalAccel::ComponentFriendly), + GlobalShortcutsRegistry::self()); } + Q_ASSERT(component); + } return component; } Index: src/runtime/kserviceactioncomponent.h =================================================================== --- /dev/null +++ src/runtime/kserviceactioncomponent.h @@ -0,0 +1,61 @@ +#ifndef KSERVICEACTIONCOMPONENT_H +#define KSERVICEACTIONCOMPONENT_H +/* Copyright (C) 2008 Michael Jansen + Copyright (C) 2016 Marco Martin + + 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 + +namespace KdeDGlobalAccel { + +/** + * @author Michael Jansen + */ +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 */ Index: src/runtime/kserviceactioncomponent.cpp =================================================================== --- /dev/null +++ src/runtime/kserviceactioncomponent.cpp @@ -0,0 +1,110 @@ +/* Copyright (C) 2008 Michael Jansen + Copyright (C) 2016 Marco Martin + + 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 + +#include +#include +#include + + +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(); +} + +#include "moc_kserviceactioncomponent.cpp" + +} // namespace KdeDGlobalAccel +