/* * Strawberry Music Player * Copyright 2020, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Strawberry 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Strawberry. If not, see . * */ #include #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) # include #endif #include "core/logging.h" #include "globalshortcutsbackend-kde.h" const char *GlobalShortcutsBackendKDE::kKdeService = "org.kde.kglobalaccel"; const char *GlobalShortcutsBackendKDE::kKdePath = "/kglobalaccel"; GlobalShortcutsBackendKDE::GlobalShortcutsBackendKDE(GlobalShortcutsManager *parent) : GlobalShortcutsBackend(parent), interface_(nullptr), component_(nullptr) {} bool GlobalShortcutsBackendKDE::DoRegister() { qLog(Debug) << "Registering"; if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(kKdeService)) { qLog(Warning) << "KGlobalAccel is not registered"; return false; } if (!interface_) { interface_ = new OrgKdeKGlobalAccelInterface(kKdeService, kKdePath, QDBusConnection::sessionBus(), this); } for (const GlobalShortcutsManager::Shortcut &shortcut : manager_->shortcuts().values()) { RegisterShortcut(shortcut); } QDBusPendingReply reply = interface_->getComponent(QCoreApplication::applicationName()); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, &GlobalShortcutsBackendKDE::RegisterFinished); return true; } void GlobalShortcutsBackendKDE::RegisterFinished(QDBusPendingCallWatcher *watcher) { QDBusReply reply = watcher->reply(); watcher->deleteLater(); if (!reply.isValid()) { if (reply.error().name() != "org.kde.kglobalaccel.NoSuchComponent") { qLog(Error) << "Failed to register:" << reply.error().name() << reply.error().message(); } return; } if (!component_) { component_ = new org::kde::kglobalaccel::Component(kKdeService, reply.value().path(), QDBusConnection::sessionBus(), interface_); } if (!component_->isValid()) { qLog(Error) << "Component is invalid:" << QDBusConnection::sessionBus().lastError(); return; } QObject::connect(component_, &org::kde::kglobalaccel::Component::globalShortcutPressed, this, &GlobalShortcutsBackendKDE::GlobalShortcutPressed, Qt::UniqueConnection); qLog(Debug) << "Registered"; } void GlobalShortcutsBackendKDE::DoUnregister() { if (!interface_ || !interface_->isValid()) return; qLog(Debug) << "Unregistering"; for (const GlobalShortcutsManager::Shortcut &shortcut : manager_->shortcuts()) { if (actions_.contains(shortcut.id)) { interface_->unRegister(GetActionId(shortcut.id, shortcut.action)); actions_.remove(shortcut.id, shortcut.action); qLog(Info) << "Unregistered shortcut" << shortcut.id << shortcut.action->shortcut(); } } if (component_) QObject::disconnect(component_, nullptr, this, nullptr); qLog(Debug) << "Unregistered"; } bool GlobalShortcutsBackendKDE::RegisterShortcut(const GlobalShortcutsManager::Shortcut &shortcut) { if (!interface_ || !interface_->isValid() || shortcut.id.isEmpty() || !shortcut.action || shortcut.action->shortcut().isEmpty()) return false; if (shortcut.action->shortcut() == QKeySequence(Qt::Key_MediaPlay) || shortcut.action->shortcut() == QKeySequence(Qt::Key_MediaStop) || shortcut.action->shortcut() == QKeySequence(Qt::Key_MediaNext) || shortcut.action->shortcut() == QKeySequence(Qt::Key_MediaPrevious)) { qLog(Info) << "Media shortcut" << shortcut.id << shortcut.action->shortcut(); return true; } QStringList action_id = GetActionId(shortcut.id, shortcut.action); actions_.insert(shortcut.id, shortcut.action); interface_->doRegister(action_id); QList active_shortcut = QList() << shortcut.action->shortcut(); const QList result = interface_->setShortcut(action_id, ToIntList(active_shortcut), 0x2); const QList result_sequence = ToKeySequenceList(result); if (result_sequence != active_shortcut) { if (result_sequence.isEmpty()) { shortcut.action->setShortcut(QKeySequence()); } else { shortcut.action->setShortcut(result_sequence[0]); } } qLog(Info) << "Registered shortcut" << shortcut.id << shortcut.action->shortcut(); return true; } QStringList GlobalShortcutsBackendKDE::GetActionId(const QString &id, const QAction *action) { QStringList ret; ret << QCoreApplication::applicationName(); ret << id; ret << QCoreApplication::applicationName(); ret << action->text().remove('&'); if (ret.back().isEmpty()) ret.back() = id; return ret; } QList GlobalShortcutsBackendKDE::ToIntList(const QList &sequence_list) { QList ret; for (const QKeySequence &sequence : sequence_list) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) ret.append(sequence[0].toCombined()); #else ret.append(sequence[0]); #endif } return ret; } QList GlobalShortcutsBackendKDE::ToKeySequenceList(const QList &sequence_list) { QList ret; for (int sequence : sequence_list) { ret.append(sequence); } return ret; } void GlobalShortcutsBackendKDE::GlobalShortcutPressed(const QString &component_unique, const QString &shortcut_unique, qlonglong) { if (QCoreApplication::applicationName() == component_unique && actions_.contains(shortcut_unique)) { for (QAction *action : actions_.values(shortcut_unique)) { qLog(Debug) << "Key" << action->shortcut() << "pressed."; if (action->isEnabled()) action->trigger(); } } }