diff --git a/kdeui/shortcuts/kglobalaccel.cpp b/kdeui/shortcuts/kglobalaccel.cpp index d7f377e63f..5f1836dddf 100644 --- a/kdeui/shortcuts/kglobalaccel.cpp +++ b/kdeui/shortcuts/kglobalaccel.cpp @@ -1,337 +1,339 @@ /* This file is part of the KDE libraries Copyright (C) 2001,2002 Ellis Whitehead Copyright (C) 2006 Hamish Rodda Copyright (C) 2007 Andreas Hartmetz This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kglobalaccel.h" #include "kglobalaccel_p.h" #include "kdedglobalaccel.h" // For KGlobalAccelImpl #ifdef Q_WS_X11 #include "kglobalaccel_x11.h" #elif defined(Q_WS_MACX) #include "kglobalaccel_mac.h" #elif defined(Q_WS_WIN) #include "kglobalaccel_win.h" #elif defined(Q_WS_QWS) #include "kglobalaccel_qws.h" #else #include "kglobalaccel_emb.h" #endif #include #include #include #ifdef Q_WS_X11 #include #include #include #include #endif #include #include #include #include #include #include #include "kaction.h" #include "kaction_p.h" #include "kactioncollection.h" #include "kmessagebox.h" #include "kshortcut.h" //TODO what was the problem that got fixed recently in the old version? - forward port if necessary KGlobalAccelPrivate::KGlobalAccelPrivate(KGlobalAccel* q) : isUsingForeignComponentName(false), enabled(true), iface("org.kde.kded", "/modules/kdedglobalaccel", QDBusConnection::sessionBus()) { // Make sure kded is running QDBusConnectionInterface* bus = QDBusConnection::sessionBus().interface(); if (!bus->isServiceRegistered("org.kde.kded")) { KToolInvocation::klauncher(); // this calls startKdeinit } QObject::connect(bus, SIGNAL(serviceOwnerChanged(QString,QString,QString)), q, SLOT(_k_serviceOwnerChanged(QString,QString,QString))); } KGlobalAccel::KGlobalAccel() : d(new KGlobalAccelPrivate(this)) { qDBusRegisterMetaType >(); connect(&d->iface, SIGNAL(invokeAction(const QStringList &)), SLOT(_k_invokeAction(const QStringList &))); connect(&d->iface, SIGNAL(yourShortcutGotChanged(const QStringList &, const QList &)), SLOT(_k_shortcutGotChanged(const QStringList &, const QList &))); if (KGlobal::hasMainComponent()) d->mainComponentName = KGlobal::mainComponent().componentName(); } KGlobalAccel::~KGlobalAccel() { //TODO *maybe* we need to ungrab/unregister all delete d; } bool KGlobalAccel::isEnabled() const { return d->enabled; } void KGlobalAccel::setEnabled( bool enabled ) { d->enabled = enabled; //TODO: implement this in KdedGlobalAccel... or not at all #if 0 if (enabled) { foreach (KAction* action, d->actionsWithGlobalShortcuts) checkAction(action); } else { foreach (int key, d->grabbedKeys.keys()) d->impl->grabKey(key, false); d->grabbedActions.clear(); d->grabbedKeys.clear(); } #endif } void KGlobalAccel::overrideMainComponentData(const KComponentData &kcd) { d->mainComponentName = kcd.componentName(); d->isUsingForeignComponentName = true; } KGlobalAccel *KGlobalAccel::self( ) { K_GLOBAL_STATIC(KGlobalAccel, s_instance) return s_instance; } QList KGlobalAccelPrivate::updateGlobalShortcutInKded(KAction* action, const QStringList& actionId, uint flags, uint initialSetterFlags) { uint setterFlags = initialSetterFlags; const KShortcut defaultShortcut = action->globalShortcut(KAction::DefaultShortcut); const KShortcut activeShortcut = action->globalShortcut(); if (flags & KAction::NoAutoloading) setterFlags |= KdedGlobalAccel::NoAutoloading; if (defaultShortcut.isEmpty()) setterFlags |= KdedGlobalAccel::IsDefaultEmpty; if (defaultShortcut == activeShortcut) setterFlags |= KdedGlobalAccel::IsDefault; const QList result = iface.setShortcut(actionId, intListFromShortcut(activeShortcut), setterFlags); const KShortcut scResult(shortcutFromIntList(result)); if (scResult != activeShortcut) action->d->setActiveGlobalShortcutNoEnable(scResult); return result; } void KGlobalAccelPrivate::updateGlobalShortcutAllowed(KAction *action, uint flags) { if (!action) return; bool oldEnabled = actionToName.contains(action); bool newEnabled = action->globalShortcutAllowed(); if (oldEnabled == newEnabled) return; if (action->text().isEmpty()) return; QStringList actionId(mainComponentName); actionId.append(action->text()); //TODO: what about i18ned names? if (!oldEnabled && newEnabled) { // action is now enabled nameToAction.insert(actionId.at(1), action); actionToName.insert(action, actionId.at(1)); updateGlobalShortcutInKded(action, actionId, flags, KdedGlobalAccel::SetPresent); } else if (oldEnabled && !newEnabled) { // action is now disabled nameToAction.remove(actionToName.take(action)); iface.setInactive(actionId); } } void KGlobalAccelPrivate::updateGlobalShortcut(KAction *action, uint flags) { if (!action) return; if (action->text().isEmpty()) return; QStringList actionId(mainComponentName); actionId.append(action->text()); //TODO: what about i18ned names? const QList result = updateGlobalShortcutInKded(action, actionId, flags, 0); //We might be able to avoid that call sometimes, but it's neither worth the effort nor //the bytes to determine the cases where it's safe to avoid it. if (isUsingForeignComponentName) { iface.setForeignShortcut(actionId, result); } } QList KGlobalAccelPrivate::intListFromShortcut(const KShortcut &cut) { QList ret; ret.append(cut.primary()[0]); ret.append(cut.alternate()[0]); while (!ret.isEmpty() && ret.last() == 0) ret.removeLast(); return ret; } KShortcut KGlobalAccelPrivate::shortcutFromIntList(const QList &list) { KShortcut ret; if (list.count() > 0) ret.setPrimary(list[0]); if (list.count() > 1) ret.setAlternate(list[1]); return ret; } void KGlobalAccelPrivate::_k_invokeAction(const QStringList &actionId) { //TODO: can we make it so that we don't have to check the mainComponentName? (i.e. targeted signals) // Well, how about making the full QStringList the key in nameToAction? if (actionId.at(0) != mainComponentName || isUsingForeignComponentName) return; KAction *action = nameToAction.value(actionId.at(1)); if (!action) return; + if (!action->isEnabled()) + return; #ifdef Q_WS_X11 // Update this application's X timestamp if needed. // TODO The 100%-correct solution should probably be handling this action // in the proper place in relation to the X events queue in order to avoid // the possibility of wrong ordering of user events. Time timestamp = actionId.at( 2 ).toULong(); if( NET::timestampCompare( timestamp, QX11Info::appTime()) > 0 ) QX11Info::setAppTime( timestamp ); if( NET::timestampCompare( timestamp, QX11Info::appUserTime()) > 0 ) QX11Info::setAppUserTime( timestamp ); #endif action->trigger(); } void KGlobalAccelPrivate::_k_shortcutGotChanged(const QStringList &actionId, const QList &keys) { KAction *action = nameToAction.value(actionId.at(1)); if (!action) return; action->d->setActiveGlobalShortcutNoEnable(shortcutFromIntList(keys)); } void KGlobalAccelPrivate::_k_serviceOwnerChanged(const QString& name, const QString& oldOwner, const QString& newOwner) { Q_UNUSED(oldOwner); if (name == QLatin1String("org.kde.kded") && !newOwner.isEmpty()) { // kded was restarted (what? you mean it crashes sometimes?) reRegisterAll(); } } void KGlobalAccelPrivate::reRegisterAll() { //### Special case for isUsingForeignComponentName? //We clear all our data, assume that all data on the other side is clear too, //and register each action as if it just was allowed to have global shortcuts. //If the kded side still has the data it doesn't matter because of the //autoloading mechanism. The worst case I can imagine is that an action's //shortcut was changed but the kded side died before it got the message so //autoloading will now assign an old shortcut to the action. Particularly //picky apps might assert or misbehave. QList allActions = actionToName.keys(); nameToAction.clear(); actionToName.clear(); foreach(KAction *const action, allActions) { updateGlobalShortcutAllowed(action, 0/*flags*/); } } //static QStringList KGlobalAccel::findActionNameSystemwide(const QKeySequence &seq) { return self()->d->iface.action(seq[0]); } //static bool KGlobalAccel::promptStealShortcutSystemwide(QWidget *parent, const QStringList &actionIdentifier, const QKeySequence &seq) { QString title = i18n("Conflict with Global Shortcut"); QString message = i18n("The '%1' key combination has already been allocated " "to the global action \"%2\" in %3.\n" "Do you want to reassign it from that action to the current one?", seq.toString(), actionIdentifier.at(1), actionIdentifier.at(0)); return KMessageBox::warningContinueCancel(parent, message, title, KGuiItem(i18n("Reassign"))) == KMessageBox::Continue; } //static void KGlobalAccel::stealShortcutSystemwide(const QKeySequence &seq) { //get the shortcut, remove seq, and set the new shorctut const QStringList actionId = self()->d->iface.action(seq[0]); if (actionId.size() < 2) // not a global shortcut return; QList sc = self()->d->iface.shortcut(actionId); for (int i = 0; i < sc.count(); i++) if (sc[i] == seq[0]) sc[i] = 0; self()->d->iface.setForeignShortcut(actionId, sc); } #include "kglobalaccel.moc" #include "kdedglobalaccel_interface.moc"