Add global shortcuts support on MATE

This commit is contained in:
Jonas Kvinge
2021-05-29 20:35:55 +02:00
parent 0c5236ebcb
commit 1ced4e277b
15 changed files with 386 additions and 77 deletions

View File

@@ -26,7 +26,6 @@
#include <QObject>
#include <QCoreApplication>
#include <QDateTime>
#include <QMap>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusPendingCallWatcher>
@@ -37,27 +36,33 @@
#include "core/logging.h"
#include "globalshortcutsmanager.h"
#include "globalshortcutsbackend.h"
#include "globalshortcutsbackend-gsd.h"
#include "globalshortcutsbackend-gnome.h"
const char *GlobalShortcutsBackendGSD::kGsdService = "org.gnome.SettingsDaemon.MediaKeys";
const char *GlobalShortcutsBackendGSD::kGsdService2 = "org.gnome.SettingsDaemon";
const char *GlobalShortcutsBackendGSD::kGsdPath = "/org/gnome/SettingsDaemon/MediaKeys";
const char *GlobalShortcutsBackendGnome::kService1 = "org.gnome.SettingsDaemon.MediaKeys";
const char *GlobalShortcutsBackendGnome::kService2 = "org.gnome.SettingsDaemon";
const char *GlobalShortcutsBackendGnome::kPath = "/org/gnome/SettingsDaemon/MediaKeys";
GlobalShortcutsBackendGSD::GlobalShortcutsBackendGSD(GlobalShortcutsManager *parent)
GlobalShortcutsBackendGnome::GlobalShortcutsBackendGnome(GlobalShortcutsManager *parent)
: GlobalShortcutsBackend(parent),
interface_(nullptr),
is_connected_(false) {}
bool GlobalShortcutsBackendGSD::DoRegister() {
bool GlobalShortcutsBackendGnome::IsAvailable() {
return QDBusConnection::sessionBus().interface()->isServiceRegistered(kService1) || QDBusConnection::sessionBus().interface()->isServiceRegistered(kService2);
}
bool GlobalShortcutsBackendGnome::DoRegister() {
qLog(Debug) << "Registering";
if (!interface_) {
if (QDBusConnection::sessionBus().interface()->isServiceRegistered(kGsdService)) {
interface_ = new OrgGnomeSettingsDaemonMediaKeysInterface(kGsdService, kGsdPath, QDBusConnection::sessionBus(), this);
if (QDBusConnection::sessionBus().interface()->isServiceRegistered(kService1)) {
interface_ = new OrgGnomeSettingsDaemonMediaKeysInterface(kService1, kPath, QDBusConnection::sessionBus(), this);
}
else if (QDBusConnection::sessionBus().interface()->isServiceRegistered(kGsdService2)) {
interface_ = new OrgGnomeSettingsDaemonMediaKeysInterface(kGsdService2, kGsdPath, QDBusConnection::sessionBus(), this);
else if (QDBusConnection::sessionBus().interface()->isServiceRegistered(kService2)) {
interface_ = new OrgGnomeSettingsDaemonMediaKeysInterface(kService2, kPath, QDBusConnection::sessionBus(), this);
}
}
@@ -69,13 +74,13 @@ bool GlobalShortcutsBackendGSD::DoRegister() {
QDBusPendingReply<> reply = interface_->GrabMediaPlayerKeys(QCoreApplication::applicationName(), QDateTime::currentDateTime().toSecsSinceEpoch());
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, &GlobalShortcutsBackendGSD::RegisterFinished);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, &GlobalShortcutsBackendGnome::RegisterFinished);
return true;
}
void GlobalShortcutsBackendGSD::RegisterFinished(QDBusPendingCallWatcher *watcher) {
void GlobalShortcutsBackendGnome::RegisterFinished(QDBusPendingCallWatcher *watcher) {
QDBusMessage reply = watcher->reply();
watcher->deleteLater();
@@ -85,30 +90,27 @@ void GlobalShortcutsBackendGSD::RegisterFinished(QDBusPendingCallWatcher *watche
return;
}
QObject::connect(interface_, &OrgGnomeSettingsDaemonMediaKeysInterface::MediaPlayerKeyPressed, this, &GlobalShortcutsBackendGSD::GnomeMediaKeyPressed);
QObject::connect(interface_, &OrgGnomeSettingsDaemonMediaKeysInterface::MediaPlayerKeyPressed, this, &GlobalShortcutsBackendGnome::GnomeMediaKeyPressed);
is_connected_ = true;
qLog(Debug) << "Registered";
qLog(Debug) << "Registered.";
}
void GlobalShortcutsBackendGSD::DoUnregister() {
void GlobalShortcutsBackendGnome::DoUnregister() {
qLog(Debug) << "Unregister";
// Check if the GSD service is available
if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(kGsdService))
return;
if (!interface_ || !is_connected_) return;
if (!IsAvailable() || !interface_ || !is_connected_) return;
is_connected_ = false;
interface_->ReleaseMediaPlayerKeys(QCoreApplication::applicationName());
QObject::disconnect(interface_, &OrgGnomeSettingsDaemonMediaKeysInterface::MediaPlayerKeyPressed, this, &GlobalShortcutsBackendGSD::GnomeMediaKeyPressed);
QObject::disconnect(interface_, &OrgGnomeSettingsDaemonMediaKeysInterface::MediaPlayerKeyPressed, this, &GlobalShortcutsBackendGnome::GnomeMediaKeyPressed);
}
void GlobalShortcutsBackendGSD::GnomeMediaKeyPressed(const QString&, const QString &key) {
void GlobalShortcutsBackendGnome::GnomeMediaKeyPressed(const QString&, const QString &key) {
auto shortcuts = manager_->shortcuts();
if (key == "Play") shortcuts["play_pause"].action->trigger();

View File

@@ -19,8 +19,8 @@
*
*/
#ifndef GLOBALSHORTCUTSBACKEND_GSD_H
#define GLOBALSHORTCUTSBACKEND_GSD_H
#ifndef GLOBALSHORTCUTSBACKEND_GNOME_H
#define GLOBALSHORTCUTSBACKEND_GNOME_H
#include "config.h"
@@ -33,18 +33,15 @@ class QDBusPendingCallWatcher;
class GlobalShortcutsManager;
class OrgGnomeSettingsDaemonMediaKeysInterface;
class GlobalShortcutsBackendGSD : public GlobalShortcutsBackend {
class GlobalShortcutsBackendGnome : public GlobalShortcutsBackend {
Q_OBJECT
public:
explicit GlobalShortcutsBackendGSD(GlobalShortcutsManager *parent);
explicit GlobalShortcutsBackendGnome(GlobalShortcutsManager *parent);
static const char *kGsdService;
static const char *kGsdService2;
static const char *kGsdPath;
bool IsAvailable() override;
protected:
bool RegisterInNewThread() const { return true; }
bool DoRegister() override;
void DoUnregister() override;
@@ -54,9 +51,13 @@ class GlobalShortcutsBackendGSD : public GlobalShortcutsBackend {
void GnomeMediaKeyPressed(const QString &application, const QString &key);
private:
static const char *kService1;
static const char *kService2;
static const char *kPath;
OrgGnomeSettingsDaemonMediaKeysInterface *interface_;
bool is_connected_;
};
#endif // GLOBALSHORTCUTSBACKEND_GSD_H
#endif // GLOBALSHORTCUTSBACKEND_GNOME_H

View File

@@ -43,6 +43,12 @@ const char *GlobalShortcutsBackendKDE::kKdePath = "/kglobalaccel";
GlobalShortcutsBackendKDE::GlobalShortcutsBackendKDE(GlobalShortcutsManager *parent) : GlobalShortcutsBackend(parent), interface_(nullptr), component_(nullptr) {}
bool GlobalShortcutsBackendKDE::IsAvailable() {
return QDBusConnection::sessionBus().interface()->isServiceRegistered(kKdeService);
}
bool GlobalShortcutsBackendKDE::DoRegister() {
qLog(Debug) << "Registering";
@@ -92,7 +98,7 @@ void GlobalShortcutsBackendKDE::RegisterFinished(QDBusPendingCallWatcher *watche
QObject::connect(component_, &org::kde::kglobalaccel::Component::globalShortcutPressed, this, &GlobalShortcutsBackendKDE::GlobalShortcutPressed, Qt::UniqueConnection);
qLog(Debug) << "Registered";
qLog(Debug) << "registered.";
}

View File

@@ -43,9 +43,8 @@ class GlobalShortcutsBackendKDE : public GlobalShortcutsBackend {
public:
explicit GlobalShortcutsBackendKDE(GlobalShortcutsManager *parent);
static const char *kKdeService;
protected:
bool IsAvailable() override;
bool DoRegister() override;
void DoUnregister() override;
@@ -60,6 +59,7 @@ class GlobalShortcutsBackendKDE : public GlobalShortcutsBackend {
void GlobalShortcutPressed(const QString &component_unique, const QString &shortcut_unique, qint64);
private:
static const char *kKdeService;
static const char *kKdePath;
OrgKdeKGlobalAccelInterface *interface_;

View File

@@ -0,0 +1,119 @@
/*
* Strawberry Music Player
* Copyright 2021, Jonas Kvinge <jonas@jkvinge.net>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <dbus/matesettingsdaemon.h>
#include <QObject>
#include <QCoreApplication>
#include <QDateTime>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusPendingCallWatcher>
#include <QDBusPendingReply>
#include <QAction>
#include <QtDebug>
#include "core/logging.h"
#include "globalshortcutsmanager.h"
#include "globalshortcutsbackend.h"
#include "globalshortcutsbackend-mate.h"
const char *GlobalShortcutsBackendMate::kService1 = "org.mate.SettingsDaemon.MediaKeys";
const char *GlobalShortcutsBackendMate::kService2 = "org.mate.SettingsDaemon";
const char *GlobalShortcutsBackendMate::kPath = "/org/mate/SettingsDaemon/MediaKeys";
GlobalShortcutsBackendMate::GlobalShortcutsBackendMate(GlobalShortcutsManager *parent)
: GlobalShortcutsBackend(parent),
interface_(nullptr),
is_connected_(false) {}
bool GlobalShortcutsBackendMate::IsAvailable() {
return QDBusConnection::sessionBus().interface()->isServiceRegistered(kService1) || QDBusConnection::sessionBus().interface()->isServiceRegistered(kService2);
}
bool GlobalShortcutsBackendMate::DoRegister() {
qLog(Debug) << "Registering";
if (!interface_) {
if (QDBusConnection::sessionBus().interface()->isServiceRegistered(kService1)) {
interface_ = new OrgMateSettingsDaemonMediaKeysInterface(kService1, kPath, QDBusConnection::sessionBus(), this);
}
else if (QDBusConnection::sessionBus().interface()->isServiceRegistered(kService2)) {
interface_ = new OrgMateSettingsDaemonMediaKeysInterface(kService2, kPath, QDBusConnection::sessionBus(), this);
}
}
if (!interface_) {
qLog(Warning) << "Mate settings daemon not registered";
return false;
}
QDBusPendingReply<> reply = interface_->GrabMediaPlayerKeys(QCoreApplication::applicationName(), QDateTime::currentDateTime().toSecsSinceEpoch());
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, &GlobalShortcutsBackendMate::RegisterFinished);
return true;
}
void GlobalShortcutsBackendMate::RegisterFinished(QDBusPendingCallWatcher *watcher) {
QDBusMessage reply = watcher->reply();
watcher->deleteLater();
if (reply.type() == QDBusMessage::ErrorMessage) {
qLog(Warning) << "Failed to grab media keys" << reply.errorName() <<reply.errorMessage();
return;
}
QObject::connect(interface_, &OrgMateSettingsDaemonMediaKeysInterface::MediaPlayerKeyPressed, this, &GlobalShortcutsBackendMate::MateMediaKeyPressed);
is_connected_ = true;
qLog(Debug) << "Registered.";
}
void GlobalShortcutsBackendMate::DoUnregister() {
qLog(Debug) << "Unregister";
if (!IsAvailable() || !interface_ || !is_connected_) return;
is_connected_ = false;
interface_->ReleaseMediaPlayerKeys(QCoreApplication::applicationName());
QObject::disconnect(interface_, &OrgMateSettingsDaemonMediaKeysInterface::MediaPlayerKeyPressed, this, &GlobalShortcutsBackendMate::MateMediaKeyPressed);
}
void GlobalShortcutsBackendMate::MateMediaKeyPressed(const QString&, const QString &key) {
auto shortcuts = manager_->shortcuts();
if (key == "Play") shortcuts["play_pause"].action->trigger();
if (key == "Stop") shortcuts["stop"].action->trigger();
if (key == "Next") shortcuts["next_track"].action->trigger();
if (key == "Previous") shortcuts["prev_track"].action->trigger();
}

View File

@@ -0,0 +1,61 @@
/*
* Strawberry Music Player
* Copyright 2021, Jonas Kvinge <jonas@jkvinge.net>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef GLOBALSHORTCUTSBACKEND_MATE_H
#define GLOBALSHORTCUTSBACKEND_MATE_H
#include "config.h"
#include <QObject>
#include <QString>
#include "globalshortcutsbackend.h"
class QDBusPendingCallWatcher;
class GlobalShortcutsManager;
class OrgMateSettingsDaemonMediaKeysInterface;
class GlobalShortcutsBackendMate : public GlobalShortcutsBackend {
Q_OBJECT
public:
explicit GlobalShortcutsBackendMate(GlobalShortcutsManager *parent);
bool IsAvailable() override;
protected:
bool DoRegister() override;
void DoUnregister() override;
private slots:
void RegisterFinished(QDBusPendingCallWatcher *watcher);
void MateMediaKeyPressed(const QString &application, const QString &key);
private:
static const char *kService1;
static const char *kService2;
static const char *kPath;
OrgMateSettingsDaemonMediaKeysInterface *interface_;
bool is_connected_;
};
#endif // GLOBALSHORTCUTSBACKEND_Mate_H

View File

@@ -41,6 +41,8 @@ class GlobalShortcutsBackendSystem : public GlobalShortcutsBackend {
explicit GlobalShortcutsBackendSystem(GlobalShortcutsManager *parent = nullptr);
~GlobalShortcutsBackendSystem() override;
bool IsAvailable() override { return true; }
protected:
bool DoRegister() override;
void DoUnregister() override;

View File

@@ -39,6 +39,8 @@ class GlobalShortcutsBackend : public QObject {
bool Register();
void Unregister();
virtual bool IsAvailable() = 0;
signals:
void RegisterFinished(bool success);

View File

@@ -38,8 +38,9 @@
#include "globalshortcutsbackend.h"
#ifdef HAVE_DBUS
# include "globalshortcutsbackend-gsd.h"
# include "globalshortcutsbackend-kde.h"
# include "globalshortcutsbackend-gnome.h"
# include "globalshortcutsbackend-mate.h"
#endif
#if (defined(HAVE_X11) && defined(HAVE_QPA_QPLATFORMNATIVEINTERFACE_H)) || defined(Q_OS_WIN)
# include "globalshortcutsbackend-system.h"
@@ -52,11 +53,13 @@
GlobalShortcutsManager::GlobalShortcutsManager(QWidget *parent)
: QWidget(parent),
gsd_backend_(nullptr),
kde_backend_(nullptr),
gnome_backend_(nullptr),
mate_backend_(nullptr),
system_backend_(nullptr),
use_gsd_(true),
use_kde_(true),
use_gnome_(true),
use_mate_(true),
use_x11_(false)
{
@@ -85,8 +88,9 @@ GlobalShortcutsManager::GlobalShortcutsManager(QWidget *parent)
// Create backends - these do the actual shortcut registration
#ifdef HAVE_DBUS
gsd_backend_ = new GlobalShortcutsBackendGSD(this);
kde_backend_ = new GlobalShortcutsBackendKDE(this);
gnome_backend_ = new GlobalShortcutsBackendGnome(this);
mate_backend_ = new GlobalShortcutsBackendMate(this);
#endif
#ifdef Q_OS_MACOS
@@ -109,8 +113,9 @@ GlobalShortcutsManager::GlobalShortcutsManager(QWidget *parent)
void GlobalShortcutsManager::ReloadSettings() {
// The actual shortcuts have been set in our actions for us by the config dialog already - we just need to reread the gnome settings.
use_gsd_ = settings_.value("use_gsd", true).toBool();
use_kde_ = settings_.value("use_kde", true).toBool();
use_gnome_ = settings_.value("use_gnome", true).toBool();
use_mate_ = settings_.value("use_mate", true).toBool();
use_x11_ = settings_.value("use_x11", false).toBool();
Unregister();
@@ -144,20 +149,30 @@ GlobalShortcutsManager::Shortcut GlobalShortcutsManager::AddShortcut(const QStri
}
bool GlobalShortcutsManager::IsGsdAvailable() const {
bool GlobalShortcutsManager::IsKdeAvailable() const {
#ifdef HAVE_DBUS
return QDBusConnection::sessionBus().interface()->isServiceRegistered(GlobalShortcutsBackendGSD::kGsdService) || QDBusConnection::sessionBus().interface()->isServiceRegistered(GlobalShortcutsBackendGSD::kGsdService2);
return kde_backend_->IsAvailable();
#else
return false;
#endif
}
bool GlobalShortcutsManager::IsKdeAvailable() const {
bool GlobalShortcutsManager::IsGnomeAvailable() const {
#ifdef HAVE_DBUS
return QDBusConnection::sessionBus().interface()->isServiceRegistered(GlobalShortcutsBackendKDE::kKdeService);
return gnome_backend_->IsAvailable();
#else
return false;
#endif
}
bool GlobalShortcutsManager::IsMateAvailable() const {
#ifdef HAVE_DBUS
return mate_backend_->IsAvailable();
#else
return false;
#endif
@@ -172,8 +187,9 @@ bool GlobalShortcutsManager::IsX11Available() const {
void GlobalShortcutsManager::Register() {
if (use_gsd_ && gsd_backend_ && gsd_backend_->Register()) return;
if (use_kde_ && kde_backend_ && kde_backend_->Register()) return;
if (use_gnome_ && gnome_backend_ && gnome_backend_->Register()) return;
if (use_mate_ && mate_backend_ && mate_backend_->Register()) return;
#if defined(HAVE_X11) && defined(HAVE_QPA_QPLATFORMNATIVEINTERFACE_H) // If this system has X11, only use the system backend if X11 is enabled in the global shortcut settings
if (use_x11_) {
#endif
@@ -187,8 +203,9 @@ void GlobalShortcutsManager::Register() {
void GlobalShortcutsManager::Unregister() {
if (gsd_backend_ && gsd_backend_->is_active()) gsd_backend_->Unregister();
if (kde_backend_ && kde_backend_->is_active()) kde_backend_->Unregister();
if (gnome_backend_ && gnome_backend_->is_active()) gnome_backend_->Unregister();
if (mate_backend_ && mate_backend_->is_active()) mate_backend_->Unregister();
if (system_backend_ && system_backend_->is_active()) system_backend_->Unregister();
}

View File

@@ -51,9 +51,10 @@ class GlobalShortcutsManager : public QWidget {
};
QMap<QString, Shortcut> shortcuts() const { return shortcuts_; }
bool IsGsdAvailable() const;
bool IsKdeAvailable() const;
bool IsX11Available() const;
bool IsGnomeAvailable() const;
bool IsMateAvailable() const;
bool IsMacAccessibilityEnabled() const;
public slots:
@@ -90,15 +91,17 @@ class GlobalShortcutsManager : public QWidget {
Shortcut AddShortcut(const QString &id, const QString &name, const QKeySequence &default_key);
private:
GlobalShortcutsBackend *gsd_backend_;
GlobalShortcutsBackend *kde_backend_;
GlobalShortcutsBackend *gnome_backend_;
GlobalShortcutsBackend *mate_backend_;
GlobalShortcutsBackend *system_backend_;
QMap<QString, Shortcut> shortcuts_;
QSettings settings_;
bool use_gsd_;
bool use_kde_;
bool use_gnome_;
bool use_mate_;
bool use_x11_;
};