KGlobalAccel

kserviceactioncomponent.cpp
1 /*
2  SPDX-FileCopyrightText: 2008 Michael Jansen <[email protected]>
3  SPDX-FileCopyrightText: 2016 Marco Martin <[email protected]>
4  SPDX-FileCopyrightText: 2021 David Redondo <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "kserviceactioncomponent.h"
10 #include "globalshortcutcontext.h"
11 #include "logging_p.h"
12 
13 #include <QDBusConnectionInterface>
14 #include <QProcess>
15 
16 namespace KdeDGlobalAccel
17 {
18 KServiceActionComponent::KServiceActionComponent(const QString &serviceStorageId, const QString &friendlyName, GlobalShortcutsRegistry *registry)
19  : Component(serviceStorageId, friendlyName, registry)
20  , m_serviceStorageId(serviceStorageId)
21  , m_desktopFile(nullptr)
22 {
23  auto fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kglobalaccel/") + serviceStorageId);
24  if (fileName.isEmpty()) {
25  // Fallback to applications data dir
26  // for custom shortcut for instance
27  fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("applications/") + serviceStorageId);
28  }
29  if (fileName.isEmpty()) {
30  qCWarning(KGLOBALACCELD) << "No desktop file found for service " << serviceStorageId;
31  }
32  m_desktopFile.reset(new KDesktopFile(fileName));
33 }
34 
35 KServiceActionComponent::~KServiceActionComponent()
36 {
37 }
38 
39 void runProcess(const KConfigGroup &group, bool klauncherAvailable)
40 {
41  QStringList parts = group.readEntry(QStringLiteral("Exec"), QString()).split(QChar(' '));
42  if (parts.isEmpty()) {
43  return;
44  }
45  // sometimes entries have an %u for command line parameters
46  if (parts.last().contains(QChar('%'))) {
47  parts.pop_back();
48  }
49 
50  const QString command = parts.takeFirst();
51  if (klauncherAvailable) {
52  QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.klauncher5"),
53  QStringLiteral("/KLauncher"),
54  QStringLiteral("org.kde.KLauncher"),
55  QStringLiteral("exec_blind"));
56  msg << command << parts;
57 
59  } else {
60  const auto kstart = QStandardPaths::findExecutable(QStringLiteral("kstart5"));
61  if (kstart.isEmpty()) {
62  QProcess::startDetached(command, parts);
63  } else {
64  parts.prepend(command);
65  QProcess::startDetached(kstart, parts);
66  }
67  }
68 }
69 
70 void KServiceActionComponent::emitGlobalShortcutPressed(const GlobalShortcut &shortcut)
71 {
72  // DBusActivatatable spec as per https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#dbus
73  if (m_desktopFile->desktopGroup().readEntry("DBusActivatable", false)) {
74  QString method;
75  const QString serviceName = m_serviceStorageId.chopped(strlen(".desktop"));
76  const QString objectPath = QStringLiteral("/%1").arg(serviceName).replace(QLatin1Char('.'), QLatin1Char('/'));
77  const QString interface = QStringLiteral("org.freedesktop.Application");
78  QDBusMessage message;
79  if (shortcut.uniqueName() == QLatin1String("_launch")) {
80  message = QDBusMessage::createMethodCall(serviceName, objectPath, interface, QStringLiteral("Activate"));
81  } else {
82  message = QDBusMessage::createMethodCall(serviceName, objectPath, interface, QStringLiteral("ActivateAction"));
83  message << shortcut.uniqueName() << QVariantList();
84  }
85  message << QVariantMap();
87  return;
88  }
89 
91  const bool klauncherAvailable = dbusDaemon->isServiceRegistered(QStringLiteral("org.kde.klauncher5"));
92 
93  // we can't use KRun there as it depends from KIO and would create a circular dep
94  if (shortcut.uniqueName() == QLatin1String("_launch")) {
95  runProcess(m_desktopFile->desktopGroup(), klauncherAvailable);
96  return;
97  }
98  const auto lstActions = m_desktopFile->readActions();
99  for (const QString &action : lstActions) {
100  if (action == shortcut.uniqueName()) {
101  runProcess(m_desktopFile->actionGroup(action), klauncherAvailable);
102  return;
103  }
104  }
105 }
106 
107 void KServiceActionComponent::loadFromService()
108 {
109  QString shortcutString;
110 
111  QStringList shortcuts = m_desktopFile->desktopGroup().readEntry(QStringLiteral("X-KDE-Shortcuts"), QString()).split(QChar(','));
112  if (!shortcuts.isEmpty()) {
113  shortcutString = shortcuts.join(QChar('\t'));
114  }
115 
116  GlobalShortcut *shortcut = registerShortcut(QStringLiteral("_launch"), m_desktopFile->readName(), shortcutString, shortcutString);
117  shortcut->setIsPresent(true);
118  const auto lstActions = m_desktopFile->readActions();
119  for (const QString &action : lstActions) {
120  shortcuts = m_desktopFile->actionGroup(action).readEntry(QStringLiteral("X-KDE-Shortcuts"), QString()).split(QChar(','));
121  if (!shortcuts.isEmpty()) {
122  shortcutString = shortcuts.join(QChar('\t'));
123  }
124 
125  GlobalShortcut *shortcut =
126  registerShortcut(action, m_desktopFile->actionGroup(action).readEntry(QStringLiteral("Name")), shortcutString, shortcutString);
127  shortcut->setIsPresent(true);
128  }
129 }
130 
132 {
133  qCDebug(KGLOBALACCELD) << "Disabling desktop file";
134 
135  const auto shortcuts = allShortcuts();
136  for (GlobalShortcut *shortcut : shortcuts) {
137  shortcut->setIsPresent(false);
138  }
139 
140  m_desktopFile->desktopGroup().writeEntry("NoDisplay", true);
141  m_desktopFile->desktopGroup().sync();
142 
143  return Component::cleanUp();
144 }
145 
146 } // namespace KdeDGlobalAccel
147 
148 #include "moc_kserviceactioncomponent.cpp"
bool cleanUp() override
Remove all currently not used global shortcuts registrations for this component and if nothing is lef...
QDBusConnectionInterface * interface() const const
bool startDetached(qint64 *pid)
QString findExecutable(const QString &executableName, const QStringList &paths)
QDBusConnection sessionBus()
QString join(const QString &separator) const const
QDBusReply< bool > isServiceRegistered(const QString &serviceName) const const
void reset(T *other)
QString uniqueName() const
Returns the unique name aka id for the shortcuts.
Global Shortcut Registry.
QString chopped(int len) const const
bool isEmpty() const const
QList< GlobalShortcut * > allShortcuts(const QString &context=QStringLiteral("default")) const
Returns all shortcuts in context .
Definition: component.cpp:106
Represents a global shortcut.
void pop_back()
QString & replace(int position, int n, QChar after)
GlobalShortcut * registerShortcut(const QString &uniqueName, const QString &friendlyName, const QString &shortcutString, const QString &defaultShortcutString)
Create a new globalShortcut by its name.
Definition: component.cpp:292
T takeFirst()
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
T & last()
QDBusPendingCall asyncCall(const QDBusMessage &message, int timeout) const const
void prepend(const T &value)
KServiceActionComponent(const QString &serviceStorageId, const QString &friendlyName, GlobalShortcutsRegistry *registry=nullptr)
Creates a new component.
T readEntry(const QString &key, const T &aDefault) const
QDBusMessage createMethodCall(const QString &service, const QString &path, const QString &interface, const QString &method)
QString locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
virtual Q_SCRIPTABLE bool cleanUp()
Remove all currently not used global shortcuts registrations for this component and if nothing is lef...
Definition: component.cpp:126
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sun May 16 2021 22:53:45 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.