Watch
1
0
Fork
You've already forked souveraine
0
souveraine/surfaces/quickshell/GlobalStates.qml
Fimeg b4b30b124d Unified device state machine + security hardening
sessiond:
- device_state.rs: 8-state unified device state machine with legal
  transition table, sensor evidence model (proximity/accel/light/touch),
  confidence scoring, cross-sensor disagreement detection, and forensic
  logging with full state snapshots at every decision point.
- protocol.rs: extended with DeviceState, SensorInput, and ForensicLog
  IPC requests. SensorSource/SensorValue types for proximity, accel,
  light, touch.
- server.rs: DeviceStateMachine integrated into Daemon struct. Handlers
  for DeviceState (full state query), SensorInput (sensor evidence +
  Observed transitions), ForensicLog (recent entries query).
- lock.rs: Failed attempt counter on PIN surface (advisory, PAM owns
  lockout policy). Rendered as red digit glyphs below PIN dots.
- draw.rs: Attempt counter rendering + test.
- auth.rs: PAM config docs reference.
- mod.rs: device_state module added.

shell:
- IdleCoordinator.qml: Legal transition table with runtime enforcement.
  setState() refuses illegal transitions with warning. returnActive()
  explicitly only allows Dimmed/Waking.
- GlobalStates.qml: Write authority comments on every property (// WRITER:).
- SessionAudit.qml: SHA-256 replaces MD5 for hash chain. Forensic event
  wiring (device-state-transition, device-error, sensor-input, wake-event).
  logDeviceError/logSensorInput/logWakeEvent functions for QML callers.

Design doc: SouveraineOS/docs/DEVICE-STATE-MACHINE.md (separate repo).

Tests: 22 passing (was 7). Full lifecycle test exercises Active → Dimmed →
Locked → Observed → DozeLight → DozeDeep → Suspending → Asleep → Locked
with 23 forensic entries.
2026-07-24 16:29:04 -04:00

176 lines
7.3 KiB
QML

// Souveraine patch to ii's stock GlobalStates.qml.
//
// Adds dockRevealed: the explicit, persistent dock state driven by the
// Souveraine's integrated navigation rail. Everything else in this file is
// unchanged stock ii — diff against upstream before re-applying this patch if
// ii updates.
import qs.modules.common
import qs.services
import QtQuick
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
pragma Singleton
pragma ComponentBehavior: Bound
Singleton {
id: root
// ── Write authority ────────────────────────────────────────────
// Each property below names its single authorized writer. Other
// files MUST NOT write to these directly — route through the
// writer's IPC or signal instead. This is a convention, not
// enforced at runtime; a lint rule or future QML analyzer should
// flag writes from files other than the named writer.
//
// Stock ii properties (barOpen, crosshairOpen, sidebarLeftOpen,
// sidebarRightOpen, mediaControlsOpen, osdBrightnessOpen,
// osdVolumeOpen, oskOpen, overlayOpen, overviewOpen,
// regionSelectorOpen, searchOpen, screenTranslatorOpen,
// sessionOpen, wallpaperSelectorOpen, workspaceShowNumbers) are
// written by their respective ii modules. Souveraine does not
// own these — they follow ii's own conventions.
// WRITER: ii bar module
property bool barOpen: true
// WRITER: ii crosshair module
property bool crosshairOpen: false
// WRITER: ii sidebar module
property bool sidebarLeftOpen: false
// WRITER: ii sidebar module
property bool sidebarRightOpen: false
// WRITER: ii media controls module
property bool mediaControlsOpen: false
// WRITER: ii OSD module
property bool osdBrightnessOpen: false
// WRITER: ii OSD module
property bool osdVolumeOpen: false
// WRITER: ii OSK module (OnScreenKeyboard.qml)
property bool oskOpen: false
// WRITER: ii overlay module
property bool overlayOpen: false
// WRITER: ii overview module + Dock.qml IPC
property bool overviewOpen: false
// WRITER: ii region selector module
property bool regionSelectorOpen: false
// WRITER: ii search module
property bool searchOpen: false
// WRITER: LockScreen.qml — the shell's lock *request*. Drives
// WlSessionLock and hides ordinary surfaces immediately. Deliberately
// separate from screenLockSecure (compositor ack). Consumers that
// disclose personal data must gate on secure, not merely request.
property bool screenLocked: false
// WRITER: IdleCoordinator.qml — true while the display is genuinely
// in use (Active or Waking). Widgets/pollers whose data may go stale
// while the screen is dimmed/locked/asleep gate their timers on this
// instead of importing IdleCoordinator into ii-base.
property bool displayActive: true
// WRITER: LockScreen.qml — WlSessionLock.secure. Only true once the
// compositor has acknowledged the lock surface. This is the real
// "session is locked" signal; screenLocked is just the request.
property bool screenLockSecure: false
// WRITER: LockScreen.qml
property bool screenLockContainsCharacters: false
// WRITER: LockScreen.qml
property bool screenUnlockFailed: false
// WRITER: ii translator module
property bool screenTranslatorOpen: false
// WRITER: ii session module
property bool sessionOpen: false
// WRITER: GlobalShortcut handler in this file
property bool superDown: false
// WRITER: GlobalShortcut handler in this file
property bool superReleaseMightTrigger: true
// WRITER: GlobalShortcut handler in this file
property real superPressTime: 0
// WRITER: GlobalShortcut handler in this file
property real superLastPressDuration: -1
// WRITER: GlobalShortcut handler in this file
property real superLastReleaseTime: 0
// WRITER: ii wallpaper selector module
property bool wallpaperSelectorOpen: false
// WRITER: ii workspace module
property bool workspaceShowNumbers: false
// WRITER: LockScreen.qml — true from shell start until the lock
// surface is secure. Covers Hyprland's boot render, continuing the
// C splash bloom animation. LockScreen.onSecureChanged clears it.
property bool bootBloomActive: true
// WRITER: Dock.qml IPC (swipeUp/reveal) + navigation rail. The
// fullscreen dock toggle. Deliberately has no timer.
property bool dockRevealed: false
// WRITER: navigation rail (triple swipe-up). The Souveraine
// process/task surface. Deliberately distinct from overviewOpen
// (app launcher/search) — this is the running-work view.
property bool missionControlOpen: false
// WRITER: Dock.qml IPC (swipeDown). A rail swipe-down on a visible
// dock dismisses it in ANY state — including pinned and
// shown-on-empty-desktop. Swipe up clears it.
property bool dockSuppressed: false
// WRITER: this file (pulseDockReveal) + OnScreenKeyboard.qml IPC.
// Transient dock reveal: shows for 3s and restores prior state.
// Restored 2026-07-16 — definition was lost in a refactor while
// its IPC caller survived, so pulseDock threw.
property bool dockRevealPulse: false
function pulseDockReveal() {
root.dockRevealPulse = true;
dockRevealPulseTimer.restart();
}
Timer {
id: dockRevealPulseTimer
interval: 3000
onTriggered: root.dockRevealPulse = false
}
// WRITER: DockAppButton drag lifecycle. True while a dock icon drag
// is in flight. Read by DockManifest's state checks so structural
// edits (pin/stack mutations) can't land mid-drag.
property bool dockDragInProgress: false
function superPressDuration() {
const now = Date.now();
if (root.superPressTime > 0)
return now - root.superPressTime;
if (root.superLastReleaseTime > 0 && now - root.superLastReleaseTime < 250)
return root.superLastPressDuration;
return -1;
}
function shouldSuppressSuperReleaseSearch() {
const autoHide = Config?.options?.bar?.autoHide;
const showWhenPressingSuper = autoHide?.showWhenPressingSuper;
if (!autoHide?.enable || !showWhenPressingSuper?.enable || !showWhenPressingSuper?.suppressSearchOnHold)
return false;
const duration = root.superPressDuration();
return duration >= (showWhenPressingSuper?.suppressSearchDelay ?? showWhenPressingSuper?.delay ?? 140);
}
onSidebarRightOpenChanged: {
if (GlobalStates.sidebarRightOpen) {
Notifications.timeoutAll();
Notifications.markAllRead();
}
}
GlobalShortcut {
name: "workspaceNumber"
description: "Hold to show workspace numbers, release to show icons"
onPressed: {
root.superDown = true
root.superPressTime = Date.now()
root.superLastPressDuration = -1
}
onReleased: {
const now = Date.now()
if (root.superPressTime > 0)
root.superLastPressDuration = now - root.superPressTime
root.superLastReleaseTime = now
root.superPressTime = 0
root.superDown = false
}
}
}