diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f063f9..d9903ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,111 +1,112 @@ cmake_minimum_required(VERSION 3.5) set(KF5_VERSION "5.57.0") # handled by release scripts set(KF5_DEP_VERSION "5.56.0") # handled by release scripts project(KGlobalAccel VERSION ${KF5_VERSION}) # ECM setup include(FeatureSummary) find_package(ECM 5.56.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) include(GenerateExportHeader) include(CMakePackageConfigHelpers) include(ECMSetupVersion) include(ECMGenerateHeaders) include(ECMAddQch) include(ECMMarkNonGuiExecutable) include(ECMQtDeclareLoggingCategory) include(ECMPoQmTools) option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") ecm_setup_version(PROJECT VARIABLE_PREFIX KGLOBALACCEL VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kglobalaccel_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5GlobalAccelConfigVersion.cmake" SOVERSION 5) # Dependencies set(REQUIRED_QT_VERSION 5.10.0) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED DBus Widgets) include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) # Dependencies of runtime component find_package(KF5Config ${KF5_DEP_VERSION} REQUIRED) find_package(KF5CoreAddons ${KF5_DEP_VERSION} REQUIRED) find_package(KF5Crash ${KF5_DEP_VERSION} REQUIRED) find_package(KF5DBusAddons ${KF5_DEP_VERSION} REQUIRED) find_package(KF5WindowSystem ${KF5_DEP_VERSION} REQUIRED) # no X11 stuff on mac if (NOT APPLE) find_package(XCB MODULE COMPONENTS XCB KEYSYMS XTEST XKB) set_package_properties(XCB PROPERTIES DESCRIPTION "X protocol C-language Binding" URL "http://xcb.freedesktop.org" TYPE OPTIONAL ) find_package(X11) endif() set(HAVE_X11 0) if(X11_FOUND AND XCB_XCB_FOUND) set(HAVE_X11 1) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED X11Extras) endif() add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050d00) # Subdirectories if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") ecm_install_po_files_as_qm(po) endif() +add_definitions(-DQT_NO_FOREACH) add_subdirectory(src) if (BUILD_TESTING) add_subdirectory(autotests) endif() # create a Config.cmake and a ConfigVersion.cmake file and install them set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5GlobalAccel") if (BUILD_QCH) ecm_install_qch_export( TARGETS KF5GlobalAccel_QCH FILE KF5GlobalAccelQchTargets.cmake DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5GlobalAccelQchTargets.cmake\")") endif() configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KF5GlobalAccelConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5GlobalAccelConfig.cmake" PATH_VARS KDE_INSTALL_DBUSINTERFACEDIR INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5GlobalAccelConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5GlobalAccelConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT KF5GlobalAccelTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5GlobalAccelTargets.cmake NAMESPACE KF5:: ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kglobalaccel_version.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5} COMPONENT Devel ) # contains list of debug categories, for kdebugsettings install(FILES kglobalaccel.categories DESTINATION ${KDE_INSTALL_CONFDIR}) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/kglobalaccel.cpp b/src/kglobalaccel.cpp index 8c24739..b8715c4 100644 --- a/src/kglobalaccel.cpp +++ b/src/kglobalaccel.cpp @@ -1,741 +1,741 @@ /* This file is part of the KDE libraries Copyright (C) 2001,2002 Ellis Whitehead Copyright (C) 2006 Hamish Rodda Copyright (C) 2007 Andreas Hartmetz Copyright (C) 2008 Michael Jansen 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 "kglobalaccel_debug.h" #include #include #include #include #include #include #include #include #include #if HAVE_X11 #include #endif org::kde::kglobalaccel::Component *KGlobalAccelPrivate::getComponent(const QString &componentUnique, bool remember = false) { // Check if we already have this component { auto component = components.value(componentUnique); if (component) { return component; } } // Connect to the kglobalaccel daemon org::kde::KGlobalAccel kglobalaccel( QStringLiteral("org.kde.kglobalaccel"), QStringLiteral("/kglobalaccel"), QDBusConnection::sessionBus()); if (!kglobalaccel.isValid()) { qCDebug(KGLOBALACCEL_LOG) << "Failed to connect to the kglobalaccel daemon" << QDBusConnection::sessionBus().lastError(); return nullptr; } // Get the path for our component. We have to do that because // componentUnique is probably not a valid dbus object path QDBusReply reply = kglobalaccel.getComponent(componentUnique); if (!reply.isValid()) { if (reply.error().name() == QLatin1String("org.kde.kglobalaccel.NoSuchComponent")) { // No problem. The component doesn't exists. That's normal return nullptr; } // An unknown error. qCDebug(KGLOBALACCEL_LOG) << "Failed to get dbus path for component " << componentUnique << reply.error(); return nullptr; } // Now get the component org::kde::kglobalaccel::Component *component = new org::kde::kglobalaccel::Component( QStringLiteral("org.kde.kglobalaccel"), reply.value().path(), QDBusConnection::sessionBus(), q); // No component no cleaning if (!component->isValid()) { qCDebug(KGLOBALACCEL_LOG) << "Failed to get component" << componentUnique << QDBusConnection::sessionBus().lastError(); return nullptr; } if (remember) { // Connect to the signals we are interested in. q->connect(component, SIGNAL(globalShortcutPressed(QString,QString,qlonglong)), SLOT(_k_invokeAction(QString,QString,qlonglong))); components[componentUnique] = component; } return component; } namespace { QString serviceName() { return QStringLiteral("org.kde.kglobalaccel"); } } void KGlobalAccelPrivate::cleanup() { qDeleteAll(components); delete m_iface; m_iface = nullptr; delete m_watcher; m_watcher = nullptr; } KGlobalAccelPrivate::KGlobalAccelPrivate(KGlobalAccel *q) : #ifndef KGLOBALACCEL_NO_DEPRECATED enabled(true), #endif q(q), m_iface(nullptr) { m_watcher = new QDBusServiceWatcher(serviceName(), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, q); q->connect(m_watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), q, SLOT(_k_serviceOwnerChanged(QString,QString,QString))); } org::kde::KGlobalAccel *KGlobalAccelPrivate::iface() { if (!m_iface) { m_iface = new org::kde::KGlobalAccel(serviceName(), QStringLiteral("/kglobalaccel"), QDBusConnection::sessionBus()); // Make sure kglobalaccel is running. The iface declaration above somehow works anyway. QDBusConnectionInterface *bus = QDBusConnection::sessionBus().interface(); if (bus && !bus->isServiceRegistered(serviceName())) { QDBusReply reply = bus->startService(serviceName()); if (!reply.isValid()) { qCritical() << "Couldn't start kglobalaccel from org.kde.kglobalaccel.service:" << reply.error(); } } q->connect(m_iface, SIGNAL(yourShortcutGotChanged(QStringList,QList)), SLOT(_k_shortcutGotChanged(QStringList,QList))); } return m_iface; } KGlobalAccel::KGlobalAccel() : d(new KGlobalAccelPrivate(this)) { qDBusRegisterMetaType >(); qDBusRegisterMetaType >(); qDBusRegisterMetaType(); qDBusRegisterMetaType >(); } KGlobalAccel::~KGlobalAccel() { delete d; } void KGlobalAccel::activateGlobalShortcutContext( const QString &contextUnique, const QString &contextFriendly, const QString &programName) { Q_UNUSED(contextFriendly); // TODO: provide contextFriendly self()->d->iface()->activateGlobalShortcutContext(programName, contextUnique); } // static bool KGlobalAccel::cleanComponent(const QString &componentUnique) { org::kde::kglobalaccel::Component *component = self()->getComponent(componentUnique); if (!component) { return false; } return component->cleanUp(); } // static bool KGlobalAccel::isComponentActive(const QString &componentUnique) { org::kde::kglobalaccel::Component *component = self()->getComponent(componentUnique); if (!component) { return false; } return component->isActive(); } #ifndef KGLOBALACCEL_NO_DEPRECATED bool KGlobalAccel::isEnabled() const { return d->enabled; } #endif org::kde::kglobalaccel::Component *KGlobalAccel::getComponent(const QString &componentUnique) { return d->getComponent(componentUnique); } #ifndef KGLOBALACCEL_NO_DEPRECATED void KGlobalAccel::setEnabled(bool enabled) { d->enabled = enabled; } #endif class KGlobalAccelSingleton { public: KGlobalAccelSingleton(); KGlobalAccel instance; }; Q_GLOBAL_STATIC(KGlobalAccelSingleton, s_instance) KGlobalAccelSingleton::KGlobalAccelSingleton() { qAddPostRoutine([]() { s_instance->instance.d->cleanup(); }); } KGlobalAccel *KGlobalAccel::self() { return &s_instance()->instance; } bool KGlobalAccelPrivate::doRegister(QAction *action) { if (!action || action->objectName().isEmpty() || action->objectName().startsWith(QLatin1String("unnamed-"))) { qWarning() << "Attempt to set global shortcut for action without objectName()." " Read the setGlobalShortcut() documentation."; return false; } const bool isRegistered = actions.contains(action); if (isRegistered) { return true; } QStringList actionId = makeActionId(action); nameToAction.insertMulti(actionId.at(KGlobalAccel::ActionUnique), action); actions.insert(action); iface()->doRegister(actionId); QObject::connect(action, &QObject::destroyed, [this, action](QObject *) { if (actions.contains(action) && (actionShortcuts.contains(action) || actionDefaultShortcuts.contains(action))) { remove(action, KGlobalAccelPrivate::SetInactive); } }); return true; } void KGlobalAccelPrivate::remove(QAction *action, Removal removal) { if (!action || action->objectName().isEmpty()) { return; } const bool isRegistered = actions.contains(action); if (!isRegistered) { return; } QStringList actionId = makeActionId(action); nameToAction.remove(actionId.at(KGlobalAccel::ActionUnique), action); actions.remove(action); if (removal == UnRegister) { // Complete removal of the shortcut is requested // (forgetGlobalShortcut) iface()->unRegister(actionId); } else { // If the action is a configurationAction wen only remove it from our // internal registry. That happened above. if (!action->property("isConfigurationAction").toBool()) { // If it's a session shortcut unregister it. action->objectName().startsWith(QStringLiteral("_k_session:")) ? iface()->unRegister(actionId) : iface()->setInactive(actionId); } } actionDefaultShortcuts.remove(action); actionShortcuts.remove(action); } void KGlobalAccelPrivate::updateGlobalShortcut(/*const would be better*/QAction* action, ShortcutTypes actionFlags, KGlobalAccel::GlobalShortcutLoading globalFlags) { // No action or no objectname -> Do nothing if (!action || action->objectName().isEmpty()) { return; } QStringList actionId = makeActionId(action); uint setterFlags = 0; if (globalFlags & NoAutoloading) { setterFlags |= NoAutoloading; } if (actionFlags & ActiveShortcut) { const QList activeShortcut = actionShortcuts.value(action); bool isConfigurationAction = action->property("isConfigurationAction").toBool(); uint activeSetterFlags = setterFlags; // setPresent tells kglobalaccel that the shortcut is active if (!isConfigurationAction) { activeSetterFlags |= SetPresent; } // Sets the shortcut, returns the active/real keys const auto result = iface()->setShortcut( actionId, intListFromShortcut(activeShortcut), activeSetterFlags); // Make sure we get informed about changes in the component by kglobalaccel getComponent(componentUniqueForAction(action), true); // Create a shortcut from the result const QList scResult(shortcutFromIntList(result)); if (isConfigurationAction && (globalFlags & NoAutoloading)) { // If this is a configuration action and we have set the shortcut, // inform the real owner of the change. // Note that setForeignShortcut will cause a signal to be sent to applications // even if it did not "see" that the shortcut has changed. This is Good because // at the time of comparison (now) the action *already has* the new shortcut. // We called setShortcut(), remember? // Also note that we will see our own signal so we may not need to call // setActiveGlobalShortcutNoEnable - _k_shortcutGotChanged() does it. // In practice it's probably better to get the change propagated here without // DBus delay as we do below. iface()->setForeignShortcut(actionId, result); } if (scResult != activeShortcut) { // If kglobalaccel returned a shortcut that differs from the one we // sent, use that one. There must have been clashes or some other problem. actionShortcuts.insert(action, scResult); emit q->globalShortcutChanged(action, scResult.isEmpty() ? QKeySequence() : scResult.first()); } } if (actionFlags & DefaultShortcut) { const QList defaultShortcut = actionDefaultShortcuts.value(action); iface()->setShortcut(actionId, intListFromShortcut(defaultShortcut), setterFlags | IsDefault); } } QStringList KGlobalAccelPrivate::makeActionId(const QAction *action) { QStringList ret(componentUniqueForAction(action)); // Component Unique Id ( see actionIdFields ) Q_ASSERT(!ret.at(KGlobalAccel::ComponentUnique).isEmpty()); Q_ASSERT(!action->objectName().isEmpty()); ret.append(action->objectName()); // Action Unique Name ret.append(componentFriendlyForAction(action)); // Component Friendly name const QString actionText = action->text().replace(QLatin1Char('&'), QStringLiteral("")); ret.append(actionText); // Action Friendly Name return ret; } QList KGlobalAccelPrivate::intListFromShortcut(const QList &cut) { QList ret; - Q_FOREACH (const QKeySequence &sequence, cut) { + for (const QKeySequence &sequence : cut) { ret.append(sequence[0]); } while (!ret.isEmpty() && ret.last() == 0) { ret.removeLast(); } return ret; } QList KGlobalAccelPrivate::shortcutFromIntList(const QList &list) { QList ret; - Q_FOREACH (int i, list) { + for (int i : list) { ret.append(i); } return ret; } QString KGlobalAccelPrivate::componentUniqueForAction(const QAction *action) { if (!action->property("componentName").isValid()) { return QCoreApplication::applicationName(); } else { return action->property("componentName").toString(); } } QString KGlobalAccelPrivate::componentFriendlyForAction(const QAction *action) { QString property = action->property("componentDisplayName").toString(); if (!property.isEmpty()) { return property; } if (!QGuiApplication::applicationDisplayName().isEmpty()) { return QGuiApplication::applicationDisplayName(); } return QCoreApplication::applicationName(); } #if HAVE_X11 int _k_timestampCompare(unsigned long time1_, unsigned long time2_) // like strcmp() { quint32 time1 = time1_; quint32 time2 = time2_; if (time1 == time2) { return 0; } return quint32(time1 - time2) < 0x7fffffffU ? 1 : -1; // time1 > time2 -> 1, handle wrapping } #endif void KGlobalAccelPrivate::_k_invokeAction( const QString &componentUnique, const QString &actionUnique, qlonglong timestamp) { QAction *action = nullptr; - QList candidates = nameToAction.values(actionUnique); - Q_FOREACH (QAction *const a, candidates) { + const QList candidates = nameToAction.values(actionUnique); + for (QAction *const a : candidates) { if (componentUniqueForAction(a) == componentUnique) { action = a; } } // We do not trigger if // - there is no action // - the action is not enabled // - the action is an configuration action if (!action || !action->isEnabled() || action->property("isConfigurationAction").toBool()) { return; } #if HAVE_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. if (QX11Info::isPlatformX11()) { if (_k_timestampCompare(timestamp, QX11Info::appTime()) > 0) { QX11Info::setAppTime(timestamp); } if (_k_timestampCompare(timestamp, QX11Info::appUserTime()) > 0) { QX11Info::setAppUserTime(timestamp); } } #endif action->setProperty("org.kde.kglobalaccel.activationTimestamp", timestamp); action->trigger(); } void KGlobalAccelPrivate::_k_shortcutGotChanged(const QStringList &actionId, const QList &keys) { QAction *action = nameToAction.value(actionId.at(KGlobalAccel::ActionUnique)); if (!action) { return; } const QList shortcuts = shortcutFromIntList(keys); actionShortcuts.insert(action, shortcuts); emit q->globalShortcutChanged(action, keys.isEmpty() ? QKeySequence() : shortcuts.first()); } void KGlobalAccelPrivate::_k_serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner) { Q_UNUSED(oldOwner); if (name == QLatin1String("org.kde.kglobalaccel") && !newOwner.isEmpty()) { // kglobalaccel was restarted qCDebug(KGLOBALACCEL_LOG) << "detected kglobalaccel restarting, re-registering all shortcut keys"; reRegisterAll(); } } void KGlobalAccelPrivate::reRegisterAll() { //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. - QSet allActions = actions; + const QSet allActions = actions; nameToAction.clear(); actions.clear(); - Q_FOREACH (QAction *const action, allActions) { + for (QAction *const action : allActions) { if (doRegister(action)) { updateGlobalShortcut(action, ActiveShortcut, KGlobalAccel::Autoloading); } } } #ifndef KGLOBALACCEL_NO_DEPRECATED QList KGlobalAccel::allMainComponents() { return d->iface()->allMainComponents(); } #endif #ifndef KGLOBALACCEL_NO_DEPRECATED QList KGlobalAccel::allActionsForComponent(const QStringList &actionId) { return d->iface()->allActionsForComponent(actionId); } #endif //static #ifndef KGLOBALACCEL_NO_DEPRECATED QStringList KGlobalAccel::findActionNameSystemwide(const QKeySequence &seq) { return self()->d->iface()->action(seq[0]); } #endif QList KGlobalAccel::getGlobalShortcutsByKey(const QKeySequence &seq) { return self()->d->iface()->getGlobalShortcutsByKey(seq[0]); } bool KGlobalAccel::isGlobalShortcutAvailable(const QKeySequence &seq, const QString &comp) { return self()->d->iface()->isGlobalShortcutAvailable(seq[0], comp); } //static #ifndef KGLOBALACCEL_NO_DEPRECATED bool KGlobalAccel::promptStealShortcutSystemwide(QWidget *parent, const QStringList &actionIdentifier, const QKeySequence &seq) { if (actionIdentifier.size() < 4) { return false; } QString title = tr("Conflict with Global Shortcut"); QString message = tr("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?") .arg(seq.toString(), actionIdentifier.at(KGlobalAccel::ActionFriendly), actionIdentifier.at(KGlobalAccel::ComponentFriendly)); QMessageBox box(parent); box.setWindowTitle(title); box.setText(message); box.addButton(QMessageBox::Ok)->setText(tr("Reassign")); box.addButton(QMessageBox::Cancel); return box.exec() == QMessageBox::Ok; } #endif //static bool KGlobalAccel::promptStealShortcutSystemwide( QWidget *parent, const QList &shortcuts, const QKeySequence &seq) { if (shortcuts.isEmpty()) { // Usage error. Just say no return false; } QString component = shortcuts[0].componentFriendlyName(); QString message; if (shortcuts.size() == 1) { message = tr("The '%1' key combination is registered by application %2 for action %3:") .arg(seq.toString(), component, shortcuts[0].friendlyName()); } else { QString actionList; - Q_FOREACH (const KGlobalShortcutInfo &info, shortcuts) { + for (const KGlobalShortcutInfo &info : shortcuts) { actionList += tr("In context '%1' for action '%2'\n") .arg(info.contextFriendlyName(), info.friendlyName()); } message = tr("The '%1' key combination is registered by application %2.\n%3") .arg(seq.toString(), component, actionList); } QString title = tr("Conflict With Registered Global Shortcut"); QMessageBox box(parent); box.setWindowTitle(title); box.setText(message); box.addButton(QMessageBox::Ok)->setText(tr("Reassign")); box.addButton(QMessageBox::Cancel); return box.exec() == QMessageBox::Ok; } //static void KGlobalAccel::stealShortcutSystemwide(const QKeySequence &seq) { //get the shortcut, remove seq, and set the new shortcut const QStringList actionId = self()->d->iface()->action(seq[0]); if (actionId.size() < 4) { // 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); } bool checkGarbageKeycode(const QList &shortcut) { // protect against garbage keycode -1 that Qt sometimes produces for exotic keys; // at the moment (~mid 2008) Multimedia PlayPause is one of those keys. - Q_FOREACH (const QKeySequence &sequence, shortcut) { + for (const QKeySequence &sequence : shortcut) { for (int i = 0; i < 4; i++) { if (sequence[i] == -1) { qWarning() << "Encountered garbage keycode (keycode = -1) in input, not doing anything."; return true; } } } return false; } bool KGlobalAccel::setDefaultShortcut(QAction *action, const QList &shortcut, GlobalShortcutLoading loadFlag) { if (checkGarbageKeycode(shortcut)) { return false; } if (!d->doRegister(action)) { return false; } d->actionDefaultShortcuts.insert(action, shortcut); d->updateGlobalShortcut(action, KGlobalAccelPrivate::DefaultShortcut, loadFlag); return true; } bool KGlobalAccel::setShortcut(QAction *action, const QList &shortcut, GlobalShortcutLoading loadFlag) { if (checkGarbageKeycode(shortcut)) { return false; } if (!d->doRegister(action)) { return false; } d->actionShortcuts.insert(action, shortcut); d->updateGlobalShortcut(action, KGlobalAccelPrivate::ActiveShortcut, loadFlag); return true; } QList KGlobalAccel::defaultShortcut(const QAction *action) const { return d->actionDefaultShortcuts.value(action); } QList KGlobalAccel::shortcut(const QAction *action) const { return d->actionShortcuts.value(action); } QList KGlobalAccel::globalShortcut(const QString& componentName, const QString& actionId) const { // see also d->updateGlobalShortcut(action, KGlobalAccelPrivate::ActiveShortcut, KGlobalAccel::Autoloading); // how componentName and actionId map to QAction, e.g: // action->setProperty("componentName", "kwin"); // action->setObjectName("Kill Window"); const QList result = self()->d->iface()->shortcut({ componentName, actionId, QString(), QString() }); const QList scResult(d->shortcutFromIntList(result)); return scResult; } void KGlobalAccel::removeAllShortcuts(QAction *action) { d->remove(action, KGlobalAccelPrivate::UnRegister); } bool KGlobalAccel::hasShortcut(const QAction *action) const { return d->actionShortcuts.contains(action) || d->actionDefaultShortcuts.contains(action); } bool KGlobalAccel::eventFilter(QObject *watched, QEvent *event) { return QObject::eventFilter(watched, event); } bool KGlobalAccel::setGlobalShortcut(QAction *action, const QList &shortcut) { KGlobalAccel *g = KGlobalAccel::self(); return g->d->setShortcutWithDefault(action, shortcut, Autoloading); } bool KGlobalAccel::setGlobalShortcut(QAction *action, const QKeySequence &shortcut) { return KGlobalAccel::setGlobalShortcut(action, QList() << shortcut); } bool KGlobalAccelPrivate::setShortcutWithDefault(QAction* action, const QList& shortcut, KGlobalAccel::GlobalShortcutLoading loadFlag) { if (checkGarbageKeycode(shortcut)) { return false; } if (!doRegister(action)) { return false; } actionDefaultShortcuts.insert(action, shortcut); actionShortcuts.insert(action, shortcut); updateGlobalShortcut(action, KGlobalAccelPrivate::DefaultShortcut | KGlobalAccelPrivate::ActiveShortcut, loadFlag); return true; } #include "moc_kglobalaccel.cpp" diff --git a/src/kglobalshortcutinfo_dbus.cpp b/src/kglobalshortcutinfo_dbus.cpp index 4e14077..89ace37 100644 --- a/src/kglobalshortcutinfo_dbus.cpp +++ b/src/kglobalshortcutinfo_dbus.cpp @@ -1,71 +1,71 @@ /* Copyright (C) 2008 Michael Jansen 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 "kglobalshortcutinfo.h" #include "kglobalshortcutinfo_p.h" QDBusArgument &operator<< (QDBusArgument &argument, const KGlobalShortcutInfo &shortcut) { argument.beginStructure(); argument << shortcut.uniqueName() << shortcut.friendlyName() << shortcut.componentUniqueName() << shortcut.componentFriendlyName() << shortcut.contextUniqueName() << shortcut.contextFriendlyName(); argument.beginArray(qMetaTypeId()); - Q_FOREACH (const QKeySequence &key, shortcut.keys()) { + for (const QKeySequence &key : shortcut.keys()) { argument << key[0]; } argument.endArray(); argument.beginArray(qMetaTypeId()); - Q_FOREACH (const QKeySequence &key, shortcut.defaultKeys()) { + for (const QKeySequence &key : shortcut.defaultKeys()) { argument << key[0]; } argument.endArray(); argument.endStructure(); return argument; } const QDBusArgument &operator>> (const QDBusArgument &argument, KGlobalShortcutInfo &shortcut) { argument.beginStructure(); argument >> shortcut.d->uniqueName >> shortcut.d->friendlyName >> shortcut.d->componentUniqueName >> shortcut.d->componentFriendlyName >> shortcut.d->contextUniqueName >> shortcut.d->contextFriendlyName; argument.beginArray(); while (!argument.atEnd()) { int key; argument >> key; shortcut.d->keys.append(QKeySequence(key)); } argument.endArray(); argument.beginArray(); while (!argument.atEnd()) { int key; argument >> key; shortcut.d->defaultKeys.append(QKeySequence(key)); } argument.endArray(); argument.endStructure(); return argument; } diff --git a/src/runtime/component.cpp b/src/runtime/component.cpp index c9ed03e..4df9ceb 100644 --- a/src/runtime/component.cpp +++ b/src/runtime/component.cpp @@ -1,497 +1,498 @@ /* Copyright (C) 2008 Michael Jansen 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 "component.h" #include "globalshortcut.h" #include "globalshortcutcontext.h" #include "globalshortcutsregistry.h" #include "logging_p.h" #include #include "kglobalaccel_interface.h" #include #include #include #if HAVE_X11 #include #endif static QList keysFromString(const QString &str) { QList ret; if (str == QLatin1String("none")) { return ret; } const QStringList strList = str.split('\t'); - foreach (const QString &s, strList) { + for (const QString &s : strList) { int key = QKeySequence(s)[0]; if (key != -1) { //sanity check just in case ret.append(key); } } return ret; } static QString stringFromKeys(const QList &keys) { if (keys.isEmpty()) { return QStringLiteral("none"); } QString ret; - foreach (int key, keys) { + for (int key : keys) { ret.append(QKeySequence(key).toString()); ret.append('\t'); } ret.chop(1); return ret; } namespace KdeDGlobalAccel { Component::Component( const QString &uniqueName, const QString &friendlyName, GlobalShortcutsRegistry *registry) : _uniqueName(uniqueName) ,_friendlyName(friendlyName) ,_registry(registry) { // Make sure we do no get uniquenames still containing the context Q_ASSERT(uniqueName.indexOf("|")==-1); // Register ourselve with the registry if (_registry) { _registry->addComponent(this); } QString DEFAULT=QStringLiteral("default"); createGlobalShortcutContext(DEFAULT, QStringLiteral("Default Context")); _current = _contexts.value(DEFAULT); } Component::~Component() { // Remove ourselve from the registry if (_registry) { _registry->takeComponent(this); } // We delete all shortcuts from all contexts qDeleteAll(_contexts); } bool Component::activateGlobalShortcutContext( const QString &uniqueName) { if (!_contexts.value(uniqueName)) { createGlobalShortcutContext(uniqueName, "TODO4"); return false; } // Deactivate the current contexts shortcuts deactivateShortcuts(); // Switch the context _current = _contexts.value(uniqueName); return true; } void Component::activateShortcuts() { - Q_FOREACH (GlobalShortcut *shortcut, _current->_actions) + for (GlobalShortcut *shortcut : qAsConst(_current->_actions)) { shortcut->setActive(); } } QList Component::allShortcuts(const QString &contextName) const { GlobalShortcutContext *context = _contexts.value(contextName); if (context) { return context->_actions.values(); } else { return QList (); } } QList Component::allShortcutInfos(const QString &contextName) const { GlobalShortcutContext *context = _contexts.value(contextName); if (!context) { return QList(); } return context->allShortcutInfos(); } bool Component::cleanUp() { bool changed = false;; - Q_FOREACH (GlobalShortcut *shortcut, _current->_actions) + for (GlobalShortcut *shortcut : qAsConst(_current->_actions)) { qCDebug(KGLOBALACCELD) << _current->_actions.size(); if (!shortcut->isPresent()) { changed = true; shortcut->unRegister(); } } if (changed) { _registry->writeSettings(); // We could be destroyed after this call! } return changed; } bool Component::createGlobalShortcutContext( const QString &uniqueName, const QString &friendlyName) { if (_contexts.value(uniqueName)) { qCDebug(KGLOBALACCELD) << "Shortcut Context " << uniqueName << "already exists for component " << _uniqueName; return false; } _contexts.insert(uniqueName, new GlobalShortcutContext(uniqueName, friendlyName, this)); return true; } GlobalShortcutContext *Component::currentContext() { return _current; } QDBusObjectPath Component::dbusPath() const { QString dbusPath = _uniqueName; // Clean up for dbus usage: any non-alphanumeric char should be turned into '_' const int len = dbusPath.length(); for ( int i = 0; i < len; ++i ) { if ( !dbusPath[i].isLetterOrNumber() ) dbusPath[i] = QLatin1Char('_'); } // QDBusObjectPath could be a little bit easier to handle :-) return QDBusObjectPath( _registry->dbusPath().path() + "component/" + dbusPath); } void Component::deactivateShortcuts(bool temporarily) { - Q_FOREACH (GlobalShortcut *shortcut, _current->_actions) + for (GlobalShortcut *shortcut : qAsConst(_current->_actions)) { if (temporarily && uniqueName() == QLatin1String("kwin") && shortcut->uniqueName() == QLatin1String("Block Global Shortcuts")) { continue; } shortcut->setInactive(); } } void Component::emitGlobalShortcutPressed( const GlobalShortcut &shortcut ) { #if HAVE_X11 // pass X11 timestamp long timestamp = QX11Info::appTime(); // Make sure kglobalacceld has ungrabbed the keyboard after receiving the // keypress, otherwise actions in application that try to grab the // keyboard (e.g. in kwin) may fail to do so. There is still a small race // condition with this being out-of-process. if (_registry->_manager) { _registry->_manager->syncWindowingSystem(); } #else long timestamp = 0; #endif // Make sure it is one of ours if (shortcut.context()->component() != this) { // In production mode do nothing return; } emit globalShortcutPressed( shortcut.context()->component()->uniqueName(), shortcut.uniqueName(), timestamp); } void Component::invokeShortcut(const QString &shortcutName, const QString &context) { GlobalShortcut *shortcut = getShortcutByName(shortcutName, context); if (shortcut) emitGlobalShortcutPressed(*shortcut); } QString Component::friendlyName() const { if (_friendlyName.isEmpty()) return _uniqueName; return _friendlyName; } GlobalShortcut *Component::getShortcutByKey(int key) const { return _current->getShortcutByKey(key); } QList Component::getShortcutsByKey(int key) const { QList rc; - Q_FOREACH(GlobalShortcutContext *context, _contexts) + for (GlobalShortcutContext *context : qAsConst(_contexts)) { GlobalShortcut *sc = context->getShortcutByKey(key); if (sc) rc.append(sc); } return rc; } GlobalShortcut *Component::getShortcutByName(const QString &uniqueName, const QString &context) const { if (!_contexts.value(context)) { return nullptr; } return _contexts.value(context)->_actions.value(uniqueName); } QStringList Component::getShortcutContexts() const { return _contexts.keys(); } bool Component::isActive() const { // The component is active if at least one of it's global shortcuts is // present. - Q_FOREACH (GlobalShortcut *shortcut, _current->_actions) + for (GlobalShortcut *shortcut : qAsConst(_current->_actions)) { if (shortcut->isPresent()) return true; } return false; } bool Component::isShortcutAvailable( int key, const QString &component, const QString &context) const { qCDebug(KGLOBALACCELD) << QKeySequence(key).toString() << component; // if this component asks for the key. only check the keys in the same // context if (component==uniqueName()) { - Q_FOREACH(GlobalShortcut *sc, shortcutContext(context)->_actions) + for (GlobalShortcut *sc : qAsConst(shortcutContext(context)->_actions)) { if (sc->keys().contains(key)) return false; } } else { - Q_FOREACH(GlobalShortcutContext *ctx, _contexts) + for (GlobalShortcutContext *ctx : qAsConst(_contexts)) { - Q_FOREACH(GlobalShortcut *sc, ctx->_actions) + for (GlobalShortcut *sc : qAsConst(ctx->_actions)) { if (sc->keys().contains(key)) return false; } } } return true; } GlobalShortcut *Component::registerShortcut(const QString &uniqueName, const QString &friendlyName, const QString &shortcutString, const QString &defaultShortcutString) { // The shortcut will register itself with us GlobalShortcut *shortcut = new GlobalShortcut( uniqueName, friendlyName, currentContext()); - QList keys = keysFromString(shortcutString); + const QList keys = keysFromString(shortcutString); shortcut->setDefaultKeys(keysFromString(defaultShortcutString)); shortcut->setIsFresh(false); - - Q_FOREACH (int key, keys) + QList newKeys = keys; + for (int key : keys) { if (key != 0) { if (GlobalShortcutsRegistry::self()->getShortcutByKey(key)) { // The shortcut is already used. The config file is // broken. Ignore the request. - keys.removeAll(key); + newKeys.removeAll(key); qCWarning(KGLOBALACCELD) << "Shortcut found twice in kglobalshortcutsrc."<setKeys(keys); return shortcut; } void Component::loadSettings(KConfigGroup &configGroup) { // GlobalShortcutsRegistry::loadSettings handles contexts. - Q_FOREACH (const QString &confKey, configGroup.keyList()) + const auto listKeys = configGroup.keyList(); + for (const QString &confKey : listKeys) { const QStringList entry = configGroup.readEntry(confKey, QStringList()); if (entry.size() != 3) { continue; } GlobalShortcut *shortcut = registerShortcut(confKey, entry[2], entry[0], entry[1]); if (configGroup.name().endsWith(QLatin1String(".desktop"))) { shortcut->setIsPresent(true); } } } void Component::setFriendlyName(const QString &name) { _friendlyName = name; } GlobalShortcutContext *Component::shortcutContext( const QString &contextName ) { return _contexts.value(contextName); } GlobalShortcutContext const *Component::shortcutContext( const QString &contextName ) const { return _contexts.value(contextName); } QStringList Component::shortcutNames( const QString &contextName) const { GlobalShortcutContext *context = _contexts.value(contextName); if (!context) { return QStringList(); } return context->_actions.keys(); } QString Component::uniqueName() const { return _uniqueName; } void Component::unregisterShortcut(const QString &uniqueName) { // Now wrote all contexts - Q_FOREACH( GlobalShortcutContext *context, _contexts) + for( GlobalShortcutContext *context : qAsConst(_contexts)) { if (context->_actions.value(uniqueName)) { delete context->takeShortcut(context->_actions.value(uniqueName)); } } } void Component::writeSettings(KConfigGroup& configGroup) const { // If we don't delete the current content global shortcut // registrations will never not deleted after forgetGlobalShortcut() configGroup.deleteGroup(); // Now write all contexts - Q_FOREACH( GlobalShortcutContext *context, _contexts) + for( GlobalShortcutContext *context : qAsConst(_contexts)) { KConfigGroup contextGroup; if (context->uniqueName() == QLatin1String("default")) { contextGroup = configGroup; // Write the friendly name contextGroup.writeEntry("_k_friendly_name", friendlyName()); } else { contextGroup = KConfigGroup(&configGroup, context->uniqueName()); // Write the friendly name contextGroup.writeEntry("_k_friendly_name", context->friendlyName()); } // qCDebug(KGLOBALACCELD) << "writing group " << _uniqueName << ":" << context->uniqueName(); - Q_FOREACH(const GlobalShortcut *shortcut, context->_actions) + for (const GlobalShortcut *shortcut : qAsConst(context->_actions)) { // qCDebug(KGLOBALACCELD) << "writing" << shortcut->uniqueName(); // We do not write fresh shortcuts. // We do not write session shortcuts if (shortcut->isFresh() || shortcut->isSessionShortcut()) { continue; } // qCDebug(KGLOBALACCELD) << "really writing" << shortcut->uniqueName(); QStringList entry(stringFromKeys(shortcut->keys())); entry.append(stringFromKeys(shortcut->defaultKeys())); entry.append(shortcut->friendlyName()); contextGroup.writeEntry(shortcut->uniqueName(), entry); } } } } // namespace KdeDGlobalAccel diff --git a/src/runtime/globalshortcut.cpp b/src/runtime/globalshortcut.cpp index 281f762..31d18fd 100644 --- a/src/runtime/globalshortcut.cpp +++ b/src/runtime/globalshortcut.cpp @@ -1,255 +1,255 @@ /* Copyright (C) 2008 Michael Jansen 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 "globalshortcut.h" #ifdef __GNUC__ #warning Remove private header kglobalshortcutinfo_p.once this kglobalaccel daemon is merged with the kglobalaccel framework #endif #include "kglobalshortcutinfo_p.h" #include "component.h" #include "globalshortcutcontext.h" #include "globalshortcutsregistry.h" #include "logging_p.h" #include #include GlobalShortcut::GlobalShortcut() : _isPresent(false) ,_isRegistered(false) ,_isFresh(true) ,_context(nullptr) ,_uniqueName() ,_friendlyName() ,_keys() ,_defaultKeys() {} GlobalShortcut::GlobalShortcut( const QString &uniqueName, const QString &friendlyName, GlobalShortcutContext *context) : _isPresent(false) ,_isRegistered(false) ,_isFresh(true) ,_context(context) ,_uniqueName(uniqueName) ,_friendlyName(friendlyName) ,_keys() ,_defaultKeys() { context->addShortcut(this); } GlobalShortcut::~GlobalShortcut() { setInactive(); } GlobalShortcut::operator KGlobalShortcutInfo () const { KGlobalShortcutInfo info; info.d->uniqueName = _uniqueName; info.d->friendlyName = _friendlyName; info.d->contextUniqueName = context()->uniqueName(); info.d->contextFriendlyName = context()->friendlyName(); info.d->componentUniqueName = context()->component()->uniqueName(); info.d->componentFriendlyName = context()->component()->friendlyName(); - Q_FOREACH (int key, _keys) + for (int key : qAsConst(_keys)) { info.d->keys.append(QKeySequence(key)); } - Q_FOREACH (int key, _defaultKeys) + for (int key : qAsConst(_defaultKeys)) { info.d->defaultKeys.append(QKeySequence(key)); } return info; } bool GlobalShortcut::isActive() const { return _isRegistered; } bool GlobalShortcut::isFresh() const { return _isFresh; } bool GlobalShortcut::isPresent() const { return _isPresent; } bool GlobalShortcut::isSessionShortcut() const { return uniqueName().startsWith(QLatin1String("_k_session:")); } void GlobalShortcut::setIsFresh(bool value) { _isFresh = value; } void GlobalShortcut::setIsPresent(bool value) { // (de)activate depending on old/new value _isPresent = value; value ? setActive() : setInactive(); } GlobalShortcutContext *GlobalShortcut::context() { return _context; } GlobalShortcutContext const *GlobalShortcut::context() const { return _context; } QString GlobalShortcut::uniqueName() const { return _uniqueName; } void GlobalShortcut::unRegister() { return _context->component()->unregisterShortcut(uniqueName()); } QString GlobalShortcut::friendlyName() const { return _friendlyName; } void GlobalShortcut::setFriendlyName(const QString &name) { _friendlyName = name; } QList GlobalShortcut::keys() const { return _keys; } void GlobalShortcut::setKeys(const QList newKeys) { bool active = _isRegistered; if (active) { setInactive(); } _keys = QList(); - Q_FOREACH(int key, newKeys) + for(int key : qAsConst(newKeys)) { if (key!=0 && !GlobalShortcutsRegistry::self()->getShortcutByKey(key)) { _keys.append(key); } else { qCDebug(KGLOBALACCELD) << _uniqueName << "skipping because key" << QKeySequence(key).toString() << "is already taken"; _keys.append(0); } } if (active) { setActive(); } } QList GlobalShortcut::defaultKeys() const { return _defaultKeys; } void GlobalShortcut::setDefaultKeys(const QList newKeys) { _defaultKeys = newKeys; } void GlobalShortcut::setActive() { if (!_isPresent || _isRegistered) { // The corresponding application is not present or the keys are // already grabbed return; } - Q_FOREACH( int key, _keys) + for( int key : qAsConst(_keys)) { if (key != 0 && !GlobalShortcutsRegistry::self()->registerKey(key, this)) { qCDebug(KGLOBALACCELD) << uniqueName() << ": Failed to register " << QKeySequence(key).toString(); } } _isRegistered = true; } void GlobalShortcut::setInactive() { if (!_isRegistered) { // The keys are not grabbed currently return; } - Q_FOREACH( int key, _keys) + for( int key : qAsConst(_keys)) { if (key != 0 && !GlobalShortcutsRegistry::self()->unregisterKey(key, this)) { qCDebug(KGLOBALACCELD) << uniqueName() << ": Failed to unregister " << QKeySequence(key).toString(); } } _isRegistered = false; } diff --git a/src/runtime/globalshortcutcontext.cpp b/src/runtime/globalshortcutcontext.cpp index b25a6ea..1d1b7bf 100644 --- a/src/runtime/globalshortcutcontext.cpp +++ b/src/runtime/globalshortcutcontext.cpp @@ -1,116 +1,116 @@ /* Copyright (C) 2008 Michael Jansen 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 "globalshortcutcontext.h" #include "globalshortcut.h" #include GlobalShortcutContext::GlobalShortcutContext( const QString &uniqueName, const QString &friendlyName, KdeDGlobalAccel::Component *component) : _uniqueName(uniqueName), _friendlyName(friendlyName), _component(component), _actions() {} GlobalShortcutContext::~GlobalShortcutContext() { qDeleteAll(_actions); _actions.clear(); } void GlobalShortcutContext::addShortcut(GlobalShortcut *shortcut) { _actions.insert(shortcut->uniqueName(), shortcut); } QList GlobalShortcutContext::allShortcutInfos() const { QList rc; - Q_FOREACH (GlobalShortcut *shortcut, _actions) + for (GlobalShortcut *shortcut : qAsConst(_actions)) { rc.append(static_cast(*shortcut)); } return rc; } KdeDGlobalAccel::Component const *GlobalShortcutContext::component() const { return _component; } KdeDGlobalAccel::Component *GlobalShortcutContext::component() { return _component; } QString GlobalShortcutContext::friendlyName() const { return _friendlyName; } GlobalShortcut *GlobalShortcutContext::getShortcutByKey(int key) const { // Qt triggers both shortcuts that include Shift+Backtab and Shift+Tab // when user presses Shift+Tab. Do the same here. int keySym = key & ~Qt::KeyboardModifierMask; int keyMod = key & Qt::KeyboardModifierMask; if ((keyMod & Qt::SHIFT) && (keySym == Qt::Key_Backtab || keySym == Qt::Key_Tab)) { - Q_FOREACH(GlobalShortcut *sc, _actions) + for (GlobalShortcut *sc : qAsConst(_actions)) { if (sc->keys().contains(keyMod | Qt::Key_Tab) || sc->keys().contains(keyMod | Qt::Key_Backtab)) return sc; } } else { - Q_FOREACH(GlobalShortcut *sc, _actions) + for (GlobalShortcut *sc : qAsConst(_actions)) { if (sc->keys().contains(key)) return sc; } } return nullptr; } GlobalShortcut *GlobalShortcutContext::takeShortcut(GlobalShortcut *shortcut) { // Try to take the shortcut. Result could be nullptr if the shortcut doesn't // belong to this component. return _actions.take(shortcut->uniqueName()); } QString GlobalShortcutContext::uniqueName() const { return _uniqueName; } diff --git a/src/runtime/globalshortcutsregistry.cpp b/src/runtime/globalshortcutsregistry.cpp index d94c798..25c3a1b 100644 --- a/src/runtime/globalshortcutsregistry.cpp +++ b/src/runtime/globalshortcutsregistry.cpp @@ -1,440 +1,445 @@ /* Copyright (C) 2008 Michael Jansen 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 "globalshortcutsregistry.h" #include "component.h" #include "kserviceactioncomponent.h" #include "globalshortcut.h" #include "globalshortcutcontext.h" #include #include "logging_p.h" #include "kglobalaccel_interface.h" #include #include #include #include #include #include #include #include #include #include static KGlobalAccelInterface *loadPlugin(GlobalShortcutsRegistry *parent) { const QVector candidates = KPluginLoader::findPlugins(QStringLiteral("org.kde.kglobalaccel5.platforms")); QString platformName = QString::fromLocal8Bit(qgetenv("KGLOBALACCELD_PLATFORM")); if (platformName.isEmpty()) { platformName = QGuiApplication::platformName(); } - foreach (const KPluginMetaData &candidate, candidates) { + for (const KPluginMetaData &candidate : candidates) { const QJsonArray platforms = candidate.rawData().value(QStringLiteral("platforms")).toArray(); for (auto it = platforms.begin(); it != platforms.end(); ++it) { if (QString::compare(platformName, (*it).toString(), Qt::CaseInsensitive) == 0) { KGlobalAccelInterface *interface = qobject_cast< KGlobalAccelInterface* >(candidate.instantiate()); if (interface) { qCDebug(KGLOBALACCELD) << "Loaded plugin" << candidate.fileName() << "for platform" << platformName; interface->setRegistry(parent); return interface; } } } } qCWarning(KGLOBALACCELD) << "Could not find any platform plugin"; return nullptr; } GlobalShortcutsRegistry::GlobalShortcutsRegistry() : QObject() ,_active_keys() ,_components() ,_manager(loadPlugin(this)) ,_config(qEnvironmentVariableIsSet("KGLOBALACCEL_TEST_MODE") ? QString() : QStringLiteral("kglobalshortcutsrc"), KConfig::SimpleConfig) { if (_manager) { _manager->setEnabled(true); } } GlobalShortcutsRegistry::~GlobalShortcutsRegistry() { if (_manager) { _manager->setEnabled(false); // Ungrab all keys. We don't go over GlobalShortcuts because // GlobalShortcutsRegistry::self() doesn't work anymore. - Q_FOREACH (const int key, _active_keys.keys()) + const auto listKeys = _active_keys.keys(); + for (const int key : listKeys) { _manager->grabKey(key, false); } } _active_keys.clear(); } KdeDGlobalAccel::Component *GlobalShortcutsRegistry::addComponent(KdeDGlobalAccel::Component *component) { if (_components.value(component->uniqueName())) { Q_ASSERT_X(false, "GlobalShortcutsRegistry::addComponent", "component already registered?!?!"); return _components.value(component->uniqueName()); } _components.insert(component->uniqueName(), component); QDBusConnection conn(QDBusConnection::sessionBus()); conn.registerObject( component->dbusPath().path(), component, QDBusConnection::ExportScriptableContents); return component; } void GlobalShortcutsRegistry::activateShortcuts() { - Q_FOREACH (KdeDGlobalAccel::Component *component, _components) + for (KdeDGlobalAccel::Component *component : qAsConst(_components)) { component->activateShortcuts(); } } QList GlobalShortcutsRegistry::allMainComponents() const { return _components.values(); } void GlobalShortcutsRegistry::clear() { - Q_FOREACH(KdeDGlobalAccel::Component *component, _components) + for (KdeDGlobalAccel::Component *component : qAsConst(_components)) { delete component; } _components.clear(); // The shortcuts should have deregistered themselves Q_ASSERT(_active_keys.isEmpty()); } QDBusObjectPath GlobalShortcutsRegistry::dbusPath() const { return _dbusPath; } void GlobalShortcutsRegistry::deactivateShortcuts(bool temporarily) { - Q_FOREACH (KdeDGlobalAccel::Component *component, _components) + for (KdeDGlobalAccel::Component *component : qAsConst(_components)) { component->deactivateShortcuts(temporarily); } } GlobalShortcut *GlobalShortcutsRegistry::getActiveShortcutByKey(int key) const { return _active_keys.value(key); } KdeDGlobalAccel::Component *GlobalShortcutsRegistry::getComponent(const QString &uniqueName) { return _components.value(uniqueName); } GlobalShortcut *GlobalShortcutsRegistry::getShortcutByKey(int key) const { - Q_FOREACH (KdeDGlobalAccel::Component *component, _components) + for (KdeDGlobalAccel::Component *component : qAsConst(_components)) { GlobalShortcut *rc = component->getShortcutByKey(key); if (rc) return rc; } return nullptr; } QList GlobalShortcutsRegistry::getShortcutsByKey(int key) const { QList rc; - Q_FOREACH (KdeDGlobalAccel::Component *component, _components) + for (KdeDGlobalAccel::Component *component : qAsConst(_components)) { rc = component->getShortcutsByKey(key); if (!rc.isEmpty()) return rc; } return rc; } bool GlobalShortcutsRegistry::isShortcutAvailable( int shortcut, const QString &componentName, const QString &contextName) const { - Q_FOREACH (KdeDGlobalAccel::Component *component, _components) + for (KdeDGlobalAccel::Component *component : qAsConst(_components)) { if (!component->isShortcutAvailable(shortcut, componentName, contextName)) return false; } return true; } Q_GLOBAL_STATIC( GlobalShortcutsRegistry, _self ) GlobalShortcutsRegistry * GlobalShortcutsRegistry::self() { return _self; } bool GlobalShortcutsRegistry::keyPressed(int keyQt) { GlobalShortcut *shortcut = getShortcutByKey(keyQt); if (!shortcut) { // This can happen for example with the ALT-Print shortcut of kwin. // ALT+PRINT is SYSREQ on my keyboard. So we grab something we think // is ALT+PRINT but symXToKeyQt and modXToQt make ALT+SYSREQ of it // when pressed (correctly). We can't match that. #ifdef KDEDGLOBALACCEL_TRACE qCDebug(KGLOBALACCELD) << "Got unknown key" << QKeySequence(keyQt).toString(); #endif // In production mode just do nothing. return false; } else if (!shortcut->isActive()) { #ifdef KDEDGLOBALACCEL_TRACE qCDebug(KGLOBALACCELD) << "Got inactive key" << QKeySequence(keyQt).toString(); #endif // In production mode just do nothing. return false; } #ifdef KDEDGLOBALACCEL_TRACE qCDebug(KGLOBALACCELD) << QKeySequence(keyQt).toString() << "=" << shortcut->uniqueName(); #endif QStringList data(shortcut->context()->component()->uniqueName()); data.append(shortcut->uniqueName()); data.append(shortcut->context()->component()->friendlyName()); data.append(shortcut->friendlyName()); // Make sure kglobalacceld has ungrabbed the keyboard after receiving the // keypress, otherwise actions in application that try to grab the // keyboard (e.g. in kwin) may fail to do so. There is still a small race // condition with this being out-of-process. if (_manager) { _manager->syncWindowingSystem(); } // 1st Invoke the action shortcut->context()->component()->emitGlobalShortcutPressed( *shortcut ); return true; } void GlobalShortcutsRegistry::loadSettings() { - foreach (const QString &groupName, _config.groupList()) + const auto groupList = _config.groupList(); + for (const QString &groupName : groupList) { qCDebug(KGLOBALACCELD) << "Loading group " << groupName; Q_ASSERT(groupName.indexOf('\x1d')==-1); // loadSettings isn't designed to be called in between. Only at the // beginning. Q_ASSERT(!getComponent(groupName)); KConfigGroup configGroup(&_config, groupName); // We previously stored the friendly name in a separate group. migrate // that const QString friendlyName = configGroup.readEntry("_k_friendly_name"); // Create the component KdeDGlobalAccel::Component *component = nullptr; if (groupName.endsWith(QLatin1String(".desktop"))) { component = new KdeDGlobalAccel::KServiceActionComponent( groupName, friendlyName, this); } else { component = new KdeDGlobalAccel::Component( groupName, friendlyName, this); } // Now load the contexts - Q_FOREACH(const QString& context, configGroup.groupList()) + const auto groupList = configGroup.groupList(); + for (const QString& context : groupList) { // Skip the friendly name group if (context==QLatin1String("Friendly Name")) continue; KConfigGroup contextGroup(&configGroup, context); QString contextFriendlyName = contextGroup.readEntry("_k_friendly_name"); component->createGlobalShortcutContext(context, contextFriendlyName); component->activateGlobalShortcutContext(context); component->loadSettings(contextGroup); } // Load the default context component->activateGlobalShortcutContext("default"); component->loadSettings(configGroup); } // Load the configured KServiceActions const QStringList desktopPaths = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kglobalaccel"), QStandardPaths::LocateDirectory); - foreach (const QString &path, desktopPaths) { + for (const QString &path : desktopPaths) { QDir dir(path); if (!dir.exists()) { continue; } const QStringList patterns = {QStringLiteral("*.desktop")}; - foreach (const QString &desktopFile, dir.entryList(patterns)) { + const auto lstDesktopFiles = dir.entryList(patterns); + for (const QString &desktopFile : lstDesktopFiles) { if (_components.contains(desktopFile)) { continue; } KDesktopFile f(dir.filePath(desktopFile)); if (f.noDisplay()) { continue; } KdeDGlobalAccel::KServiceActionComponent *component = new KdeDGlobalAccel::KServiceActionComponent( desktopFile, f.readName(), this); component->activateGlobalShortcutContext(QStringLiteral("default")); component->loadFromService(); } } } void GlobalShortcutsRegistry::grabKeys() { activateShortcuts(); } bool GlobalShortcutsRegistry::registerKey(int key, GlobalShortcut *shortcut) { if (!_manager) { return false; } if (key == 0) { qCDebug(KGLOBALACCELD) << shortcut->uniqueName() << ": Key '" << QKeySequence(key).toString() << "' already taken by " << _active_keys.value(key)->uniqueName() << "."; return false; } else if (_active_keys.value(key)) { qCDebug(KGLOBALACCELD) << shortcut->uniqueName() << ": Attempt to register key 0."; return false; } qCDebug(KGLOBALACCELD) << "Registering key" << QKeySequence(key).toString() << "for" << shortcut->context()->component()->uniqueName() << ":" << shortcut->uniqueName(); _active_keys.insert(key, shortcut); return _manager->grabKey(key, true); } void GlobalShortcutsRegistry::setAccelManager(KGlobalAccelInterface *manager) { _manager = manager; } void GlobalShortcutsRegistry::setDBusPath(const QDBusObjectPath &path) { _dbusPath = path; } KdeDGlobalAccel::Component *GlobalShortcutsRegistry::takeComponent(KdeDGlobalAccel::Component *component) { QDBusConnection conn(QDBusConnection::sessionBus()); conn.unregisterObject(component->dbusPath().path()); return _components.take(component->uniqueName()); } void GlobalShortcutsRegistry::ungrabKeys() { deactivateShortcuts(); } bool GlobalShortcutsRegistry::unregisterKey(int key, GlobalShortcut *shortcut) { if (!_manager) { return false; } if (_active_keys.value(key)!=shortcut) { // The shortcut doesn't own the key or the key isn't grabbed return false; } qCDebug(KGLOBALACCELD) << "Unregistering key" << QKeySequence(key).toString() << "for" << shortcut->context()->component()->uniqueName() << ":" << shortcut->uniqueName(); _manager->grabKey(key, false); _active_keys.take(key); return true; } void GlobalShortcutsRegistry::writeSettings() const { - Q_FOREACH( - const KdeDGlobalAccel::Component *component, - GlobalShortcutsRegistry::self()->allMainComponents()) + const auto lst = GlobalShortcutsRegistry::self()->allMainComponents(); + for ( + const KdeDGlobalAccel::Component *component : lst + ) { KConfigGroup configGroup(&_config, component->uniqueName()); if (component->allShortcuts().isEmpty()) { configGroup.deleteGroup(); delete component; } else { component->writeSettings(configGroup); } } _config.sync(); } #include "moc_globalshortcutsregistry.cpp" diff --git a/src/runtime/kglobalacceld.cpp b/src/runtime/kglobalacceld.cpp index eb8eaaa..84b2795 100644 --- a/src/runtime/kglobalacceld.cpp +++ b/src/runtime/kglobalacceld.cpp @@ -1,583 +1,585 @@ /* This file is part of the KDE libraries Copyright (c) 2007 Andreas Hartmetz Copyright (c) 2007 Michael Jansen 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 "kglobalacceld.h" #include "component.h" #include "globalshortcut.h" #include "globalshortcutcontext.h" #include "globalshortcutsregistry.h" #include "logging_p.h" #include "kserviceactioncomponent.h" #include #include #include #include #include "kglobalaccel.h" #include struct KGlobalAccelDPrivate { KGlobalAccelDPrivate(KGlobalAccelD *q) : q(q) {} GlobalShortcut *findAction(const QStringList &actionId) const; /** * Find the action @a shortcutUnique in @a componentUnique. * * @return the action or @c nullptr if doesn't exist */ GlobalShortcut *findAction( const QString &componentUnique, const QString &shortcutUnique) const; GlobalShortcut *addAction(const QStringList &actionId); KdeDGlobalAccel::Component *component(const QStringList &actionId) const; void splitComponent(QString &component, QString &context) const { context = QStringLiteral("default"); if (component.indexOf('|')!=-1) { QStringList tmp = component.split('|'); Q_ASSERT(tmp.size()==2); component= tmp.at(0); context= tmp.at(1); } } //! Timer for delayed writing to kglobalshortcutsrc QTimer writeoutTimer; //! Our holder KGlobalAccelD *q; }; GlobalShortcut *KGlobalAccelDPrivate::findAction(const QStringList &actionId) const { // Check if actionId is valid if (actionId.size() != 4) { qCDebug(KGLOBALACCELD) << "Invalid! '" << actionId << "'"; return nullptr; } return findAction( actionId.at(KGlobalAccel::ComponentUnique), actionId.at(KGlobalAccel::ActionUnique)); } GlobalShortcut *KGlobalAccelDPrivate::findAction( const QString &_componentUnique, const QString &shortcutUnique) const { QString componentUnique = _componentUnique; KdeDGlobalAccel::Component *component; QString contextUnique; if (componentUnique.indexOf('|')==-1) { component = GlobalShortcutsRegistry::self()->getComponent( componentUnique); if (component) contextUnique = component->currentContext()->uniqueName(); } else { splitComponent(componentUnique, contextUnique); component = GlobalShortcutsRegistry::self()->getComponent( componentUnique); } if (!component) { #ifdef KDEDGLOBALACCEL_TRACE qCDebug(KGLOBALACCELD) << componentUnique << "not found"; #endif return nullptr; } GlobalShortcut *shortcut = component->getShortcutByName(shortcutUnique, contextUnique); #ifdef KDEDGLOBALACCEL_TRACE if (shortcut) { qCDebug(KGLOBALACCELD) << componentUnique << contextUnique << shortcut->uniqueName(); } else { qCDebug(KGLOBALACCELD) << "No match for" << shortcutUnique; } #endif return shortcut; } KdeDGlobalAccel::Component *KGlobalAccelDPrivate::component(const QStringList &actionId) const { // Get the component for the action. If we have none create a new one KdeDGlobalAccel::Component *component = GlobalShortcutsRegistry::self()->getComponent(actionId.at(KGlobalAccel::ComponentUnique)); if (!component) { if (actionId.at(KGlobalAccel::ComponentUnique).endsWith(QLatin1String(".desktop"))) { component = new KdeDGlobalAccel::KServiceActionComponent( actionId.at(KGlobalAccel::ComponentUnique), actionId.at(KGlobalAccel::ComponentFriendly), GlobalShortcutsRegistry::self()); component->activateGlobalShortcutContext(QStringLiteral("default")); static_cast(component)->loadFromService(); } else { component = new KdeDGlobalAccel::Component( actionId.at(KGlobalAccel::ComponentUnique), actionId.at(KGlobalAccel::ComponentFriendly), GlobalShortcutsRegistry::self()); } Q_ASSERT(component); } return component; } GlobalShortcut *KGlobalAccelDPrivate::addAction(const QStringList &actionId) { Q_ASSERT(actionId.size() >= 4); QString componentUnique = actionId.at(KGlobalAccel::ComponentUnique); QString contextUnique = QStringLiteral("default"); if (componentUnique.indexOf('|')!=-1) { QStringList tmp = componentUnique.split('|'); Q_ASSERT(tmp.size()==2); componentUnique = tmp.at(0); contextUnique = tmp.at(1); } QStringList actionIdTmp = actionId; actionIdTmp.replace(KGlobalAccel::ComponentUnique, componentUnique); // Create the component if necessary KdeDGlobalAccel::Component *component = this->component(actionIdTmp); Q_ASSERT(component); // Create the context if necessary if (component->getShortcutContexts().count(contextUnique)==0) { component->createGlobalShortcutContext(contextUnique); } Q_ASSERT(!component->getShortcutByName(componentUnique, contextUnique)); return new GlobalShortcut( actionId.at(KGlobalAccel::ActionUnique), actionId.at(KGlobalAccel::ActionFriendly), component->shortcutContext(contextUnique)); } Q_DECLARE_METATYPE(QStringList) KGlobalAccelD::KGlobalAccelD(QObject* parent) : QObject(parent), d(new KGlobalAccelDPrivate(this)) {} bool KGlobalAccelD::init() { qDBusRegisterMetaType< QList >(); qDBusRegisterMetaType< QList >(); qDBusRegisterMetaType< QList >(); qDBusRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType< QList >(); GlobalShortcutsRegistry *reg = GlobalShortcutsRegistry::self(); Q_ASSERT(reg); d->writeoutTimer.setSingleShot(true); connect(&d->writeoutTimer, SIGNAL(timeout()), reg, SLOT(writeSettings())); if (!QDBusConnection::sessionBus().registerService(QLatin1String("org.kde.kglobalaccel"))) { qCWarning(KGLOBALACCELD) << "Failed to register service org.kde.kglobalaccel"; return false; } if (!QDBusConnection::sessionBus().registerObject( QStringLiteral("/kglobalaccel"), this, QDBusConnection::ExportScriptableContents)) { qCWarning(KGLOBALACCELD) << "Failed to register object kglobalaccel in org.kde.kglobalaccel"; return false; } GlobalShortcutsRegistry::self()->setDBusPath(QDBusObjectPath("/")); GlobalShortcutsRegistry::self()->loadSettings(); return true; } KGlobalAccelD::~KGlobalAccelD() { GlobalShortcutsRegistry *const reg = GlobalShortcutsRegistry::self(); if (d->writeoutTimer.isActive()) { d->writeoutTimer.stop(); reg->writeSettings(); } reg->deactivateShortcuts(); delete d; } QList KGlobalAccelD::allMainComponents() const { QList ret; QStringList emptyList; emptyList.reserve(4); for (int i = 0; i < 4; i++) { emptyList.append(QString()); } const auto components = GlobalShortcutsRegistry::self()->allMainComponents(); ret.reserve(components.size() * 4); for (const KdeDGlobalAccel::Component *component : components) { QStringList actionId(emptyList); actionId[KGlobalAccel::ComponentUnique] = component->uniqueName(); actionId[KGlobalAccel::ComponentFriendly] = component->friendlyName(); ret.append(actionId); } return ret; } QList KGlobalAccelD::allActionsForComponent(const QStringList &actionId) const { //### Would it be advantageous to sort the actions by unique name? QList ret; KdeDGlobalAccel::Component *const component = GlobalShortcutsRegistry::self()->getComponent(actionId[KGlobalAccel::ComponentUnique]); if (!component) { return ret; } QStringList partialId(actionId[KGlobalAccel::ComponentUnique]); //ComponentUnique partialId.append(QString()); //ActionUnique //Use our internal friendlyName, not the one passed in. We should have the latest data. partialId.append(component->friendlyName()); //ComponentFriendly partialId.append(QString()); //ActionFriendly - foreach (const GlobalShortcut *const shortcut, component->allShortcuts()) { + const auto listShortcuts = component->allShortcuts(); + for (const GlobalShortcut *const shortcut : listShortcuts) { if (shortcut->isFresh()) { // isFresh is only an intermediate state, not to be reported outside. continue; } QStringList actionId(partialId); actionId[KGlobalAccel::ActionUnique] = shortcut->uniqueName(); actionId[KGlobalAccel::ActionFriendly] = shortcut->friendlyName(); ret.append(actionId); } return ret; } QStringList KGlobalAccelD::action(int key) const { GlobalShortcut *shortcut = GlobalShortcutsRegistry::self()->getShortcutByKey(key); QStringList ret; if (shortcut) { ret.append(shortcut->context()->component()->uniqueName()); ret.append(shortcut->uniqueName()); ret.append(shortcut->context()->component()->friendlyName()); ret.append(shortcut->friendlyName()); } return ret; } void KGlobalAccelD::activateGlobalShortcutContext( const QString &component, const QString &uniqueName) { KdeDGlobalAccel::Component *const comp = GlobalShortcutsRegistry::self()->getComponent(component); if (comp) comp->activateGlobalShortcutContext(uniqueName); } QList KGlobalAccelD::allComponents() const { QList allComp; - Q_FOREACH (const KdeDGlobalAccel::Component *component, - GlobalShortcutsRegistry::self()->allMainComponents()) + const auto lstMainComponents = GlobalShortcutsRegistry::self()->allMainComponents(); + for (const KdeDGlobalAccel::Component *component : + lstMainComponents) { allComp.append(component->dbusPath()); } return allComp; } void KGlobalAccelD::blockGlobalShortcuts(bool block) { #ifdef KDEDGLOBALACCEL_TRACE qCDebug(KGLOBALACCELD) << block; #endif block ? GlobalShortcutsRegistry::self()->deactivateShortcuts(true) : GlobalShortcutsRegistry::self()->activateShortcuts(); } QList KGlobalAccelD::shortcut(const QStringList &action) const { GlobalShortcut *shortcut = d->findAction(action); if (shortcut) return shortcut->keys(); return QList(); } QList KGlobalAccelD::defaultShortcut(const QStringList &action) const { GlobalShortcut *shortcut = d->findAction(action); if (shortcut) return shortcut->defaultKeys(); return QList(); } // This method just registers the action. Nothing else. Shortcut has to be set // later. void KGlobalAccelD::doRegister(const QStringList &actionId) { #ifdef KDEDGLOBALACCEL_TRACE qCDebug(KGLOBALACCELD) << actionId; #endif // Check because we would not want to add a action for an invalid // actionId. findAction returns nullptr in that case. if (actionId.size() < 4) { return; } GlobalShortcut *shortcut = d->findAction(actionId); if (!shortcut) { shortcut = d->addAction(actionId); } else { //a switch of locales is one common reason for a changing friendlyName if ((!actionId[KGlobalAccel::ActionFriendly].isEmpty()) && shortcut->friendlyName() != actionId[KGlobalAccel::ActionFriendly]) { shortcut->setFriendlyName(actionId[KGlobalAccel::ActionFriendly]); scheduleWriteSettings(); } if ((!actionId[KGlobalAccel::ComponentFriendly].isEmpty()) && shortcut->context()->component()->friendlyName() != actionId[KGlobalAccel::ComponentFriendly]) { shortcut->context()->component()->setFriendlyName(actionId[KGlobalAccel::ComponentFriendly]); scheduleWriteSettings(); } } } QDBusObjectPath KGlobalAccelD::getComponent(const QString &componentUnique) const { #ifdef KDEDGLOBALACCEL_TRACE qCDebug(KGLOBALACCELD) << componentUnique; #endif KdeDGlobalAccel::Component *component = GlobalShortcutsRegistry::self()->getComponent(componentUnique); if (component) { return component->dbusPath(); } else { sendErrorReply("org.kde.kglobalaccel.NoSuchComponent", QString("The component '%1' doesn't exist.").arg(componentUnique)); return QDBusObjectPath("/"); } } QList KGlobalAccelD::getGlobalShortcutsByKey(int key) const { #ifdef KDEDGLOBALACCEL_TRACE qCDebug(KGLOBALACCELD) << key; #endif - QList shortcuts = + const QList shortcuts = GlobalShortcutsRegistry::self()->getShortcutsByKey(key); QList rc; - Q_FOREACH(const GlobalShortcut *sc, shortcuts) + for (const GlobalShortcut *sc : shortcuts) { #ifdef KDEDGLOBALACCEL_TRACE qCDebug(KGLOBALACCELD) << sc->context()->uniqueName() << sc->uniqueName(); #endif rc.append(static_cast(*sc)); } return rc; } bool KGlobalAccelD::isGlobalShortcutAvailable(int shortcut, const QString &component) const { QString realComponent = component; QString context; d->splitComponent(realComponent, context); return GlobalShortcutsRegistry::self()->isShortcutAvailable(shortcut, realComponent, context); } void KGlobalAccelD::setInactive(const QStringList &actionId) { #ifdef KDEDGLOBALACCEL_TRACE qCDebug(KGLOBALACCELD) << actionId; #endif GlobalShortcut *shortcut = d->findAction(actionId); if (shortcut) shortcut->setIsPresent(false); } bool KGlobalAccelD::unregister(const QString &componentUnique, const QString &shortcutUnique) { #ifdef KDEDGLOBALACCEL_TRACE qCDebug(KGLOBALACCELD) << componentUnique << shortcutUnique; #endif // Stop grabbing the key GlobalShortcut *shortcut = d->findAction(componentUnique, shortcutUnique); if (shortcut) { shortcut->unRegister(); scheduleWriteSettings(); } return shortcut; } void KGlobalAccelD::unRegister(const QStringList &actionId) { #ifdef KDEDGLOBALACCEL_TRACE qCDebug(KGLOBALACCELD) << actionId; #endif // Stop grabbing the key GlobalShortcut *shortcut = d->findAction(actionId); if (shortcut) { shortcut->unRegister(); scheduleWriteSettings(); } } QList KGlobalAccelD::setShortcut(const QStringList &actionId, const QList &keys, uint flags) { //spare the DBus framework some work const bool setPresent = (flags & SetPresent); const bool isAutoloading = !(flags & NoAutoloading); const bool isDefault = (flags & IsDefault); GlobalShortcut *shortcut = d->findAction(actionId); if (!shortcut) { return QList(); } //default shortcuts cannot clash because they don't do anything if (isDefault) { if (shortcut->defaultKeys() != keys) { shortcut->setDefaultKeys(keys); scheduleWriteSettings(); } return keys; //doesn't matter } if (isAutoloading && !shortcut->isFresh()) { //the trivial and common case - synchronize the action from our data //and exit. if (!shortcut->isPresent() && setPresent) { shortcut->setIsPresent(true); } // We are finished here. Return the list of current active keys. return shortcut->keys(); } //now we are actually changing the shortcut of the action shortcut->setKeys(keys); if (setPresent) { shortcut->setIsPresent(true); } //maybe isFresh should really only be set if setPresent, but only two things should use !setPresent: //- the global shortcuts KCM: very unlikely to catch KWin/etc.'s actions in isFresh state //- KGlobalAccel::stealGlobalShortcutSystemwide(): only applies to actions with shortcuts // which can never be fresh if created the usual way shortcut->setIsFresh(false); scheduleWriteSettings(); return shortcut->keys(); } void KGlobalAccelD::setForeignShortcut(const QStringList &actionId, const QList &keys) { #ifdef KDEDGLOBALACCEL_TRACE qCDebug(KGLOBALACCELD) << actionId; #endif GlobalShortcut *shortcut = d->findAction(actionId); if (!shortcut) return; QList newKeys = setShortcut(actionId, keys, NoAutoloading); emit yourShortcutGotChanged(actionId, newKeys); } void KGlobalAccelD::scheduleWriteSettings() const { if (!d->writeoutTimer.isActive()) d->writeoutTimer.start(500); } #include "moc_kglobalacceld.cpp" diff --git a/src/runtime/kserviceactioncomponent.cpp b/src/runtime/kserviceactioncomponent.cpp index 2312c82..65bedbb 100644 --- a/src/runtime/kserviceactioncomponent.cpp +++ b/src/runtime/kserviceactioncomponent.cpp @@ -1,153 +1,154 @@ /* Copyright (C) 2008 Michael Jansen Copyright (C) 2016 Marco Martin 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 "kserviceactioncomponent.h" #include "globalshortcutcontext.h" #include "logging_p.h" #include #include #include #include namespace KdeDGlobalAccel { KServiceActionComponent::KServiceActionComponent( const QString &serviceStorageId, const QString &friendlyName, GlobalShortcutsRegistry *registry) : Component(serviceStorageId, friendlyName, registry), m_serviceStorageId(serviceStorageId), m_desktopFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kglobalaccel/") + serviceStorageId)) { } KServiceActionComponent::~KServiceActionComponent() { } void KServiceActionComponent::emitGlobalShortcutPressed( const GlobalShortcut &shortcut ) { QDBusConnectionInterface *dbusDaemon = QDBusConnection::sessionBus().interface(); const bool klauncherAvailable = dbusDaemon->isServiceRegistered(QStringLiteral("org.kde.klauncher5")); //we can't use KRun there as it depends from KIO and would create a circular dep if (shortcut.uniqueName() == QStringLiteral("_launch")) { QStringList parts = m_desktopFile.desktopGroup().readEntry(QStringLiteral("Exec"), QString()).split(QChar(' ')); if (parts.isEmpty()) { return; } const QString command = parts.first(); //sometimes entries have an %u for command line parameters if (parts.last().contains(QChar('%'))) { parts.pop_back(); } parts.pop_front(); if (klauncherAvailable) { QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.klauncher5"), QStringLiteral("/KLauncher"), QStringLiteral("org.kde.KLauncher"), QStringLiteral("exec_blind")); msg << command << parts; QDBusConnection::sessionBus().asyncCall(msg); } else { QProcess::startDetached(m_desktopFile.desktopGroup().readEntry(QStringLiteral("Exec"), QString())); } return; } - foreach (const QString &action, m_desktopFile.readActions()) { + const auto lstActions = m_desktopFile.readActions(); + for (const QString &action : lstActions) { if (action == shortcut.uniqueName()) { QStringList parts = m_desktopFile.actionGroup(action).readEntry(QStringLiteral("Exec"), QString()).split(QChar(' ')); if (parts.isEmpty()) { return; } const QString command = parts.first(); //sometimes entries have an %u for command line parameters if (parts.last().contains(QChar('%'))) { parts.pop_back(); } parts.pop_front(); if (klauncherAvailable) { QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.klauncher5"), QStringLiteral("/KLauncher"), QStringLiteral("org.kde.KLauncher"), QStringLiteral("exec_blind")); msg << command << parts; QDBusConnection::sessionBus().asyncCall(msg); } else { QProcess::startDetached(command, parts); } return; } } } void KServiceActionComponent::loadFromService() { QString shortcutString; QStringList shortcuts = m_desktopFile.desktopGroup().readEntry(QStringLiteral("X-KDE-Shortcuts"), QString()).split(QChar(',')); if (!shortcuts.isEmpty()) { shortcutString = shortcuts.join(QChar('\t')); } GlobalShortcut *shortcut = registerShortcut(QStringLiteral("_launch"), m_desktopFile.readName(), shortcutString, shortcutString); shortcut->setIsPresent(true); - - foreach(const QString &action, m_desktopFile.readActions()) + const auto lstActions = m_desktopFile.readActions(); + for (const QString &action : lstActions) { shortcuts = m_desktopFile.actionGroup(action).readEntry(QStringLiteral("X-KDE-Shortcuts"), QString()).split(QChar(',')); if (!shortcuts.isEmpty()) { shortcutString = shortcuts.join(QChar('\t')); } GlobalShortcut *shortcut = registerShortcut(action, m_desktopFile.actionGroup(action).readEntry(QStringLiteral("Name")), shortcutString, shortcutString); shortcut->setIsPresent(true); } } bool KServiceActionComponent::cleanUp() { qCDebug(KGLOBALACCELD) << "Disabling desktop file"; const auto shortcuts = allShortcuts(); for (GlobalShortcut *shortcut : shortcuts) { shortcut->setIsPresent(false); } m_desktopFile.desktopGroup().writeEntry("NoDisplay", true); m_desktopFile.desktopGroup().sync(); return Component::cleanUp(); } } // namespace KdeDGlobalAccel #include "moc_kserviceactioncomponent.cpp" diff --git a/src/runtime/plugins/osx/kglobalaccel_mac.cpp b/src/runtime/plugins/osx/kglobalaccel_mac.cpp index b79eec1..63986e7 100644 --- a/src/runtime/plugins/osx/kglobalaccel_mac.cpp +++ b/src/runtime/plugins/osx/kglobalaccel_mac.cpp @@ -1,158 +1,159 @@ /* This file is part of the KDE libraries Copyright (C) 2001,2002 Ellis Whitehead Copyright (C) 2006 Marijn Kruisselbrink 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_mac.h" #include #ifdef Q_OS_OSX #include #include #include "globalshortcutsregistry.h" #include "kkeyserver.h" #include "logging_p.h" OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void * inUserData) { UInt32 eventKind = GetEventKind(inEvent); if (eventKind == kEventRawKeyDown) { UInt32 keycode; if (GetEventParameter(inEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof(keycode), NULL, &keycode) != noErr) { qCWarning(KGLOBALACCELD) << "Error retrieving keycode parameter from event"; } qCDebug(KGLOBALACCELD) << " key down, keycode = " << keycode; } else if (eventKind == kEventHotKeyPressed) { KGlobalAccelImpl* impl = static_cast(inUserData); EventHotKeyID hotkey; if (GetEventParameter(inEvent, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(hotkey), NULL, &hotkey) != noErr) { qCWarning(KGLOBALACCELD) << "Error retrieving hotkey parameter from event"; return eventNotHandledErr; } // Typecasts necesary to prevent a warning from gcc return (impl->keyPressed(hotkey.id) ? (OSStatus) noErr : (OSStatus) eventNotHandledErr); } return eventNotHandledErr; } void layoutChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { static_cast(observer)->keyboardLayoutChanged(); } KGlobalAccelImpl::KGlobalAccelImpl(GlobalShortcutsRegistry* owner) : m_owner(owner) , m_eventTarget(GetApplicationEventTarget()) , m_eventHandler(NewEventHandlerUPP(hotKeyEventHandler)) { m_eventType[0].eventClass = kEventClassKeyboard; m_eventType[0].eventKind = kEventHotKeyPressed; m_eventType[1].eventClass = kEventClassKeyboard; // only useful for testing, is not used because count passed in call to InstallEventHandler is 1 m_eventType[1].eventKind = kEventRawKeyDown; refs = new QMap >(); CFStringRef str = CFStringCreateWithCString(NULL, "AppleKeyboardPreferencesChangedNotification", kCFStringEncodingASCII); if (str) { CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), this, layoutChanged, str, NULL, CFNotificationSuspensionBehaviorHold); CFRelease(str); } else { qCWarning(KGLOBALACCELD) << "Couldn't create CFString to register for keyboard notifications"; } } KGlobalAccelImpl::~KGlobalAccelImpl() { DisposeEventHandlerUPP(hotKeyEventHandler); CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), this, NULL, NULL); delete refs; } bool KGlobalAccelImpl::grabKey( int keyQt, bool grab ) { if (grab) { qCDebug(KGLOBALACCELD) << "Grabbing key " << keyQt; QList keyCodes; uint mod; KKeyServer::keyQtToCodeMac( keyQt, keyCodes ); KKeyServer::keyQtToModMac( keyQt, mod ); qCDebug(KGLOBALACCELD) << "keyQt: " << keyQt << " mod: " << mod; - foreach (uint keyCode, keyCodes) { + for (uint keyCode : qAsConst(keyCodes)) { qCDebug(KGLOBALACCELD) << " keyCode: " << keyCode; } EventHotKeyID ehkid; ehkid.signature = 'Kgai'; ehkid.id = keyQt; QList hotkeys; - foreach (uint keyCode, keyCodes) { + for (uint keyCode : qAsConst(keyCodes)) { EventHotKeyRef ref; if (RegisterEventHotKey(keyCode, mod, ehkid, m_eventTarget, 0, &ref) != noErr) { qCWarning(KGLOBALACCELD) << "RegisterEventHotKey failed!"; } hotkeys.append(ref); } refs->insert(keyQt, hotkeys); } else { qCDebug(KGLOBALACCELD) << "Ungrabbing key " << keyQt; if (refs->count(keyQt) == 0) qCWarning(KGLOBALACCELD) << "Trying to ungrab a key thas is not grabbed"; - foreach (const EventHotKeyRef &ref, refs->value(keyQt)) { + const auto lstRef = refs->value(keyQt); + for (const EventHotKeyRef &ref : lstRef) { if (UnregisterEventHotKey(ref) != noErr) { qCWarning(KGLOBALACCELD) << "UnregisterEventHotKey should not fail!"; } } refs->remove(keyQt); } return true; } void KGlobalAccelImpl::setEnabled(bool enable) { if (enable) { if (InstallEventHandler(m_eventTarget, m_eventHandler, 1, m_eventType, this, &m_curHandler) != noErr) qCWarning(KGLOBALACCELD) << "InstallEventHandler failed!"; } else { if (RemoveEventHandler(m_curHandler) != noErr) qCWarning(KGLOBALACCELD) << "RemoveEventHandler failed!"; } } bool KGlobalAccelImpl::keyPressed( int key ) { return m_owner->keyPressed(key); } void KGlobalAccelImpl::keyboardLayoutChanged() { // Keyboard layout might have changed, first ungrab all keys QList keys; // Array to store all the keys that were grabbed while (!refs->empty()) { int key = refs->begin().key(); keys.append(key); grabKey(key, false); } // Now re-grab all the keys - foreach (int key, keys) { + for (int key : qAsConst(keys)) { grabKey(key, true); } } #endif // !Q_OS_OSX