From 64115a9cb48f94fd23d32fd368abe95f78d9738f Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Sun, 17 May 2026 23:31:47 -0400 Subject: [PATCH] Read cornerRadius from Hyprland instead of the quickshell-menu.json toggle --- bin/omarchy-style-corners | 8 ++- bin/omarchy-style-corners-quickshell | 33 +++------ .../omarchy-shell/Commons/Style.qml | 72 +++++++++++++++---- .../clipboard-picker/ClipboardPicker.qml | 20 +----- .../plugins/emoji-picker/EmojiPicker.qml | 20 +----- .../omarchy-shell/plugins/menu/Menu.qml | 19 +---- .../plugins/notifications/Service.qml | 24 +------ .../plugins/polkit/PolkitAgent.qml | 19 +---- 8 files changed, 77 insertions(+), 138 deletions(-) diff --git a/bin/omarchy-style-corners b/bin/omarchy-style-corners index af71bde1..fdf8abe5 100755 --- a/bin/omarchy-style-corners +++ b/bin/omarchy-style-corners @@ -1,6 +1,6 @@ #!/bin/bash -# omarchy:summary=Set Hyprland, Hyprlock, Walker, and Quickshell (bar, menu, notifications) corners to sharp or round +# omarchy:summary=Set Hyprland, Hyprlock, and Walker corners to sharp or round (the shell mirrors Hyprland) # omarchy:args= # omarchy:examples=omarchy style corners round | omarchy style corners sharp @@ -9,10 +9,14 @@ if [[ $1 != "sharp" && $1 != "round" ]]; then exit 1 fi +# The shell tracks Hyprland's `decoration:rounding` directly via +# Quickshell's qs.Commons.Style singleton, so we no longer write a +# parallel quickshell-menu.json. omarchy-style-corners-quickshell is +# retained for back-compat but is now a no-op trigger that nudges the +# shell to re-poll, so old callers stay quiet. omarchy-style-corners-hyprland "$1" omarchy-style-corners-hyprlock "$1" omarchy-style-corners-walker "$1" -omarchy-style-corners-quickshell "$1" case $1 in sharp) omarchy-notification-send "Sharp corners enabled" -g 󰝣 ;; diff --git a/bin/omarchy-style-corners-quickshell b/bin/omarchy-style-corners-quickshell index 8023bdbc..46cb0932 100755 --- a/bin/omarchy-style-corners-quickshell +++ b/bin/omarchy-style-corners-quickshell @@ -1,36 +1,19 @@ #!/bin/bash -# omarchy:summary=Set or toggle corner radius for the omarchy-shell menu and bar settings panel +# omarchy:summary=No-op shim; the shell now mirrors Hyprland's decoration:rounding directly # omarchy:args=[toggle|sharp|round] # omarchy:examples=omarchy style corners quickshell toggle | omarchy style corners quickshell round | omarchy style corners quickshell sharp -STYLE_FILE="$HOME/.local/state/omarchy/toggles/quickshell-menu.json" - -current_radius() { - [[ -f $STYLE_FILE ]] || { echo 0; return; } - local r - r=$(grep -oE '"radius"[[:space:]]*:[[:space:]]*[0-9]+' "$STYLE_FILE" | grep -oE '[0-9]+$') - echo "${r:-0}" -} - -set_radius() { - local radius="$1" - mkdir -p "$(dirname "$STYLE_FILE")" - printf '{ "radius": %s }\n' "$radius" >"$STYLE_FILE" -} +# qs.Commons.Style reads decoration:rounding from hyprctl and watches the +# theme name + rounded-corners toggle files for changes. There is no +# separate quickshell-menu.json to write anymore. This shim stays around +# so anyone still calling the old subcommand (or the dispatcher in +# omarchy-style-corners) doesn't error out. case "${1:-toggle}" in - round) set_radius 6 ;; - sharp) set_radius 0 ;; - toggle) - if (( $(current_radius) > 0 )); then - set_radius 0 - else - set_radius 6 - fi - ;; + round|sharp|toggle) exit 0 ;; *) - echo "Usage: omarchy-style-corners-quickshell [toggle|sharp|round]" + echo "Usage: omarchy-style-corners-quickshell [toggle|sharp|round]" >&2 exit 1 ;; esac diff --git a/default/quickshell/omarchy-shell/Commons/Style.qml b/default/quickshell/omarchy-shell/Commons/Style.qml index 5ab404cc..415f8cb5 100644 --- a/default/quickshell/omarchy-shell/Commons/Style.qml +++ b/default/quickshell/omarchy-shell/Commons/Style.qml @@ -8,9 +8,16 @@ import Quickshell.Io // every panel surface and qs.Ui component should bind to so they stay // in sync as the user toggles round/sharp corners or as themes change. // -// `cornerRadius` is mirrored from ~/.local/state/omarchy/toggles/quickshell-menu.json. -// `omarchy style corners ` writes that file; we watch it and -// hot-reload the binding here so every consumer rerenders. +// `cornerRadius` mirrors Hyprland's `decoration:rounding`. Themes ship +// their own rounding via theme/hyprland.lua; the user toggle via +// `omarchy style corners ` flips Hyprland's flag file +// and Hyprland's auto-reload pushes the new value out. The shell picks +// up the change here by re-running `hyprctl getoption` whenever either +// of those input files changes. +// +// Single source of truth lives in Hyprland; the shell follows. That +// means a theme that ships `rounding = 10` gives us 10px panels by +// default, and the round/sharp user toggle still works on top of it. QtObject { id: root @@ -29,23 +36,60 @@ QtObject { // value PillButton was already painting before promotion. readonly property color hotFill: Qt.rgba(Color.foreground.r, Color.foreground.g, Color.foreground.b, 0.12) - function loadStyleState(raw) { + function refresh() { + hyprctlProc.running = true + } + + function applyRoundingJson(raw) { try { - var s = JSON.parse(raw || "{}") - var n = Number(s.radius) - cornerRadius = isFinite(n) ? n : 0 + var json = JSON.parse(raw || "{}") + var n = Number(json.int) + if (isFinite(n) && n >= 0) cornerRadius = n } catch (e) { - cornerRadius = 0 + // hyprctl missing / Hyprland not running — leave the previous value. } } - property FileView styleStateFile: FileView { - id: styleStateFile - path: Quickshell.env("HOME") + "/.local/state/omarchy/toggles/quickshell-menu.json" + property Process hyprctlProc: Process { + id: hyprctlProc + command: ["hyprctl", "-j", "getoption", "decoration:rounding"] + stdout: StdioCollector { + waitForEnd: true + onStreamFinished: root.applyRoundingJson(text) + } + } + + // Re-poll Hyprland a beat after either input file changes. Hyprland's + // auto-reload runs asynchronously when its sourced .lua files change, + // so racing it with an immediate hyprctl gives the old value. 200ms is + // generous enough for Hyprland to settle without being user-visible. + property Timer refreshTimer: Timer { + id: refreshTimer + interval: 200 + repeat: false + onTriggered: root.refresh() + } + + // The theme name flips whenever `omarchy-theme-set` swaps the theme/ + // symlink; that's when theme/hyprland.lua's `rounding` value changes. + property FileView themeNameFile: FileView { + path: Quickshell.env("HOME") + "/.config/omarchy/current/theme.name" watchChanges: true printErrors: false - onLoaded: root.loadStyleState(text()) - onLoadFailed: root.loadStyleState("") - onFileChanged: reload() + onFileChanged: refreshTimer.restart() } + + // `omarchy style corners ` creates or removes this flag file. + // Hyprland reloads its config when sourced files change, then hyprctl + // reflects the new effective rounding value. + property FileView roundedCornersToggle: FileView { + path: Quickshell.env("HOME") + "/.local/state/omarchy/toggles/hypr/rounded-corners.lua" + watchChanges: true + printErrors: false + onFileChanged: refreshTimer.restart() + onLoaded: refreshTimer.restart() + onLoadFailed: refreshTimer.restart() + } + + Component.onCompleted: refresh() } diff --git a/default/quickshell/omarchy-shell/plugins/clipboard-picker/ClipboardPicker.qml b/default/quickshell/omarchy-shell/plugins/clipboard-picker/ClipboardPicker.qml index da7c3293..d1382fe5 100644 --- a/default/quickshell/omarchy-shell/plugins/clipboard-picker/ClipboardPicker.qml +++ b/default/quickshell/omarchy-shell/plugins/clipboard-picker/ClipboardPicker.qml @@ -21,10 +21,8 @@ Item { property color background: Color.menu.background property color foreground: Color.menu.text property color border: foreground - property int cornerRadius: 0 + readonly property int cornerRadius: Style.cornerRadius property string fontFamily: Quickshell.env("OMARCHY_MENU_FONT") || "monospace" - property string styleFile: Quickshell.env("OMARCHY_MENU_STYLE_FILE") || (Quickshell.env("HOME") + "/.local/state/omarchy/toggles/quickshell-menu.json") - property int contentMargin: 18 property int headerHeight: 34 property int contentSpacing: 6 @@ -122,14 +120,6 @@ Item { var escId = identifier.replace(/'/g, "'\\''") Quickshell.execDetached(["bash", "-lc", "elephant activate 'clipboard;" + escId + ";copy;;'; sleep 0.15; wtype -M shift -k Insert -m shift 2>/dev/null || true"]) } - - function loadStyle(raw) { - try { - var style = JSON.parse(raw || "{}") - root.cornerRadius = Number(style.radius || 0) - } catch (e) {} - } - ListModel { id: displayModel } Process { @@ -163,14 +153,6 @@ Item { function toggle(): string { root.toggle(); return "ok" } function ping(): string { return "ok" } } - - FileView { - path: root.styleFile - watchChanges: true - onLoaded: root.loadStyle(text()) - onFileChanged: { reload(); root.loadStyle(text()) } - } - PanelWindow { id: panel visible: root.opened diff --git a/default/quickshell/omarchy-shell/plugins/emoji-picker/EmojiPicker.qml b/default/quickshell/omarchy-shell/plugins/emoji-picker/EmojiPicker.qml index 56035bed..39fbff0d 100644 --- a/default/quickshell/omarchy-shell/plugins/emoji-picker/EmojiPicker.qml +++ b/default/quickshell/omarchy-shell/plugins/emoji-picker/EmojiPicker.qml @@ -22,10 +22,8 @@ Item { property color background: Color.menu.background property color foreground: Color.menu.text property color border: foreground - property int cornerRadius: 0 + readonly property int cornerRadius: Style.cornerRadius property string fontFamily: Quickshell.env("OMARCHY_MENU_FONT") || "monospace" - property string styleFile: Quickshell.env("OMARCHY_MENU_STYLE_FILE") || (Quickshell.env("HOME") + "/.local/state/omarchy/toggles/quickshell-menu.json") - property int contentMargin: 18 property int headerHeight: 34 property int contentSpacing: 6 @@ -143,14 +141,6 @@ Item { var escEmoji = emoji.replace(/'/g, "'\\''") Quickshell.execDetached(["bash", "-lc", "wl-copy '" + escEmoji + "'; sleep 0.15; wtype '" + escEmoji + "' 2>/dev/null || true"]) } - - function loadStyle(raw) { - try { - var style = JSON.parse(raw || "{}") - root.cornerRadius = Number(style.radius || 0) - } catch (e) {} - } - ListModel { id: displayModel } IpcHandler { @@ -165,14 +155,6 @@ Item { path: root.omarchyPath + "/default/quickshell/omarchy-shell/plugins/emoji-picker/emojis.json" onLoaded: root.loadEmojis(text()) } - - FileView { - path: root.styleFile - watchChanges: true - onLoaded: root.loadStyle(text()) - onFileChanged: { reload(); root.loadStyle(text()) } - } - PanelWindow { id: panel visible: root.opened diff --git a/default/quickshell/omarchy-shell/plugins/menu/Menu.qml b/default/quickshell/omarchy-shell/plugins/menu/Menu.qml index 318b01e9..1231c456 100644 --- a/default/quickshell/omarchy-shell/plugins/menu/Menu.qml +++ b/default/quickshell/omarchy-shell/plugins/menu/Menu.qml @@ -32,7 +32,6 @@ Item { } property string fontFamily: Quickshell.env("OMARCHY_MENU_FONT") || "monospace" - property string styleFile: Quickshell.env("OMARCHY_MENU_STYLE_FILE") || (Quickshell.env("HOME") + "/.local/state/omarchy/toggles/quickshell-menu.json") // JSONC menu definitions. The shell parses both at startup and merges // the user file on top of the defaults, so the keybind → IPC → visible // path doesn't have to shell out to bash + jq on every open. @@ -57,7 +56,7 @@ Item { property color background: Color.menu.background property color foreground: Color.menu.text property color border: foreground - property int cornerRadius: 0 + readonly property int cornerRadius: Style.cornerRadius property int contentMargin: 18 property int headerHeight: 34 property int contentSpacing: 6 @@ -613,14 +612,6 @@ Item { Qt.callLater(function() { keyCatcher.forceActiveFocus() }) } - - function loadStyle(raw) { - try { - var style = JSON.parse(raw || "{}") - root.cornerRadius = Number(style.radius || 0) - } catch (e) {} - } - ListModel { id: displayModel } // ----------------------------------------------------------- IPC surface @@ -788,14 +779,6 @@ Item { if (root.opened) root.rebuildDisplay() } } - - FileView { - path: root.styleFile - watchChanges: true - onLoaded: root.loadStyle(text()) - onFileChanged: { reload(); root.loadStyle(text()) } - } - PanelWindow { id: panel visible: root.opened && root.rowsLoaded diff --git a/default/quickshell/omarchy-shell/plugins/notifications/Service.qml b/default/quickshell/omarchy-shell/plugins/notifications/Service.qml index db5f0044..5d5ca495 100644 --- a/default/quickshell/omarchy-shell/plugins/notifications/Service.qml +++ b/default/quickshell/omarchy-shell/plugins/notifications/Service.qml @@ -32,13 +32,10 @@ Item { // ~/.cache where regeneratable artifacts belong. readonly property string cacheDir: home + "/.cache/omarchy/" readonly property string imageCacheDir: cacheDir + "notification-images/" - readonly property string styleStatePath: home + "/.local/state/omarchy/toggles/quickshell-menu.json" - // Corner radius is shared with omarchy-shell menu and bar settings panel — // `omarchy style corners ` writes this file once and every // surface reads it. Default 0 for sharp corners. - property int cornerRadius: 0 - + readonly property int cornerRadius: Style.cornerRadius // Surfaces anchor relative to the omarchy bar so popups and history land // alongside the other shell panels rather than on top of the bar itself. // Falls back to the bar's default size (26 horizontal / 28 vertical) when @@ -49,25 +46,6 @@ Item { readonly property int liveBarSize: shell && shell.bar && !shell.bar.barHidden ? Math.max(0, shell.bar.barSize) : defaultBarSize readonly property int barClearance: liveBarSize + 12 - function loadStyleState(raw) { - try { - var parsed = JSON.parse(raw || "{}") - var n = Number(parsed.radius) - cornerRadius = isFinite(n) && n >= 0 ? n : 0 - } catch (e) { - cornerRadius = 0 - } - } - - FileView { - path: service.styleStatePath - watchChanges: true - printErrors: false - onLoaded: service.loadStyleState(text()) - onFileChanged: reload() - } - - // Fired by IPC (`omarchy-shell-ipc notifications showHistory`) so the // bar widget can drop its PopupCard from the same anchor a click would. signal historyOpenRequested() diff --git a/default/quickshell/omarchy-shell/plugins/polkit/PolkitAgent.qml b/default/quickshell/omarchy-shell/plugins/polkit/PolkitAgent.qml index 5ad4f063..9c2e0db2 100644 --- a/default/quickshell/omarchy-shell/plugins/polkit/PolkitAgent.qml +++ b/default/quickshell/omarchy-shell/plugins/polkit/PolkitAgent.qml @@ -13,12 +13,11 @@ Item { property var manifest: null property string fontFamily: Quickshell.env("OMARCHY_MENU_FONT") || "monospace" - property string styleFile: Quickshell.env("OMARCHY_MENU_STYLE_FILE") || (Quickshell.env("HOME") + "/.local/state/omarchy/toggles/quickshell-menu.json") property color accent: Color.accent property color background: Color.menu.background property color foreground: Color.menu.text property color border: foreground - property int cornerRadius: 0 + readonly property int cornerRadius: Style.cornerRadius property int contentMargin: 18 property int contentSpacing: 12 property int fieldHeight: 42 @@ -43,14 +42,6 @@ Item { function withAlpha(color, alpha) { return Qt.rgba(color.r, color.g, color.b, alpha) } - - function loadStyle(raw) { - try { - var style = JSON.parse(raw || "{}") - root.cornerRadius = Number(style.radius || 0) - } catch (e) {} - } - function messageText() { return "Authentication is needed..." } @@ -164,14 +155,6 @@ Item { NumberAnimation { target: root; property: "shakeOffset"; to: 8; duration: 50; easing.type: Easing.InOutQuad } NumberAnimation { target: root; property: "shakeOffset"; to: 0; duration: 55; easing.type: Easing.OutQuad } } - - FileView { - path: root.styleFile - watchChanges: true - onLoaded: root.loadStyle(text()) - onFileChanged: { reload(); root.loadStyle(text()) } - } - FileView { path: "/etc/pam.d/polkit-1" watchChanges: true