mirror of
https://git.outfoxxed.me/quickshell/quickshell.git
synced 2026-02-23 03:33:57 +11:00
wayland/shortcuts-inhibit: add shortcuts inhibitor
Some checks failed
Build / Nix (push) Has been cancelled
Build / Nix-1 (push) Has been cancelled
Build / Nix-2 (push) Has been cancelled
Build / Nix-3 (push) Has been cancelled
Build / Nix-4 (push) Has been cancelled
Build / Nix-5 (push) Has been cancelled
Build / Nix-6 (push) Has been cancelled
Build / Nix-7 (push) Has been cancelled
Build / Nix-8 (push) Has been cancelled
Build / Nix-9 (push) Has been cancelled
Build / Nix-10 (push) Has been cancelled
Build / Nix-11 (push) Has been cancelled
Build / Nix-12 (push) Has been cancelled
Build / Nix-13 (push) Has been cancelled
Build / Nix-14 (push) Has been cancelled
Build / Nix-15 (push) Has been cancelled
Build / Nix-16 (push) Has been cancelled
Build / Nix-17 (push) Has been cancelled
Build / Nix-18 (push) Has been cancelled
Build / Nix-19 (push) Has been cancelled
Build / Nix-20 (push) Has been cancelled
Build / Nix-21 (push) Has been cancelled
Build / Nix-22 (push) Has been cancelled
Build / Nix-23 (push) Has been cancelled
Build / Nix-24 (push) Has been cancelled
Build / Nix-25 (push) Has been cancelled
Build / Nix-26 (push) Has been cancelled
Build / Nix-27 (push) Has been cancelled
Build / Nix-28 (push) Has been cancelled
Build / Nix-29 (push) Has been cancelled
Build / Nix-30 (push) Has been cancelled
Build / Nix-31 (push) Has been cancelled
Build / Archlinux (push) Has been cancelled
Lint / Lint (push) Has been cancelled
Some checks failed
Build / Nix (push) Has been cancelled
Build / Nix-1 (push) Has been cancelled
Build / Nix-2 (push) Has been cancelled
Build / Nix-3 (push) Has been cancelled
Build / Nix-4 (push) Has been cancelled
Build / Nix-5 (push) Has been cancelled
Build / Nix-6 (push) Has been cancelled
Build / Nix-7 (push) Has been cancelled
Build / Nix-8 (push) Has been cancelled
Build / Nix-9 (push) Has been cancelled
Build / Nix-10 (push) Has been cancelled
Build / Nix-11 (push) Has been cancelled
Build / Nix-12 (push) Has been cancelled
Build / Nix-13 (push) Has been cancelled
Build / Nix-14 (push) Has been cancelled
Build / Nix-15 (push) Has been cancelled
Build / Nix-16 (push) Has been cancelled
Build / Nix-17 (push) Has been cancelled
Build / Nix-18 (push) Has been cancelled
Build / Nix-19 (push) Has been cancelled
Build / Nix-20 (push) Has been cancelled
Build / Nix-21 (push) Has been cancelled
Build / Nix-22 (push) Has been cancelled
Build / Nix-23 (push) Has been cancelled
Build / Nix-24 (push) Has been cancelled
Build / Nix-25 (push) Has been cancelled
Build / Nix-26 (push) Has been cancelled
Build / Nix-27 (push) Has been cancelled
Build / Nix-28 (push) Has been cancelled
Build / Nix-29 (push) Has been cancelled
Build / Nix-30 (push) Has been cancelled
Build / Nix-31 (push) Has been cancelled
Build / Archlinux (push) Has been cancelled
Lint / Lint (push) Has been cancelled
This commit is contained in:
parent
1ddb355121
commit
ed036d514b
9 changed files with 523 additions and 0 deletions
|
|
@ -14,6 +14,7 @@ set shell id.
|
||||||
- Added support for creating Polkit agents.
|
- Added support for creating Polkit agents.
|
||||||
- Added support for creating wayland idle inhibitors.
|
- Added support for creating wayland idle inhibitors.
|
||||||
- Added support for wayland idle timeouts.
|
- Added support for wayland idle timeouts.
|
||||||
|
- Added support for inhibiting wayland compositor shortcuts for focused windows.
|
||||||
- Added the ability to override Quickshell.cacheDir with a custom path.
|
- Added the ability to override Quickshell.cacheDir with a custom path.
|
||||||
|
|
||||||
## Other Changes
|
## Other Changes
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,9 @@ list(APPEND WAYLAND_MODULES Quickshell.Wayland._IdleInhibitor)
|
||||||
add_subdirectory(idle_notify)
|
add_subdirectory(idle_notify)
|
||||||
list(APPEND WAYLAND_MODULES Quickshell.Wayland._IdleNotify)
|
list(APPEND WAYLAND_MODULES Quickshell.Wayland._IdleNotify)
|
||||||
|
|
||||||
|
add_subdirectory(shortcuts_inhibit)
|
||||||
|
list(APPEND WAYLAND_MODULES Quickshell.Wayland._ShortcutsInhibitor)
|
||||||
|
|
||||||
# widgets for qmenu
|
# widgets for qmenu
|
||||||
target_link_libraries(quickshell-wayland PRIVATE
|
target_link_libraries(quickshell-wayland PRIVATE
|
||||||
Qt::Quick Qt::Widgets Qt::WaylandClient Qt::WaylandClientPrivate
|
Qt::Quick Qt::Widgets Qt::WaylandClient Qt::WaylandClientPrivate
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,6 @@ headers = [
|
||||||
"screencopy/view.hpp",
|
"screencopy/view.hpp",
|
||||||
"idle_inhibit/inhibitor.hpp",
|
"idle_inhibit/inhibitor.hpp",
|
||||||
"idle_notify/monitor.hpp",
|
"idle_notify/monitor.hpp",
|
||||||
|
"shortcuts_inhibit/inhibitor.hpp",
|
||||||
]
|
]
|
||||||
-----
|
-----
|
||||||
|
|
|
||||||
25
src/wayland/shortcuts_inhibit/CMakeLists.txt
Normal file
25
src/wayland/shortcuts_inhibit/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
qt_add_library(quickshell-wayland-shortcuts-inhibit STATIC
|
||||||
|
proto.cpp
|
||||||
|
inhibitor.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_add_qml_module(quickshell-wayland-shortcuts-inhibit
|
||||||
|
URI Quickshell.Wayland._ShortcutsInhibitor
|
||||||
|
VERSION 0.1
|
||||||
|
DEPENDENCIES QtQuick
|
||||||
|
)
|
||||||
|
|
||||||
|
install_qml_module(quickshell-wayland-shortcuts-inhibit)
|
||||||
|
|
||||||
|
qs_add_module_deps_light(quickshell-wayland-shortcuts-inhibit Quickshell)
|
||||||
|
|
||||||
|
wl_proto(wlp-shortcuts-inhibit keyboard-shortcuts-inhibit-unstable-v1 "${WAYLAND_PROTOCOLS}/unstable/keyboard-shortcuts-inhibit")
|
||||||
|
|
||||||
|
target_link_libraries(quickshell-wayland-shortcuts-inhibit PRIVATE
|
||||||
|
Qt::Quick Qt::WaylandClient Qt::WaylandClientPrivate wayland-client
|
||||||
|
wlp-shortcuts-inhibit
|
||||||
|
)
|
||||||
|
|
||||||
|
qs_module_pch(quickshell-wayland-shortcuts-inhibit SET large)
|
||||||
|
|
||||||
|
target_link_libraries(quickshell PRIVATE quickshell-wayland-shortcuts-inhibitplugin)
|
||||||
187
src/wayland/shortcuts_inhibit/inhibitor.cpp
Normal file
187
src/wayland/shortcuts_inhibit/inhibitor.cpp
Normal file
|
|
@ -0,0 +1,187 @@
|
||||||
|
#include "inhibitor.hpp"
|
||||||
|
|
||||||
|
#include <private/qwaylandwindow_p.h>
|
||||||
|
#include <qguiapplication.h>
|
||||||
|
#include <qlogging.h>
|
||||||
|
#include <qloggingcategory.h>
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
#include <qwindow.h>
|
||||||
|
|
||||||
|
#include "../../window/proxywindow.hpp"
|
||||||
|
#include "../../window/windowinterface.hpp"
|
||||||
|
#include "proto.hpp"
|
||||||
|
|
||||||
|
namespace qs::wayland::shortcuts_inhibit {
|
||||||
|
using QtWaylandClient::QWaylandWindow;
|
||||||
|
|
||||||
|
ShortcutInhibitor::ShortcutInhibitor() {
|
||||||
|
this->bBoundWindow.setBinding([this] {
|
||||||
|
return this->bEnabled ? this->bWindowObject.value() : nullptr;
|
||||||
|
});
|
||||||
|
|
||||||
|
this->bActive.setBinding([this]() {
|
||||||
|
auto* inhibitor = this->bInhibitor.value();
|
||||||
|
if (!inhibitor) return false;
|
||||||
|
if (!inhibitor->bindableActive().value()) return false;
|
||||||
|
return this->bWindow.value() == this->bFocusedWindow;
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
dynamic_cast<QGuiApplication*>(QGuiApplication::instance()),
|
||||||
|
&QGuiApplication::focusWindowChanged,
|
||||||
|
this,
|
||||||
|
&ShortcutInhibitor::onFocusedWindowChanged
|
||||||
|
);
|
||||||
|
|
||||||
|
this->onFocusedWindowChanged(QGuiApplication::focusWindow());
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortcutInhibitor::~ShortcutInhibitor() {
|
||||||
|
if (!this->bInhibitor) return;
|
||||||
|
|
||||||
|
auto* manager = impl::ShortcutsInhibitManager::instance();
|
||||||
|
if (!manager) return;
|
||||||
|
|
||||||
|
manager->unrefShortcutsInhibitor(this->bInhibitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutInhibitor::onBoundWindowChanged() {
|
||||||
|
auto* window = this->bBoundWindow.value();
|
||||||
|
auto* proxyWindow = qobject_cast<ProxyWindowBase*>(window);
|
||||||
|
|
||||||
|
if (!proxyWindow) {
|
||||||
|
if (auto* iface = qobject_cast<WindowInterface*>(window)) {
|
||||||
|
proxyWindow = iface->proxyWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxyWindow == this->proxyWindow) return;
|
||||||
|
|
||||||
|
if (this->proxyWindow) {
|
||||||
|
QObject::disconnect(this->proxyWindow, nullptr, this, nullptr);
|
||||||
|
this->proxyWindow = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->mWaylandWindow) {
|
||||||
|
QObject::disconnect(this->mWaylandWindow, nullptr, this, nullptr);
|
||||||
|
this->mWaylandWindow = nullptr;
|
||||||
|
this->onWaylandSurfaceDestroyed();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxyWindow) {
|
||||||
|
this->proxyWindow = proxyWindow;
|
||||||
|
|
||||||
|
QObject::connect(proxyWindow, &QObject::destroyed, this, &ShortcutInhibitor::onWindowDestroyed);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
proxyWindow,
|
||||||
|
&ProxyWindowBase::backerVisibilityChanged,
|
||||||
|
this,
|
||||||
|
&ShortcutInhibitor::onWindowVisibilityChanged
|
||||||
|
);
|
||||||
|
|
||||||
|
this->onWindowVisibilityChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutInhibitor::onWindowDestroyed() {
|
||||||
|
this->proxyWindow = nullptr;
|
||||||
|
this->onWaylandSurfaceDestroyed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutInhibitor::onWindowVisibilityChanged() {
|
||||||
|
if (!this->proxyWindow->isVisibleDirect()) return;
|
||||||
|
|
||||||
|
auto* window = this->proxyWindow->backingWindow();
|
||||||
|
if (!window->handle()) window->create();
|
||||||
|
|
||||||
|
auto* waylandWindow = dynamic_cast<QWaylandWindow*>(window->handle());
|
||||||
|
if (!waylandWindow) {
|
||||||
|
qCCritical(impl::logShortcutsInhibit()) << "Window handle is not a QWaylandWindow";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (waylandWindow == this->mWaylandWindow) return;
|
||||||
|
this->mWaylandWindow = waylandWindow;
|
||||||
|
this->bWindow = window;
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
waylandWindow,
|
||||||
|
&QObject::destroyed,
|
||||||
|
this,
|
||||||
|
&ShortcutInhibitor::onWaylandWindowDestroyed
|
||||||
|
);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
waylandWindow,
|
||||||
|
&QWaylandWindow::surfaceCreated,
|
||||||
|
this,
|
||||||
|
&ShortcutInhibitor::onWaylandSurfaceCreated
|
||||||
|
);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
waylandWindow,
|
||||||
|
&QWaylandWindow::surfaceDestroyed,
|
||||||
|
this,
|
||||||
|
&ShortcutInhibitor::onWaylandSurfaceDestroyed
|
||||||
|
);
|
||||||
|
|
||||||
|
if (waylandWindow->surface()) this->onWaylandSurfaceCreated();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutInhibitor::onWaylandWindowDestroyed() { this->mWaylandWindow = nullptr; }
|
||||||
|
|
||||||
|
void ShortcutInhibitor::onWaylandSurfaceCreated() {
|
||||||
|
auto* manager = impl::ShortcutsInhibitManager::instance();
|
||||||
|
|
||||||
|
if (!manager) {
|
||||||
|
qWarning() << "Cannot enable shortcuts inhibitor as keyboard-shortcuts-inhibit-unstable-v1 is "
|
||||||
|
"not supported by "
|
||||||
|
"the current compositor.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->bInhibitor) {
|
||||||
|
qFatal("ShortcutsInhibitor: inhibitor already exists when creating surface");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->bInhibitor = manager->createShortcutsInhibitor(this->mWaylandWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutInhibitor::onWaylandSurfaceDestroyed() {
|
||||||
|
if (!this->bInhibitor) return;
|
||||||
|
|
||||||
|
auto* manager = impl::ShortcutsInhibitManager::instance();
|
||||||
|
if (!manager) return;
|
||||||
|
|
||||||
|
manager->unrefShortcutsInhibitor(this->bInhibitor);
|
||||||
|
this->bInhibitor = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutInhibitor::onInhibitorChanged() {
|
||||||
|
auto* inhibitor = this->bInhibitor.value();
|
||||||
|
if (inhibitor) {
|
||||||
|
QObject::connect(
|
||||||
|
inhibitor,
|
||||||
|
&impl::ShortcutsInhibitor::activeChanged,
|
||||||
|
this,
|
||||||
|
&ShortcutInhibitor::onInhibitorActiveChanged
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutInhibitor::onInhibitorActiveChanged() {
|
||||||
|
auto* inhibitor = this->bInhibitor.value();
|
||||||
|
if (inhibitor && !inhibitor->isActive()) {
|
||||||
|
// Compositor has deactivated the inhibitor, making it invalid.
|
||||||
|
// Set enabled to false so the user can enable it again to create a new inhibitor.
|
||||||
|
this->bEnabled = false;
|
||||||
|
emit this->cancelled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutInhibitor::onFocusedWindowChanged(QWindow* focusedWindow) {
|
||||||
|
this->bFocusedWindow = focusedWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace qs::wayland::shortcuts_inhibit
|
||||||
89
src/wayland/shortcuts_inhibit/inhibitor.hpp
Normal file
89
src/wayland/shortcuts_inhibit/inhibitor.hpp
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qproperty.h>
|
||||||
|
#include <qqmlintegration.h>
|
||||||
|
#include <qtclasshelpermacros.h>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
#include <qwindow.h>
|
||||||
|
|
||||||
|
#include "../../window/proxywindow.hpp"
|
||||||
|
#include "proto.hpp"
|
||||||
|
|
||||||
|
namespace qs::wayland::shortcuts_inhibit {
|
||||||
|
|
||||||
|
///! Prevents compositor keyboard shortcuts from being triggered
|
||||||
|
/// A shortcuts inhibitor prevents the compositor from processing its own keyboard shortcuts
|
||||||
|
/// for the focused surface. This allows applications to receive key events for shortcuts
|
||||||
|
/// that would normally be handled by the compositor.
|
||||||
|
///
|
||||||
|
/// The inhibitor only takes effect when the associated window is focused and the inhibitor
|
||||||
|
/// is enabled. The compositor may choose to ignore inhibitor requests based on its policy.
|
||||||
|
///
|
||||||
|
/// > [!NOTE] Using a shortcuts inhibitor requires the compositor support the [keyboard-shortcuts-inhibit-unstable-v1] protocol.
|
||||||
|
///
|
||||||
|
/// [keyboard-shortcuts-inhibit-unstable-v1]: https://wayland.app/protocols/keyboard-shortcuts-inhibit-unstable-v1
|
||||||
|
class ShortcutInhibitor: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
QML_ELEMENT;
|
||||||
|
// clang-format off
|
||||||
|
/// If the shortcuts inhibitor should be enabled. Defaults to false.
|
||||||
|
Q_PROPERTY(bool enabled READ default WRITE default NOTIFY enabledChanged BINDABLE bindableEnabled);
|
||||||
|
/// The window to associate the shortcuts inhibitor with.
|
||||||
|
/// The inhibitor will only inhibit shortcuts pressed while this window has keyboard focus.
|
||||||
|
///
|
||||||
|
/// Must be set to a non null value to enable the inhibitor.
|
||||||
|
Q_PROPERTY(QObject* window READ default WRITE default NOTIFY windowChanged BINDABLE bindableWindow);
|
||||||
|
/// Whether the inhibitor is currently active. The inhibitor is only active if @@enabled is true,
|
||||||
|
/// @@window has keyboard focus, and the compositor grants the inhibit request.
|
||||||
|
///
|
||||||
|
/// The compositor may deactivate the inhibitor at any time (for example, if the user requests
|
||||||
|
/// normal shortcuts to be restored). When deactivated by the compositor, the inhibitor cannot be
|
||||||
|
/// programmatically reactivated.
|
||||||
|
Q_PROPERTY(bool active READ default NOTIFY activeChanged BINDABLE bindableActive);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
public:
|
||||||
|
ShortcutInhibitor();
|
||||||
|
~ShortcutInhibitor() override;
|
||||||
|
Q_DISABLE_COPY_MOVE(ShortcutInhibitor);
|
||||||
|
|
||||||
|
[[nodiscard]] QBindable<bool> bindableEnabled() { return &this->bEnabled; }
|
||||||
|
[[nodiscard]] QBindable<QObject*> bindableWindow() { return &this->bWindowObject; }
|
||||||
|
[[nodiscard]] QBindable<bool> bindableActive() const { return &this->bActive; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void enabledChanged();
|
||||||
|
void windowChanged();
|
||||||
|
void activeChanged();
|
||||||
|
/// Sent if the compositor cancels the inhibitor while it is active.
|
||||||
|
void cancelled();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onWindowDestroyed();
|
||||||
|
void onWindowVisibilityChanged();
|
||||||
|
void onWaylandWindowDestroyed();
|
||||||
|
void onWaylandSurfaceCreated();
|
||||||
|
void onWaylandSurfaceDestroyed();
|
||||||
|
void onInhibitorActiveChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onBoundWindowChanged();
|
||||||
|
void onInhibitorChanged();
|
||||||
|
void onFocusedWindowChanged(QWindow* focusedWindow);
|
||||||
|
|
||||||
|
ProxyWindowBase* proxyWindow = nullptr;
|
||||||
|
QtWaylandClient::QWaylandWindow* mWaylandWindow = nullptr;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(ShortcutInhibitor, bool, bEnabled, &ShortcutInhibitor::enabledChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(ShortcutInhibitor, QObject*, bWindowObject, &ShortcutInhibitor::windowChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(ShortcutInhibitor, QObject*, bBoundWindow, &ShortcutInhibitor::onBoundWindowChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(ShortcutInhibitor, impl::ShortcutsInhibitor*, bInhibitor, &ShortcutInhibitor::onInhibitorChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(ShortcutInhibitor, QWindow*, bWindow);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(ShortcutInhibitor, QWindow*, bFocusedWindow);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(ShortcutInhibitor, bool, bActive, &ShortcutInhibitor::activeChanged);
|
||||||
|
// clang-format on
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace qs::wayland::shortcuts_inhibit
|
||||||
88
src/wayland/shortcuts_inhibit/proto.cpp
Normal file
88
src/wayland/shortcuts_inhibit/proto.cpp
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
#include "proto.hpp"
|
||||||
|
|
||||||
|
#include <private/qwaylanddisplay_p.h>
|
||||||
|
#include <private/qwaylandinputdevice_p.h>
|
||||||
|
#include <private/qwaylandintegration_p.h>
|
||||||
|
#include <private/qwaylandwindow_p.h>
|
||||||
|
#include <qlogging.h>
|
||||||
|
#include <qloggingcategory.h>
|
||||||
|
#include <qpair.h>
|
||||||
|
#include <qwaylandclientextension.h>
|
||||||
|
|
||||||
|
#include "../../core/logcat.hpp"
|
||||||
|
|
||||||
|
namespace qs::wayland::shortcuts_inhibit::impl {
|
||||||
|
|
||||||
|
QS_LOGGING_CATEGORY(logShortcutsInhibit, "quickshell.wayland.shortcuts_inhibit", QtWarningMsg);
|
||||||
|
|
||||||
|
ShortcutsInhibitManager::ShortcutsInhibitManager(): QWaylandClientExtensionTemplate(1) {
|
||||||
|
this->initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortcutsInhibitManager* ShortcutsInhibitManager::instance() {
|
||||||
|
static auto* instance = new ShortcutsInhibitManager(); // NOLINT
|
||||||
|
return instance->isInitialized() ? instance : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortcutsInhibitor*
|
||||||
|
ShortcutsInhibitManager::createShortcutsInhibitor(QtWaylandClient::QWaylandWindow* surface) {
|
||||||
|
auto* display = QtWaylandClient::QWaylandIntegration::instance()->display();
|
||||||
|
auto* inputDevice = display->lastInputDevice();
|
||||||
|
if (inputDevice == nullptr) inputDevice = display->defaultInputDevice();
|
||||||
|
|
||||||
|
if (inputDevice == nullptr) {
|
||||||
|
qCCritical(logShortcutsInhibit) << "Could not create shortcuts inhibitor: No seat.";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* wlSurface = surface->surface();
|
||||||
|
|
||||||
|
if (this->inhibitors.contains(wlSurface)) {
|
||||||
|
auto& pair = this->inhibitors[wlSurface];
|
||||||
|
pair.second++;
|
||||||
|
qCDebug(logShortcutsInhibit) << "Reusing existing inhibitor" << pair.first << "for surface"
|
||||||
|
<< wlSurface << "- refcount:" << pair.second;
|
||||||
|
return pair.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* inhibitor =
|
||||||
|
new ShortcutsInhibitor(this->inhibit_shortcuts(wlSurface, inputDevice->object()), wlSurface);
|
||||||
|
this->inhibitors.insert(wlSurface, qMakePair(inhibitor, 1));
|
||||||
|
qCDebug(logShortcutsInhibit) << "Created inhibitor" << inhibitor << "for surface" << wlSurface;
|
||||||
|
return inhibitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutsInhibitManager::unrefShortcutsInhibitor(ShortcutsInhibitor* inhibitor) {
|
||||||
|
if (!inhibitor) return;
|
||||||
|
|
||||||
|
auto* surface = inhibitor->surface();
|
||||||
|
if (!this->inhibitors.contains(surface)) return;
|
||||||
|
|
||||||
|
auto& pair = this->inhibitors[surface];
|
||||||
|
pair.second--;
|
||||||
|
qCDebug(logShortcutsInhibit) << "Decremented refcount for inhibitor" << inhibitor
|
||||||
|
<< "- refcount:" << pair.second;
|
||||||
|
|
||||||
|
if (pair.second <= 0) {
|
||||||
|
qCDebug(logShortcutsInhibit) << "Refcount reached 0, destroying inhibitor" << inhibitor;
|
||||||
|
this->inhibitors.remove(surface);
|
||||||
|
delete inhibitor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortcutsInhibitor::~ShortcutsInhibitor() {
|
||||||
|
qCDebug(logShortcutsInhibit) << "Destroying inhibitor" << this << "for surface" << this->mSurface;
|
||||||
|
if (this->isInitialized()) this->destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutsInhibitor::zwp_keyboard_shortcuts_inhibitor_v1_active() {
|
||||||
|
qCDebug(logShortcutsInhibit) << "Inhibitor became active" << this;
|
||||||
|
this->bActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutsInhibitor::zwp_keyboard_shortcuts_inhibitor_v1_inactive() {
|
||||||
|
qCDebug(logShortcutsInhibit) << "Inhibitor became inactive" << this;
|
||||||
|
this->bActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace qs::wayland::shortcuts_inhibit::impl
|
||||||
64
src/wayland/shortcuts_inhibit/proto.hpp
Normal file
64
src/wayland/shortcuts_inhibit/proto.hpp
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <private/qwaylandwindow_p.h>
|
||||||
|
#include <qpair.h>
|
||||||
|
#include <qproperty.h>
|
||||||
|
#include <qtclasshelpermacros.h>
|
||||||
|
#include <qwayland-keyboard-shortcuts-inhibit-unstable-v1.h>
|
||||||
|
#include <qwaylandclientextension.h>
|
||||||
|
|
||||||
|
#include "../../core/logcat.hpp"
|
||||||
|
#include "wayland-keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
|
||||||
|
|
||||||
|
namespace qs::wayland::shortcuts_inhibit::impl {
|
||||||
|
|
||||||
|
QS_DECLARE_LOGGING_CATEGORY(logShortcutsInhibit);
|
||||||
|
|
||||||
|
class ShortcutsInhibitor;
|
||||||
|
|
||||||
|
class ShortcutsInhibitManager
|
||||||
|
: public QWaylandClientExtensionTemplate<ShortcutsInhibitManager>
|
||||||
|
, public QtWayland::zwp_keyboard_shortcuts_inhibit_manager_v1 {
|
||||||
|
public:
|
||||||
|
explicit ShortcutsInhibitManager();
|
||||||
|
|
||||||
|
ShortcutsInhibitor* createShortcutsInhibitor(QtWaylandClient::QWaylandWindow* surface);
|
||||||
|
void unrefShortcutsInhibitor(ShortcutsInhibitor* inhibitor);
|
||||||
|
|
||||||
|
static ShortcutsInhibitManager* instance();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<wl_surface*, QPair<ShortcutsInhibitor*, int>> inhibitors;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ShortcutsInhibitor
|
||||||
|
: public QObject
|
||||||
|
, public QtWayland::zwp_keyboard_shortcuts_inhibitor_v1 {
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ShortcutsInhibitor(::zwp_keyboard_shortcuts_inhibitor_v1* inhibitor, wl_surface* surface)
|
||||||
|
: QtWayland::zwp_keyboard_shortcuts_inhibitor_v1(inhibitor)
|
||||||
|
, mSurface(surface)
|
||||||
|
, bActive(false) {}
|
||||||
|
|
||||||
|
~ShortcutsInhibitor() override;
|
||||||
|
Q_DISABLE_COPY_MOVE(ShortcutsInhibitor);
|
||||||
|
|
||||||
|
[[nodiscard]] QBindable<bool> bindableActive() const { return &this->bActive; }
|
||||||
|
[[nodiscard]] bool isActive() const { return this->bActive; }
|
||||||
|
[[nodiscard]] wl_surface* surface() const { return this->mSurface; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void activeChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void zwp_keyboard_shortcuts_inhibitor_v1_active() override;
|
||||||
|
void zwp_keyboard_shortcuts_inhibitor_v1_inactive() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
wl_surface* mSurface;
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(ShortcutsInhibitor, bool, bActive, &ShortcutsInhibitor::activeChanged);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace qs::wayland::shortcuts_inhibit::impl
|
||||||
65
src/wayland/shortcuts_inhibit/test/manual/test.qml
Normal file
65
src/wayland/shortcuts_inhibit/test/manual/test.qml
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
|
||||||
|
Scope {
|
||||||
|
Timer {
|
||||||
|
id: toggleTimer
|
||||||
|
interval: 100
|
||||||
|
onTriggered: windowLoader.active = true
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyLoader {
|
||||||
|
id: windowLoader
|
||||||
|
active: true
|
||||||
|
|
||||||
|
property bool enabled: false
|
||||||
|
|
||||||
|
FloatingWindow {
|
||||||
|
id: w
|
||||||
|
color: contentItem.palette.window
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: loadedCb
|
||||||
|
text: "Loaded"
|
||||||
|
checked: true
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: enabledCb
|
||||||
|
text: "Enabled"
|
||||||
|
checked: windowLoader.enabled
|
||||||
|
onCheckedChanged: windowLoader.enabled = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: `Active: ${inhibitorLoader.item?.active ?? false}`
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Toggle Window"
|
||||||
|
onClicked: {
|
||||||
|
windowLoader.active = false;
|
||||||
|
toggleTimer.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyLoader {
|
||||||
|
id: inhibitorLoader
|
||||||
|
active: loadedCb.checked
|
||||||
|
|
||||||
|
ShortcutInhibitor {
|
||||||
|
window: w
|
||||||
|
enabled: enabledCb.checked
|
||||||
|
onCancelled: enabledCb.checked = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue