Read cornerRadius from Hyprland instead of the quickshell-menu.json toggle

This commit is contained in:
Ryan Hughes
2026-05-17 23:31:47 -04:00
parent b1e3a23088
commit 64115a9cb4
8 changed files with 77 additions and 138 deletions
@@ -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 <round|sharp>` 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 <round|sharp>` 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 <round|sharp>` 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()
}
@@ -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
@@ -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
@@ -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
@@ -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 <sharp|round>` 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()
@@ -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