aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers
diff options
context:
space:
mode:
Diffstat (limited to 'docs/superpowers')
-rw-r--r--docs/superpowers/plans/2026-09-14-desktop-shell.md125
1 files changed, 54 insertions, 71 deletions
diff --git a/docs/superpowers/plans/2026-09-14-desktop-shell.md b/docs/superpowers/plans/2026-09-14-desktop-shell.md
index d263b2e..d067b15 100644
--- a/docs/superpowers/plans/2026-09-14-desktop-shell.md
+++ b/docs/superpowers/plans/2026-09-14-desktop-shell.md
@@ -71,7 +71,6 @@ desktop/
VmPage.qml VmPanel's content, rehomed
appearance/
AppearanceModule.qml tile only, activate() calls the external shell
- qmldir singleton registrations
```
Deleted when their contents have moved: `volume-osd/`, `mail-overview/`,
@@ -80,11 +79,20 @@ Deleted when their contents have moved: `volume-osd/`, `mail-overview/`,
### A note on singletons
`Player.qml`, `Accounts.qml`, `Virsh.qml` and `Theme.qml` are all
-`pragma Singleton`. In the existing components they work because each is in the
-component's root directory, which quickshell scans. Moving them into
-`modules/<name>/` subdirectories means they are no longer in the root, so they
-need a `qmldir` registering them. Task 1 creates it, and every later task that
-moves a singleton adds its line.
+`pragma Singleton`, and all three of the first group move into
+`modules/<name>/` subdirectories.
+
+**They need no `qmldir`.** An earlier draft of this plan claimed a singleton
+outside the config root is invisible until a `qmldir` names it. That was
+wrong, and it was tested: a `pragma Singleton` in `modules/sub/`, reached by a
+plain `import "modules/sub"`, resolves with no `qmldir` anywhere. The control
+for that test was a reference to a genuinely undefined type, which produces a
+visible `ReferenceError: <name> is not defined` warning; the singleton case
+produced no such warning and the binding evaluated.
+
+So each module directory gets a plain directory import and nothing else. This
+matches what AGENTS.md already says about `Theme.qml`: quickshell follows the
+symlink and resolves the singleton with no qmldir and no consumer change.
---
@@ -92,7 +100,6 @@ moves a singleton adds its line.
**Files:**
- Create: `desktop/shell.qml`
-- Create: `desktop/qmldir`
- Create: `desktop/Theme.qml` (symlink)
- [ ] **Step 1: Create the directory and the Theme symlink**
@@ -109,15 +116,7 @@ ls -l desktop/Theme.qml
Expected: `desktop/Theme.qml -> ../shared/Theme.qml`
-- [ ] **Step 2: Write the qmldir**
-
-`desktop/qmldir`:
-
-```
-singleton Theme 1.0 Theme.qml
-```
-
-- [ ] **Step 3: Write a shell that only holds itself open**
+- [ ] **Step 2: Write a shell that only holds itself open**
`desktop/shell.qml`:
@@ -153,7 +152,7 @@ ShellRoot {
}
```
-- [ ] **Step 4: Verify it loads and stays up**
+- [ ] **Step 3: Verify it loads and stays up**
Run it in the foreground under a timeout, so the harness owns the process:
@@ -165,7 +164,7 @@ Expected: a line containing `Configuration Loaded`, no `QML` errors, and the
command ending only when the timeout fires (exit 124). If it returns
immediately with no error, the keepalive window is missing or malformed.
-- [ ] **Step 5: Commit**
+- [ ] **Step 4: Commit**
```bash
git add desktop/
@@ -875,7 +874,6 @@ the page.
- Create: `desktop/modules/sound/SoundPage.qml`
- Move: `volume-osd/Player.qml` -> `desktop/modules/sound/Player.qml`
- Move: `volume-osd/TransportButton.qml` -> `desktop/modules/sound/TransportButton.qml`
-- Modify: `desktop/qmldir`
- [ ] **Step 1: Move the two files that need no change**
@@ -884,16 +882,10 @@ git mv volume-osd/Player.qml desktop/modules/sound/Player.qml
git mv volume-osd/TransportButton.qml desktop/modules/sound/TransportButton.qml
```
-- [ ] **Step 2: Register Player as a singleton**
-
-`Player.qml` is `pragma Singleton` and is no longer in the config root, so it
-needs a qmldir entry. Append to `desktop/qmldir`:
+`Player.qml` is `pragma Singleton` and needs no registration: the directory
+import in the shell resolves it. See "A note on singletons" above.
-```
-singleton Player 1.0 modules/sound/Player.qml
-```
-
-- [ ] **Step 3: Write the service**
+- [ ] **Step 2: Write the service**
The PipeWire half of the old `VolumeOsd.qml`, with the two traps preserved
verbatim in comment and code.
@@ -978,7 +970,7 @@ Scope {
}
```
-- [ ] **Step 4: Write the OSD**
+- [ ] **Step 3: Write the OSD**
The window half, keeping its namespace so the existing Hyprland blur rule needs
no edit. The body is the old `VolumeOsd.qml` from its first `PanelWindow`
@@ -1248,7 +1240,7 @@ document. When moving the file, take the glyph bytes from the original
`volume-osd/VolumeOsd.qml` rather than retyping them, and check
`git diff` shows no change to those literals.
-- [ ] **Step 5: Write the tile content and the page**
+- [ ] **Step 4: Write the tile content and the page**
`desktop/modules/sound/SoundTile.qml`:
@@ -1425,7 +1417,7 @@ Column {
}
```
-- [ ] **Step 6: Write the module**
+- [ ] **Step 5: Write the module**
`desktop/modules/sound/SoundModule.qml`:
@@ -1471,7 +1463,7 @@ Module {
}
```
-- [ ] **Step 7: Register it and delete the old component**
+- [ ] **Step 6: Register it and delete the old component**
In `desktop/shell.qml`, add `import "modules/sound"` and put `SoundModule {}`
first in the `modules` list, before `AppearanceModule {}`.
@@ -1484,7 +1476,7 @@ git mv volume-osd/README.md desktop/modules/sound/README.md
rmdir volume-osd
```
-- [ ] **Step 8: Verify the OSD still works and the page renders**
+- [ ] **Step 7: Verify the OSD still works and the page renders**
```bash
pkill -x qs
@@ -1517,10 +1509,10 @@ qs -p window-switcher &
Note these are detached and will not survive the tool call; they are for the
user's session, so have the user start them, or leave them for the next login.
-- [ ] **Step 9: Commit**
+- [ ] **Step 8: Commit**
```bash
-git add -A desktop/modules/sound volume-osd desktop/shell.qml desktop/qmldir
+git add -A desktop/modules/sound volume-osd desktop/shell.qml
git commit -m "feat(desktop): move volume-osd in as the sound module
VolumeOsd.qml did three jobs in one file: PipeWire tracking, the OSD
@@ -1544,7 +1536,6 @@ the page, and the three scripts move with it.
- Create: `desktop/modules/mail/MailModule.qml`
- Create: `desktop/modules/mail/MailTile.qml`
- Create: `desktop/modules/mail/MailPage.qml`
-- Modify: `desktop/qmldir`
- [ ] **Step 1: Move the files that need no change**
@@ -1559,15 +1550,10 @@ git mv mail-overview/waybar-mail.sh desktop/modules/mail/waybar-mail.sh
git mv mail-overview/test-mail-notify.sh desktop/modules/mail/test-mail-notify.sh
```
-- [ ] **Step 2: Register Accounts as a singleton**
+`Accounts.qml` is `pragma Singleton` and needs no registration: the directory
+import in the shell resolves it. See "A note on singletons" above.
-Append to `desktop/qmldir`:
-
-```
-singleton Accounts 1.0 modules/mail/Accounts.qml
-```
-
-- [ ] **Step 3: Check the scripts for self-referential paths**
+- [ ] **Step 2: Check the scripts for self-referential paths**
The scripts may locate siblings relative to their own directory. Check before
assuming the move is transparent:
@@ -1579,7 +1565,7 @@ grep -n 'dirname\|BASH_SOURCE\|\$0\|mail-overview' desktop/modules/mail/*.sh
If any line hardcodes `mail-overview`, update it to the new path. If they use
`$(dirname "$0")` they are already correct.
-- [ ] **Step 4: Verify the test suite still passes**
+- [ ] **Step 3: Verify the test suite still passes**
This is the only automated oracle in the whole project.
@@ -1590,7 +1576,7 @@ This is the only automated oracle in the whole project.
Expected: `16 passed, 0 failed`. If the count differs, the move broke
something; fix before continuing.
-- [ ] **Step 5: Write the page**
+- [ ] **Step 4: Write the page**
`MailPanel.qml`'s content, with the window chrome dropped and `root.` reads
pointing at the page. The heartbeat `FileView` moves in unchanged, including
@@ -1820,7 +1806,7 @@ Column {
}
```
-- [ ] **Step 6: Write the tile and the module**
+- [ ] **Step 5: Write the tile and the module**
`desktop/modules/mail/MailTile.qml`:
@@ -1890,7 +1876,7 @@ Module {
}
```
-- [ ] **Step 7: Register it and delete the old component**
+- [ ] **Step 6: Register it and delete the old component**
Add `import "modules/mail"` to `desktop/shell.qml` and put `MailModule {}` in
the `modules` list, after sound.
@@ -1901,7 +1887,7 @@ git mv mail-overview/README.md desktop/modules/mail/README.md
rmdir mail-overview
```
-- [ ] **Step 8: Verify**
+- [ ] **Step 7: Verify**
```bash
pkill -x qs
@@ -1920,7 +1906,7 @@ Expected: the test reporting `16 passed, 0 failed`, then
`qs -p desktop ipc call drawer open mail` and confirm the account rows, thread
previews and watcher dot all render as they did in the old drawer.
-- [ ] **Step 9: Commit**
+- [ ] **Step 8: Commit**
```bash
git add -A desktop mail-overview
@@ -1946,7 +1932,7 @@ The largest move. `Virsh.qml` becomes the module's service unchanged;
- Create: `desktop/modules/vm/VmModule.qml`
- Create: `desktop/modules/vm/VmTile.qml`
- Create: `desktop/modules/vm/VmPage.qml`
-- Modify: `desktop/qmldir`, `desktop/shell.qml`
+- Modify: `desktop/shell.qml`
- [ ] **Step 1: Move the two files that need no change**
@@ -1964,15 +1950,10 @@ deleting:
git show HEAD~1:vm-manager/Button.qml | diff - desktop/Button.qml && echo IDENTICAL
```
-- [ ] **Step 2: Register Virsh as a singleton**
+`Virsh.qml` is `pragma Singleton` and needs no registration: the directory
+import in the shell resolves it. See "A note on singletons" above.
-Append to `desktop/qmldir`:
-
-```
-singleton Virsh 1.0 modules/vm/Virsh.qml
-```
-
-- [ ] **Step 3: Write the page**
+- [ ] **Step 2: Write the page**
`VmPanel.qml`'s content with the window chrome dropped. The confirm-step logic,
the per-VM rows and the snapshot list all move unchanged; only the enclosing
@@ -2346,7 +2327,7 @@ Column {
Note the stat row changed from `Row` to `Flow`: four stats at 150px bars do not
fit in a 600px drawer as one row, where they did in the old full-width panel.
-- [ ] **Step 4: Write the tile and the module**
+- [ ] **Step 3: Write the tile and the module**
The tile shows one dot per VM. `Virsh` runs `virsh event --all --loop`
unconditionally and refreshes the list on every lifecycle event, so
@@ -2439,7 +2420,7 @@ Module {
}
```
-- [ ] **Step 5: Keep the failure notification**
+- [ ] **Step 4: Keep the failure notification**
`vm-manager/shell.qml` turned `Virsh.actionFailed` into a `notify-send`. That
belongs in the module now. Add to `VmModule.qml`, inside the `Module` block:
@@ -2463,7 +2444,7 @@ belongs in the module now. Add to `VmModule.qml`, inside the `Module` block:
and add `import Quickshell.Io` at the top of the file.
-- [ ] **Step 6: Register it and delete the old component**
+- [ ] **Step 5: Register it and delete the old component**
Add `import "modules/vm"` to `desktop/shell.qml` and put `VmModule {}` in the
`modules` list, after mail.
@@ -2474,7 +2455,7 @@ git mv vm-manager/README.md desktop/modules/vm/README.md
rmdir vm-manager
```
-- [ ] **Step 7: Verify**
+- [ ] **Step 6: Verify**
```bash
pkill -x qs
@@ -2511,7 +2492,7 @@ file was edited when it should have been moved verbatim.
A VM carrying a managed save shows "Discard saved state" among its actions; if
the user has one, that button appearing is the end-to-end check.
-- [ ] **Step 8: Commit**
+- [ ] **Step 7: Commit**
```bash
git add -A desktop vm-manager
@@ -2627,10 +2608,11 @@ Two sections are now wrong:
Add to the per-component notes, since both cost time to rediscover:
```markdown
-- **A singleton outside the config root needs a `qmldir` entry.** The five
- original components each kept their singletons beside `shell.qml`, where
- quickshell finds them. Moving one into `modules/<name>/` makes it invisible
- until `qmldir` names it.
+- **A `pragma Singleton` in a subdirectory needs no `qmldir`.** A plain
+ directory import resolves it, the same way quickshell resolves the
+ `Theme.qml` symlink. Tested while merging the components: the control was a
+ reference to an undefined type, which warns `ReferenceError: <name> is not
+ defined`, and the singleton case produced no such warning.
- **`Virsh.sampling` gates the 2s stats poll, not the whole service.** The
lifecycle event stream runs unconditionally, which is what keeps the VM list
and the tile's dots current while the page is closed.
@@ -2654,9 +2636,10 @@ git add README.md AGENTS.md desktop/README.md
git commit -m "docs: the desktop shell and what the merge changed
Five components become three, and the Theme symlink count with them. Two
-new notes: a singleton outside the config root is invisible without a
-qmldir entry, and Virsh.sampling gates only the stats poll, not the
-lifecycle stream that keeps the tile correct while the page is closed."
+new notes: a pragma Singleton in a subdirectory resolves through a plain
+directory import with no qmldir, and Virsh.sampling gates only the stats
+poll, not the lifecycle stream that keeps the tile correct while the page
+is closed."
```
---