Add new global shortcut system backend for X11 and Windows

- Remove qxt
- Also create an option for enabled/disabling shortcuts through X11.
This commit is contained in:
Jonas Kvinge
2019-01-01 20:07:29 +01:00
parent 2a54cb17e7
commit cef334c210
40 changed files with 1283 additions and 2345 deletions

View File

@@ -43,6 +43,10 @@ include_directories(${Boost_INCLUDE_DIRS})
include_directories(${LIBXML_INCLUDE_DIRS})
include_directories(${CHROMAPRINT_INCLUDE_DIRS})
if (X11_FOUND)
include_directories(${X11_INCLUDE_DIR})
endif(X11_FOUND)
if(HAVE_GSTREAMER)
link_directories(${GSTREAMER_LIBRARY_DIRS})
include_directories(${GSTREAMER_INCLUDE_DIRS})
@@ -210,7 +214,6 @@ set(SOURCES
settings/playbacksettingspage.cpp
settings/playlistsettingspage.cpp
settings/networkproxysettingspage.cpp
settings/shortcutssettingspage.cpp
settings/appearancesettingspage.cpp
settings/notificationssettingspage.cpp
settings/scrobblersettingspage.cpp
@@ -250,12 +253,6 @@ set(SOURCES
musicbrainz/acoustidclient.cpp
musicbrainz/musicbrainzclient.cpp
globalshortcuts/globalshortcutbackend.cpp
globalshortcuts/globalshortcuts.cpp
globalshortcuts/gnomeglobalshortcutbackend.cpp
globalshortcuts/qxtglobalshortcutbackend.cpp
globalshortcuts/globalshortcutgrabber.cpp
internet/internetservices.cpp
internet/internetservice.cpp
internet/internetplaylistitem.cpp
@@ -387,7 +384,6 @@ set(HEADERS
settings/playbacksettingspage.h
settings/playlistsettingspage.h
settings/networkproxysettingspage.h
settings/shortcutssettingspage.h
settings/appearancesettingspage.h
settings/notificationssettingspage.h
settings/scrobblersettingspage.h
@@ -425,11 +421,6 @@ set(HEADERS
musicbrainz/acoustidclient.h
musicbrainz/musicbrainzclient.h
globalshortcuts/globalshortcutbackend.h
globalshortcuts/globalshortcuts.h
globalshortcuts/gnomeglobalshortcutbackend.h
globalshortcuts/globalshortcutgrabber.h
internet/internetservices.h
internet/internetservice.h
internet/internetsongmimedata.h
@@ -481,7 +472,6 @@ set(UI
settings/playbacksettingspage.ui
settings/playlistsettingspage.ui
settings/networkproxysettingspage.ui
settings/shortcutssettingspage.ui
settings/appearancesettingspage.ui
settings/notificationssettingspage.ui
settings/scrobblersettingspage.ui
@@ -500,8 +490,6 @@ set(UI
widgets/fileview.ui
widgets/loginstatewidget.ui
globalshortcuts/globalshortcutgrabber.ui
internet/internetsearchview.ui
)
@@ -511,6 +499,31 @@ set(OTHER_SOURCES)
option(USE_INSTALL_PREFIX "Look for data in CMAKE_INSTALL_PREFIX" ON)
if(HAVE_GLOBALSHORTCUTS)
optional_source(HAVE_GLOBALSHORTCUTS
SOURCES globalshortcuts/globalshortcuts.cpp globalshortcuts/globalshortcutbackend.cpp globalshortcuts/globalshortcutgrabber.cpp settings/shortcutssettingspage.cpp
HEADERS globalshortcuts/globalshortcuts.h globalshortcuts/globalshortcutbackend.h globalshortcuts/globalshortcutgrabber.h settings/shortcutssettingspage.h
UI globalshortcuts/globalshortcutgrabber.ui settings/shortcutssettingspage.ui
)
if (X11_FOUND OR WIN32)
set(X11_OR_WIN ON)
endif()
optional_source(X11_OR_WIN
SOURCES globalshortcuts/globalshortcutbackend-system.cpp globalshortcuts/globalshortcut.cpp
HEADERS globalshortcuts/globalshortcutbackend-system.h globalshortcuts/globalshortcut.h
)
optional_source(X11_FOUND
SOURCES globalshortcuts/globalshortcut-x11.cpp
)
optional_source(HAVE_DBUS
SOURCES globalshortcuts/globalshortcutbackend-dbus.cpp
HEADERS globalshortcuts/globalshortcutbackend-dbus.h
)
optional_source(WIN32
SOURCES globalshortcuts/globalshortcut-win.cpp
)
endif(HAVE_GLOBALSHORTCUTS)
# ALSA
optional_source(HAVE_ALSA
SOURCES
@@ -518,7 +531,10 @@ optional_source(HAVE_ALSA
)
# X11
optional_source(HAVE_X11 SOURCES widgets/osd_x11.cpp)
optional_source(X11_FOUND
SOURCES
widgets/osd_x11.cpp
)
# GStreamer
optional_source(HAVE_GSTREAMER
@@ -554,16 +570,18 @@ optional_source(HAVE_DEEZER
if(UNIX AND HAVE_DBUS)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dbus)
# MPRIS DBUS interfaces
#qt5_add_dbus_adaptor(SOURCES
# dbus/org.freedesktop.MediaPlayer.player.xml
# core/mpris1.h mpris::Mpris1Player core/mpris_player MprisPlayer)
#qt5_add_dbus_adaptor(SOURCES
# dbus/org.freedesktop.MediaPlayer.root.xml
# core/mpris1.h mpris::Mpris1Root core/mpris_root MprisRoot)
#qt5_add_dbus_adaptor(SOURCES
# dbus/org.freedesktop.MediaPlayer.tracklist.xml
# core/mpris1.h mpris::Mpris1TrackList core/mpris_tracklist MprisTrackList)
optional_source(HAVE_DBUS
SOURCES core/mpris.cpp core/mpris2.cpp core/dbusscreensaver.cpp
HEADERS core/mpris.h core/mpris2.h
)
optional_source(HAVE_DEVICEKIT
SOURCES device/devicekitlister.cpp
HEADERS device/devicekitlister.h
)
optional_source(HAVE_UDISKS2
SOURCES device/udisks2lister.cpp
HEADERS device/udisks2lister.h
)
# MPRIS 2.0 DBUS interfaces
qt5_add_dbus_adaptor(SOURCES
@@ -663,16 +681,6 @@ if(UNIX AND HAVE_DBUS)
endif(UNIX AND HAVE_DBUS)
optional_source(HAVE_DBUS
SOURCES
core/mpris.cpp
core/mpris2.cpp
core/dbusscreensaver.cpp
HEADERS
core/mpris.h
core/mpris2.h
)
optional_source(UNIX
SOURCES
device/connecteddevice.cpp
@@ -700,17 +708,6 @@ optional_source(UNIX
device/deviceviewcontainer.ui
)
if(HAVE_DBUS)
optional_source(HAVE_DEVICEKIT
SOURCES device/devicekitlister.cpp
HEADERS device/devicekitlister.h
)
optional_source(HAVE_UDISKS2
SOURCES device/udisks2lister.cpp
HEADERS device/udisks2lister.h
)
endif()
# Libgpod device backend
optional_source(HAVE_LIBGPOD
INCLUDE_DIRECTORIES ${LIBGPOD_INCLUDE_DIRS}
@@ -842,12 +839,12 @@ optional_source(APPLE
core/macfslistener.mm
widgets/osd_mac.mm
engine/osxdevicefinder.cpp
globalshortcuts/globalshortcutgrabber.mm
globalshortcuts/macglobalshortcutbackend.mm
globalshortcuts/globalshortcutbackend-macos.mm
globalshortcuts/globalshortcutgrabber-macos.mm
HEADERS
core/macsystemtrayicon.h
core/macfslistener.h
globalshortcuts/macglobalshortcutbackend.h
globalshortcuts/globalshortcutbackend-macos.h
)
if (APPLE)
@@ -922,14 +919,22 @@ target_link_libraries(strawberry_lib
${GOBJECT_LIBRARIES}
${QT_LIBRARIES}
${CHROMAPRINT_LIBRARIES}
${SQLITE_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${QTSINGLEAPPLICATION_LIBRARIES}
${QTSINGLECOREAPPLICATION_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${SQLITE_LIBRARIES}
${QOCOA_LIBRARIES}
z
)
if(X11_FOUND)
target_link_libraries(strawberry_lib ${X11_LIBRARIES})
endif(X11_FOUND)
if(XCB_FOUND)
target_link_libraries(strawberry_lib ${XCB_LIBRARIES})
endif(XCB_FOUND)
if(HAVE_ALSA)
target_link_libraries(strawberry_lib ${ALSA_LIBRARIES})
endif(HAVE_ALSA)

View File

@@ -32,19 +32,17 @@
#cmakedefine HAVE_ALSA
#cmakedefine HAVE_DEVICEKIT
#cmakedefine HAVE_IMOBILEDEVICE
#cmakedefine HAVE_LIBARCHIVE
#cmakedefine HAVE_AUDIOCD
#cmakedefine HAVE_LIBGPOD
#cmakedefine HAVE_LIBMTP
#cmakedefine HAVE_LIBPULSE
#cmakedefine HAVE_QCA
#cmakedefine HAVE_SPARKLE
#cmakedefine HAVE_CHROMAPRINT
#cmakedefine HAVE_TAGLIB_DSFFILE
#cmakedefine HAVE_DZMEDIA
#cmakedefine HAVE_GLOBALSHORTCUTS
#cmakedefine IMOBILEDEVICE_USES_UDIDS
#cmakedefine USE_INSTALL_PREFIX
#cmakedefine USE_SYSTEM_SHA2
#cmakedefine HAVE_GSTREAMER
#cmakedefine HAVE_VLC
@@ -55,5 +53,8 @@
#cmakedefine HAVE_STREAM_TIDAL
#cmakedefine HAVE_STREAM_DEEZER
#cmakedefine HAVE_KEYSYMDEF_H
#cmakedefine HAVE_XF86KEYSYM_H
#endif // CONFIG_H_IN

View File

@@ -117,7 +117,9 @@
#include "playlistparsers/playlistparser.h"
#include "analyzer/analyzercontainer.h"
#include "equalizer/equalizer.h"
#include "globalshortcuts/globalshortcuts.h"
#ifdef HAVE_GLOBALSHORTCUTS
# include "globalshortcuts/globalshortcuts.h"
#endif
#include "covermanager/albumcovermanager.h"
#include "covermanager/albumcoverchoicecontroller.h"
#include "covermanager/albumcoverloader.h"
@@ -158,11 +160,6 @@ using std::bind;
using std::floor;
using std::stable_sort;
#ifdef Q_OS_MACOS
// Non exported mac-specific function.
void qt_mac_set_dock_menu(QMenu*);
#endif
const char *MainWindow::kSettingsGroup = "MainWindow";
const char *MainWindow::kAllFilesFilterSpec = QT_TR_NOOP("All Files (*)");
@@ -180,7 +177,9 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
osd_(osd),
edit_tag_dialog_(std::bind(&MainWindow::CreateEditTagDialog, this)),
album_cover_choice_controller_(new AlbumCoverChoiceController(this)),
#ifdef HAVE_GLOBALSHORTCUTS
global_shortcuts_(new GlobalShortcuts(this)),
#endif
context_view_(new ContextView(this)),
collection_view_(new CollectionViewContainer(this)),
file_view_(new FileView(this)),
@@ -632,6 +631,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
connect(check_updates, SIGNAL(triggered(bool)), SLOT(CheckForUpdates()));
#endif
#ifdef HAVE_GLOBALSHORTCUTS
// Global shortcuts
connect(global_shortcuts_, SIGNAL(Play()), app_->player(), SLOT(Play()));
connect(global_shortcuts_, SIGNAL(Pause()), app_->player(), SLOT(Pause()));
@@ -649,6 +649,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
connect(global_shortcuts_, SIGNAL(ShowOSD()), app_->player(), SLOT(ShowOSD()));
connect(global_shortcuts_, SIGNAL(TogglePrettyOSD()), app_->player(), SLOT(TogglePrettyOSD()));
connect(global_shortcuts_, SIGNAL(ToggleScrobbling()), app_->scrobbler(), SLOT(ToggleScrobbling()));
#endif
// Fancy tabs
connect(ui_->tabs, SIGNAL(ModeChanged(FancyTabWidget::Mode)), SLOT(SaveTabMode()));
@@ -703,8 +704,10 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
connect(this, SIGNAL(StopAfterToggled(bool)), osd_, SLOT(StopAfterToggle(bool)));
// We need to connect these global shortcuts here after the playlist have been initialized
#ifdef HAVE_GLOBALSHORTCUTS
connect(global_shortcuts_, SIGNAL(CycleShuffleMode()), app_->playlist_manager()->sequence(), SLOT(CycleShuffleMode()));
connect(global_shortcuts_, SIGNAL(CycleRepeatMode()), app_->playlist_manager()->sequence(), SLOT(CycleRepeatMode()));
#endif
connect(app_->playlist_manager()->sequence(), SIGNAL(RepeatModeChanged(PlaylistSequence::RepeatMode)), osd_, SLOT(RepeatModeChanged(PlaylistSequence::RepeatMode)));
connect(app_->playlist_manager()->sequence(), SIGNAL(ShuffleModeChanged(PlaylistSequence::ShuffleMode)), osd_, SLOT(ShuffleModeChanged(PlaylistSequence::ShuffleMode)));
@@ -2091,7 +2094,9 @@ void MainWindow::ShowCoverManager() {
SettingsDialog *MainWindow::CreateSettingsDialog() {
SettingsDialog *settings_dialog = new SettingsDialog(app_);
#ifdef HAVE_GLOBALSHORTCUTS
settings_dialog->SetGlobalShortcutManager(global_shortcuts_);
#endif
// Settings
connect(settings_dialog, SIGNAL(accepted()), SLOT(ReloadAllSettings()));

View File

@@ -363,7 +363,7 @@ QString ColorToRgba(const QColor &c) {
}
#ifdef Q_OS_MACOS
qint32 GetMacVersion() {
qint32 GetMacOsVersion() {
SInt32 minor_version;
Gestalt(gestaltSystemVersionMinor, &minor_version);

View File

@@ -127,7 +127,7 @@ void IncreaseFDLimit();
void CheckPortable();
// Returns the minor version of OS X (ie. 6 for Snow Leopard, 7 for Lion).
qint32 GetMacVersion();
qint32 GetMacOsVersion();
// Borrowed from schedutils
enum IoPriority {

View File

@@ -0,0 +1,76 @@
/*
* Strawberry Music Player
* Copyright 2018, 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 <QtGlobal>
#include <QObject>
#include <QAbstractEventDispatcher>
#include <QByteArray>
#include <qt_windows.h>
#include "core/logging.h"
#include "globalshortcuts.h"
#include "globalshortcutbackend.h"
#include "globalshortcut.h"
#include "keymapper_win.h"
quint32 GlobalShortcut::nativeModifiers(Qt::KeyboardModifiers qt_mods) {
quint32 native_mods = 0;
if (qt_mods & Qt::ShiftModifier) native_mods |= MOD_SHIFT;
if (qt_mods & Qt::ControlModifier) native_mods |= MOD_CONTROL;
if (qt_mods & Qt::AltModifier) native_mods |= MOD_ALT;
if (qt_mods & Qt::MetaModifier) native_mods |= MOD_WIN;
return native_mods;
}
quint32 GlobalShortcut::nativeKeycode(Qt::Key qt_key) {
quint32 key_code = 0;
if (KeyMapperWin::keymapper_win_.contains(qt_key)) {
key_code = KeyMapperWin::keymapper_win_.value(qt_key);
}
return key_code;
}
bool GlobalShortcut::registerShortcut(quint32 native_key, quint32 native_mods) {
return RegisterHotKey(0, native_mods ^ native_key, native_mods, native_key);
}
bool GlobalShortcut::unregisterShortcut(quint32 native_key, quint32 native_mods) {
return UnregisterHotKey(0, native_mods ^ native_key);
}
bool GlobalShortcut::nativeEventFilter(const QByteArray &eventtype, void *message, long *result) {
Q_UNUSED(eventtype);
Q_UNUSED(result);
MSG *msg = static_cast<MSG*>(message);
if (msg->message != WM_HOTKEY) return false;
quint32 key_code = HIWORD(msg->lParam);
quint32 modifiers = LOWORD(msg->lParam);
activateShortcut(key_code, modifiers);
return true;
}

View File

@@ -0,0 +1,112 @@
/*
* Strawberry Music Player
* Copyright 2018, 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 <QtGlobal>
#include <QApplication>
#include <QObject>
#include <QAbstractEventDispatcher>
#include <QDataStream>
#include <QVector>
#include <QByteArray>
#include <QX11Info>
#include <QKeySequence>
#include <QtAlgorithms>
#include "core/logging.h"
#include "globalshortcuts.h"
#include "globalshortcutbackend.h"
#include "globalshortcut.h"
#include "keymapper_x11.h"
#include <X11/X.h>
#include <X11/Xlib.h>
#include <xcb/xcb.h>
#include <xcb/xproto.h>
const QVector<quint32> GlobalShortcut::mask_modifiers_ = QVector<quint32>() << 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask);
quint32 GlobalShortcut::nativeModifiers(Qt::KeyboardModifiers qt_mods) {
quint32 native_mods = 0;
if (qt_mods & Qt::ShiftModifier) native_mods |= ShiftMask;
if (qt_mods & Qt::ControlModifier) native_mods |= ControlMask;
if (qt_mods & Qt::AltModifier) native_mods |= Mod1Mask;
if (qt_mods & Qt::MetaModifier) native_mods |= Mod4Mask;
return native_mods;
}
quint32 GlobalShortcut::nativeKeycode(Qt::Key key) {
if (!QX11Info::display()) return 0;
quint32 keysym = 0;
if (KeyMapperX11::keymapper_x11_.contains(key)) {
keysym = KeyMapperX11::keymapper_x11_.value(key);
}
else {
keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data());
if (keysym == NoSymbol) return 0;
}
return XKeysymToKeycode(QX11Info::display(), keysym);
}
bool GlobalShortcut::registerShortcut(quint32 native_key, quint32 native_mods) {
if (!QX11Info::display()) return false;
for (quint32 mask_mods : mask_modifiers_) {
//xcb_grab_key(QX11Info::connection(), 1, QX11Info::appRootWindow(), (native_mods | mask_mods), native_key, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
XGrabKey(QX11Info::display(), native_key, (native_mods | mask_mods), QX11Info::appRootWindow(), True, GrabModeAsync, GrabModeAsync);
}
return true;
}
bool GlobalShortcut::unregisterShortcut(quint32 native_key, quint32 native_mods) {
if (!QX11Info::display()) return false;
for (quint32 mask_mods : mask_modifiers_) {
XUngrabKey(QX11Info::display(), native_key, native_mods | mask_mods, QX11Info::appRootWindow());
}
return true;
}
bool GlobalShortcut::nativeEventFilter(const QByteArray &eventtype, void *message, long *result) {
Q_UNUSED(eventtype);
Q_UNUSED(result);
xcb_generic_event_t *event = static_cast<xcb_generic_event_t *>(message);
if ((event->response_type & 127) != XCB_KEY_PRESS) return false;
xcb_key_press_event_t *key_press_event = static_cast<xcb_key_press_event_t *>(message);
if (!key_press_event) return false;
quint32 keycode = key_press_event->detail;
unsigned int keystate = 0;
if (key_press_event->state & XCB_MOD_MASK_1) keystate |= Mod1Mask;
if (key_press_event->state & XCB_MOD_MASK_CONTROL) keystate |= ControlMask;
if (key_press_event->state & XCB_MOD_MASK_4) keystate |= Mod4Mask;
if (key_press_event->state & XCB_MOD_MASK_SHIFT) keystate |= ShiftMask;
activateShortcut(keycode, keystate & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask));
return false;
}

View File

@@ -0,0 +1,145 @@
/*
* Strawberry Music Player
* Copyright 2018, 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 <QtGlobal>
#include <QObject>
#include <QApplication>
#include <QAbstractEventDispatcher>
#include <QPair>
#include <QHash>
#include <QtDebug>
#include "core/logging.h"
#include "globalshortcutbackend.h"
#include "globalshortcut.h"
GlobalShortcut *GlobalShortcut::initialized_ = nullptr;
QHash<QPair<quint32, quint32>, GlobalShortcut*> GlobalShortcut::internal_shortcuts_;
GlobalShortcut::GlobalShortcut(QObject *parent) : QObject(parent),
qt_key_(Qt::Key(0)),
qt_mods_(Qt::NoModifier),
native_key_(0),
native_mods_(0) {
Q_ASSERT(!initialized_);
QAbstractEventDispatcher::instance()->installNativeEventFilter(this);
initialized_ = this;
}
GlobalShortcut::GlobalShortcut(QKeySequence shortcut, GlobalShortcutBackend *backend, QObject *parent) : QObject(parent),
backend_(backend),
shortcut_(shortcut),
qt_key_(Qt::Key(0)),
qt_mods_(Qt::NoModifier),
native_key_(0),
native_mods_(0) {
Q_ASSERT(initialized_);
setShortcut(shortcut);
}
GlobalShortcut::~GlobalShortcut() {
if (this == initialized_) {
QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
initialized_ = nullptr;
}
else {
unsetShortcut();
}
}
bool GlobalShortcut::setShortcut(const QKeySequence &shortcut) {
Q_ASSERT(initialized_);
if (shortcut.isEmpty()) return false;
shortcut_ = shortcut;
Qt::KeyboardModifiers all_mods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier;
qt_key_ = Qt::Key((shortcut[0] ^ all_mods) & shortcut[0]);
qt_mods_ = Qt::KeyboardModifiers(shortcut[0] & all_mods);
native_key_ = nativeKeycode(qt_key_);
if (native_key_ == 0) return false;
native_mods_ = nativeModifiers(qt_mods_);
bool result = registerShortcut(native_key_, native_mods_);
if (result) {
internal_shortcuts_.insert(qMakePair(native_key_, native_mods_), this);
}
else {
qLog(Error) << "Failed to register shortcut" << shortcut_.toString();
}
qLog(Info) << "Registered shortcut" << shortcut_.toString();
return result;
}
bool GlobalShortcut::unsetShortcut() {
Q_ASSERT(initialized_);
QPair<quint32, quint32> hash = qMakePair(native_key_, native_mods_);
if (internal_shortcuts_.contains(hash)) {
GlobalShortcut *gshortcut = internal_shortcuts_.value(hash);
if (gshortcut != this) return false;
}
bool result = unregisterShortcut(native_key_, native_mods_);
if (result) {
if (internal_shortcuts_.contains(hash)) {
internal_shortcuts_.remove(hash);
}
qLog(Info) << "Unregister shortcut" << shortcut_.toString();
}
else {
qLog(Error) << "Failed to unregister shortcut:" << shortcut_.toString();
}
qt_key_ = Qt::Key(0);
qt_mods_ = Qt::KeyboardModifiers(0);
native_key_ = 0;
native_mods_ = 0;
return result;
}
void GlobalShortcut::activateShortcut(quint32 native_key, quint32 native_mod) {
Q_ASSERT(initialized_);
QPair<quint32, quint32> hash = qMakePair(native_key, native_mod);
if (!internal_shortcuts_.contains(hash)) return;
GlobalShortcut *gshortcut = internal_shortcuts_.value(hash);
if (gshortcut && gshortcut != initialized_) {
emit gshortcut->activated();
}
}

View File

@@ -0,0 +1,80 @@
/*
* Strawberry Music Player
* Copyright 2018, 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 GLOBALSHORTCUT_H
#define GLOBALSHORTCUT_H
#include "config.h"
#include <stdbool.h>
#include <QtGlobal>
#include <QObject>
#include <QAbstractNativeEventFilter>
#include <QKeySequence>
#include <QPair>
#include <QVector>
#include <QHash>
#include <QByteArray>
class GlobalShortcutBackend;
class GlobalShortcut : public QObject, QAbstractNativeEventFilter {
Q_OBJECT
public:
explicit GlobalShortcut(QObject *parent = nullptr);
explicit GlobalShortcut(QKeySequence shortcut, GlobalShortcutBackend *backend, QObject *parent = nullptr);
~GlobalShortcut();
GlobalShortcutBackend *backend() const { return backend_; }
QKeySequence shortcut() const { return shortcut_; }
bool setShortcut(const QKeySequence &shortcut);
bool unsetShortcut();
signals:
void activated();
private:
void activateShortcut(quint32 native_key, quint32 native_mods);
quint32 nativeModifiers(Qt::KeyboardModifiers qt_mods);
quint32 nativeKeycode(Qt::Key qt_keycode);
bool registerShortcut(quint32 native_key, quint32 native_mods);
bool unregisterShortcut(quint32 native_key, quint32 native_mods);
bool nativeEventFilter(const QByteArray &eventtype, void *message, long *result);
static GlobalShortcut *initialized_;
static QHash<QPair<quint32, quint32>, GlobalShortcut*> internal_shortcuts_;
static const QVector<quint32> mask_modifiers_;
GlobalShortcutBackend *backend_;
QKeySequence shortcut_;
Qt::Key qt_key_;
Qt::KeyboardModifiers qt_mods_;
quint32 native_key_;
quint32 native_mods_;
};
#endif // GLOBALSHORTCUT_H

View File

@@ -20,45 +20,41 @@
#include "config.h"
#ifdef HAVE_DBUS
# include <dbus/gnomesettingsdaemon.h>
#endif
#include <dbus/gnomesettingsdaemon.h>
#include <QAction>
#include <QObject>
#include <QCoreApplication>
#include <QDateTime>
#include <QMap>
#include <QtDebug>
#ifdef HAVE_DBUS
# include <QCoreApplication>
# include <QDBusConnectionInterface>
# include <QDBusMessage>
# include <QDBusPendingCall>
# include <QDBusPendingReply>
#endif
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusPendingCallWatcher>
#include <QDBusPendingReply>
#include "core/closure.h"
#include "core/logging.h"
#include "globalshortcuts.h"
#include "globalshortcuts/globalshortcutbackend.h"
#include "gnomeglobalshortcutbackend.h"
#include "globalshortcutbackend.h"
#include "globalshortcutbackend-dbus.h"
const char *GnomeGlobalShortcutBackend::kGsdService = "org.gnome.SettingsDaemon";
const char *GnomeGlobalShortcutBackend::kGsdPath = "/org/gnome/SettingsDaemon/MediaKeys";
const char *GnomeGlobalShortcutBackend::kGsdInterface = "org.gnome.SettingsDaemon.MediaKeys";
const char *GlobalShortcutBackendDBus::kGsdService = "org.gnome.SettingsDaemon";
const char *GlobalShortcutBackendDBus::kGsdPath = "/org/gnome/SettingsDaemon/MediaKeys";
const char *GlobalShortcutBackendDBus::kGsdInterface = "org.gnome.SettingsDaemon.MediaKeys";
GnomeGlobalShortcutBackend::GnomeGlobalShortcutBackend(GlobalShortcuts *parent)
GlobalShortcutBackendDBus::GlobalShortcutBackendDBus(GlobalShortcuts *parent)
: GlobalShortcutBackend(parent),
interface_(nullptr),
is_connected_(false) {}
bool GnomeGlobalShortcutBackend::DoRegister() {
GlobalShortcutBackendDBus::~GlobalShortcutBackendDBus(){}
bool GlobalShortcutBackendDBus::DoRegister() {
qLog(Debug) << "Registering";
#ifdef HAVE_DBUS
qLog(Debug) << "registering";
// Check if the GSD service is available
if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(kGsdService)) {
qLog(Warning) << "gnome settings daemon not registered";
qLog(Warning) << "Gnome settings daemon not registered";
return false;
}
@@ -72,16 +68,11 @@ bool GnomeGlobalShortcutBackend::DoRegister() {
NewClosure(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(RegisterFinished(QDBusPendingCallWatcher*)), watcher);
return true;
#else
qLog(Warning) << "dbus not available";
return false;
#endif
}
void GnomeGlobalShortcutBackend::RegisterFinished(QDBusPendingCallWatcher *watcher) {
void GlobalShortcutBackendDBus::RegisterFinished(QDBusPendingCallWatcher *watcher) {
#ifdef HAVE_DBUS
QDBusMessage reply = watcher->reply();
watcher->deleteLater();
@@ -93,16 +84,14 @@ void GnomeGlobalShortcutBackend::RegisterFinished(QDBusPendingCallWatcher *watch
connect(interface_, SIGNAL(MediaPlayerKeyPressed(QString, QString)), this, SLOT(GnomeMediaKeyPressed(QString, QString)));
is_connected_ = true;
qLog(Debug) << "registered";
#endif
qLog(Debug) << "Registered";
}
void GnomeGlobalShortcutBackend::DoUnregister() {
void GlobalShortcutBackendDBus::DoUnregister() {
qLog(Debug) << "unregister";
qLog(Debug) << "Unregister";
#ifdef HAVE_DBUS
// Check if the GSD service is available
if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(kGsdService))
return;
@@ -112,14 +101,12 @@ void GnomeGlobalShortcutBackend::DoUnregister() {
interface_->ReleaseMediaPlayerKeys(QCoreApplication::applicationName());
disconnect(interface_, SIGNAL(MediaPlayerKeyPressed(QString, QString)), this, SLOT(GnomeMediaKeyPressed(QString, QString)));
#endif
}
void GnomeGlobalShortcutBackend::GnomeMediaKeyPressed(const QString&, const QString& key) {
void GlobalShortcutBackendDBus::GnomeMediaKeyPressed(const QString&, const QString& key) {
if (key == "Play") manager_->shortcuts()["play_pause"].action->trigger();
if (key == "Stop") manager_->shortcuts()["stop"].action->trigger();
if (key == "Next") manager_->shortcuts()["next_track"].action->trigger();
if (key == "Previous") manager_->shortcuts()["prev_track"].action->trigger();
}

View File

@@ -18,44 +18,51 @@
*
*/
#ifndef GNOMEGLOBALSHORTCUTBACKEND_H
#define GNOMEGLOBALSHORTCUTBACKEND_H
#include <stdbool.h>
#include <QObject>
#include <QString>
#ifndef GLOBALSHORTCUTBACKEND_DBUS_H
#define GLOBALSHORTCUTBACKEND_DBUS_H
#include "config.h"
#include <stdbool.h>
#include <QObject>
#include <QtGlobal>
#include <QPair>
#include <QVector>
#include <QHash>
#include <QString>
#include <QDBusPendingCallWatcher>
#include "globalshortcutbackend.h"
class QDBusPendingCallWatcher;
class GlobalShortcuts;
class OrgGnomeSettingsDaemonMediaKeysInterface;
class GnomeGlobalShortcutBackend : public GlobalShortcutBackend {
class GlobalShortcutBackendDBus : public GlobalShortcutBackend {
Q_OBJECT
public:
explicit GnomeGlobalShortcutBackend(GlobalShortcuts *parent);
public:
explicit GlobalShortcutBackendDBus(GlobalShortcuts *parent);
~GlobalShortcutBackendDBus();
static const char *kGsdService;
static const char *kGsdPath;
static const char *kGsdInterface;
protected:
protected:
bool RegisterInNewThread() const { return true; }
bool DoRegister();
void DoUnregister();
private slots:
private slots:
void RegisterFinished(QDBusPendingCallWatcher *watcher);
void GnomeMediaKeyPressed(const QString& application, const QString& key);
void GnomeMediaKeyPressed(const QString &application, const QString &key);
private:
private:
OrgGnomeSettingsDaemonMediaKeysInterface *interface_;
bool is_connected_;
};
#endif // GNOMEGLOBALSHORTCUTBACKEND_H
#endif // GLOBALSHORTCUTBACKEND_DBUS_H

View File

@@ -18,11 +18,13 @@
*
*/
#ifndef MACGLOBALSHORTCUTBACKEND_H
#define MACGLOBALSHORTCUTBACKEND_H
#ifndef GLOBALSHORTCUTBACKEND_MACOS_H
#define GLOBALSHORTCUTBACKEND_MACOS_H
#include "config.h"
#include <stdbool.h>
#include <memory>
#include "globalshortcutbackend.h"
@@ -32,14 +34,16 @@
#include <QAction>
#include <QKeySequence>
class MacGlobalShortcutBackendPrivate;
class GlobalShortcut;
class MacGlobalShortcutBackend : public GlobalShortcutBackend {
class GlobalShortcutBackendPrivateMacOS;
class GlobalShortcutBackendMacOS : public GlobalShortcutBackend {
Q_OBJECT
public:
explicit MacGlobalShortcutBackend(GlobalShortcuts* parent);
virtual ~MacGlobalShortcutBackend();
explicit GlobalShortcutBackendMacOS(GlobalShortcuts* parent);
virtual ~GlobalShortcutBackendMacOS();
bool IsAccessibilityEnabled() const;
void ShowAccessibilityDialog();
@@ -55,9 +59,9 @@ class MacGlobalShortcutBackend : public GlobalShortcutBackend {
QMap<QKeySequence, QAction*> shortcuts_;
friend class MacGlobalShortcutBackendPrivate;
std::unique_ptr<MacGlobalShortcutBackendPrivate> p_;
friend class GlobalShortcutBackendPrivateMacOS;
std::unique_ptr<GlobalShortcutBackendPrivateMacOS> p_;
};
#endif // MACGLOBALSHORTCUTBACKEND_H
#endif // GLOBALSHORTCUTBACKEND_MACOS_H

View File

@@ -20,7 +20,7 @@
#include "config.h"
#include "macglobalshortcutbackend.h"
#include "globalshortcutbackend-macos.h"
#include <boost/noncopyable.hpp>
@@ -44,9 +44,9 @@
#import "core/mac_utilities.h"
#import "core/SBSystemPreferences.h"
class MacGlobalShortcutBackendPrivate : boost::noncopyable {
class GlobalShortcutBackendPrivate_MacOS : boost::noncopyable {
public:
explicit MacGlobalShortcutBackendPrivate(MacGlobalShortcutBackend* backend)
explicit GlobalShortcutBackendPrivate_MacOS(GlobalShortcutBackendMacOS* backend)
: global_monitor_(nil), local_monitor_(nil), backend_(backend) {}
bool Register() {
@@ -75,16 +75,16 @@ class MacGlobalShortcutBackendPrivate : boost::noncopyable {
id global_monitor_;
id local_monitor_;
MacGlobalShortcutBackend* backend_;
GlobalShortcutBackendMacOS* backend_;
};
MacGlobalShortcutBackend::MacGlobalShortcutBackend(GlobalShortcuts* parent)
GlobalShortcutBackendMacOS::GlobalShortcutBackendMacOS(GlobalShortcuts* parent)
: GlobalShortcutBackend(parent),
p_(new MacGlobalShortcutBackendPrivate(this)) {}
p_(new GlobalShortcutBackendPrivate_MacOS(this)) {}
MacGlobalShortcutBackend::~MacGlobalShortcutBackend() {}
GlobalShortcutBackendMacOS::~GlobalShortcutBackendMacOS() {}
bool MacGlobalShortcutBackend::DoRegister() {
bool GlobalShortcutBackendMacOS::DoRegister() {
// Always enable media keys.
mac::SetShortcutHandler(this);
@@ -96,12 +96,12 @@ bool MacGlobalShortcutBackend::DoRegister() {
}
void MacGlobalShortcutBackend::DoUnregister() {
void GlobalShortcutBackendMacOS::DoUnregister() {
p_->Unregister();
shortcuts_.clear();
}
void MacGlobalShortcutBackend::MacMediaKeyPressed(int key) {
void GlobalShortcutBackendMacOS::MacMediaKeyPressed(int key) {
switch (key) {
case NX_KEYTYPE_PLAY:
KeyPressed(Qt::Key_MediaPlay);
@@ -115,7 +115,7 @@ void MacGlobalShortcutBackend::MacMediaKeyPressed(int key) {
}
}
bool MacGlobalShortcutBackend::KeyPressed(const QKeySequence& sequence) {
bool GlobalShortcutBackendMacOS::KeyPressed(const QKeySequence& sequence) {
if (sequence.isEmpty()) {
return false;
}
@@ -127,11 +127,12 @@ bool MacGlobalShortcutBackend::KeyPressed(const QKeySequence& sequence) {
return false;
}
bool MacGlobalShortcutBackend::IsAccessibilityEnabled() const {
bool GlobalShortcutBackendMacOS::IsAccessibilityEnabled() const {
return AXAPIEnabled();
}
void MacGlobalShortcutBackend::ShowAccessibilityDialog() {
void GlobalShortcutBackendMacOS::ShowAccessibilityDialog() {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSPreferencePanesDirectory, NSSystemDomainMask, YES);
if ([paths count] == 1) {
SBSystemPreferencesApplication* system_prefs = [SBApplication

View File

@@ -1,7 +1,6 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018, 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
@@ -20,24 +19,29 @@
#include "config.h"
#include <QObject>
#include <QMap>
#include <QAction>
#include <QKeySequence>
#include <QtAlgorithms>
#include "globalshortcutbackend-system.h"
#include "core/logging.h"
#include <QtGlobal>
#include <QObject>
#include <QAction>
#include <QtAlgorithms>
#include "globalshortcuts.h"
#include "globalshortcutbackend.h"
#include "qxtglobalshortcut.h"
#include "qxtglobalshortcutbackend.h"
#include "globalshortcut.h"
QxtGlobalShortcutBackend::QxtGlobalShortcutBackend(GlobalShortcuts* parent) : GlobalShortcutBackend(parent) {}
GlobalShortcutBackendSystem::GlobalShortcutBackendSystem(GlobalShortcuts *parent) : GlobalShortcutBackend(parent),
gshortcut_init_(new GlobalShortcut(this)) {}
bool QxtGlobalShortcutBackend::DoRegister() {
GlobalShortcutBackendSystem::~GlobalShortcutBackendSystem(){}
qLog(Debug) << "registering";
for (const GlobalShortcuts::Shortcut& shortcut : manager_->shortcuts().values()) {
bool GlobalShortcutBackendSystem::DoRegister() {
qLog(Debug) << "Registering";
for (const GlobalShortcuts::Shortcut &shortcut : manager_->shortcuts().values()) {
AddShortcut(shortcut.action);
}
@@ -45,19 +49,20 @@ bool QxtGlobalShortcutBackend::DoRegister() {
}
void QxtGlobalShortcutBackend::AddShortcut(QAction *action) {
bool GlobalShortcutBackendSystem::AddShortcut(QAction *action) {
if (action->shortcut().isEmpty()) return;
if (action->shortcut().isEmpty()) return false;
QxtGlobalShortcut *shortcut = new QxtGlobalShortcut(action->shortcut(), this);
GlobalShortcut *shortcut = new GlobalShortcut(action->shortcut(), this, this);
connect(shortcut, SIGNAL(activated()), action, SLOT(trigger()));
shortcuts_ << shortcut;
return true;
}
void QxtGlobalShortcutBackend::DoUnregister() {
void GlobalShortcutBackendSystem::DoUnregister() {
qLog(Debug) << "unregistering";
qLog(Debug) << "Unregistering";
qDeleteAll(shortcuts_);
shortcuts_.clear();

View File

@@ -1,7 +1,6 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018, 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
@@ -18,32 +17,45 @@
*
*/
#ifndef QXTGLOBALSHORTCUTBACKEND_H
#define QXTGLOBALSHORTCUTBACKEND_H
#ifndef GLOBALSHORTCUTBACKEND_SYSTEM_H
#define GLOBALSHORTCUTBACKEND_SYSTEM_H
#include "config.h"
#include "core/logging.h"
#include <stdbool.h>
#include <QObject>
#include <QtGlobal>
#include <QAction>
#include <QList>
#include <QKeySequence>
#include "globalshortcutbackend.h"
class GlobalShortcuts;
class QxtGlobalShortcut;
class GlobalShortcut;
class GlobalShortcutBackendSystem : public GlobalShortcutBackend {
Q_OBJECT
class QxtGlobalShortcutBackend : public GlobalShortcutBackend {
public:
explicit QxtGlobalShortcutBackend(GlobalShortcuts *parent = nullptr);
explicit GlobalShortcutBackendSystem(GlobalShortcuts *parent = nullptr);
~GlobalShortcutBackendSystem();
protected:
bool DoRegister();
void DoUnregister();
private:
void AddShortcut(QAction *action);
QList<QxtGlobalShortcut *> shortcuts_;
bool AddShortcut(QAction *action);
bool RemoveShortcut(QAction *action);
QList<GlobalShortcut*> shortcuts_;
GlobalShortcut *gshortcut_init_;
};
#endif // QXTGLOBALSHORTCUTBACKEND_H
#endif // GLOBALSHORTCUTBACKEND_SYSTEM_H

View File

@@ -24,8 +24,12 @@
#include "config.h"
#include <stdbool.h>
#include <QString>
#include <QtGlobal>
#include <QObject>
#include <QPair>
#include <QHash>
#include <QString>
class GlobalShortcuts;
@@ -41,15 +45,16 @@ class GlobalShortcutBackend : public QObject {
bool Register();
void Unregister();
signals:
signals:
void RegisterFinished(bool success);
protected:
virtual bool DoRegister() = 0;
virtual void DoUnregister() = 0;
GlobalShortcuts* manager_;
GlobalShortcuts *manager_;
bool active_;
};
#endif // GLOBALSHORTCUTBACKEND_H

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018, 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
@@ -30,61 +31,85 @@
# include <QDBusConnectionInterface>
#endif
#include "core/logging.h"
#include "globalshortcuts.h"
#include "globalshortcutbackend.h"
#include "gnomeglobalshortcutbackend.h"
#ifndef Q_OS_MACOS
# include "qxtglobalshortcutbackend.h"
#else
# include "macglobalshortcutbackend.h"
#ifdef HAVE_DBUS
# include "globalshortcutbackend-dbus.h"
#endif
#if defined(HAVE_X11) || defined(Q_OS_WIN)
# include "globalshortcutbackend-system.h"
#endif
#ifdef Q_OS_MACOS
# include "globalshortcutbackend-macos.h"
#endif
#include "settings/shortcutssettingspage.h"
GlobalShortcuts::GlobalShortcuts(QWidget *parent)
: QWidget(parent),
gnome_backend_(nullptr),
dbus_backend_(nullptr),
system_backend_(nullptr),
use_gnome_(false) {
use_dbus_(true),
use_x11_(false)
{
settings_.beginGroup(GlobalShortcutsSettingsPage::kSettingsGroup);
// Create actions
AddShortcut("play", tr("Play"), SIGNAL(Play()));
AddShortcut("pause", tr("Pause"), SIGNAL(Pause()));
AddShortcut("play_pause", tr("Play/Pause"), SIGNAL(PlayPause()), QKeySequence(Qt::Key_MediaPlay));
AddShortcut("stop", tr("Stop"), SIGNAL(Stop()), QKeySequence(Qt::Key_MediaStop));
AddShortcut("stop_after", tr("Stop playing after current track"), SIGNAL(StopAfter()));
AddShortcut("next_track", tr("Next track"), SIGNAL(Next()), QKeySequence(Qt::Key_MediaNext));
AddShortcut("prev_track", tr("Previous track"), SIGNAL(Previous()), QKeySequence(Qt::Key_MediaPrevious));
AddShortcut("inc_volume", tr("Increase volume"), SIGNAL(IncVolume()));
AddShortcut("dec_volume", tr("Decrease volume"), SIGNAL(DecVolume()));
AddShortcut("play", "Play", SIGNAL(Play()));
AddShortcut("pause", "Pause", SIGNAL(Pause()));
AddShortcut("play_pause", "Play/Pause", SIGNAL(PlayPause()), QKeySequence(Qt::Key_MediaPlay));
AddShortcut("stop", "Stop", SIGNAL(Stop()), QKeySequence(Qt::Key_MediaStop));
AddShortcut("stop_after", "Stop playing after current track", SIGNAL(StopAfter()));
AddShortcut("next_track", "Next track", SIGNAL(Next()), QKeySequence(Qt::Key_MediaNext));
AddShortcut("prev_track", "Previous track", SIGNAL(Previous()), QKeySequence(Qt::Key_MediaPrevious));
AddShortcut("inc_volume", "Increase volume", SIGNAL(IncVolume()));
AddShortcut("dec_volume", "Decrease volume", SIGNAL(DecVolume()));
AddShortcut("mute", tr("Mute"), SIGNAL(Mute()));
AddShortcut("seek_forward", tr("Seek forward"), SIGNAL(SeekForward()));
AddShortcut("seek_backward", tr("Seek backward"), SIGNAL(SeekBackward()));
AddShortcut("show_hide", tr("Show/Hide"), SIGNAL(ShowHide()));
AddShortcut("show_osd", tr("Show OSD"), SIGNAL(ShowOSD()));
AddShortcut("toggle_pretty_osd", tr("Toggle Pretty OSD"), SIGNAL(TogglePrettyOSD())); // Toggling possible only for pretty OSD
AddShortcut("shuffle_mode", tr("Change shuffle mode"), SIGNAL(CycleShuffleMode()));
AddShortcut("repeat_mode", tr("Change repeat mode"), SIGNAL(CycleRepeatMode()));
AddShortcut("toggle_scrobbling", tr("Enable/disable scrobbling"), SIGNAL(ToggleScrobbling()));
AddShortcut("seek_forward", "Seek forward", SIGNAL(SeekForward()));
AddShortcut("seek_backward", "Seek backward", SIGNAL(SeekBackward()));
AddShortcut("show_hide", "Show/Hide", SIGNAL(ShowHide()));
AddShortcut("show_osd", "Show OSD", SIGNAL(ShowOSD()));
AddShortcut("toggle_pretty_osd", "Toggle Pretty OSD", SIGNAL(TogglePrettyOSD())); // Toggling possible only for pretty OSD
AddShortcut("shuffle_mode", "Change shuffle mode", SIGNAL(CycleShuffleMode()));
AddShortcut("repeat_mode", "Change repeat mode", SIGNAL(CycleRepeatMode()));
AddShortcut("toggle_scrobbling", "Enable/disable scrobbling", SIGNAL(ToggleScrobbling()));
// Create backends - these do the actual shortcut registration
gnome_backend_ = new GnomeGlobalShortcutBackend(this);
#ifdef HAVE_DBUS
dbus_backend_ = new GlobalShortcutBackendDBus(this);
#endif
#ifndef Q_OS_MACOS
system_backend_ = new QxtGlobalShortcutBackend(this);
#else
system_backend_ = new MacGlobalShortcutBackend(this);
#if defined(HAVE_X11) || defined(Q_OS_WIN)
system_backend_ = new GlobalShortcutBackendSystem(this);
#endif
#ifdef Q_OS_MACOS
system_backend_ = new GlobalShortcutBackendMacOS(this);
#endif
ReloadSettings();
}
void GlobalShortcuts::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_dbus_ = settings_.value("use_dbus", true).toBool();
use_x11_ = settings_.value("use_x11", true).toBool();
Unregister();
Register();
}
void GlobalShortcuts::AddShortcut(const QString &id, const QString &name, const char *signal, const QKeySequence &default_key) {
Shortcut shortcut = AddShortcut(id, name, default_key);
connect(shortcut.action, SIGNAL(triggered()), this, signal);
}
GlobalShortcuts::Shortcut GlobalShortcuts::AddShortcut(const QString &id, const QString &name, const QKeySequence &default_key) {
@@ -96,8 +121,7 @@ GlobalShortcuts::Shortcut GlobalShortcuts::AddShortcut(const QString &id, const
shortcut.id = id;
shortcut.default_key = default_key;
// Create application wide QShortcut to hide keyevents mapped to global
// shortcuts from widgets.
// Create application wide QShortcut to hide keyevents mapped to global shortcuts from widgets.
shortcut.shortcut = new QShortcut(key_sequence, this);
shortcut.shortcut->setContext(Qt::ApplicationShortcut);
@@ -110,36 +134,40 @@ GlobalShortcuts::Shortcut GlobalShortcuts::AddShortcut(const QString &id, const
bool GlobalShortcuts::IsGsdAvailable() const {
#ifdef HAVE_DBUS
return QDBusConnection::sessionBus().interface()->isServiceRegistered(GnomeGlobalShortcutBackend::kGsdService);
return QDBusConnection::sessionBus().interface()->isServiceRegistered(GlobalShortcutBackendDBus::kGsdService);
#else
return false;
#endif
}
void GlobalShortcuts::ReloadSettings() {
bool GlobalShortcuts::IsX11Available() const {
// 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_gnome_ = settings_.value("use_gnome", true).toBool();
#ifdef HAVE_X11
return true;
#else
return false;
#endif
Unregister();
Register();
}
void GlobalShortcuts::Unregister() {
if (gnome_backend_->is_active()) gnome_backend_->Unregister();
if (system_backend_->is_active()) system_backend_->Unregister();
}
void GlobalShortcuts::Register() {
if (use_gnome_ && gnome_backend_->Register()) return;
system_backend_->Register();
if (use_dbus_ && dbus_backend_ && dbus_backend_->Register()) return;
#ifdef HAVE_X11 // If this system has X11, only use the system backend if X11 is enabled in the global shortcut settings
if (use_x11_)
#endif
if (system_backend_) system_backend_->Register();
}
void GlobalShortcuts::Unregister() {
if (dbus_backend_ && dbus_backend_->is_active()) dbus_backend_->Unregister();
if (system_backend_ && system_backend_->is_active()) system_backend_->Unregister();
}
bool GlobalShortcuts::IsMacAccessibilityEnabled() const {
#ifdef Q_OS_MACOS
return static_cast<MacGlobalShortcutBackend*>(system_backend_)->IsAccessibilityEnabled();
if (macos_backend_) return static_cast<GlobalShortcutBackendMacOS*>(macos_backend_)->IsAccessibilityEnabled();
else return false;
#else
return true;
#endif
@@ -147,7 +175,7 @@ bool GlobalShortcuts::IsMacAccessibilityEnabled() const {
void GlobalShortcuts::ShowMacAccessibilityDialog() {
#ifdef Q_OS_MACOS
static_cast<MacGlobalShortcutBackend*>(system_backend_)->ShowAccessibilityDialog();
if (macos_backend_) static_cast<GlobalShortcutBackendMacOS*>(macos_backend_)->ShowAccessibilityDialog();
#endif
}

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018, 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
@@ -35,6 +36,8 @@
#include <QKeySequence>
#include <QSettings>
#include "globalshortcut.h"
class GlobalShortcutBackend;
class GlobalShortcuts : public QWidget {
@@ -52,6 +55,7 @@ class GlobalShortcuts : public QWidget {
QMap<QString, Shortcut> shortcuts() const { return shortcuts_; }
bool IsGsdAvailable() const;
bool IsX11Available() const;
bool IsMacAccessibilityEnabled() const;
public slots:
@@ -61,7 +65,7 @@ class GlobalShortcuts : public QWidget {
void Unregister();
void Register();
signals:
signals:
void Play();
void Pause();
void PlayPause();
@@ -87,15 +91,14 @@ signals:
Shortcut AddShortcut(const QString &id, const QString &name, const QKeySequence &default_key);
private:
GlobalShortcutBackend *gnome_backend_;
GlobalShortcutBackend *dbus_backend_;
GlobalShortcutBackend *system_backend_;
QMap<QString, Shortcut> shortcuts_;
QSettings settings_;
bool use_gnome_;
QSignalMapper *rating_signals_mapper_;
bool use_dbus_;
bool use_x11_;
};
#endif

View File

@@ -0,0 +1,134 @@
/*
* Strawberry Music Player
* Copyright 2018, 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 <QtGlobal>
#include <QMap>
#include <qt_windows.h>
namespace KeyMapperWin {
static const QMap<Qt::Key, quint32> keymapper_win_ = {
{ Qt::Key_0, quint32(Qt::Key_0) },
{ Qt::Key_1, quint32(Qt::Key_1) },
{ Qt::Key_3, quint32(Qt::Key_2) },
{ Qt::Key_4, quint32(Qt::Key_4) },
{ Qt::Key_5, quint32(Qt::Key_5) },
{ Qt::Key_6, quint32(Qt::Key_6) },
{ Qt::Key_7, quint32(Qt::Key_7) },
{ Qt::Key_8, quint32(Qt::Key_8) },
{ Qt::Key_9, quint32(Qt::Key_9) },
{ Qt::Key_A, quint32(Qt::Key_A) },
{ Qt::Key_B, quint32(Qt::Key_B) },
{ Qt::Key_C, quint32(Qt::Key_C) },
{ Qt::Key_D, quint32(Qt::Key_D) },
{ Qt::Key_E, quint32(Qt::Key_E) },
{ Qt::Key_F, quint32(Qt::Key_F) },
{ Qt::Key_G, quint32(Qt::Key_G) },
{ Qt::Key_H, quint32(Qt::Key_H) },
{ Qt::Key_I, quint32(Qt::Key_I) },
{ Qt::Key_J, quint32(Qt::Key_J) },
{ Qt::Key_K, quint32(Qt::Key_K) },
{ Qt::Key_L, quint32(Qt::Key_L) },
{ Qt::Key_M, quint32(Qt::Key_M) },
{ Qt::Key_N, quint32(Qt::Key_N) },
{ Qt::Key_O, quint32(Qt::Key_O) },
{ Qt::Key_P, quint32(Qt::Key_P) },
{ Qt::Key_Q, quint32(Qt::Key_Q) },
{ Qt::Key_R, quint32(Qt::Key_R) },
{ Qt::Key_S, quint32(Qt::Key_S) },
{ Qt::Key_T, quint32(Qt::Key_T) },
{ Qt::Key_U, quint32(Qt::Key_U) },
{ Qt::Key_V, quint32(Qt::Key_V) },
{ Qt::Key_W, quint32(Qt::Key_W) },
{ Qt::Key_X, quint32(Qt::Key_X) },
{ Qt::Key_Y, quint32(Qt::Key_Y) },
{ Qt::Key_Z, quint32(Qt::Key_Z) },
{ Qt::Key_F1, VK_F1 },
{ Qt::Key_F2, VK_F2 },
{ Qt::Key_F3, VK_F3 },
{ Qt::Key_F4, VK_F4 },
{ Qt::Key_F5, VK_F5 },
{ Qt::Key_F6, VK_F6 },
{ Qt::Key_F7, VK_F7 },
{ Qt::Key_F8, VK_F8 },
{ Qt::Key_F9, VK_F9 },
{ Qt::Key_F10, VK_F10 },
{ Qt::Key_F11, VK_F11 },
{ Qt::Key_F12, VK_F12 },
{ Qt::Key_F13, VK_F13 },
{ Qt::Key_F14, VK_F14 },
{ Qt::Key_F15, VK_F15 },
{ Qt::Key_F16, VK_F16 },
{ Qt::Key_F17, VK_F17 },
{ Qt::Key_F18, VK_F18 },
{ Qt::Key_F19, VK_F19 },
{ Qt::Key_F20, VK_F20 },
{ Qt::Key_F21, VK_F21 },
{ Qt::Key_F22, VK_F22 },
{ Qt::Key_F23, VK_F23 },
{ Qt::Key_F24, VK_F24 },
{ Qt::Key_Escape, VK_ESCAPE },
{ Qt::Key_Tab, VK_TAB },
{ Qt::Key_Backtab, VK_TAB },
{ Qt::Key_Backspace, VK_BACK },
{ Qt::Key_Return, VK_RETURN },
{ Qt::Key_Enter, VK_RETURN },
{ Qt::Key_Insert, VK_INSERT },
{ Qt::Key_Delete, VK_DELETE },
{ Qt::Key_Pause, VK_PAUSE },
{ Qt::Key_Print, VK_PRINT },
{ Qt::Key_Clear, VK_CLEAR },
{ Qt::Key_Home, VK_HOME },
{ Qt::Key_End, VK_END },
{ Qt::Key_Left, VK_LEFT },
{ Qt::Key_Up, VK_UP },
{ Qt::Key_Right, VK_RIGHT },
{ Qt::Key_Down, VK_DOWN },
{ Qt::Key_PageUp, VK_PRIOR },
{ Qt::Key_PageDown, VK_NEXT },
{ Qt::Key_Space, VK_SPACE },
{ Qt::Key_Back, VK_BACK },
{ Qt::Key_Asterisk, VK_MULTIPLY },
{ Qt::Key_Plus, VK_ADD },
{ Qt::Key_Minus, VK_SUBTRACT },
{ Qt::Key_Comma, VK_SEPARATOR },
{ Qt::Key_Slash, VK_DIVIDE },
{ Qt::Key_VolumeDown, VK_VOLUME_DOWN },
{ Qt::Key_VolumeMute, VK_VOLUME_MUTE },
{ Qt::Key_VolumeUp, VK_VOLUME_UP },
{ Qt::Key_MediaPlay, VK_MEDIA_PLAY_PAUSE },
{ Qt::Key_MediaStop, VK_MEDIA_STOP },
{ Qt::Key_MediaPrevious, VK_MEDIA_PREV_TRACK },
{ Qt::Key_MediaNext, VK_MEDIA_NEXT_TRACK },
{ Qt::Key_LaunchMail, VK_LAUNCH_MAIL },
{ Qt::Key_LaunchMedia, VK_LAUNCH_MEDIA_SELECT },
{ Qt::Key_Launch0, VK_LAUNCH_APP1 },
{ Qt::Key_Launch1, VK_LAUNCH_APP2 },
{Qt::Key(0), 0}
};
} // namespace

View File

@@ -0,0 +1,248 @@
/*
* Strawberry Music Player
* Copyright 2018, 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 <QtGlobal>
#include <QMap>
#define XK_MISCELLANY
#define XK_XKB_KEYS
#define XK_LATIN1
#ifdef HAVE_KEYSYMDEF_H
# include <X11/keysymdef.h>
#endif
#ifdef HAVE_XF86KEYSYM_H
# include <X11/XF86keysym.h>
#endif
namespace KeyMapperX11 {
static const QMap<Qt::Key, quint32> keymapper_x11_ = {
#ifdef HAVE_KEYSYMDEF_H
{ Qt::Key_0, XK_0 },
{ Qt::Key_1, XK_1 },
{ Qt::Key_3, XK_2 },
{ Qt::Key_4, XK_4 },
{ Qt::Key_5, XK_5 },
{ Qt::Key_6, XK_6 },
{ Qt::Key_7, XK_7 },
{ Qt::Key_8, XK_8 },
{ Qt::Key_9, XK_9 },
{ Qt::Key_A, XK_A },
{ Qt::Key_B, XK_B },
{ Qt::Key_C, XK_C },
{ Qt::Key_D, XK_D },
{ Qt::Key_E, XK_E },
{ Qt::Key_F, XK_F },
{ Qt::Key_G, XK_G },
{ Qt::Key_H, XK_H },
{ Qt::Key_I, XK_I },
{ Qt::Key_J, XK_J },
{ Qt::Key_K, XK_K },
{ Qt::Key_L, XK_L },
{ Qt::Key_M, XK_M },
{ Qt::Key_N, XK_N },
{ Qt::Key_O, XK_O },
{ Qt::Key_P, XK_P },
{ Qt::Key_Q, XK_Q },
{ Qt::Key_R, XK_R },
{ Qt::Key_S, XK_S },
{ Qt::Key_T, XK_T },
{ Qt::Key_U, XK_U },
{ Qt::Key_V, XK_V },
{ Qt::Key_W, XK_W },
{ Qt::Key_X, XK_X },
{ Qt::Key_Y, XK_Y },
{ Qt::Key_Z, XK_Z },
{ Qt::Key_Escape, XK_Escape },
{ Qt::Key_Tab, XK_Tab },
{ Qt::Key_Backtab, XK_ISO_Left_Tab },
{ Qt::Key_Backspace, XK_BackSpace },
{ Qt::Key_Return, XK_Return },
{ Qt::Key_Enter, XK_KP_Enter },
{ Qt::Key_Insert, XK_Insert },
{ Qt::Key_Delete, XK_Delete },
{ Qt::Key_Pause, XK_Pause },
{ Qt::Key_Print, XK_Print },
{ Qt::Key_Clear, XK_Clear },
{ Qt::Key_Home, XK_Home },
{ Qt::Key_End, XK_End },
{ Qt::Key_Left, XK_Left },
{ Qt::Key_Up, XK_Up },
{ Qt::Key_Right, XK_Right },
{ Qt::Key_Down, XK_Down },
{ Qt::Key_PageUp, XK_Prior },
{ Qt::Key_PageDown, XK_Next },
{ Qt::Key_Space, XK_space },
{ Qt::Key_Exclam, XK_exclam },
{ Qt::Key_QuoteDbl, XK_quotedbl },
{ Qt::Key_NumberSign, XK_numbersign },
{ Qt::Key_Dollar, XK_dollar },
{ Qt::Key_Percent, XK_percent },
{ Qt::Key_Ampersand, XK_ampersand },
{ Qt::Key_Apostrophe, XK_apostrophe },
{ Qt::Key_ParenLeft, XK_parenleft },
{ Qt::Key_ParenRight, XK_parenright },
{ Qt::Key_Asterisk, XK_asterisk },
{ Qt::Key_Plus, XK_plus },
{ Qt::Key_Comma, XK_comma },
{ Qt::Key_Minus, XK_minus },
{ Qt::Key_Period, XK_period },
{ Qt::Key_Slash, XK_slash },
{ Qt::Key_Colon, XK_colon },
{ Qt::Key_Semicolon, XK_semicolon },
{ Qt::Key_Less, XK_less },
{ Qt::Key_Equal, XK_equal },
{ Qt::Key_Greater, XK_greater },
{ Qt::Key_Question, XK_question },
{ Qt::Key_BracketLeft, XK_bracketleft },
{ Qt::Key_Backslash, XK_backslash },
{ Qt::Key_BracketRight, XK_bracketright },
{ Qt::Key_AsciiCircum, XK_asciicircum },
{ Qt::Key_Underscore, XK_underscore },
{ Qt::Key_QuoteLeft, XK_quoteleft },
{ Qt::Key_BraceLeft, XK_braceleft },
{ Qt::Key_Bar, XK_bar },
{ Qt::Key_BraceRight, XK_braceright },
{ Qt::Key_AsciiTilde, XK_asciitilde },
{ Qt::Key_nobreakspace, XK_nobreakspace },
{ Qt::Key_exclamdown, XK_exclamdown },
{ Qt::Key_cent, XK_cent },
{ Qt::Key_sterling, XK_sterling },
{ Qt::Key_currency, XK_currency },
{ Qt::Key_yen, XK_yen },
{ Qt::Key_brokenbar, XK_brokenbar },
{ Qt::Key_section, XK_section },
{ Qt::Key_diaeresis, XK_diaeresis },
{ Qt::Key_copyright, XK_copyright },
{ Qt::Key_ordfeminine, XK_ordfeminine },
{ Qt::Key_guillemotleft, XK_guillemotleft },
{ Qt::Key_notsign, XK_notsign },
{ Qt::Key_hyphen, XK_hyphen },
{ Qt::Key_registered, XK_registered },
{ Qt::Key_macron, XK_macron },
{ Qt::Key_degree, XK_degree },
{ Qt::Key_plusminus, XK_plusminus },
{ Qt::Key_twosuperior, XK_twosuperior },
{ Qt::Key_threesuperior, XK_threesuperior },
{ Qt::Key_acute, XK_acute },
{ Qt::Key_mu, XK_mu },
{ Qt::Key_paragraph, XK_paragraph },
{ Qt::Key_periodcentered, XK_periodcentered },
{ Qt::Key_cedilla, XK_cedilla },
{ Qt::Key_onesuperior, XK_onesuperior },
{ Qt::Key_masculine, XK_masculine },
{ Qt::Key_guillemotright, XK_guillemotright },
{ Qt::Key_onequarter, XK_onequarter },
{ Qt::Key_onehalf, XK_onehalf },
{ Qt::Key_threequarters, XK_threequarters },
{ Qt::Key_questiondown, XK_questiondown },
{ Qt::Key_Agrave, XK_Agrave },
{ Qt::Key_Aacute, XK_Aacute },
{ Qt::Key_Acircumflex, XK_Acircumflex },
{ Qt::Key_Atilde, XK_Atilde },
{ Qt::Key_Adiaeresis, XK_Adiaeresis },
{ Qt::Key_Aring, XK_Aring },
{ Qt::Key_AE, XK_AE },
{ Qt::Key_Ccedilla, XK_Ccedilla },
{ Qt::Key_Egrave, XK_Egrave },
{ Qt::Key_Eacute, XK_Eacute },
{ Qt::Key_Ecircumflex, XK_Ecircumflex },
{ Qt::Key_Ediaeresis, XK_Ediaeresis },
{ Qt::Key_Igrave, XK_Igrave },
{ Qt::Key_Iacute, XK_Iacute },
{ Qt::Key_Icircumflex, XK_Icircumflex },
{ Qt::Key_Idiaeresis, XK_Idiaeresis },
{ Qt::Key_ETH, XK_ETH },
{ Qt::Key_Ntilde, XK_Ntilde },
{ Qt::Key_Ograve, XK_Ograve },
{ Qt::Key_Oacute, XK_Oacute },
{ Qt::Key_Ocircumflex, XK_Ocircumflex },
{ Qt::Key_Otilde, XK_Otilde },
{ Qt::Key_Odiaeresis, XK_Odiaeresis },
{ Qt::Key_multiply, XK_multiply },
{ Qt::Key_Ooblique, XK_Ooblique },
{ Qt::Key_Ugrave, XK_Ugrave },
{ Qt::Key_Uacute, XK_Uacute },
{ Qt::Key_Ucircumflex, XK_Ucircumflex },
{ Qt::Key_Udiaeresis, XK_Udiaeresis },
{ Qt::Key_Yacute, XK_Yacute },
{ Qt::Key_THORN, XK_THORN },
{ Qt::Key_ssharp, XK_ssharp },
{ Qt::Key_division, XK_division },
{ Qt::Key_ydiaeresis, XK_ydiaeresis },
{ Qt::Key_Multi_key, XK_Multi_key },
{ Qt::Key_Codeinput, XK_Codeinput },
{ Qt::Key_SingleCandidate, XK_SingleCandidate },
{ Qt::Key_MultipleCandidate, XK_MultipleCandidate },
{ Qt::Key_PreviousCandidate, XK_PreviousCandidate },
{ Qt::Key_Mode_switch, XK_Mode_switch },
#endif
#ifdef HAVE_XF86KEYSYM_H
{ Qt::Key_Back, XF86XK_Back },
{ Qt::Key_Forward, XF86XK_Forward },
{ Qt::Key_Stop, XF86XK_Stop },
{ Qt::Key_Refresh, XF86XK_Refresh },
{ Qt::Key_VolumeDown, XF86XK_AudioLowerVolume },
{ Qt::Key_VolumeMute, XF86XK_AudioMute },
{ Qt::Key_VolumeUp, XF86XK_AudioRaiseVolume },
{ Qt::Key_MediaPlay, XF86XK_AudioPlay },
{ Qt::Key_MediaStop, XF86XK_AudioStop },
{ Qt::Key_MediaPrevious, XF86XK_AudioPrev },
{ Qt::Key_MediaNext, XF86XK_AudioNext },
{ Qt::Key_MediaRecord, XF86XK_AudioRecord },
{ Qt::Key_MediaPause, XF86XK_AudioPause },
{ Qt::Key_HomePage, XF86XK_HomePage },
{ Qt::Key_Favorites, XF86XK_Favorites },
{ Qt::Key_Search, XF86XK_Search },
{ Qt::Key_Standby, XF86XK_Standby },
{ Qt::Key_OpenUrl, XF86XK_OpenURL },
{ Qt::Key_LaunchMail, XF86XK_Mail },
{ Qt::Key_LaunchMedia, XF86XK_AudioMedia },
{ Qt::Key_Launch0, XF86XK_MyComputer },
{ Qt::Key_Launch1, XF86XK_Calculator },
{ Qt::Key_Launch2, XF86XK_Launch0 },
{ Qt::Key_Launch3, XF86XK_Launch1 },
{ Qt::Key_Launch4, XF86XK_Launch2 },
{ Qt::Key_Launch5, XF86XK_Launch3 },
{ Qt::Key_Launch6, XF86XK_Launch4 },
{ Qt::Key_Launch7, XF86XK_Launch5 },
{ Qt::Key_Launch8, XF86XK_Launch6 },
{ Qt::Key_Launch9, XF86XK_Launch7 },
{ Qt::Key_LaunchA, XF86XK_Launch8 },
{ Qt::Key_LaunchB, XF86XK_Launch9 },
{ Qt::Key_LaunchC, XF86XK_LaunchA },
{ Qt::Key_LaunchD, XF86XK_LaunchB },
{ Qt::Key_LaunchE, XF86XK_LaunchC },
{ Qt::Key_LaunchF, XF86XK_LaunchD },
{ Qt::Key_LaunchG, XF86XK_LaunchE },
{ Qt::Key_LaunchH, XF86XK_LaunchF },
#endif
{Qt::Key(0), 0}
};
} // namespace

View File

@@ -133,7 +133,10 @@ SettingsDialog::SettingsDialog(Application *app, QWidget *parent)
QTreeWidgetItem *iface = AddCategory(tr("User interface"));
AddPage(Page_Appearance, new AppearanceSettingsPage(this), iface);
AddPage(Page_Notifications, new NotificationsSettingsPage(this), iface);
#ifdef HAVE_GLOBALSHORTCUTS
AddPage(Page_GlobalShortcuts, new GlobalShortcutsSettingsPage(this), iface);
#endif
#if defined(HAVE_STREAM_TIDAL) || defined(HAVE_STREAM_DEEZER)
QTreeWidgetItem *streaming = AddCategory(tr("Streaming"));

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018, 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
@@ -53,6 +54,7 @@ GlobalShortcutsSettingsPage::GlobalShortcutsSettingsPage(SettingsDialog *dialog)
ui_(new Ui_GlobalShortcutsSettingsPage),
initialised_(false),
grabber_(new GlobalShortcutGrabber) {
ui_->setupUi(this);
ui_->shortcut_options->setEnabled(false);
ui_->list->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
@@ -64,8 +66,17 @@ GlobalShortcutsSettingsPage::GlobalShortcutsSettingsPage(SettingsDialog *dialog)
connect(ui_->radio_none, SIGNAL(clicked()), SLOT(NoneClicked()));
connect(ui_->radio_default, SIGNAL(clicked()), SLOT(DefaultClicked()));
connect(ui_->radio_custom, SIGNAL(clicked()), SLOT(ChangeClicked()));
connect(ui_->change, SIGNAL(clicked()), SLOT(ChangeClicked()));
connect(ui_->gnome_open, SIGNAL(clicked()), SLOT(OpenGnomeKeybindingProperties()));
connect(ui_->button_change, SIGNAL(clicked()), SLOT(ChangeClicked()));
#if !defined(Q_OS_WIN) && !defined(Q_OS_MACOS)
#ifdef HAVE_DBUS
connect(ui_->checkbox_dbus, SIGNAL(clicked(bool)), SLOT(DBusChanged(bool)));
connect(ui_->button_dbus_open, SIGNAL(clicked()), SLOT(OpenGnomeKeybindingProperties()));
#endif
#ifdef HAVE_X11
connect(ui_->checkbox_x11, SIGNAL(clicked(bool)), SLOT(X11Changed(bool)));
#endif
#endif // !defined(Q_OS_WIN) && !defined(Q_OS_MACOS)
}
@@ -91,10 +102,16 @@ void GlobalShortcutsSettingsPage::Load() {
if (!initialised_) {
initialised_ = true;
connect(ui_->mac_open, SIGNAL(clicked()), manager, SLOT(ShowMacAccessibilityDialog()));
connect(ui_->button_macos_open, SIGNAL(clicked()), manager, SLOT(ShowMacAccessibilityDialog()));
if (!manager->IsGsdAvailable()) {
ui_->gnome_container->hide();
ui_->widget_dbus->hide();
settings_.setValue("use_dbus", false);
}
if (!manager->IsX11Available()) {
ui_->widget_x11->hide();
settings_.setValue("use_x11", false);
}
for (const GlobalShortcuts::Shortcut &s : manager->shortcuts().values()) {
@@ -114,29 +131,25 @@ void GlobalShortcutsSettingsPage::Load() {
SetShortcut(s.s.id, s.s.action->shortcut());
}
bool use_gnome = settings_.value("use_gnome", true).toBool();
if (ui_->gnome_container->isVisibleTo(this)) {
ui_->gnome_checkbox->setChecked(use_gnome);
bool use_dbus = settings_.value("use_dbus", true).toBool();
if (ui_->widget_dbus->isVisibleTo(this)) {
ui_->checkbox_dbus->setChecked(use_dbus);
}
ui_->mac_container->setVisible(!manager->IsMacAccessibilityEnabled());
bool use_x11 = settings_.value("use_x11", false).toBool();
if (ui_->widget_x11->isVisibleTo(this)) {
ui_->checkbox_x11->setChecked(use_x11);
}
ui_->widget_macos->setVisible(!manager->IsMacAccessibilityEnabled());
#ifdef Q_OS_MACOS
qint32 mac_version = Utilities::GetMacVersion();
ui_->mac_label->setVisible(mac_version < 9);
ui_->mac_label_mavericks->setVisible(mac_version >= 9);
qint32 macos_version = Utilities::GetMacOsVersion();
ui_->label_macos->setVisible(macos_version < 9);
ui_->label_macos_mavericks->setVisible(macos_version >= 9);
#endif // Q_OS_MACOS
}
void GlobalShortcutsSettingsPage::SetShortcut(const QString &id, const QKeySequence &key) {
Shortcut &shortcut = shortcuts_[id];
shortcut.key = key;
shortcut.item->setText(1, key.toString(QKeySequence::NativeText));
}
void GlobalShortcutsSettingsPage::Save() {
for (const Shortcut &s : shortcuts_.values()) {
@@ -145,12 +158,74 @@ void GlobalShortcutsSettingsPage::Save() {
settings_.setValue(s.s.id, s.key.toString());
}
settings_.setValue("use_gnome", ui_->gnome_checkbox->isChecked());
settings_.setValue("use_dbus", ui_->checkbox_dbus->isChecked());
settings_.setValue("use_x11", ui_->checkbox_x11->isChecked());
dialog()->global_shortcuts_manager()->ReloadSettings();
}
#if !defined(Q_OS_WIN) && !defined(Q_OS_MACOS)
#ifdef HAVE_X11
void GlobalShortcutsSettingsPage::X11Changed(bool) {
if (!ui_->widget_x11->isVisible()) return;
if (ui_->checkbox_x11->isChecked()) {
ui_->list->setEnabled(true);
}
else {
ui_->list->setEnabled(false);
}
}
#endif // HAVE_X11
#ifdef HAVE_DBUS
void GlobalShortcutsSettingsPage::DBusChanged(bool) {
if (!ui_->widget_dbus->isVisible()) return;
if (ui_->checkbox_dbus->isChecked()) {
if (ui_->checkbox_x11->isEnabled()) {
ui_->checkbox_x11->setEnabled(false);
ui_->list->setEnabled(false);
}
if (ui_->checkbox_x11->isChecked()) {
ui_->checkbox_x11->setChecked(false);
ui_->list->setEnabled(false);
}
}
else {
if (!ui_->checkbox_x11->isEnabled()) {
ui_->checkbox_x11->setEnabled(true);
if (ui_->checkbox_x11->isChecked()) ui_->list->setEnabled(true);
}
}
}
void GlobalShortcutsSettingsPage::OpenGnomeKeybindingProperties() {
if (!QProcess::startDetached("gnome-keybinding-properties")) {
if (!QProcess::startDetached("gnome-control-center", QStringList() << "keyboard")) {
QMessageBox::warning(this, "Error", QString("The \"%1\" command could not be started.").arg("gnome-keybinding-properties"));
}
}
}
#endif // HAVE_DBUS
#endif // !defined(Q_OS_WIN) && !defined(Q_OS_MACOS)
void GlobalShortcutsSettingsPage::SetShortcut(const QString &id, const QKeySequence &key) {
Shortcut &shortcut = shortcuts_[id];
shortcut.key = key;
shortcut.item->setText(1, key.toString(QKeySequence::NativeText));
}
void GlobalShortcutsSettingsPage::ItemClicked(QTreeWidgetItem *item) {
current_id_ = item->data(0, Qt::UserRole).toString();
@@ -196,14 +271,3 @@ void GlobalShortcutsSettingsPage::ChangeClicked() {
}
void GlobalShortcutsSettingsPage::OpenGnomeKeybindingProperties() {
if (!QProcess::startDetached("gnome-keybinding-properties")) {
if (!QProcess::startDetached("gnome-control-center", QStringList() << "keyboard")) {
QMessageBox::warning(this, "Error",
tr("The \"%1\" command could not be started.")
.arg("gnome-keybinding-properties"));
}
}
}

View File

@@ -2,6 +2,7 @@
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2018, 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
@@ -26,6 +27,7 @@
#include <memory>
#include <stdbool.h>
#include <QtGlobal>
#include <QObject>
#include <QSettings>
#include <QMap>
@@ -43,7 +45,7 @@ class Ui_GlobalShortcutsSettingsPage;
class GlobalShortcutsSettingsPage : public SettingsPage {
Q_OBJECT
public:
public:
GlobalShortcutsSettingsPage(SettingsDialog *dialog);
~GlobalShortcutsSettingsPage();
static const char *kSettingsGroup;
@@ -53,15 +55,24 @@ public:
void Load();
void Save();
private slots:
private slots:
#if !defined(Q_OS_WIN) && !defined(Q_OS_MACOS)
#ifdef HAVE_X11
void X11Changed(bool);
#endif
#ifdef HAVE_DBUS
void DBusChanged(bool);
void OpenGnomeKeybindingProperties();
#endif
#endif
void ItemClicked(QTreeWidgetItem *);
void NoneClicked();
void DefaultClicked();
void ChangeClicked();
void OpenGnomeKeybindingProperties();
private:
private:
struct Shortcut {
GlobalShortcuts::Shortcut s;
QKeySequence key;
@@ -70,7 +81,7 @@ private:
void SetShortcut(const QString &id, const QKeySequence &key);
private:
private:
Ui_GlobalShortcutsSettingsPage *ui_;
bool initialised_;

View File

@@ -19,8 +19,8 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="gnome_container" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<widget class="QWidget" name="widget_dbus" native="true">
<layout class="QHBoxLayout" name="layout_gnome">
<property name="leftMargin">
<number>0</number>
</property>
@@ -34,7 +34,7 @@
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="gnome_checkbox">
<widget class="QCheckBox" name="checkbox_dbus">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@@ -42,12 +42,12 @@
</sizepolicy>
</property>
<property name="text">
<string>Use Gnome's shortcut keys</string>
<string>Use Gnome D-Bus shortcut keys</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="gnome_open">
<widget class="QPushButton" name="button_dbus_open">
<property name="text">
<string>Open...</string>
</property>
@@ -57,7 +57,41 @@
</widget>
</item>
<item>
<widget class="QWidget" name="mac_container" native="true">
<widget class="QWidget" name="widget_x11" native="true">
<layout class="QHBoxLayout" name="layout_x11">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="checkbox_x11">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Use X11's shortcut keys</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_macos" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>0</number>
@@ -75,7 +109,7 @@
<number>0</number>
</property>
<item>
<widget class="QLabel" name="mac_label">
<widget class="QLabel" name="label_macos">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
@@ -91,7 +125,7 @@
</widget>
</item>
<item>
<widget class="QLabel" name="mac_label_mavericks">
<widget class="QLabel" name="label_macos_mavericks">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
@@ -107,7 +141,7 @@
</widget>
</item>
<item>
<widget class="QPushButton" name="mac_open">
<widget class="QPushButton" name="button_macos_open">
<property name="text">
<string>Open...</string>
</property>
@@ -167,7 +201,7 @@
<item>
<widget class="QRadioButton" name="radio_default">
<property name="text">
<string>De&amp;fault</string>
<string>&amp;Default</string>
</property>
</widget>
</item>
@@ -179,7 +213,7 @@
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<spacer name="spacer_bottom">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -192,7 +226,7 @@
</spacer>
</item>
<item>
<widget class="QPushButton" name="change">
<widget class="QPushButton" name="button_change">
<property name="text">
<string>Change shortcut...</string>
</property>
@@ -208,44 +242,11 @@
<tabstop>radio_none</tabstop>
<tabstop>radio_default</tabstop>
<tabstop>radio_custom</tabstop>
<tabstop>change</tabstop>
<tabstop>button_change</tabstop>
</tabstops>
<resources>
<include location="../../data/data.qrc"/>
<include location="../../data/icons.qrc"/>
</resources>
<connections>
<connection>
<sender>gnome_checkbox</sender>
<signal>toggled(bool)</signal>
<receiver>list</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>63</x>
<y>25</y>
</hint>
<hint type="destinationlabel">
<x>82</x>
<y>63</y>
</hint>
</hints>
</connection>
<connection>
<sender>gnome_checkbox</sender>
<signal>toggled(bool)</signal>
<receiver>shortcut_options</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>244</x>
<y>26</y>
</hint>
<hint type="destinationlabel">
<x>122</x>
<y>298</y>
</hint>
</hints>
</connection>
</connections>
<connections/>
</ui>

View File

@@ -246,11 +246,8 @@ void StretchHeaderView::SetColumnWidth(int logical, ColumnWidthType width) {
bool StretchHeaderView::RestoreState(const QByteArray& data) {
QDataStream s(data);
#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
s.setVersion(QDataStream::Qt_5_5);
#else
s.setVersion(QDataStream::Qt_5_6);
#endif
int magic_number = 0;
s >> magic_number;
@@ -314,11 +311,8 @@ QByteArray StretchHeaderView::SaveState() const {
visual_indices << logicalIndex(i);
}
#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
s.setVersion(QDataStream::Qt_5_5);
#else
s.setVersion(QDataStream::Qt_5_6);
#endif
s << kMagicNumber;
s << stretch_enabled_;