Compare commits

..

1 commit

Author SHA1 Message Date
cacfcea559
set up caddy redirects 2025-06-07 05:23:45 -07:00
4 changed files with 193 additions and 177 deletions

5
redirects.caddy Normal file
View file

@ -0,0 +1,5 @@
redir /docs/configuration/getting-started /docs/guide/install-setup permanent
redir /docs/configuration/intro /docs/guide/introduction permanent
redir /docs/configuration/positioning /docs/guide/size-position permanent
redir /docs/configuration/qml-overview /docs/guide/qml-language permanent
redir /docs/configuration /docs/guide permanent

View file

@ -1,5 +0,0 @@
redir /docs/configuration/getting-started* /docs/guide/install-setup permanent
redir /docs/configuration/intro* /docs/guide/introduction permanent
redir /docs/configuration/positioning* /docs/guide/size-position permanent
redir /docs/configuration/qml-overview* /docs/guide/qml-language permanent
redir /docs/configuration* /docs/guide permanent

View file

@ -32,7 +32,7 @@ const remarkParseAtTypes: RemarkPlugin<[]> = () => {
const node = rawNode as Md.Literal;
node.value = node.value.replace(
/@@((?<module>([A-Z]\w*\.)*)(?<type>([A-Z]\w*))(\.(?!\s|$))?)?((?<member>[a-z]\w*)((?<function>\(\))|(?<signal>\(s\)))?)?(?=[$.,;:)\s]|$)/g,
/@@((?<module>([A-Z]\w*\.)*)(?<type>([A-Z]\w*))\.?)?((?<member>[a-z]\w*)((?<function>\(\))|(?<signal>\(s\)))?)?(?=[$.,;:)\s]|$)/g,
(_full, ...args) => {
type Capture = {
module: string | undefined;

View file

@ -3,27 +3,41 @@ title: "Introduction"
index: 2
---
import Collapsible from "@components/Collapsible.astro";
# {frontmatter.title}
> [!NOTE]
> This guide was created a long time ago, and is somewhat outdated.
> Take a look at @@Quickshell.SystemClock after going through.
This page will walk you through the process of creating a simple bar/panel, and
introduce you to all the basic concepts involved. You can use the
[QML Language Reference](/docs/guide/qml-language) to learn about the syntax
of the QML language.
introduce you to all the basic concepts involved.
Note that all the <a>Green Links</a> in code blocks will take you to the documentation
for their respective types.
There are many links to the [QML Overview](/docs/guide/qml-language)
and [Type Reference](/docs/types) which you should follow if you don't
fully understand the concepts involved.
## Config Files
Quickshell searches the `quickshell` subfolder of every XDG standard config path
for configs. Usually this is `~/.config/quickshell`.
## Shell Files
Each named subfolder containing a `shell.qml` file is considered to be a config.
If the base `quickshell` folder contains a shell.qml file, subfolders will not be
considered.
Every quickshell instance starts from a shell root file, conventionally named `shell.qml`.
The default path is `~/.config/quickshell/shell.qml`.
(where `~/.config` can be substituted with `$XDG_CONFIG_HOME` if present.)
A specific config can be picked using the `--config` or `-c` argument to Quickshell.
Each shell file starts with the shell root object. Only one may exist per configuration.
Configs at other paths, including raw qml files can be run with `--path` or `-p`.
```qml
// ~/.config/quickshell/shell.qml
import Quickshell
@@Quickshell.ShellRoot {
// ...
}
```
The shell root is not a visual element but instead contains all of the visual
and non visual objects in your shell. You can have multiple different shells
with shared components and different shell roots.
## Creating Windows
@ -34,23 +48,25 @@ Quickshell has two main window types available,
We'll start with an example:
```qml
import Quickshell // for PanelWindow
import Quickshell // for ShellRoot and PanelWindow
import QtQuick // for Text
@@Quickshell.PanelWindow {
anchors {
top: true
left: true
right: true
}
@@Quickshell.ShellRoot {
@@Quickshell.PanelWindow {
anchors {
top: true
left: true
right: true
}
implicitHeight: 30
implicitHeight: 30
@@QtQuick.Text {
// center the bar in its parent component (the window)
anchors.centerIn: parent
@@QtQuick.Text {
// center the bar in its parent component (the window)
anchors.centerIn: parent
text: "hello world"
text: "hello world"
}
}
}
```
@ -58,16 +74,13 @@ import QtQuick // for Text
The above example creates a bar/panel on your currently focused monitor with
a centered piece of [text](https://doc.qt.io/qt-6/qml-qtquick-text.html). It will also reserve space for itself on your monitor.
More information about available properties is available in the [type reference](/docs/types/Quickshell/PanelWindow).
More information about available properties is available in the [type reference](/docs/types/quickshell/panelwindow).
## Running a process
Now that we have a piece of text, what if it did something useful?
To start with lets make a clock. To get the time we'll use the `date` command.
> [!note/Note]
> Quickshell can do more than just run processes. Read until the end for more information.
We can use a [Process](/docs/types/quickshell.io/process) object to run commands
and return their results.
@ -85,35 +98,37 @@ import Quickshell
import Quickshell.Io // for Process
import QtQuick
@@Quickshell.PanelWindow {
anchors {
top: true
left: true
right: true
}
@@Quickshell.ShellRoot {
@@Quickshell.PanelWindow {
anchors {
top: true
left: true
right: true
}
implicitHeight: 30
implicitHeight: 30
@@QtQuick.Text {
// give the text an ID we can refer to elsewhere in the file
id: clock
@@QtQuick.Text {
// give the text an ID we can refer to elsewhere in the file
id: clock
anchors.centerIn: parent
anchors.centerIn: parent
// create a process management object
@@Quickshell.Io.Process {
// the command it will run, every argument is its own string
command: ["date"]
// create a process management object
@@Quickshell.Io.Process {
// the command it will run, every argument is its own string
command: ["date"]
// run the command immediately
running: true
// run the command immediately
running: true
// process the stdout stream using a SplitParser
// which returns chunks of output after a delimiter
stdout: @@Quickshell.Io.SplitParser {
// listen for the read signal, which returns the data that was read
// from stdout, then write that data to the clock's text property
onRead: data => clock.text = data
// process the stdout stream using a SplitParser
// which returns chunks of output after a delimiter
stdout: @@Quickshell.Io.SplitParser {
// listen for the read signal, which returns the data that was read
// from stdout, then write that data to the clock's text property
onRead: data => clock.text = data
}
}
}
}
@ -130,46 +145,48 @@ import Quickshell
import Quickshell.Io
import QtQuick
@@Quickshell.PanelWindow {
anchors {
top: true
left: true
right: true
}
implicitHeight: 30
@@QtQuick.Text {
id: clock
anchors.centerIn: parent
@@Quickshell.Io.Process {
// give the process object an id so we can talk
// about it from the timer
id: dateProc
command: ["date"]
running: true
stdout: @@Quickshell.Io.SplitParser {
onRead: data => clock.text = data
}
@@Quickshell.ShellRoot {
@@Quickshell.PanelWindow {
anchors {
top: true
left: true
right: true
}
// use a timer to rerun the process at an interval
@@QtQml.Timer {
// 1000 milliseconds is 1 second
interval: 1000
implicitHeight: 30
// start the timer immediately
running: true
@@QtQuick.Text {
id: clock
anchors.centerIn: parent
// run the timer again when it ends
repeat: true
@@Quickshell.Io.Process {
// give the process object an id so we can talk
// about it from the timer
id: dateProc
// when the timer is triggered, set the running property of the
// process to true, which reruns it if stopped.
onTriggered: dateProc.running = true
command: ["date"]
running: true
stdout: @@Quickshell.Io.SplitParser {
onRead: data => clock.text = data
}
}
// use a timer to rerun the process at an interval
@@QtQml.Timer {
// 1000 milliseconds is 1 second
interval: 1000
// start the timer immediately
running: true
// run the timer again when it ends
repeat: true
// when the timer is triggered, set the running property of the
// process to true, which reruns it if stopped.
onTriggered: dateProc.running = true
}
}
}
}
@ -200,45 +217,47 @@ import Quickshell
import Quickshell.Io
import QtQuick
@@Quickshell.Variants {
model: Quickshell.screens;
@@Quickshell.ShellRoot {
@@Quickshell.Variants {
model: Quickshell.screens;
delegate: @@QtQml.Component {
@@Quickshell.PanelWindow {
// the screen from the screens list will be injected into this
// property
property var modelData
delegate: @@QtQml.Component {
@@Quickshell.PanelWindow {
// the screen from the screens list will be injected into this
// property
property var modelData
// we can then set the window's screen to the injected property
screen: modelData
// we can then set the window's screen to the injected property
screen: modelData
anchors {
top: true
left: true
right: true
}
implicitHeight: 30
@@QtQuick.Text {
id: clock
anchors.centerIn: parent
@@Quickshell.Io.Process {
id: dateProc
command: ["date"]
running: true
stdout: @@Quickshell.Io.SplitParser {
onRead: data => clock.text = data
}
anchors {
top: true
left: true
right: true
}
@@QtQml.Timer {
interval: 1000
running: true
repeat: true
onTriggered: dateProc.running = true
implicitHeight: 30
@@QtQuick.Text {
id: clock
anchors.centerIn: parent
@@Quickshell.Io.Process {
id: dateProc
command: ["date"]
running: true
stdout: @@Quickshell.Io.SplitParser {
onRead: data => clock.text = data
}
}
@@QtQml.Timer {
interval: 1000
running: true
repeat: true
onTriggered: dateProc.running = true
}
}
}
}
@ -257,9 +276,8 @@ due to the reactive nature of the
(See: [Reactive Bindings](/docs/configuration/qml-overview/#reactive-bindings).)
Now there's an important problem you might have noticed: when the window
is created multiple times we also make a new Process and Timer, which makes the
bar less efficient than it could be. We can fix this by moving the
Process and Timer outside of the window using @@Quickshell.Scope.
is created multiple times we also make a new Process and Timer. We can fix
this by moving the Process and Timer outside of the window.
> [!caution/Error]
> This code will not work correctly.
@ -269,7 +287,7 @@ import Quickshell
import Quickshell.Io
import QtQuick
@@Quickshell.Scope {
@@Quickshell.ShellRoot {
@@Quickshell.Variants {
model: Quickshell.screens
@ -320,11 +338,11 @@ _What about the `clock` that the process references?_
If you run the above example you'll see something like this in the console every second:
```
WARN scene: **/shell.qml[36:-1]: ReferenceError: clock is not defined
WARN scene: **/shell.qml[36:-1]: ReferenceError: clock is not defined
WARN scene: **/shell.qml[36:-1]: ReferenceError: clock is not defined
WARN scene: **/shell.qml[36:-1]: ReferenceError: clock is not defined
WARN scene: **/shell.qml[36:-1]: ReferenceError: clock is not defined
file:///home/name/.config/quickshell/shell.qml:33: ReferenceError: clock is not defined
file:///home/name/.config/quickshell/shell.qml:33: ReferenceError: clock is not defined
file:///home/name/.config/quickshell/shell.qml:33: ReferenceError: clock is not defined
file:///home/name/.config/quickshell/shell.qml:33: ReferenceError: clock is not defined
file:///home/name/.config/quickshell/shell.qml:33: ReferenceError: clock is not defined
```
This is because the `clock` object, even though it has an ID, cannot be referenced
@ -344,11 +362,11 @@ import Quickshell
import Quickshell.Io
import QtQuick
@@Quickshell.Scope {
@@Quickshell.ShellRoot {
id: root
// add a property in the root
property string time
property string time;
@@Quickshell.Variants {
model: Quickshell.screens
@ -371,7 +389,7 @@ import QtQuick
anchors.centerIn: parent
// bind the text to the root object's time property
// bind the text to the root's time property
text: root.time
}
}
@ -409,6 +427,9 @@ above code, but we can make it more concise:
which means we can skip the `delegate:` part of the assignment.
We're already using the default property of @@Quickshell.ShellRoot to store our
Variants, Process, and Timer components among other things.
3. The ShellRoot doesn't actually need an `id` property to talk about
the time property, as it is the outermost object in the file which
has [special scoping rules](/docs/configuration/qml-overview/#property-access-scopes).
This is what our shell looks like with the above (optional) cleanup:
@ -417,9 +438,8 @@ import Quickshell
import Quickshell.Io
import QtQuick
@@Quickshell.Scope {
id: root
property string time
@@Quickshell.ShellRoot {
property string time;
@@Quickshell.Variants {
model: Quickshell.screens
@ -438,7 +458,9 @@ import QtQuick
@@QtQuick.Text {
anchors.centerIn: parent
text: root.time
// now just time instead of root.time
text: time
}
}
}
@ -449,7 +471,8 @@ import QtQuick
running: true
stdout: @@Quickshell.Io.SplitParser {
onRead: data => root.time = data
// now just time instead of root.time
onRead: data => time = data
}
}
@ -473,7 +496,7 @@ To start with, let's move the entire bar into a new file.
// shell.qml
import Quickshell
@@Quickshell.Scope {
@@Quickshell.ShellRoot {
Bar {}
}
```
@ -485,8 +508,7 @@ import Quickshell.Io
import QtQuick
@@Quickshell.Scope {
id: root
property string time
property string time;
@@Quickshell.Variants {
model: Quickshell.screens
@ -505,7 +527,9 @@ import QtQuick
@@QtQuick.Text {
anchors.centerIn: parent
text: root.time
// now just time instead of root.time
text: time
}
}
}
@ -516,7 +540,8 @@ import QtQuick
running: true
stdout: @@Quickshell.Io.SplitParser {
onRead: data => root.time = data
// now just time instead of root.time
onRead: data => time = data
}
}
@ -564,7 +589,7 @@ import QtQuick
@@Quickshell.Scope {
id: root
property string time
property string time;
@@Quickshell.Variants {
model: Quickshell.screens
@ -584,6 +609,7 @@ import QtQuick
// the ClockWidget type we just created
ClockWidget {
anchors.centerIn: parent
// Warning: setting `time: time` will bind time to itself which is not what we want
time: root.time
}
}
@ -595,7 +621,7 @@ import QtQuick
running: true
stdout: @@Quickshell.Io.SplitParser {
onRead: data => root.time = data
onRead: data => time = data
}
}
@ -620,8 +646,7 @@ import Quickshell.Io
import QtQuick
@@Quickshell.Scope {
id: root
property string time
property string time;
@@Quickshell.Io.Process {
id: dateProc
@ -629,7 +654,7 @@ import QtQuick
running: true
stdout: @@Quickshell.Io.SplitParser {
onRead: data => root.time = data
onRead: data => time = data
}
}
@ -696,7 +721,6 @@ import QtQuick
// your singletons should always have Singleton as the type
@@Quickshell.Singleton {
id: root
property string time
@@Quickshell.Io.Process {
@ -705,7 +729,7 @@ import QtQuick
running: true
stdout: @@Quickshell.Io.SplitParser {
onRead: data => root.time = data
onRead: data => time = data
}
}
@ -762,39 +786,31 @@ import Quickshell
}
```
## Quickshell Support Libraries
In addition to calling external processes, Quickshell comes with a large set of support libraries
for common OS integrations and tasks. These libraries are indexed on the left sidebar.
## JavaScript APIs
One of these integrations is @@Quickshell.SystemClock, which exposes the system time in an easy to
use way.
In addition to calling external processes, a [limited set of javascript interfaces] is available.
We can use this to improve our clock by using the [Date API] instead of calling `date`.
We can use @@Quickshell.SystemClock.date to get a Date object to display. The
@@QtQml.Qt.formatDateTime() function can be used to easily format the date
as shown below.
@@Quickshell.SystemClock.precision can be set to `Minutes` to improve battery life if you don't
show seconds on your clock, as Quickshell will have less work to do.
[limited set of javascript interfaces]: https://doc.qt.io/qt-6/qtqml-javascript-functionlist.html
[Date API]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
```qml
// Time.qml
pragma Singleton
import Quickshell
import Quickshell.Io
import QtQuick
@@Quickshell.Singleton {
id: root
// an expression can be broken across multiple lines using {}
readonly property string time: {
// The passed format string matches the default output of
// the `date` command.
Qt.formatDateTime(clock.date, "ddd MMM d hh:mm:ss AP t yyyy")
}
property var date: new Date()
property string time: date.toLocaleString(Qt.locale())
@@Quickshell.SystemClock {
id: clock
precision: SystemClock.Seconds
@@QtQml.Timer {
interval: 1000
running: true
repeat: true
onTriggered: date = new Date()
}
}
```