Skip to content

Commit

Permalink
FEAT(client, unix): Make shortcuts disablable
Browse files Browse the repository at this point in the history
Previously the shortcut engine on Unix could not be disabled. Therefore,
the bEnableShortcut setting effectively had no effect on these systems,
making the change of its default value on Wayland (in order to prevent
CPU intensive polling) as done in 13c7ff5
pointless.

This commit extends the engine's implementation such that it is now able
to disable shortcuts. This will automatically expose the enable shortcut
setting in the settings page. Thus, users can now explicitly re-enabled
the shortcut engine on Wayland systems.
  • Loading branch information
Krzmbrzl committed Jul 29, 2022
1 parent 19cdb0b commit 8f27798
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 17 deletions.
2 changes: 1 addition & 1 deletion src/mumble/GlobalShortcut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ GlobalShortcutConfig::GlobalShortcutConfig(Settings &st) : ConfigWidget(st) {
qlWaylandNote->setVisible(false);
#ifdef Q_OS_LINUX
if (EnvUtils::waylandIsUsed()) {
// Our global shortcut system doesn't work with Wayland
// Our global shortcut system doesn't work properly with Wayland
qlWaylandNote->setVisible(true);
}
#endif
Expand Down
80 changes: 64 additions & 16 deletions src/mumble/GlobalShortcut_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ GlobalShortcutEngine *GlobalShortcutEngine::platformInit() {
GlobalShortcutX::GlobalShortcutX() {
iXIopcode = -1;
bRunning = false;
m_enabled = true;

display = XOpenDisplay(nullptr);

Expand All @@ -61,27 +62,57 @@ GlobalShortcutX::GlobalShortcutX() {
return;
}

init();
}

GlobalShortcutX::~GlobalShortcutX() {
stop();

if (display) {
XCloseDisplay(display);
}

}

void GlobalShortcutX::stop() {
bRunning = false;
wait();

if (m_watcher) {
m_watcher->deleteLater();
m_watcher = nullptr;
}
if (m_notifier) {
m_notifier->deleteLater();
m_notifier = nullptr;
}
}

bool GlobalShortcutX::init() {
#ifdef Q_OS_LINUX
if (Global::get().s.bEnableEvdev) {
QString dir = QLatin1String("/dev/input");
QFileSystemWatcher *fsw = new QFileSystemWatcher(QStringList(dir), this);
connect(fsw, SIGNAL(directoryChanged(const QString &)), this, SLOT(directoryChanged(const QString &)));
m_watcher = new QFileSystemWatcher(QStringList(dir), this);
connect(m_watcher, SIGNAL(directoryChanged(const QString &)), this, SLOT(directoryChanged(const QString &)));
directoryChanged(dir);

if (qsKeyboards.isEmpty()) {
foreach (QFile *f, qmInputDevices)
for (QFile *f : qmInputDevices) {
delete f;
}
qmInputDevices.clear();

delete fsw;
delete m_watcher;
m_watcher = nullptr;
qWarning(
"GlobalShortcutX: Unable to open any keyboard input devices under /dev/input, falling back to XInput");
} else {
return;
return false;
}
}
#endif

qsRootWindows.clear();
for (int i = 0; i < ScreenCount(display); ++i)
qsRootWindows.insert(RootWindow(display, i));

Expand Down Expand Up @@ -113,29 +144,24 @@ GlobalShortcutX::GlobalShortcutX() {
evmask.mask_len = sizeof(mask);
evmask.mask = mask;

foreach (Window w, qsRootWindows)
for (Window w : qsRootWindows) {
XISelectEvents(display, w, &evmask, 1);
}
XFlush(display);

connect(new QSocketNotifier(ConnectionNumber(display), QSocketNotifier::Read, this), SIGNAL(activated(int)),
this, SLOT(displayReadyRead(int)));
m_notifier = new QSocketNotifier(ConnectionNumber(display), QSocketNotifier::Read, this);
connect(m_notifier, SIGNAL(activated(int)), this, SLOT(displayReadyRead(int)));

return;
return true;
}
}
#endif
qWarning("GlobalShortcutX: No XInput support, falling back to polled input. This wastes a lot of CPU resources, so "
"please enable one of the other methods.");
bRunning = true;
start(QThread::TimeCriticalPriority);
}

GlobalShortcutX::~GlobalShortcutX() {
bRunning = false;
wait();

if (display)
XCloseDisplay(display);
return true;
}

// Tight loop polling
Expand Down Expand Up @@ -208,6 +234,28 @@ void GlobalShortcutX::queryXIMasterList() {
#endif
}

bool GlobalShortcutX::canDisable() {
return true;
}

bool GlobalShortcutX::enabled() {
return m_enabled;
}

void GlobalShortcutX::setEnabled(bool enabled) {
if (enabled == m_enabled && (enabled != bRunning)) {
return;
}

m_enabled = enabled;

if (!m_enabled) {
stop();
} else {
m_enabled = init();
}
}

// XInput2 event is ready on socketnotifier.
void GlobalShortcutX::displayReadyRead(int) {
#ifndef NO_XINPUT2
Expand Down
16 changes: 16 additions & 0 deletions src/mumble/GlobalShortcut_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@
#include "Global.h"
#include "GlobalShortcut.h"


#include <X11/X.h>

#define NUM_BUTTONS 0x2ff

struct _XDisplay;
typedef _XDisplay Display;

class QFileSystemWatcher;
class QSocketNotifier;

class GlobalShortcutX : public GlobalShortcutEngine {
private:
Q_OBJECT
Expand All @@ -37,10 +41,22 @@ class GlobalShortcutX : public GlobalShortcutEngine {
ButtonInfo buttonInfo(const QVariant &) Q_DECL_OVERRIDE;

void queryXIMasterList();

bool canDisable() override;
bool enabled() override;
void setEnabled(bool enabled) override;
public slots:
void displayReadyRead(int);
void inputReadyRead(int);
void directoryChanged(const QString &);

protected:
bool m_enabled = true;
QFileSystemWatcher *m_watcher = nullptr;
QSocketNotifier *m_notifier = nullptr;

bool init();
void stop();
};

// These are macros that X11/X.h defines and that are causing problems in unity builds
Expand Down

0 comments on commit 8f27798

Please sign in to comment.