Skip to content

Commit 21eb42f

Browse files
committed
wayland/shortcuts-inhibit: track active state and prevent duplicate
inhibitors
1 parent 39906a7 commit 21eb42f

File tree

4 files changed

+93
-9
lines changed

4 files changed

+93
-9
lines changed

src/wayland/shortcuts_inhibit/inhibitor.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ void ShortcutsInhibitor::setWindow(QObject* window) {
3636
this->bWindowObject = proxyWindow ? window : nullptr;
3737
}
3838

39+
bool ShortcutsInhibitor::isActive() const {
40+
return this->inhibitor ? this->inhibitor->isActive() : false;
41+
}
42+
3943
void ShortcutsInhibitor::boundWindowChanged() {
4044
auto* window = this->bBoundWindow.value();
4145
auto* proxyWindow = qobject_cast<ProxyWindowBase*>(window);
@@ -134,13 +138,31 @@ void ShortcutsInhibitor::onWaylandSurfaceCreated() {
134138
return;
135139
}
136140

137-
delete this->inhibitor;
141+
if (this->inhibitor) {
142+
QObject::disconnect(this->inhibitor, nullptr, this, nullptr);
143+
delete this->inhibitor;
144+
this->inhibitor = nullptr;
145+
}
138146
this->inhibitor = manager->createShortcutsInhibitor(this->mWaylandWindow);
147+
148+
if (this->inhibitor) {
149+
QObject::connect(
150+
this->inhibitor,
151+
&impl::ShortcutsInhibitor::activeChanged,
152+
this,
153+
&ShortcutsInhibitor::activeChanged
154+
);
155+
}
139156
}
140157

141158
void ShortcutsInhibitor::onWaylandSurfaceDestroyed() {
142-
delete this->inhibitor;
143-
this->inhibitor = nullptr;
159+
if (this->inhibitor) {
160+
QObject::disconnect(this->inhibitor, nullptr, this, nullptr);
161+
auto wasActive = this->inhibitor->isActive();
162+
delete this->inhibitor;
163+
this->inhibitor = nullptr;
164+
if (wasActive) { emit this->activeChanged(); }
165+
}
144166
}
145167

146168
} // namespace qs::wayland::shortcuts_inhibit

src/wayland/shortcuts_inhibit/inhibitor.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ class ShortcutsInhibitor: public QObject {
3232
///
3333
/// Must be set to a non null value to enable the inhibitor.
3434
Q_PROPERTY(QObject* window READ window WRITE setWindow NOTIFY windowChanged);
35+
/// Whether the inhibitor is currently active. The inhibitor is active when the compositor
36+
/// has granted the request and shortcuts are being inhibited.
37+
///
38+
/// The compositor may deactivate the inhibitor if the user requests normal shortcuts to be restored.
39+
/// When inactive, there is no way to programmatically reactivate it - the user must do so through
40+
/// compositor-specific mechanisms.
41+
///
42+
/// Note that if the surface loses focus or is destroyed, the inhibitor becomes irrelevant and this
43+
/// property will become false, but no inactive event is sent by the compositor in those cases.
44+
Q_PROPERTY(bool active READ isActive NOTIFY activeChanged);
3545
// clang-format on
3646

3747
public:
@@ -43,10 +53,12 @@ class ShortcutsInhibitor: public QObject {
4353
void setWindow(QObject* window);
4454

4555
[[nodiscard]] QBindable<bool> bindableEnabled() { return &this->bEnabled; }
56+
[[nodiscard]] bool isActive() const;
4657

4758
signals:
4859
void enabledChanged();
4960
void windowChanged();
61+
void activeChanged();
5062

5163
private slots:
5264
void onWindowDestroyed();

src/wayland/shortcuts_inhibit/proto.cpp

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,42 @@ ShortcutsInhibitManager::createShortcutsInhibitor(QtWaylandClient::QWaylandWindo
3636
return nullptr;
3737
}
3838

39+
auto* wlSurface = surface->surface();
40+
41+
if (this->inhibitors.contains(wlSurface)) {
42+
qCWarning(logShortcutsInhibit)
43+
<< "An inhibitor already exists for surface, skipping creation." << wlSurface;
44+
return nullptr;
45+
}
46+
3947
auto* inhibitor =
40-
new ShortcutsInhibitor(this->inhibit_shortcuts(surface->surface(), inputDevice->object()));
41-
qCDebug(logShortcutsInhibit) << "Created inhibitor" << inhibitor;
48+
new ShortcutsInhibitor(this->inhibit_shortcuts(wlSurface, inputDevice->object()), wlSurface);
49+
this->inhibitors.insert(wlSurface, inhibitor);
50+
qCDebug(logShortcutsInhibit) << "Created inhibitor" << inhibitor << "for surface" << wlSurface;
4251
return inhibitor;
4352
}
4453

54+
void ShortcutsInhibitManager::destroyShortcutsInhibitor(ShortcutsInhibitor* inhibitor) {
55+
if (inhibitor) { this->inhibitors.remove(inhibitor->surface()); }
56+
}
57+
4558
ShortcutsInhibitor::~ShortcutsInhibitor() {
46-
qCDebug(logShortcutsInhibit) << "Destroyed inhibitor" << this;
59+
qCDebug(logShortcutsInhibit) << "Destroying inhibitor" << this << "for surface" << this->mSurface;
60+
auto* manager = ShortcutsInhibitManager::instance();
61+
if (manager) { manager->destroyShortcutsInhibitor(this); }
4762
if (this->isInitialized()) this->destroy();
4863
}
4964

65+
void ShortcutsInhibitor::zwp_keyboard_shortcuts_inhibitor_v1_active() {
66+
qCDebug(logShortcutsInhibit) << "Inhibitor became active" << this;
67+
this->mActive = true;
68+
emit this->activeChanged();
69+
}
70+
71+
void ShortcutsInhibitor::zwp_keyboard_shortcuts_inhibitor_v1_inactive() {
72+
qCDebug(logShortcutsInhibit) << "Inhibitor became inactive" << this;
73+
this->mActive = false;
74+
emit this->activeChanged();
75+
}
76+
5077
} // namespace qs::wayland::shortcuts_inhibit::impl

src/wayland/shortcuts_inhibit/proto.hpp

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,40 @@ class ShortcutsInhibitManager
1818
explicit ShortcutsInhibitManager();
1919

2020
ShortcutsInhibitor* createShortcutsInhibitor(QtWaylandClient::QWaylandWindow* surface);
21+
void destroyShortcutsInhibitor(ShortcutsInhibitor* inhibitor);
2122

2223
static ShortcutsInhibitManager* instance();
24+
25+
private:
26+
QHash<wl_surface*, ShortcutsInhibitor*> inhibitors;
2327
};
2428

25-
class ShortcutsInhibitor: public QtWayland::zwp_keyboard_shortcuts_inhibitor_v1 {
29+
class ShortcutsInhibitor
30+
: public QObject
31+
, public QtWayland::zwp_keyboard_shortcuts_inhibitor_v1 {
32+
Q_OBJECT;
33+
2634
public:
27-
explicit ShortcutsInhibitor(::zwp_keyboard_shortcuts_inhibitor_v1* inhibitor)
28-
: QtWayland::zwp_keyboard_shortcuts_inhibitor_v1(inhibitor) {}
35+
explicit ShortcutsInhibitor(::zwp_keyboard_shortcuts_inhibitor_v1* inhibitor, wl_surface* surface)
36+
: QtWayland::zwp_keyboard_shortcuts_inhibitor_v1(inhibitor)
37+
, mSurface(surface) {}
2938

3039
~ShortcutsInhibitor() override;
3140
Q_DISABLE_COPY_MOVE(ShortcutsInhibitor);
41+
42+
[[nodiscard]] bool isActive() const { return this->mActive; }
43+
[[nodiscard]] wl_surface* surface() const { return this->mSurface; }
44+
45+
signals:
46+
void activeChanged();
47+
48+
protected:
49+
void zwp_keyboard_shortcuts_inhibitor_v1_active() override;
50+
void zwp_keyboard_shortcuts_inhibitor_v1_inactive() override;
51+
52+
private:
53+
bool mActive = false;
54+
wl_surface* mSurface;
3255
};
3356

3457
} // namespace qs::wayland::shortcuts_inhibit::impl

0 commit comments

Comments
 (0)