PersistentProperties is in-process, so it carries the surface choice
through a reload and not through a fresh shell. sessiond locks before the
shell exists, so a greetd-started shell adopts a live lock with
Config.ready still false and binds the desktop surface — and
WlSessionLock.surfaceComponent cannot change once active. A lock screen
that will not take your PIN, on the iPhone 7 tonight.
Reads the environment, which answers at construction. Unset behaves
exactly as before, so nothing changes on blueline until it sets it.
PanelLoader is a LazyLoader gated on Config.ready, behind a second one.
On reload both are shut when quickshell propagates, so LazyLoader has no
item to hand its successor and the new WlSessionLock never adopts the live
compositor lock. Lock is a direct child of ShellRoot now, as the boot-order
doc already asked.
Ungated means Config may not have loaded, and touchKeypad reads false from
the adapter defaults — which would bind the desktop surface on the phone and
cannot be changed once the lock is active. The choice rides the reload too.
The repo qmldirs listed only repo-owned types; composed dirs also carry
ii-borrowed types (ReloadPopup, PanelLoader, Bar, ...) which a qmldir
present in the dir must list or they stop resolving — broke the phone
shell on deploy. Regenerated every deployed qmldir from the composed
config on-device (capitalized .qml -> type line, pragma Singleton ->
singleton line) and pulled back. Shell verified active, zero load
errors.
19 dirs had .qml but no qmldir -> quickshell config load failed
(File not found @ shell.qml[-1:-1]). Corrected singleton decls in
3 existing qmldir. SystemGestureRail: pill->WlrLayer.Top, oskLift
200, drop oskOpen hide.
The session-lock surface was transparent with nothing painting behind it.
TouchLockSurface now owns its backdrop: lock.wallpaperPath when pinned,
else the system wallpaper, else a dark field — plus a scrim for glance
legibility. Glance clock gains lock.twelveHourClock (default on, h:mm ap).
LockConfig grows the wallpaper picker (same FolderListModel grid as the
wallpaper page, no matugen side effects) and the 12-hour switch.
Wallpaper grid in the settings app applying through the shell's
wallpapers IPC. Lock pad now tracks the finger during the swipe and
settles on release instead of snapping at a threshold.
seat0-active polkit rule so power off/reboot/suspend stop returning
challenge into a session with no polkit agent on the lock surface.
Lock-surface buttons stay gated behind allowPowerFromLock (opt-in) and
requirePasswordToPower. SystemGestureRail progressive gesture + mission
control nav flag.
PIN pad hidden until swipe up / tap hint / hardware key; retreats after
25s idle with nothing typed. shouldReFocus no longer implies reveal --
hypridle fires it on every wake and wake must land on glance.
Grows Souveraine's own surfaces on top of the borrowed ii shell and drops
the separate pill shell in favor of one integrated navigation rail.
Session arbiter (functions/Session.qml): probe logind's Can* methods over
busctl instead of guessing from installed binaries -- the answer carries the
polkit tier (yes/challenge/na), so a swapless phone reports hibernate as na
and refuses honestly rather than firing a verb that no-ops. Verbs run through
a Process that logs exit codes and tracks lastAction; refusals log too. The
busctl output is parsed with awk, not a sed regex buried under four escaping
layers -- the sed version returned nothing on the phone and left every
capability stuck at "unknown" (invisible on the laptop, where timing masked
it). Every structured result is JSON-over-string; quickshell maps a var
return to void.
Lock trust: screenLocked (the shell's lock request) is now distinct from
screenLockSecure (WlSessionLock.secure, the compositor's acknowledgement,
mirrored from LockScreen). Cards that disclose personal data gate on secure,
not on a button press. LockContentPolicy centralizes the ambient/personal/
step-up tiers so no card grows its own private rule.
New first-party namespace modules/souveraine/: LockMediaCard, LockSurfaceHost,
SystemGestureRail -- owned surfaces, not ii patches. IdleCoordinator gives one
staged idle vocabulary (dim/lock) gated behind nativeCoordinatorEnabled, off
until the native Wayland idle-notify is verified on the Pixel compositor;
hypridle stays the adapter. WallpaperAssets selects aspect-aware variants for
phone-vs-laptop display shapes.
Pill retired: pill/shell.qml and PillConfig gone, replaced by NavigationConfig
and the gesture rail. Hyprland starts qs -c souveraine directly; no secondary
shell, no qsConfig flip.
Verified on the phone: session.* reports challenge/na correctly, hibernate
and unlock refuse, inhibit round-trips with its reason.
Fork ii's Session singleton and add a sessionctl.* surface.
The IPC bug is the important half. Quickshell marshals exactly five types
(string/int/bool/double/color) and maps a `var` return to VOID, discarding
the payload with no error -- src/io/ipc.cpp, "void and var get mixed by qml
engine". dock.*, shell.* and apps.* were all declared `: var`, so they
registered as `(): void` and returned nothing at all. The {ok, reason}
contract has never once reached a caller. All of them now return JSON as a
string, which is what actually crosses the socket.
Session: upstream fires `systemctl X || loginctl X` detached and throws the
exit code away. Fine on a desktop with someone at the keyboard, not fine on
a phone where the shell is the session manager and a verb that silently does
nothing leaves you believing the machine is suspending when it isn't. So:
probe loginctl/systemctl/hibernate once instead of assuming, run verbs
through a Process that logs the exit code, and refuse honestly when the
machine can't do the thing (the phone has no swap -- hibernate now says so
instead of no-opping). Every upstream verb keeps its name and call sites.
Inhibits carry a mandatory reason and get a cookie; state() lists who is
holding the machine awake and why. "Why didn't it sleep" is now answerable.
unlock() is refused by design -- the lock is the credential gate, so no IPC
caller routes around the PIN pad.
Named sessionctl, not session: ii's SessionScreen already owns "session",
and quickshell drops duplicate targets silently rather than erroring.
Idle: drop the 2>/dev/null and run hypridle through a Process, so a unit
that fails to come back is a log line instead of a flat battery.
Verified on the laptop: inhibit stops hypridle, uninhibit brings it back.
The OSK is layershell and can't rise above a session lock, so the lock
surface carries its own keypad. Lock state persists to states.json so a
qs crash while locked comes back locked; with lock.launchOnStartup the
lock screen is the greeter (greetd autologins straight into Hyprland).
Keypad gated behind lock.touchKeypad so desktop deploys keep the stock
surface.