Merge upstream quattro for the Qt 6.12 palette fix (#14553)

Qt 6.12 shadows the bare Color singleton, so the bar and every Color
role read undefined on fresh installs. Keep our I18n text in the four
conflicting files, qualify #14433's notification button color, give the
new dictation menu rows and notifications Chinese, and drop table
entries for the removed Voxtype and FIDO2 texts.
This commit is contained in:
ZacharyZhang-NY committed 2026-10-09 01:24:30 -04:00
commit fcd681c099
239 files changed
+3996 -616

No files matched your search

@@ -0,0 +1,28 @@
import QtQuick
import Quickshell
import Quickshell.Io
import "background" as BackgroundPlugin
ShellRoot {
property bool reloaded: false
BackgroundPlugin.Background { id: background }
FileView { id: command; path: Quickshell.env("RELOAD_TEST_COMMAND"); watchChanges: true; onFileChanged: reload() }
FileView { id: result; path: Quickshell.env("RELOAD_TEST_RESULT"); atomicWrites: true }
Timer { interval: 600; running: true; onTriggered: result.setText("initial") }
Timer { id: settled; interval: 600; onTriggered: result.setText("reloaded") }
Timer {
interval: 100
running: true
repeat: true
onTriggered: {
if (command.text().trim() === "done") {
Qt.quit()
} else if (command.text().trim() === "reload" && !reloaded) {
reloaded = true
background.setBackground(background.currentBackground, true)
settled.start()
}
}
}
}
@@ -0,0 +1,43 @@
import QtQuick
import Quickshell
import Quickshell.Io
import "services"
import "clone" as Clone
ShellRoot {
id: test
property var services: ({ "intro-test.background": background })
function firstPartyServiceFor(id) { return id === "omarchy.background" ? background : null }
PluginShellApi { id: facade; pluginId: "intro-test.background" }
Clone.Background { id: background; shell: facade }
BackgroundIntro { id: intro; host: test }
property bool stillReported: false
FileView { id: release; path: Quickshell.env("INTRO_TEST_RELEASE"); watchChanges: true; onFileChanged: reload() }
FileView { id: result; path: Quickshell.env("INTRO_TEST_RESULT"); atomicWrites: true }
Timer {
interval: 600
running: true
onTriggered: result.setText(JSON.stringify({
phase: "cover",
scoped: background.shell.pluginId === "intro-test.background",
privateCoordinator: background.shell.bootIntro === undefined,
selected: background.displayedBackground.endsWith("still.png"),
covered: intro.cover
}))
}
Timer {
interval: 100
running: true
repeat: true
onTriggered: {
if (release.text().trim() === "done") {
Qt.quit()
} else if (release.text().trim() === "captured" && !intro.cover && !intro.startupPending && !test.stillReported) {
test.stillReported = true
result.setText(JSON.stringify({ phase: "still", covered: intro.cover }))
}
}
}
}
@@ -0,0 +1,121 @@
import QtQuick
import Quickshell
import Quickshell.Io
import "services"
import "Commons" as Commons
ShellRoot {
id: test
property bool failed: false
property var services: ({})
function firstPartyServiceFor(id) { return services[id] || null }
function check(ok, message) {
if (!ok) {
failed = true
console.log("RESULT fail " + message)
}
}
QtObject { id: retainedBackground; property bool suspended: false }
BackgroundIntro { id: intro; host: test }
Process {
id: revealVideo
command: ["touch", Quickshell.env("INTRO_TEST_FRAME_READY")]
}
Timer {
interval: 300
running: true
onTriggered: {
test.check(intro.checked, "startup runs even when OWE left the background disabled for a video")
test.services = ({ "omarchy.background": retainedBackground })
intro.prepareTheme(Quickshell.env("INTRO_TEST_COVER"), "theme-one", Qt.btoa('background = "#123456"'), "")
test.check(intro.themeCoverStatus("theme-one") === "loading", "the cover waits for decoding and presentation")
test.check(intro.themeStatus("theme-one") === "pending", "app retints wait for the intro reveal")
test.check(!Qt.colorEqual(Commons.Color.background, "#123456"), "the palette waits for OWE's first frame")
intro.finishTheme("superseded-theme")
test.check(intro.themeToken === "theme-one", "an older intro cannot release the pending handoff")
}
}
Timer {
interval: 500
running: true
onTriggered: {
test.check(intro.cover, "the still stays covered while the launcher waits")
test.check(intro.themeCoverStatus("theme-one") === "ready", "the outgoing cover is presented before the shell is hidden")
retainedBackground.suspended = true
}
}
Timer {
interval: 600
running: true
onTriggered: {
test.check(intro.themeToken === "theme-one", "a leftover renderer still stays covered until video is revealed")
revealVideo.running = true
handoffDeadline = Date.now() + 3000
handoff.start()
}
}
property double handoffDeadline: 0
property bool openingFadeObserved: false
Connections {
target: intro
function onThemeTokenChanged() {
if (handoff.running && intro.themeToken === "") {
Qt.callLater(function() {
test.check(intro.themeStatus("theme-one") === "pending", "app retints also wait through the opening crossfade")
test.openingFadeObserved = true
})
}
}
}
Timer {
id: handoff
interval: 16
repeat: true
onTriggered: {
if (intro.themeToken || !test.openingFadeObserved) {
if (Date.now() >= test.handoffDeadline) {
test.check(false, "the ready video releases its cover before the deadline")
Qt.quit()
}
return
}
stop()
test.check(!intro.cover && intro.checked, "OWE taking the background releases the cover")
test.check(intro.themeToken === "" && Qt.colorEqual(Commons.Color.background, "#123456"), "first-frame handoff starts the palette and wallpaper fade together")
retainedBackground.suspended = false
Qt.callLater(function() { test.check(!intro.cover, "resuming the retained background cannot cover or retry playback") })
completionDeadline = Date.now() + 3000
completion.start()
}
}
property double completionDeadline: 0
Timer {
id: completion
interval: 16
repeat: true
onTriggered: {
if (intro.themeStatus("theme-one") !== "ready" || !intro.startupSettled) {
if (Date.now() >= test.completionDeadline) {
test.check(false, "the fade and launcher complete before the deadline")
Qt.quit()
}
return
}
stop()
test.check(intro.themeStatus("theme-one") === "ready", "the completed crossfade releases app retints")
intro.prepareTheme("", "failed-theme", Qt.btoa('background = "#654321"'), "")
intro.finishTheme("failed-theme")
test.check(Qt.colorEqual(Commons.Color.background, "#654321"), "failed playback still releases its pending palette")
intro.prepareTheme("", "cancelled-theme", Qt.btoa('background = "#abcdef"'), "")
intro.cancelTheme()
intro.finishTheme("cancelled-theme")
test.check(Qt.colorEqual(Commons.Color.background, "#654321") && !intro.themeToken, "a superseding theme cannot be overwritten by an older completion")
test.check(!intro.cover, "launcher completion leaves the still uncovered")
if (!test.failed) console.log("RESULT pass")
Qt.quit()
}
}
}
@@ -0,0 +1,36 @@
import QtQuick
import Quickshell
import qs.Commons
import qs.Commons as Commons
import "background" as BackgroundPlugin
ShellRoot {
id: shell
function firstPartyServiceFor(id) { return id === "omarchy.background" ? background : null }
BackgroundPlugin.Background { id: background }
// APPLY_THEME_FUNCTION
Timer {
interval: 600
running: true
onTriggered: {
var oldColors = Qt.btoa('accent = "#ff0000"\nbackground = "#000000"\nforeground = "#ffffff"\n')
var newColors = Qt.btoa('accent = "#123456"\nbackground = "#000000"\nforeground = "#ffffff"\n')
background.transitionBackgroundWithTheme("", "/missing-still.png", "/missing-still.png", oldColors, "")
shell.applyTheme(newColors, "")
}
}
Timer {
interval: 1300
running: true
onTriggered: {
if (Qt.colorEqual(Commons.Color.accent, "#123456")) {
console.log("RESULT pass")
} else {
console.log("RESULT fail previous colors returned: " + Commons.Color.accent)
}
Qt.quit()
}
}
}
@@ -0,0 +1,40 @@
import QtQuick
import Quickshell
import "services"
import "background" as BackgroundPlugin
ShellRoot {
id: test
property var services: ({ "omarchy.background": background })
property var bar: ({})
property bool failed: false
function firstPartyServiceFor(id) { return services[id] || null }
function check(ok, message) {
if (!ok) {
failed = true
console.log("RESULT fail " + message)
}
}
BackgroundPlugin.Background { id: background }
BackgroundIntro { id: intro; host: test }
Timer {
interval: 600
running: true
onTriggered: {
test.check(background.displayedBackground.endsWith("deleted.png"), "the missing wallpaper is selected")
test.check(!background.ready && intro.startupPending && intro.cover, "the failed image cannot release startup through readiness")
}
}
Timer {
interval: 11000
running: true
onTriggered: {
test.check(!background.ready, "the missing wallpaper never becomes ready")
test.check(!intro.startupPending && !intro.cover && intro.startupOpacity === 0, "the deadline fades the cover away despite the failed wallpaper")
if (!test.failed) console.log("RESULT pass")
Qt.quit()
}
}
}
@@ -0,0 +1,86 @@
import QtQuick
import Quickshell
import Quickshell.Io
import "services"
ShellRoot {
id: test
property var services: ({})
property var pluginRegistry: null
property var bar: null
property bool failed: false
function firstPartyServiceFor(id) { return services[id] || null }
function check(ok, message) {
if (!ok) {
failed = true
console.log("RESULT fail " + message)
}
}
QtObject {
id: registry
property var installedPlugins: ({ "omarchy.background": {} })
signal pluginsChanged()
function resolveEnabledId(id) { return id }
function isEnabled(id) { return false }
}
QtObject {
id: background
property bool suspended: false
property bool ready: false
}
BackgroundIntro { id: intro; host: test }
FileView { id: cursorLog; path: Quickshell.env("STARTUP_CURSOR_LOG"); printErrors: false }
Timer {
interval: 400
running: true
onTriggered: {
test.check(!intro.backgroundActive, "the plugin has not loaded yet")
test.check(intro.cover && !intro.themeBackground, "fresh startup does not prepare an outgoing still image")
test.check(intro.startupSettled, "the launcher has finished without an intro")
test.check(intro.startupPending && intro.startupOpacity === 1, "a fresh login hides the desktop until its media and bar are ready")
cursorLog.reload()
cursorLog.waitForJob()
test.check(!cursorLog.text().trim(), "startup does not restore the cursor while media is loading")
test.services = ({ "omarchy.background": background })
}
}
Timer {
interval: 600
running: true
onTriggered: {
test.check(intro.cover, "a loading plugin does not release the startup wallpaper")
background.ready = true
}
}
Timer {
interval: 800
running: true
onTriggered: {
test.check(!intro.cover && !intro.themeBackground, "a ready plugin releases the startup cover and its image")
test.check(intro.startupPending && intro.startupOpacity === 1, "a ready background alone cannot reveal an unready bar")
cursorLog.reload()
cursorLog.waitForJob()
test.check(!cursorLog.text().trim(), "startup does not restore the cursor before the bar is ready")
test.bar = ({})
}
}
Timer {
interval: 1400
running: true
onTriggered: {
test.check(!intro.startupPending && intro.startupOpacity === 0, "the desktop fades in after both the media and bar are ready")
cursorLog.reload()
cursorLog.waitForJob()
test.check(cursorLog.text().includes("omarchy_startup_cursor_restore()"), "the opening fade restores the cursor")
test.services = ({})
intro.cover = true
test.pluginRegistry = registry
registry.pluginsChanged()
test.check(!intro.cover, "a disabled background plugin does not leave a startup cover on screen")
if (!test.failed) console.log("RESULT pass")
Qt.quit()
}
}
}
@@ -198,16 +198,6 @@ ShellRoot {
root.assertTrue(root.commandCount("omarchy-capture-screenrecording --stop-recording") === 1, "Screen Recording left click stops active recording")
}
var dictation = root.createIndicator("Dictation")
if (dictation) {
dictation.moduleName = "Dictation"
root.injectBar(dictation)
dictation.triggerPress(Qt.LeftButton)
dictation.triggerPress(Qt.RightButton)
root.assertTrue(root.commandCount("omarchy-voxtype-config") === 2, "Dictation clicks run config command")
root.assertTrue(root.commandCount("omarchy-voxtype-model") === 0, "Dictation clicks do not run model command")
}
var stayAwake = root.createIndicator("StayAwake")
if (stayAwake) {
stayAwake.moduleName = "StayAwake"
@@ -2,6 +2,7 @@ import QtQuick
import Quickshell
import Quickshell.Networking
import qs.Commons
import qs.Commons as Commons
import "mocks"
import "network" as Network
@@ -21,9 +22,9 @@ ShellRoot {
Network.Panel {
id: panel
bar: QtObject {
property color foreground: Color.foreground
property color barForeground: Color.foreground
property color urgent: Color.urgent
property color foreground: Commons.Color.foreground
property color barForeground: Commons.Color.foreground
property color urgent: Commons.Color.urgent
property string fontFamily: Style.font.family
property string position: "top"
property int barSize: 24
@@ -1,6 +1,7 @@
import QtQuick
import Quickshell
import qs.Commons
import qs.Commons as Commons
import "mocks"
import "network" as Network
import "network/Model.js" as Model
@@ -25,9 +26,9 @@ ShellRoot {
Network.Panel {
id: panel
bar: QtObject {
property color foreground: Color.foreground
property color barForeground: Color.foreground
property color urgent: Color.urgent
property color foreground: Commons.Color.foreground
property color barForeground: Commons.Color.foreground
property color urgent: Commons.Color.urgent
property string fontFamily: Style.font.family
property string position: "top"
property int barSize: 24
@@ -0,0 +1,25 @@
package.path = os.getenv("OMARCHY_PATH") .. "/?.lua;" .. package.path
o = {
shell_quote = function(value) return "'" .. value:gsub("'", "'\\''") .. "'" end,
launch = function(value) return value end,
}
local exec = hl.exec_cmd
hl.exec_cmd = function(command)
if command == "omarchy-launch-shell" then
local file = assert(io.open(os.getenv("CURSOR_TEST_STAGE") .. "/session", "w"))
file:write(os.getenv("WAYLAND_DISPLAY") .. "\n" .. os.getenv("HYPRLAND_INSTANCE_SIGNATURE"))
file:close()
exec("quickshell -p " .. o.shell_quote(os.getenv("CURSOR_TEST_STAGE")))
elseif command:match("^hyprctl ") then
exec(command)
end
end
require("default.hypr.autostart")
hl.config({
misc = { disable_hyprland_logo = true, disable_splash_rendering = true, background_color = "rgb(000000)", disable_watchdog_warning = true },
xwayland = { enabled = false },
cursor = { enable_hyprcursor = false },
})
hl.monitor({ output = "", mode = "640x480@60", position = "auto", scale = 1 })
hl.layer_rule({ match = { namespace = "omarchy-background" }, no_anim = true })
hl.bind("SUPER + Q", hl.dsp.exec_cmd("true"))
@@ -0,0 +1,38 @@
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import "services"
ShellRoot {
id: test
property var bar: ({})
property var services: ({ "omarchy.background": background })
function firstPartyServiceFor(id) { return background }
QtObject { id: background; property bool suspended: false; property bool ready: false }
BackgroundIntro {
id: intro
host: test
onStartupPendingChanged: if (!startupPending) phase.setText("revealed")
}
FileView {
id: release
path: Quickshell.env("CURSOR_TEST_STAGE") + "/release"
watchChanges: true
onLoaded: background.ready = text().trim() === "reveal"
onFileChanged: reload()
}
FileView {
id: phase
path: Quickshell.env("CURSOR_TEST_STAGE") + "/phase"
atomicWrites: true
}
PanelWindow {
anchors { top: true; bottom: true; left: true; right: true }
exclusionMode: ExclusionMode.Ignore
WlrLayershell.layer: WlrLayer.Bottom
mask: Region {}
color: "magenta"
}
Component.onCompleted: phase.setText("holding")
}
@@ -0,0 +1,105 @@
import os
import pathlib
import pwd
import signal
import shutil
import socket
import subprocess
import tempfile
import time
root = pathlib.Path(os.environ['ROOT'])
with tempfile.TemporaryDirectory(prefix='theme-ssh-') as directory:
stage = pathlib.Path(directory)
for name in ('host', 'identity'):
subprocess.run(['ssh-keygen', '-q', '-t', 'ed25519', '-N', '', '-f', str(stage / name)], check=True)
try:
with socket.socket() as port_probe:
port_probe.bind(('127.0.0.1', 0))
port = port_probe.getsockname()[1]
except PermissionError:
print('ok - sandbox blocks loopback sockets; skipping real SSH connection reuse # SKIP')
raise SystemExit(0)
remote = stage / 'remote'
remote.write_text('#!/bin/bash\ncat >>"' + str(stage / 'received') + '"\necho theme-received\n')
remote.chmod(0o700)
server_config = stage / 'sshd.conf'
server_config.write_text(f'''Port {port}
ListenAddress 127.0.0.1
HostKey {stage / 'host'}
PidFile {stage / 'server.pid'}
AuthorizedKeysFile {stage / 'identity.pub'}
PasswordAuthentication no
KbdInteractiveAuthentication no
UsePAM no
StrictModes no
AllowUsers {pwd.getpwuid(os.getuid()).pw_name}
LogLevel VERBOSE
ForceCommand /bin/bash {remote}
''')
host_key = (stage / 'host.pub').read_text().split()
(stage / 'known_hosts').write_text(f'[127.0.0.1]:{port} {host_key[0]} {host_key[1]}\n')
client_config = stage / 'ssh.conf'
client_config.write_text(f'''Host fixture
HostName 127.0.0.1
Port {port}
User {pwd.getpwuid(os.getuid()).pw_name}
IdentityFile {stage / 'identity'}
IdentityAgent none
IdentitiesOnly yes
StrictHostKeyChecking yes
UserKnownHostsFile {stage / 'known_hosts'}
''')
home = stage / 'home'
current = home / '.local/state/omarchy/current'
current.mkdir(parents=True)
toggles = home / '.local/state/omarchy/toggles'
toggles.mkdir()
(toggles / 'herdr-theme-sync').touch()
runtime = stage / 'run'
runtime.mkdir(mode=0o700)
stub_bin = stage / 'bin'
stub_bin.mkdir()
scripts = {
'herdr': "#!/bin/bash\nprintf 'id\\tfixture\\tfixture\\tdefault\\tenabled\\n'\n",
'ssh': '#!/bin/bash\nexec /usr/bin/ssh -F "' + str(client_config) + '" "$@"\n',
}
for name, content in scripts.items():
path = stub_bin / name
path.write_text(content)
path.chmod(0o700)
environment = {**os.environ, 'HOME': str(home), 'XDG_RUNTIME_DIR': str(runtime), 'PATH': str(stub_bin) + ':' + str(root / 'bin') + ':' + os.environ['PATH']}
log_path = stage / 'sshd.log'
with log_path.open('w') as log:
server = subprocess.Popen([shutil.which('sshd'), '-D', '-e', '-f', str(server_config)], stdout=log, stderr=log, start_new_session=True)
try:
deadline = time.monotonic() + 5
while True:
try:
with socket.create_connection(('127.0.0.1', port), timeout=0.1):
break
except OSError:
if server.poll() is not None and 'Missing privilege separation directory' in log_path.read_text():
print('ok - SSH server runtime directory is unavailable; skipping real SSH connection reuse # SKIP')
raise SystemExit(0)
assert server.poll() is None and time.monotonic() < deadline, log_path.read_text()
time.sleep(0.05)
for theme in ('tokyo-night', 'nord'):
(current / 'theme.name').write_text(theme + '\n')
result = subprocess.run([str(root / 'bin/omarchy-theme-set-herdr-machines')], env=environment, capture_output=True, text=True, timeout=10)
assert result.returncode == 0 and 'theme-received' in result.stdout, (result.stdout, result.stderr, log_path.read_text())
if theme == 'tokyo-night':
(stage / 'identity').rename(stage / 'identity-unavailable')
assert log_path.read_text().count('Accepted publickey') == 1, log_path.read_text()
received = (stage / 'received').read_text()
assert 'theme=tokyo-night' in received and 'theme=nord' in received
assert (runtime / 'omarchy-theme-sync').stat().st_mode & 0o777 == 0o700
lock = runtime / 'omarchy-theme-set-herdr-machines.lock'
assert subprocess.run(['flock', '-n', str(lock), 'true']).returncode == 0, 'SSH master retained the theme sync lock'
print('ok - two theme syncs authenticate once, even with the key removed before the second sync')
print('ok - persistent SSH master leaves the sync lock available')
finally:
subprocess.run(['/usr/bin/ssh', '-F', str(client_config), '-o', 'ControlPath=' + str(runtime / 'omarchy-theme-sync/%C'), '-O', 'exit', 'fixture'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=5)
if server.poll() is None:
os.killpg(server.pid, signal.SIGTERM)
server.wait(timeout=5)