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; const node = rawNode as Md.Literal;
node.value = node.value.replace( 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) => { (_full, ...args) => {
type Capture = { type Capture = {
module: string | undefined; module: string | undefined;

View file

@ -3,27 +3,41 @@ title: "Introduction"
index: 2 index: 2
--- ---
import Collapsible from "@components/Collapsible.astro";
# {frontmatter.title} # {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 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 introduce you to all the basic concepts involved.
[QML Language Reference](/docs/guide/qml-language) to learn about the syntax
of the QML language.
Note that all the <a>Green Links</a> in code blocks will take you to the documentation There are many links to the [QML Overview](/docs/guide/qml-language)
for their respective types. and [Type Reference](/docs/types) which you should follow if you don't
fully understand the concepts involved.
## Config Files ## Shell Files
Quickshell searches the `quickshell` subfolder of every XDG standard config path
for configs. Usually this is `~/.config/quickshell`.
Each named subfolder containing a `shell.qml` file is considered to be a config. Every quickshell instance starts from a shell root file, conventionally named `shell.qml`.
If the base `quickshell` folder contains a shell.qml file, subfolders will not be The default path is `~/.config/quickshell/shell.qml`.
considered. (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 ## Creating Windows
@ -34,23 +48,25 @@ Quickshell has two main window types available,
We'll start with an example: We'll start with an example:
```qml ```qml
import Quickshell // for PanelWindow import Quickshell // for ShellRoot and PanelWindow
import QtQuick // for Text import QtQuick // for Text
@@Quickshell.PanelWindow { @@Quickshell.ShellRoot {
anchors { @@Quickshell.PanelWindow {
top: true anchors {
left: true top: true
right: true left: true
} right: true
}
implicitHeight: 30 implicitHeight: 30
@@QtQuick.Text { @@QtQuick.Text {
// center the bar in its parent component (the window) // center the bar in its parent component (the window)
anchors.centerIn: parent 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 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. 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 ## Running a process
Now that we have a piece of text, what if it did something useful? 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. 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 We can use a [Process](/docs/types/quickshell.io/process) object to run commands
and return their results. and return their results.
@ -85,35 +98,37 @@ import Quickshell
import Quickshell.Io // for Process import Quickshell.Io // for Process
import QtQuick import QtQuick
@@Quickshell.PanelWindow { @@Quickshell.ShellRoot {
anchors { @@Quickshell.PanelWindow {
top: true anchors {
left: true top: true
right: true left: true
} right: true
}
implicitHeight: 30 implicitHeight: 30
@@QtQuick.Text { @@QtQuick.Text {
// give the text an ID we can refer to elsewhere in the file // give the text an ID we can refer to elsewhere in the file
id: clock id: clock
anchors.centerIn: parent anchors.centerIn: parent
// create a process management object // create a process management object
@@Quickshell.Io.Process { @@Quickshell.Io.Process {
// the command it will run, every argument is its own string // the command it will run, every argument is its own string
command: ["date"] command: ["date"]
// run the command immediately // run the command immediately
running: true running: true
// process the stdout stream using a SplitParser // process the stdout stream using a SplitParser
// which returns chunks of output after a delimiter // which returns chunks of output after a delimiter
stdout: @@Quickshell.Io.SplitParser { stdout: @@Quickshell.Io.SplitParser {
// listen for the read signal, which returns the data that was read // listen for the read signal, which returns the data that was read
// from stdout, then write that data to the clock's text property // from stdout, then write that data to the clock's text property
onRead: data => clock.text = data onRead: data => clock.text = data
}
} }
} }
} }
@ -130,46 +145,48 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import QtQuick import QtQuick
@@Quickshell.PanelWindow { @@Quickshell.ShellRoot {
anchors { @@Quickshell.PanelWindow {
top: true anchors {
left: true top: true
right: 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
}
} }
// use a timer to rerun the process at an interval implicitHeight: 30
@@QtQml.Timer {
// 1000 milliseconds is 1 second
interval: 1000
// start the timer immediately @@QtQuick.Text {
running: true id: clock
anchors.centerIn: parent
// run the timer again when it ends @@Quickshell.Io.Process {
repeat: true // 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 command: ["date"]
// process to true, which reruns it if stopped. running: true
onTriggered: dateProc.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 Quickshell.Io
import QtQuick import QtQuick
@@Quickshell.Variants { @@Quickshell.ShellRoot {
model: Quickshell.screens; @@Quickshell.Variants {
model: Quickshell.screens;
delegate: @@QtQml.Component { delegate: @@QtQml.Component {
@@Quickshell.PanelWindow { @@Quickshell.PanelWindow {
// the screen from the screens list will be injected into this // the screen from the screens list will be injected into this
// property // property
property var modelData property var modelData
// we can then set the window's screen to the injected property // we can then set the window's screen to the injected property
screen: modelData screen: modelData
anchors { anchors {
top: true top: true
left: true left: true
right: 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
}
} }
@@QtQml.Timer { implicitHeight: 30
interval: 1000
running: true @@QtQuick.Text {
repeat: true id: clock
onTriggered: dateProc.running = true 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).) (See: [Reactive Bindings](/docs/configuration/qml-overview/#reactive-bindings).)
Now there's an important problem you might have noticed: when the window 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 is created multiple times we also make a new Process and Timer. We can fix
bar less efficient than it could be. We can fix this by moving the this by moving the Process and Timer outside of the window.
Process and Timer outside of the window using @@Quickshell.Scope.
> [!caution/Error] > [!caution/Error]
> This code will not work correctly. > This code will not work correctly.
@ -269,7 +287,7 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import QtQuick import QtQuick
@@Quickshell.Scope { @@Quickshell.ShellRoot {
@@Quickshell.Variants { @@Quickshell.Variants {
model: Quickshell.screens 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: 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 file:///home/name/.config/quickshell/shell.qml:33: 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
WARN scene: **/shell.qml[36:-1]: ReferenceError: clock is not defined file:///home/name/.config/quickshell/shell.qml:33: 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
WARN scene: **/shell.qml[36:-1]: 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 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 Quickshell.Io
import QtQuick import QtQuick
@@Quickshell.Scope { @@Quickshell.ShellRoot {
id: root id: root
// add a property in the root // add a property in the root
property string time property string time;
@@Quickshell.Variants { @@Quickshell.Variants {
model: Quickshell.screens model: Quickshell.screens
@ -371,7 +389,7 @@ import QtQuick
anchors.centerIn: parent 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 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. which means we can skip the `delegate:` part of the assignment.
We're already using the default property of @@Quickshell.ShellRoot to store our We're already using the default property of @@Quickshell.ShellRoot to store our
Variants, Process, and Timer components among other things. 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: This is what our shell looks like with the above (optional) cleanup:
@ -417,9 +438,8 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import QtQuick import QtQuick
@@Quickshell.Scope { @@Quickshell.ShellRoot {
id: root property string time;
property string time
@@Quickshell.Variants { @@Quickshell.Variants {
model: Quickshell.screens model: Quickshell.screens
@ -438,7 +458,9 @@ import QtQuick
@@QtQuick.Text { @@QtQuick.Text {
anchors.centerIn: parent anchors.centerIn: parent
text: root.time
// now just time instead of root.time
text: time
} }
} }
} }
@ -449,7 +471,8 @@ import QtQuick
running: true running: true
stdout: @@Quickshell.Io.SplitParser { 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 // shell.qml
import Quickshell import Quickshell
@@Quickshell.Scope { @@Quickshell.ShellRoot {
Bar {} Bar {}
} }
``` ```
@ -485,8 +508,7 @@ import Quickshell.Io
import QtQuick import QtQuick
@@Quickshell.Scope { @@Quickshell.Scope {
id: root property string time;
property string time
@@Quickshell.Variants { @@Quickshell.Variants {
model: Quickshell.screens model: Quickshell.screens
@ -505,7 +527,9 @@ import QtQuick
@@QtQuick.Text { @@QtQuick.Text {
anchors.centerIn: parent anchors.centerIn: parent
text: root.time
// now just time instead of root.time
text: time
} }
} }
} }
@ -516,7 +540,8 @@ import QtQuick
running: true running: true
stdout: @@Quickshell.Io.SplitParser { 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 { @@Quickshell.Scope {
id: root id: root
property string time property string time;
@@Quickshell.Variants { @@Quickshell.Variants {
model: Quickshell.screens model: Quickshell.screens
@ -584,6 +609,7 @@ import QtQuick
// the ClockWidget type we just created // the ClockWidget type we just created
ClockWidget { ClockWidget {
anchors.centerIn: parent anchors.centerIn: parent
// Warning: setting `time: time` will bind time to itself which is not what we want
time: root.time time: root.time
} }
} }
@ -595,7 +621,7 @@ import QtQuick
running: true running: true
stdout: @@Quickshell.Io.SplitParser { stdout: @@Quickshell.Io.SplitParser {
onRead: data => root.time = data onRead: data => time = data
} }
} }
@ -620,8 +646,7 @@ import Quickshell.Io
import QtQuick import QtQuick
@@Quickshell.Scope { @@Quickshell.Scope {
id: root property string time;
property string time
@@Quickshell.Io.Process { @@Quickshell.Io.Process {
id: dateProc id: dateProc
@ -629,7 +654,7 @@ import QtQuick
running: true running: true
stdout: @@Quickshell.Io.SplitParser { 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 // your singletons should always have Singleton as the type
@@Quickshell.Singleton { @@Quickshell.Singleton {
id: root
property string time property string time
@@Quickshell.Io.Process { @@Quickshell.Io.Process {
@ -705,7 +729,7 @@ import QtQuick
running: true running: true
stdout: @@Quickshell.Io.SplitParser { stdout: @@Quickshell.Io.SplitParser {
onRead: data => root.time = data onRead: data => time = data
} }
} }
@ -762,39 +786,31 @@ import Quickshell
} }
``` ```
## Quickshell Support Libraries ## JavaScript APIs
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.
One of these integrations is @@Quickshell.SystemClock, which exposes the system time in an easy to In addition to calling external processes, a [limited set of javascript interfaces] is available.
use way. 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 [limited set of javascript interfaces]: https://doc.qt.io/qt-6/qtqml-javascript-functionlist.html
@@QtQml.Qt.formatDateTime() function can be used to easily format the date [Date API]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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.
```qml ```qml
// Time.qml // Time.qml
pragma Singleton pragma Singleton
import Quickshell import Quickshell
import Quickshell.Io
import QtQuick import QtQuick
@@Quickshell.Singleton { @@Quickshell.Singleton {
id: root property var date: new Date()
// an expression can be broken across multiple lines using {} property string time: date.toLocaleString(Qt.locale())
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")
}
@@Quickshell.SystemClock { @@QtQml.Timer {
id: clock interval: 1000
precision: SystemClock.Seconds running: true
repeat: true
onTriggered: date = new Date()
} }
} }
``` ```