1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-09 23:32:10 -04:00

plugins/desktop-widgets: create a new "desktop" widget plugin type

- Draggable per-monitor background layer widgets
- Add basic dms version checks on plugins
- Clock: built-in clock desktop plugin
- dgop: built-in system monitor desktop plugin
This commit is contained in:
bbedward
2025-12-17 12:08:03 -05:00
parent d082d41ab9
commit 0034926df7
27 changed files with 4135 additions and 62 deletions

View File

@@ -6,6 +6,7 @@ import QtQuick
import Qt.labs.folderlistmodel
import Quickshell
import qs.Common
import qs.Services
Singleton {
id: root
@@ -15,6 +16,7 @@ Singleton {
property var pluginWidgetComponents: ({})
property var pluginDaemonComponents: ({})
property var pluginLauncherComponents: ({})
property var pluginDesktopComponents: ({})
property var availablePluginsList: []
property string pluginDirectory: {
var configDir = StandardPaths.writableLocation(StandardPaths.ConfigLocation);
@@ -206,6 +208,7 @@ Singleton {
info.loaded = isPluginLoaded(manifest.id);
info.type = manifest.type || "widget";
info.source = sourceTag;
info.requires_dms = manifest.requires_dms || null;
const existing = availablePlugins[manifest.id];
const shouldReplace = (!existing) || (existing && existing.source === "system" && sourceTag === "user");
@@ -262,6 +265,7 @@ Singleton {
const isDaemon = plugin.type === "daemon";
const isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher"));
const isDesktop = plugin.type === "desktop";
const prevInstance = pluginInstances[pluginId];
if (prevInstance) {
@@ -302,6 +306,10 @@ Singleton {
const newLaunchers = Object.assign({}, pluginLauncherComponents);
newLaunchers[pluginId] = comp;
pluginLauncherComponents = newLaunchers;
} else if (isDesktop) {
const newDesktop = Object.assign({}, pluginDesktopComponents);
newDesktop[pluginId] = comp;
pluginDesktopComponents = newDesktop;
} else {
const newComponents = Object.assign({}, pluginWidgetComponents);
newComponents[pluginId] = comp;
@@ -332,6 +340,7 @@ Singleton {
try {
const isDaemon = plugin.type === "daemon";
const isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher"));
const isDesktop = plugin.type === "desktop";
const instance = pluginInstances[pluginId];
if (instance) {
@@ -349,6 +358,10 @@ Singleton {
const newLaunchers = Object.assign({}, pluginLauncherComponents);
delete newLaunchers[pluginId];
pluginLauncherComponents = newLaunchers;
} else if (isDesktop && pluginDesktopComponents[pluginId]) {
const newDesktop = Object.assign({}, pluginDesktopComponents);
delete newDesktop[pluginId];
pluginDesktopComponents = newDesktop;
} else if (pluginWidgetComponents[pluginId]) {
const newComponents = Object.assign({}, pluginWidgetComponents);
delete newComponents[pluginId];
@@ -376,6 +389,10 @@ Singleton {
return pluginDaemonComponents;
}
function getDesktopComponents() {
return pluginDesktopComponents;
}
function getAvailablePlugins() {
return availablePluginsList;
}
@@ -667,4 +684,21 @@ Singleton {
globalVars = newGlobals;
globalVarChanged(pluginId, varName);
}
function checkPluginCompatibility(requiresDms) {
if (!requiresDms)
return true;
return SystemUpdateService.checkVersionRequirement(requiresDms, SystemUpdateService.getParsedShellVersion());
}
function getIncompatiblePlugins() {
const result = [];
for (const pluginId in availablePlugins) {
const plugin = availablePlugins[pluginId];
if (plugin.loaded && plugin.requires_dms && !checkPluginCompatibility(plugin.requires_dms)) {
result.push(plugin);
}
}
return result;
}
}

View File

@@ -20,6 +20,11 @@ Singleton {
property bool distributionSupported: false
property string shellVersion: ""
property string shellCodename: ""
property string semverVersion: ""
function getParsedShellVersion() {
return parseVersion(semverVersion);
}
readonly property var archBasedUCSettings: {
"listUpdatesSettings": {
@@ -135,6 +140,18 @@ Singleton {
}
}
Process {
id: semverDetection
command: ["sh", "-c", `cd "${Quickshell.shellDir}" && if [ -f VERSION ]; then cat VERSION; fi`]
running: true
stdout: StdioCollector {
onStreamFinished: {
semverVersion = text.trim();
}
}
}
Process {
id: codenameDetection
command: ["sh", "-c", `cd "${Quickshell.shellDir}" && if [ -f CODENAME ]; then cat CODENAME; fi`]
@@ -288,4 +305,86 @@ Singleton {
return "SUCCESS: Now checking...";
}
}
function parseVersion(versionStr) {
if (!versionStr || typeof versionStr !== "string")
return {
major: 0,
minor: 0,
patch: 0
};
let v = versionStr.trim();
if (v.startsWith("v"))
v = v.substring(1);
const dashIdx = v.indexOf("-");
if (dashIdx !== -1)
v = v.substring(0, dashIdx);
const plusIdx = v.indexOf("+");
if (plusIdx !== -1)
v = v.substring(0, plusIdx);
const parts = v.split(".");
return {
major: parseInt(parts[0], 10) || 0,
minor: parseInt(parts[1], 10) || 0,
patch: parseInt(parts[2], 10) || 0
};
}
function compareVersions(v1, v2) {
if (v1.major !== v2.major)
return v1.major - v2.major;
if (v1.minor !== v2.minor)
return v1.minor - v2.minor;
return v1.patch - v2.patch;
}
function checkVersionRequirement(requirementStr, currentVersion) {
if (!requirementStr || typeof requirementStr !== "string")
return true;
const req = requirementStr.trim();
let operator = "";
let versionPart = req;
if (req.startsWith(">=")) {
operator = ">=";
versionPart = req.substring(2);
} else if (req.startsWith("<=")) {
operator = "<=";
versionPart = req.substring(2);
} else if (req.startsWith(">")) {
operator = ">";
versionPart = req.substring(1);
} else if (req.startsWith("<")) {
operator = "<";
versionPart = req.substring(1);
} else if (req.startsWith("=")) {
operator = "=";
versionPart = req.substring(1);
} else {
operator = ">=";
}
const reqVersion = parseVersion(versionPart);
const cmp = compareVersions(currentVersion, reqVersion);
switch (operator) {
case ">=":
return cmp >= 0;
case ">":
return cmp > 0;
case "<=":
return cmp <= 0;
case "<":
return cmp < 0;
case "=":
return cmp === 0;
default:
return cmp >= 0;
}
}
}