diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-14 10:48:29 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-14 10:48:29 +0200 |
| commit | d7345a83052b6389fd28db5f0564021537d8e025 (patch) | |
| tree | 2463be1883c48d59f7bfad37c14f4bf277649507 /docs/superpowers/plans/2026-09-14-desktop-shell.md | |
| parent | 17f664386994e6da3b8fe2d97f7c664cf26fe300 (diff) | |
| download | quickshell-d7345a83052b6389fd28db5f0564021537d8e025.tar.gz quickshell-d7345a83052b6389fd28db5f0564021537d8e025.zip | |
docs: a subdirectory singleton needs no qmldir, drop it from the plan
The plan claimed a pragma Singleton outside the config root is invisible
until a qmldir names it, and had Task 1 create one plus Tasks 6, 7 and 8
append a line each. That premise was wrong.
Tested: a pragma Singleton in modules/sub/, reached by a plain
import "modules/sub", resolves with no qmldir anywhere. The control was a
reference to a genuinely undefined type, which warns "ReferenceError:
<name> is not defined"; the singleton case produced no such warning and
the binding evaluated. This matches what AGENTS.md already documented
about Theme.qml, which the code review pointed out.
Four registration steps removed and the remaining steps renumbered. The
AGENTS.md note Task 9 adds now records the tested behaviour rather than
the invented one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01We9zcHEH8ZWHPcQwMaJRNv
Diffstat (limited to 'docs/superpowers/plans/2026-09-14-desktop-shell.md')
| -rw-r--r-- | docs/superpowers/plans/2026-09-14-desktop-shell.md | 125 |
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." ``` --- |
