Compare commits

...

2 commits

13 changed files with 201 additions and 14 deletions

View file

@ -69,6 +69,7 @@ IndentWidth: 2
TabWidth: 2
AllowAllConstructorInitializersOnNextLine: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
CommentPragmas: '.*'
NamespaceIndentation: None
IncludeBlocks: Regroup
IncludeCategories:

11
.editorconfig Normal file
View file

@ -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

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "docs"]
path = docs
url = https://git.outfoxxed.me/outfoxxed/quickshell-docs

1
docs Submodule

@ -0,0 +1 @@
Subproject commit 27b3274027251ebf382e31546ef2b350ae2f7b0e

View file

@ -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

13
src/cpp/module.md Normal file
View file

@ -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

View file

@ -5,6 +5,7 @@
#include <qquickitem.h>
#include <qquickwindow.h>
#include <qtypes.h>
#include <qwindow.h>
ProxyWindowBase::~ProxyWindowBase() {
if (this->window != nullptr) {
@ -25,6 +26,7 @@ void ProxyWindowBase::earlyInit(QObject* old) {
QObject::connect(this->window, &QWindow::visibilityChanged, this, &ProxyWindowBase::visibleChanged);
QObject::connect(this->window, &QWindow::widthChanged, this, &ProxyWindowBase::widthChanged);
QObject::connect(this->window, &QWindow::heightChanged, this, &ProxyWindowBase::heightChanged);
QObject::connect(this->window, &QQuickWindow::colorChanged, this, &ProxyWindowBase::colorChanged);
// clang-format on
}

View file

@ -20,11 +20,30 @@
// 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);
Q_PROPERTY(QColor color READ color WRITE setColor);
/// 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 NOTIFY colorChanged);
Q_PROPERTY(QQmlListProperty<QObject> data READ data);
Q_CLASSINFO("DefaultProperty", "data");
@ -64,6 +83,7 @@ signals:
void visibleChanged(bool visible);
void widthChanged(qint32 width);
void heightChanged(qint32 width);
void colorChanged(QColor color);
private:
static QQmlListProperty<QObject> dataBacker(QQmlListProperty<QObject>* prop);

View file

@ -33,7 +33,8 @@ qsizetype QuickShellGlobal::screensCount(QQmlListProperty<QuickShellScreenInfo>*
return static_cast<QuickShellGlobal*>(prop->object)->mScreens.size(); // NOLINT
}
QuickShellScreenInfo* QuickShellGlobal::screenAt(QQmlListProperty<QuickShellScreenInfo>* prop, qsizetype i) {
QuickShellScreenInfo*
QuickShellGlobal::screenAt(QQmlListProperty<QuickShellScreenInfo>* prop, qsizetype i) {
return static_cast<QuickShellGlobal*>(prop->object)->mScreens.at(i); // NOLINT
}

View file

@ -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<QuickShellScreenInfo> screens READ screens NOTIFY screensChanged);
QML_SINGLETON;
QML_NAMED_ELEMENT(QuickShell);
@ -20,11 +40,47 @@ public:
QQmlListProperty<QuickShellScreenInfo> 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:

View file

@ -8,16 +8,34 @@
#include <qtypes.h>
// 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);

View file

@ -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<QObject> components READ components FINAL);
Q_PROPERTY(QQmlListProperty<QObject> components READ components);
Q_CLASSINFO("DefaultProperty", "components");
QML_ELEMENT;

View file

@ -21,10 +21,20 @@ public:
QList<QPair<K, V>> 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<QVariant> variants MEMBER mVariants WRITE setVariants);
Q_CLASSINFO("DefaultProperty", "component");
QML_ELEMENT;