From e8a8fcf183fab5a5768447fb789ac6d7eae5b8ba Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Tue, 2 Jun 2026 22:38:31 -0400 Subject: [PATCH] Fix theme switcher preload scrim race --- shell/plugins/background/Background.qml | 2 +- shell/plugins/image-picker/ImagePicker.qml | 6 ++++++ test/shell.d/background-test.sh | 13 +++++++++++++ test/shell.d/image-picker-test.sh | 7 +++++++ 4 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 test/shell.d/background-test.sh diff --git a/shell/plugins/background/Background.qml b/shell/plugins/background/Background.qml index 0c4a2e95..e5d51831 100644 --- a/shell/plugins/background/Background.qml +++ b/shell/plugins/background/Background.qml @@ -110,7 +110,7 @@ Item { Process { id: themeSwitchProc - command: ["bash", "-lc", "theme=$(omarchy-theme-switcher); [[ -n $theme ]] && omarchy-theme-set \"$theme\""] + command: ["bash", "-lc", "theme=$(omarchy-theme-switcher); [[ -n $theme ]] && omarchy-theme-set \"$theme\" >/dev/null 2>&1 &"] onExited: root.refreshBackground() } diff --git a/shell/plugins/image-picker/ImagePicker.qml b/shell/plugins/image-picker/ImagePicker.qml index be1a73de..1d8d6a4c 100644 --- a/shell/plugins/image-picker/ImagePicker.qml +++ b/shell/plugins/image-picker/ImagePicker.qml @@ -324,6 +324,12 @@ Item { } function preloadRows(nextImageRows, nextSelectedImage, nextShowLabels, nextFilterable) { + // Theme/background set hooks can warm selector rows after a picker was + // dismissed. Ignore those preloads while a user-visible request is open; + // otherwise the preload resets layoutSettled without revealing again, + // leaving only the fullscreen scrim. + if (opened || requestActive) return + requestSerial += 1 imageRows = nextImageRows selectedImage = nextSelectedImage diff --git a/test/shell.d/background-test.sh b/test/shell.d/background-test.sh new file mode 100644 index 00000000..db512476 --- /dev/null +++ b/test/shell.d/background-test.sh @@ -0,0 +1,13 @@ +#!/bin/bash +source "$(dirname "$0")/base-test.sh" + +run_node_test <<'JS' +const fs = require('fs') + +const backgroundQml = fs.readFileSync(path.join(root, 'shell/plugins/background/Background.qml'), 'utf8') + +assert( + /theme=\$\(omarchy-theme-switcher\); \[\[ -n \$theme \]\] && omarchy-theme-set \\"\$theme\\" >\/dev\/null 2>&1 &/.test(backgroundQml), + 'background theme switcher starts theme application asynchronously after selection' +) +JS diff --git a/test/shell.d/image-picker-test.sh b/test/shell.d/image-picker-test.sh index f52b90a2..2fd8e5fa 100644 --- a/test/shell.d/image-picker-test.sh +++ b/test/shell.d/image-picker-test.sh @@ -5,6 +5,7 @@ set -euo pipefail source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" run_node_test <<'JS' +const fs = require('fs') const picker = requireFromRoot('shell/plugins/image-picker/ImagePickerModel.js') assertEqual(picker.nameForPath('/themes/nord-river.png'), 'nord-river', 'image picker strips directory and extension') @@ -40,4 +41,10 @@ assertEqual(picker.indexForSelectedImage(images, '/missing.png'), 0, 'image pick assertEqual(picker.filteredPosition(images, 2, 'dark'), 1, 'image picker computes filtered position') assertEqual(picker.selectedFilteredPosition(images, 2, 'dark'), 0, 'image picker selected filtered position falls back when selected is hidden') assertEqual(picker.nextSelectedIndexForFilter(images, 0, 'dark'), 1, 'image picker moves selection to first match when filter hides current item') + +const imagePickerQml = fs.readFileSync(path.join(root, 'shell/plugins/image-picker/ImagePicker.qml'), 'utf8') +assert( + /function preloadRows[\s\S]*if \(opened \|\| requestActive\) return/.test(imagePickerQml), + 'image picker ignores cache preloads while a request is visible' +) JS