KGlobalAccel

kglobalaccel.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2001, 2002 Ellis Whitehead <ellis@kde.org>
4 SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
5 SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com>
6 SPDX-FileCopyrightText: 2008 Michael Jansen <kde@michael-jansen.biz>
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
25#if WITH_X11
26#include <private/qtx11extras_p.h>
27#endif
28
29org::kde::kglobalaccel::Component *KGlobalAccelPrivate::getComponent(const QString &componentUnique, bool remember = false)
30{
31 // Check if we already have this component
32 {
33 auto component = components.value(componentUnique);
34 if (component) {
35 return component;
36 }
37 }
38
39 // Get the path for our component. We have to do that because
40 // componentUnique is probably not a valid dbus object path
41 QDBusReply<QDBusObjectPath> reply = iface()->getComponent(componentUnique);
42 if (!reply.isValid()) {
43 if (reply.error().name() == QLatin1String("org.kde.kglobalaccel.NoSuchComponent")) {
44 // No problem. The component doesn't exists. That's normal
45 return nullptr;
46 }
47
48 // An unknown error.
49 qCDebug(KGLOBALACCEL_LOG) << "Failed to get dbus path for component " << componentUnique << reply.error();
50 return nullptr;
51 }
52
53 // Now get the component
54 org::kde::kglobalaccel::Component *component =
55 new org::kde::kglobalaccel::Component(QStringLiteral("org.kde.kglobalaccel"), reply.value().path(), QDBusConnection::sessionBus(), q);
56
57 // No component no cleaning
58 if (!component->isValid()) {
59 qCDebug(KGLOBALACCEL_LOG) << "Failed to get component" << componentUnique << QDBusConnection::sessionBus().lastError();
60 return nullptr;
61 }
62
63 if (remember) {
64 // Connect to the signals we are interested in.
65 QObject::connect(component,
66 &org::kde::kglobalaccel::Component::globalShortcutPressed,
67 q,
68 [this](const QString &componentUnique, const QString &shortcutUnique, qlonglong timestamp) {
69 invokeAction(componentUnique, shortcutUnique, timestamp);
70 });
71
72 QObject::connect(component,
73 &org::kde::kglobalaccel::Component::globalShortcutReleased,
74 q,
75 [this](const QString &componentUnique, const QString &shortcutUnique, qlonglong) {
76 invokeDeactivate(componentUnique, shortcutUnique);
77 });
78
79 components[componentUnique] = component;
80 }
81
82 return component;
83}
84
85namespace
86{
87QString serviceName()
88{
89 return QStringLiteral("org.kde.kglobalaccel");
90}
91}
92
93void KGlobalAccelPrivate::cleanup()
94{
95 qDeleteAll(components);
96 delete m_iface;
97 m_iface = nullptr;
98 delete m_watcher;
99 m_watcher = nullptr;
100}
101
102KGlobalAccelPrivate::KGlobalAccelPrivate(KGlobalAccel *qq)
103 : q(qq)
104{
106 QObject::connect(m_watcher,
108 q,
109 [this](const QString &serviceName, const QString &oldOwner, const QString &newOwner) {
110 serviceOwnerChanged(serviceName, oldOwner, newOwner);
111 });
112}
113
114org::kde::KGlobalAccel *KGlobalAccelPrivate::iface()
115{
116 if (!m_iface) {
117 m_iface = new org::kde::KGlobalAccel(serviceName(), QStringLiteral("/kglobalaccel"), QDBusConnection::sessionBus());
118 // Make sure kglobalaccel is running. The iface declaration above somehow works anyway.
120 if (bus && !bus->isServiceRegistered(serviceName())) {
121 QDBusReply<void> reply = bus->startService(serviceName());
122 if (!reply.isValid()) {
123 qCritical() << "Couldn't start kglobalaccel from org.kde.kglobalaccel.service:" << reply.error();
124 }
125 }
126
127 QObject::connect(m_iface, &org::kde::KGlobalAccel::yourShortcutsChanged, q, [this](const QStringList &actionId, const QList<QKeySequence> &newKeys) {
128 shortcutsChanged(actionId, newKeys);
129 });
130 }
131 return m_iface;
132}
133
134KGlobalAccel::KGlobalAccel()
135 : d(new KGlobalAccelPrivate(this))
136{
137 qDBusRegisterMetaType<QList<int>>();
138 qDBusRegisterMetaType<QKeySequence>();
139 qDBusRegisterMetaType<QList<QKeySequence>>();
140 qDBusRegisterMetaType<QList<QStringList>>();
141 qDBusRegisterMetaType<KGlobalShortcutInfo>();
142 qDBusRegisterMetaType<QList<KGlobalShortcutInfo>>();
143 qDBusRegisterMetaType<KGlobalAccel::MatchType>();
144}
145
146KGlobalAccel::~KGlobalAccel()
147{
148 delete d;
149}
150
151// static
152bool KGlobalAccel::cleanComponent(const QString &componentUnique)
153{
154 org::kde::kglobalaccel::Component *component = self()->getComponent(componentUnique);
155 if (!component) {
156 return false;
157 }
158
159 return component->cleanUp();
160}
161
162// static
163bool KGlobalAccel::isComponentActive(const QString &componentUnique)
164{
165 org::kde::kglobalaccel::Component *component = self()->getComponent(componentUnique);
166 if (!component) {
167 return false;
168 }
169
170 return component->isActive();
171}
172
173org::kde::kglobalaccel::Component *KGlobalAccel::getComponent(const QString &componentUnique)
174{
175 return d->getComponent(componentUnique);
176}
177
178class KGlobalAccelSingleton
179{
180public:
181 KGlobalAccelSingleton();
182
183 KGlobalAccel instance;
184};
185
186Q_GLOBAL_STATIC(KGlobalAccelSingleton, s_instance)
187
188KGlobalAccelSingleton::KGlobalAccelSingleton()
189{
190 qAddPostRoutine([]() {
191 s_instance->instance.d->cleanup();
192 });
193}
194
196{
197 return &s_instance()->instance;
198}
199
200bool KGlobalAccelPrivate::doRegister(QAction *action)
201{
202 if (!action || action->objectName().isEmpty() || action->objectName().startsWith(QLatin1String("unnamed-"))) {
203 qWarning() << "Attempt to set global shortcut for action without objectName()."
204 " Read the setGlobalShortcut() documentation.";
205 return false;
206 }
207
208 const bool isRegistered = actions.contains(action);
209 if (isRegistered) {
210 return true;
211 }
212
213 QStringList actionId = makeActionId(action);
214
215 nameToAction.insert(actionId.at(KGlobalAccel::ActionUnique), action);
216 actions.insert(action);
217 iface()->doRegister(actionId);
218
219 QObject::connect(action, &QObject::destroyed, q, [this, action](QObject *) {
220 if (actions.contains(action) && (actionShortcuts.contains(action) || actionDefaultShortcuts.contains(action))) {
221 remove(action, KGlobalAccelPrivate::SetInactive);
222 }
223 });
224
225 return true;
226}
227
228void KGlobalAccelPrivate::remove(QAction *action, Removal removal)
229{
230 if (!action || action->objectName().isEmpty()) {
231 return;
232 }
233
234 const bool isRegistered = actions.contains(action);
235 if (!isRegistered) {
236 return;
237 }
238
239 QStringList actionId = makeActionId(action);
240
241 nameToAction.remove(actionId.at(KGlobalAccel::ActionUnique), action);
242 actions.remove(action);
243
244 if (removal == UnRegister) {
245 // Complete removal of the shortcut is requested
246 // (forgetGlobalShortcut)
247 unregister(actionId);
248 } else {
249 // If the action is a configurationAction wen only remove it from our
250 // internal registry. That happened above.
251
252 // If we are merely marking a callback as inactive there is nothing for kglobalaccel to do if kglobalaccel is not running
253 // this can happen on shutdown where all apps and kglobalaccel are all torn down at once
254 // For this reason we turn off the autostart flag in the DBus message call
255
256 if (!action->property("isConfigurationAction").toBool()) {
257 // If it's a session shortcut unregister it.
258 if (action->objectName().startsWith(QLatin1String("_k_session:"))) {
259 unregister(actionId);
260 } else {
261 setInactive(actionId);
262 }
263 }
264 }
265
266 actionDefaultShortcuts.remove(action);
267 actionShortcuts.remove(action);
268}
269
270void KGlobalAccelPrivate::unregister(const QStringList &actionId)
271{
272 const auto component = actionId.at(KGlobalAccel::ComponentUnique);
273 const auto action = actionId.at(KGlobalAccel::ActionUnique);
274
275 auto message = QDBusMessage::createMethodCall(iface()->service(), iface()->path(), iface()->interface(), QStringLiteral("unregister"));
276 message.setArguments({component, action});
277 message.setAutoStartService(false);
279}
280
281void KGlobalAccelPrivate::setInactive(const QStringList &actionId)
282{
283 auto message = QDBusMessage::createMethodCall(iface()->service(), iface()->path(), iface()->interface(), QStringLiteral("setInactive"));
284 message.setArguments({actionId});
285 message.setAutoStartService(false);
287}
288
289void KGlobalAccelPrivate::updateGlobalShortcut(/*const would be better*/ QAction *action,
290 ShortcutTypes actionFlags,
292{
293 // No action or no objectname -> Do nothing
294 if (!action || action->objectName().isEmpty()) {
295 return;
296 }
297
298 QStringList actionId = makeActionId(action);
299
300 uint setterFlags = 0;
301 if (globalFlags & NoAutoloading) {
302 setterFlags |= NoAutoloading;
303 }
304
305 if (actionFlags & ActiveShortcut) {
306 const QList<QKeySequence> activeShortcut = actionShortcuts.value(action);
307 bool isConfigurationAction = action->property("isConfigurationAction").toBool();
308 uint activeSetterFlags = setterFlags;
309
310 // setPresent tells kglobalaccel that the shortcut is active
311 if (!isConfigurationAction) {
312 activeSetterFlags |= SetPresent;
313 }
314
315 // Sets the shortcut, returns the active/real keys
316 const auto result = iface()->setShortcutKeys(actionId, activeShortcut, activeSetterFlags);
317
318 // Make sure we get informed about changes in the component by kglobalaccel
319 getComponent(componentUniqueForAction(action), true);
320
321 // Create a shortcut from the result
322 const QList<QKeySequence> scResult(result);
323
324 if (isConfigurationAction && (globalFlags & NoAutoloading)) {
325 // If this is a configuration action and we have set the shortcut,
326 // inform the real owner of the change.
327 // Note that setForeignShortcut will cause a signal to be sent to applications
328 // even if it did not "see" that the shortcut has changed. This is Good because
329 // at the time of comparison (now) the action *already has* the new shortcut.
330 // We called setShortcut(), remember?
331 // Also note that we will see our own signal so we may not need to call
332 // setActiveGlobalShortcutNoEnable - shortcutGotChanged() does it.
333 // In practice it's probably better to get the change propagated here without
334 // DBus delay as we do below.
335 iface()->setForeignShortcutKeys(actionId, result);
336 }
337 if (scResult != activeShortcut) {
338 // If kglobalaccel returned a shortcut that differs from the one we
339 // sent, use that one. There must have been clashes or some other problem.
340 actionShortcuts.insert(action, scResult);
341 Q_EMIT q->globalShortcutChanged(action, scResult.isEmpty() ? QKeySequence() : scResult.first());
342 }
343 }
344
345 if (actionFlags & DefaultShortcut) {
346 const QList<QKeySequence> defaultShortcut = actionDefaultShortcuts.value(action);
347 iface()->setShortcutKeys(actionId, defaultShortcut, setterFlags | IsDefault);
348 }
349}
350
351QStringList KGlobalAccelPrivate::makeActionId(const QAction *action)
352{
353 QStringList ret(componentUniqueForAction(action)); // Component Unique Id ( see actionIdFields )
354 Q_ASSERT(!ret.at(KGlobalAccel::ComponentUnique).isEmpty());
355 Q_ASSERT(!action->objectName().isEmpty());
356 ret.append(action->objectName()); // Action Unique Name
357 ret.append(componentFriendlyForAction(action)); // Component Friendly name
358 const QString actionText = action->text().replace(QLatin1Char('&'), QStringLiteral(""));
359 ret.append(actionText); // Action Friendly Name
360 return ret;
361}
362
363QList<int> KGlobalAccelPrivate::intListFromShortcut(const QList<QKeySequence> &cut)
364{
365 QList<int> ret;
366 for (const QKeySequence &sequence : cut) {
367 ret.append(sequence[0].toCombined());
368 }
369 while (!ret.isEmpty() && ret.last() == 0) {
370 ret.removeLast();
371 }
372 return ret;
373}
374
375QList<QKeySequence> KGlobalAccelPrivate::shortcutFromIntList(const QList<int> &list)
376{
378 ret.reserve(list.size());
379 std::transform(list.begin(), list.end(), std::back_inserter(ret), [](int i) {
380 return QKeySequence(i);
381 });
382 return ret;
383}
384
385QString KGlobalAccelPrivate::componentUniqueForAction(const QAction *action)
386{
387 if (!action->property("componentName").isValid()) {
389 } else {
390 return action->property("componentName").toString();
391 }
392}
393
394QString KGlobalAccelPrivate::componentFriendlyForAction(const QAction *action)
395{
396 QString property = action->property("componentDisplayName").toString();
397 if (!property.isEmpty()) {
398 return property;
399 }
402 }
404}
405
406#if WITH_X11
407int timestampCompare(unsigned long time1_, unsigned long time2_) // like strcmp()
408{
409 quint32 time1 = time1_;
410 quint32 time2 = time2_;
411 if (time1 == time2) {
412 return 0;
413 }
414 return quint32(time1 - time2) < 0x7fffffffU ? 1 : -1; // time1 > time2 -> 1, handle wrapping
415}
416#endif
417
418QAction *KGlobalAccelPrivate::findAction(const QString &componentUnique, const QString &actionUnique)
419{
420 QAction *action = nullptr;
421 const QList<QAction *> candidates = nameToAction.values(actionUnique);
422 for (QAction *const a : candidates) {
423 if (componentUniqueForAction(a) == componentUnique) {
424 action = a;
425 }
426 }
427
428 // We do not trigger if
429 // - there is no action
430 // - the action is not enabled
431 // - the action is an configuration action
432 if (!action || !action->isEnabled() || action->property("isConfigurationAction").toBool()) {
433 return nullptr;
434 }
435 return action;
436}
437
438void KGlobalAccelPrivate::invokeAction(const QString &componentUnique, const QString &actionUnique, qlonglong timestamp)
439{
440 QAction *action = findAction(componentUnique, actionUnique);
441 if (!action) {
442 return;
443 }
444
445#if WITH_X11
446 // Update this application's X timestamp if needed.
447 // TODO The 100%-correct solution should probably be handling this action
448 // in the proper place in relation to the X events queue in order to avoid
449 // the possibility of wrong ordering of user events.
450 if (QX11Info::isPlatformX11()) {
451 if (timestampCompare(timestamp, QX11Info::appTime()) > 0) {
452 QX11Info::setAppTime(timestamp);
453 }
454 if (timestampCompare(timestamp, QX11Info::appUserTime()) > 0) {
455 QX11Info::setAppUserTime(timestamp);
456 }
457 }
458#endif
459 action->setProperty("org.kde.kglobalaccel.activationTimestamp", timestamp);
460
461 if (m_lastActivatedAction != action) {
462 Q_EMIT q->globalShortcutActiveChanged(action, true);
463 m_lastActivatedAction = action;
464 }
465 action->trigger();
466}
467
468void KGlobalAccelPrivate::invokeDeactivate(const QString &componentUnique, const QString &actionUnique)
469{
470 QAction *action = findAction(componentUnique, actionUnique);
471 if (!action) {
472 return;
473 }
474
475 m_lastActivatedAction.clear();
476
477 Q_EMIT q->globalShortcutActiveChanged(action, false);
478}
479
480void KGlobalAccelPrivate::shortcutsChanged(const QStringList &actionId, const QList<QKeySequence> &keys)
481{
482 QAction *action = nameToAction.value(actionId.at(KGlobalAccel::ActionUnique));
483 if (!action) {
484 return;
485 }
486
487 actionShortcuts.insert(action, keys);
488 Q_EMIT q->globalShortcutChanged(action, keys.isEmpty() ? QKeySequence() : keys.first());
489}
490
491void KGlobalAccelPrivate::serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
492{
493 Q_UNUSED(oldOwner);
494 if (name == QLatin1String("org.kde.kglobalaccel") && !newOwner.isEmpty()) {
495 // kglobalaccel was restarted
496 qCDebug(KGLOBALACCEL_LOG) << "detected kglobalaccel restarting, re-registering all shortcut keys";
497 reRegisterAll();
498 }
499}
500
501void KGlobalAccelPrivate::reRegisterAll()
502{
503 // We clear all our data, assume that all data on the other side is clear too,
504 // and register each action as if it just was allowed to have global shortcuts.
505 // If the kded side still has the data it doesn't matter because of the
506 // autoloading mechanism. The worst case I can imagine is that an action's
507 // shortcut was changed but the kded side died before it got the message so
508 // autoloading will now assign an old shortcut to the action. Particularly
509 // picky apps might assert or misbehave.
510 const QSet<QAction *> allActions = actions;
511 nameToAction.clear();
512 actions.clear();
513 for (QAction *const action : allActions) {
514 if (doRegister(action)) {
515 updateGlobalShortcut(action, ActiveShortcut, KGlobalAccel::Autoloading);
516 }
517 }
518}
519
521{
522 return self()->d->iface()->globalShortcutsByKey(seq, type);
523}
524
526{
527 return self()->d->iface()->globalShortcutAvailable(seq, comp);
528}
529
530// static
532{
533 if (shortcuts.isEmpty()) {
534 // Usage error. Just say no
535 return false;
536 }
537
538 QString component = shortcuts[0].componentFriendlyName();
539
540 QString message;
541 if (shortcuts.size() == 1) {
542 message = tr("The '%1' key combination is registered by application %2 for action %3.").arg(seq.toString(), component, shortcuts[0].friendlyName());
543 } else {
544 QString actionList;
545 for (const KGlobalShortcutInfo &info : shortcuts) {
546 actionList += tr("In context '%1' for action '%2'\n").arg(info.contextFriendlyName(), info.friendlyName());
547 }
548 message = tr("The '%1' key combination is registered by application %2.\n%3").arg(seq.toString(), component, actionList);
549 }
550
551 QString title = tr("Conflict With Registered Global Shortcut");
552
553 QMessageBox box(parent);
554 box.setWindowTitle(title);
555 box.setText(message);
556 box.addButton(QMessageBox::Ok)->setText(tr("Reassign"));
558
559 return box.exec() == QMessageBox::Ok;
560}
561
562// static
564{
565 // get the shortcut, remove seq, and set the new shortcut
566 const QStringList actionId = self()->d->iface()->actionList(seq);
567 if (actionId.size() < 4) { // not a global shortcut
568 return;
569 }
570 QList<QKeySequence> sc = self()->d->iface()->shortcutKeys(actionId);
571
572 for (int i = 0; i < sc.count(); i++) {
573 if (sc[i] == seq) {
574 sc[i] = QKeySequence();
575 }
576 }
577
578 self()->d->iface()->setForeignShortcutKeys(actionId, sc);
579}
580
581bool checkGarbageKeycode(const QList<QKeySequence> &shortcut)
582{
583 // protect against garbage keycode -1 that Qt sometimes produces for exotic keys;
584 // at the moment (~mid 2008) Multimedia PlayPause is one of those keys.
585 for (const QKeySequence &sequence : shortcut) {
586 for (int i = 0; i < 4; i++) {
587 if (sequence[i].toCombined() == -1) {
588 qWarning() << "Encountered garbage keycode (keycode = -1) in input, not doing anything.";
589 return true;
590 }
591 }
592 }
593 return false;
594}
595
597{
598 if (checkGarbageKeycode(shortcut)) {
599 return false;
600 }
601
602 if (!d->doRegister(action)) {
603 return false;
604 }
605
606 d->actionDefaultShortcuts.insert(action, shortcut);
607 d->updateGlobalShortcut(action, KGlobalAccelPrivate::DefaultShortcut, loadFlag);
608 return true;
609}
610
612{
613 if (checkGarbageKeycode(shortcut)) {
614 return false;
615 }
616
617 if (!d->doRegister(action)) {
618 return false;
619 }
620
621 d->actionShortcuts.insert(action, shortcut);
622 d->updateGlobalShortcut(action, KGlobalAccelPrivate::ActiveShortcut, loadFlag);
623 return true;
624}
625
627{
628 return d->actionDefaultShortcuts.value(action);
629}
630
632{
633 return d->actionShortcuts.value(action);
634}
635
636QList<QKeySequence> KGlobalAccel::globalShortcut(const QString &componentName, const QString &actionId) const
637{
638 // see also d->updateGlobalShortcut(action, KGlobalAccelPrivate::ActiveShortcut, KGlobalAccel::Autoloading);
639
640 // how componentName and actionId map to QAction, e.g:
641 // action->setProperty("componentName", "kwin");
642 // action->setObjectName("Kill Window");
643
644 const QList<QKeySequence> scResult = self()->d->iface()->shortcutKeys({componentName, actionId, QString(), QString()});
645 return scResult;
646}
647
649{
650 d->remove(action, KGlobalAccelPrivate::UnRegister);
651}
652
653bool KGlobalAccel::hasShortcut(const QAction *action) const
654{
655 return d->actionShortcuts.contains(action) || d->actionDefaultShortcuts.contains(action);
656}
657
659{
661 return g->d->setShortcutWithDefault(action, shortcut, Autoloading);
662}
663
668
669bool KGlobalAccelPrivate::setShortcutWithDefault(QAction *action, const QList<QKeySequence> &shortcut, KGlobalAccel::GlobalShortcutLoading loadFlag)
670{
671 if (checkGarbageKeycode(shortcut)) {
672 return false;
673 }
674
675 if (!doRegister(action)) {
676 return false;
677 }
678
679 actionDefaultShortcuts.insert(action, shortcut);
680 actionShortcuts.insert(action, shortcut);
681 updateGlobalShortcut(action, KGlobalAccelPrivate::DefaultShortcut | KGlobalAccelPrivate::ActiveShortcut, loadFlag);
682 return true;
683}
684
686{
687 argument.beginStructure();
688 argument << static_cast<int>(type);
689 argument.endStructure();
690 return argument;
691}
692
694{
695 argument.beginStructure();
696 int arg;
697 argument >> arg;
698 type = static_cast<KGlobalAccel::MatchType>(arg);
699 argument.endStructure();
700 return argument;
701}
702
703#include "moc_kglobalaccel.cpp"
Configurable global shortcut support.
static QList< KGlobalShortcutInfo > globalShortcutsByKey(const QKeySequence &seq, MatchType type=Equal)
Returns a list of global shortcuts registered for the shortcut seq.
bool hasShortcut(const QAction *action) const
Returns true if a shortcut or a default shortcut has been registered for the given action.
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...
static void stealShortcutSystemwide(const QKeySequence &seq)
Take away the given shortcut from the named action it belongs to.
static bool isComponentActive(const QString &componentName)
Check if component is active.
MatchType
Keysequence match semantics.
static bool cleanComponent(const QString &componentUnique)
Clean the shortcuts for component componentUnique.
static KGlobalAccel * self()
Returns (and creates if necessary) the singleton instance.
bool setShortcut(QAction *action, const QList< QKeySequence > &shortcut, GlobalShortcutLoading loadFlag=Autoloading)
Assign a global shortcut for the given action.
GlobalShortcutLoading
An enum about global shortcut setter semantics.
@ Autoloading
Look up the action in global settings (using its main component's name and text()) and set the shortc...
void removeAllShortcuts(QAction *action)
Unregister and remove all defined global shortcuts for the given action.
bool setDefaultShortcut(QAction *action, const QList< QKeySequence > &shortcut, GlobalShortcutLoading loadFlag=Autoloading)
Assign a default global shortcut for a given QAction.
static bool isGlobalShortcutAvailable(const QKeySequence &seq, const QString &component=QString())
Check if the shortcut @seq is available for the component.
static bool setGlobalShortcut(QAction *action, const QList< QKeySequence > &shortcut)
Convenient method to set both active and default shortcut.
QList< QKeySequence > shortcut(const QAction *action) const
Get the global shortcut for this action, if one exists.
QList< QKeySequence > globalShortcut(const QString &componentName, const QString &actionId) const
Retrieves the shortcut as defined in global settings by componentName (e.g.
@ ComponentUnique
Components Unique Name (ID)
@ ActionUnique
Actions Unique Name(ID)
QList< QKeySequence > defaultShortcut(const QAction *action) const
Get the global default shortcut for this action, if one exists.
Type type(const QSqlDatabase &db)
KCALENDARCORE_EXPORT QDataStream & operator>>(QDataStream &in, const KCalendarCore::Alarm::Ptr &)
QString path(const QString &relativePath)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
KGuiItem remove()
QDebug operator<<(QDebug dbg, const PerceptualColor::MultiSpinBoxSection &value)
void setText(const QString &text)
bool isEnabled() const const
void trigger()
void beginStructure()
void endStructure()
QDBusMessage call(const QDBusMessage &message, QDBus::CallMode mode, int timeout) const const
QDBusConnectionInterface * interface() const const
QDBusError lastError() const const
QDBusConnection sessionBus()
QDBusReply< bool > isServiceRegistered(const QString &serviceName) const const
QDBusReply< void > startService(const QString &name)
QString name() const const
QDBusMessage createMethodCall(const QString &service, const QString &path, const QString &interface, const QString &method)
const QDBusError & error()
bool isValid() const const
void serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner)
QString toString(SequenceFormat format) const const
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
iterator begin()
qsizetype count() const const
iterator end()
T & first()
bool isEmpty() const const
T & last()
void removeLast()
void reserve(qsizetype size)
qsizetype size() const const
T value(qsizetype i) const const
QPushButton * addButton(StandardButton button)
virtual int exec() override
void setWindowTitle(const QString &title)
void setText(const QString &text)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void destroyed(QObject *obj)
QObject * parent() const const
QVariant property(const char *name) const const
bool setProperty(const char *name, QVariant &&value)
QString tr(const char *sourceText, const char *disambiguation, int n)
void clear()
QString arg(Args &&... args) const const
bool isEmpty() const const
bool isValid() const const
bool toBool() const const
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:10:29 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.