aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/README.md')
-rw-r--r--desktop/README.md133
1 files changed, 133 insertions, 0 deletions
diff --git a/desktop/README.md b/desktop/README.md
new file mode 100644
index 0000000..0350f9a
--- /dev/null
+++ b/desktop/README.md
@@ -0,0 +1,133 @@
+# desktop
+
+One drawer, left of DP-1, hosting the things a desktop lets you adjust.
+Reached from a launcher at the left end of waybar.
+
+The drawer opens as a grid of tiles, and clicking a tile either opens that
+module's page or fires an action. Escape, a click outside, or a module's back
+arrow returns to the grid; Escape again closes the drawer. It takes keyboard
+focus while it is open, so those keys reach it.
+
+## Running it
+
+ qs -p ./desktop
+
+ qs -p ./desktop ipc call drawer toggle # the grid
+ qs -p ./desktop ipc call drawer open mail # straight to a page
+
+`open` always takes a page name, because quickshell 0.3.1 IPC requires every
+declared argument to be present and a defaulted parameter registers as a type
+the IPC layer rejects. The page-less grid entry is therefore the zero-argument
+`toggle`. `ipc call drawer close` closes it.
+
+## The modules
+
+ modules/sound/ output and input volume, the OSD, the player
+ modules/mail/ unread per account, threads, the watcher dot
+ modules/vm/ libvirt state, live stats, snapshots
+ modules/appearance/ a tile that opens the separate appearance shell
+
+Sound, mail and vm each carry their own README. Appearance is a tile onto the
+separate appearance shell, whose README covers the picker it opens.
+
+## Writing a module
+
+A module is a `Module` (from `Module.qml` in this directory) declaring what the
+drawer needs to show it:
+
+- `name`: identifies the module, both for grid ordering and for IPC, where it
+ is the page name `ipc call drawer open <name>` takes.
+- `icon` and `label`: the glyph and the text on the tile.
+- `tileContent`: a `Component` for the short state line under the label, or
+ null for a tile that says nothing beyond its name.
+- `page`: a `Component` for the full-height page behind the tile, or null.
+- `activate()`: what a tile with no page does when clicked.
+- `alwaysActive`: whether the module's background service runs while the
+ drawer is closed, covered below.
+
+A module provides a tile, a page, both, or neither. The drawer does not care
+which: it reads those properties and does the obvious thing. A page is wrapped
+in `Page.qml` for the header and back arrow, and a tile with no page is
+fire-and-forget, so its click calls `activate()` and closes the drawer.
+
+`modules/appearance/AppearanceModule.qml` is the smallest complete example: a
+name, an icon, a label, and an `activate()` that launches the separate
+appearance shell. It has no page and no service. Sound, mail and vm each add a
+service and a page on top of that same shape.
+
+Module files live under `desktop/modules/<name>/` and reference root types
+(`Module`, `Page`, `Button`, `Theme`), so each needs `import "../.."`. A plain
+directory import does not reach the parent. The moved `TransportButton.qml` and
+`Stat.qml` gained that import for the same reason.
+
+## alwaysActive
+
+Sound and mail are `alwaysActive: true`; vm is false. The property governs the
+module's background service, not its page: pages are lazily loaded either way.
+
+Sound's OSD has to answer a volume keypress with no drawer open, which is the
+whole point of it, so its PipeWire service runs for the session. Mail's unread
+count outlives the drawer and its config watcher makes a newly added account
+appear without a restart, so its service runs too. The vm module's 2s stats
+poll exists only to paint a page nobody is looking at, so it starts and stops
+with the page.
+
+That last line is not the whole story for vm: its lifecycle event stream runs
+unconditionally, which is what keeps the VM list and the tile's dots current
+while the page is closed. `alwaysActive` gates the poll, not everything the
+module does.
+
+## Geometry
+
+The panel is 600px wide and full height, on `DP-1`. Waybar runs there and the
+launcher sits at its left end, while conky holds the right side of the screen,
+so the drawer belongs on the left. It falls back to the first screen when
+`DP-1` is not connected, so the drawer is never invisible.
+
+The window uses `ExclusionMode.Normal`, not `Ignore`. Waybar claims an
+exclusive zone at the top of the screen, so respecting it puts the drawer below
+the bar without this code knowing the bar's height, and the bar stays visible
+and clickable while the drawer is open. The whole surface is an overlay so a
+click outside closes it.
+
+The top of the panel is an empty reserved area for the notification engine. It
+is an empty `Item` claiming the space, not a placeholder graphic, so the grid
+below it sits where it will sit once notifications arrive. The bottom is a
+fixed, never-scrolled `Flow` grid: three columns at 180px minimum, wrapping
+and adding rows up to a 3x3 ceiling for the modules that exist.
+
+## Hyprland and waybar
+
+Nothing here is in the repo's control, and the drawer works without it. Two
+pieces of outside configuration belong to it.
+
+Frosting is the compositor's, matched on the namespace this window sets. The
+drawer sets `quickshell-desktop`, so it needs:
+
+ hl.layer_rule({
+ name = "blur-desktop",
+ match = { namespace = "^(quickshell-desktop)$" },
+ blur = true,
+ xray = false,
+ ignore_alpha = 0.1,
+ })
+
+The sound module's OSD owns its own window and keeps its old
+`quickshell-volume-osd` namespace, so the existing `blur-volume-osd` rule still
+matches and stays. Without any of these the surfaces still render, just flat
+translucent.
+
+The waybar launcher is a static `custom` module with no `exec`, so it cannot
+show whether the drawer is open. Its `on-click` runs the zero-argument toggle:
+
+ "on-click": "qs -p ~/Programming/GIT/quickshell/desktop ipc call drawer toggle"
+
+The mail module's waybar count keeps its own `custom` module, whose click
+deep-links to the mail page with `ipc call drawer open mail`. `SUPER+v` reaches
+the vm page the same way, with `ipc call drawer open vm`. The full list of
+edits to the live Hyprland and waybar configuration is Task 10 of the plan in
+`docs/superpowers/plans/2026-09-14-desktop-shell.md`.
+
+## Theme
+
+`Theme.qml` is a symlink to `shared/Theme.qml`, as in every component here.