forked from quickshell/quickshell
188 lines
5.6 KiB
C++
188 lines
5.6 KiB
C++
#pragma once
|
|
|
|
#include <qcolor.h>
|
|
#include <qcontainerfwd.h>
|
|
#include <qguiapplication.h>
|
|
#include <qmap.h>
|
|
#include <qnamespace.h>
|
|
#include <qobject.h>
|
|
#include <qqmlcomponent.h>
|
|
#include <qqmlintegration.h>
|
|
#include <qquickitem.h>
|
|
#include <qquickwindow.h>
|
|
#include <qscreen.h>
|
|
#include <qtclasshelpermacros.h>
|
|
#include <qtmetamacros.h>
|
|
#include <qtypes.h>
|
|
|
|
#include "../core/qmlscreen.hpp"
|
|
#include "../core/reload.hpp"
|
|
#include "session_lock/session_lock.hpp"
|
|
|
|
class WlSessionLockSurface;
|
|
|
|
///! Wayland session locker.
|
|
/// Wayland session lock implemented using the [ext_session_lock_v1] protocol.
|
|
///
|
|
/// WlSessionLock will create an instance of its `surface` component for every screen when
|
|
/// `locked` is set to true. The `surface` component must create a @@WlSessionLockSurface
|
|
/// which will be displayed on each screen.
|
|
///
|
|
/// The below example will create a session lock that disappears when the button is clicked.
|
|
/// ```qml
|
|
/// WlSessionLock {
|
|
/// id: lock
|
|
///
|
|
/// WlSessionLockSurface {
|
|
/// Button {
|
|
/// text: "unlock me"
|
|
/// onClicked: lock.locked = false
|
|
/// }
|
|
/// }
|
|
/// }
|
|
///
|
|
/// // ...
|
|
/// lock.locked = true
|
|
/// ```
|
|
///
|
|
/// > [!WARNING] If the WlSessionLock is destroyed or quickshell exits without setting `locked`
|
|
/// > to false, conformant compositors will leave the screen locked and painted with a solid
|
|
/// > color.
|
|
/// >
|
|
/// > This is what makes the session lock secure. The lock dying will not expose your session,
|
|
/// > but it will render it inoperable.
|
|
///
|
|
/// [ext_session_lock_v1]: https://wayland.app/protocols/ext-session-lock-v1
|
|
class WlSessionLock: public Reloadable {
|
|
Q_OBJECT;
|
|
// clang-format off
|
|
/// Controls the lock state.
|
|
///
|
|
/// > [!WARNING] Only one WlSessionLock may be locked at a time. Attempting to enable a lock while
|
|
/// > another lock is enabled will do nothing.
|
|
Q_PROPERTY(bool locked READ isLocked WRITE setLocked NOTIFY lockStateChanged);
|
|
/// The compositor lock state.
|
|
///
|
|
/// This is set to true once the compositor has confirmed all screens are covered with locks.
|
|
Q_PROPERTY(bool secure READ isSecure NOTIFY secureStateChanged);
|
|
/// The surface that will be created for each screen. Must create a @@WlSessionLockSurface$.
|
|
Q_PROPERTY(QQmlComponent* surface READ surfaceComponent WRITE setSurfaceComponent NOTIFY surfaceComponentChanged);
|
|
// clang-format on
|
|
QML_ELEMENT;
|
|
Q_CLASSINFO("DefaultProperty", "surface");
|
|
|
|
public:
|
|
explicit WlSessionLock(QObject* parent = nullptr): Reloadable(parent) {}
|
|
|
|
void onReload(QObject* oldInstance) override;
|
|
|
|
[[nodiscard]] bool isLocked() const;
|
|
void setLocked(bool locked);
|
|
|
|
[[nodiscard]] bool isSecure() const;
|
|
|
|
[[nodiscard]] QQmlComponent* surfaceComponent() const;
|
|
void setSurfaceComponent(QQmlComponent* surfaceComponent);
|
|
|
|
signals:
|
|
void lockStateChanged();
|
|
void secureStateChanged();
|
|
void surfaceComponentChanged();
|
|
|
|
private slots:
|
|
void unlock();
|
|
void onScreensChanged();
|
|
|
|
private:
|
|
void updateSurfaces(bool show, WlSessionLock* old = nullptr);
|
|
void realizeLockTarget(WlSessionLock* old = nullptr);
|
|
|
|
SessionLockManager* manager = nullptr;
|
|
QQmlComponent* mSurfaceComponent = nullptr;
|
|
QMap<QScreen*, WlSessionLockSurface*> surfaces;
|
|
bool lockTarget = false;
|
|
|
|
friend class WlSessionLockSurface;
|
|
};
|
|
|
|
///! Surface to display with a `WlSessionLock`.
|
|
/// Surface displayed by a @@WlSessionLock when it is locked.
|
|
class WlSessionLockSurface: public Reloadable {
|
|
Q_OBJECT;
|
|
// clang-format off
|
|
Q_PROPERTY(QQuickItem* contentItem READ contentItem);
|
|
/// If the surface has been made visible.
|
|
///
|
|
/// Note: SessionLockSurfaces will never become invisible, they will only be destroyed.
|
|
Q_PROPERTY(bool visible READ isVisible NOTIFY visibleChanged);
|
|
Q_PROPERTY(qint32 width READ width NOTIFY widthChanged);
|
|
Q_PROPERTY(qint32 height READ height NOTIFY heightChanged);
|
|
/// The screen that the surface is displayed on.
|
|
Q_PROPERTY(QuickshellScreenInfo* screen READ screen NOTIFY screenChanged);
|
|
/// The background color of the window. Defaults to white.
|
|
///
|
|
/// > [!WARNING] This seems to behave weirdly when using transparent colors on some systems.
|
|
/// > Using a colored content item over a transparent window is the recommended way to work around this:
|
|
/// > ```qml
|
|
/// > ProxyWindow {
|
|
/// > Rectangle {
|
|
/// > anchors.fill: parent
|
|
/// > color: "#20ffffff"
|
|
/// >
|
|
/// > // your content here
|
|
/// > }
|
|
/// > }
|
|
/// > ```
|
|
/// > ... but you probably shouldn't make a transparent lock,
|
|
/// > and most compositors will ignore an attempt to do so.
|
|
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged);
|
|
Q_PROPERTY(QQmlListProperty<QObject> data READ data);
|
|
// clang-format on
|
|
QML_NAMED_ELEMENT(WlSessionLockSurface);
|
|
Q_CLASSINFO("DefaultProperty", "data");
|
|
|
|
public:
|
|
explicit WlSessionLockSurface(QObject* parent = nullptr);
|
|
~WlSessionLockSurface() override;
|
|
Q_DISABLE_COPY_MOVE(WlSessionLockSurface);
|
|
|
|
void onReload(QObject* oldInstance) override;
|
|
QQuickWindow* disownWindow();
|
|
|
|
void attach();
|
|
void show();
|
|
|
|
[[nodiscard]] QQuickItem* contentItem() const;
|
|
|
|
[[nodiscard]] bool isVisible() const;
|
|
|
|
[[nodiscard]] qint32 width() const;
|
|
[[nodiscard]] qint32 height() const;
|
|
|
|
[[nodiscard]] QuickshellScreenInfo* screen() const;
|
|
void setScreen(QScreen* qscreen);
|
|
|
|
[[nodiscard]] QColor color() const;
|
|
void setColor(QColor color);
|
|
|
|
[[nodiscard]] QQmlListProperty<QObject> data();
|
|
|
|
signals:
|
|
void visibleChanged();
|
|
void widthChanged();
|
|
void heightChanged();
|
|
void screenChanged();
|
|
void colorChanged();
|
|
|
|
private slots:
|
|
void onScreenDestroyed();
|
|
void onWidthChanged();
|
|
void onHeightChanged();
|
|
|
|
private:
|
|
QQuickWindow* window = nullptr;
|
|
QQuickItem* mContentItem;
|
|
QScreen* mScreen = nullptr;
|
|
QColor mColor = Qt::white;
|
|
LockWindowExtension* ext;
|
|
};
|