delay a few things on startup, such as setting the visibility mode, which ensures...
[personal-kdebase.git] / runtime / kdedglobalaccel / kdedglobalaccel.cpp
blob14d6fbfb5a17e0b93dc48d967269e645329d89fb
1 /*
2 This file is part of the KDE libraries
4 Copyright (c) 2007 Andreas Hartmetz <ahartmetz@gmail.com>
5 Copyright (c) 2007 Michael Jansen <kde@michael-jansen.biz>
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
23 #include "kdedglobalaccel.h"
25 #include "component.h"
26 #include "globalshortcut.h"
27 #include "globalshortcutcontext.h"
28 #include "globalshortcutsregistry.h"
30 #include <QtCore/QTimer>
31 #include <QtCore/QMetaMethod>
32 #include <QtDBus/QDBusMetaType>
33 #include <QtDBus/QDBusObjectPath>
35 #include "kglobalaccel.h"
36 #include "kglobalsettings.h"
37 #include "kdebug.h"
39 #include "kpluginfactory.h"
40 #include "kpluginloader.h"
42 K_PLUGIN_FACTORY(KdedGlobalAccelFactory,
43 registerPlugin<KdedGlobalAccel>();
45 K_EXPORT_PLUGIN(KdedGlobalAccelFactory("globalaccel"))
47 struct KdedGlobalAccelPrivate
49 GlobalShortcut *findAction(const QStringList &actionId) const;
50 GlobalShortcut *addAction(const QStringList &actionId);
51 KdeDGlobalAccel::Component *component(const QStringList &actionId) const;
52 QTimer writeoutTimer;
54 void splitComponent(QString &component, QString &context) const
56 context = "default";
57 if (component.indexOf('|')!=-1)
59 QStringList tmp = component.split("|");
60 Q_ASSERT(tmp.size()==2);
61 component= tmp.at(0);
62 context= tmp.at(1);
66 void _k_initializeDBus(const QDBusObjectPath &path);
69 void KdedGlobalAccelPrivate::_k_initializeDBus(const QDBusObjectPath &path)
71 GlobalShortcutsRegistry::self()->setDBusPath(QDBusObjectPath(path));
72 GlobalShortcutsRegistry::self()->loadSettings();
76 GlobalShortcut *KdedGlobalAccelPrivate::findAction(const QStringList &actionId) const
78 // Check if actionId is valid
79 if (actionId.size() != 4)
81 kDebug() << "Invalid! '" << actionId << "'";
82 return NULL;
85 QString componentUnique = actionId.at(KGlobalAccel::ComponentUnique);
87 KdeDGlobalAccel::Component *component;
88 QString contextUnique;
89 if (componentUnique.indexOf('|')==-1)
91 component = GlobalShortcutsRegistry::self()->getComponent( componentUnique);
92 if (component) contextUnique = component->currentContext()->uniqueName();
94 else
96 splitComponent(componentUnique, contextUnique);
97 component = GlobalShortcutsRegistry::self()->getComponent( componentUnique);
100 if (!component)
102 #ifdef KDEDGLOBALACCEL_TRACE
103 kDebug() << componentUnique << "not found";
104 #endif
105 return NULL;
108 GlobalShortcut *shortcut = component
109 ? component->getShortcutByName(actionId.at(KGlobalAccel::ActionUnique), contextUnique)
110 : NULL;
112 #ifdef KDEDGLOBALACCEL_TRACE
113 if (shortcut)
115 kDebug() << componentUnique
116 << contextUnique
117 << shortcut->uniqueName();
119 else
121 kDebug() << "No match for" << actionId;
123 #endif
124 return shortcut;
128 KdeDGlobalAccel::Component *KdedGlobalAccelPrivate::component(const QStringList &actionId) const
130 // Get the component for the action. If we have none create a new one
131 KdeDGlobalAccel::Component *component = GlobalShortcutsRegistry::self()->getComponent(actionId.at(KGlobalAccel::ComponentUnique));
132 if (!component)
134 component = new KdeDGlobalAccel::Component(
135 actionId.at(KGlobalAccel::ComponentUnique),
136 actionId.at(KGlobalAccel::ComponentFriendly),
137 GlobalShortcutsRegistry::self());
138 Q_ASSERT(component);
140 return component;
144 GlobalShortcut *KdedGlobalAccelPrivate::addAction(const QStringList &actionId)
146 Q_ASSERT(actionId.size() >= 4);
148 QString componentUnique = actionId.at(KGlobalAccel::ComponentUnique);
149 QString contextUnique = "default";
151 if (componentUnique.indexOf("|")!=-1) {
152 QStringList tmp = componentUnique.split("|");
153 Q_ASSERT(tmp.size()==2);
154 componentUnique = tmp.at(0);
155 contextUnique = tmp.at(1);
158 QStringList actionIdTmp = actionId;
159 actionIdTmp.replace(KGlobalAccel::ComponentUnique, componentUnique);
161 // Create the component if necessary
162 KdeDGlobalAccel::Component *component = this->component(actionIdTmp);
163 Q_ASSERT(component);
165 // Create the context if necessary
166 if (component->getShortcutContexts().count(contextUnique)==0) {
167 component->createGlobalShortcutContext(contextUnique);
170 Q_ASSERT(!component->getShortcutByName(componentUnique, contextUnique));
172 return new GlobalShortcut(
173 actionId.at(KGlobalAccel::ActionUnique),
174 actionId.at(KGlobalAccel::ActionFriendly),
175 component->shortcutContext(contextUnique));
178 Q_DECLARE_METATYPE(QStringList)
180 KdedGlobalAccel::KdedGlobalAccel(QObject* parent, const QList<QVariant>&)
181 : KDEDModule(parent),
182 d(new KdedGlobalAccelPrivate)
184 qDBusRegisterMetaType< QList<int> >();
185 qDBusRegisterMetaType< QList<QDBusObjectPath> >();
186 qDBusRegisterMetaType< QList<QStringList> >();
187 qDBusRegisterMetaType<QStringList>();
188 qDBusRegisterMetaType<KGlobalShortcutInfo>();
189 qDBusRegisterMetaType< QList<KGlobalShortcutInfo> >();
191 GlobalShortcutsRegistry *reg = GlobalShortcutsRegistry::self();
192 Q_ASSERT(reg);
194 connect(&d->writeoutTimer, SIGNAL(timeout()),
195 reg, SLOT(writeSettings()));
197 connect(this, SIGNAL(moduleRegistered(const QDBusObjectPath &)),
198 this, SLOT(_k_initializeDBus(const QDBusObjectPath &)));
200 d->writeoutTimer.setSingleShot(true);
201 connect(this, SIGNAL(moduleDeleted(KDEDModule *)),
202 reg, SLOT(writeSettings()));
204 connect(reg, SIGNAL(invokeAction(const QStringList &, qlonglong)),
205 SIGNAL(invokeAction(const QStringList &, qlonglong)));
207 connect(KGlobalSettings::self(), SIGNAL(blockShortcuts(int)),
208 SLOT(blockGlobalShortcuts(int)));
212 KdedGlobalAccel::~KdedGlobalAccel()
214 // Unregister all currently registered actions. Enables the module to be
215 // loaded / unloaded by kded.
216 GlobalShortcutsRegistry::self()->deactivateShortcuts();
217 delete d;
220 QList<QStringList> KdedGlobalAccel::allMainComponents() const
222 QList<QStringList> ret;
223 QStringList emptyList;
224 for (int i = 0; i < 4; i++) {
225 emptyList.append(QString());
228 foreach (const KdeDGlobalAccel::Component *component, GlobalShortcutsRegistry::self()->allMainComponents()) {
229 QStringList actionId(emptyList);
230 actionId[KGlobalAccel::ComponentUnique] = component->uniqueName();
231 actionId[KGlobalAccel::ComponentFriendly] = component->friendlyName();
232 ret.append(actionId);
235 return ret;
239 QList<QStringList> KdedGlobalAccel::allActionsForComponent(const QStringList &actionId) const
241 //### Would it be advantageous to sort the actions by unique name?
242 QList<QStringList> ret;
244 KdeDGlobalAccel::Component *const component =
245 GlobalShortcutsRegistry::self()->getComponent(actionId[KGlobalAccel::ComponentUnique]);
246 if (!component) {
247 return ret;
250 QStringList partialId(actionId[KGlobalAccel::ComponentUnique]); //ComponentUnique
251 partialId.append(QString()); //ActionUnique
252 //Use our internal friendlyName, not the one passed in. We should have the latest data.
253 partialId.append(component->friendlyName()); //ComponentFriendly
254 partialId.append(QString()); //ActionFriendly
256 foreach (const GlobalShortcut *const shortcut, component->allShortcuts()) {
257 if (shortcut->isFresh()) {
258 // isFresh is only an intermediate state, not to be reported outside.
259 continue;
261 QStringList actionId(partialId);
262 actionId[KGlobalAccel::ActionUnique] = shortcut->uniqueName();
263 actionId[KGlobalAccel::ActionFriendly] = shortcut->friendlyName();
264 ret.append(actionId);
266 return ret;
270 QStringList KdedGlobalAccel::action(int key) const
272 GlobalShortcut *shortcut = GlobalShortcutsRegistry::self()->getShortcutByKey(key);
273 QStringList ret;
274 if (shortcut) {
275 ret.append(shortcut->context()->component()->uniqueName());
276 ret.append(shortcut->uniqueName());
277 ret.append(shortcut->context()->component()->friendlyName());
278 ret.append(shortcut->friendlyName());
280 return ret;
284 void KdedGlobalAccel::activateGlobalShortcutContext(
285 const QString &component,
286 const QString &uniqueName)
288 KdeDGlobalAccel::Component *const comp =
289 GlobalShortcutsRegistry::self()->getComponent(component);
291 comp->activateGlobalShortcutContext(uniqueName);
295 QList<QDBusObjectPath> KdedGlobalAccel::allComponents() const
297 QList<QDBusObjectPath> allComp;
299 Q_FOREACH (const KdeDGlobalAccel::Component *component,
300 GlobalShortcutsRegistry::self()->allMainComponents())
302 allComp.append(component->dbusPath());
305 return allComp;
309 void KdedGlobalAccel::blockGlobalShortcuts(int block)
311 #ifdef KDEDGLOBALACCEL_TRACE
312 kDebug() << block;
313 #endif
314 block
315 ? GlobalShortcutsRegistry::self()->deactivateShortcuts(true)
316 : GlobalShortcutsRegistry::self()->activateShortcuts();
320 QList<int> KdedGlobalAccel::shortcut(const QStringList &action) const
322 GlobalShortcut *shortcut = d->findAction(action);
323 if (shortcut)
324 return shortcut->keys();
325 return QList<int>();
329 QList<int> KdedGlobalAccel::defaultShortcut(const QStringList &action) const
331 GlobalShortcut *shortcut = d->findAction(action);
332 if (shortcut)
333 return shortcut->defaultKeys();
334 return QList<int>();
338 // This method just registers the action. Nothing else. Shortcut has to be set
339 // later.
340 void KdedGlobalAccel::doRegister(const QStringList &actionId)
342 #ifdef KDEDGLOBALACCEL_TRACE
343 kDebug() << actionId;
344 #endif
346 // Check because we would not want to add a action for an invalid
347 // actionId. findAction returns NULL in that case.
348 if (actionId.size() < 4) {
349 return;
352 GlobalShortcut *shortcut = d->findAction(actionId);
353 if (!shortcut) {
354 shortcut = d->addAction(actionId);
355 } else {
356 //a switch of locales is one common reason for a changing friendlyName
357 if ((!actionId[KGlobalAccel::ActionFriendly].isEmpty()) && shortcut->friendlyName() != actionId[KGlobalAccel::ActionFriendly]) {
358 shortcut->setFriendlyName(actionId[KGlobalAccel::ActionFriendly]);
359 scheduleWriteSettings();
361 if ((!actionId[KGlobalAccel::ComponentFriendly].isEmpty())
362 && shortcut->context()->component()->friendlyName() != actionId[KGlobalAccel::ComponentFriendly]) {
363 shortcut->context()->component()->setFriendlyName(actionId[KGlobalAccel::ComponentFriendly]);
364 scheduleWriteSettings();
370 QList<KGlobalShortcutInfo> KdedGlobalAccel::getGlobalShortcutsByKey(int key) const
372 QList<GlobalShortcut*> shortcuts =
373 GlobalShortcutsRegistry::self()->getShortcutsByKey(key);
375 QList<KGlobalShortcutInfo> rc;
376 Q_FOREACH(GlobalShortcut const*sc, shortcuts)
378 rc.append(static_cast<KGlobalShortcutInfo>(*sc));
381 return rc;
385 bool KdedGlobalAccel::isGlobalShortcutAvailable(int shortcut, const QString &component) const
387 QString realComponent = component;
388 QString context;
389 d->splitComponent(realComponent, context);
390 return GlobalShortcutsRegistry::self()->isShortcutAvailable(shortcut, realComponent, context);
394 void KdedGlobalAccel::setInactive(const QStringList &actionId)
396 #ifdef KDEDGLOBALACCEL_TRACE
397 kDebug() << actionId;
398 #endif
400 GlobalShortcut *shortcut = d->findAction(actionId);
401 if (shortcut)
402 shortcut->setIsPresent(false);
406 void KdedGlobalAccel::unRegister(const QStringList &actionId)
408 #ifdef KDEDGLOBALACCEL_TRACE
409 kDebug() << actionId;
410 #endif
412 // Stop grabbing the key
413 GlobalShortcut *shortcut = d->findAction(actionId);
414 if (shortcut) {
415 delete shortcut;
418 scheduleWriteSettings();
422 QList<int> KdedGlobalAccel::setShortcut(const QStringList &actionId,
423 const QList<int> &keys, uint flags)
425 //spare the DBus framework some work
426 const bool setPresent = (flags & SetPresent);
427 const bool isAutoloading = !(flags & NoAutoloading);
428 const bool isDefault = (flags & IsDefault);
430 GlobalShortcut *shortcut = d->findAction(actionId);
431 if (!shortcut) {
432 return QList<int>();
435 //default shortcuts cannot clash because they don't do anything
436 if (isDefault) {
437 if (shortcut->defaultKeys() != keys) {
438 shortcut->setDefaultKeys(keys);
439 scheduleWriteSettings();
441 return keys; //doesn't matter
444 if (isAutoloading && !shortcut->isFresh()) {
445 //the trivial and common case - synchronize the action from our data
446 //and exit.
447 if (!shortcut->isPresent() && setPresent) {
448 shortcut->setIsPresent(true);
450 // We are finished here. Return the list of current active keys.
451 return shortcut->keys();
454 //now we are actually changing the shortcut of the action
455 shortcut->setKeys(keys);
457 if (setPresent) {
458 shortcut->setIsPresent(true);
461 //maybe isFresh should really only be set if setPresent, but only two things should use !setPresent:
462 //- the global shortcuts KCM: very unlikely to catch KWin/etc.'s actions in isFresh state
463 //- KGlobalAccel::stealGlobalShortcutSystemwide(): only applies to actions with shortcuts
464 // which can never be fresh if created the usual way
465 shortcut->setIsFresh(false);
467 scheduleWriteSettings();
469 return shortcut->keys();
473 void KdedGlobalAccel::setForeignShortcut(const QStringList &actionId, const QList<int> &keys)
475 #ifdef KDEDGLOBALACCEL_TRACE
476 kDebug() << actionId;
477 #endif
479 GlobalShortcut *shortcut = d->findAction(actionId);
480 if (!shortcut)
481 return;
483 QList<int> newKeys = setShortcut(actionId, keys, NoAutoloading);
485 emit yourShortcutGotChanged(actionId, newKeys);
489 void KdedGlobalAccel::scheduleWriteSettings() const
491 if (!d->writeoutTimer.isActive())
492 d->writeoutTimer.start(500);
496 #include "moc_kdedglobalaccel.cpp"