diff --git a/.clang-format b/.clang-format index faedbee8..eb81a3b7 100644 --- a/.clang-format +++ b/.clang-format @@ -69,6 +69,7 @@ IndentWidth: 2 TabWidth: 2 AllowAllConstructorInitializersOnNextLine: false ConstructorInitializerAllOnOneLineOrOnePerLine: true +CommentPragmas: '.*' NamespaceIndentation: None IncludeBlocks: Regroup IncludeCategories: diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..6b1b58df --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = tab + +[*.nix] +indent_style = space +indent_size = 2 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..b3bb12cb --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "docs"] + path = docs + url = https://git.outfoxxed.me/outfoxxed/quickshell-docs diff --git a/docs b/docs new file mode 160000 index 00000000..27b32740 --- /dev/null +++ b/docs @@ -0,0 +1 @@ +Subproject commit 27b3274027251ebf382e31546ef2b350ae2f7b0e diff --git a/src/cpp/layershell.hpp b/src/cpp/layershell.hpp index 3d9e4540..29375ce4 100644 --- a/src/cpp/layershell.hpp +++ b/src/cpp/layershell.hpp @@ -56,13 +56,23 @@ Q_ENUM_NS(Enum); } // namespace Layer +/// Type of keyboard focus that will be accepted by a [ProxyShellWindow] +/// +/// [ProxyShellWindow]: ../proxyshellwindow namespace KeyboardFocus { // NOLINT Q_NAMESPACE; QML_ELEMENT; enum Enum { + /// No keyboard input will be accepted. None = 0, + /// Exclusive access to the keyboard, locking out all other windows. Exclusive = 1, + /// Access to the keyboard as determined by the operating system. + /// + /// > [!WARNING] On some systems, `OnDemand` may cause the shell window to + /// > retain focus over another window unexpectedly. + /// > You should try `None` if you experience issues. OnDemand = 2, }; Q_ENUM_NS(Enum); @@ -81,19 +91,57 @@ Q_ENUM_NS(Enum); } // namespace ScreenConfiguration +///! Decorationless window attached to screen edges by anchors. +/// Decorationless window attached to screen edges by anchors. +/// +/// #### Example +/// The following snippet creates a white bar attached to the bottom of [TODO] screen. +/// +/// ```qml +/// ProxyShellWindow { +/// anchors { +/// left: true +/// bottom: true +/// right: true +/// } +/// +/// Text { +/// anchors.horizontalCenter: parent.horizontalCenter +/// anchors.verticalCenter: parent.verticalCenter +/// text: "Hello!" +/// } +/// } +/// ``` class ProxyShellWindow: public ProxyWindowBase { // clang-format off Q_OBJECT; + /// The screen that the shell window currently occupies. + /// + /// > [!INFO] This cannot be changed while the shell window is visible. Q_PROPERTY(QuickShellScreenInfo* screen READ screen WRITE setScreen NOTIFY screenChanged); + /// Anchors attach a shell window to the sides of the screen. + /// By default all anchors are disabled to avoid blocking the entire screen due to a misconfiguration. + /// + /// > [!INFO] When two opposite anchors are attached at the same time, the corrosponding dimension + /// > (width or height) will be forced to equal the screen width/height. + /// > Margins can be used to create anchored windows that are also disconnected from the monitor sides. Q_PROPERTY(Anchors anchors READ anchors WRITE setAnchors NOTIFY anchorsChanged); - Q_PROPERTY(qint32 exclusionZone READ exclusiveZone WRITE setExclusiveZone NOTIFY exclusionZoneChanged) - Q_PROPERTY(Margins margins READ margins WRITE setMargins NOTIFY marginsChanged) - Q_PROPERTY(Layer::Enum layer READ layer WRITE setLayer NOTIFY layerChanged) - Q_PROPERTY(QString scope READ scope WRITE setScope) - Q_PROPERTY(KeyboardFocus::Enum keyboardFocus READ keyboardFocus WRITE setKeyboardFocus NOTIFY keyboardFocusChanged) - Q_PROPERTY(ScreenConfiguration::Enum screenConfiguration READ screenConfiguration WRITE setScreenConfiguration) + /// The amount of space reserved for the shell layer relative to its anchors. + /// + /// > [!INFO] Some systems will require exactly 3 anchors to be attached for the exclusion zone to take + /// > effect. + Q_PROPERTY(qint32 exclusionZone READ exclusiveZone WRITE setExclusiveZone NOTIFY exclusionZoneChanged); + /// Offsets from the sides of the screen. + /// + /// > [!INFO] Only applies to edges with anchors + Q_PROPERTY(Margins margins READ margins WRITE setMargins NOTIFY marginsChanged); + /// The shell layer the window sits in. Defaults to `Layer.Top`. + Q_PROPERTY(Layer::Enum layer READ layer WRITE setLayer NOTIFY layerChanged); + Q_PROPERTY(QString scope READ scope WRITE setScope); + /// The degree of keyboard focus taken. Defaults to `KeyboardFocus.None`. + Q_PROPERTY(KeyboardFocus::Enum keyboardFocus READ keyboardFocus WRITE setKeyboardFocus NOTIFY keyboardFocusChanged); + Q_PROPERTY(ScreenConfiguration::Enum screenConfiguration READ screenConfiguration WRITE setScreenConfiguration); Q_PROPERTY(bool closeOnDismissed READ closeOnDismissed WRITE setCloseOnDismissed); - Q_CLASSINFO("DefaultProperty", "data"); QML_ELEMENT; // clang-format on diff --git a/src/cpp/module.md b/src/cpp/module.md new file mode 100644 index 00000000..f7e1d8ec --- /dev/null +++ b/src/cpp/module.md @@ -0,0 +1,13 @@ +name = "QuickShell" +description = "Core QuickShell types" +headers = [ + "qmlglobal.hpp", + "qmlscreen.hpp", + "scavenge.hpp", + "shell.hpp", + "variants.hpp", + "proxywindow.hpp", + "layershell.hpp", +] +----- +The core types provided by QuickShell diff --git a/src/cpp/proxywindow.hpp b/src/cpp/proxywindow.hpp index 8bdc8743..19d8b4c5 100644 --- a/src/cpp/proxywindow.hpp +++ b/src/cpp/proxywindow.hpp @@ -20,10 +20,29 @@ // like anchors must use `item`. class ProxyWindowBase: public Scavenger { Q_OBJECT; + /// The content item of the window. Q_PROPERTY(QQuickItem* item READ item CONSTANT); + /// The visibility of the window. + /// + /// > [!INFO] Windows are not visible by default so you will need to set this to make the window + /// appear. Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged); Q_PROPERTY(qint32 width READ width WRITE setWidth NOTIFY widthChanged); Q_PROPERTY(qint32 height READ height WRITE setHeight NOTIFY heightChanged); + /// 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 + /// > } + /// > } + /// > ``` Q_PROPERTY(QColor color READ color WRITE setColor); Q_PROPERTY(QQmlListProperty data READ data); Q_CLASSINFO("DefaultProperty", "data"); diff --git a/src/cpp/qmlglobal.cpp b/src/cpp/qmlglobal.cpp index 3c4e427b..ddc3987a 100644 --- a/src/cpp/qmlglobal.cpp +++ b/src/cpp/qmlglobal.cpp @@ -33,7 +33,8 @@ qsizetype QuickShellGlobal::screensCount(QQmlListProperty* return static_cast(prop->object)->mScreens.size(); // NOLINT } -QuickShellScreenInfo* QuickShellGlobal::screenAt(QQmlListProperty* prop, qsizetype i) { +QuickShellScreenInfo* +QuickShellGlobal::screenAt(QQmlListProperty* prop, qsizetype i) { return static_cast(prop->object)->mScreens.at(i); // NOLINT } diff --git a/src/cpp/qmlglobal.hpp b/src/cpp/qmlglobal.hpp index b94ecda6..03009d53 100644 --- a/src/cpp/qmlglobal.hpp +++ b/src/cpp/qmlglobal.hpp @@ -11,6 +11,26 @@ class QuickShellGlobal: public QObject { Q_OBJECT; + /// All currently connected screens. + /// + /// This property updates as connected screens change. + /// + /// #### Reusing a window on every screen + /// ```qml + /// ShellRoot { + /// Variants { + /// ProxyShellWindow { + /// // ... + /// } + /// + /// // see Variants for details + /// variants: QuickShell.screens.map(screen => ({ screen })) + /// } + /// } + /// ``` + /// + /// This creates an instance of your window once on every screen. + /// As screens are added or removed your window will be created or destroyed on those screens. Q_PROPERTY(QQmlListProperty screens READ screens NOTIFY screensChanged); QML_SINGLETON; QML_NAMED_ELEMENT(QuickShell); @@ -20,11 +40,47 @@ public: QQmlListProperty screens(); + /// Reload the shell from the [ShellRoot]. + /// + /// `hard` - perform a hard reload. If this is false, QuickShell will attempt to reuse windows + /// that already exist. If true windows will be recreated. + /// + /// > [!INFO] QuickShell can only reuse windows that are in a hierarchy of elements known + /// > internally as `Scavengeable`. These types are [ShellRoot] and [Variants]. + /// > + /// > ```qml + /// > // this will reuse the window on reload + /// > ShellRoot { + /// > Varaints { + /// > ProxyShellWindow { + /// > // ... + /// > } + /// > + /// > // ... + /// > } + /// > } + /// > + /// > // this will NOT reuse the window on reload, + /// > // and will destroy the old one / create a new one every time + /// > ShellRoot { + /// > AnyNonScavengeableType { + /// > ProxyShellWindow { + /// > // ... + /// > } + /// > + /// > // ... + /// > } + /// > } + /// > ``` + /// > + /// > [ShellRoot]: ../shellroot + /// > [Variants]: ../variants + Q_INVOKABLE void reload(bool hard); + signals: void screensChanged(); public slots: - void reload(bool hard); void updateScreens(); private: diff --git a/src/cpp/qmlscreen.hpp b/src/cpp/qmlscreen.hpp index c89e3e76..1fbfd2c7 100644 --- a/src/cpp/qmlscreen.hpp +++ b/src/cpp/qmlscreen.hpp @@ -8,16 +8,34 @@ #include // unfortunately QQuickScreenInfo is private. + +/// Monitor object useful for setting the monitor for a [ProxyShellWindow] +/// or querying information about the monitor. +/// +/// > [!WARNING] If the monitor is disconnected than any stored copies of its ShellMonitor will +/// > be marked as dangling and all properties will return default values. +/// > Reconnecting the monitor will not reconnect it to the ShellMonitor object. +/// +/// Due to some technical limitations, it was not possible to reuse the native qml [Screen] type. +/// +/// [ProxyShellWindow]: ../proxyshellwindow +/// [Screen]: https://doc.qt.io/qt-6/qml-qtquick-screen.html class QuickShellScreenInfo: public QObject { Q_OBJECT; - QML_ELEMENT; - QML_UNCREATABLE("QuickShellScreenInfo can only be obtained via QuickShell.screens"); + QML_NAMED_ELEMENT(ShellScreen); + QML_UNCREATABLE("ShellScreen can only be obtained via QuickShell.screens"); // clang-format off + /// The name of the screen as seen by the operating system. + /// + /// Usually something like `DP-1`, `HDMI-1`, `eDP-1`. Q_PROPERTY(QString name READ name NOTIFY nameChanged); Q_PROPERTY(qint32 width READ width NOTIFY widthChanged); Q_PROPERTY(qint32 height READ height NOTIFY heightChanged); + /// The number of physical pixels per millimeter. Q_PROPERTY(qreal pixelDensity READ pixelDensity NOTIFY logicalPixelDensityChanged); + /// The number of device-independent (scaled) pixels per millimeter. Q_PROPERTY(qreal logicalPixelDensity READ logicalPixelDensity NOTIFY logicalPixelDensityChanged); + /// The ratio between physical pixels and device-independent (scaled) pixels. Q_PROPERTY(qreal devicePixelRatio READ devicePixelRatio NOTIFY devicePixelRatioChanged); Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation NOTIFY orientationChanged); Q_PROPERTY(Qt::ScreenOrientation primatyOrientation READ primaryOrientation NOTIFY primaryOrientationChanged); diff --git a/src/cpp/shell.hpp b/src/cpp/shell.hpp index 0cfd794f..d4c1b5d7 100644 --- a/src/cpp/shell.hpp +++ b/src/cpp/shell.hpp @@ -17,10 +17,13 @@ public: bool mWatchFiles = true; }; +///! Root config element class ShellRoot: public Scavenger, virtual public Scavengeable { Q_OBJECT; + /// If `config.watchFiles` is true the configuration will be reloaded whenever it changes. + /// Defaults to true. Q_PROPERTY(ShellConfig config READ config WRITE setConfig); - Q_PROPERTY(QQmlListProperty components READ components FINAL); + Q_PROPERTY(QQmlListProperty components READ components); Q_CLASSINFO("DefaultProperty", "components"); QML_ELEMENT; diff --git a/src/cpp/variants.hpp b/src/cpp/variants.hpp index 6f87f0bd..9526538b 100644 --- a/src/cpp/variants.hpp +++ b/src/cpp/variants.hpp @@ -21,10 +21,20 @@ public: QList> values; }; +///! Creates instances of a component based on a given set of variants. +/// Creates and destroys instances of the given component when the given property changes. +/// +/// See [QuickShell.screens] for an example of using `Variants` to create copies of a window per +/// screen. +/// +/// [QuickShell.screens]: ../quickshell#prop.screens class Variants: public Scavenger, virtual public Scavengeable { Q_OBJECT; + /// The component to create instances of Q_PROPERTY(QQmlComponent* component MEMBER mComponent); - Q_PROPERTY(QVariantList variants MEMBER mVariants WRITE setVariants); + /// The list of sets of properties to create instances with. + /// Each set creates an instance of the component, which are updated when the input sets update. + Q_PROPERTY(QList variants MEMBER mVariants WRITE setVariants); Q_CLASSINFO("DefaultProperty", "component"); QML_ELEMENT;