mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
plugins: fix reactivity, tooltips, new IPCs to reload
This commit is contained in:
@@ -1,12 +1,10 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import Qt.labs.folderlistmodel
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
|
||||
Singleton {
|
||||
@@ -17,13 +15,14 @@ Singleton {
|
||||
property var pluginWidgetComponents: ({})
|
||||
property var pluginDaemonComponents: ({})
|
||||
property var pluginLauncherComponents: ({})
|
||||
property var availablePluginsList: []
|
||||
property string pluginDirectory: {
|
||||
var configDir = StandardPaths.writableLocation(StandardPaths.ConfigLocation)
|
||||
var configDirStr = configDir.toString()
|
||||
var configDir = StandardPaths.writableLocation(StandardPaths.ConfigLocation);
|
||||
var configDirStr = configDir.toString();
|
||||
if (configDirStr.startsWith("file://")) {
|
||||
configDirStr = configDirStr.substring(7)
|
||||
configDirStr = configDirStr.substring(7);
|
||||
}
|
||||
return configDirStr + "/DankMaterialShell/plugins"
|
||||
return configDirStr + "/DankMaterialShell/plugins";
|
||||
}
|
||||
property string systemPluginDirectory: "/etc/xdg/quickshell/dms-plugins"
|
||||
|
||||
@@ -36,7 +35,7 @@ Singleton {
|
||||
signal pluginUnloaded(string pluginId)
|
||||
signal pluginLoadFailed(string pluginId, string error)
|
||||
signal pluginDataChanged(string pluginId)
|
||||
signal pluginListUpdated()
|
||||
signal pluginListUpdated
|
||||
signal globalVarChanged(string pluginId, string varName)
|
||||
|
||||
Timer {
|
||||
@@ -47,9 +46,9 @@ Singleton {
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
userWatcher.folder = Paths.toFileUrl(root.pluginDirectory)
|
||||
systemWatcher.folder = Paths.toFileUrl(root.systemPluginDirectory)
|
||||
Qt.callLater(resyncAll)
|
||||
userWatcher.folder = Paths.toFileUrl(root.pluginDirectory);
|
||||
systemWatcher.folder = Paths.toFileUrl(root.systemPluginDirectory);
|
||||
Qt.callLater(resyncAll);
|
||||
}
|
||||
|
||||
FolderListModel {
|
||||
@@ -57,10 +56,12 @@ Singleton {
|
||||
showDirs: true
|
||||
showFiles: false
|
||||
showDotAndDotDot: false
|
||||
nameFilters: ["plugin.json"]
|
||||
|
||||
onCountChanged: resyncDebounce.restart()
|
||||
onStatusChanged: if (status === FolderListModel.Ready) resyncDebounce.restart()
|
||||
onStatusChanged: {
|
||||
if (status === FolderListModel.Ready)
|
||||
resyncDebounce.restart();
|
||||
}
|
||||
}
|
||||
|
||||
FolderListModel {
|
||||
@@ -68,65 +69,74 @@ Singleton {
|
||||
showDirs: true
|
||||
showFiles: false
|
||||
showDotAndDotDot: false
|
||||
nameFilters: ["plugin.json"]
|
||||
|
||||
onCountChanged: resyncDebounce.restart()
|
||||
onStatusChanged: if (status === FolderListModel.Ready) resyncDebounce.restart()
|
||||
onStatusChanged: {
|
||||
if (status === FolderListModel.Ready)
|
||||
resyncDebounce.restart();
|
||||
}
|
||||
}
|
||||
|
||||
function snapshotModel(model, sourceTag) {
|
||||
const out = []
|
||||
const n = model.count
|
||||
const baseDir = sourceTag === "user" ? pluginDirectory : systemPluginDirectory
|
||||
const out = [];
|
||||
const n = model.count;
|
||||
const baseDir = sourceTag === "user" ? pluginDirectory : systemPluginDirectory;
|
||||
for (let i = 0; i < n; i++) {
|
||||
let dirPath = model.get(i, "filePath")
|
||||
let dirPath = model.get(i, "filePath");
|
||||
if (dirPath.startsWith("file://")) {
|
||||
dirPath = dirPath.substring(7)
|
||||
dirPath = dirPath.substring(7);
|
||||
}
|
||||
if (!dirPath.startsWith(baseDir)) {
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
const manifestPath = dirPath + "/plugin.json"
|
||||
out.push({ path: manifestPath, source: sourceTag })
|
||||
const manifestPath = dirPath + "/plugin.json";
|
||||
out.push({
|
||||
path: manifestPath,
|
||||
source: sourceTag
|
||||
});
|
||||
}
|
||||
return out
|
||||
return out;
|
||||
}
|
||||
|
||||
function resyncAll() {
|
||||
const userList = snapshotModel(userWatcher, "user")
|
||||
const sysList = snapshotModel(systemWatcher, "system")
|
||||
const seenPaths = {}
|
||||
const userList = snapshotModel(userWatcher, "user");
|
||||
const sysList = snapshotModel(systemWatcher, "system");
|
||||
const seenPaths = {};
|
||||
|
||||
function consider(entry) {
|
||||
const key = entry.path
|
||||
seenPaths[key] = true
|
||||
const prev = knownManifests[key]
|
||||
const key = entry.path;
|
||||
seenPaths[key] = true;
|
||||
const prev = knownManifests[key];
|
||||
if (!prev) {
|
||||
loadPluginManifestFile(entry.path, entry.source, Date.now())
|
||||
loadPluginManifestFile(entry.path, entry.source, Date.now());
|
||||
}
|
||||
}
|
||||
for (let i=0;i<userList.length;i++) consider(userList[i])
|
||||
for (let i=0;i<sysList.length;i++) consider(sysList[i])
|
||||
for (let i = 0; i < userList.length; i++)
|
||||
consider(userList[i]);
|
||||
for (let i = 0; i < sysList.length; i++)
|
||||
consider(sysList[i]);
|
||||
|
||||
const removed = []
|
||||
const removed = [];
|
||||
for (const path in knownManifests) {
|
||||
if (!seenPaths[path]) removed.push(path)
|
||||
if (!seenPaths[path])
|
||||
removed.push(path);
|
||||
}
|
||||
if (removed.length) {
|
||||
removed.forEach(function(path) {
|
||||
const pid = pathToPluginId[path]
|
||||
removed.forEach(function (path) {
|
||||
const pid = pathToPluginId[path];
|
||||
if (pid) {
|
||||
unregisterPluginByPath(path, pid)
|
||||
unregisterPluginByPath(path, pid);
|
||||
}
|
||||
delete knownManifests[path]
|
||||
delete pathToPluginId[path]
|
||||
})
|
||||
pluginListUpdated()
|
||||
delete knownManifests[path];
|
||||
delete pathToPluginId[path];
|
||||
});
|
||||
_updateAvailablePluginsList();
|
||||
pluginListUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
function loadPluginManifestFile(manifestPathNoScheme, sourceTag, mtimeEpochMs) {
|
||||
const manifestId = "m_" + Math.random().toString(36).slice(2)
|
||||
const manifestId = "m_" + Math.random().toString(36).slice(2);
|
||||
const qml = `
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
@@ -150,226 +160,251 @@ Singleton {
|
||||
fv.destroy()
|
||||
}
|
||||
}
|
||||
`
|
||||
const loader = Qt.createQmlObject(qml, root, "mf_" + manifestId)
|
||||
loader.absPath = manifestPathNoScheme
|
||||
loader.path = manifestPathNoScheme
|
||||
`;
|
||||
|
||||
const loader = Qt.createQmlObject(qml, root, "mf_" + manifestId);
|
||||
loader.absPath = manifestPathNoScheme;
|
||||
loader.path = manifestPathNoScheme;
|
||||
}
|
||||
|
||||
function _onManifestParsed(absPath, manifest, sourceTag, mtimeEpochMs) {
|
||||
if (!manifest || !manifest.id || !manifest.name || !manifest.component) {
|
||||
console.error("PluginService: invalid manifest fields:", absPath)
|
||||
knownManifests[absPath] = { mtime: mtimeEpochMs, source: sourceTag, bad: true }
|
||||
return
|
||||
console.error("PluginService: invalid manifest fields:", absPath);
|
||||
knownManifests[absPath] = {
|
||||
mtime: mtimeEpochMs,
|
||||
source: sourceTag,
|
||||
bad: true
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
const dir = absPath.substring(0, absPath.lastIndexOf('/'))
|
||||
let comp = manifest.component
|
||||
if (comp.startsWith("./")) comp = comp.slice(2)
|
||||
let settings = manifest.settings
|
||||
if (settings && settings.startsWith("./")) settings = settings.slice(2)
|
||||
const dir = absPath.substring(0, absPath.lastIndexOf('/'));
|
||||
let comp = manifest.component;
|
||||
if (comp.startsWith("./"))
|
||||
comp = comp.slice(2);
|
||||
let settings = manifest.settings;
|
||||
if (settings && settings.startsWith("./"))
|
||||
settings = settings.slice(2);
|
||||
|
||||
const info = {}
|
||||
for (const k in manifest) info[k] = manifest[k]
|
||||
const info = {};
|
||||
for (const k in manifest)
|
||||
info[k] = manifest[k];
|
||||
|
||||
let perms = manifest.permissions
|
||||
let perms = manifest.permissions;
|
||||
if (typeof perms === "string") {
|
||||
perms = perms.split(/\s*,\s*/)
|
||||
perms = perms.split(/\s*,\s*/);
|
||||
}
|
||||
if (!Array.isArray(perms)) {
|
||||
perms = []
|
||||
perms = [];
|
||||
}
|
||||
info.permissions = perms.map(p => String(p).trim())
|
||||
info.permissions = perms.map(p => String(p).trim());
|
||||
|
||||
info.manifestPath = absPath
|
||||
info.pluginDirectory = dir
|
||||
info.componentPath = dir + "/" + comp
|
||||
info.settingsPath = settings ? (dir + "/" + settings) : null
|
||||
info.loaded = isPluginLoaded(manifest.id)
|
||||
info.type = manifest.type || "widget"
|
||||
info.source = sourceTag
|
||||
info.manifestPath = absPath;
|
||||
info.pluginDirectory = dir;
|
||||
info.componentPath = dir + "/" + comp;
|
||||
info.settingsPath = settings ? (dir + "/" + settings) : null;
|
||||
info.loaded = isPluginLoaded(manifest.id);
|
||||
info.type = manifest.type || "widget";
|
||||
info.source = sourceTag;
|
||||
|
||||
const existing = availablePlugins[manifest.id]
|
||||
const shouldReplace =
|
||||
(!existing) ||
|
||||
(existing && existing.source === "system" && sourceTag === "user")
|
||||
const existing = availablePlugins[manifest.id];
|
||||
const shouldReplace = (!existing) || (existing && existing.source === "system" && sourceTag === "user");
|
||||
|
||||
if (shouldReplace) {
|
||||
if (existing && existing.loaded && existing.source !== sourceTag) {
|
||||
unloadPlugin(manifest.id)
|
||||
unloadPlugin(manifest.id);
|
||||
}
|
||||
const newMap = Object.assign({}, availablePlugins)
|
||||
newMap[manifest.id] = info
|
||||
availablePlugins = newMap
|
||||
pathToPluginId[absPath] = manifest.id
|
||||
knownManifests[absPath] = { mtime: mtimeEpochMs, source: sourceTag }
|
||||
pluginListUpdated()
|
||||
const enabled = SettingsData.getPluginSetting(manifest.id, "enabled", false)
|
||||
if (enabled && !info.loaded) loadPlugin(manifest.id)
|
||||
const newMap = Object.assign({}, availablePlugins);
|
||||
newMap[manifest.id] = info;
|
||||
availablePlugins = newMap;
|
||||
pathToPluginId[absPath] = manifest.id;
|
||||
knownManifests[absPath] = {
|
||||
mtime: mtimeEpochMs,
|
||||
source: sourceTag
|
||||
};
|
||||
_updateAvailablePluginsList();
|
||||
pluginListUpdated();
|
||||
const enabled = SettingsData.getPluginSetting(manifest.id, "enabled", false);
|
||||
if (enabled && !info.loaded)
|
||||
loadPlugin(manifest.id);
|
||||
} else {
|
||||
knownManifests[absPath] = { mtime: mtimeEpochMs, source: sourceTag, shadowedBy: existing.source }
|
||||
pathToPluginId[absPath] = manifest.id
|
||||
knownManifests[absPath] = {
|
||||
mtime: mtimeEpochMs,
|
||||
source: sourceTag,
|
||||
shadowedBy: existing.source
|
||||
};
|
||||
pathToPluginId[absPath] = manifest.id;
|
||||
}
|
||||
}
|
||||
|
||||
function unregisterPluginByPath(absPath, pluginId) {
|
||||
const current = availablePlugins[pluginId]
|
||||
const current = availablePlugins[pluginId];
|
||||
if (current && current.manifestPath === absPath) {
|
||||
if (current.loaded) unloadPlugin(pluginId)
|
||||
const newMap = Object.assign({}, availablePlugins)
|
||||
delete newMap[pluginId]
|
||||
availablePlugins = newMap
|
||||
if (current.loaded)
|
||||
unloadPlugin(pluginId);
|
||||
const newMap = Object.assign({}, availablePlugins);
|
||||
delete newMap[pluginId];
|
||||
availablePlugins = newMap;
|
||||
}
|
||||
}
|
||||
|
||||
function loadPlugin(pluginId) {
|
||||
const plugin = availablePlugins[pluginId]
|
||||
function loadPlugin(pluginId, bustCache) {
|
||||
const plugin = availablePlugins[pluginId];
|
||||
if (!plugin) {
|
||||
console.error("PluginService: Plugin not found:", pluginId)
|
||||
pluginLoadFailed(pluginId, "Plugin not found")
|
||||
return false
|
||||
console.error("PluginService: Plugin not found:", pluginId);
|
||||
pluginLoadFailed(pluginId, "Plugin not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (plugin.loaded) {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
const isDaemon = plugin.type === "daemon"
|
||||
const isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher"))
|
||||
const map = isDaemon ? pluginDaemonComponents : isLauncher ? pluginLauncherComponents : pluginWidgetComponents
|
||||
const isDaemon = plugin.type === "daemon";
|
||||
const isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher"));
|
||||
|
||||
const prevInstance = pluginInstances[pluginId]
|
||||
const prevInstance = pluginInstances[pluginId];
|
||||
if (prevInstance) {
|
||||
prevInstance.destroy()
|
||||
const newInstances = Object.assign({}, pluginInstances)
|
||||
delete newInstances[pluginId]
|
||||
pluginInstances = newInstances
|
||||
prevInstance.destroy();
|
||||
const newInstances = Object.assign({}, pluginInstances);
|
||||
delete newInstances[pluginId];
|
||||
pluginInstances = newInstances;
|
||||
}
|
||||
|
||||
try {
|
||||
const url = "file://" + plugin.componentPath
|
||||
const comp = Qt.createComponent(url, Component.PreferSynchronous)
|
||||
let url = "file://" + plugin.componentPath;
|
||||
if (bustCache)
|
||||
url += "?t=" + Date.now();
|
||||
const comp = Qt.createComponent(url, Component.PreferSynchronous);
|
||||
if (comp.status === Component.Error) {
|
||||
console.error("PluginService: component error", pluginId, comp.errorString())
|
||||
pluginLoadFailed(pluginId, comp.errorString())
|
||||
return false
|
||||
console.error("PluginService: component error", pluginId, comp.errorString());
|
||||
pluginLoadFailed(pluginId, comp.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isDaemon) {
|
||||
const instance = comp.createObject(root, { "pluginId": pluginId })
|
||||
const instance = comp.createObject(root, {
|
||||
"pluginId": pluginId
|
||||
});
|
||||
if (!instance) {
|
||||
console.error("PluginService: failed to instantiate daemon:", pluginId, comp.errorString())
|
||||
pluginLoadFailed(pluginId, comp.errorString())
|
||||
return false
|
||||
console.error("PluginService: failed to instantiate daemon:", pluginId, comp.errorString());
|
||||
pluginLoadFailed(pluginId, comp.errorString());
|
||||
return false;
|
||||
}
|
||||
const newInstances = Object.assign({}, pluginInstances)
|
||||
newInstances[pluginId] = instance
|
||||
pluginInstances = newInstances
|
||||
const newInstances = Object.assign({}, pluginInstances);
|
||||
newInstances[pluginId] = instance;
|
||||
pluginInstances = newInstances;
|
||||
|
||||
const newDaemons = Object.assign({}, pluginDaemonComponents)
|
||||
newDaemons[pluginId] = comp
|
||||
pluginDaemonComponents = newDaemons
|
||||
const newDaemons = Object.assign({}, pluginDaemonComponents);
|
||||
newDaemons[pluginId] = comp;
|
||||
pluginDaemonComponents = newDaemons;
|
||||
} else if (isLauncher) {
|
||||
const newLaunchers = Object.assign({}, pluginLauncherComponents)
|
||||
newLaunchers[pluginId] = comp
|
||||
pluginLauncherComponents = newLaunchers
|
||||
const newLaunchers = Object.assign({}, pluginLauncherComponents);
|
||||
newLaunchers[pluginId] = comp;
|
||||
pluginLauncherComponents = newLaunchers;
|
||||
} else {
|
||||
const newComponents = Object.assign({}, pluginWidgetComponents)
|
||||
newComponents[pluginId] = comp
|
||||
pluginWidgetComponents = newComponents
|
||||
const newComponents = Object.assign({}, pluginWidgetComponents);
|
||||
newComponents[pluginId] = comp;
|
||||
pluginWidgetComponents = newComponents;
|
||||
}
|
||||
|
||||
plugin.loaded = true
|
||||
loadedPlugins[pluginId] = plugin
|
||||
|
||||
pluginLoaded(pluginId)
|
||||
return true
|
||||
plugin.loaded = true;
|
||||
const newLoaded = Object.assign({}, loadedPlugins);
|
||||
newLoaded[pluginId] = plugin;
|
||||
loadedPlugins = newLoaded;
|
||||
|
||||
pluginLoaded(pluginId);
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error("PluginService: Error loading plugin:", pluginId, e.message)
|
||||
pluginLoadFailed(pluginId, e.message)
|
||||
return false
|
||||
console.error("PluginService: Error loading plugin:", pluginId, e.message);
|
||||
pluginLoadFailed(pluginId, e.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function unloadPlugin(pluginId) {
|
||||
const plugin = loadedPlugins[pluginId]
|
||||
const plugin = loadedPlugins[pluginId];
|
||||
if (!plugin) {
|
||||
console.warn("PluginService: Plugin not loaded:", pluginId)
|
||||
return false
|
||||
console.warn("PluginService: Plugin not loaded:", pluginId);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const isDaemon = plugin.type === "daemon"
|
||||
const isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher"))
|
||||
const isDaemon = plugin.type === "daemon";
|
||||
const isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher"));
|
||||
|
||||
const instance = pluginInstances[pluginId]
|
||||
const instance = pluginInstances[pluginId];
|
||||
if (instance) {
|
||||
instance.destroy()
|
||||
const newInstances = Object.assign({}, pluginInstances)
|
||||
delete newInstances[pluginId]
|
||||
pluginInstances = newInstances
|
||||
instance.destroy();
|
||||
const newInstances = Object.assign({}, pluginInstances);
|
||||
delete newInstances[pluginId];
|
||||
pluginInstances = newInstances;
|
||||
}
|
||||
|
||||
if (isDaemon && pluginDaemonComponents[pluginId]) {
|
||||
const newDaemons = Object.assign({}, pluginDaemonComponents)
|
||||
delete newDaemons[pluginId]
|
||||
pluginDaemonComponents = newDaemons
|
||||
const newDaemons = Object.assign({}, pluginDaemonComponents);
|
||||
delete newDaemons[pluginId];
|
||||
pluginDaemonComponents = newDaemons;
|
||||
} else if (isLauncher && pluginLauncherComponents[pluginId]) {
|
||||
const newLaunchers = Object.assign({}, pluginLauncherComponents)
|
||||
delete newLaunchers[pluginId]
|
||||
pluginLauncherComponents = newLaunchers
|
||||
const newLaunchers = Object.assign({}, pluginLauncherComponents);
|
||||
delete newLaunchers[pluginId];
|
||||
pluginLauncherComponents = newLaunchers;
|
||||
} else if (pluginWidgetComponents[pluginId]) {
|
||||
const newComponents = Object.assign({}, pluginWidgetComponents)
|
||||
delete newComponents[pluginId]
|
||||
pluginWidgetComponents = newComponents
|
||||
const newComponents = Object.assign({}, pluginWidgetComponents);
|
||||
delete newComponents[pluginId];
|
||||
pluginWidgetComponents = newComponents;
|
||||
}
|
||||
|
||||
plugin.loaded = false
|
||||
delete loadedPlugins[pluginId]
|
||||
|
||||
pluginUnloaded(pluginId)
|
||||
return true
|
||||
plugin.loaded = false;
|
||||
const newLoaded = Object.assign({}, loadedPlugins);
|
||||
delete newLoaded[pluginId];
|
||||
loadedPlugins = newLoaded;
|
||||
|
||||
pluginUnloaded(pluginId);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("PluginService: Error unloading plugin:", pluginId, "Error:", error.message)
|
||||
return false
|
||||
console.error("PluginService: Error unloading plugin:", pluginId, "Error:", error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getWidgetComponents() {
|
||||
return pluginWidgetComponents
|
||||
return pluginWidgetComponents;
|
||||
}
|
||||
|
||||
function getDaemonComponents() {
|
||||
return pluginDaemonComponents
|
||||
return pluginDaemonComponents;
|
||||
}
|
||||
|
||||
function getAvailablePlugins() {
|
||||
const result = []
|
||||
return availablePluginsList;
|
||||
}
|
||||
|
||||
function _updateAvailablePluginsList() {
|
||||
const result = [];
|
||||
for (const key in availablePlugins) {
|
||||
result.push(availablePlugins[key])
|
||||
result.push(availablePlugins[key]);
|
||||
}
|
||||
return result
|
||||
availablePluginsList = result;
|
||||
}
|
||||
|
||||
function getPluginVariants(pluginId) {
|
||||
const plugin = availablePlugins[pluginId]
|
||||
const plugin = availablePlugins[pluginId];
|
||||
if (!plugin) {
|
||||
return []
|
||||
return [];
|
||||
}
|
||||
const variants = SettingsData.getPluginSetting(pluginId, "variants", [])
|
||||
return variants
|
||||
const variants = SettingsData.getPluginSetting(pluginId, "variants", []);
|
||||
return variants;
|
||||
}
|
||||
|
||||
function getAllPluginVariants() {
|
||||
const result = []
|
||||
const result = [];
|
||||
for (const pluginId in availablePlugins) {
|
||||
const plugin = availablePlugins[pluginId]
|
||||
const plugin = availablePlugins[pluginId];
|
||||
if (plugin.type !== "widget") {
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
const variants = getPluginVariants(pluginId)
|
||||
const variants = getPluginVariants(pluginId);
|
||||
if (variants.length === 0) {
|
||||
result.push({
|
||||
pluginId: pluginId,
|
||||
@@ -379,10 +414,10 @@ Singleton {
|
||||
icon: plugin.icon || "extension",
|
||||
description: plugin.description || "Plugin widget",
|
||||
loaded: plugin.loaded
|
||||
})
|
||||
});
|
||||
} else {
|
||||
for (let i = 0; i < variants.length; i++) {
|
||||
const variant = variants[i]
|
||||
const variant = variants[i];
|
||||
result.push({
|
||||
pluginId: pluginId,
|
||||
variantId: variant.id,
|
||||
@@ -391,244 +426,245 @@ Singleton {
|
||||
icon: variant.icon || plugin.icon || "extension",
|
||||
description: variant.description || plugin.description || "Plugin widget variant",
|
||||
loaded: plugin.loaded
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
return result;
|
||||
}
|
||||
|
||||
function createPluginVariant(pluginId, variantName, variantConfig) {
|
||||
const variants = getPluginVariants(pluginId)
|
||||
const variantId = "variant_" + Date.now()
|
||||
const variants = getPluginVariants(pluginId);
|
||||
const variantId = "variant_" + Date.now();
|
||||
const newVariant = Object.assign({}, variantConfig, {
|
||||
id: variantId,
|
||||
name: variantName
|
||||
})
|
||||
variants.push(newVariant)
|
||||
SettingsData.setPluginSetting(pluginId, "variants", variants)
|
||||
pluginDataChanged(pluginId)
|
||||
return variantId
|
||||
});
|
||||
variants.push(newVariant);
|
||||
SettingsData.setPluginSetting(pluginId, "variants", variants);
|
||||
pluginDataChanged(pluginId);
|
||||
return variantId;
|
||||
}
|
||||
|
||||
function removePluginVariant(pluginId, variantId) {
|
||||
const variants = getPluginVariants(pluginId)
|
||||
const newVariants = variants.filter(function(v) { return v.id !== variantId })
|
||||
SettingsData.setPluginSetting(pluginId, "variants", newVariants)
|
||||
const variants = getPluginVariants(pluginId);
|
||||
const newVariants = variants.filter(function (v) {
|
||||
return v.id !== variantId;
|
||||
});
|
||||
SettingsData.setPluginSetting(pluginId, "variants", newVariants);
|
||||
|
||||
const fullId = pluginId + ":" + variantId
|
||||
removeWidgetFromDankBar(fullId)
|
||||
const fullId = pluginId + ":" + variantId;
|
||||
removeWidgetFromDankBar(fullId);
|
||||
|
||||
pluginDataChanged(pluginId)
|
||||
pluginDataChanged(pluginId);
|
||||
}
|
||||
|
||||
function removeWidgetFromDankBar(widgetId) {
|
||||
function filterWidget(widget) {
|
||||
const id = typeof widget === "string" ? widget : widget.id
|
||||
return id !== widgetId
|
||||
const id = typeof widget === "string" ? widget : widget.id;
|
||||
return id !== widgetId;
|
||||
}
|
||||
|
||||
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
|
||||
if (!defaultBar) return
|
||||
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default");
|
||||
if (!defaultBar)
|
||||
return;
|
||||
const leftWidgets = defaultBar.leftWidgets || [];
|
||||
const centerWidgets = defaultBar.centerWidgets || [];
|
||||
const rightWidgets = defaultBar.rightWidgets || [];
|
||||
|
||||
const leftWidgets = defaultBar.leftWidgets || []
|
||||
const centerWidgets = defaultBar.centerWidgets || []
|
||||
const rightWidgets = defaultBar.rightWidgets || []
|
||||
|
||||
const newLeft = leftWidgets.filter(filterWidget)
|
||||
const newCenter = centerWidgets.filter(filterWidget)
|
||||
const newRight = rightWidgets.filter(filterWidget)
|
||||
const newLeft = leftWidgets.filter(filterWidget);
|
||||
const newCenter = centerWidgets.filter(filterWidget);
|
||||
const newRight = rightWidgets.filter(filterWidget);
|
||||
|
||||
if (newLeft.length !== leftWidgets.length) {
|
||||
SettingsData.setDankBarLeftWidgets(newLeft)
|
||||
SettingsData.setDankBarLeftWidgets(newLeft);
|
||||
}
|
||||
if (newCenter.length !== centerWidgets.length) {
|
||||
SettingsData.setDankBarCenterWidgets(newCenter)
|
||||
SettingsData.setDankBarCenterWidgets(newCenter);
|
||||
}
|
||||
if (newRight.length !== rightWidgets.length) {
|
||||
SettingsData.setDankBarRightWidgets(newRight)
|
||||
SettingsData.setDankBarRightWidgets(newRight);
|
||||
}
|
||||
}
|
||||
|
||||
function updatePluginVariant(pluginId, variantId, variantConfig) {
|
||||
const variants = getPluginVariants(pluginId)
|
||||
const variants = getPluginVariants(pluginId);
|
||||
for (let i = 0; i < variants.length; i++) {
|
||||
if (variants[i].id === variantId) {
|
||||
variants[i] = Object.assign({}, variants[i], variantConfig)
|
||||
break
|
||||
variants[i] = Object.assign({}, variants[i], variantConfig);
|
||||
break;
|
||||
}
|
||||
}
|
||||
SettingsData.setPluginSetting(pluginId, "variants", variants)
|
||||
pluginDataChanged(pluginId)
|
||||
SettingsData.setPluginSetting(pluginId, "variants", variants);
|
||||
pluginDataChanged(pluginId);
|
||||
}
|
||||
|
||||
function getPluginVariantData(pluginId, variantId) {
|
||||
const variants = getPluginVariants(pluginId)
|
||||
const variants = getPluginVariants(pluginId);
|
||||
for (let i = 0; i < variants.length; i++) {
|
||||
if (variants[i].id === variantId) {
|
||||
return variants[i]
|
||||
return variants[i];
|
||||
}
|
||||
}
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
function getLoadedPlugins() {
|
||||
const result = []
|
||||
const result = [];
|
||||
for (const key in loadedPlugins) {
|
||||
result.push(loadedPlugins[key])
|
||||
result.push(loadedPlugins[key]);
|
||||
}
|
||||
return result
|
||||
return result;
|
||||
}
|
||||
|
||||
function isPluginLoaded(pluginId) {
|
||||
return loadedPlugins[pluginId] !== undefined
|
||||
return loadedPlugins[pluginId] !== undefined;
|
||||
}
|
||||
|
||||
function enablePlugin(pluginId) {
|
||||
SettingsData.setPluginSetting(pluginId, "enabled", true)
|
||||
return loadPlugin(pluginId)
|
||||
SettingsData.setPluginSetting(pluginId, "enabled", true);
|
||||
return loadPlugin(pluginId);
|
||||
}
|
||||
|
||||
function disablePlugin(pluginId) {
|
||||
SettingsData.setPluginSetting(pluginId, "enabled", false)
|
||||
return unloadPlugin(pluginId)
|
||||
SettingsData.setPluginSetting(pluginId, "enabled", false);
|
||||
return unloadPlugin(pluginId);
|
||||
}
|
||||
|
||||
function reloadPlugin(pluginId) {
|
||||
if (isPluginLoaded(pluginId)) {
|
||||
unloadPlugin(pluginId)
|
||||
}
|
||||
return loadPlugin(pluginId)
|
||||
if (isPluginLoaded(pluginId))
|
||||
unloadPlugin(pluginId);
|
||||
return loadPlugin(pluginId, true);
|
||||
}
|
||||
|
||||
function savePluginData(pluginId, key, value) {
|
||||
SettingsData.setPluginSetting(pluginId, key, value)
|
||||
pluginDataChanged(pluginId)
|
||||
return true
|
||||
SettingsData.setPluginSetting(pluginId, key, value);
|
||||
pluginDataChanged(pluginId);
|
||||
return true;
|
||||
}
|
||||
|
||||
function loadPluginData(pluginId, key, defaultValue) {
|
||||
return SettingsData.getPluginSetting(pluginId, key, defaultValue)
|
||||
return SettingsData.getPluginSetting(pluginId, key, defaultValue);
|
||||
}
|
||||
|
||||
function saveAllPluginSettings() {
|
||||
SettingsData.savePluginSettings()
|
||||
SettingsData.savePluginSettings();
|
||||
}
|
||||
|
||||
function scanPlugins() {
|
||||
resyncDebounce.restart()
|
||||
resyncDebounce.restart();
|
||||
}
|
||||
|
||||
function forceRescanPlugin(pluginId) {
|
||||
const plugin = availablePlugins[pluginId]
|
||||
const plugin = availablePlugins[pluginId];
|
||||
if (plugin && plugin.manifestPath) {
|
||||
const manifestPath = plugin.manifestPath
|
||||
const source = plugin.source || "user"
|
||||
delete knownManifests[manifestPath]
|
||||
const newMap = Object.assign({}, availablePlugins)
|
||||
delete newMap[pluginId]
|
||||
availablePlugins = newMap
|
||||
loadPluginManifestFile(manifestPath, source, Date.now())
|
||||
const manifestPath = plugin.manifestPath;
|
||||
const source = plugin.source || "user";
|
||||
delete knownManifests[manifestPath];
|
||||
const newMap = Object.assign({}, availablePlugins);
|
||||
delete newMap[pluginId];
|
||||
availablePlugins = newMap;
|
||||
loadPluginManifestFile(manifestPath, source, Date.now());
|
||||
}
|
||||
}
|
||||
|
||||
function createPluginDirectory() {
|
||||
const mkdirProcess = Qt.createComponent("data:text/plain,import Quickshell.Io; Process { }")
|
||||
const mkdirProcess = Qt.createComponent("data:text/plain,import Quickshell.Io; Process { }");
|
||||
if (mkdirProcess.status === Component.Ready) {
|
||||
const process = mkdirProcess.createObject(root)
|
||||
process.command = ["mkdir", "-p", pluginDirectory]
|
||||
process.exited.connect(function(exitCode) {
|
||||
const process = mkdirProcess.createObject(root);
|
||||
process.command = ["mkdir", "-p", pluginDirectory];
|
||||
process.exited.connect(function (exitCode) {
|
||||
if (exitCode !== 0) {
|
||||
console.error("PluginService: Failed to create plugin directory, exit code:", exitCode)
|
||||
console.error("PluginService: Failed to create plugin directory, exit code:", exitCode);
|
||||
}
|
||||
process.destroy()
|
||||
})
|
||||
process.running = true
|
||||
return true
|
||||
process.destroy();
|
||||
});
|
||||
process.running = true;
|
||||
return true;
|
||||
} else {
|
||||
console.error("PluginService: Failed to create mkdir process")
|
||||
return false
|
||||
console.error("PluginService: Failed to create mkdir process");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Launcher plugin helper functions
|
||||
function getLauncherPlugins() {
|
||||
const launchers = {}
|
||||
const launchers = {};
|
||||
|
||||
// Check plugins that have launcher components
|
||||
for (const pluginId in pluginLauncherComponents) {
|
||||
const plugin = availablePlugins[pluginId]
|
||||
const plugin = availablePlugins[pluginId];
|
||||
if (plugin && plugin.loaded) {
|
||||
launchers[pluginId] = plugin
|
||||
launchers[pluginId] = plugin;
|
||||
}
|
||||
}
|
||||
return launchers
|
||||
return launchers;
|
||||
}
|
||||
|
||||
function getLauncherPlugin(pluginId) {
|
||||
const plugin = availablePlugins[pluginId]
|
||||
const plugin = availablePlugins[pluginId];
|
||||
if (plugin && plugin.loaded && pluginLauncherComponents[pluginId]) {
|
||||
return plugin
|
||||
return plugin;
|
||||
}
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
function getPluginTrigger(pluginId) {
|
||||
const plugin = getLauncherPlugin(pluginId)
|
||||
const plugin = getLauncherPlugin(pluginId);
|
||||
if (plugin) {
|
||||
// Check if noTrigger is set (always active mode)
|
||||
const noTrigger = SettingsData.getPluginSetting(pluginId, "noTrigger", false)
|
||||
const noTrigger = SettingsData.getPluginSetting(pluginId, "noTrigger", false);
|
||||
if (noTrigger) {
|
||||
return ""
|
||||
return "";
|
||||
}
|
||||
// Otherwise load the custom trigger, defaulting to plugin manifest trigger
|
||||
const customTrigger = SettingsData.getPluginSetting(pluginId, "trigger", plugin.trigger || "!")
|
||||
return customTrigger
|
||||
const customTrigger = SettingsData.getPluginSetting(pluginId, "trigger", plugin.trigger || "!");
|
||||
return customTrigger;
|
||||
}
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
function getAllPluginTriggers() {
|
||||
const triggers = {}
|
||||
const launchers = getLauncherPlugins()
|
||||
const triggers = {};
|
||||
const launchers = getLauncherPlugins();
|
||||
|
||||
for (const pluginId in launchers) {
|
||||
const trigger = getPluginTrigger(pluginId)
|
||||
const trigger = getPluginTrigger(pluginId);
|
||||
if (trigger && trigger.trim() !== "") {
|
||||
triggers[trigger] = pluginId
|
||||
triggers[trigger] = pluginId;
|
||||
}
|
||||
}
|
||||
return triggers
|
||||
return triggers;
|
||||
}
|
||||
|
||||
function getPluginsWithEmptyTrigger() {
|
||||
const plugins = []
|
||||
const launchers = getLauncherPlugins()
|
||||
const plugins = [];
|
||||
const launchers = getLauncherPlugins();
|
||||
|
||||
for (const pluginId in launchers) {
|
||||
const trigger = getPluginTrigger(pluginId)
|
||||
const trigger = getPluginTrigger(pluginId);
|
||||
if (!trigger || trigger.trim() === "") {
|
||||
plugins.push(pluginId)
|
||||
plugins.push(pluginId);
|
||||
}
|
||||
}
|
||||
return plugins
|
||||
return plugins;
|
||||
}
|
||||
|
||||
function getGlobalVar(pluginId, varName, defaultValue) {
|
||||
if (globalVars[pluginId] && varName in globalVars[pluginId]) {
|
||||
return globalVars[pluginId][varName]
|
||||
return globalVars[pluginId][varName];
|
||||
}
|
||||
return defaultValue
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
function setGlobalVar(pluginId, varName, value) {
|
||||
const newGlobals = Object.assign({}, globalVars)
|
||||
const newGlobals = Object.assign({}, globalVars);
|
||||
if (!newGlobals[pluginId]) {
|
||||
newGlobals[pluginId] = {}
|
||||
newGlobals[pluginId] = {};
|
||||
}
|
||||
newGlobals[pluginId] = Object.assign({}, newGlobals[pluginId])
|
||||
newGlobals[pluginId][varName] = value
|
||||
globalVars = newGlobals
|
||||
globalVarChanged(pluginId, varName)
|
||||
newGlobals[pluginId] = Object.assign({}, newGlobals[pluginId]);
|
||||
newGlobals[pluginId][varName] = value;
|
||||
globalVars = newGlobals;
|
||||
globalVarChanged(pluginId, varName);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user