Skip to content

Sync upstream quattro through #18831 - #132

Merged
mark-groves merged 7 commits into
quattrofrom
cursor/upstream-changes-pr-6bac
Nov 14, 2026
Merged

mark-groves merged 7 commits into
quattrofrom
cursor/upstream-changes-pr-6bac

Conversation

@cursor

@cursor cursor Bot commented Nov 13, 2026

Copy link
Copy Markdown

What changes

Upstream quattro moved past omacom#18674 (ac6cb9c71), which is what #131 merged. Six commits replayed onto current quattro, through 6baca275b (translations, omacom#18831). No merge commits. Nothing skipped. One conflict, in the power-profile test. One follow-up drops the fork's parent-directory translation watch, which the new watcher replaces. Fork delta vs 6baca275b is 253 paths. The 250 paths upstream did not touch keep the same added and removed lines as quattro vs ac6cb9c71, except shell/Commons/ParentDirReload.qml, which this branch deletes. I18n.qml and Translations.qml now match upstream. Face, Grok Bot, Cursor, linux / linux-headers, and the dropped translation-sync workflow stay.

  • Snapdragon power profiles get a CPU floor (Give Snapdragon power profiles a CPU floor for bursty work omacom/omarchy#18745). schedutil raises a core's clock too slowly for a browser's bursts. A root service sets a utilisation floor (uclamp.min) on logged-in users' processes: 75% in balanced, 100% in performance, none otherwise. It applies the floor once it is listening, again when the profile changes, and again when someone logs in. If the D-Bus monitor stops, the service fails so systemd restarts it. Setup enables it only on Snapdragon (omarchy-hw-aarch64-qualcomm), and starts it on an image's first boot, where a newly enabled service would otherwise wait for the next boot. Migration 1794503281 does the same for an existing Snapdragon install. Other machines are untouched. List and set still read and write the profile through busctl. The floor reads the active profile with powerprofilesctl get.
  • Wine tray icons answer a double-click and a right-click (Make Wine tray icons respond to double-click and right-click omacom/omarchy#18597). Double-click runs the item's activate action, which is how Battle.net comes back from the tray. Right-click runs omarchy-tray-context-menu, which asks the app over StatusNotifierItem.ContextMenu to draw its own menu at the pointer. The pointer is converted with xrandr, so xorg-xrandr joins the base packages and migration 1794518371 installs it. Two items with the same id, or one that did not answer and might be another Wine app with that id, open nothing. The Battle.net window rule only floats now: the tray menu shares the launcher's title, so the old 1280x800 size was stretching the menu, and the launcher's fullscreen request is ignored. Maximize stays on its own binding.
  • Translation files are watched before they are reread (Watch translation files before rereading them, so no change is lost omacom/omarchy#18734). FileView.reload() reads the file and only then replaces its watcher, so a change in that gap was lost, and a watcher that is never reloaded stays on the inode it first saw. WatchedFile splits the two: a reader with no watch, and a watcher that is reloaded before the read. I18n and Translations read catalogs, the language selection, and the locale registry through it. The fork's ParentDirReload was covering the same gap by watching the parent directory and calling reload() on the file. After the replay that call landed on WatchedFile, which has no reload(). The follow-up removes ParentDirReload.
  • Wi-Fi rows stay in step with NetworkManager (Keep Wi-Fi rows in step with NetworkManager omacom/omarchy#18702). The rows were snapshots, rebuilt when the list of networks changed, when the panel opened, or when one of its own actions finished. A network connected, dropped, saved, or forgotten by anything else kept its old row until the panel was opened again. The panel now binds a key over every listed network's state and rebuilds when it changes, including networks with no row on screen and changes while the panel is closed. Identical rows stay in place, so a passphrase being typed keeps focus, and the cursor stays on its network through the re-sort. A hidden network's empty name is no longer the cursor's "no row". An action whose network is already in the asked-for state settles before the call, except the enterprise script, which still brings a profile up. A failed connect's reason, and its passphrase prompt, clear once that network connects and settles.
  • First boot asks what the installer asks, on the installer's screens (Ask at first boot what the installer asks, on the installer's screens omacom/omarchy#18783). Owner setup and the installer had drifted: the console font, gum's key hints, gum's colours without COLORTERM, and a first boot with no language step that asked for the account in another order and reviewed it in a table that split "English (US, Dvorak)" in two. The shared form now carries the language picker, the layout and timezone that follow from the language, the review table, the gum look, and a COLORTERM default. console-font.sh and console-font.py come over from the ISO, and terminus-font joins the base packages. The size is the kernel's own, 8x16 or 16x32, counted in whole 16x32 cells so asking again cannot flip it. A console left in the kernel's font stays in English, because that font cannot draw the translations. First boot asks language, keyboard, then timezone, username, password, and hostname. "No, change it" goes back to the keyboard. The language picked is written to /etc/omarchy/language once its locale is generated, which is what makes it the owner's desktop language. A locale that cannot be generated leaves the desktop in English, and a retry forgets what an earlier attempt seeded.
  • Translations through Update translations omacom/omarchy#18831, including the new first-boot strings.

The power-profile test conflict kept list and set off powerprofilesctl (they go through busctl) and took the floor's get queue, so the new assertion can step balanced, performance, and power-saver.

Verification

  • Cherry-pick of the six commits from 3f974d011 through 6baca275b applied onto quattro ab8aa8782. test/shell.d/powerprofiles-set-test.sh conflicted and was resolved as above. git diff --numstat of HEAD vs upstream 6baca275b is 253 paths. On the paths upstream did not touch, the added and removed line counts match quattro vs ac6cb9c71, apart from deleting ParentDirReload.qml. I18n.qml and Translations.qml match upstream. linux and linux-headers are still in the other-packages list. Face, Grok Bot, and Cursor are still in the menu. The translation-sync workflow is still absent. The English catalog still has the fork's Grok Bot and AUR-held strings. docs/i18n.md still says catalogs arrive with these syncs, and it takes the new first-boot sentence.
  • ./test/cli passed (133).
  • ./test/shell completed with the files this sync covers green: powerprofiles-set-test.sh (9, including the floor), setup-form-test.sh (31), i18n-test.sh (401, one structural skip), tray-test.sh (21). i18n-startup-test.sh, network-panel-runtime-test.sh, and tray-menu-test.sh skipped: no Quickshell and no Wayland compositor, so the live translation reload, the Wi-Fi rows, and the tray menu were not driven. luks-rekey-journal-test.sh skipped its volume runs (no cryptsetup).
  • provision-owner-keyboard-test.sh stopped on "the Georgian layout (ge) gets an XKB layout". This machine's /usr/share/systemd/kbd-model-map is 72 lines and has no ge row. Current systemd's map does (ge to ge,us). With that row bound over the host file, the same test passed (26). One skip: no readable VT, so the console-font size choice was not built.
  • Thirteen other files failed the same way on quattro ab8aa8782: missing mise, socat, or pacman-conf, Python compression, no systemd as init, systemd-tmpfiles without --inline, pidwait, the China timezone Asia/Chungking, the update lock, and no private XDG runtime. They are not part of this sync.
  • This checkout has no Omarchy session, so the tray menu, the Wi-Fi rows, the first-boot screens, and the CPU floor were not checked on a machine. No other sync was open.

Screenshots

No visible change: this checkout has no Omarchy session, so nothing was drawn here. The Wine tray menu, the Wi-Fi rows, and the first-boot language screen are visible on a machine; the tests above cover the behavior that can run here.

Open in Web View Automation 

dhh and others added 7 commits November 13, 2026 23:05
)

* Give Snapdragon power profiles a CPU floor for bursty work

schedutil raises a core's clock too slowly for a browser's bursts, so
Speedometer 3.1 scored 22 in balanced on a Zenbook A16, and holding every
core at max with the performance governor cost 2W at idle and likely
reset the machine on battery. A root service now sets a uclamp.min floor
on logged-in users' processes that follows the profile (75% balanced,
100% performance), re-applied on profile changes and logins. Balanced
scores 42 and performance 45.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Start the CPU floor on an image's first boot and restart a lost monitor

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Mark Groves <mark-groves@users.noreply.github.com>
…18597)

Double-clicking a Wine tray icon (Battle.net) now reopens its window, and right-clicking opens the app's own menu at the pointer. The Battle.net launcher rule only floats now, so the tray menu that shares its title isn't stretched to 1280x800, and it ignores the launcher's fullscreen request.

Fixes omacom#15057

Co-authored-by: Clément Rog <clem.rog@gmail.com>
Co-authored-by: Yarim Berreby <YarimBerreby@outlook.com>
…macom#18734)

* Log the i18n startup test's file events while it fails in CI

Temporary: the live scenario runs five times with Quickshell's FileView and Qt's file watcher debug logging on, and every write, delete and wait is marked in the same log, so a CI failure shows which event never arrived. It fails only on CI's slower VM and always at a step that deletes a watched file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Log less and repeat more while the i18n startup test is diagnosed

Qt's watcher logging slowed the shell enough that ten CI repetitions all passed. Keep only FileView's own lines and run the scenario twenty times.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep a translation file's watcher across reloads

FileView's reload() reads the file and only then replaces its watcher, disconnecting the old one. A change landing between the read and the new watcher went to a watcher already let go, and the new one started too late to see it, so the shell kept showing the old strings until the next change. A late event from one change reloads the file just as the next change lands, which is what the i18n startup test kept hitting on CI's slower VM: the language selection deleted during that reload, and the shell stayed Danish.

WatchedFile splits the two: a reader FileView with no watch, read synchronously as before, and a watcher FileView that is never reloaded and only tells the reader to. I18n and Translations read their catalogs, the language selection and the locale registry through it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Rewatch before rereading, and test a replace that keeps the old file alive

A watcher that is never reloaded stays on the inode it first saw. When the replaced file lives on under another name -- an editor's backup, a hard link -- a rename over it ends nothing Qt can see, so every later change was missed. WatchedFile now rebuilds the watch on each change and only then rereads, which keeps the ordering that closes the race: anything that changes after the read reaches a live watch. A path change rereads once both FileViews have moved, since they follow it in no set order.

The startup test drops its temporary diagnostics and gains that case: the language file is given a second name, replaced, and changed again. It fails every time on a watcher that is never reloaded, and two runs in five on quattro, which misses the replacement itself.

Co-Authored-By: Codex Medium <noreply@openai.com>
Co-Authored-By: Muse Wonder High <noreply@meta.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Omarchybot <317366263+omarchybot@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Codex Medium <noreply@openai.com>
Co-authored-by: Muse Wonder High <noreply@meta.com>
* Keep Wi-Fi rows in step with NetworkManager

The rows are primitive snapshots, rebuilt only when the list of networks changes, when the panel opens, or when one of its own actions completes. A listed network that connects, drops, is saved or is forgotten by anything else -- autoconnect, nmcli, another settings tool -- changes state without changing the list, so the rows kept showing the old state until the panel was reopened: a dropped network still "Connected", a connected one under Other Networks, a saved one asking for its password, a forgotten one under Known Networks.

The panel now binds a key over every listed network's state at the root and rebuilds the rows when it changes. Bound at the root, it also sees networks that have no delegate, so it replaces the per-row completion handlers, which missed rows scrolled out of view and everything while the panel was closed. The rebuild leaves identical rows in place, since a new model takes focus from a passphrase being typed, and keeps the cursor on its network through the re-sort. An action whose outcome already holds settles at once, where it used to wait for a change that never came and time out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Track the enterprise reconnect, and follow a hidden row

The immediate settle exists because Quickshell ignores connect() on a connected network and disconnect() on a disconnected one, so those calls can never signal. The enterprise script is different: it creates a profile and brings it up even when the network is already connected, so settling at once would drop its busy state and the failure it may report.

The cursor marked "no row" with "", which is also a hidden network's SSID, so a selected hidden row was left behind when the list re-sorted. It now uses null.

The fixture now drives a disconnect that completes only once stateChanging clears, which is the only thing keeping stateChanging in the key, and checks the in-flight connect is the one it started.

Co-Authored-By: Codex Medium <noreply@openai.com>
Co-Authored-By: Muse Wonder High <noreply@meta.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Drop a failed connect's reason once NetworkManager connects that network

A panel connect that fails or times out leaves its reason on the row. When NetworkManager later connects that network on its own -- the access point comes back, the radio returns -- no action is in flight, so nothing cleared it, and the row read "Timed out connecting" or "Network lost" under a connected header. checkActionCompletion now drops the failure once the network that failed reports connected, before its in-flight guard, and only for a failed connect, since a timed-out disconnect leaves the network connected. The root state key makes it run whenever that network's connected flag changes.

This is the fix proposed in omacom#15367.

Co-Authored-By: Alexander Holbreich <16252784+aholbreich@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Settle before acting, and clear a failure only once its network settles

An action whose network is already in the asked-for state now settles before its call is made instead of after. For connect(), connectWithPsk() and disconnect() nothing changes, since Quickshell ignores those calls then. For the enterprise script it does: it creates a profile and brings it up, so started against a live connection it would run untracked once the next rebuild saw the old link still connected, and a failure of it would be erased by that same link.

The failure clear now waits for the network to stop changing state, as the disconnect and forget checks already do, so a connection that is still coming up and then fails does not take the explanation with it. It also closes a passphrase reprompt opened for that network, which would otherwise sit open over a connected row.

Co-Authored-By: Codex Medium <noreply@openai.com>
Co-Authored-By: Muse Wonder High <noreply@meta.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Close only the completed network's passphrase prompt

A connect that settles closed whatever prompt was open. Now that a connect to an already-connected network settles before anything is asked, a stale row clicked while another network's prompt is open would throw away the passphrase being typed there.

Co-Authored-By: Muse Wonder High <noreply@meta.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Close a passphrase prompt once its network connects, error or not

The prompt was closed only from the failure clear, which needs the failure text. The row's failureTimer clears that text two seconds into a reprompt, so a reconnect after that left the prompt open over the connected network, as did one with no failure behind it at all. A prompt only opens for a network that is not connected, so once that network is connected and settled there is nothing left to ask.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Omarchybot <317366263+omarchybot@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Codex Medium <noreply@openai.com>
Co-authored-by: Muse Wonder High <noreply@meta.com>
Co-authored-by: Alexander Holbreich <16252784+aholbreich@users.noreply.github.com>
…omacom#18783)

* Ask at first boot what the installer asks, on the installer's screens

First-boot owner setup finishes an install prepared for another owner, and a factory reset, on a machine the installer has already drawn on. The two had drifted wherever a piece lived on the installer's side instead of in the files they share: the installer set the console in Terminus and first boot in whichever of three kbd fonts came nearest 48 rows; the installer turned gum's key hints off in its entry script and first boot showed them; the installer's login shell sets COLORTERM, so gum's purples reached the kernel as they are, and first boot, a systemd unit without it, got gum's own 16-colour matches, blue and red; and first boot had no language step, asked the account in another order, reviewed it in a comma-separated table that split "English (US, Dvorak)" in two, and said all of it in English.

The shared files now carry those pieces. setup-form.sh gains the language picker, what follows from the language (the form's text, the layout preselected, the timezone fallback, from the ISO's language-defaults.json), the review table, the gum look and the COLORTERM default. console-font.sh and console-font.py come over from the ISO, which can vendor them as it does setup-form.sh, and terminus-font joins the base packages; the size rule is the kernel's own between its 8x16 and 16x32 fonts, counted in whole 16x32 cells so that asking again once the font is set cannot flip the answer. A console left in the kernel's font, on a system without Terminus, keeps setup in English, since that font cannot draw the translations.

First boot asks language, keyboard, then timezone, username, password and hostname, and "No, change it" goes back to the keyboard, as in the installer. The language picked becomes the machine's preset in /etc/omarchy/language once its locale is generated, which finalize-user already turns into the owner's desktop language; a locale that cannot be generated leaves the desktop in English rather than failing setup, and a retry forgets what an earlier attempt seeded for the account. Its strings move to ownerSetup.* and setupForm.* in the English catalog for the sync workflow to translate.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>

* Keep a caller's keyboard preset when a language is picked

omarchy_form_use_language kept only the layout the install media's form-defaults named, so one a caller put in OMARCHY_FORM_KEYBOARD_DEFAULT before loading the form was replaced by the language's own, and with both set the file won over the environment it is documented to lose to. The preset is now whichever is in effect once the form has loaded.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>

* Keep the owner setup tests in one file

The language, account order and console font checks for first-boot setup move into provision-owner-keyboard-test.sh, which already holds the rest of that flow, as AGENTS.md asks.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.2 <noreply@anthropic.com>
Co-authored-by: Codex XHigh <noreply@openai.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
WatchedFile rebuilds its watch before rereading, which is the gap ParentDirReload covered. The directory watch called reload() on WatchedFile, and WatchedFile has no such function.

Co-authored-by: Mark Groves <mark-groves@users.noreply.github.com>
@mark-groves
mark-groves merged commit 1141aef into quattro Nov 14, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants