| Age | Commit message (Collapse) | Author | Files | Lines |
|
One row per mode. Adding a mode is one file in the singleton and one row
here, which is what a registry buys over two separate toggles.
|
|
The module is thin because the singleton owns the modes: it is a tile and
a page over Status, always active so the effects hold whether or not the
drawer has been opened.
Injected as st rather than mod, since a component property named the same
as the enclosing object's id binds to itself and arrives undefined.
|
|
Presentation mode sets DND, asserts a Wayland idle inhibitor and pauses
breaktimer. The effects hang off the mode property rather than the setter,
so a mode set with statusctl while the drawer is closed asserts them too.
DND has two writers once presentation mode exists, so turning presentation
off restores the value DND had before rather than clearing it, or an
afternoon of hand-set DND would vanish when a talk ends. That prior value
lives in the singleton, not in a file: it means nothing once presentation
mode is off, and presentation mode does not survive a reboot.
breaktimer owns its own state file and is driven only through its verbs.
Two writers on that file would race with its daemon loop.
|
|
IdleInhibitor needs a non-null window and this is the only one that lives
for the whole session, so presentation mode attaches to it. Naming it is a
prerequisite for that and changes nothing else.
|
|
statusctl reads and writes the mode files directly rather than going
through the shell, so it works while quickshell is down. Setting a mode
that way records the state without firing its effects; the shell sees the
change through its own watch and reasserts them.
The watch listens on the directory, not the file: an atomic write replaces
the file, so a watch held on the old inode dies with it. Same trap the mail
watcher hit with Xapian, and the reason moved_to is in the event list.
An unknown mode exits non-zero rather than reading as off, so a typo
cannot masquerade as a mode that happens to be disabled.
The watch loop runs inotifywait through process substitution, held open on
fd 3, with the PID captured and trapped on EXIT/TERM/INT. Piped straight
into the while loop, inotifywait would be a pipeline sibling rather than a
child, so a plain kill on statusctl leaves it running, watching a directory
nobody reads anymore. Task 7 wires this CLI into waybar's exec, and waybar
kills and respawns exec children on every reload the same plain way, so
every reload would otherwise leak another watcher for the rest of the
session. Process substitution makes inotifywait a real child whose PID the
trap can hold and kill. A SIGKILL still orphans it, since KILL cannot be
trapped, but nothing in the described path sends one.
A failed rename exits non-zero instead of being swallowed. Reporting
success on a write that did not land would leave the caller and the shell
disagreeing about the mode, with an orphan temp file as the only trace, and
this script is the interface the whole registry is read and written through.
Verified against an unwritable directory: exit 1, no orphan left, prior
value intact.
Reading uses a redirect rather than cat piped into tr, so that an unreadable
file falling back to off is explicit rather than a side effect of a pipeline
discarding cat's exit status.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A7ThHHh5iTYbVfp3rNAkw2
|
|
Modes live as files under XDG_RUNTIME_DIR, one per mode, holding 0 or 1,
with a missing file meaning off. That directory is tmpfs, so a reboot
resets every mode and no cleanup code is needed.
FileView covers both directions: atomicWrites for the write, watchChanges
for the watch, so an external writer repaints the drawer with no polling.
Both are already the documented defaults in 0.3.1 and are set explicitly
anyway, because statusctl watches close_write,moved_to precisely because an
atomic write lands as a rename. A future release flipping either default
would break the watcher with no error, and a declaration is a stronger
guarantee than a default.
The documented behaviour is that a FileView fires its own fileChanged on
setText, so the reparse compares before assigning and a self-write is a
no-op rather than a loop. That has not been observed running yet: nothing
consumes the singleton until the status module exists, so the guard stays
unproven until then.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A7ThHHh5iTYbVfp3rNAkw2
|
|
Neither scan property self-terminates. BlueZ discovery runs until
StartDiscovery is stopped, and the NetworkManager scanner repeats until
disabled; the docs for both say as much and give no timeout or interval
property. The scan button was the only writer of either property, and
closing the drawer destroys the page without touching them, so a scan
started and forgotten kept the radio busy for the rest of the session.
Continuous wifi scanning also costs throughput on the connected link.
Each page gets a Timer bound to the scan property rather than started by
the button. Binding it that way means a manual stop cancels the clock,
and reopening the page on a scan still running from an earlier visit
re-arms a fresh 60s instead of leaving it running forever.
Verified both files parse: the desktop shell hot-reloaded without
dropping its process. The timeout firing at 60s is not verified here,
since it needs a real scan on the radio.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A7ThHHh5iTYbVfp3rNAkw2
|
|
Page.qml gains an icon rendered before the title, and the drawer binds
it to the loaded module's icon so a module whose glyph changes (network
follows the active link) keeps the header in step.
|
|
A second action while one was in flight killed the first process, whose
onExited then fired under the new label and raised a false failure
notification. Actions are now queued and launched on exit, so each exit
reports under its own label. Also correct two comments that contradicted
the code: the pairing banner is only noticed on the on-open poll, and the
laptop glyph keys off the daemon's desktop type.
|
|
The tile, page and row each took a required property named mod while the
module object's id is also mod. In a Component scope the id resolves to
the property's own unset self, so every page.mod read was undefined and
the device list never rendered. Only a runtime TypeError showed it; the
smoke check was clean because the drawer was closed.
kc matches the net and bt convention and cannot collide with the id.
|
|
No D-Bus module means shell-outs and no push; the daemon and the
indicator are separate; the battery plugin is not on every device; and
qdbus reads properties and methods through one call shape.
|
|
Records that the phone-to-PC clipboard is the daemon's plugin and not the
indicator's, so removing the indicator does not break it, and that polling
stops when the drawer closes.
|
|
A QtQuick.Dialogs FileDialog held on the module, not the page, so a
closed drawer does not destroy it mid-pick. The path is decoded from the
file:// URL before it reaches kdeconnect-cli.
|
|
Outgoing pair and unpair go through kdeconnect-cli; accepting and
rejecting an incoming request go straight to the daemon, since the CLI
has no verb for them. The verification key is shown on the row while a
pairing is in flight so the two ends can be compared.
An incoming request is not noticed while the drawer is closed, because
the poll only runs when it is open; the daemon keeps the request, so it
is there on the next open.
|
|
Ring, clipboard, mount and unpair, all shell-outs since there is no D-Bus
module. Actions share one serialized Process and a failure notifies, for
the case where the drawer has closed by the time the command returns.
Mount runs --mount and then --get-mount-point in one shell, because
--mount prints nothing and the path is a second call.
|
|
State is polled from kdeconnect-state.sh because there is no D-Bus module
to subscribe with. The poll runs only while the drawer is open: the tile
is created when the panel loads and destroyed when it unloads, and it
flips the module's polling flag.
The laptop reports no battery plugin, so an absent charge is an empty
field and renders as nothing, never as a zero.
|
|
Quickshell 0.3.1 has no generic D-Bus module, so device state comes from
qdbus6 shell-outs. The script emits a tab line protocol for the QML side
and is checked by a stub-daemon test, since the live daemon is not an
oracle an agent can rely on.
A failed daemon query exits non-zero with no output so the module keeps
its last list, which is not the same as a valid empty device list.
|
|
|
|
|
|
Glyphs are Nerd Font private-use codepoints, and relying on per-codepoint fontconfig fallback from Noto Sans let the same codepoint resolve to a different glyph in a different Nerd Font.
A Theme.iconFamily now names the render family once, and every glyph Text uses it, while fontFamily stays Noto Sans for words and labels. The ethernet glyph moves from \uf6ff to \uef44, the fa-ethernet codepoint present in Inconsolata.
|
|
|
|
|
|
|
|
The native backends start empty for about two seconds, device lists are
ObjectModels, NMSettings is not in QML scope, and quickshell has no BlueZ
agent. Each one cost a probe to learn; writing them down is cheaper than
re-learning them.
|
|
|
|
Quickshell has no BlueZ agent and no generic D-Bus module, so a pairing
that needs a passkey confirmed cannot be done from QML. bluetoothctl
registers its own agent, so pairing is the one shell-out; adapter state,
scanning, connecting and forgetting all stay native.
The timeout is the ceiling: a device bluetoothctl cannot auto-confirm
fails visibly rather than hanging the page.
|
|
|
|
Native Quickshell.Bluetooth for adapter power, discoverable, scan,
connect, disconnect, trust and forget. Pairing is separate, because
quickshell ships no BlueZ agent.
The adapter is null for the first ~2s, so every access is navigated
safely rather than assuming a first paint.
|
|
|
|
|
|
Radio switch, scan, and a list ordered connected, known, strongest. A
secured unknown network reveals an inline password field rather than
opening a popup, since a QtQuick.Controls popup is a separate window that
positions badly on this layer surface, the same reason the sound page
expands in place.
Connection failures come through the Network.connectionFailed signal and
show inline; the same failure also notifies, for the case where the
drawer has closed by the time it lands.
|
|
Wired first because it is the simpler half and proves the module wiring.
Native Quickshell.Networking, no polling: the singletons push, and
alwaysActive is true with no Service.qml because there is nothing to gate.
The tile shows one line per active link rather than picking a primary,
since the API exposes no route metric and guessing wrong would be worse
than showing both.
|
|
The sound page showed the default sink and source but gave no way to
choose another device and the meter was inert. Each section now lists
the real audio devices, streams and monitor nodes filtered out, behind
an in-place dropdown that sets Pipewire.preferredDefaultAudioSink or
preferredDefaultAudioSource. The meter takes the wheel, click and drag,
and the state glyph beside the percentage toggles mute.
The list expands in place rather than in a popup because a
QtQuick.Controls popup is a separate window and does not position
reliably on a layer surface. The meter accepts the wheel and prevents
stealing so the page's ScrollView neither scrolls nor flicks instead.
|
|
|
|
The README claimed a click outside returns to the grid; it closes the
drawer, and only Escape-with-a-page or the back arrow return to the grid.
The three moved module READMEs' run and IPC commands still named the
deleted volume-osd, mail-overview and vm-manager paths, so point them at
qs -p desktop and ipc call drawer open sound|mail|vm.
|
|
Five components become three, and the Theme symlink count with them. Two
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.
|
|
Virsh.qml is unchanged; VmPanel's body becomes the page and the stat row
becomes a Flow, because four stats with 150px bars do not fit a 600px
drawer as one row. The page starts and stops Virsh.sampling, so the 2s
poll runs only while something is looking at it; the lifecycle event
stream still runs always, which is what keeps the tile's dots current.
|
|
The singleton was referenced only inside lazy Components, so its
qtmaildir.conf watcher and unread-count refresh did not start until the
drawer first opened, contradicting alwaysActive and the old MailPanel,
which shell.qml instantiated directly. Naming Accounts at the Module top
level creates it at shell load; the page keeps its own refresh on open.
|
|
Accounts.qml is unchanged and MailPanel's body becomes the page. The
three scripts move with it, which changes the absolute paths in autostart
and in the waybar module; both are outside this repo and listed in the
plan's final task. Button.qml, byte-identical here and in vm-manager,
lands at the shell root as the single copy.
|
|
VolumeOsd.qml did three jobs in one file: PipeWire tracking, the OSD
surface and the player transport. They become Service, Osd and the page.
The OSD keeps its namespace so the existing Hyprland blur rule still
matches, and the service stays always-active because the OSD has to
answer a keypress with no drawer open.
|
|
A tile with no page: appearance stays its own process because a wallpaper
picker needs more room than a 600px drawer, so the tile only fires its
existing IPC. This is the case the contract's activate() exists for.
|
|
The page Loader is anchored to its parent, so the x binding on it was
overridden and the slide never rendered. Drive the motion with a
Translate transform instead, which the anchors do not touch. Opacity
and the back-arrow wiring are unchanged.
|
|
Left of DP-1 because conky holds the right; ExclusionMode.Normal so the
bar the drawer is reached from stays visible and clickable. The top is an
empty Item claiming the space the notification engine will fill, so the
grid already sits where it will sit once that lands.
|
|
The page body scrolls because mail with several accounts and vm with
several VMs both exceed the drawer height; the tile grid deliberately
does not, being fixed at a 3x3 ceiling.
|
|
A module provides a tile, a page, both or neither, plus alwaysActive,
which governs the background service rather than the page: the drawer is
closed most of the time and three of four modules have background work.
|
|
The window draws nothing and catches nothing; it exists because a
quickshell config with no visible window exits silently, and this
shell's drawer is closed most of the time.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01We9zcHEH8ZWHPcQwMaJRNv
|