KGlobalAccel

kglobalaccel.cpp
1 /*
2  This file is part of the KDE libraries
3  SPDX-FileCopyrightText: 2001, 2002 Ellis Whitehead <[email protected]>
4  SPDX-FileCopyrightText: 2006 Hamish Rodda <[email protected]>
5  SPDX-FileCopyrightText: 2007 Andreas Hartmetz <[email protected]>
6  SPDX-FileCopyrightText: 2008 Michael Jansen <[email protected]>
7 
8  SPDX-License-Identifier: LGPL-2.0-or-later
9 */
10 
11 #include "kglobalaccel.h"
12 #include "kglobalaccel_debug.h"
13 #include "kglobalaccel_p.h"
14 
15 #include <memory>
16 
17 #include <QAction>
18 #include <QDBusMessage>
19 #include <QDBusMetaType>
20 #include <QGuiApplication>
21 #include <QMessageBox>
22 #include <QPushButton>
23 #include <config-kglobalaccel.h>
24 #if HAVE_X11
25 #include <QX11Info>
26 #endif
27 
28 bool active()
29 {
30  return qgetenv("XDG_CURRENT_DESKTOP") == QByteArrayLiteral("KDE");
31 }
32 
33 org::kde::kglobalaccel::Component *KGlobalAccelPrivate::getComponent(const QString &componentUnique, bool remember = false)
34 {
35  // Check if we already have this component
36  {
37  auto component = components.value(componentUnique);
38  if (component) {
39  return component;
40  }
41  }
42 
43  // Connect to the kglobalaccel daemon
44  org::kde::KGlobalAccel kglobalaccel(QStringLiteral("org.kde.kglobalaccel"), QStringLiteral("/kglobalaccel"), QDBusConnection::sessionBus());
45  if (!kglobalaccel.isValid()) {
46  qCDebug(KGLOBALACCEL_LOG) << "Failed to connect to the kglobalaccel daemon" << QDBusConnection::sessionBus().lastError();
47  return nullptr;
48  }
49 
50  // Get the path for our component. We have to do that because
51  // componentUnique is probably not a valid dbus object path
52  QDBusReply<QDBusObjectPath> reply = kglobalaccel.getComponent(componentUnique);
53  if (!reply.isValid()) {
54  if (reply.error().name() == QLatin1String("org.kde.kglobalaccel.NoSuchComponent")) {
55  // No problem. The component doesn't exists. That's normal
56  return nullptr;
57  }
58 
59  // An unknown error.
60  qCDebug(KGLOBALACCEL_LOG) << "Failed to get dbus path for component " << componentUnique << reply.error();
61  return nullptr;
62  }
63 
64  // Now get the component
65  org::kde::kglobalaccel::Component *component =
66  new org::kde::kglobalaccel::Component(QStringLiteral("org.kde.kglobalaccel"), reply.value().path(), QDBusConnection::sessionBus(), q);
67 
68  // No component no cleaning
69  if (!component->isValid()) {
70  qCDebug(KGLOBALACCEL_LOG) << "Failed to get component" << componentUnique << QDBusConnection::sessionBus().lastError();
71  return nullptr;
72  }
73 
74  if (remember) {
75  // Connect to the signals we are interested in.
76  q->connect(component,
77  &org::kde::kglobalaccel::Component::globalShortcutPressed,
78  q,
79  [this](const QString &componentUnique, const QString &shortcutUnique, qlonglong timestamp) {
80  _k_invokeAction(componentUnique, shortcutUnique, timestamp);
81  });
82 
83  components[componentUnique] = component;
84  }
85 
86  return component;
87 }
88 
89 namespace
90 {
91 QString serviceName()
92 {
93  return QStringLiteral("org.kde.kglobalaccel");
94 }
95 }
96 
97 void KGlobalAccelPrivate::cleanup()
98 {
99  qDeleteAll(components);
100  delete m_iface;
101  m_iface = nullptr;
102  delete m_watcher;
103  m_watcher = nullptr;
104 }
105 
106 KGlobalAccelPrivate::KGlobalAccelPrivate(KGlobalAccel *q)
107  : q(q)
108 {
110  q->connect(m_watcher, &QDBusServiceWatcher::serviceOwnerChanged, q, [this](const QString &serviceName, const QString &oldOwner, const QString &newOwner) {
111  _k_serviceOwnerChanged(serviceName, oldOwner, newOwner);
112  });
113 }
114 
115 org::kde::KGlobalAccel *KGlobalAccelPrivate::iface()
116 {
117  if (!m_iface) {
118  m_iface = new org::kde::KGlobalAccel(serviceName(), QStringLiteral("/kglobalaccel"), QDBusConnection::sessionBus());
119  // Make sure kglobalaccel is running. The iface declaration above somehow works anyway.
121  if (bus && !bus->isServiceRegistered(serviceName())) {
122  QDBusReply<void> reply = bus->startService(serviceName());
123  if (!reply.isValid()) {
124  qCritical() << "Couldn't start kglobalaccel from org.kde.kglobalaccel.service:" << reply.error();
125  }
126  }
127  q->connect(m_iface, &org::kde::KGlobalAccel::yourShortcutGotChanged, q, [this](const QStringList &actionId, const QList<int> &newKeys) {
128  _k_shortcutGotChanged(actionId, newKeys);
129  });
130  }
131  return m_iface;
132 }
133 
134 KGlobalAccel::KGlobalAccel()
135  : d(new KGlobalAccelPrivate(this))
136 {
137  qDBusRegisterMetaType<QList<int>>();
138  qDBusRegisterMetaType<QList<QStringList>>();
139  qDBusRegisterMetaType<KGlobalShortcutInfo>();
140  qDBusRegisterMetaType<QList<KGlobalShortcutInfo>>();
141 }
142 
143 KGlobalAccel::~KGlobalAccel()
144 {
145  delete d;
146 }
147 
148 void KGlobalAccel::activateGlobalShortcutContext(const QString &contextUnique, const QString &contextFriendly, const QString &programName)
149 {
150  Q_UNUSED(contextFriendly);
151 
152  if (!active()) {
153  return;
154  }
155 
156  // TODO: provide contextFriendly
157  self()->d->iface()->activateGlobalShortcutContext(programName, contextUnique);
158 }
159 
160 // static
161 bool KGlobalAccel::cleanComponent(const QString &componentUnique)
162 {
163  if (!active()) {
164  return false;
165  }
166 
167  org::kde::kglobalaccel::Component *component = self()->getComponent(componentUnique);
168  if (!component) {
169  return false;
170  }
171 
172  return component->cleanUp();
173 }
174 
175 // static
176 bool KGlobalAccel::isComponentActive(const QString &componentUnique)
177 {
178  if (!active()) {
179  return false;
180  }
181 
182  org::kde::kglobalaccel::Component *component = self()->getComponent(componentUnique);
183  if (!component) {
184  return false;
185  }
186 
187  return component->isActive();
188 }
189 
190 #if KGLOBALACCEL_BUILD_DEPRECATED_SINCE(4, 4)
192 {
193  return d->enabled;
194 }
195 #endif
196 
197 org::kde::kglobalaccel::Component *KGlobalAccel::getComponent(const QString &componentUnique)
198 {
199  if (!active()) {
200  return nullptr;
201  }
202 
203  return d->getComponent(componentUnique);
204 }
205 
206 #if KGLOBALACCEL_BUILD_DEPRECATED_SINCE(4, 4)
207 void KGlobalAccel::setEnabled(bool enabled)
208 {
209  d->enabled = enabled;
210 }
211 #endif
212 
213 class KGlobalAccelSingleton
214 {
215 public:
216  KGlobalAccelSingleton();
217 
218  KGlobalAccel instance;
219 };
220 
221 Q_GLOBAL_STATIC(KGlobalAccelSingleton, s_instance)
222 
223 KGlobalAccelSingleton::KGlobalAccelSingleton()
224 {
225  qAddPostRoutine([]() {
226  s_instance->instance.d->cleanup();
227  });
228 }
229 
231 {
232  return &s_instance()->instance;
233 }
234 
235 bool KGlobalAccelPrivate::doRegister(QAction *action)
236 {
237  if (!action || action->objectName().isEmpty() || action->objectName().startsWith(QLatin1String("unnamed-"))) {
238  qWarning() << "Attempt to set global shortcut for action without objectName()."
239  " Read the setGlobalShortcut() documentation.";
240  return false;
241  }
242 
243  const bool isRegistered = actions.contains(action);
244  if (isRegistered) {
245  return true;
246  }
247 
248  QStringList actionId = makeActionId(action);
249 
250  nameToAction.insert(actionId.at(KGlobalAccel::ActionUnique), action);
251  actions.insert(action);
252  iface()->doRegister(actionId);
253 
254  QObject::connect(action, &QObject::destroyed, [this, action](QObject *) {
255  if (actions.contains(action) && (actionShortcuts.contains(action) || actionDefaultShortcuts.contains(action))) {
256  remove(action, KGlobalAccelPrivate::SetInactive);
257  }
258  });
259 
260  return true;
261 }
262 
263 void KGlobalAccelPrivate::remove(QAction *action, Removal removal)
264 {
265  if (!action || action->objectName().isEmpty()) {
266  return;
267  }
268 
269  const bool isRegistered = actions.contains(action);
270  if (!isRegistered) {
271  return;
272  }
273 
274  QStringList actionId = makeActionId(action);
275 
276  nameToAction.remove(actionId.at(KGlobalAccel::ActionUnique), action);
277  actions.remove(action);
278 
279  if (removal == UnRegister) {
280  // Complete removal of the shortcut is requested
281  // (forgetGlobalShortcut)
282  unregister(actionId);
283  } else {
284  // If the action is a configurationAction wen only remove it from our
285  // internal registry. That happened above.
286 
287  // If we are merely marking a callback as inactive there is nothing for kglobalaccel to do if kglobalaccel is not running
288  // this can happen on shutdown where all apps and kglobalaccel are all torn down at once
289  // For this reason we turn off the autostart flag in the DBus message call
290 
291  if (!action->property("isConfigurationAction").toBool()) {
292  // If it's a session shortcut unregister it.
293  action->objectName().startsWith(QLatin1String("_k_session:")) ? unregister(actionId) : setInactive(actionId);
294  }
295  }
296 
297  actionDefaultShortcuts.remove(action);
298  actionShortcuts.remove(action);
299 }
300 
301 void KGlobalAccelPrivate::unregister(const QStringList &actionId)
302 {
303  const auto component = actionId.at(KGlobalAccel::ComponentUnique);
304  const auto action = actionId.at(KGlobalAccel::ActionUnique);
305 
306  auto message = QDBusMessage::createMethodCall(iface()->service(), iface()->path(), iface()->interface(), QStringLiteral("unregister"));
307  message.setArguments({component, action});
308  message.setAutoStartService(false);
310 }
311 
312 void KGlobalAccelPrivate::setInactive(const QStringList &actionId)
313 {
314  auto message = QDBusMessage::createMethodCall(iface()->service(), iface()->path(), iface()->interface(), QStringLiteral("setInactive"));
315  message.setArguments({actionId});
316  message.setAutoStartService(false);
318 }
319 
320 void KGlobalAccelPrivate::updateGlobalShortcut(/*const would be better*/ QAction *action,
321  ShortcutTypes actionFlags,
323 {
324  // No action or no objectname -> Do nothing
325  if (!action || action->objectName().isEmpty()) {
326  return;
327  }
328 
329  QStringList actionId = makeActionId(action);
330 
331  uint setterFlags = 0;
332  if (globalFlags & NoAutoloading) {
333  setterFlags |= NoAutoloading;
334  }
335 
336  if (actionFlags & ActiveShortcut) {
337  const QList<QKeySequence> activeShortcut = actionShortcuts.value(action);
338  bool isConfigurationAction = action->property("isConfigurationAction").toBool();
339  uint activeSetterFlags = setterFlags;
340 
341  // setPresent tells kglobalaccel that the shortcut is active
342  if (!isConfigurationAction) {
343  activeSetterFlags |= SetPresent;
344  }
345 
346  // Sets the shortcut, returns the active/real keys
347  const auto result = iface()->setShortcut(actionId, intListFromShortcut(activeShortcut), activeSetterFlags);
348 
349  // Make sure we get informed about changes in the component by kglobalaccel
350  getComponent(componentUniqueForAction(action), true);
351 
352  // Create a shortcut from the result
353  const QList<QKeySequence> scResult(shortcutFromIntList(result));
354 
355  if (isConfigurationAction && (globalFlags & NoAutoloading)) {
356  // If this is a configuration action and we have set the shortcut,
357  // inform the real owner of the change.
358  // Note that setForeignShortcut will cause a signal to be sent to applications
359  // even if it did not "see" that the shortcut has changed. This is Good because
360  // at the time of comparison (now) the action *already has* the new shortcut.
361  // We called setShortcut(), remember?
362  // Also note that we will see our own signal so we may not need to call
363  // setActiveGlobalShortcutNoEnable - _k_shortcutGotChanged() does it.
364  // In practice it's probably better to get the change propagated here without
365  // DBus delay as we do below.
366  iface()->setForeignShortcut(actionId, result);
367  }
368  if (scResult != activeShortcut) {
369  // If kglobalaccel returned a shortcut that differs from the one we
370  // sent, use that one. There must have been clashes or some other problem.
371  actionShortcuts.insert(action, scResult);
372  Q_EMIT q->globalShortcutChanged(action, scResult.isEmpty() ? QKeySequence() : scResult.first());
373  }
374  }
375 
376  if (actionFlags & DefaultShortcut) {
377  const QList<QKeySequence> defaultShortcut = actionDefaultShortcuts.value(action);
378  iface()->setShortcut(actionId, intListFromShortcut(defaultShortcut), setterFlags | IsDefault);
379  }
380 }
381 
382 QStringList KGlobalAccelPrivate::makeActionId(const QAction *action)
383 {
384  QStringList ret(componentUniqueForAction(action)); // Component Unique Id ( see actionIdFields )
385  Q_ASSERT(!ret.at(KGlobalAccel::ComponentUnique).isEmpty());
386  Q_ASSERT(!action->objectName().isEmpty());
387  ret.append(action->objectName()); // Action Unique Name
388  ret.append(componentFriendlyForAction(action)); // Component Friendly name
389  const QString actionText = action->text().replace(QLatin1Char('&'), QStringLiteral(""));
390  ret.append(actionText); // Action Friendly Name
391  return ret;
392 }
393 
394 QList<int> KGlobalAccelPrivate::intListFromShortcut(const QList<QKeySequence> &cut)
395 {
396  QList<int> ret;
397  for (const QKeySequence &sequence : cut) {
398  ret.append(sequence[0]);
399  }
400  while (!ret.isEmpty() && ret.last() == 0) {
401  ret.removeLast();
402  }
403  return ret;
404 }
405 
406 QList<QKeySequence> KGlobalAccelPrivate::shortcutFromIntList(const QList<int> &list)
407 {
409  for (int i : list) {
410  ret.append(i);
411  }
412  return ret;
413 }
414 
415 QString KGlobalAccelPrivate::componentUniqueForAction(const QAction *action)
416 {
417  if (!action->property("componentName").isValid()) {
419  } else {
420  return action->property("componentName").toString();
421  }
422 }
423 
424 QString KGlobalAccelPrivate::componentFriendlyForAction(const QAction *action)
425 {
426  QString property = action->property("componentDisplayName").toString();
427  if (!property.isEmpty()) {
428  return property;
429  }
432  }
434 }
435 
436 #if HAVE_X11
437 int _k_timestampCompare(unsigned long time1_, unsigned long time2_) // like strcmp()
438 {
439  quint32 time1 = time1_;
440  quint32 time2 = time2_;
441  if (time1 == time2) {
442  return 0;
443  }
444  return quint32(time1 - time2) < 0x7fffffffU ? 1 : -1; // time1 > time2 -> 1, handle wrapping
445 }
446 #endif
447 
448 void KGlobalAccelPrivate::_k_invokeAction(const QString &componentUnique, const QString &actionUnique, qlonglong timestamp)
449 {
450  QAction *action = nullptr;
451  const QList<QAction *> candidates = nameToAction.values(actionUnique);
452  for (QAction *const a : candidates) {
453  if (componentUniqueForAction(a) == componentUnique) {
454  action = a;
455  }
456  }
457 
458  // We do not trigger if
459  // - there is no action
460  // - the action is not enabled
461  // - the action is an configuration action
462  if (!action || !action->isEnabled() || action->property("isConfigurationAction").toBool()) {
463  return;
464  }
465 
466 #if HAVE_X11
467  // Update this application's X timestamp if needed.
468  // TODO The 100%-correct solution should probably be handling this action
469  // in the proper place in relation to the X events queue in order to avoid
470  // the possibility of wrong ordering of user events.
471  if (QX11Info::isPlatformX11()) {
472  if (_k_timestampCompare(timestamp, QX11Info::appTime()) > 0) {
473  QX11Info::setAppTime(timestamp);
474  }
475  if (_k_timestampCompare(timestamp, QX11Info::appUserTime()) > 0) {
476  QX11Info::setAppUserTime(timestamp);
477  }
478  }
479 #endif
480  action->setProperty("org.kde.kglobalaccel.activationTimestamp", timestamp);
481 
482  action->trigger();
483 }
484 
485 void KGlobalAccelPrivate::_k_shortcutGotChanged(const QStringList &actionId, const QList<int> &keys)
486 {
487  QAction *action = nameToAction.value(actionId.at(KGlobalAccel::ActionUnique));
488  if (!action) {
489  return;
490  }
491 
492  const QList<QKeySequence> shortcuts = shortcutFromIntList(keys);
493  actionShortcuts.insert(action, shortcuts);
494  Q_EMIT q->globalShortcutChanged(action, keys.isEmpty() ? QKeySequence() : shortcuts.first());
495 }
496 
497 void KGlobalAccelPrivate::_k_serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
498 {
499  Q_UNUSED(oldOwner);
500  if (name == QLatin1String("org.kde.kglobalaccel") && !newOwner.isEmpty()) {
501  // kglobalaccel was restarted
502  qCDebug(KGLOBALACCEL_LOG) << "detected kglobalaccel restarting, re-registering all shortcut keys";
503  reRegisterAll();
504  }
505 }
506 
507 void KGlobalAccelPrivate::reRegisterAll()
508 {
509  // We clear all our data, assume that all data on the other side is clear too,
510  // and register each action as if it just was allowed to have global shortcuts.
511  // If the kded side still has the data it doesn't matter because of the
512  // autoloading mechanism. The worst case I can imagine is that an action's
513  // shortcut was changed but the kded side died before it got the message so
514  // autoloading will now assign an old shortcut to the action. Particularly
515  // picky apps might assert or misbehave.
516  const QSet<QAction *> allActions = actions;
517  nameToAction.clear();
518  actions.clear();
519  for (QAction *const action : allActions) {
520  if (doRegister(action)) {
521  updateGlobalShortcut(action, ActiveShortcut, KGlobalAccel::Autoloading);
522  }
523  }
524 }
525 
526 #if KGLOBALACCEL_BUILD_DEPRECATED_SINCE(4, 2)
528 {
529  if (!active()) {
530  return {};
531  }
532 
533  return d->iface()->allMainComponents();
534 }
535 #endif
536 
537 #if KGLOBALACCEL_BUILD_DEPRECATED_SINCE(4, 2)
539 {
540  if (!active()) {
541  return {};
542  }
543  return d->iface()->allActionsForComponent(actionId);
544 }
545 #endif
546 
547 // static
548 #if KGLOBALACCEL_BUILD_DEPRECATED_SINCE(4, 2)
550 {
551  if (!active()) {
552  return {};
553  }
554 
555  return self()->d->iface()->action(seq[0]);
556 }
557 #endif
558 
560 {
561  if (!active()) {
562  return {};
563  }
564 
565  return self()->d->iface()->getGlobalShortcutsByKey(seq[0]);
566 }
567 
569 {
570  if (!active()) {
571  return false;
572  }
573 
574  return self()->d->iface()->isGlobalShortcutAvailable(seq[0], comp);
575 }
576 
577 // static
578 #if KGLOBALACCEL_BUILD_DEPRECATED_SINCE(4, 2)
580 {
581  if (!active()) {
582  return false;
583  }
584 
585  if (actionIdentifier.size() < 4) {
586  return false;
587  }
588  QString title = tr("Conflict with Global Shortcut");
589  QString message = tr("The '%1' key combination has already been allocated "
590  "to the global action \"%2\" in %3.\n"
591  "Do you want to reassign it from that action to the current one?")
592  .arg(seq.toString(), actionIdentifier.at(KGlobalAccel::ActionFriendly), actionIdentifier.at(KGlobalAccel::ComponentFriendly));
593 
594  QMessageBox box(parent);
595  box.setWindowTitle(title);
596  box.setText(message);
597  box.addButton(QMessageBox::Ok)->setText(tr("Reassign"));
599 
600  return box.exec() == QMessageBox::Ok;
601 }
602 #endif
603 
604 // static
606 {
607  if (!active()) {
608  return false;
609  }
610 
611  if (shortcuts.isEmpty()) {
612  // Usage error. Just say no
613  return false;
614  }
615 
616  QString component = shortcuts[0].componentFriendlyName();
617 
618  QString message;
619  if (shortcuts.size() == 1) {
620  message = tr("The '%1' key combination is registered by application %2 for action %3:").arg(seq.toString(), component, shortcuts[0].friendlyName());
621  } else {
622  QString actionList;
623  for (const KGlobalShortcutInfo &info : shortcuts) {
624  actionList += tr("In context '%1' for action '%2'\n").arg(info.contextFriendlyName(), info.friendlyName());
625  }
626  message = tr("The '%1' key combination is registered by application %2.\n%3").arg(seq.toString(), component, actionList);
627  }
628 
629  QString title = tr("Conflict With Registered Global Shortcut");
630 
631  QMessageBox box(parent);
632  box.setWindowTitle(title);
633  box.setText(message);
634  box.addButton(QMessageBox::Ok)->setText(tr("Reassign"));
636 
637  return box.exec() == QMessageBox::Ok;
638 }
639 
640 // static
642 {
643  if (!active()) {
644  return;
645  }
646 
647  // get the shortcut, remove seq, and set the new shortcut
648  const QStringList actionId = self()->d->iface()->action(seq[0]);
649  if (actionId.size() < 4) { // not a global shortcut
650  return;
651  }
652  QList<int> sc = self()->d->iface()->shortcut(actionId);
653 
654  for (int i = 0; i < sc.count(); i++)
655  if (sc[i] == seq[0]) {
656  sc[i] = 0;
657  }
658 
659  self()->d->iface()->setForeignShortcut(actionId, sc);
660 }
661 
662 bool checkGarbageKeycode(const QList<QKeySequence> &shortcut)
663 {
664  // protect against garbage keycode -1 that Qt sometimes produces for exotic keys;
665  // at the moment (~mid 2008) Multimedia PlayPause is one of those keys.
666  for (const QKeySequence &sequence : shortcut) {
667  for (int i = 0; i < 4; i++) {
668  if (sequence[i] == -1) {
669  qWarning() << "Encountered garbage keycode (keycode = -1) in input, not doing anything.";
670  return true;
671  }
672  }
673  }
674  return false;
675 }
676 
678 {
679  if (!active()) {
680  return false;
681  }
682 
683  if (checkGarbageKeycode(shortcut)) {
684  return false;
685  }
686 
687  if (!d->doRegister(action)) {
688  return false;
689  }
690 
691  d->actionDefaultShortcuts.insert(action, shortcut);
692  d->updateGlobalShortcut(action, KGlobalAccelPrivate::DefaultShortcut, loadFlag);
693  return true;
694 }
695 
697 {
698  if (!active()) {
699  return false;
700  }
701 
702  if (checkGarbageKeycode(shortcut)) {
703  return false;
704  }
705 
706  if (!d->doRegister(action)) {
707  return false;
708  }
709 
710  d->actionShortcuts.insert(action, shortcut);
711  d->updateGlobalShortcut(action, KGlobalAccelPrivate::ActiveShortcut, loadFlag);
712  return true;
713 }
714 
716 {
717  return d->actionDefaultShortcuts.value(action);
718 }
719 
721 {
722  return d->actionShortcuts.value(action);
723 }
724 
725 QList<QKeySequence> KGlobalAccel::globalShortcut(const QString &componentName, const QString &actionId) const
726 {
727  if (!active()) {
728  return {};
729  }
730  // see also d->updateGlobalShortcut(action, KGlobalAccelPrivate::ActiveShortcut, KGlobalAccel::Autoloading);
731 
732  // how componentName and actionId map to QAction, e.g:
733  // action->setProperty("componentName", "kwin");
734  // action->setObjectName("Kill Window");
735 
736  const QList<int> result = self()->d->iface()->shortcut({componentName, actionId, QString(), QString()});
737  const QList<QKeySequence> scResult(d->shortcutFromIntList(result));
738  return scResult;
739 }
740 
742 {
743  if (!active()) {
744  return;
745  }
746 
747  d->remove(action, KGlobalAccelPrivate::UnRegister);
748 }
749 
750 bool KGlobalAccel::hasShortcut(const QAction *action) const
751 {
752  if (!active()) {
753  return false;
754  }
755 
756  return d->actionShortcuts.contains(action) || d->actionDefaultShortcuts.contains(action);
757 }
758 
759 #if KGLOBALACCEL_BUILD_DEPRECATED_SINCE(5, 9)
761 {
762  return QObject::eventFilter(watched, event);
763 }
764 #endif
765 
767 {
768  if (!active()) {
769  return false;
770  }
771 
773  return g->d->setShortcutWithDefault(action, shortcut, Autoloading);
774 }
775 
777 {
778  return KGlobalAccel::setGlobalShortcut(action, QList<QKeySequence>() << shortcut);
779 }
780 
781 bool KGlobalAccelPrivate::setShortcutWithDefault(QAction *action, const QList<QKeySequence> &shortcut, KGlobalAccel::GlobalShortcutLoading loadFlag)
782 {
783  if (!active()) {
784  return false;
785  }
786 
787  if (checkGarbageKeycode(shortcut)) {
788  return false;
789  }
790 
791  if (!doRegister(action)) {
792  return false;
793  }
794 
795  actionDefaultShortcuts.insert(action, shortcut);
796  actionShortcuts.insert(action, shortcut);
797  updateGlobalShortcut(action, KGlobalAccelPrivate::DefaultShortcut | KGlobalAccelPrivate::ActiveShortcut, loadFlag);
798  return true;
799 }
800 
801 #include "moc_kglobalaccel.cpp"
bool eventFilter(QObject *watched, QEvent *event) override
void removeAllShortcuts(QAction *action)
Unregister and remove all defined global shortcuts for the given action.
QDBusReply< void > startService(const QString &name)
void globalShortcutChanged(QAction *action, const QKeySequence &seq)
Emitted when the global shortcut is changed.
QDBusMessage call(const QDBusMessage &message, QDBus::CallMode mode, int timeout) const const
QDBusConnectionInterface * interface() const const
const T & at(int i) const const
QString name() const const
static bool cleanComponent(const QString &componentUnique)
Clean the shortcuts for component componentUnique.
bool isValid() const const
void serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner)
QDBusConnection sessionBus()
QDBusReply< bool > isServiceRegistered(const QString &serviceName) const const
bool isEnabled() const
No effect.
QString tr(const char *sourceText, const char *disambiguation, int n)
Q_SCRIPTABLE bool isActive() const
Check if the component is currently active.
Definition: component.cpp:257
Components Unique Name (ID)
Definition: kglobalaccel.h:54
int size() const const
void trigger()
T value(int i) const const
virtual bool event(QEvent *e)
int count(const T &value) const const
QList< QKeySequence > globalShortcut(const QString &componentName, const QString &actionId) const
Retrieves the shortcut as defined in global settings by componentName (e.g.
void append(const T &value)
QVariant property(const char *name) const const
void setWindowTitle(const QString &title)
QDBusReply::Type value() const const
bool isEmpty() const const
bool isEmpty() const const
void setText(const QString &text)
QList< QKeySequence > shortcut(const QAction *action) const
Get the global shortcut for this action, if one exists.
virtual bool eventFilter(QObject *watched, QEvent *event)
T & first()
Actions Unique Name(ID)
Definition: kglobalaccel.h:55
static QStringList findActionNameSystemwide(const QKeySequence &seq)
virtual int exec() override
const QDBusError & error()
static QList< KGlobalShortcutInfo > getGlobalShortcutsByKey(const QKeySequence &seq)
Returns a list of global shortcuts registered for the shortcut .
static KGlobalAccel * self()
Returns (and creates if necessary) the singleton instance.
bool setDefaultShortcut(QAction *action, const QList< QKeySequence > &shortcut, GlobalShortcutLoading loadFlag=Autoloading)
Assign a default global shortcut for a given QAction.
QString toString(QKeySequence::SequenceFormat format) const const
bool hasShortcut(const QAction *action) const
Returns true if a shortcut or a default shortcut has been registered for the given action...
static void activateGlobalShortcutContext(const QString &contextUnique, const QString &contextFriendly, const QString &programName)
Set global shortcut context.
Actions Friendly Translated Name.
Definition: kglobalaccel.h:57
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
T & last()
void removeLast()
void setEnabled(bool enabled)
No effect.
bool toBool() const const
bool isValid() const const
static bool promptStealShortcutSystemwide(QWidget *parent, const QList< KGlobalShortcutInfo > &shortcuts, const QKeySequence &seq)
Show a messagebox to inform the user that a global shortcut is already occupied, and ask to take it a...
bool setProperty(const char *name, const QVariant &value)
void addButton(QAbstractButton *button, QMessageBox::ButtonRole role)
QDBusError lastError() const const
QList< QKeySequence > defaultShortcut(const QAction *action) const
Get the global default shortcut for this action, if one exists.
void clear()
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
static void stealShortcutSystemwide(const QKeySequence &seq)
Take away the given shortcut from the named action it belongs to.
GlobalShortcutLoading
An enum about global shortcut setter semantics.
Definition: kglobalaccel.h:41
static bool isComponentActive(const QString &componentName)
Check if component is active.
QString toString() const const
Look up the action in global settings (using its main component&#39;s name and text()) and set the shortc...
Definition: kglobalaccel.h:45
bool setShortcut(QAction *action, const QList< QKeySequence > &shortcut, GlobalShortcutLoading loadFlag=Autoloading)
Assign a global shortcut for the given action.
static bool isGlobalShortcutAvailable(const QKeySequence &seq, const QString &component=QString())
Check if the shortcut is available for the component.
QString applicationDisplayName()
Components Friendly Translated Name.
Definition: kglobalaccel.h:56
QDBusMessage createMethodCall(const QString &service, const QString &path, const QString &interface, const QString &method)
Configurable global shortcut support.
Definition: kglobalaccel.h:33
void destroyed(QObject *obj)
bool isEnabled() const const
static bool setGlobalShortcut(QAction *action, const QList< QKeySequence > &shortcut)
Convenient method to set both active and default shortcut.
Q_EMITQ_EMIT
QString applicationName()
QList< QStringList > allActionsForComponent(const QStringList &actionId)
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
QList< QStringList > allMainComponents()
Return the unique and common names of all main components that have global shortcuts.
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.