Make built-in widgets plugins

This commit is contained in:
Ryan Hughes
2026-05-23 04:32:20 -04:00
parent fc180af54e
commit 4f0bdb790b
51 changed files with 565 additions and 230 deletions
+29 -8
View File
@@ -17,9 +17,6 @@ ShellRoot {
// own empty copies.
property PluginRegistry pluginRegistry: PluginRegistry { }
property BarWidgetRegistry barWidgetRegistry: BarWidgetRegistry { }
property FirstPartyWidgets firstPartyWidgets: FirstPartyWidgets {
barWidgetRegistry: shell.barWidgetRegistry
}
property string home: Quickshell.env("HOME")
@@ -362,9 +359,17 @@ ShellRoot {
return true
}
function isPluginOpen(pluginId) {
var id = String(pluginId || "")
var loader = panelLoaders[id]
if (loader && loader.item && loader.item.opened !== undefined)
return loader.item.opened === true
return openPanelIds[id] === true
}
function toggle(pluginId, payloadJson) {
var id = String(pluginId || "")
return openPanelIds[id] ? hide(id) : summon(id, payloadJson)
return isPluginOpen(id) ? hide(id) : summon(id, payloadJson)
}
// Map of pluginId -> Loader, populated by the Instantiator delegate below.
@@ -411,6 +416,19 @@ ShellRoot {
}
}
function callIfLoaded(pluginId, method, arg) {
var loader = panelLoaders[pluginId]
if (!loader || !loader.item) return "unknown"
if (typeof loader.item[method] !== "function") return "unknown"
try {
var result = loader.item[method](arg)
return result === undefined || result === null ? "ok" : String(result)
} catch (e) {
console.warn("plugin " + pluginId + " " + method + "() threw:", e)
return "error"
}
}
// One Loader per discoverable panel/overlay/menu plugin. Active when the
// host marks it open. The Loader holds onto the instance while active so the
// plugin's FloatingWindow + state survive between summons within a session.
@@ -490,10 +508,8 @@ ShellRoot {
// Mirror plugin registry state into BarWidgetRegistry whenever it changes.
// Each enabled plugin with kind "bar-widget" gets a Component created from
// its manifest entry point and registered under its plain manifest id.
// First-party widget ids (clock, weather, etc.) are short and don't
// collide with namespaced plugin ids, so we don't need a separate
// "plugin:" namespace anymore.
// its manifest entry point and registered under its manifest id. Built-in
// widgets use the same first-party manifest contract as third-party widgets.
Connections {
target: shell.pluginRegistry
function onPluginsChanged() { shell.syncPluginWidgets() }
@@ -527,6 +543,7 @@ ShellRoot {
category: meta.category || "Plugin",
allowMultiple: meta.allowMultiple === true,
defaults: meta.defaults || {},
settingsForm: meta.settingsForm || "",
schema: meta.schema || [],
pluginId: manifest.id,
sourceDir: manifest.__sourceDir || "",
@@ -641,5 +658,9 @@ ShellRoot {
function toggle(id: string, payloadJson: string): void {
shell.toggle(id, payloadJson)
}
function call(id: string, method: string, arg: string): string {
return shell.callIfLoaded(id, method, arg)
}
}
}