Complete contextual desktop controls

This commit is contained in:
Gabriel Brown
2026-08-20 22:00:53 -04:00
parent a90f6eb357
commit 69ecec7ecf
9 changed files with 249 additions and 23 deletions
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
# A ScreencopyView only has content *after* capture. It is not a readiness
# signal, so an overview thumbnail must first wait for its enclosing layer
# surface to render a frame. This contract keeps that warning-prone boundary
# explicit without opening a QML test window.
set -uo pipefail
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
thumbnail="$repo_dir/config/dot/quickshell/modules/overview/WindowThumbnail.qml"
fail() {
printf 'overview thumbnail contract: %s\n' "$1" >&2
exit 1
}
[[ -r "$thumbnail" ]] || fail 'WindowThumbnail.qml is missing'
grep -qF 'FrameAnimation {' "$thumbnail" \
|| fail 'capture has no frame-ready gate'
grep -qF 'property bool recordingReady: false' "$thumbnail" \
|| fail 'capture readiness is not tracked independently from captured content'
grep -qF 'if (!shot.recordingReady)' "$thumbnail" \
|| fail 'capture can start before the frame-ready gate'
grep -qF 'frameReady.restart();' "$thumbnail" \
|| fail 'a pending capture is not scheduled by the frame-ready gate'
grep -qF 'shot.recordingReady = true;' "$thumbnail" \
|| fail 'the frame-ready signal never releases capture'
capture_calls="$(grep -cF 'shot.captureFrame()' "$thumbnail")"
[[ "$capture_calls" -eq 1 ]] \
|| fail "capture must have one bounded attempt after readiness, found $capture_calls"
! grep -qF 'captureAttempts' "$thumbnail" \
|| fail 'blind capture retry state remains'
! grep -qF 'captureRetry' "$thumbnail" \
|| fail 'blind capture retry timer remains'
# The application icon remains visible until the one-shot capture succeeds.
grep -qF 'opacity: shotLoader.hasFrame ? 0 : 1' "$thumbnail" \
|| fail 'app-icon fallback no longer remains visible before a frame arrives'
printf 'overview thumbnail contract: PASS (frame-gated one-shot capture with icon fallback)\n'
+30
View File
@@ -16,6 +16,9 @@ set -uo pipefail
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
shell_state="$repo_dir/config/dot/quickshell/services/ShellState.qml"
modules="$repo_dir/config/dot/quickshell/modules"
dock_menu="$modules/dock/DockContextMenu.qml"
notification_card="$modules/notifications/NotificationCard.qml"
osd="$modules/osd/Osd.qml"
fail() {
printf 'settings jump contract: %s\n' "$1" >&2
@@ -47,4 +50,31 @@ for widget in Clock WeatherWidget VitalsWidget StatusCluster MediaWidget; do
|| fail "$widget has no right-click jump; Pill routes right-click to secondaryActivated, so leaving it unconnected makes the gesture silently inert"
done
# These surfaces do not have a bar-style secondary-click signal. Their
# contextual affordances must retain the original interaction and route to the
# setting page that owns the controls.
[[ -r "$dock_menu" ]] || fail 'dock has no contextual menu, so application actions cannot keep a final Dock settings action'
grep -qF 'ShellState.openSettings("desktop")' "$dock_menu" \
|| fail 'dock context menu does not open Desktop settings'
grep -qF 'entry.actions' "$dock_menu" \
|| fail 'dock context menu dropped application actions'
actions_line="$(grep -nF 'entry.actions' "$dock_menu" | head -1 | cut -d: -f1)"
settings_line="$(grep -nF 'Dock settings' "$dock_menu" | head -1 | cut -d: -f1)"
[[ -n "$actions_line" && -n "$settings_line" && "$actions_line" -lt "$settings_line" ]] \
|| fail 'Dock settings is not the final contextual action after application actions'
grep -qF 'Notification settings' "$notification_card" \
|| fail 'notification card has no overflow Settings action'
grep -qF 'ShellState.openSettings("notifications")' "$notification_card" \
|| fail 'notification overflow does not open Notifications settings'
grep -qF 'Popover {' "$notification_card" \
|| fail 'notification Settings action is not contained in an overflow menu'
grep -qF 'acceptedButtons: Qt.RightButton' "$osd" \
|| fail 'OSD does not accept its contextual secondary click'
grep -qF 'ShellState.openSettings("accessibility")' "$osd" \
|| fail 'OSD secondary click does not open Accessibility settings'
grep -qF 'OsdState.hide()' "$osd" \
|| fail 'OSD remains visible after its Settings jump'
printf 'settings jump contract: PASS (%d distinct destinations)\n' "$count"