Remove dead code

This commit is contained in:
David Heinemeier Hansson
2026-05-19 10:50:36 +02:00
parent 8cd9e34294
commit 8fa463975a
36 changed files with 130 additions and 309 deletions
+4 -5
View File
@@ -17,7 +17,6 @@ first call.
"author": "You", "author": "You",
"description": "A clock that does cool things", "description": "A clock that does cool things",
"kinds": ["bar-widget"], "kinds": ["bar-widget"],
"activation": "on-demand",
"entryPoints": { "barWidget": "Widget.qml" } "entryPoints": { "barWidget": "Widget.qml" }
} }
``` ```
@@ -32,9 +31,9 @@ first call.
| `menu` | Summoned menu surface | | `menu` | Summoned menu surface |
| `service` | Headless singleton, no UI | | `service` | Headless singleton, no UI |
`activation` is `persistent` (loaded at startup) or `on-demand` Panels, overlays, and menus are loaded when summoned. Plugins can set
(loaded by `shell summon`, unloaded by `shell hide`). On-demand `keepLoaded: true` to survive between summons. First-party services are
plugins can set `keepLoaded: true` to survive between summons. loaded at startup.
Full schema: [`shell/services/PluginRegistry.qml`](../shell/services/PluginRegistry.qml). Full schema: [`shell/services/PluginRegistry.qml`](../shell/services/PluginRegistry.qml).
@@ -91,7 +90,7 @@ Rules:
bar widgets, `plugins[]` for everything else. bar widgets, `plugins[]` for everything else.
2. Settings are inline on the entry. No `config:` sub-object, no 2. Settings are inline on the entry. No `config:` sub-object, no
merge layers. merge layers.
3. Enabled ⇔ present. 3. Third-party enabled ⇔ present; first-party plugins are always enabled.
4. `allowMultiple: true` in the manifest permits multiple instances. 4. `allowMultiple: true` in the manifest permits multiple instances.
5. `version: 1` is required. 5. `version: 1` is required.
+9 -13
View File
@@ -52,7 +52,6 @@ shell should load it. Minimal example:
"author": "You", "author": "You",
"description": "A clock that does cool things", "description": "A clock that does cool things",
"kinds": ["bar-widget"], "kinds": ["bar-widget"],
"activation": "on-demand",
"entryPoints": { "barWidget": "Widget.qml" }, "entryPoints": { "barWidget": "Widget.qml" },
"barWidget": { "barWidget": {
"displayName": "Cool clock", "displayName": "Cool clock",
@@ -77,11 +76,10 @@ Supported `kinds`:
| `service` | A headless singleton, no UI | | `service` | A headless singleton, no UI |
| `bar` | Reserved for the first-party bar host (`omarchy.bar`). Third-party plugins should ship `bar-widget`s; they do not replace the host bar. | | `bar` | Reserved for the first-party bar host (`omarchy.bar`). Third-party plugins should ship `bar-widget`s; they do not replace the host bar. |
`activation` is either `persistent` (loaded on startup, never unloaded) or Panels, overlays, and menus are loaded when summoned. Plugins that need
`on-demand` (loaded by `shell summon <id>` and unloaded by `shell hide`). to outlive a single summon can set `keepLoaded: true` (e.g. the image
Plugins that need to outlive a single summon can set `keepLoaded: true` picker keeps its overlay window mounted between summons). First-party
(e.g. the image picker keeps its overlay window mounted between services are loaded at startup.
summons).
The full schema lives in `services/PluginRegistry.qml`. The full schema lives in `services/PluginRegistry.qml`.
@@ -176,10 +174,7 @@ rewrites the `bar` subtree from the current `shell-defaults.json`.
] ]
} }
}, },
"plugins": [ "plugins": []
{ "id": "omarchy.settings" },
{ "id": "omarchy.image-picker" }
]
} }
``` ```
@@ -191,9 +186,10 @@ rewrites the `bar` subtree from the current `shell-defaults.json`.
2. **Settings are inline on the entry.** No `config:` sub-object, no 2. **Settings are inline on the entry.** No `config:` sub-object, no
separate per-plugin settings file, no merge layers. The fields on each separate per-plugin settings file, no merge layers. The fields on each
entry are the values the plugin sees. entry are the values the plugin sees.
3. **Enabled ⇔ present.** A plugin is enabled iff its id appears somewhere 3. **Third-party enabled ⇔ present.** A third-party plugin is enabled iff
in shell.json. For bar widgets, the bar settings UI adds/removes layout its id appears somewhere in shell.json. For bar widgets, the bar
entries; other plugin kinds are enabled with the shell IPC. settings UI adds/removes layout entries; other plugin kinds are enabled
with the shell IPC. First-party plugins are always enabled.
4. **Multiple instances** are allowed when a manifest sets 4. **Multiple instances** are allowed when a manifest sets
`allowMultiple: true`. Each instance is independent — e.g. two clocks `allowMultiple: true`. Each instance is independent — e.g. two clocks
in different timezones are just two `{"id":"calendar", "timezone": ...}` in different timezones are just two `{"id":"calendar", "timezone": ...}`
+1 -1
View File
@@ -2,7 +2,7 @@ import QtQuick
// Drop-in key dispatcher for keyboard-driven panels. Wraps panel content // Drop-in key dispatcher for keyboard-driven panels. Wraps panel content
// and emits semantic signals so each panel keeps its own state machine // and emits semantic signals so each panel keeps its own state machine
// (focusSection, selectedIndex, activation rules) while the boilerplate // (focusSection, selectedIndex, action rules) while the boilerplate
// key handling lives here. // key handling lives here.
// //
// Usage: // Usage:
+14 -13
View File
@@ -1,24 +1,25 @@
# First-party plugins # First-party plugins
These plugins ship with Omarchy and are loaded by the shell at startup. These plugins ship with Omarchy and are discovered by the shell at startup.
They use the same `manifest.json` contract as third-party plugins; the They use the same `manifest.json` contract as third-party plugins; the
only difference is that the shell flags them with `__isFirstParty: true` only difference is that the shell flags them with `__isFirstParty: true`
so they cannot be disabled. so they are always enabled. Services and keep-loaded panels are mounted at
startup; other panels, overlays, and menus are loaded on demand.
User-installed plugins live alongside these conceptually but on disk under User-installed plugins live alongside these conceptually but on disk under
`~/.config/omarchy/plugins/<plugin-id>/` rather than in this directory. `~/.config/omarchy/plugins/<plugin-id>/` rather than in this directory.
| Plugin | id | kinds | activation | entry point | | Plugin | id | kinds | entry point |
|---------------|-------------------------|-----------|------------|-------------------------------------| |---------------|---------------------------|-----------|---------------------------------------|
| Bar | `omarchy.bar` | `bar` | persistent | `bar/Bar.qml` | | Bar | `omarchy.bar` | `bar` | `bar/Bar.qml` |
| Bar settings | `omarchy.settings` | `panel` | on-demand | `settings/SettingsPanel.qml` | | Bar settings | `omarchy.settings` | `panel` | `settings/SettingsPanel.qml` |
| Image picker | `omarchy.image-picker` | `overlay` | on-demand | `image-picker/ImagePicker.qml` | | Image picker | `omarchy.image-picker` | `overlay` | `image-picker/ImagePicker.qml` |
| Emoji picker | `omarchy.emoji-picker` | `overlay` | on-demand | `emoji-picker/EmojiPicker.qml` | | Emoji picker | `omarchy.emoji-picker` | `overlay` | `emoji-picker/EmojiPicker.qml` |
| Clipboard mgr | `omarchy.clipboard-picker`| `overlay` | on-demand | `clipboard-picker/ClipboardPicker.qml`| | Clipboard mgr | `omarchy.clipboard-picker`| `overlay` | `clipboard-picker/ClipboardPicker.qml`|
| Omarchy menu | `omarchy.menu` | `menu` | on-demand | `menu/Menu.qml` | | Omarchy menu | `omarchy.menu` | `menu` | `menu/Menu.qml` |
| Notifications | `omarchy.notifications` | `service` | persistent | `notifications/Service.qml` | | Notifications | `omarchy.notifications` | `service` | `notifications/Service.qml` |
| OSD | `omarchy.osd` | `panel` | persistent | `osd/Osd.qml` | | OSD | `omarchy.osd` | `panel` | `osd/Osd.qml` |
| Polkit agent | `omarchy.polkit` | `service` | persistent | `polkit/PolkitAgent.qml` | | Polkit agent | `omarchy.polkit` | `service` | `polkit/PolkitAgent.qml` |
## Bar ## Bar
-4
View File
@@ -9,10 +9,6 @@ import qs.Commons as NoctaliaCommons
Item { Item {
id: root id: root
property string omarchyPath: ""
property var shell: null
property var manifest: null
readonly property string home: Quickshell.env("HOME") readonly property string home: Quickshell.env("HOME")
readonly property string currentBackgroundLink: home + "/.config/omarchy/current/background" readonly property string currentBackgroundLink: home + "/.config/omarchy/current/background"
+6 -3
View File
@@ -5,7 +5,10 @@
"version": "1.0.0", "version": "1.0.0",
"author": "Omarchy", "author": "Omarchy",
"description": "Desktop background renderer with click handling and transitions", "description": "Desktop background renderer with click handling and transitions",
"kinds": ["service"], "kinds": [
"activation": "startup", "service"
"entryPoints": { "service": "Background.qml" } ],
"entryPoints": {
"service": "Background.qml"
}
} }
+10 -13
View File
@@ -222,6 +222,14 @@ Item {
return index === -1 ? [] : entries.slice(index + 1) return index === -1 ? [] : entries.slice(index + 1)
} }
function canonicalWidgetId(name) {
switch (String(name)) {
case "idle": return "idleInhibitor"
case "weatherFlyout": return "weather"
default: return String(name)
}
}
function builtinModuleComponent(name) { function builtinModuleComponent(name) {
switch (String(name)) { switch (String(name)) {
case "omarchy": return omarchyModuleComponent case "omarchy": return omarchyModuleComponent
@@ -459,18 +467,6 @@ Item {
return ids return ids
} }
function activeTrayItemCount() {
var count = 0
var values = SystemTray.items.values
for (var i = 0; i < values.length; i++) {
if (values[i].status !== Status.Passive)
count++
}
return count
}
function trayIconSource(icon) { function trayIconSource(icon) {
var value = String(icon || "") var value = String(icon || "")
var marker = "?path=" var marker = "?path="
@@ -939,7 +935,8 @@ Item {
readonly property var registryComponent: { readonly property var registryComponent: {
var w = root.barWidgetRegistry.widgets var w = root.barWidgetRegistry.widgets
if (customType || builtinComponent) return null if (customType || builtinComponent) return null
return w[moduleName] ? w[moduleName].component : null var registryName = root.canonicalWidgetId(moduleName)
return w[registryName] ? w[registryName].component : null
} }
readonly property bool qmlCustom: customType === "qml" readonly property bool qmlCustom: customType === "qml"
readonly property bool commandCustom: customType === "command" readonly property bool commandCustom: customType === "command"
+1 -2
View File
@@ -5,10 +5,9 @@ shipped as a first-party plugin of [`omarchy-shell`](../../README.md), the
long-running shell host. The bar is mounted at startup and lives inside long-running shell host. The bar is mounted at startup and lives inside
the shell for its whole session. the shell for its whole session.
- `manifest.json` declares the plugin (`id: omarchy.bar`, `kind: bar`, `activation: persistent`) and points at `Bar.qml` as the entry point. - `manifest.json` declares the plugin (`id: omarchy.bar`, `kind: bar`) and points at `Bar.qml` as the entry point.
- `Bar.qml` is Omarchy-owned bar engine code, loaded by the omarchy-shell host. Users should not edit it directly. - `Bar.qml` is Omarchy-owned bar engine code, loaded by the omarchy-shell host. Users should not edit it directly.
- `widgets/` holds first-party widgets — modular, interactive components shipped with Omarchy. - `widgets/` holds first-party widgets — modular, interactive components shipped with Omarchy.
- `common/` holds shared QML helpers (buttons, sliders, popup cards).
- The bar receives its config from the host shell as a `barConfig` property; the host loads it from `~/.config/omarchy/shell.json` (or `shell-defaults.json` when the user has no file). - The bar receives its config from the host shell as a `barConfig` property; the host loads it from `~/.config/omarchy/shell.json` (or `shell-defaults.json` when the user has no file).
- `omarchy-style-bar-position` updates only the user shell.json file. - `omarchy-style-bar-position` updates only the user shell.json file.
+6 -3
View File
@@ -5,7 +5,10 @@
"version": "1.0.0", "version": "1.0.0",
"author": "Omarchy", "author": "Omarchy",
"description": "Status bar with widgets", "description": "Status bar with widgets",
"kinds": ["bar"], "kinds": [
"activation": "persistent", "bar"
"entryPoints": { "bar": "Bar.qml" } ],
"entryPoints": {
"bar": "Bar.qml"
}
} }
+1 -13
View File
@@ -123,7 +123,7 @@ Item {
var d = displays[selectedIndex] var d = displays[selectedIndex]
if (d) toggleDisplay(d.name, d.enabled) if (d) toggleDisplay(d.name, d.enabled)
} }
// brightness: no semantic activation; the slider value is the action. // brightness: no separate action; the slider value is the action.
} }
function clampCursor() { function clampCursor() {
@@ -222,18 +222,6 @@ Item {
brightnessDebounce.restart() brightnessDebounce.restart()
} }
function toggleMirror() {
if (!internalMonitor || !externalMonitor) return
actionProc.command = ["bash", "-lc", "if hyprctl monitors -j | jq -e --arg i '" + internalMonitor + "' --arg e '" + externalMonitor + "' '.[] | select(.name == $i and .mirrorOf == $e)' >/dev/null; then hyprctl keyword monitor '" + internalMonitor + ",preferred,auto,auto'; else hyprctl keyword monitor '" + internalMonitor + ",preferred,auto,auto,mirror," + externalMonitor + "'; fi"]
if (!actionProc.running) actionProc.running = true
}
function toggleInternal() {
if (!internalMonitor || !externalMonitor) return
actionProc.command = ["bash", "-lc", "if hyprctl monitors -j | jq -e --arg i '" + internalMonitor + "' '.[] | select(.name == $i)' >/dev/null; then hyprctl keyword monitor '" + internalMonitor + ",disable'; else hyprctl keyword monitor '" + internalMonitor + ",preferred,auto,auto'; fi"]
if (!actionProc.running) actionProc.running = true
}
function normalizeScale(scale) { function normalizeScale(scale) {
var n = parseFloat(String(scale || "")) var n = parseFloat(String(scale || ""))
if (!isFinite(n)) return "" if (!isFinite(n)) return ""
@@ -196,16 +196,6 @@ iwctl known-networks list 2>/dev/null \\
Quickshell.execDetached(["bash", "-lc", "printf %s " + root.bar.shellQuote(value) + " | wl-copy"]) Quickshell.execDetached(["bash", "-lc", "printf %s " + root.bar.shellQuote(value) + " | wl-copy"])
} }
function networkTooltip() {
if (kind === "wifi") {
var f = parseFloat(frequency)
var ftext = f > 0 ? " (" + (f / 1000).toFixed(1) + " GHz)" : ""
return (label || "Wi-Fi") + ftext
}
if (kind === "ethernet") return "Connected"
return "Disconnected"
}
function networkCommand() { function networkCommand() {
return [ return [
"device=$(ip route get 1.1.1.1 2>/dev/null | awk '{ for (i = 1; i <= NF; i++) if ($i == \"dev\") { print $(i + 1); exit } }')", "device=$(ip route get 1.1.1.1 2>/dev/null | awk '{ for (i = 1; i <= NF; i++) if ($i == \"dev\") { print $(i + 1); exit } }')",
+12 -19
View File
@@ -14,16 +14,21 @@ Item {
property bool popupOpen: false property bool popupOpen: false
function closePopout() { popupOpen = false } function closePopout() { popupOpen = false }
function showPopup() {
root.popupOpen = !root.popupOpen
if (root.popupOpen) root.refresh()
}
IpcHandler { IpcHandler {
target: "weather" target: "weather"
function show(): void { function show(): void { root.showPopup() }
root.popupOpen = !root.popupOpen function toggle(): void { root.showPopup() }
if (root.popupOpen) root.refresh() }
}
function toggle(): void { IpcHandler {
show() target: "weatherFlyout"
} function show(): void { root.showPopup() }
function toggle(): void { root.showPopup() }
} }
// Parsed wttr.in j1 response. Kept on failure so stale data stays visible. // Parsed wttr.in j1 response. Kept on failure so stale data stays visible.
@@ -58,8 +63,6 @@ Item {
readonly property int refreshMinutes: Math.max(1, parseInt(setting("refreshMinutes", 15), 10) || 15) readonly property int refreshMinutes: Math.max(1, parseInt(setting("refreshMinutes", 15), 10) || 15)
readonly property string reportLocation: wttrLocation || (areaInfo && areaInfo.areaName && areaInfo.areaName[0] ? areaInfo.areaName[0].value : "") readonly property string reportLocation: wttrLocation || (areaInfo && areaInfo.areaName && areaInfo.areaName[0] ? areaInfo.areaName[0].value : "")
readonly property string reportCondition: current && current.weatherDesc && current.weatherDesc[0] ? current.weatherDesc[0].value : ""
readonly property string reportTemp: current ? formatTemp(useImperial ? current.temp_F : current.temp_C) : ""
readonly property string reportTempNum: current ? String(useImperial ? current.temp_F : current.temp_C) : "" readonly property string reportTempNum: current ? String(useImperial ? current.temp_F : current.temp_C) : ""
readonly property string tempUnit: "°" + (useImperial ? "F" : "C") readonly property string tempUnit: "°" + (useImperial ? "F" : "C")
readonly property string reportFeels: current ? formatTemp(useImperial ? current.FeelsLikeF : current.FeelsLikeC) : "" readonly property string reportFeels: current ? formatTemp(useImperial ? current.FeelsLikeF : current.FeelsLikeC) : ""
@@ -164,16 +167,6 @@ Item {
return Qt.formatDate(d, "dddd") return Qt.formatDate(d, "dddd")
} }
function maxTempForDay(day) {
if (!day) return ""
return formatTemp(useImperial ? day.maxtempF : day.maxtempC)
}
function minTempForDay(day) {
if (!day) return ""
return formatTemp(useImperial ? day.mintempF : day.mintempC)
}
// Bare degree value (no unit letter), used in the forecast row. // Bare degree value (no unit letter), used in the forecast row.
function bareTempForDay(day, kind) { function bareTempForDay(day, kind) {
if (!day) return "" if (!day) return ""
@@ -7,11 +7,6 @@ import qs.Commons
Item { Item {
id: root id: root
property string omarchyPath: Quickshell.env("OMARCHY_PATH") || (Quickshell.env("HOME") + "/.local/share/omarchy")
property var shell: null
property var manifest: null
property var pluginRegistry: null
property bool opened: false property bool opened: false
property string filterText: "" property string filterText: ""
property int selectedIndex: 0 property int selectedIndex: 0
@@ -153,14 +148,6 @@ Item {
root.rebuildDisplay() root.rebuildDisplay()
} }
} }
IpcHandler {
target: "clipboard-picker"
function summon(): string { root.open("{}"); return "ok" }
function hide(): string { root.close(); return "ok" }
function toggle(): string { root.toggle(); return "ok" }
function ping(): string { return "ok" }
}
PanelWindow { PanelWindow {
id: panel id: panel
visible: root.opened visible: root.opened
+3 -2
View File
@@ -5,8 +5,9 @@
"version": "1.0.0", "version": "1.0.0",
"author": "Omarchy", "author": "Omarchy",
"description": "A clipboard manager to view and paste history", "description": "A clipboard manager to view and paste history",
"kinds": ["overlay"], "kinds": [
"activation": "on-demand", "overlay"
],
"keepLoaded": true, "keepLoaded": true,
"entryPoints": { "entryPoints": {
"overlay": "ClipboardPicker.qml" "overlay": "ClipboardPicker.qml"
+1 -4
View File
@@ -63,10 +63,7 @@ Item {
} }
// ---- host injections ---------------------------------------------------- // ---- host injections ----------------------------------------------------
property var barWidgetRegistry: null
property var pluginRegistry: null
property var shell: null property var shell: null
property var manifest: null
// ---- theme -------------------------------------------------------------- // ---- theme --------------------------------------------------------------
readonly property color foreground: Color.foreground readonly property color foreground: Color.foreground
@@ -104,7 +101,7 @@ Item {
property string focusSection: "cursor-surface" property string focusSection: "cursor-surface"
property int selectedIndex: 0 property int selectedIndex: 0
// Demo state mutated by activation. // Demo state mutated by interaction.
property string choiceDemoValue: "top" property string choiceDemoValue: "top"
property bool toggleDemoOn: true property bool toggleDemoOn: true
property bool toggleSquareOn: false property bool toggleSquareOn: false
+6 -3
View File
@@ -5,7 +5,10 @@
"version": "1.0.0", "version": "1.0.0",
"author": "Omarchy", "author": "Omarchy",
"description": "Visual reference for omarchy-shell common UI components. Summon with: omarchy-shell shell summon omarchy.dev-gallery '{}' (or run: omarchy dev ui-preview).", "description": "Visual reference for omarchy-shell common UI components. Summon with: omarchy-shell shell summon omarchy.dev-gallery '{}' (or run: omarchy dev ui-preview).",
"kinds": ["panel"], "kinds": [
"activation": "on-demand", "panel"
"entryPoints": { "panel": "GalleryPanel.qml" } ],
"entryPoints": {
"panel": "GalleryPanel.qml"
}
} }
@@ -10,7 +10,6 @@ Item {
property string omarchyPath: Quickshell.env("OMARCHY_PATH") || (Quickshell.env("HOME") + "/.local/share/omarchy") property string omarchyPath: Quickshell.env("OMARCHY_PATH") || (Quickshell.env("HOME") + "/.local/share/omarchy")
property var shell: null property var shell: null
property var manifest: null property var manifest: null
property var pluginRegistry: null
property bool opened: false property bool opened: false
property string filterText: "" property string filterText: ""
@@ -163,14 +162,6 @@ Item {
} }
ListModel { id: displayModel } ListModel { id: displayModel }
IpcHandler {
target: "emoji-picker"
function summon(): string { root.open("{}"); return "ok" }
function hide(): string { root.close(); return "ok" }
function toggle(): string { root.toggle(); return "ok" }
function ping(): string { return "ok" }
}
FileView { FileView {
path: root.omarchyPath + "/shell/plugins/emoji-picker/emojis.json" path: root.omarchyPath + "/shell/plugins/emoji-picker/emojis.json"
onLoaded: root.loadEmojis(text()) onLoaded: root.loadEmojis(text())
+3 -2
View File
@@ -5,8 +5,9 @@
"version": "1.0.0", "version": "1.0.0",
"author": "Omarchy", "author": "Omarchy",
"description": "An emoji picker to copy or type emojis", "description": "An emoji picker to copy or type emojis",
"kinds": ["overlay"], "kinds": [
"activation": "on-demand", "overlay"
],
"keepLoaded": true, "keepLoaded": true,
"entryPoints": { "entryPoints": {
"overlay": "EmojiPicker.qml" "overlay": "EmojiPicker.qml"
+2 -20
View File
@@ -9,16 +9,9 @@ import qs.Commons
Item { Item {
id: root id: root
// Injected by omarchy-shell. Optional here — the picker doesn't need // Injected by omarchy-shell so helper scripts resolve without relying on
// omarchyPath itself, but every plugin gets it so user-installed scripts // OMARCHY_PATH being set in the environment.
// referenced by other plugins can stay path-portable.
property string omarchyPath: "" property string omarchyPath: ""
// Set by omarchy-shell when summoning the overlay; not currently consumed but
// declared so the host's onLoaded injection doesn't trip a missing-property
// warning.
property var shell: null
property var manifest: null
property string imageDirs: Quickshell.env("OMARCHY_IMAGE_SELECTOR_DIRS") || Quickshell.env("OMARCHY_IMAGE_SELECTOR_DIR") || Quickshell.env("OMARCHY_STOCK_BACKGROUNDS_DIR") || (Quickshell.env("HOME") + "/.config/omarchy/current/theme/backgrounds") property string imageDirs: Quickshell.env("OMARCHY_IMAGE_SELECTOR_DIRS") || Quickshell.env("OMARCHY_IMAGE_SELECTOR_DIR") || Quickshell.env("OMARCHY_STOCK_BACKGROUNDS_DIR") || (Quickshell.env("HOME") + "/.config/omarchy/current/theme/backgrounds")
property string imageRows: "" property string imageRows: ""
property string loadedImageRows: "" property string loadedImageRows: ""
@@ -120,17 +113,6 @@ Item {
return nameForPath(path).toLowerCase().indexOf(needle) !== -1 || labelForPath(path).toLowerCase().indexOf(needle) !== -1 return nameForPath(path).toLowerCase().indexOf(needle) !== -1 || labelForPath(path).toLowerCase().indexOf(needle) !== -1
} }
function matchingCount() {
if (!filterText) return imageArray.length
var count = 0
for (var i = 0; i < imageArray.length; i++) {
if (itemMatches(i)) count++
}
return count
}
function firstMatchingIndex() { function firstMatchingIndex() {
for (var i = 0; i < imageArray.length; i++) { for (var i = 0; i < imageArray.length; i++) {
if (itemMatches(i)) return i if (itemMatches(i)) return i
+5 -5
View File
@@ -5,11 +5,11 @@
"version": "1.0.0", "version": "1.0.0",
"author": "Omarchy", "author": "Omarchy",
"description": "Image-grid selector overlay used for wallpapers, themes, and any other directory of images", "description": "Image-grid selector overlay used for wallpapers, themes, and any other directory of images",
"kinds": ["overlay"], "kinds": [
"activation": "on-demand", "overlay"
],
"keepLoaded": true, "keepLoaded": true,
"entryPoints": { "overlay": "ImagePicker.qml" }, "entryPoints": {
"ipc": { "overlay": "ImagePicker.qml"
"summon": "image-picker"
} }
} }
-11
View File
@@ -9,9 +9,6 @@ Item {
// Injected by omarchy-shell when this plugin is summoned. // Injected by omarchy-shell when this plugin is summoned.
property string omarchyPath: Quickshell.env("OMARCHY_PATH") || (Quickshell.env("HOME") + "/.local/share/omarchy") property string omarchyPath: Quickshell.env("OMARCHY_PATH") || (Quickshell.env("HOME") + "/.local/share/omarchy")
property var shell: null
property var manifest: null
property var pluginRegistry: null
// Plugin lifecycle hooks. The host calls open(payloadJson) after // Plugin lifecycle hooks. The host calls open(payloadJson) after
// `omarchy-shell shell summon omarchy.menu ...` and close() when hidden. // `omarchy-shell shell summon omarchy.menu ...` and close() when hidden.
@@ -71,14 +68,6 @@ Item {
property int visibleRowsHeight: rowListHeight(layoutSerial, displayModel.count, filterText, searchDivider) property int visibleRowsHeight: rowListHeight(layoutSerial, displayModel.count, filterText, searchDivider)
property int cardHeight: Math.min(Math.max(Style.space(220), contentMargin * 2 + headerHeight + contentSpacing + visibleRowsHeight), panel.height - Style.gapsOut * 2) property int cardHeight: Math.min(Math.max(Style.space(220), contentMargin * 2 + headerHeight + contentSpacing + visibleRowsHeight), panel.height - Style.gapsOut * 2)
function shellQuote(value) {
return "'" + String(value).replace(/'/g, "'\\''") + "'"
}
function decodeField(value) {
return String(value || "").replace(/\v/g, "\n").replace(/\f/g, "\t")
}
function withAlpha(color, alpha) { function withAlpha(color, alpha) {
return Qt.rgba(color.r, color.g, color.b, alpha) return Qt.rgba(color.r, color.g, color.b, alpha)
} }
+5 -5
View File
@@ -5,11 +5,11 @@
"version": "1.0.0", "version": "1.0.0",
"author": "Omarchy", "author": "Omarchy",
"description": "Quickshell-powered Omarchy command menu", "description": "Quickshell-powered Omarchy command menu",
"kinds": ["menu"], "kinds": [
"activation": "on-demand", "menu"
],
"keepLoaded": true, "keepLoaded": true,
"entryPoints": { "menu": "Menu.qml" }, "entryPoints": {
"ipc": { "menu": "Menu.qml"
"summon": "menu"
} }
} }
-2
View File
@@ -17,9 +17,7 @@ Item {
id: service id: service
// Injected by omarchy-shell (the first-party service loader). // Injected by omarchy-shell (the first-party service loader).
property string omarchyPath: ""
property var shell: null property var shell: null
property var manifest: null
readonly property string home: Quickshell.env("HOME") readonly property string home: Quickshell.env("HOME")
// History + DND live under XDG_STATE_HOME: they're persistent user state // History + DND live under XDG_STATE_HOME: they're persistent user state
@@ -34,28 +34,6 @@ Rectangle {
signal closeRequested() signal closeRequested()
signal cardClicked() signal cardClicked()
signal imageClicked()
// Media mode = the notification carries a real screenshot or screen
// recording preview. Quickshell normalizes file paths from `-i` and the
// `image-path` hint into `image://icon//<absolute path>` (double slash
// marks an absolute filesystem path vs a themed icon name like
// `image://icon/firefox`).
function _imageFilePath(s) {
if (!s) return ""
if (s.indexOf("image://icon//") === 0) return s.substring("image://icon/".length)
if (s.indexOf("file://") === 0) return decodeURIComponent(s.substring(7))
return ""
}
function _isMediaFile(path) {
if (!path) return false
var lower = path.toLowerCase()
return lower.endsWith(".png") || lower.endsWith(".jpg") ||
lower.endsWith(".jpeg") || lower.endsWith(".webp") ||
lower.endsWith(".gif")
}
readonly property string mediaImageSource: ""
readonly property bool mediaMode: false
// Use only what the notification explicitly carries — no themed-icon // Use only what the notification explicitly carries — no themed-icon
// theme-lookup fallback because Quickshell's icon image provider returns // theme-lookup fallback because Quickshell's icon image provider returns
// a placeholder for missing names (rather than erroring), which means // a placeholder for missing names (rather than erroring), which means
@@ -64,7 +42,7 @@ Rectangle {
// `appIcon` (-i flag) still get one. // `appIcon` (-i flag) still get one.
readonly property string smallIconSource: image.length > 0 ? image : appIcon readonly property string smallIconSource: image.length > 0 ? image : appIcon
readonly property bool hasGlyph: glyph.length > 0 readonly property bool hasGlyph: glyph.length > 0
readonly property bool hasSmallIcon: !mediaMode && (smallIconSource.length > 0 || hasGlyph) readonly property bool hasSmallIcon: smallIconSource.length > 0 || hasGlyph
readonly property bool chromiumDerived: { readonly property bool chromiumDerived: {
var source = (app + "\n" + appIcon).toLowerCase() var source = (app + "\n" + appIcon).toLowerCase()
return source.indexOf("chrom") >= 0 || source.indexOf("brave") >= 0 || return source.indexOf("chrom") >= 0 || source.indexOf("brave") >= 0 ||
@@ -75,7 +53,6 @@ Rectangle {
readonly property color dimColor: Qt.darker(Color.notifications.text, 1.4) readonly property color dimColor: Qt.darker(Color.notifications.text, 1.4)
readonly property color bodyColor: Qt.darker(Color.notifications.text, 1.15) readonly property color bodyColor: Qt.darker(Color.notifications.text, 1.15)
readonly property color hoverColor: Qt.rgba(Color.notifications.text.r, Color.notifications.text.g, Color.notifications.text.b, 0.14)
readonly property color accentColor: urgency === 2 ? Color.urgent : (urgency === 0 ? dimColor : Color.notifications.countdown) readonly property color accentColor: urgency === 2 ? Color.urgent : (urgency === 0 ? dimColor : Color.notifications.countdown)
function sanitizeBody(s) { function sanitizeBody(s) {
@@ -111,9 +88,8 @@ Rectangle {
ColumnLayout { ColumnLayout {
id: mainColumn id: mainColumn
// Inset by the card border so the hero image (and the text row) don't // Inset by the card border so the content doesn't paint over the card's
// paint over the card's outer border. Without this the left/right/top // outer border.
// border is invisible under the image.
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
@@ -122,46 +98,7 @@ Rectangle {
anchors.rightMargin: root.border.width anchors.rightMargin: root.border.width
spacing: 0 spacing: 0
// Hero image strip (media notifications only). PreserveAspectCrop so // Text content.
// the preview looks like a clean banner without dark letterboxing.
Item {
Layout.fillWidth: true
Layout.preferredHeight: Style.space(140)
visible: root.mediaMode
clip: true
Image {
anchors.fill: parent
source: root.mediaImageSource
fillMode: Image.PreserveAspectCrop
sourceSize.width: width > 0 ? width * Screen.devicePixelRatio : 0
sourceSize.height: height > 0 ? height * Screen.devicePixelRatio : 0
asynchronous: true
smooth: true
cache: false
}
// Bottom divider matching the card border so the screenshot is
// visually framed on every side (card border wraps top/left/right;
// this line completes the bottom).
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: root.border.width
color: root.urgency === 2 ? Color.urgent : Color.notifications.border
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: root.imageClicked()
}
}
// Text content. Always rendered — for media notifications this carries
// the summary/body ("Screenshot saved" etc) under the hero image.
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: Style.space(12) Layout.leftMargin: Style.space(12)
+3 -2
View File
@@ -5,8 +5,9 @@
"version": "1.0.0", "version": "1.0.0",
"author": "Omarchy", "author": "Omarchy",
"description": "Notification daemon, popups, and history", "description": "Notification daemon, popups, and history",
"kinds": ["service"], "kinds": [
"activation": "persistent", "service"
],
"keepLoaded": true, "keepLoaded": true,
"entryPoints": { "entryPoints": {
"service": "Service.qml" "service": "Service.qml"
-4
View File
@@ -7,10 +7,6 @@ import qs.Commons
Item { Item {
id: root id: root
property string omarchyPath: ""
property var shell: null
property var manifest: null
property bool opened: false property bool opened: false
property string icon: "" property string icon: ""
property string message: "" property string message: ""
+6 -3
View File
@@ -4,8 +4,11 @@
"name": "On-screen display", "name": "On-screen display",
"version": "1.0.0", "version": "1.0.0",
"description": "Quickshell volume, brightness, and status overlays.", "description": "Quickshell volume, brightness, and status overlays.",
"kinds": ["panel"], "kinds": [
"activation": "persistent", "panel"
],
"keepLoaded": true, "keepLoaded": true,
"entryPoints": { "panel": "Osd.qml" } "entryPoints": {
"panel": "Osd.qml"
}
} }
-9
View File
@@ -8,10 +8,6 @@ import qs.Commons
Item { Item {
id: root id: root
property string omarchyPath: ""
property var shell: null
property var manifest: null
property string fontFamily: Quickshell.env("OMARCHY_MENU_FONT") || "monospace" property string fontFamily: Quickshell.env("OMARCHY_MENU_FONT") || "monospace"
property color accent: Color.accent property color accent: Color.accent
property color background: Color.menu.background property color background: Color.menu.background
@@ -19,7 +15,6 @@ Item {
property color border: foreground property color border: foreground
readonly property int cornerRadius: Style.cornerRadius readonly property int cornerRadius: Style.cornerRadius
property int contentMargin: Style.spacing.panelPadding property int contentMargin: Style.spacing.panelPadding
property int contentSpacing: Style.spacing.rowPaddingX
property int fieldHeight: Math.max(Style.space(42), Style.spacing.controlHeight) property int fieldHeight: Math.max(Style.space(42), Style.spacing.controlHeight)
property bool closing: false property bool closing: false
@@ -42,10 +37,6 @@ Item {
function withAlpha(color, alpha) { function withAlpha(color, alpha) {
return Qt.rgba(color.r, color.g, color.b, alpha) return Qt.rgba(color.r, color.g, color.b, alpha)
} }
function messageText() {
return "Authentication is needed..."
}
function promptLooksFingerprint(text) { function promptLooksFingerprint(text) {
var s = String(text || "").toLowerCase() var s = String(text || "").toLowerCase()
return s.indexOf("finger") !== -1 || s.indexOf("fprint") !== -1 || s.indexOf("swipe") !== -1 return s.indexOf("finger") !== -1 || s.indexOf("fprint") !== -1 || s.indexOf("swipe") !== -1
+3 -2
View File
@@ -5,8 +5,9 @@
"version": "1.0.0", "version": "1.0.0",
"author": "Omarchy", "author": "Omarchy",
"description": "Theme-aware authentication dialog for privileged actions.", "description": "Theme-aware authentication dialog for privileged actions.",
"kinds": ["service"], "kinds": [
"activation": "persistent", "service"
],
"keepLoaded": true, "keepLoaded": true,
"entryPoints": { "entryPoints": {
"service": "PolkitAgent.qml" "service": "PolkitAgent.qml"
+13 -4
View File
@@ -153,7 +153,7 @@ Item {
] ]
} }
}, },
plugins: [{ id: "omarchy.osd" }] plugins: []
}) })
property var defaultConfig: builtinShellConfig property var defaultConfig: builtinShellConfig
@@ -355,11 +355,20 @@ Item {
function onChanged() { root.catalogRevision++ } function onChanged() { root.catalogRevision++ }
} }
function canonicalWidgetId(id) {
switch (String(id || "")) {
case "idle": return "idleInhibitor"
case "weatherFlyout": return "weather"
default: return String(id || "")
}
}
function widgetMetadata(id) { function widgetMetadata(id) {
var key = String(id || "") var key = String(id || "")
if (root.barWidgetRegistry && root.barWidgetRegistry.has(key)) var canonicalKey = canonicalWidgetId(key)
return root.barWidgetRegistry.metadataFor(key) || {} if (root.barWidgetRegistry && root.barWidgetRegistry.has(canonicalKey))
if (builtinWidgetMeta[key]) return builtinWidgetMeta[key] return root.barWidgetRegistry.metadataFor(canonicalKey) || {}
if (builtinWidgetMeta[canonicalKey]) return builtinWidgetMeta[canonicalKey]
var manifest = root.pluginRegistry ? root.pluginRegistry.installedPlugins[key] : null var manifest = root.pluginRegistry ? root.pluginRegistry.installedPlugins[key] : null
if (manifest) { if (manifest) {
+6 -3
View File
@@ -5,7 +5,10 @@
"version": "1.0.0", "version": "1.0.0",
"author": "Omarchy", "author": "Omarchy",
"description": "Customize the Omarchy bar position and widgets", "description": "Customize the Omarchy bar position and widgets",
"kinds": ["panel"], "kinds": [
"activation": "on-demand", "panel"
"entryPoints": { "panel": "SettingsPanel.qml" } ],
"entryPoints": {
"panel": "SettingsPanel.qml"
}
} }
-7
View File
@@ -1,7 +0,0 @@
#!/bin/bash
if pgrep -x hypridle >/dev/null; then
echo '{"text": ""}'
else
echo '{"text": "󱫖", "tooltip": "Idle lock disabled", "class": "active"}'
fi
-5
View File
@@ -34,11 +34,6 @@ QtObject {
changed() changed()
} }
function componentFor(id) {
var entry = widgets[String(id)]
return entry ? entry.component : null
}
function metadataFor(id) { function metadataFor(id) {
var entry = widgets[String(id)] var entry = widgets[String(id)]
return entry ? entry.metadata : null return entry ? entry.metadata : null
-9
View File
@@ -181,15 +181,6 @@ QtObject {
pluginsChanged() pluginsChanged()
} }
function manifestsOfKind(kind) {
var result = []
for (var id in installedPlugins) {
var m = installedPlugins[id]
if (m && Array.isArray(m.kinds) && m.kinds.indexOf(kind) !== -1) result.push(m)
}
return result
}
// ---------------------------------------------------------------- scanning // ---------------------------------------------------------------- scanning
// Output format produced by the rescan script: // Output format produced by the rescan script:
+1 -5
View File
@@ -61,9 +61,5 @@
] ]
} }
}, },
"plugins": [ "plugins": []
{
"id": "omarchy.osd"
}
]
} }
+5 -14
View File
@@ -57,11 +57,7 @@ ShellRoot {
right: [{ id: "audioPanel" }] right: [{ id: "audioPanel" }]
} }
}, },
plugins: [ plugins: []
{ id: "omarchy.settings" },
{ id: "omarchy.image-picker" },
{ id: "omarchy.osd" }
]
}) })
property var defaultsConfig: builtinShellConfig property var defaultsConfig: builtinShellConfig
@@ -117,8 +113,6 @@ ShellRoot {
} }
readonly property var barConfig: shellConfig && isPlainObject(shellConfig.bar) ? shellConfig.bar : builtinShellConfig.bar readonly property var barConfig: shellConfig && isPlainObject(shellConfig.bar) ? shellConfig.bar : builtinShellConfig.bar
readonly property var pluginsConfig: shellConfig && Array.isArray(shellConfig.plugins) ? shellConfig.plugins : []
FileView { FileView {
id: defaultsFile id: defaultsFile
path: shell.defaultsPath path: shell.defaultsPath
@@ -217,15 +211,14 @@ ShellRoot {
console.warn("first-party service load failed for " + key + ": " + comp.errorString()) console.warn("first-party service load failed for " + key + ": " + comp.errorString())
return return
} }
var inst = comp.createObject(firstPartyServiceHost, { var inst = comp.createObject(firstPartyServiceHost)
omarchyPath: shell.omarchyPath,
shell: shell,
manifest: manifest
})
if (!inst) { if (!inst) {
console.warn("first-party service createObject returned null for", key) console.warn("first-party service createObject returned null for", key)
return return
} }
if ("omarchyPath" in inst) inst.omarchyPath = shell.omarchyPath
if ("shell" in inst) inst.shell = shell
if ("manifest" in inst) inst.manifest = manifest
var snext = ({}) var snext = ({})
for (var sk in _firstPartyServices) snext[sk] = _firstPartyServices[sk] for (var sk in _firstPartyServices) snext[sk] = _firstPartyServices[sk]
snext[key] = inst snext[key] = inst
@@ -323,8 +316,6 @@ ShellRoot {
// QML to notice the change. // QML to notice the change.
property var openPanelIds: ({}) property var openPanelIds: ({})
function isPanelOpen(id) { return openPanelIds[id] === true }
// Pending payloads to deliver to a plugin's open() once its loader resolves. // Pending payloads to deliver to a plugin's open() once its loader resolves.
// Keyed by plugin id; the value is an array so two summon() calls before // Keyed by plugin id; the value is an array so two summon() calls before
// the Loader resolves both reach the plugin in arrival order rather than // the Loader resolves both reach the plugin in arrival order rather than