00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "kglobalaccel.h"
00023 #include "kglobalaccel_p.h"
00024 #include "kdedglobalaccel.h"
00025
00026
00027 #ifdef Q_WS_X11
00028 #include "kglobalaccel_x11.h"
00029 #elif defined(Q_WS_MACX)
00030 #include "kglobalaccel_mac.h"
00031 #elif defined(Q_WS_WIN)
00032 #include "kglobalaccel_win.h"
00033 #elif defined(Q_WS_QWS)
00034 #include "kglobalaccel_qws.h"
00035 #else
00036 #include "kglobalaccel_emb.h"
00037 #endif
00038
00039 #include <QtCore/QCoreApplication>
00040 #include <QtDBus/QDBusInterface>
00041 #include <QtDBus/QDBusMetaType>
00042 #ifdef Q_WS_X11
00043 #include <QtGui/QX11Info>
00044 #include <netwm_def.h>
00045 #include <X11/X.h>
00046 #include <fixx11h.h>
00047 #endif
00048
00049 #include <kdebug.h>
00050 #include <klocale.h>
00051 #include <ktoolinvocation.h>
00052 #include <kaboutdata.h>
00053 #include <kcomponentdata.h>
00054 #include <kconfig.h>
00055 #include <kconfiggroup.h>
00056 #include <kglobal.h>
00057 #include "kaction.h"
00058 #include "kaction_p.h"
00059 #include "kmessagebox.h"
00060 #include "kshortcut.h"
00061
00062
00063
00064 enum actionIdFields
00065 {
00066 ComponentUnique = 0,
00067 ActionUnique = 1,
00068 ComponentFriendly = 2,
00069 ActionFriendly = 3
00070 };
00071
00072
00073 KGlobalAccelPrivate::KGlobalAccelPrivate(KGlobalAccel *q)
00074 : isUsingForeignComponentName(false),
00075 enabled(true),
00076 iface("org.kde.kded", "/modules/kdedglobalaccel", QDBusConnection::sessionBus())
00077 {
00078
00079 QDBusConnectionInterface* bus = QDBusConnection::sessionBus().interface();
00080 if (!bus->isServiceRegistered("org.kde.kded")) {
00081 KToolInvocation::klauncher();
00082 }
00083 QObject::connect(bus, SIGNAL(serviceOwnerChanged(QString, QString, QString)),
00084 q, SLOT(_k_serviceOwnerChanged(QString, QString, QString)));
00085 }
00086
00087 void KGlobalAccelPrivate::readComponentData(const KComponentData &componentData)
00088 {
00089 Q_ASSERT(!componentData.componentName().isEmpty());
00090
00091 mainComponent = componentData;
00092 if (componentData.aboutData()->programName().isEmpty()) {
00093 kDebug(123) << componentData.componentName() << " has empty programName()";
00094 }
00095 }
00096
00097
00098 KGlobalAccel::KGlobalAccel()
00099 : d(new KGlobalAccelPrivate(this))
00100 {
00101 qDBusRegisterMetaType<QList<int> >();
00102
00103 connect(&d->iface, SIGNAL(invokeAction(const QStringList &, qlonglong)),
00104 SLOT(_k_invokeAction(const QStringList &, qlonglong)));
00105 connect(&d->iface, SIGNAL(yourShortcutGotChanged(const QStringList &, const QList<int> &)),
00106 SLOT(_k_shortcutGotChanged(const QStringList &, const QList<int> &)));
00107
00108 if (KGlobal::hasMainComponent()) {
00109 d->readComponentData( KGlobal::mainComponent() );
00110 }
00111 }
00112
00113
00114 KGlobalAccel::~KGlobalAccel()
00115 {
00116
00117 delete d;
00118 }
00119
00120
00121 bool KGlobalAccel::isEnabled() const
00122 {
00123 return d->enabled;
00124 }
00125
00126
00127 void KGlobalAccel::setEnabled(bool enabled)
00128 {
00129 d->enabled = enabled;
00130
00131
00132 #if 0
00133 if (enabled) {
00134 foreach (KAction* action, d->actionsWithGlobalShortcuts)
00135 checkAction(action);
00136
00137 } else {
00138 foreach (int key, d->grabbedKeys.keys())
00139 d->impl->grabKey(key, false);
00140 d->grabbedActions.clear();
00141 d->grabbedKeys.clear();
00142 }
00143 #endif
00144 }
00145
00146
00147 void KGlobalAccel::overrideMainComponentData(const KComponentData &kcd)
00148 {
00149 d->readComponentData(kcd);
00150 d->isUsingForeignComponentName = true;
00151 }
00152
00153
00154 KGlobalAccel *KGlobalAccel::self()
00155 {
00156 K_GLOBAL_STATIC(KGlobalAccel, s_instance)
00157 return s_instance;
00158 }
00159
00160
00161 void KGlobalAccelPrivate::doRegister(KAction *action)
00162 {
00163 if (!action || action->objectName().isEmpty()) {
00164 return;
00165 }
00166
00167 const bool isRegistered = actions.contains(action);
00168 if (isRegistered)
00169 return;
00170
00171
00172
00173 if (isUsingForeignComponentName) {
00174 action->d->componentData = mainComponent;
00175 }
00176 QStringList actionId = makeActionId(action);
00177
00178 nameToAction.insertMulti(actionId.at(ActionUnique), action);
00179 actions.insert(action);
00180 iface.doRegister(actionId);
00181 }
00182
00183
00184 void KGlobalAccelPrivate::remove(KAction *action, Removal removal)
00185 {
00186 if (!action || action->objectName().isEmpty()) {
00187 return;
00188 }
00189
00190 const bool isRegistered = actions.contains(action);
00191 if (!isRegistered) {
00192 return;
00193 }
00194
00195 QStringList actionId = makeActionId(action);
00196
00197 nameToAction.remove(actionId.at(ActionUnique), action);
00198 actions.remove(action);
00199
00200 if (removal == UnRegister) {
00201
00202
00203 iface.unRegister(actionId);
00204 } else {
00205
00206
00207 if (!action->property("isConfigurationAction").toBool()) {
00208 iface.setInactive(actionId);
00209 }
00210 }
00211 }
00212
00213
00214 void KGlobalAccelPrivate::updateGlobalShortcut(KAction *action, uint flags)
00215 {
00216
00217
00218 if (!action || action->objectName().isEmpty()) {
00219 return;
00220 }
00221
00222 QStringList actionId = makeActionId(action);
00223 const KShortcut activeShortcut = action->globalShortcut();
00224 const KShortcut defaultShortcut = action->globalShortcut(KAction::DefaultShortcut);
00225
00226 uint setterFlags = 0;
00227 if (flags & KAction::NoAutoloading) {
00228 setterFlags |= KdedGlobalAccel::NoAutoloading;
00229 }
00230
00231 if (flags & KAction::ActiveShortcut) {
00232 bool isConfigurationAction = isUsingForeignComponentName
00233 || action->property("isConfigurationAction").toBool();
00234 uint activeSetterFlags = setterFlags;
00235
00236
00237 if (!isConfigurationAction) {
00238 activeSetterFlags |= KdedGlobalAccel::SetPresent;
00239 }
00240
00241
00242 const QList<int> result = iface.setShortcut(
00243 actionId,
00244 intListFromShortcut(activeShortcut),
00245 activeSetterFlags);
00246
00247 const KShortcut scResult(shortcutFromIntList(result));
00248
00249 if (isConfigurationAction && (flags & KAction::NoAutoloading)) {
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260 iface.setForeignShortcut(actionId, result);
00261 }
00262 if (scResult != activeShortcut) {
00263
00264
00265 action->d->setActiveGlobalShortcutNoEnable(scResult);
00266 }
00267 }
00268
00269 if (flags & KAction::DefaultShortcut) {
00270 iface.setShortcut(actionId, intListFromShortcut(defaultShortcut),
00271 setterFlags | KdedGlobalAccel::IsDefault);
00272 }
00273 }
00274
00275
00276 QStringList KGlobalAccelPrivate::makeActionId(const KAction *action)
00277 {
00278 QStringList ret(componentUniqueForAction(action));
00279 Q_ASSERT(!ret.at(ComponentUnique).isEmpty());
00280 Q_ASSERT(!action->objectName().isEmpty());
00281 ret.append(action->objectName());
00282 ret.append(componentFriendlyForAction(action));
00283 ret.append(action->text());
00284 return ret;
00285 }
00286
00287
00288 QList<int> KGlobalAccelPrivate::intListFromShortcut(const KShortcut &cut)
00289 {
00290 QList<int> ret;
00291 ret.append(cut.primary()[0]);
00292 ret.append(cut.alternate()[0]);
00293 while (!ret.isEmpty() && ret.last() == 0)
00294 ret.removeLast();
00295 return ret;
00296 }
00297
00298
00299 KShortcut KGlobalAccelPrivate::shortcutFromIntList(const QList<int> &list)
00300 {
00301 KShortcut ret;
00302 if (list.count() > 0)
00303 ret.setPrimary(list[0]);
00304 if (list.count() > 1)
00305 ret.setAlternate(list[1]);
00306 return ret;
00307 }
00308
00309
00310 QString KGlobalAccelPrivate::componentUniqueForAction(const KAction *action)
00311 {
00312 Q_ASSERT(action->d->componentData.isValid());
00313 return action->d->componentData.componentName();
00314 }
00315
00316
00317 QString KGlobalAccelPrivate::componentFriendlyForAction(const KAction *action)
00318 {
00319 Q_ASSERT(action->d->componentData.isValid());
00320 return action->d->componentData.aboutData()->programName();
00321 }
00322
00323
00324 void KGlobalAccelPrivate::_k_invokeAction(const QStringList &actionId, qlonglong timestamp)
00325 {
00326
00327
00328 if (isUsingForeignComponentName ) {
00329 return;
00330 }
00331
00332 KAction *action = 0;
00333 QList<KAction *> candidates = nameToAction.values(actionId.at(ActionUnique));
00334 foreach (KAction *const a, candidates) {
00335 if (componentUniqueForAction(a) == actionId.at(ComponentUnique)) {
00336 action = a;
00337 }
00338 }
00339
00340
00341
00342
00343
00344 if (!action || !action->isEnabled()
00345 || action->property("isConfigurationAction").toBool()) {
00346 return;
00347 }
00348
00349 #ifdef Q_WS_X11
00350
00351
00352
00353
00354 if( NET::timestampCompare(timestamp, QX11Info::appTime()) > 0)
00355 QX11Info::setAppTime(timestamp);
00356 if( NET::timestampCompare(timestamp, QX11Info::appUserTime()) > 0)
00357 QX11Info::setAppUserTime(timestamp);
00358 #else
00359 Q_UNUSED(timestamp);
00360 #endif
00361
00362 action->trigger();
00363 }
00364
00365 void KGlobalAccelPrivate::_k_shortcutGotChanged(const QStringList &actionId,
00366 const QList<int> &keys)
00367 {
00368 KAction *action = nameToAction.value(actionId.at(ActionUnique));
00369 if (!action)
00370 return;
00371
00372 action->d->setActiveGlobalShortcutNoEnable(shortcutFromIntList(keys));
00373 }
00374
00375 void KGlobalAccelPrivate::_k_serviceOwnerChanged(const QString &name, const QString &oldOwner,
00376 const QString &newOwner)
00377 {
00378 Q_UNUSED(oldOwner);
00379 if (name == QLatin1String("org.kde.kded") && !newOwner.isEmpty()) {
00380
00381 reRegisterAll();
00382 }
00383 }
00384
00385 void KGlobalAccelPrivate::reRegisterAll()
00386 {
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 QSet<KAction *> allActions = actions;
00397 nameToAction.clear();
00398 actions.clear();
00399 foreach(KAction *const action, allActions) {
00400 doRegister(action);
00401 updateGlobalShortcut(action, KAction::Autoloading | KAction::ActiveShortcut);
00402 }
00403 }
00404
00405
00406 QList<QStringList> KGlobalAccel::allMainComponents()
00407 {
00408 return d->iface.allMainComponents();
00409 }
00410
00411
00412 QList<QStringList> KGlobalAccel::allActionsForComponent(const QStringList &actionId)
00413 {
00414 return d->iface.allActionsForComponent(actionId);
00415 }
00416
00417
00418
00419 QStringList KGlobalAccel::findActionNameSystemwide(const QKeySequence &seq)
00420 {
00421 return self()->d->iface.action(seq[0]);
00422 }
00423
00424
00425
00426 bool KGlobalAccel::promptStealShortcutSystemwide(QWidget *parent, const QStringList &actionIdentifier,
00427 const QKeySequence &seq)
00428 {
00429 if (actionIdentifier.size() < 4) {
00430 return false;
00431 }
00432 QString title = i18n("Conflict with Global Shortcut");
00433 QString message = i18n("The '%1' key combination has already been allocated "
00434 "to the global action \"%2\" in %3.\n"
00435 "Do you want to reassign it from that action to the current one?",
00436 seq.toString(), actionIdentifier.at(ActionFriendly),
00437 actionIdentifier.at(ComponentFriendly));
00438
00439 return KMessageBox::warningContinueCancel(parent, message, title, KGuiItem(i18n("Reassign")))
00440 == KMessageBox::Continue;
00441 }
00442
00443
00444
00445 void KGlobalAccel::stealShortcutSystemwide(const QKeySequence &seq)
00446 {
00447
00448 const QStringList actionId = self()->d->iface.action(seq[0]);
00449 if (actionId.size() < 4)
00450 return;
00451 QList<int> sc = self()->d->iface.shortcut(actionId);
00452
00453 for (int i = 0; i < sc.count(); i++)
00454 if (sc[i] == seq[0])
00455 sc[i] = 0;
00456
00457 self()->d->iface.setForeignShortcut(actionId, sc);
00458 }
00459
00460 #include "kglobalaccel.moc"
00461 #include "kdedglobalaccel_interface.moc"