diff --git a/kdeui/shortcuts/kglobalaccel.cpp b/kdeui/shortcuts/kglobalaccel.cpp index fc47967064..b82b61b4a7 100644 --- a/kdeui/shortcuts/kglobalaccel.cpp +++ b/kdeui/shortcuts/kglobalaccel.cpp @@ -1,336 +1,347 @@ /* 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() +KGlobalAccelPrivate::KGlobalAccelPrivate(KGlobalAccel* q) : isUsingForeignComponentName(false), enabled(true), iface("org.kde.kded", "/modules/kdedglobalaccel", QDBusConnection::sessionBus()) { // Make sure kded is running - if (!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kded")) { + 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) + : 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; } 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) { uint setterFlags = KdedGlobalAccel::SetPresent; KShortcut defaultShortcut = action->globalShortcut(KAction::DefaultShortcut); KShortcut activeShortcut = action->globalShortcut(); if (flags & KAction::NoAutoloading) setterFlags |= KdedGlobalAccel::NoAutoloading; if (defaultShortcut.isEmpty()) setterFlags |= KdedGlobalAccel::IsDefaultEmpty; if (defaultShortcut == activeShortcut) setterFlags |= KdedGlobalAccel::IsDefault; nameToAction.insert(actionId.at(1), action); actionToName.insert(action, actionId.at(1)); QList result = iface.setShortcut(actionId, intListFromShortcut(action->globalShortcut()), setterFlags); KShortcut scResult(shortcutFromIntList(result)); if (scResult != action->globalShortcut()) action->d->setActiveGlobalShortcutNoEnable(scResult); } if (oldEnabled && !newEnabled) { 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? uint setterFlags = 0; KShortcut defaultShortcut = action->globalShortcut(KAction::DefaultShortcut); KShortcut activeShortcut = action->globalShortcut(); if (flags & KAction::NoAutoloading) setterFlags |= KdedGlobalAccel::NoAutoloading; if (defaultShortcut.isEmpty()) setterFlags |= KdedGlobalAccel::IsDefaultEmpty; if (defaultShortcut == activeShortcut) setterFlags |= KdedGlobalAccel::IsDefault; QList result = iface.setShortcut(actionId, intListFromShortcut(action->globalShortcut()), setterFlags); KShortcut scResult(shortcutFromIntList(result)); if (scResult != action->globalShortcut()) { action->d->setActiveGlobalShortcutNoEnable(scResult); } //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) if (actionId.at(0) != mainComponentName || isUsingForeignComponentName) return; KAction *action = nameToAction.value(actionId.at(1)); if (!action) 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::_k_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" diff --git a/kdeui/shortcuts/kglobalaccel.h b/kdeui/shortcuts/kglobalaccel.h index 01ee41fb80..c642466c6f 100644 --- a/kdeui/shortcuts/kglobalaccel.h +++ b/kdeui/shortcuts/kglobalaccel.h @@ -1,125 +1,125 @@ /* 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. */ #ifndef _KGLOBALACCEL_H_ #define _KGLOBALACCEL_H_ #include #include "kaction.h" #include class QWidget; class KShortcut; class KComponentData; /** * @short Configurable global shortcut support * * KGlobalAccel allows you to have global accelerators that are independent of * the focused window. Unlike regular shortcuts, the application's window does not need focus * for them to be activated. * * @see KKeyChooser * @see KKeyDialog */ class KDEUI_EXPORT KGlobalAccel : public QObject { friend class KGlobalAccelImpl; Q_OBJECT public: /** * Returns (and creates if necessary) the singleton instance */ static KGlobalAccel *self(); /** * Checks whether the accelerators are enabled. * @return true if the KGlobalAccel is enabled */ bool isEnabled() const; /** * Enables or disables the KGlobalAccel * @param enabled true if the KGlobalAccel should be enabled, false if it * should be disabled. */ void setEnabled(bool enabled); /** * Set the KComponentData for which to manipulate shortcuts. This is for exceptional * situations, when you want to modify the shortcuts of another application * as if they were yours. * You cannot have your own working global shortcuts in a module/application using this * special functionality. All global shortcuts of KActions will essentially be proxies. * Be sure to set the default global shortcuts of the proxy KActions to the same as * those on the receiving end. * An example use case is the KControl Module for the window manager KWin, which has * no own facility for users to change its global shortcuts. * * @param componentData a KComponentData about the application for which you want to * manipulate shortcuts. */ void overrideMainComponentData(const KComponentData &componentData); /** * Return the name of the action that uses the given key sequence. This applies to * all actions with global shortcuts in any KDE application. * * @see promptStealShortcutSystemwide(), stealShorctutSystemwide() */ static QStringList findActionNameSystemwide(const QKeySequence &seq); /** * Show a messagebox to inform the user that a global shorcut is already occupied, * and ask to take it away from its current action. This is GUI only, so nothing will * be actually changed. * * @see stealShorctutSystemwide() */ static bool promptStealShortcutSystemwide(QWidget *parent, const QStringList &actionIdentifier, const QKeySequence &seq); /** * Take away the given shortcut from the named action it belongs to. * This applies to all actions with global shortcuts in any KDE application. * * @see promptStealShortcutSystemwide() */ static void stealShortcutSystemwide(const QKeySequence &seq); private: friend class KAction; /// Creates a new KGlobalAccel object KGlobalAccel(); /// Destructor ~KGlobalAccel(); class KGlobalAccelPrivate *const d; Q_PRIVATE_SLOT(d, void _k_invokeAction(const QStringList&)) Q_PRIVATE_SLOT(d, void _k_shortcutGotChanged(const QStringList&, const QList&)) - Q_PRIVATE_SLOT(d, void _k_reRegisterAll()) + Q_PRIVATE_SLOT(d, void _k_serviceOwnerChanged(const QString&, const QString&, const QString&)) }; #endif // _KGLOBALACCEL_H_ diff --git a/kdeui/shortcuts/kglobalaccel_p.h b/kdeui/shortcuts/kglobalaccel_p.h index 7912d89c39..8aa0ceb7b4 100644 --- a/kdeui/shortcuts/kglobalaccel_p.h +++ b/kdeui/shortcuts/kglobalaccel_p.h @@ -1,65 +1,66 @@ /* 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. */ #ifndef KGLOBALACCEL_P_H #define KGLOBALACCEL_P_H #include #include #include "kdedglobalaccel_interface.h" class KAction; class KShortcut; class KGlobalAccelPrivate { public: - KGlobalAccelPrivate(); + KGlobalAccelPrivate(KGlobalAccel*); ///Propagate any shortcut changes to the KDED module that does the bookkeeping ///and the key grabbing. ///If this is called with an action that has an empty active global shortcut and ///an empty default shortcut, the record of that action will be deleted. void updateGlobalShortcut(KAction *action, /*KAction::ShortcutTypes*/uint flags); ///Register or unregister the action in this class, and notify the KDED module void updateGlobalShortcutAllowed(KAction *action, /*KAction::ShortcutTypes*/uint flags); QList intListFromShortcut(const KShortcut &cut); KShortcut shortcutFromIntList(const QList &list); void _k_invokeAction(const QStringList&); void _k_shortcutGotChanged(const QStringList&, const QList&); - void _k_reRegisterAll(); + void _k_serviceOwnerChanged(const QString& name, const QString& oldOwner, const QString& newOwner); + void reRegisterAll(); //for all actions with (isEnabled() && globalShortcutAllowed()) QHash nameToAction; QHash actionToName; QString mainComponentName; bool isUsingForeignComponentName; bool enabled; org::kde::KdedGlobalAccelInterface iface; }; #endif