Watch
1
0
Fork
You've already forked souveraine
0
Commit graph souveraine/surfaces/quickshell/modules/ii
Author SHA1 Message Date
Fimeg
bf469c4216 lock: answer touchKeypad on a cold start, not just a reload
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.
2026-08-09 22:21:14 -04:00
Fimeg
16c6ee1033 multitasking: one owner for the transition, and the release travels
ZoneTransition owns the card rect, the four overview verbs, the end-target
table and the gesture clock. ZoneOverview and the rail read it; neither
derives a geometry.

Deletes poseActiveZone/clearPose/_posed, zoneCard.scale and
zonePullProgress. The card's ColumnLayout went too — its margin was a second
opinion about where a window sits in its zone; panes are the compositor's
tiling scaled.

The swipe felt wrong because the release committed where the thumb left it.
settleTo() travels to the destination first and commits on arrival, with
quickstep's numbers (350ms cap, min(1/0.7, 1/0.3)). Abandoned half-swipes
settle to last_zone instead of snapping. Dwell gate restored — quickstep
gates the same way and "ever paused" is a latch.

Card box is measured from the surface, not assumed from the screen: the
overview panel respects exclusive zones and its height moves.

Strand repro passes on hardware.
2026-08-07 12:26:12 -04:00
Fimeg
72171accec the card is the window's size through the whole pull
Two fixes to the same seam. columnLayout was still gated on
missionControlOpen, so a peek raised a panel whose contents were
invisible — the same line that had been left behind once before, with
its own comment saying so.

The card scaled 0.6 -> 1.0 while pose runs 1.0 -> 0.6 against the same
progress, so at the handoff the window was at 0.6 of the glass and the
card arrived near full-bleed. Same curve now, and the 26/12 inset is
gone: scale is the inset, and stacking both squashed the aspect because
the bottom label margin has no counterpart at the top.
2026-08-07 08:52:58 -04:00
Fimeg
f699f57235 multitasking draws under a dwelling thumb
The overview loader was only active once missionControlOpen was already
true, so nothing existed during the pull and ZoneOverview.progress
following the rail was dead mid-drag. The cards appeared at release and
animated on their own clock — two motions, which is the seam TASK-60's
acceptance names.

missionPeek gates presentation only: visibility, mask, which body the
loader builds. Focus, dismissal and every commit path still read
missionControlOpen, so a preview draws and decides nothing. Masked to a
zero-size item while peeking so the in-flight gesture stays the rail's.

Dwell rather than any pull, so a flick to home never flashes the blur,
and it drops above the multitasking detent so the preview never shows a
destination the release would not commit.
2026-08-07 08:42:00 -04:00
Fimeg
630d6912fd sidebar: the keyboard leaves with the panel that summoned it
The drawer clears oskOpen on close and this did not, so the OSK outlived the
surface holding the only text field it was serving — and with nothing focused
there was no obvious way to put it away.

On the state, not on a visibility handler: the panel's `visible` is a binding
to that flag, so reacting to visibility would be reacting to our own effect.
2026-08-07 02:24:24 -04:00
Fimeg
f4caaae1cb drawer: the keyboard comes up on a tap, not on a press
Summoning on onPressed meant any gesture that merely began over the search
field raised the keyboard — including the swipe that scrolls the app grid,
which starts at the top of the drawer more often than not. The press now only
remembers where it landed and the release decides, with a generous slop: a
thumb reaching the top of a 540px panel is not steady, and a few pixels of
drift while tapping a text field is a tap.
2026-08-07 02:22:28 -04:00
Fimeg
5c44ea06d5 dock: scale it up, and put the scale in settings
44px buttons with 35px icons read small on a 540px panel, and a stack's
members were 12px inside a 35px box — unreadable, which is the whole job of
the collapsed form. 56/44 now, and the member icons give back the border and
padding that were being subtracted from them as well as the grid spacing.

Both numbers live in Config so this is a setting rather than a rebuild, with
spin boxes in Settings > Dock. Two numbers and not one ratio: the button is
the row's height and the icon is what you see, and fixing the ratio would
mean either cramped icons in a tall row or icons overflowing a short one.
2026-08-07 02:04:12 -04:00
Fimeg
6f375286bf multitasking: the cards were zero pixels wide
ZoneOverview took its width from the Column it sits in, and a Column is as
wide as its widest child. The drawer's search widget supplies that; mission
control is the cards alone and has no search, so the only child left was the
loader — whose width came from the column, whose width came from the loader.
The cycle resolves to zero.

Full-height zero-width cards draw nothing, which is why multitasking was a
blurred backdrop and nothing else while every other signal read healthy:
zones 2, windows 1, subscribed true, loader active, item present, opacity 1,
progress 1. Bound to the panel's width instead, which is what this surface
covers anyway.

Also adds `overview missionControl` and `overview state` — the surface that
had been reported broken was the one nothing but a pill swipe could raise,
and the state readout is what located this.
2026-08-07 01:32:27 -04:00
Fimeg
5ec6bfdc63 overview: a verb for mission control, and a state readout
Multitasking was raised only by the pill's first-stage swipe, so the one
surface that has been reported broken was the one neither an agent nor a test
could reach. state() reports what the cards are drawn from.

Used it immediately: with a window open the model is not empty — zones 2,
windows 1, subscribed true — so the missing cards are not missing data.
2026-08-07 01:23:14 -04:00
Fimeg
ac35b3436b her face on the glass: it draws, it listens, and it gets out of the way
The rig never drew. live2d.js is not only the Cubism runtime — it carries the
reference's character layer, which reads #live_talk every update as its
motion-state slot. Our page omitted the element, so it threw on the first
frame after the model and all four textures had loaded: assets 200, WebGL
live, no error reaching Rust, blank canvas.

--app-id was a no-op. set_prgname ran after GTK had already created the
surface, so the compositor saw souveraine-web and window rules could only
match the title. It has to run before the event loop.

Press and hold her to speak: pw-record at 16k mono s16, release transcribes
through souveraine-stt --file and goes out over Souveraine.send, so the
sidebar logs it. Whisper wraps with newlines and the transcript arrives
through a SplitParser, so it is collapsed here or one utterance becomes four
turns. Double tap dismisses; the clock and quote fade out when she is up and
the clock stops being a target, because a double tap on an invisible object
is not a way back.

The page reports its silhouette and the host installs it as the input region.
Claiming the GL context for preserveDrawingBuffer must happen after the
canvas is sized — before it, the context is born 300x150 and she renders as a
thumbnail in the corner.

Console and errors are forwarded to the host's stdout. Without that a rig
that fails to draw is silent in every direction, which is what cost this
the afternoon.
2026-08-07 00:24:12 -04:00
casey
3d3eb2cc8e the avatar draws: serve the rig over loopback, not the opaque scheme 2026-08-05 22:14:07 -04:00
Fimeg
a5f0fadba8 unlocking closes a keyboard nobody asked for 2026-08-05 21:55:11 -04:00
Fimeg
bb81781007 the backdrop is the input region, so it owes the way out 2026-08-05 20:10:40 -04:00
Fimeg
1ac33afb25 dock is home's alone; the pill stops riding above it 2026-08-05 20:04:45 -04:00
Fimeg
d7965a57fd two swipes, one progress; home is zone 0; pocket is a belief 2026-08-05 19:16:41 -04:00
Fimeg
277a0d2b32 dock lives on zone one; short swipe multitasks, big swipe goes home 2026-08-05 16:17:47 -04:00
Fimeg
bf8bc013ef three-finger tap opens a window sheet, not the overview 2026-08-05 14:12:22 -04:00
Fimeg
3aea8398a9 shell: intent wins the settle window, and a swap is a request for a keyboard
Two gaps in the owner-change handling, both found on device.

The push at adopt time can lose a race. osk-switch sleeps 0.3s before
its deliberate SetVisible(true), and stevia self-shows once it has
finished coming up - both land after the shell has spoken. Measured:
adopt+hide 07:37:51, Visible=true 07:37:52, leaving oskOpen=false with a
keyboard on the screen. Re-assert when the settle window closes so the
last speaker is not the winner.

And the oskSwap gesture never recorded that a swap means the user wants
a keyboard, so osk-switch's re-show and the shell's stale false were
racing with nothing to arbitrate them. Declare the intent first.
2026-08-05 07:41:02 -04:00
Fimeg
d7a04f27d5 shell: an owner change is not a visibility event
sm.puri.OSK0 is a name, not a process. Boot, a crash-restart and an
osk-switch swap each put a fresh keyboard behind it, and the visibility
monitor mirrored the newcomer's opening claim into oskOpen as though the
user had asked for a keyboard. Measured: shell up 03:03:38, self-showed
at 03:03:43, nobody near the phone.

Track the bus owner - gdbus already prints it and the 'Visible' filter
was throwing it away - and on a change push oskOpen at the new owner
instead of pulling state out of it. A process that just started has no
history; the shell is the continuity of intent across the keyboard's
lifetime.
2026-08-05 07:34:53 -04:00
Fimeg
f320a0221d shell: answer to the ipc target sessiond actually calls
Action::Overview shells out to `ipc call overview toggle`. The only handler
here was `search`, so that call reached nothing and the three-finger tap
did nothing, without an error anyone would see.

It has been invisible from the device because the shipped sessiond has no
`gesture` verb yet and refuses the op long before the executor runs, so
only the first half of the break was observable.

This makes the existing binding reach the surface it already names. What
the tap should raise is TASK-55 Q1 and is not decided here.
2026-08-04 15:02:34 -04:00
Fimeg
44a54330c2 shell: mission control draws the cards it was already building
The panel, its mask and the loader all moved to overviewOpen ||
missionControlOpen when mission control landed; the Column holding them
did not. So the second-stage pill swipe raised a panel whose entire
contents were invisible — WindowOverview instantiated, laid out, and never
shown.

Search stays overview-only: mission control takes no keyboard focus on
purpose, so a field there is one you can see and cannot use. Outside-tap
now clears both states, because with no focus grab that tap is mission
control's only way back.
2026-08-04 14:43:35 -04:00
Fimeg
cc4bb83573 shell: the overview arrives as one surface, and mission control finally lands
Everything drove off a visible/not-visible flag, so the cards appeared
rather than the overview opening. One shared `progress` now: the strip
slides 24px, each card takes its own share of it staggered by index and
capped at the fifth, and scale runs 0.86 to 1.0 — the reference shell's
numbers, driven from the same clock instead of a timer per card. The cap
is what stops the tenth card starting half a second after the first,
which reads as loading rather than opening.

This is also SHELL-ECOSYSTEM's stated model, taken from Phosh: state
gates visibility, never the reverse.

`missionControlOpen` has been set by the pill's second-stage swipe since
July and consumed by NOTHING — TASK-14 records the Auxo-like card
surface it was meant to raise as never built. WindowOverview is that
surface. The state reaches something now instead of being set and
dropped.

Mission control is the cards alone: no search, and no keyboard focus,
because it is "switch to what is running" and not "find something" — and
taking the keyboard would summon the OSK over a surface with no field.
2026-08-03 22:18:43 -04:00
Fimeg
fdb0acfdce shell: the overview shows windows, because there are no workspaces here
OverviewWidget draws a grid of workspaces and places windows in them by
Hyprland coordinates — HyprlandData.windowList, monitorData,
Hyprland.monitorFor. Under viewtop none of it resolves, and more to the
point viewtop has no workspaces at all: one space, a tiling layout. The
old overview could not be repaired by repointing it at another data
source, because the thing it draws does not exist. It rendered an empty
frame, which reads as the overview being broken.

WindowOverview lists what does exist. Cards from
ToplevelManager.toplevels — the same list the dock and TaskbarApps
already read, so there is one idea of what is open — each holding a
live ScreencopyView of one window, which only became possible when the
compositor started serving a per-window capture source; until then a
card could have shown nothing but the screen it was covering.

The motion is the reference shell's, read out of
overview_window_card.dart rather than invented: stagger at index * 45 ms
capped at the fifth card, intro scale 0.86 to 1.0, dismiss past 32% of
the card height, 56 px of downward rubber-banding, settle under 200 ms.
The cap is the part worth keeping — without it the tenth card starts
half a second after the first and the overview feels like it is loading
rather than opening.

Captures run only while the overview is up. A live capture per window is
a render of that window every frame, and leaving them going behind a
closed overview is battery spent drawing what nobody can see.
2026-08-03 18:37:56 -04:00
Fimeg
c21bd1d7d9 shell: stop gating the dock on a flag the keyboard flaps
Suppressing the dock whenever oskOpen was true, above effectivePinned so
it applied in every state, hid the dock permanently on the device.

oskOpen is not "the keyboard is on screen". GlobalStates' own comment
says squeekboard hides itself whenever input-method focus drops and that
a hold re-asserts it, and the journal shows exactly that: self-showed /
self-hid every couple of seconds, settling at Visible=true with no
keyboard in front of the user. Gating a persistent surface on a flag
that flaps turns a cosmetic overlap into a dock nobody can reach.

The empty-desktop check keeps its oskOpen term, where it always was: a
spuriously-true flag there costs a reveal that was cosmetic anyway,
which is a different price from hiding a pinned dock.

The real signal is the keyboard's exclusive zone, which the compositor
already applies — an unpinned dock declares zone 0 and is placed above
the keyboard for free, the same mechanism that fixed the pill. The
pinned case, where both reserve space and the reservations stack, wants
fixing where the zones are arbitrated.
2026-08-03 17:17:01 -04:00
Fimeg
ca44b0be2a shell: the keyboard owns the bottom edge, and nothing measures it
Two bugs with one cause — the bottom edge was being reasoned about
twice, by hand, against a compositor that is gone.

The rail set ExclusionMode.Ignore (exclusive zone -1: ignore what
everyone else reserved, anchor to the whole screen) and then computed
its own lift from the keyboard's height, probed by shelling out to
`hyprctl -j layers`. Under viewtop there is no hyprctl, so every probe
threw a JSON.parse on empty output and logged it in a loop every second
or two, forever, while the margin stayed at a hardcoded fallback
measured against a keyboard that is not the one running. A 200px
fallback against some other height is exactly "the pill spawns in the
middle of the keyboard". Zone 0 with Normal — the idiom SidebarRight and
ReloadPopup already use — reserves nothing and respects what others
reserved, so the compositor anchors the rail to the top of the
keyboard's exclusive zone. Correct at any height, any rotation, across a
swap, with nothing to go stale. The probe, its retry timer and
probeOskHeight() are deleted rather than ported: a second measurement of
a number the protocol already carries is what this class of bug is made
of.

The dock consulted oskOpen only in its empty-desktop branch, below
effectivePinned, so a PINNED dock ignored the keyboard and sat under it.
DockManifest.dockState() has always reported "suppressed-by-osk" and
_blockReason() has always refused mutations with "osk-open" — the
manifest promised a suppression the dock never performed, so the agent's
view of the screen and the screen disagreed. The check moves above
pinning and applies in every state, staying below dockRevealPulse
because an explicit reveal is the one thing that should outrank the
keyboard.

Verified on the phone: the probe loop is gone from the journal. The
resulting pill and dock positions want eyes on the glass.
2026-08-03 16:53:06 -04:00
Fimeg
5c618f1514 lock: hoist the lock out of the Config.ready loaders so a reload can adopt
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.
2026-07-31 21:25:05 -04:00
Fimeg
49635fb005 shell: give the subconscious event log a host
Tier 2 was written, deployed and mounted by nothing — its own header named the
gap. The chat sidebar hosts it now: ticker long-press, or the psychology
indicator by the input box, which works when no pass is running.
2026-07-31 12:51:17 -04:00
Fimeg
483902a40e shell: restore the subconscious ticker to the chat column
Re-mount SubconsciousTicker in AiChat (lost in the 07-30 relocation out
of the ii tree). The view is decoupled; it just needed its host back.
2026-07-30 15:17:55 -04:00
Fimeg
25898a9d14 shell: re-home the subconscious surface from the ii tree to souveraine
The subconscious three-tier surface (SubconsciousTicker + SubconsciousEventPanel)
is Souveraine-original, not upstream ii. It lived under ii-base/modules/ii only
because it had never been re-homed, so the ii -> souveraine shell migration
silently stranded it: the files survived, but the running shell (qs -c souveraine)
never loaded them, and the feature dropped off the device.

Relocated into modules/souveraine/subconscious/, decoupled from the ii overlay
system it was riveted to:

- SubconsciousTicker: was clean of ii imports but opened the panel through the
  ii OverlayContext singleton. Now emits requestOpenPanel(); a host connects it.
- SubconsciousEventPanel: was a StyledOverlayWidget (qs.modules.ii.overlay). Now
  plain content a host instantiates; the pin/close/drag affordances were the
  overlay host's job, not the content's.

The model (services/Ai.qml) was already substrate-neutral and never moved; only
the views were stranded. GAP NAMED: no souveraine overlay host mounts these yet,
so they do not reach the glass until one exists — the ii overlay host was
intentionally not ported. The dangling ii references (AiChat, OverlayContext,
OverlayWidgetDelegateChooser) are removed.
2026-07-30 12:57:19 -04:00
Fimeg
0ef239515f surface: per-agent TTS voice + turn clock + reply-handler fix
Speech resolves voice per active agent (agents[].voice_id from the list),
with the system voice as fallback — two agents on a host need not match.
Souveraine.qml carries voice_id into the agents map and adds a turn clock
(turnStartedAt/turnElapsedMs) + a 60s agent-inventory refresh. Ai.qml
declares pendingFilePath and imports qs.modules.common.functions so
StringUtils.ttsClean no longer aborts the stream-finished handler.
2026-07-30 09:18:56 -04:00
Fimeg
5965c64781 shell: recover the phone-only edits into the repo
~/souveraine-surfaces/quickshell on the phone is not a git repo and was the
only copy of five files. Brought back verbatim:

- Gestures.qml, SystemGestureRail.qml: TASK-38 osk-swap detent (DUMP §5, §6)
- OnScreenKeyboard.qml: showOsk asks the bus instead of pgrep+sleep 1
- DockAppButton.qml, DockStack.qml: suffix-tolerant AppSearch.resolveEntry

resolveEntry itself had been added to the phone's live ~/.config/quickshell/ii
tree, which deploy.sh rsyncs from ii-base — the next deploy would have deleted
it and left the two dock callers referring to nothing. It lands in ii-base here.
2026-07-29 08:27:27 -04:00
Fimeg
7475fae505 osk: polkit holds the keyboard open instead of poking it once
squeekboard hides itself when input-method focus drops, so the password
field was left with no keyboard. A hold re-asserts through that and
releases on dismiss; a manual close drops the hold.
2026-07-26 16:56:34 -04:00
Fimeg
19fe6b1d0e shell: dock reorder, fullscreen detection fix, idle-power, sessiond, misc shell work
- Dock drag-to-reorder for pinned apps (insertion gap, quick-slide vs dwell)
- Fullscreen detection: scan all windows via HyprlandData.windowList
- IdleCoordinator, GlobalStates, Session.qml updates
- Deploy script, qmldir, settings, wallpaper, visualizer fixes
- sessiond server, memory module updates

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 22:18:20 -04:00
Fimeg
9ccefd6c73 dock: fix fullscreen detection — scan all windows, not just active/focused
Previous fullscreen detection had two blind spots:
1. Workspace scan used wayland?.fullscreen (unreliable) and missed qs -p windows
2. HyprlandData.activeWindow fallback only saw the focused window — missed
   fullscreen apps that lost focus to layer-shell surfaces (dock, notifications)

Now scans HyprlandData.windowList (hyprctl clients -j) for any window with
fullscreen === 2 on the focused monitor. Source of truth for all windows,
not just the active one. Reactive via HyprlandData's event-driven updates.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 21:25:08 -04:00
Fimeg
132d8134f2 dock: add drag-to-reorder for pinned apps alongside existing combine-into-stack
Dragging a pinned app now shows an insertion gap indicator when hovering
over other pinned apps. Quick horizontal slide + release = reorder the
pinned apps array. Dwell (500ms) on a target still = combine into stack
(existing behavior). Both gestures share the same drag start and ghost.

TaskbarApps: reorderPinned() splice-moves within Config.options.dock.pinnedApps.
DockApps: shared dragSourceIndex/dragInsertIndex state, delegate passes
  parent.index as modelIndex to DockAppButton.
DockAppButton: insertion indicator (2px primary-color line), DropArea
  onEntered computes gap position based on drag direction, release handler
  commits reorder when no dwell fired.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 21:11:19 -04:00
Fimeg
b0a1304ba1 quickshell: pin shared ii base and phone overlay 2026-07-21 18:55:02 -04:00
Fimeg
0d06cbb983 quickshell: dock fullscreen fallback via HyprlandData IPC, wallpaper folder browsing 2026-07-21 15:52:32 -04:00
Fimeg
db6d732e32 shell: regenerate qmldir manifests from the composed tree
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.
2026-07-21 13:36:39 -04:00
Fimeg
acc1161e71 shell: Speech service + sidebar Speak button (Read Aloud seam)
Speech.qml singleton: speak(text) reads the who->voice mapping live
from souveraine /v1/config (VoiceConfig tts_url + voice_id), POSTs
VibeVoice /audio/speech ({input, voice, model} -> mp3, same contract
as core/voice/client.rs) and plays via mpv/ffplay. The shell picks no
voice of its own. speech.tts.enable is the kill switch (button hidden
when off); speech.tts.endpoint overrides the mapped URL. Sidebar gains
a volume_up/stop toggle beside send that reads the last visible
assistant reply, skipping lock-redacted content.
2026-07-21 13:28:47 -04:00
Fimeg
271e4f2cc2 shell: add missing qmldir manifests + rail OSK layer fix
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.
2026-07-21 13:01:58 -04:00
Fimeg
5083954c38 lock: own backdrop with wallpaper option, am/pm clock
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.
2026-07-20 22:47:11 -04:00
Fimeg
3837698c8b osk: mirror squeekboard's real Visible back into oskOpen
squeekboard auto-shows/hides itself on input-method focus without
telling the shell; the stale flag left the dock suppressed and the rail
floating at keyboard height. gdbus monitor on its Visible property is
the single truth now.
2026-07-19 22:46:09 -04:00
Fimeg
47858d5b06 phone: wallpaper picker settings page, drag-follow PIN reveal
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.
2026-07-19 22:46:01 -04:00
Fimeg
5cb1be06cd lock primitives: power-from-lock, login1 polkit rule, gesture rail progress
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.
2026-07-19 22:13:08 -04:00
Fimeg
dfd494c5f1 quickshell: complete native PulseAudio source support 2026-07-18 15:05:17 -04:00
Fimeg
401a6609ea lock: glance-first touch surface, keypad behind swipe-to-unlock
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.
2026-07-17 06:46:49 -04:00
Fimeg
c96f95b9da quickshell: fix drag-to-combine, rail rides the keyboard, overview gap-tap dismiss
The drag ghost was anchored (centerIn) — Qt won't move an anchored
drag.target, so no DropArea ever fired and stack creation died silently;
position it on press instead. Drag lifecycle now sets dockDragInProgress
(the DockManifest guard finally has a writer). Restored pulseDockReveal,
lost in a refactor while its osk.pulseDock caller survived.

Rail lifts atop squeekboard by measured layer height (hyprctl -j layers,
namespace osk); swipe down dismisses the keyboard first, then a visible
dock in any state (new dockSuppressed, cleared by swipe up). Overview:
taps in the grid's dead space dismiss it instead of being eaten.
DockConfig grew the real pins/stacks editor (unpin, rename, unstack,
dissolve).
2026-07-16 12:04:08 -04:00
Fimeg
72b01457d2 quickshell: restore ii-stock config keys the fork dropped
Config.qml regained sidebar.width/widthExtended (their absence collapsed
the right sidebar PanelWindow to 1px — 'unclickable' on the laptop), plus
lock.dpmsTimeout, lock.unlockHook, and autoIdleInhibit with its Idle.qml
property. Audio.qml's absent capture source is now a zero-volume stub so
stock consumers stop dereferencing null, and the pactl status parse runs
under LC_ALL=C. volumeMixer dialog content comes along for the sidebar.
Findings logged in SouveraineOS/docs/DUMP-power-idle-lock-2026-07-15.md.
2026-07-16 08:06:11 -04:00
Fimeg
e31c3aaf62 quickshell: first-party lock/nav/session layer, retire the pill
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.
2026-07-14 20:00:57 -04:00
Fimeg
cecde3bac2 quickshell: session arbiter + fix IPC returns silently dropping payloads
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.
2026-07-14 18:31:59 -04:00