summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services
diff options
context:
space:
mode:
Diffstat (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services')
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/AppSearchService.qml985
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/AudioService.qml1075
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BarWidgetService.qml171
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BatteryService.qml271
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BluetoothService.qml523
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BlurService.qml113
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CalendarService.qml317
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CavaService.qml76
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ChangelogService.qml108
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ClipboardService.qml275
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CompositorService.qml677
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CupsService.qml860
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DMSNetworkService.qml944
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DMSService.qml757
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DSearchService.qml184
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DesktopService.qml94
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DesktopWidgetRegistry.qml232
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DgopService.qml778
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DisplayService.qml1170
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DwlService.qml454
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ExtWorkspaceService.qml277
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/FirstLaunchService.qml111
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/HyprlandService.qml338
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/IdleService.qml191
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/KeybindsService.qml528
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/LegacyNetworkService.qml987
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/LocationService.qml55
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/MprisController.qml78
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/MultimediaService.qml35
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/MuxService.qml230
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NetworkService.qml313
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml1494
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NotepadStorageService.qml473
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NotificationService.qml1237
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PluginService.qml876
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PolkitService.qml40
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PopoutService.qml709
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PortalService.qml316
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PowerProfileWatcher.qml36
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PrivacyService.qml155
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/SessionService.qml619
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/SettingsSearchService.qml240
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/SystemUpdateService.qml396
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ToastService.qml174
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/TrackArtService.qml49
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/UserInfoService.qml35
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/VPNService.qml221
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/WallpaperCyclingService.qml495
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/WeatherService.qml914
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/WlrOutputService.qml346
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/niri-wpblur.kdl9
51 files changed, 0 insertions, 22041 deletions
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/AppSearchService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/AppSearchService.qml
deleted file mode 100644
index 1c8413f..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/AppSearchService.qml
+++ /dev/null
@@ -1,985 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import qs.Common
-
-Singleton {
- id: root
-
- property var applications: []
- property var _cachedCategories: null
- property var _cachedVisibleApps: null
- property var _hiddenAppsSet: new Set()
-
- property var _transformCache: ({})
- property var _cachedDefaultSections: []
- property var _cachedDefaultFlatModel: []
- property bool _defaultCacheValid: false
- property int cacheVersion: 0
-
- readonly property int maxResults: 10
- readonly property int frecencySampleSize: 10
-
- readonly property var timeBuckets: [
- {
- "maxDays": 4,
- "weight": 100
- },
- {
- "maxDays": 14,
- "weight": 70
- },
- {
- "maxDays": 31,
- "weight": 50
- },
- {
- "maxDays": 90,
- "weight": 30
- },
- {
- "maxDays": 99999,
- "weight": 10
- }
- ]
-
- function refreshApplications() {
- applications = DesktopEntries.applications.values;
- _cachedCategories = null;
- _cachedVisibleApps = null;
- invalidateLauncherCache();
- }
-
- function invalidateLauncherCache() {
- _transformCache = {};
- _defaultCacheValid = false;
- _cachedDefaultSections = [];
- _cachedDefaultFlatModel = [];
- cacheVersion++;
- }
-
- function getOrTransformApp(app, transformFn) {
- const id = app.id || app.execString || app.exec || "";
- if (!id)
- return transformFn(app);
- const cached = _transformCache[id];
- if (cached) {
- const currentIcon = app.icon || "";
- const cachedSourceIcon = cached._sourceIcon || "";
- if (currentIcon === cachedSourceIcon)
- return cached;
- }
- const transformed = transformFn(app);
- transformed._sourceIcon = app.icon || "";
- _transformCache[id] = transformed;
- return transformed;
- }
-
- function getCachedDefaultSections() {
- if (!_defaultCacheValid)
- return null;
- return _cachedDefaultSections;
- }
-
- function setCachedDefaultSections(sections, flatModel) {
- _cachedDefaultSections = sections.map(function (s) {
- return Object.assign({}, s, {
- items: s.items ? s.items.slice() : []
- });
- });
- _cachedDefaultFlatModel = flatModel.slice();
- _defaultCacheValid = true;
- }
-
- function isCacheValid() {
- return _defaultCacheValid;
- }
-
- function _rebuildHiddenSet() {
- _hiddenAppsSet = new Set(SessionData.hiddenApps || []);
- _cachedVisibleApps = null;
- }
-
- function isAppHidden(app) {
- if (!app)
- return false;
- const appId = app.id || app.execString || app.exec || "";
- return _hiddenAppsSet.has(appId);
- }
-
- function getVisibleApplications() {
- if (_cachedVisibleApps === null) {
- const seen = new Set();
- _cachedVisibleApps = applications.filter(app => {
- if (isAppHidden(app))
- return false;
- const id = app.id;
- if (id && seen.has(id))
- return false;
- if (id)
- seen.add(id);
- return true;
- });
- }
- return _cachedVisibleApps.map(app => applyAppOverride(app));
- }
-
- Connections {
- target: SessionData
- function onHiddenAppsChanged() {
- root._rebuildHiddenSet();
- root.invalidateLauncherCache();
- }
- function onAppOverridesChanged() {
- root._cachedVisibleApps = null;
- root.invalidateLauncherCache();
- }
- }
-
- Connections {
- target: AppUsageHistoryData
- function onAppUsageRankingChanged() {
- root.invalidateLauncherCache();
- }
- }
-
- function applyAppOverride(app) {
- if (!app)
- return app;
- const appId = app.id || app.execString || app.exec || "";
- const override = SessionData.getAppOverride(appId);
- if (!override)
- return app;
- return Object.assign({}, app, {
- name: override.name || app.name,
- icon: override.icon || app.icon,
- comment: override.comment || app.comment,
- _override: override
- });
- }
-
- readonly property string dmsLogoPath: Qt.resolvedUrl("../assets/danklogo2.svg")
-
- readonly property var builtInPlugins: ({
- "dms_settings": {
- id: "dms_settings",
- name: I18n.tr("Settings", "settings window title"),
- icon: "svg+corner:" + dmsLogoPath + "|settings",
- cornerIcon: "settings",
- comment: "DMS",
- action: "ipc:settings",
- categories: ["Settings", "System"],
- defaultTrigger: "",
- isLauncher: false
- },
- "dms_notepad": {
- id: "dms_notepad",
- name: I18n.tr("Notepad", "Notepad"),
- icon: "svg+corner:" + dmsLogoPath + "|description",
- cornerIcon: "description",
- comment: "DMS",
- action: "ipc:notepad",
- categories: ["Office", "Utility"],
- defaultTrigger: "",
- isLauncher: false
- },
- "dms_sysmon": {
- id: "dms_sysmon",
- name: I18n.tr("System Monitor", "sysmon window title"),
- icon: "svg+corner:" + dmsLogoPath + "|monitor_heart",
- cornerIcon: "monitor_heart",
- comment: "DMS",
- action: "ipc:processlist",
- categories: ["System", "Monitor"],
- defaultTrigger: "",
- isLauncher: false
- },
- "dms_colorpicker": {
- id: "dms_colorpicker",
- name: I18n.tr("Color Picker"),
- icon: "svg+corner:" + dmsLogoPath + "|palette",
- cornerIcon: "palette",
- comment: "DMS",
- action: "ipc:color-picker",
- categories: ["Graphics", "Utility"],
- defaultTrigger: "",
- isLauncher: false
- },
- "dms_settings_search": {
- id: "dms_settings_search",
- name: I18n.tr("Settings", "settings window title"),
- cornerIcon: "search",
- comment: "DMS",
- defaultTrigger: "?",
- isLauncher: true
- }
- })
-
- function getBuiltInPluginTrigger(pluginId) {
- const plugin = builtInPlugins[pluginId];
- if (!plugin)
- return null;
- return SettingsData.getBuiltInPluginSetting(pluginId, "trigger", plugin.defaultTrigger);
- }
-
- readonly property var coreApps: {
- SettingsData.builtInPluginSettings;
- const apps = [];
- for (const pluginId in builtInPlugins) {
- if (!SettingsData.getBuiltInPluginSetting(pluginId, "enabled", true))
- continue;
- const plugin = builtInPlugins[pluginId];
- if (plugin.isLauncher)
- continue;
- apps.push({
- name: plugin.name,
- icon: plugin.icon,
- comment: plugin.comment,
- action: plugin.action,
- categories: plugin.categories,
- isCore: true,
- builtInPluginId: pluginId,
- cornerIcon: plugin.cornerIcon
- });
- }
- return apps;
- }
-
- function getBuiltInLauncherPlugins() {
- const result = {};
- for (const pluginId in builtInPlugins) {
- const plugin = builtInPlugins[pluginId];
- if (!plugin.isLauncher)
- continue;
- if (!SettingsData.getBuiltInPluginSetting(pluginId, "enabled", true))
- continue;
- result[pluginId] = plugin;
- }
- return result;
- }
-
- function getBuiltInLauncherTriggers() {
- const triggers = {};
- const launchers = getBuiltInLauncherPlugins();
- for (const pluginId in launchers) {
- const trigger = getBuiltInPluginTrigger(pluginId);
- if (trigger && trigger.trim() !== "")
- triggers[trigger] = pluginId;
- }
- return triggers;
- }
-
- function getBuiltInLauncherPluginsWithEmptyTrigger() {
- const result = [];
- const launchers = getBuiltInLauncherPlugins();
- for (const pluginId in launchers) {
- const trigger = getBuiltInPluginTrigger(pluginId);
- if (!trigger || trigger.trim() === "")
- result.push(pluginId);
- }
- return result;
- }
-
- function getBuiltInLauncherItems(pluginId, query) {
- if (pluginId !== "dms_settings_search")
- return [];
-
- SettingsSearchService.search(query);
- const results = SettingsSearchService.results;
- const items = [];
- for (let i = 0; i < results.length; i++) {
- const r = results[i];
- items.push({
- name: r.label,
- icon: "material:" + r.icon,
- comment: r.category,
- action: "settings_nav:" + r.tabIndex + ":" + r.section,
- categories: ["Settings"],
- isCore: true,
- isBuiltInLauncher: true,
- builtInPluginId: pluginId
- });
- }
- return items;
- }
-
- function executeBuiltInLauncherItem(item) {
- if (!item?.action)
- return false;
-
- const parts = item.action.split(":");
- if (parts[0] !== "settings_nav")
- return false;
-
- const tabIndex = parseInt(parts[1]);
- const section = parts.slice(2).join(":");
- SettingsSearchService.navigateToSection(section);
- PopoutService.openSettingsWithTabIndex(tabIndex);
- return true;
- }
-
- function getCoreApps(query) {
- if (!query || query.length === 0)
- return coreApps;
- const lowerQuery = query.toLowerCase();
- return coreApps.filter(app => app.name.toLowerCase().includes(lowerQuery) || app.comment.toLowerCase().includes(lowerQuery));
- }
-
- function executeCoreApp(app) {
- if (!app?.action)
- return false;
-
- const parts = app.action.split(":");
- if (parts[0] !== "ipc")
- return false;
-
- switch (parts[1]) {
- case "settings":
- PopoutService.focusOrToggleSettings();
- return true;
- case "notepad":
- PopoutService.toggleNotepad();
- return true;
- case "processlist":
- PopoutService.toggleProcessListModal();
- return true;
- case "color-picker":
- PopoutService.showColorPicker();
- return true;
- }
- return false;
- }
-
- Connections {
- target: DesktopEntries
- function onApplicationsChanged() {
- root.refreshApplications();
- }
- }
-
- Component.onCompleted: {
- _rebuildHiddenSet();
- refreshApplications();
- }
-
- function tokenize(text) {
- return text.toLowerCase().trim().split(/[\s\-_]+/).filter(w => w.length > 0);
- }
-
- function wordBoundaryMatch(text, query) {
- const textWords = tokenize(text);
- const queryWords = tokenize(query);
-
- if (queryWords.length === 0)
- return false;
- if (queryWords.length > textWords.length)
- return false;
-
- for (var i = 0; i <= textWords.length - queryWords.length; i++) {
- let allMatch = true;
- for (var j = 0; j < queryWords.length; j++) {
- if (!textWords[i + j].startsWith(queryWords[j])) {
- allMatch = false;
- break;
- }
- }
- if (allMatch)
- return true;
- }
- return false;
- }
-
- function levenshteinDistance(s1, s2) {
- const len1 = s1.length;
- const len2 = s2.length;
- const matrix = [];
-
- for (var i = 0; i <= len1; i++) {
- matrix[i] = [i];
- }
- for (var j = 0; j <= len2; j++) {
- matrix[0][j] = j;
- }
-
- for (var i = 1; i <= len1; i++) {
- for (var j = 1; j <= len2; j++) {
- const cost = s1[i - 1] === s2[j - 1] ? 0 : 1;
- matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost);
- }
- }
- return matrix[len1][len2];
- }
-
- function fuzzyMatchScore(text, query) {
- const queryLower = query.toLowerCase();
- const maxDistance = query.length <= 2 ? 0 : query.length === 3 ? 1 : query.length <= 6 ? 2 : 3;
-
- let bestScore = 0;
-
- const distance = levenshteinDistance(text.toLowerCase(), queryLower);
- if (distance <= maxDistance) {
- const maxLen = Math.max(text.length, query.length);
- bestScore = 1 - (distance / maxLen);
- }
-
- const words = tokenize(text);
- for (const word of words) {
- const wordDistance = levenshteinDistance(word, queryLower);
- if (wordDistance <= maxDistance) {
- const maxLen = Math.max(word.length, query.length);
- const score = 1 - (wordDistance / maxLen);
- bestScore = Math.max(bestScore, score);
- }
- }
-
- return bestScore;
- }
-
- function calculateFrecency(app) {
- const usageRanking = AppUsageHistoryData.appUsageRanking || {};
- const appId = app.id || (app.execString || app.exec || "");
- const idVariants = [appId, appId.replace(".desktop", ""), app.id, app.id ? app.id.replace(".desktop", "") : null].filter(id => id);
-
- let usageData = null;
- for (const variant of idVariants) {
- if (usageRanking[variant]) {
- usageData = usageRanking[variant];
- break;
- }
- }
-
- if (!usageData || !usageData.usageCount) {
- return {
- "frecency": 0,
- "daysSinceUsed": 999999
- };
- }
-
- const usageCount = usageData.usageCount || 0;
- const lastUsed = usageData.lastUsed || 0;
- const now = Date.now();
- const daysSinceUsed = (now - lastUsed) / (1000 * 60 * 60 * 24);
-
- let timeBucketWeight = 10;
- for (const bucket of timeBuckets) {
- if (daysSinceUsed <= bucket.maxDays) {
- timeBucketWeight = bucket.weight;
- break;
- }
- }
-
- const contextBonus = 100;
- const sampleSize = Math.min(usageCount, frecencySampleSize);
- const frecency = (timeBucketWeight * contextBonus * sampleSize) / 100;
-
- return {
- "frecency": frecency,
- "daysSinceUsed": daysSinceUsed
- };
- }
-
- function searchApplications(query) {
- if (!query || query.length === 0)
- return getVisibleApplications();
- if (applications.length === 0)
- return [];
-
- const queryLower = query.toLowerCase().trim();
- const scoredApps = [];
- const results = [];
- const visibleApps = getVisibleApplications();
-
- for (const app of visibleApps) {
- const name = (app.name || "").toLowerCase();
- const genericName = (app.genericName || "").toLowerCase();
- const comment = (app.comment || "").toLowerCase();
- const id = (app.id || "").toLowerCase();
- const keywords = app.keywords ? app.keywords.map(k => k.toLowerCase()) : [];
-
- let textScore = 0;
- let matchType = "none";
-
- if (name === queryLower) {
- textScore = 10000;
- matchType = "exact";
- } else if (name.startsWith(queryLower)) {
- textScore = 5000;
- matchType = "prefix";
- } else if (wordBoundaryMatch(name, queryLower)) {
- textScore = 3000;
- matchType = "word_boundary";
- } else if (name.includes(queryLower)) {
- textScore = 500;
- matchType = "substring";
- } else if (genericName && genericName.startsWith(queryLower)) {
- textScore = 800;
- matchType = "generic_prefix";
- } else if (genericName && genericName.includes(queryLower)) {
- textScore = 400;
- matchType = "generic";
- } else if (id && id.includes(queryLower)) {
- textScore = 350;
- matchType = "id";
- }
-
- if (matchType === "none" && keywords.length > 0) {
- for (const keyword of keywords) {
- if (keyword.startsWith(queryLower)) {
- textScore = 300;
- matchType = "keyword_prefix";
- break;
- } else if (keyword.includes(queryLower)) {
- textScore = 150;
- matchType = "keyword";
- break;
- }
- }
- }
-
- if (matchType === "none" && comment && comment.includes(queryLower)) {
- textScore = 50;
- matchType = "comment";
- }
-
- if (matchType === "none") {
- const fuzzyScore = fuzzyMatchScore(name, queryLower);
- if (fuzzyScore > 0) {
- textScore = fuzzyScore * 100;
- matchType = "fuzzy";
- }
- }
-
- if (matchType !== "none") {
- const frecencyData = calculateFrecency(app);
-
- results.push({
- "app": app,
- "textScore": textScore,
- "frecency": frecencyData.frecency,
- "daysSinceUsed": frecencyData.daysSinceUsed,
- "matchType": matchType
- });
- }
- }
-
- for (const result of results) {
- const frecencyBonus = result.frecency > 0 ? Math.min(result.frecency, 2000) : 0;
- const recencyBonus = result.daysSinceUsed < 1 ? 1500 : result.daysSinceUsed < 7 ? 1000 : result.daysSinceUsed < 30 ? 500 : 0;
-
- const finalScore = result.textScore + frecencyBonus + recencyBonus;
-
- scoredApps.push({
- "app": result.app,
- "score": finalScore
- });
- }
-
- if (SessionData.searchAppActions) {
- const actionResults = searchAppActions(queryLower, visibleApps);
- for (const actionResult of actionResults) {
- scoredApps.push({
- app: actionResult.app,
- score: actionResult.score
- });
- }
- }
-
- scoredApps.sort((a, b) => b.score - a.score);
- return scoredApps.slice(0, maxResults).map(item => item.app);
- }
-
- function searchAppActions(query, apps) {
- const results = [];
- for (const app of apps) {
- if (!app.actions || app.actions.length === 0)
- continue;
- for (const action of app.actions) {
- const actionName = (action.name || "").toLowerCase();
- if (!actionName)
- continue;
-
- let score = 0;
- if (actionName === query) {
- score = 8000;
- } else if (actionName.startsWith(query)) {
- score = 4000;
- } else if (actionName.includes(query)) {
- score = 400;
- }
-
- if (score > 0) {
- results.push({
- app: {
- name: action.name,
- icon: action.icon || app.icon,
- comment: app.name,
- categories: app.categories || [],
- isAction: true,
- parentApp: app,
- actionData: action
- },
- score: score
- });
- }
- }
- }
- return results;
- }
-
- function getCategoriesForApp(app) {
- if (!app?.categories)
- return [];
-
- const categoryMap = {
- "AudioVideo": I18n.tr("Media"),
- "Audio": I18n.tr("Media"),
- "Video": I18n.tr("Media"),
- "Development": I18n.tr("Development"),
- "TextEditor": I18n.tr("Development"),
- "IDE": I18n.tr("Development"),
- "Education": I18n.tr("Education"),
- "Game": I18n.tr("Games"),
- "Graphics": I18n.tr("Graphics"),
- "Photography": I18n.tr("Graphics"),
- "Network": I18n.tr("Internet"),
- "WebBrowser": I18n.tr("Internet"),
- "Email": I18n.tr("Internet"),
- "Office": I18n.tr("Office"),
- "WordProcessor": I18n.tr("Office"),
- "Spreadsheet": I18n.tr("Office"),
- "Presentation": I18n.tr("Office"),
- "Science": I18n.tr("Science"),
- "Settings": I18n.tr("Settings"),
- "System": I18n.tr("System"),
- "Utility": I18n.tr("Utilities"),
- "Accessories": I18n.tr("Utilities"),
- "FileManager": I18n.tr("Utilities"),
- "TerminalEmulator": I18n.tr("Utilities")
- };
-
- const mappedCategories = new Set();
-
- for (const cat of app.categories) {
- if (categoryMap[cat])
- mappedCategories.add(categoryMap[cat]);
- }
-
- return Array.from(mappedCategories);
- }
-
- property var categoryIcons: ({
- "All": "apps",
- "Media": "music_video",
- "Development": "code",
- "Games": "sports_esports",
- "Graphics": "photo_library",
- "Internet": "web",
- "Office": "content_paste",
- "Settings": "settings",
- "System": "host",
- "Utilities": "build"
- })
-
- function getCategoryIcon(category) {
- // Check if it's a plugin category
- const pluginIcon = getPluginCategoryIcon(category);
- if (pluginIcon) {
- return pluginIcon;
- }
- return categoryIcons[category] || "folder";
- }
-
- function getAllCategories() {
- if (_cachedCategories)
- return _cachedCategories;
-
- const categories = new Set([I18n.tr("All")]);
- for (const app of applications) {
- const appCategories = getCategoriesForApp(app);
- appCategories.forEach(cat => categories.add(cat));
- }
-
- // Include categories from core apps (e.g. DMS Settings)
- for (const app of coreApps) {
- const appCategories = getCategoriesForApp(app);
- appCategories.forEach(cat => categories.add(cat));
- }
-
- const pluginCategories = getPluginCategories();
- pluginCategories.forEach(cat => categories.add(cat));
-
- _cachedCategories = Array.from(categories).sort();
- return _cachedCategories;
- }
-
- function getAppsInCategory(category) {
- const visibleApps = getVisibleApplications();
- if (category === I18n.tr("All"))
- return visibleApps;
-
- const pluginItems = getPluginItems(category, "");
- if (pluginItems.length > 0)
- return pluginItems;
-
- return visibleApps.filter(app => {
- const appCategories = getCategoriesForApp(app);
- return appCategories.includes(category);
- });
- }
-
- // Plugin launcher support functions
- function getPluginCategories() {
- if (typeof PluginService === "undefined") {
- return [];
- }
-
- const categories = [];
- const launchers = PluginService.getLauncherPlugins();
-
- for (const pluginId in launchers) {
- const plugin = launchers[pluginId];
- const categoryName = plugin.name || pluginId;
- categories.push(categoryName);
- }
-
- return categories;
- }
-
- function getPluginCategoryIcon(category) {
- if (typeof PluginService === "undefined")
- return null;
-
- const launchers = PluginService.getLauncherPlugins();
- for (const pluginId in launchers) {
- const plugin = launchers[pluginId];
- if ((plugin.name || pluginId) === category) {
- return plugin.icon || "extension";
- }
- }
- return null;
- }
-
- function getAllPluginItems() {
- if (typeof PluginService === "undefined") {
- return [];
- }
-
- let allItems = [];
- const launchers = PluginService.getLauncherPlugins();
-
- for (const pluginId in launchers) {
- const categoryName = launchers[pluginId].name || pluginId;
- const items = getPluginItems(categoryName, "");
- allItems = allItems.concat(items);
- }
-
- return allItems;
- }
-
- function getPluginItems(category, query) {
- if (typeof PluginService === "undefined")
- return [];
-
- const launchers = PluginService.getLauncherPlugins();
- for (const pluginId in launchers) {
- const plugin = launchers[pluginId];
- if ((plugin.name || pluginId) === category) {
- return getPluginItemsForPlugin(pluginId, query);
- }
- }
- return [];
- }
-
- function getPluginItemsForPlugin(pluginId, query) {
- if (typeof PluginService === "undefined") {
- return [];
- }
-
- let instance = PluginService.pluginInstances[pluginId];
- let isPersistent = true;
-
- if (!instance) {
- const component = PluginService.pluginLauncherComponents[pluginId];
- if (!component)
- return [];
-
- try {
- instance = component.createObject(root, {
- "pluginService": PluginService
- });
- isPersistent = false;
- } catch (e) {
- console.warn("AppSearchService: Error creating temporary plugin instance", pluginId, ":", e);
- return [];
- }
- }
-
- if (!instance)
- return [];
-
- try {
- if (typeof instance.getItems === "function") {
- const items = instance.getItems(query || "");
- if (!isPersistent)
- instance.destroy();
- return items || [];
- }
-
- if (!isPersistent) {
- instance.destroy();
- }
- } catch (e) {
- console.warn("AppSearchService: Error getting items from plugin", pluginId, ":", e);
- if (!isPersistent)
- instance.destroy();
- }
-
- return [];
- }
-
- function executePluginItem(item, pluginId) {
- if (typeof PluginService === "undefined")
- return false;
-
- let instance = PluginService.pluginInstances[pluginId];
- let isPersistent = true;
-
- if (!instance) {
- const component = PluginService.pluginLauncherComponents[pluginId];
- if (!component)
- return false;
-
- try {
- instance = component.createObject(root, {
- "pluginService": PluginService
- });
- isPersistent = false;
- } catch (e) {
- console.warn("AppSearchService: Error creating temporary plugin instance for execution", pluginId, ":", e);
- return false;
- }
- }
-
- if (!instance)
- return false;
-
- try {
- if (typeof instance.executeItem === "function") {
- instance.executeItem(item);
- if (!isPersistent)
- instance.destroy();
- return true;
- }
-
- if (!isPersistent) {
- instance.destroy();
- }
- } catch (e) {
- console.warn("AppSearchService: Error executing item from plugin", pluginId, ":", e);
- if (!isPersistent)
- instance.destroy();
- }
-
- return false;
- }
-
- function getPluginPasteText(pluginId, item) {
- if (typeof PluginService === "undefined")
- return null;
-
- const instance = PluginService.pluginInstances[pluginId];
- if (!instance)
- return null;
-
- if (typeof instance.getPasteText === "function") {
- return instance.getPasteText(item);
- }
-
- return null;
- }
-
- function getPluginPasteArgs(pluginId, item) {
- if (typeof PluginService === "undefined")
- return null;
-
- const instance = PluginService.pluginInstances[pluginId];
- if (!instance)
- return null;
-
- if (typeof instance.getPasteArgs === "function")
- return instance.getPasteArgs(item);
-
- if (typeof instance.getPasteText === "function") {
- const text = instance.getPasteText(item);
- if (text)
- return ["dms", "cl", "copy", text];
- }
-
- return null;
- }
-
- function searchPluginItems(query) {
- if (typeof PluginService === "undefined")
- return [];
-
- let allItems = [];
- const launchers = PluginService.getLauncherPlugins();
-
- for (const pluginId in launchers) {
- const items = getPluginItemsForPlugin(pluginId, query);
- allItems = allItems.concat(items);
- }
-
- return allItems;
- }
-
- function getPluginLauncherCategories(pluginId) {
- if (typeof PluginService === "undefined")
- return [];
-
- const instance = PluginService.pluginInstances[pluginId];
- if (!instance)
- return [];
-
- if (typeof instance.getCategories !== "function")
- return [];
-
- try {
- return instance.getCategories() || [];
- } catch (e) {
- console.warn("AppSearchService: Error getting categories from plugin", pluginId, ":", e);
- return [];
- }
- }
-
- function setPluginLauncherCategory(pluginId, categoryId) {
- if (typeof PluginService === "undefined")
- return;
-
- const instance = PluginService.pluginInstances[pluginId];
- if (!instance)
- return;
-
- if (typeof instance.setCategory !== "function")
- return;
-
- try {
- instance.setCategory(categoryId);
- } catch (e) {
- console.warn("AppSearchService: Error setting category on plugin", pluginId, ":", e);
- }
- }
-
- function pluginHasCategories(pluginId) {
- if (typeof PluginService === "undefined")
- return false;
-
- const instance = PluginService.pluginInstances[pluginId];
- if (!instance)
- return false;
-
- return typeof instance.getCategories === "function";
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/AudioService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/AudioService.qml
deleted file mode 100644
index 015fedc..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/AudioService.qml
+++ /dev/null
@@ -1,1075 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtCore
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import Quickshell.Services.Pipewire
-import qs.Common
-import qs.Services
-
-Singleton {
- id: root
-
- readonly property PwNode sink: Pipewire.defaultAudioSink
- readonly property PwNode source: Pipewire.defaultAudioSource
-
- readonly property bool soundsAvailable: MultimediaService.available
- property bool gsettingsAvailable: false
- property var availableSoundThemes: []
- property string currentSoundTheme: ""
- property var soundFilePaths: ({})
-
- property var volumeChangeSound: null
- property var powerPlugSound: null
- property var powerUnplugSound: null
- property var normalNotificationSound: null
- property var criticalNotificationSound: null
- property var loginSound: null
- property real notificationsVolume: 1.0
- property bool notificationsAudioMuted: false
-
- property var mediaDevices: null
- property var mediaDevicesConnections: null
-
- property var deviceAliases: ({})
- property string wireplumberConfigPath: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/wireplumber/wireplumber.conf.d/51-dms-audio-aliases.conf"
- property bool wireplumberReloading: false
-
- readonly property int sinkMaxVolume: {
- const name = sink?.name ?? "";
- if (!name)
- return 100;
- return SessionData.deviceMaxVolumes[name] ?? 100;
- }
-
- signal micMuteChanged
- signal audioOutputCycled(string deviceName, string deviceIcon)
- signal deviceAliasChanged(string nodeName, string newAlias)
- signal wireplumberReloadStarted
- signal wireplumberReloadCompleted(bool success)
-
- function getMaxVolumePercent(node) {
- if (!node?.name)
- return 100;
- return SessionData.deviceMaxVolumes[node.name] ?? 100;
- }
-
- Connections {
- target: SessionData
- function onDeviceMaxVolumesChanged() {
- if (!root.sink?.audio)
- return;
- const maxVol = root.sinkMaxVolume;
- const currentPercent = Math.round(root.sink.audio.volume * 100);
- if (currentPercent > maxVol)
- root.sink.audio.volume = maxVol / 100;
- }
- }
-
- // Used in playLoginSoundIfApplicable()
- Process {
- id: loginSoundChecker
- onExited: (exitCode) => {
- if (exitCode === 0) {
- playLoginSound();
- }
- }
-}
-
- function getAvailableSinks() {
- const hidden = SessionData.hiddenOutputDeviceNames ?? [];
- return Pipewire.nodes.values.filter(node => node.audio && node.isSink && !node.isStream && !hidden.includes(node.name));
- }
-
- function cycleAudioOutput() {
- const sinks = getAvailableSinks();
- if (sinks.length < 2)
- return null;
-
- const currentName = root.sink?.name ?? "";
- const currentIndex = sinks.findIndex(s => s.name === currentName);
- const nextIndex = (currentIndex + 1) % sinks.length;
- const nextSink = sinks[nextIndex];
- Pipewire.preferredDefaultAudioSink = nextSink;
- const name = displayName(nextSink);
- audioOutputCycled(name, sinkIcon(nextSink));
- return name;
- }
-
- function getDeviceAlias(nodeName) {
- if (!nodeName)
- return null;
- return deviceAliases[nodeName] || null;
- }
-
- function hasDeviceAlias(nodeName) {
- if (!nodeName)
- return false;
- return deviceAliases.hasOwnProperty(nodeName) && deviceAliases[nodeName] !== null && deviceAliases[nodeName] !== "";
- }
-
- function setDeviceAlias(nodeName, customAlias) {
- if (!nodeName) {
- console.error("AudioService: Cannot set alias - nodeName is empty");
- return false;
- }
-
- if (!customAlias || customAlias.trim() === "") {
- return removeDeviceAlias(nodeName);
- }
-
- const trimmedAlias = customAlias.trim();
-
- const updated = Object.assign({}, deviceAliases);
- updated[nodeName] = trimmedAlias;
- deviceAliases = updated;
-
- writeWireplumberConfig();
- deviceAliasChanged(nodeName, trimmedAlias);
- return true;
- }
-
- function removeDeviceAlias(nodeName) {
- if (!nodeName)
- return false;
-
- if (!hasDeviceAlias(nodeName))
- return false;
-
- const updated = Object.assign({}, deviceAliases);
- delete updated[nodeName];
- deviceAliases = updated;
-
- writeWireplumberConfig();
- deviceAliasChanged(nodeName, "");
- return true;
- }
-
- function writeWireplumberConfig() {
- const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/wireplumber/wireplumber.conf.d";
- const configContent = generateWireplumberConfig();
-
- const shellCmd = `mkdir -p "${configDir}" && cat > "${wireplumberConfigPath}" << 'EOFCONFIG'
-${configContent}
-EOFCONFIG
-`;
-
- Proc.runCommand("writeWireplumberConfig", ["sh", "-c", shellCmd], (output, exitCode) => {
- if (exitCode !== 0) {
- console.error("AudioService: Failed to write WirePlumber config. Exit code:", exitCode);
- console.error("AudioService: Error output:", output);
- ToastService.showError(I18n.tr("Failed to save audio config"), output || "");
- return;
- }
-
- reloadWireplumberConfig();
- }, 0);
- }
-
- function generateWireplumberConfig() {
- let config = "# Generated by DankMaterialShell - Audio Device Aliases\n";
- config += "# Do not edit manually - changes will be overwritten\n";
- config += "# Last updated: " + new Date().toISOString() + "\n\n";
-
- const aliasKeys = Object.keys(deviceAliases);
- if (aliasKeys.length === 0) {
- config += "# No device aliases configured\n";
- return config;
- }
-
- const alsaAliases = [];
- const bluezAliases = [];
- const otherAliases = [];
-
- for (const nodeName of aliasKeys) {
- const alias = deviceAliases[nodeName];
- if (!alias)
- continue;
-
- const rule = {
- nodeName: nodeName,
- alias: alias
- };
-
- if (nodeName.includes("alsa")) {
- alsaAliases.push(rule);
- } else if (nodeName.includes("bluez")) {
- bluezAliases.push(rule);
- } else {
- otherAliases.push(rule);
- }
- }
-
- if (alsaAliases.length > 0) {
- config += "monitor.alsa.rules = [\n";
- for (let i = 0; i < alsaAliases.length; i++) {
- const rule = alsaAliases[i];
- config += " {\n";
- config += ` matches = [ { "node.name" = "${rule.nodeName}" } ]\n`;
- config += ` actions = { update-props = { "node.description" = "${rule.alias}" } }\n`;
- config += " }";
- if (i < alsaAliases.length - 1)
- config += ",";
- config += "\n";
- }
- config += "]\n\n";
- }
-
- if (bluezAliases.length > 0) {
- config += "monitor.bluez.rules = [\n";
- for (let i = 0; i < bluezAliases.length; i++) {
- const rule = bluezAliases[i];
- config += " {\n";
- config += ` matches = [ { "node.name" = "${rule.nodeName}" } ]\n`;
- config += ` actions = { update-props = { "node.description" = "${rule.alias}" } }\n`;
- config += " }";
- if (i < bluezAliases.length - 1)
- config += ",";
- config += "\n";
- }
- config += "]\n\n";
- }
-
- if (otherAliases.length > 0) {
- config += "# Other device aliases (RAOP, USB, and other devices)\n";
- config += "wireplumber.rules = [\n";
- for (let i = 0; i < otherAliases.length; i++) {
- const rule = otherAliases[i];
- config += " {\n";
- config += ` matches = [\n`;
- config += ` { "node.name" = "${rule.nodeName}" }\n`;
- config += ` ]\n`;
- config += ` actions = {\n`;
- config += ` update-props = {\n`;
- config += ` "node.description" = "${rule.alias}"\n`;
- config += ` "node.nick" = "${rule.alias}"\n`;
- config += ` "device.description" = "${rule.alias}"\n`;
- config += ` }\n`;
- config += ` }\n`;
- config += " }";
- if (i < otherAliases.length - 1)
- config += ",";
- config += "\n";
- }
- config += "]\n";
- }
-
- return config;
- }
-
- function reloadWireplumberConfig() {
- if (wireplumberReloading) {
- return;
- }
-
- wireplumberReloading = true;
- wireplumberReloadStarted();
-
- Proc.runCommand("restartWireplumber", ["systemctl", "--user", "restart", "wireplumber"], (output, exitCode) => {
- wireplumberReloading = false;
-
- if (exitCode === 0) {
- ToastService.showInfo(I18n.tr("Audio system restarted"), I18n.tr("Device names updated"));
- wireplumberReloadCompleted(true);
- } else {
- console.error("AudioService: Failed to restart WirePlumber:", output);
- ToastService.showError(I18n.tr("Failed to restart audio system"), output);
- wireplumberReloadCompleted(false);
- }
- }, 5000);
- }
-
- function loadDeviceAliases() {
- const configPath = wireplumberConfigPath;
-
- Proc.runCommand("readWireplumberConfig", ["cat", configPath], (output, exitCode) => {
- if (exitCode !== 0) {
- console.log("AudioService: No existing WirePlumber config found");
- return;
- }
-
- const aliases = {};
- const lines = output.split('\n');
- let currentNodeName = null;
-
- for (const line of lines) {
- const nodeNameMatch = line.match(/"node\.name"\s*=\s*"([^"]+)"/);
- if (nodeNameMatch) {
- currentNodeName = nodeNameMatch[1];
- }
-
- const descriptionMatch = line.match(/"node\.description"\s*=\s*"([^"]+)"/);
- if (descriptionMatch && currentNodeName) {
- aliases[currentNodeName] = descriptionMatch[1];
- currentNodeName = null;
- }
- }
-
- if (Object.keys(aliases).length > 0) {
- deviceAliases = aliases;
- console.log("AudioService: Loaded", Object.keys(aliases).length, "device aliases");
- }
- }, 0);
- }
-
- Connections {
- target: root.sink?.audio ?? null
-
- function onVolumeChanged() {
- if (SessionData.suppressOSD)
- return;
- root.playVolumeChangeSoundIfEnabled();
- }
- }
-
- function checkGsettings() {
- Proc.runCommand("checkGsettings", ["sh", "-c", "gsettings get org.gnome.desktop.sound theme-name 2>/dev/null"], (output, exitCode) => {
- gsettingsAvailable = (exitCode === 0);
- if (gsettingsAvailable) {
- scanSoundThemes();
- getCurrentSoundTheme();
- }
- }, 0);
- }
-
- function scanSoundThemes() {
- const xdgDataDirs = Quickshell.env("XDG_DATA_DIRS");
- const searchPaths = xdgDataDirs && xdgDataDirs.trim() !== "" ? xdgDataDirs.split(":").concat(Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericDataLocation))) : ["/usr/share", "/usr/local/share", Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericDataLocation))];
-
- const basePaths = searchPaths.map(p => p + "/sounds").join(" ");
- const script = `
- for base_dir in ${basePaths}; do
- [ -d "$base_dir" ] || continue
- for theme_dir in "$base_dir"/*; do
- [ -d "$theme_dir/stereo" ] || continue
- basename "$theme_dir"
- done
- done | sort -u
- `;
-
- Proc.runCommand("scanSoundThemes", ["sh", "-c", script], (output, exitCode) => {
- if (exitCode === 0 && output.trim()) {
- const themes = output.trim().split('\n').filter(t => t && t.length > 0);
- availableSoundThemes = themes;
- } else {
- availableSoundThemes = [];
- }
- }, 0);
- }
-
- function getCurrentSoundTheme() {
- Proc.runCommand("getCurrentSoundTheme", ["sh", "-c", "gsettings get org.gnome.desktop.sound theme-name 2>/dev/null | sed \"s/'//g\""], (output, exitCode) => {
- if (exitCode === 0 && output.trim()) {
- currentSoundTheme = output.trim();
- console.log("AudioService: Current system sound theme:", currentSoundTheme);
- if (SettingsData.useSystemSoundTheme) {
- discoverSoundFiles(currentSoundTheme);
- }
- } else {
- currentSoundTheme = "";
- console.log("AudioService: No system sound theme found");
- }
- }, 0);
- }
-
- function setSoundTheme(themeName) {
- if (!themeName || themeName === currentSoundTheme) {
- return;
- }
-
- Proc.runCommand("setSoundTheme", ["sh", "-c", `gsettings set org.gnome.desktop.sound theme-name '${themeName}'`], (output, exitCode) => {
- if (exitCode === 0) {
- currentSoundTheme = themeName;
- if (SettingsData.useSystemSoundTheme) {
- discoverSoundFiles(themeName);
- }
- }
- }, 0);
- }
-
- function discoverSoundFiles(themeName) {
- if (!themeName) {
- soundFilePaths = {};
- if (soundsAvailable) {
- destroySoundPlayers();
- createSoundPlayers();
- }
- return;
- }
-
- const xdgDataDirs = Quickshell.env("XDG_DATA_DIRS");
- const searchPaths = xdgDataDirs && xdgDataDirs.trim() !== "" ? xdgDataDirs.split(":").concat(Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericDataLocation))) : ["/usr/share", "/usr/local/share", Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericDataLocation))];
-
- const extensions = ["oga", "ogg", "wav", "mp3", "flac"];
- const themesToSearch = themeName !== "freedesktop" ? `${themeName} freedesktop` : themeName;
-
- const script = `
- for event_key in audio-volume-change power-plug power-unplug message message-new-instant desktop-login; do
- found=0
-
- case "$event_key" in
- message)
- names="dialog-information message message-lowpriority bell"
- ;;
- message-new-instant)
- names="dialog-warning message-new-instant message-highlight"
- ;;
- *)
- names="$event_key"
- ;;
- esac
-
- for theme in ${themesToSearch}; do
- for event_name in $names; do
- for base_path in ${searchPaths.join(" ")}; do
- sounds_path="$base_path/sounds"
- for ext in ${extensions.join(" ")}; do
- file_path="$sounds_path/$theme/stereo/$event_name.$ext"
- if [ -f "$file_path" ]; then
- echo "$event_key=$file_path"
- found=1
- break
- fi
- done
- [ $found -eq 1 ] && break
- done
- [ $found -eq 1 ] && break
- done
- [ $found -eq 1 ] && break
- done
- done
- `;
-
- Proc.runCommand("discoverSoundFiles", ["sh", "-c", script], (output, exitCode) => {
- const paths = {};
- if (exitCode === 0 && output.trim()) {
- const lines = output.trim().split('\n');
- for (let line of lines) {
- const parts = line.split('=');
- if (parts.length === 2) {
- paths[parts[0]] = "file://" + parts[1];
- }
- }
- }
- soundFilePaths = paths;
-
- if (soundsAvailable) {
- destroySoundPlayers();
- createSoundPlayers();
- }
- }, 0);
- }
-
- function getSoundPath(soundEvent) {
- const soundMap = {
- "audio-volume-change": "../assets/sounds/freedesktop/audio-volume-change.wav",
- "power-plug": "../assets/sounds/plasma/power-plug.wav",
- "power-unplug": "../assets/sounds/plasma/power-unplug.wav",
- "message": "../assets/sounds/freedesktop/message.wav",
- "message-new-instant": "../assets/sounds/freedesktop/message-new-instant.wav",
- "desktop-login": "../assets/sounds/freedesktop/desktop-login.wav"
- };
-
- const specialConditions = {
- "smooth": ["audio-volume-change"]
- };
-
- const themeLower = currentSoundTheme.toLowerCase();
- if (SettingsData.useSystemSoundTheme && specialConditions[themeLower]?.includes(soundEvent)) {
- const bundledPath = Qt.resolvedUrl(soundMap[soundEvent] || "../assets/sounds/freedesktop/message.wav");
- console.log("AudioService: Using bundled sound (special condition) for", soundEvent, ":", bundledPath);
- return bundledPath;
- }
-
- if (SettingsData.useSystemSoundTheme && soundFilePaths[soundEvent]) {
- console.log("AudioService: Using system sound for", soundEvent, ":", soundFilePaths[soundEvent]);
- return soundFilePaths[soundEvent];
- }
-
- const bundledPath = Qt.resolvedUrl(soundMap[soundEvent] || "../assets/sounds/freedesktop/message.wav");
- console.log("AudioService: Using bundled sound for", soundEvent, ":", bundledPath);
- return bundledPath;
- }
-
- function reloadSounds() {
- console.log("AudioService: Reloading sounds, useSystemSoundTheme:", SettingsData.useSystemSoundTheme, "currentSoundTheme:", currentSoundTheme);
- if (SettingsData.useSystemSoundTheme && currentSoundTheme) {
- discoverSoundFiles(currentSoundTheme);
- } else {
- soundFilePaths = {};
- if (soundsAvailable) {
- destroySoundPlayers();
- createSoundPlayers();
- }
- }
- }
-
- function setupMediaDevices() {
- if (!soundsAvailable || mediaDevices) {
- return;
- }
-
- try {
- mediaDevices = Qt.createQmlObject(`
- import QtQuick
- import QtMultimedia
- MediaDevices {
- id: devices
- Component.onCompleted: {
- console.log("AudioService: MediaDevices initialized, default output:", defaultAudioOutput?.description)
- }
- }
- `, root, "AudioService.MediaDevices");
-
- if (mediaDevices) {
- mediaDevicesConnections = Qt.createQmlObject(`
- import QtQuick
- Connections {
- target: root.mediaDevices
- function onDefaultAudioOutputChanged() {
- console.log("AudioService: Default audio output changed, recreating sound players")
- root.destroySoundPlayers()
- root.createSoundPlayers()
- }
- }
- `, root, "AudioService.MediaDevicesConnections");
- }
- } catch (e) {
- console.log("AudioService: MediaDevices not available, using default audio output");
- mediaDevices = null;
- }
- }
-
- function destroySoundPlayers() {
- if (volumeChangeSound) {
- volumeChangeSound.destroy();
- volumeChangeSound = null;
- }
- if (powerPlugSound) {
- powerPlugSound.destroy();
- powerPlugSound = null;
- }
- if (powerUnplugSound) {
- powerUnplugSound.destroy();
- powerUnplugSound = null;
- }
- if (normalNotificationSound) {
- normalNotificationSound.destroy();
- normalNotificationSound = null;
- }
- if (criticalNotificationSound) {
- criticalNotificationSound.destroy();
- criticalNotificationSound = null;
- }
- if (loginSound) {
- loginSound.destroy();
- loginSound = null;
- }
- }
-
- function createSoundPlayers() {
- if (!soundsAvailable) {
- return;
- }
-
- setupMediaDevices();
-
- try {
- const deviceProperty = mediaDevices ? `device: root.mediaDevices.defaultAudioOutput\n ` : "";
-
- const volumeChangePath = getSoundPath("audio-volume-change");
- volumeChangeSound = Qt.createQmlObject(`
- import QtQuick
- import QtMultimedia
- MediaPlayer {
- source: "${volumeChangePath}"
- audioOutput: AudioOutput {
- ${deviceProperty}volume: notificationsVolume
- }
- }
- `, root, "AudioService.VolumeChangeSound");
-
- const powerPlugPath = getSoundPath("power-plug");
- powerPlugSound = Qt.createQmlObject(`
- import QtQuick
- import QtMultimedia
- MediaPlayer {
- source: "${powerPlugPath}"
- audioOutput: AudioOutput {
- ${deviceProperty}volume: notificationsVolume
- }
- }
- `, root, "AudioService.PowerPlugSound");
-
- const powerUnplugPath = getSoundPath("power-unplug");
- powerUnplugSound = Qt.createQmlObject(`
- import QtQuick
- import QtMultimedia
- MediaPlayer {
- source: "${powerUnplugPath}"
- audioOutput: AudioOutput {
- ${deviceProperty}volume: notificationsVolume
- }
- }
- `, root, "AudioService.PowerUnplugSound");
-
- const messagePath = getSoundPath("message");
- normalNotificationSound = Qt.createQmlObject(`
- import QtQuick
- import QtMultimedia
- MediaPlayer {
- source: "${messagePath}"
- audioOutput: AudioOutput {
- ${deviceProperty}volume: notificationsVolume
- }
- }
- `, root, "AudioService.NormalNotificationSound");
-
- const messageNewInstantPath = getSoundPath("message-new-instant");
- criticalNotificationSound = Qt.createQmlObject(`
- import QtQuick
- import QtMultimedia
- MediaPlayer {
- source: "${messageNewInstantPath}"
- audioOutput: AudioOutput {
- ${deviceProperty}volume: notificationsVolume
- }
- }
- `, root, "AudioService.CriticalNotificationSound");
-
- const loginPath = getSoundPath("desktop-login");
- loginSound = Qt.createQmlObject(`
- import QtQuick
- import QtMultimedia
- MediaPlayer {
- source: "${loginPath}"
- audioOutput: AudioOutput {
- ${deviceProperty}volume: notificationsVolume
- }
- }
- `, root, "AudioService.LoginSound");
-
- } catch (e) {
- console.warn("AudioService: Error creating sound players:", e);
- }
- }
-
- function isMediaPlaying() {
- return MprisController.activePlayer?.isPlaying ?? false;
- }
-
- function playVolumeChangeSound() {
- if (!soundsAvailable || !volumeChangeSound || notificationsAudioMuted || isMediaPlaying())
- return;
- volumeChangeSound.play();
- }
-
- function playPowerPlugSound() {
- if (!soundsAvailable || !powerPlugSound || notificationsAudioMuted || isMediaPlaying())
- return;
- powerPlugSound.play();
- }
-
- function playPowerUnplugSound() {
- if (!soundsAvailable || !powerUnplugSound || notificationsAudioMuted || isMediaPlaying())
- return;
- powerUnplugSound.play();
- }
-
- function playNormalNotificationSound() {
- if (!soundsAvailable || !normalNotificationSound || SessionData.doNotDisturb || notificationsAudioMuted || isMediaPlaying())
- return;
- normalNotificationSound.play();
- }
-
- function playCriticalNotificationSound() {
- if (!soundsAvailable || !criticalNotificationSound || SessionData.doNotDisturb || notificationsAudioMuted || isMediaPlaying())
- return;
- criticalNotificationSound.play();
- }
-
- function playLoginSound() {
- if (!soundsAvailable || !loginSound || notificationsAudioMuted || isMediaPlaying()) {
- return;
- }
- loginSound.play();
- }
-
- function playLoginSoundIfApplicable() {
- if (SettingsData.soundsEnabled && SettingsData.soundLogin && !notificationsAudioMuted) {
- // plays login sound on session start, but only if a specific file doesn't exist,
- // to prevent it from playing on every DMS restart during the session
- const runtimeDir = Quickshell.env("XDG_RUNTIME_DIR");
- const sessionId = Quickshell.env("XDG_SESSION_ID") || "0";
-
- if (!runtimeDir) return;
-
- const loginFile = `${runtimeDir}/danklinux.login-${sessionId}`;
-
- // if file doesn't exist, touch it (0)
- // If it exists, do nothing (1)
- loginSoundChecker.command = ["sh", "-c", `[ ! -f ${loginFile} ] && touch ${loginFile}`];
- loginSoundChecker.running = true;
- }
- }
-
- function playVolumeChangeSoundIfEnabled() {
- if (SettingsData.soundsEnabled && SettingsData.soundVolumeChanged && !notificationsAudioMuted) {
- playVolumeChangeSound();
- }
- }
-
- function sinkIcon(node) {
- if (!node)
- return "speaker";
-
- const props = node.properties || {};
- const formFactor = (props["device.form-factor"] || "").toLowerCase();
-
- switch (formFactor) {
- case "headphone":
- case "headset":
- case "hands-free":
- case "handset":
- return "headset";
- case "tv":
- case "monitor":
- return "tv";
- case "speaker":
- case "computer":
- case "hifi":
- case "portable":
- case "car":
- return "speaker";
- }
-
- const bus = (props["device.bus"] || "").toLowerCase();
- if (bus === "bluetooth")
- return "headset";
-
- const name = (node.name || "").toLowerCase();
- if (name.includes("hdmi"))
- return "tv";
- if (name.includes("iec958") || name.includes("spdif"))
- return "speaker";
-
- if (bus === "usb")
- return "headset";
-
- return "speaker";
- }
-
- function displayName(node) {
- if (!node) {
- return "";
- }
-
- // FIRST: Check if we have a custom alias in our deviceAliases map
- // This ensures we always show the user's custom name, regardless of
- // whether WirePlumber has applied it to the node properties yet
- if (node.name && deviceAliases[node.name]) {
- return deviceAliases[node.name];
- }
-
- // Check node.properties["node.description"] for WirePlumber-applied aliases
- // This is the live property updated by WirePlumber rules
- if (node.properties && node.properties["node.description"]) {
- const desc = node.properties["node.description"];
- if (desc !== node.name) {
- return desc;
- }
- }
-
- // Check cached description as fallback
- if (node.description && node.description !== node.name) {
- return node.description;
- }
-
- // Fallback to device description property
- if (node.properties && node.properties["device.description"]) {
- return node.properties["device.description"];
- }
-
- // Fallback to nickname
- if (node.nickname && node.nickname !== node.name) {
- return node.nickname;
- }
-
- // Fallback to friendly names based on node name patterns
- if (node.name.includes("analog-stereo")) {
- return "Built-in Audio Analog Stereo";
- }
- if (node.name.includes("bluez")) {
- return "Bluetooth Audio";
- }
- if (node.name.includes("usb")) {
- return "USB Audio";
- }
- if (node.name.includes("hdmi")) {
- return "HDMI Audio";
- }
-
- return node.name;
- }
-
- function originalName(node) {
- if (!node) {
- return "";
- }
-
- // Get the original name without checking for custom aliases
- // Check pattern-based friendly names FIRST (before device.description)
- // This ensures we show user-friendly names like "Built-in Audio Analog Stereo"
- // instead of hardware chip names like "ALC274 Analog"
- if (node.name.includes("analog-stereo")) {
- return "Built-in Audio Analog Stereo";
- }
- if (node.name.includes("bluez")) {
- return "Bluetooth Audio";
- }
- if (node.name.includes("usb")) {
- return "USB Audio";
- }
- if (node.name.includes("hdmi")) {
- return "HDMI Audio";
- }
- if (node.name.includes("raop_sink")) {
- // Extract friendly name from RAOP node name
- const match = node.name.match(/raop_sink\.([^.]+)/);
- if (match) {
- return match[1].replace(/-/g, " ");
- }
- }
-
- // Fallback to device.description property
- if (node.properties && node.properties["device.description"]) {
- return node.properties["device.description"];
- }
-
- // Fallback to nickname
- if (node.nickname && node.nickname !== node.name) {
- return node.nickname;
- }
-
- return node.name;
- }
-
- function subtitle(name) {
- if (!name) {
- return "";
- }
-
- if (name.includes('usb-')) {
- if (name.includes('SteelSeries')) {
- return "USB Gaming Headset";
- }
- if (name.includes('Generic')) {
- return "USB Audio Device";
- }
- return "USB Audio";
- }
-
- if (name.includes('pci-')) {
- if (name.includes('01_00.1') || name.includes('01:00.1')) {
- return "NVIDIA GPU Audio";
- }
- return "PCI Audio";
- }
-
- if (name.includes('bluez')) {
- return "Bluetooth Audio";
- }
- if (name.includes('analog')) {
- return "Built-in Audio";
- }
- if (name.includes('hdmi')) {
- return "HDMI Audio";
- }
-
- return "";
- }
-
- PwObjectTracker {
- objects: Pipewire.nodes.values.filter(node => node.audio && !node.isStream)
- }
-
- Connections {
- target: Pipewire
- function onDefaultAudioSinkChanged() {
- if (soundsAvailable) {
- Qt.callLater(root.destroySoundPlayers);
- Qt.callLater(root.createSoundPlayers);
- }
- }
- }
-
- function setVolume(percentage) {
- if (!root.sink?.audio)
- return "No audio sink available";
-
- const maxVol = root.sinkMaxVolume;
- const clampedVolume = Math.max(0, Math.min(maxVol, percentage));
- root.sink.audio.volume = clampedVolume / 100;
- return `Volume set to ${clampedVolume}%`;
- }
-
- function toggleMute() {
- if (!root.sink?.audio) {
- return "No audio sink available";
- }
-
- root.sink.audio.muted = !root.sink.audio.muted;
- return root.sink.audio.muted ? "Audio muted" : "Audio unmuted";
- }
-
- function setMicVolume(percentage) {
- if (!root.source?.audio) {
- return "No audio source available";
- }
-
- const clampedVolume = Math.max(0, Math.min(100, percentage));
- root.source.audio.volume = clampedVolume / 100;
- return `Microphone volume set to ${clampedVolume}%`;
- }
-
- function toggleMicMute() {
- if (!root.source?.audio) {
- return "No audio source available";
- }
-
- root.source.audio.muted = !root.source.audio.muted;
- return root.source.audio.muted ? "Microphone muted" : "Microphone unmuted";
- }
-
- IpcHandler {
- target: "audio"
-
- function setvolume(percentage: string): string {
- return root.setVolume(parseInt(percentage));
- }
-
- function increment(step: string): string {
- if (!root.sink?.audio)
- return "No audio sink available";
-
- if (root.sink.audio.muted)
- root.sink.audio.muted = false;
-
- const maxVol = root.sinkMaxVolume;
- const currentVolume = Math.round(root.sink.audio.volume * 100);
- const stepValue = parseInt(step || "5");
- const newVolume = Math.max(0, Math.min(maxVol, currentVolume + stepValue));
-
- root.sink.audio.volume = newVolume / 100;
- return `Volume increased to ${newVolume}%`;
- }
-
- function decrement(step: string): string {
- if (!root.sink?.audio)
- return "No audio sink available";
-
- if (root.sink.audio.muted)
- root.sink.audio.muted = false;
-
- const maxVol = root.sinkMaxVolume;
- const currentVolume = Math.round(root.sink.audio.volume * 100);
- const stepValue = parseInt(step || "5");
- const newVolume = Math.max(0, Math.min(maxVol, currentVolume - stepValue));
-
- root.sink.audio.volume = newVolume / 100;
- return `Volume decreased to ${newVolume}%`;
- }
-
- function mute(): string {
- return root.toggleMute();
- }
-
- function setmic(percentage: string): string {
- return root.setMicVolume(parseInt(percentage));
- }
-
- function micmute(): string {
- const result = root.toggleMicMute();
- root.micMuteChanged();
- return result;
- }
-
- function status(): string {
- let result = "Audio Status:\n";
-
- if (root.sink?.audio) {
- const volume = Math.round(root.sink.audio.volume * 100);
- const muteStatus = root.sink.audio.muted ? " (muted)" : "";
- const maxVol = root.sinkMaxVolume;
- result += `Output: ${volume}%${muteStatus} (max: ${maxVol}%)\n`;
- } else {
- result += "Output: No sink available\n";
- }
-
- if (root.source?.audio) {
- const micVolume = Math.round(root.source.audio.volume * 100);
- const muteStatus = root.source.audio.muted ? " (muted)" : "";
- result += `Input: ${micVolume}%${muteStatus}`;
- } else {
- result += "Input: No source available";
- }
-
- return result;
- }
-
- function getmaxvolume(): string {
- return `${root.sinkMaxVolume}`;
- }
-
- function setmaxvolume(percent: string): string {
- if (!root.sink?.name)
- return "No audio sink available";
- const val = parseInt(percent);
- if (isNaN(val))
- return "Invalid percentage";
- SessionData.setDeviceMaxVolume(root.sink.name, val);
- return `Max volume set to ${SessionData.getDeviceMaxVolume(root.sink.name)}%`;
- }
-
- function getmaxvolumefor(nodeName: string): string {
- if (!nodeName)
- return "No node name specified";
- return `${SessionData.getDeviceMaxVolume(nodeName)}`;
- }
-
- function setmaxvolumefor(nodeName: string, percent: string): string {
- if (!nodeName)
- return "No node name specified";
- const val = parseInt(percent);
- if (isNaN(val))
- return "Invalid percentage";
- SessionData.setDeviceMaxVolume(nodeName, val);
- return `Max volume for ${nodeName} set to ${SessionData.getDeviceMaxVolume(nodeName)}%`;
- }
-
- function cycleoutput(): string {
- const result = root.cycleAudioOutput();
- if (!result)
- return "Only one audio output available";
- return `Switched to: ${result}`;
- }
- }
-
- Connections {
- target: SettingsData
- function onUseSystemSoundThemeChanged() {
- reloadSounds();
- }
- }
-
- Component.onCompleted: {
- if (soundsAvailable) {
- checkGsettings();
- Qt.callLater(createSoundPlayers);
- }
-
- loadDeviceAliases();
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BarWidgetService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BarWidgetService.qml
deleted file mode 100644
index 0ae2450..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BarWidgetService.qml
+++ /dev/null
@@ -1,171 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Hyprland
-import Quickshell.I3
-
-Singleton {
- id: root
-
- property var widgetRegistry: ({})
- property var dankBarRepeater: null
-
- signal widgetRegistered(string widgetId, string screenName)
- signal widgetUnregistered(string widgetId, string screenName)
-
- function registerWidget(widgetId, screenName, widgetRef) {
- if (!widgetId || !screenName || !widgetRef)
- return;
- if (typeof widgetRegistry !== "object" || widgetRegistry === null)
- widgetRegistry = ({});
-
- if (!widgetRegistry[widgetId])
- widgetRegistry[widgetId] = {};
-
- widgetRegistry[widgetId][screenName] = widgetRef;
- widgetRegistered(widgetId, screenName);
- }
-
- function unregisterWidget(widgetId, screenName) {
- if (!widgetId || !screenName)
- return;
- if (typeof widgetRegistry !== "object" || widgetRegistry === null)
- return;
- if (!widgetRegistry[widgetId])
- return;
-
- delete widgetRegistry[widgetId][screenName];
- if (Object.keys(widgetRegistry[widgetId]).length === 0)
- delete widgetRegistry[widgetId];
-
- widgetUnregistered(widgetId, screenName);
- }
-
- function getWidget(widgetId, screenName) {
- if (!widgetRegistry[widgetId])
- return null;
- if (screenName)
- return widgetRegistry[widgetId][screenName] || null;
-
- const screens = Object.keys(widgetRegistry[widgetId]);
- return screens.length > 0 ? widgetRegistry[widgetId][screens[0]] : null;
- }
-
- function getWidgetOnFocusedScreen(widgetId) {
- if (!widgetRegistry[widgetId])
- return null;
-
- const focusedScreen = getFocusedScreenName();
- if (focusedScreen && widgetRegistry[widgetId][focusedScreen])
- return widgetRegistry[widgetId][focusedScreen];
-
- const screens = Object.keys(widgetRegistry[widgetId]);
- return screens.length > 0 ? widgetRegistry[widgetId][screens[0]] : null;
- }
-
- function getFocusedScreenName() {
- if (CompositorService.isHyprland && Hyprland.focusedWorkspace?.monitor)
- return Hyprland.focusedWorkspace.monitor.name;
- if (CompositorService.isNiri && NiriService.currentOutput)
- return NiriService.currentOutput;
- if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
- const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
- return focusedWs?.monitor?.name || "";
- }
- return "";
- }
-
- function getRegisteredWidgetIds() {
- return Object.keys(widgetRegistry);
- }
-
- function hasWidget(widgetId) {
- return widgetRegistry[widgetId] && Object.keys(widgetRegistry[widgetId]).length > 0;
- }
-
- function triggerWidgetPopout(widgetId) {
- const widget = getWidgetOnFocusedScreen(widgetId);
- if (!widget)
- return false;
-
- if (typeof widget.triggerPopout === "function") {
- widget.triggerPopout();
- return true;
- }
-
- const signalMap = {
- "battery": "toggleBatteryPopup",
- "vpn": "toggleVpnPopup",
- "layout": "toggleLayoutPopup",
- "clock": "clockClicked",
- "cpuUsage": "cpuClicked",
- "memUsage": "ramClicked",
- "cpuTemp": "cpuTempClicked",
- "gpuTemp": "gpuTempClicked"
- };
-
- const signalName = signalMap[widgetId];
- if (signalName && typeof widget[signalName] === "function") {
- widget[signalName]();
- return true;
- }
-
- if (typeof widget.clicked === "function") {
- widget.clicked();
- return true;
- }
-
- if (widget.popoutTarget?.toggle) {
- widget.popoutTarget.toggle();
- return true;
- }
-
- return false;
- }
-
- function getBarWindowForScreen(screenName) {
- if (!dankBarRepeater)
- return null;
-
- for (var i = 0; i < dankBarRepeater.count; i++) {
- const loader = dankBarRepeater.itemAt(i);
- if (!loader?.item)
- continue;
-
- const barItem = loader.item;
- if (!barItem.barVariants?.instances)
- continue;
-
- for (var j = 0; j < barItem.barVariants.instances.length; j++) {
- const barInstance = barItem.barVariants.instances[j];
- if (barInstance.modelData?.name === screenName)
- return barInstance;
- }
- }
- return null;
- }
-
- function getBarWindowOnFocusedScreen() {
- const focusedScreen = getFocusedScreenName();
- if (!focusedScreen)
- return getFirstBarWindow();
- return getBarWindowForScreen(focusedScreen) || getFirstBarWindow();
- }
-
- function getFirstBarWindow() {
- if (!dankBarRepeater || dankBarRepeater.count === 0)
- return null;
-
- const loader = dankBarRepeater.itemAt(0);
- if (!loader?.item)
- return null;
-
- const barItem = loader.item;
- if (!barItem.barVariants?.instances || barItem.barVariants.instances.length === 0)
- return null;
-
- return barItem.barVariants.instances[0];
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BatteryService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BatteryService.qml
deleted file mode 100644
index e7cea56..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BatteryService.qml
+++ /dev/null
@@ -1,271 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Services.UPower
-import qs.Common
-
-Singleton {
- id: root
-
- property bool suppressSound: true
- property bool previousPluggedState: false
-
- readonly property var scale: 100 / SettingsData.batteryChargeLimit
-
- Timer {
- id: startupTimer
- interval: 500
- repeat: false
- running: true
- onTriggered: root.suppressSound = false
- }
-
- readonly property string preferredBatteryOverride: Quickshell.env("DMS_PREFERRED_BATTERY")
-
- // List of laptop batteries
- readonly property var batteries: UPower.devices.values.filter(dev => dev.isLaptopBattery)
-
- readonly property bool usePreferred: preferredBatteryOverride && preferredBatteryOverride.length > 0
-
- // Main battery (for backward compatibility)
- readonly property UPowerDevice device: {
- var preferredDev;
- if (usePreferred) {
- preferredDev = batteries.find(dev => dev.nativePath.toLowerCase().includes(preferredBatteryOverride.toLowerCase()));
- }
- return preferredDev || batteries[0] || null;
- }
- // Whether at least one battery is available
- readonly property bool batteryAvailable: batteries.length > 0
- // Aggregated charge level (percentage)
- readonly property real batteryLevel: {
- if (!batteryAvailable)
- return 0;
- if (batteryCapacity === 0) {
- if (usePreferred && device && device.ready)
- return Math.round(device.percentage * 100 * scale);
- const validBatteries = batteries.filter(b => b.ready && b.percentage >= 0);
- if (validBatteries.length === 0)
- return 0;
- const avgPercentage = validBatteries.reduce((sum, b) => sum + b.percentage, 0) / validBatteries.length;
- return Math.round(avgPercentage * 100 * scale);
- }
- return Math.round((batteryEnergy * 100) / batteryCapacity * scale);
- }
- readonly property bool isCharging: batteryAvailable && batteries.some(b => b.state === UPowerDeviceState.Charging)
-
- // Is the system plugged in (Is not running on battery)
- readonly property bool isPluggedIn: !UPower.onBattery
- readonly property bool isLowBattery: batteryAvailable && batteryLevel <= 20
-
- onIsPluggedInChanged: {
- if (suppressSound || !batteryAvailable) {
- previousPluggedState = isPluggedIn;
- return;
- }
-
- if (SettingsData.soundsEnabled && SettingsData.soundPluggedIn) {
- if (isPluggedIn && !previousPluggedState) {
- AudioService.playPowerPlugSound();
- } else if (!isPluggedIn && previousPluggedState) {
- AudioService.playPowerUnplugSound();
- }
- }
-
- const profileValue = BatteryService.isPluggedIn ? SettingsData.acProfileName : SettingsData.batteryProfileName;
-
- if (profileValue !== "") {
- const targetProfile = parseInt(profileValue);
- if (!isNaN(targetProfile) && PowerProfiles.profile !== targetProfile) {
- PowerProfiles.profile = targetProfile;
- }
- }
-
- previousPluggedState = isPluggedIn;
- }
-
- // Aggregated charge/discharge rate
- readonly property real changeRate: {
- if (!batteryAvailable)
- return 0;
- if (usePreferred && device && device.ready)
- return device.changeRate;
- return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.changeRate, 0) : 0;
- }
-
- // Aggregated battery health
- readonly property string batteryHealth: {
- if (!batteryAvailable)
- return "N/A";
-
- // If a preferred battery is selected and ready
- if (usePreferred && device && device.ready && device.healthSupported)
- return `${Math.round(device.healthPercentage)}%`;
-
- // Otherwise, calculate the average health of all laptop batteries
- const validBatteries = batteries.filter(b => b.healthSupported && b.healthPercentage > 0);
- if (validBatteries.length === 0)
- return "N/A";
-
- const avgHealth = validBatteries.reduce((sum, b) => sum + b.healthPercentage, 0) / validBatteries.length;
- return `${Math.round(avgHealth)}%`;
- }
-
- readonly property real batteryEnergy: {
- if (!batteryAvailable)
- return 0;
- if (usePreferred && device && device.ready)
- return device.energy;
- return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energy, 0) : 0;
- }
-
- // Total battery capacity (Wh)
- readonly property real batteryCapacity: {
- if (!batteryAvailable)
- return 0;
- if (usePreferred && device && device.ready)
- return device.energyCapacity;
- return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energyCapacity, 0) : 0;
- }
-
- function translateBatteryState(state) {
- switch (state) {
- case UPowerDeviceState.Charging:
- return I18n.tr("Charging", "battery status");
- case UPowerDeviceState.Discharging:
- return I18n.tr("Discharging", "battery status");
- case UPowerDeviceState.Empty:
- return I18n.tr("Empty", "battery status");
- case UPowerDeviceState.FullyCharged:
- return I18n.tr("Fully Charged", "battery status");
- case UPowerDeviceState.PendingCharge:
- return I18n.tr("Pending Charge", "battery status");
- case UPowerDeviceState.PendingDischarge:
- return I18n.tr("Pending Discharge", "battery status");
- default:
- return I18n.tr("Unknown", "battery status");
- }
- }
-
- // Aggregated battery status
- readonly property string batteryStatus: {
- if (!batteryAvailable) {
- return I18n.tr("No Battery", "battery status");
- }
-
- if (isCharging && !batteries.some(b => b.changeRate > 0))
- return I18n.tr("Plugged In", "battery status");
-
- const states = batteries.map(b => b.state);
- if (states.every(s => s === states[0]))
- return translateBatteryState(states[0]);
-
- return isCharging ? I18n.tr("Charging", "battery status") : (isPluggedIn ? I18n.tr("Plugged In", "battery status") : I18n.tr("Discharging", "battery status"));
- }
-
- readonly property bool suggestPowerSaver: false
-
- readonly property var bluetoothDevices: {
- const btDevices = [];
- const bluetoothTypes = [UPowerDeviceType.BluetoothGeneric, UPowerDeviceType.Headphones, UPowerDeviceType.Headset, UPowerDeviceType.Keyboard, UPowerDeviceType.Mouse, UPowerDeviceType.Speakers];
-
- for (var i = 0; i < UPower.devices.count; i++) {
- const dev = UPower.devices.get(i);
- if (dev && dev.ready && bluetoothTypes.includes(dev.type)) {
- btDevices.push({
- "name": dev.model || UPowerDeviceType.toString(dev.type),
- "percentage": Math.round(dev.percentage * 100),
- "type": dev.type
- });
- }
- }
- return btDevices;
- }
-
- // Format time remaining for charge/discharge
- function formatTimeRemaining() {
- if (!batteryAvailable) {
- return "Unknown";
- }
-
- let totalTime = 0;
- totalTime = (isCharging) ? ((batteryCapacity - batteryEnergy) / changeRate) : (batteryEnergy / changeRate);
- const avgTime = Math.abs(totalTime * 3600);
- if (!avgTime || avgTime <= 0 || avgTime > 86400)
- return "Unknown";
-
- const hours = Math.floor(avgTime / 3600);
- const minutes = Math.floor((avgTime % 3600) / 60);
- return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
- }
-
- function getBatteryIcon() {
- if (!batteryAvailable) {
- return "power";
- }
-
- if (isCharging) {
- if (batteryLevel >= 90) {
- return "battery_charging_full";
- }
- if (batteryLevel >= 80) {
- return "battery_charging_90";
- }
- if (batteryLevel >= 60) {
- return "battery_charging_80";
- }
- if (batteryLevel >= 50) {
- return "battery_charging_60";
- }
- if (batteryLevel >= 30) {
- return "battery_charging_50";
- }
- if (batteryLevel >= 20) {
- return "battery_charging_30";
- }
- return "battery_charging_20";
- }
- if (isPluggedIn) {
- if (batteryLevel >= 90) {
- return "battery_charging_full";
- }
- if (batteryLevel >= 80) {
- return "battery_charging_90";
- }
- if (batteryLevel >= 60) {
- return "battery_charging_80";
- }
- if (batteryLevel >= 50) {
- return "battery_charging_60";
- }
- if (batteryLevel >= 30) {
- return "battery_charging_50";
- }
- if (batteryLevel >= 20) {
- return "battery_charging_30";
- }
- return "battery_charging_20";
- }
- if (batteryLevel >= 95) {
- return "battery_full";
- }
- if (batteryLevel >= 85) {
- return "battery_6_bar";
- }
- if (batteryLevel >= 70) {
- return "battery_5_bar";
- }
- if (batteryLevel >= 55) {
- return "battery_4_bar";
- }
- if (batteryLevel >= 40) {
- return "battery_3_bar";
- }
- if (batteryLevel >= 25) {
- return "battery_2_bar";
- }
- return "battery_1_bar";
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BluetoothService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BluetoothService.qml
deleted file mode 100644
index 4de300e..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BluetoothService.qml
+++ /dev/null
@@ -1,523 +0,0 @@
-pragma Singleton
-
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import Quickshell.Bluetooth
-import qs.Services
-
-Singleton {
- id: root
-
- readonly property BluetoothAdapter adapter: Bluetooth.defaultAdapter
- readonly property bool available: adapter !== null
- readonly property bool enabled: (adapter && adapter.enabled) ?? false
- readonly property bool discovering: (adapter && adapter.discovering) ?? false
- readonly property var devices: adapter ? adapter.devices : null
- readonly property bool enhancedPairingAvailable: DMSService.dmsAvailable && DMSService.apiVersion >= 9 && DMSService.capabilities.includes("bluetooth")
- readonly property bool connected: {
- if (!adapter || !adapter.devices) {
- return false
- }
-
- let isConnected = false
- adapter.devices.values.forEach(dev => { if (dev.connected) isConnected = true })
- return isConnected
- }
- readonly property var pairedDevices: {
- if (!adapter || !adapter.devices) {
- return []
- }
-
- return adapter.devices.values.filter(dev => {
- return dev && (dev.paired || dev.trusted)
- })
- }
- readonly property var allDevicesWithBattery: {
- if (!adapter || !adapter.devices) {
- return []
- }
-
- return adapter.devices.values.filter(dev => {
- return dev && dev.batteryAvailable && dev.battery > 0
- })
- }
-
- function sortDevices(devices) {
- return devices.sort((a, b) => {
- const aName = a.name || a.deviceName || ""
- const bName = b.name || b.deviceName || ""
- const aAddr = a.address || ""
- const bAddr = b.address || ""
-
- const aHasRealName = aName.includes(" ") && aName.length > 3
- const bHasRealName = bName.includes(" ") && bName.length > 3
-
- if (aHasRealName && !bHasRealName) return -1
- if (!aHasRealName && bHasRealName) return 1
-
- if (aHasRealName && bHasRealName) {
- return aName.localeCompare(bName)
- }
-
- return aAddr.localeCompare(bAddr)
- })
- }
-
- function getDeviceIcon(device) {
- if (!device) {
- return "bluetooth"
- }
-
- const name = (device.name || device.deviceName || "").toLowerCase()
- const icon = (device.icon || "").toLowerCase()
-
- const audioKeywords = ["headset", "audio", "headphone", "airpod", "arctis"]
- if (audioKeywords.some(keyword => icon.includes(keyword) || name.includes(keyword))) {
- return "headset"
- }
-
- if (icon.includes("mouse") || name.includes("mouse")) {
- return "mouse"
- }
-
- if (icon.includes("keyboard") || name.includes("keyboard")) {
- return "keyboard"
- }
-
- const phoneKeywords = ["phone", "iphone", "android", "samsung"]
- if (phoneKeywords.some(keyword => icon.includes(keyword) || name.includes(keyword))) {
- return "smartphone"
- }
-
- if (icon.includes("watch") || name.includes("watch")) {
- return "watch"
- }
-
- if (icon.includes("speaker") || name.includes("speaker")) {
- return "speaker"
- }
-
- if (icon.includes("display") || name.includes("tv")) {
- return "tv"
- }
-
- return "bluetooth"
- }
-
- function canConnect(device) {
- if (!device) {
- return false
- }
-
- return !device.paired && !device.pairing && !device.blocked
- }
-
- function getSignalStrength(device) {
- if (!device || device.signalStrength === undefined || device.signalStrength <= 0) {
- return "Unknown"
- }
-
- const signal = device.signalStrength
- if (signal >= 80) {
- return "Excellent"
- }
- if (signal >= 60) {
- return "Good"
- }
- if (signal >= 40) {
- return "Fair"
- }
- if (signal >= 20) {
- return "Poor"
- }
-
- return "Very Poor"
- }
-
- function getSignalIcon(device) {
- if (!device || device.signalStrength === undefined || device.signalStrength <= 0) {
- return "signal_cellular_null"
- }
-
- const signal = device.signalStrength
- if (signal >= 80) {
- return "signal_cellular_4_bar"
- }
- if (signal >= 60) {
- return "signal_cellular_3_bar"
- }
- if (signal >= 40) {
- return "signal_cellular_2_bar"
- }
- if (signal >= 20) {
- return "signal_cellular_1_bar"
- }
-
- return "signal_cellular_0_bar"
- }
-
- function isDeviceBusy(device) {
- if (!device) {
- return false
- }
- return device.pairing || device.state === BluetoothDeviceState.Disconnecting || device.state === BluetoothDeviceState.Connecting
- }
-
- function connectDeviceWithTrust(device) {
- if (!device) {
- return
- }
-
- device.trusted = true
- device.connect()
- }
-
- function pairDevice(device, callback) {
- if (!device) {
- if (callback) callback({error: "Invalid device"})
- return
- }
-
- // The DMS backend actually implements a bluez agent, so we can pair anything
- if (enhancedPairingAvailable) {
- const devicePath = getDevicePath(device)
- DMSService.bluetoothPair(devicePath, callback)
- return
- }
-
- // Quickshell does not implement a bluez agent, so we can try to pair but only with devices that don't require a passcode
- device.trusted = true
- device.connect()
- if (callback) callback({success: true})
- }
-
- function getCardName(device) {
- if (!device) {
- return ""
- }
- return `bluez_card.${device.address.replace(/:/g, "_")}`
- }
-
- function getDevicePath(device) {
- if (!device || !device.address) {
- return ""
- }
- const adapterPath = adapter ? "/org/bluez/hci0" : "/org/bluez/hci0"
- return `${adapterPath}/dev_${device.address.replace(/:/g, "_")}`
- }
-
- function isAudioDevice(device) {
- if (!device) {
- return false
- }
- const icon = getDeviceIcon(device)
- return icon === "headset" || icon === "speaker"
- }
-
- function getCodecInfo(codecName) {
- const codec = codecName.replace(/-/g, "_").toUpperCase()
-
- const codecMap = {
- "LDAC": {
- "name": "LDAC",
- "description": "Highest quality • Higher battery usage",
- "qualityColor": "#4CAF50"
- },
- "APTX_HD": {
- "name": "aptX HD",
- "description": "High quality • Balanced battery",
- "qualityColor": "#FF9800"
- },
- "APTX": {
- "name": "aptX",
- "description": "Good quality • Low latency",
- "qualityColor": "#FF9800"
- },
- "AAC": {
- "name": "AAC",
- "description": "Balanced quality and battery",
- "qualityColor": "#2196F3"
- },
- "SBC_XQ": {
- "name": "SBC-XQ",
- "description": "Enhanced SBC • Better compatibility",
- "qualityColor": "#2196F3"
- },
- "SBC": {
- "name": "SBC",
- "description": "Basic quality • Universal compatibility",
- "qualityColor": "#9E9E9E"
- },
- "MSBC": {
- "name": "mSBC",
- "description": "Modified SBC • Optimized for speech",
- "qualityColor": "#9E9E9E"
- },
- "CVSD": {
- "name": "CVSD",
- "description": "Basic speech codec • Legacy compatibility",
- "qualityColor": "#9E9E9E"
- }
- }
-
- return codecMap[codec] || {
- "name": codecName,
- "description": "Unknown codec",
- "qualityColor": "#9E9E9E"
- }
- }
-
- property var deviceCodecs: ({})
-
- function updateDeviceCodec(deviceAddress, codec) {
- deviceCodecs[deviceAddress] = codec
- deviceCodecsChanged()
- }
-
- function refreshDeviceCodec(device) {
- if (!device || !device.connected || !isAudioDevice(device)) {
- return
- }
-
- const cardName = getCardName(device)
- codecQueryProcess.cardName = cardName
- codecQueryProcess.deviceAddress = device.address
- codecQueryProcess.availableCodecs = []
- codecQueryProcess.parsingTargetCard = false
- codecQueryProcess.detectedCodec = ""
- codecQueryProcess.running = true
- }
-
- function getCurrentCodec(device, callback) {
- if (!device || !device.connected || !isAudioDevice(device)) {
- callback("")
- return
- }
-
- const cardName = getCardName(device)
- codecQueryProcess.cardName = cardName
- codecQueryProcess.callback = callback
- codecQueryProcess.availableCodecs = []
- codecQueryProcess.parsingTargetCard = false
- codecQueryProcess.detectedCodec = ""
- codecQueryProcess.running = true
- }
-
- function getAvailableCodecs(device, callback) {
- if (!device || !device.connected || !isAudioDevice(device)) {
- callback([], "")
- return
- }
-
- const cardName = getCardName(device)
- codecFullQueryProcess.cardName = cardName
- codecFullQueryProcess.callback = callback
- codecFullQueryProcess.availableCodecs = []
- codecFullQueryProcess.parsingTargetCard = false
- codecFullQueryProcess.detectedCodec = ""
- codecFullQueryProcess.running = true
- }
-
- function switchCodec(device, profileName, callback) {
- if (!device || !isAudioDevice(device)) {
- callback(false, "Invalid device")
- return
- }
-
- const cardName = getCardName(device)
- codecSwitchProcess.cardName = cardName
- codecSwitchProcess.profile = profileName
- codecSwitchProcess.callback = callback
- codecSwitchProcess.running = true
- }
-
- Process {
- id: codecQueryProcess
-
- property string cardName: ""
- property string deviceAddress: ""
- property var callback: null
- property bool parsingTargetCard: false
- property string detectedCodec: ""
- property var availableCodecs: []
-
- command: ["pactl", "list", "cards"]
-
- onExited: (exitCode, exitStatus) => {
- if (exitCode === 0 && detectedCodec) {
- if (deviceAddress) {
- root.updateDeviceCodec(deviceAddress, detectedCodec)
- }
- if (callback) {
- callback(detectedCodec)
- }
- } else if (callback) {
- callback("")
- }
-
- parsingTargetCard = false
- detectedCodec = ""
- availableCodecs = []
- deviceAddress = ""
- callback = null
- }
-
- stdout: SplitParser {
- splitMarker: "\n"
- onRead: data => {
- let line = data.trim()
-
- if (line.includes(`Name: ${codecQueryProcess.cardName}`)) {
- codecQueryProcess.parsingTargetCard = true
- return
- }
-
- if (codecQueryProcess.parsingTargetCard && line.startsWith("Name: ") && !line.includes(codecQueryProcess.cardName)) {
- codecQueryProcess.parsingTargetCard = false
- return
- }
-
- if (codecQueryProcess.parsingTargetCard) {
- if (line.startsWith("Active Profile:")) {
- let profile = line.split(": ")[1] || ""
- let activeCodec = codecQueryProcess.availableCodecs.find(c => {
- return c.profile === profile
- })
- if (activeCodec) {
- codecQueryProcess.detectedCodec = activeCodec.name
- }
- return
- }
- if (line.includes("codec") && line.includes("available: yes")) {
- let parts = line.split(": ")
- if (parts.length >= 2) {
- let profile = parts[0].trim()
- let description = parts[1]
- let codecMatch = description.match(/codec ([^\)\s]+)/i)
- let codecName = codecMatch ? codecMatch[1].toUpperCase() : "UNKNOWN"
- let codecInfo = root.getCodecInfo(codecName)
- if (codecInfo && !codecQueryProcess.availableCodecs.some(c => {
- return c.profile === profile
- })) {
- let newCodecs = codecQueryProcess.availableCodecs.slice()
- newCodecs.push({
- "name": codecInfo.name,
- "profile": profile,
- "description": codecInfo.description,
- "qualityColor": codecInfo.qualityColor
- })
- codecQueryProcess.availableCodecs = newCodecs
- }
- }
- }
- }
- }
- }
- }
-
- Process {
- id: codecFullQueryProcess
-
- property string cardName: ""
- property var callback: null
- property bool parsingTargetCard: false
- property string detectedCodec: ""
- property var availableCodecs: []
-
- command: ["pactl", "list", "cards"]
-
- onExited: function (exitCode, exitStatus) {
- if (callback) {
- callback(exitCode === 0 ? availableCodecs : [], exitCode === 0 ? detectedCodec : "")
- }
- parsingTargetCard = false
- detectedCodec = ""
- availableCodecs = []
- callback = null
- }
-
- stdout: SplitParser {
- splitMarker: "\n"
- onRead: data => {
- let line = data.trim()
-
- if (line.includes(`Name: ${codecFullQueryProcess.cardName}`)) {
- codecFullQueryProcess.parsingTargetCard = true
- return
- }
-
- if (codecFullQueryProcess.parsingTargetCard && line.startsWith("Name: ") && !line.includes(codecFullQueryProcess.cardName)) {
- codecFullQueryProcess.parsingTargetCard = false
- return
- }
-
- if (codecFullQueryProcess.parsingTargetCard) {
- if (line.startsWith("Active Profile:")) {
- let profile = line.split(": ")[1] || ""
- let activeCodec = codecFullQueryProcess.availableCodecs.find(c => {
- return c.profile === profile
- })
- if (activeCodec) {
- codecFullQueryProcess.detectedCodec = activeCodec.name
- }
- return
- }
- if (line.includes("codec") && line.includes("available: yes")) {
- let parts = line.split(": ")
- if (parts.length >= 2) {
- let profile = parts[0].trim()
- let description = parts[1]
- let codecMatch = description.match(/codec ([^\)\s]+)/i)
- let codecName = codecMatch ? codecMatch[1].toUpperCase() : "UNKNOWN"
- let codecInfo = root.getCodecInfo(codecName)
- if (codecInfo && !codecFullQueryProcess.availableCodecs.some(c => {
- return c.profile === profile
- })) {
- let newCodecs = codecFullQueryProcess.availableCodecs.slice()
- newCodecs.push({
- "name": codecInfo.name,
- "profile": profile,
- "description": codecInfo.description,
- "qualityColor": codecInfo.qualityColor
- })
- codecFullQueryProcess.availableCodecs = newCodecs
- }
- }
- }
- }
- }
- }
- }
-
- Process {
- id: codecSwitchProcess
-
- property string cardName: ""
- property string profile: ""
- property var callback: null
-
- command: ["pactl", "set-card-profile", cardName, profile]
-
- onExited: function (exitCode, exitStatus) {
- if (callback) {
- callback(exitCode === 0, exitCode === 0 ? "Codec switched successfully" : "Failed to switch codec")
- }
-
- // If successful, refresh the codec for this device
- if (exitCode === 0) {
- if (root.adapter && root.adapter.devices) {
- root.adapter.devices.values.forEach(device => {
- if (device && root.getCardName(device) === cardName) {
- Qt.callLater(() => root.refreshDeviceCodec(device))
- }
- })
- }
- }
-
- callback = null
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BlurService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BlurService.qml
deleted file mode 100644
index 40a3aeb..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/BlurService.qml
+++ /dev/null
@@ -1,113 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import Quickshell.Wayland // ! Import is needed despite what qmlls says
-import qs.Common
-
-Singleton {
- id: root
-
- property bool quickshellSupported: false
- property bool compositorSupported: false
- property bool available: quickshellSupported && compositorSupported
- readonly property bool enabled: available && (SettingsData.blurEnabled ?? false)
-
- readonly property color borderColor: {
- if (!enabled)
- return "transparent";
- const opacity = SettingsData.blurBorderOpacity ?? 0.5;
- switch (SettingsData.blurBorderColor ?? "outline") {
- case "primary":
- return Theme.withAlpha(Theme.primary, opacity);
- case "secondary":
- return Theme.withAlpha(Theme.secondary, opacity);
- case "surfaceText":
- return Theme.withAlpha(Theme.surfaceText, opacity);
- case "custom":
- return Theme.withAlpha(SettingsData.blurBorderCustomColor ?? "#ffffff", opacity);
- default:
- return Theme.withAlpha(Theme.outline, opacity);
- }
- }
- readonly property int borderWidth: enabled ? 1 : 0
-
- function hoverColor(baseColor, hoverAlpha) {
- if (!enabled)
- return baseColor;
- return Theme.withAlpha(baseColor, hoverAlpha ?? 0.15);
- }
-
- function createBlurRegion(targetWindow) {
- if (!available)
- return null;
-
- try {
- const region = Qt.createQmlObject(`
- import Quickshell
- Region {}
- `, targetWindow, "BlurRegion");
- targetWindow.BackgroundEffect.blurRegion = region;
- return region;
- } catch (e) {
- console.warn("BlurService: Failed to create blur region:", e);
- return null;
- }
- }
-
- function reapplyBlurRegion(targetWindow, region) {
- if (!region || !available)
- return;
- try {
- targetWindow.BackgroundEffect.blurRegion = region;
- region.changed();
- } catch (e) {}
- }
-
- function destroyBlurRegion(targetWindow, region) {
- if (!region)
- return;
- try {
- targetWindow.BackgroundEffect.blurRegion = null;
- } catch (e) {}
- region.destroy();
- }
-
- Process {
- id: blurProbe
- running: false
- command: ["dms", "blur", "check"]
-
- stdout: StdioCollector {
- onStreamFinished: {
- root.compositorSupported = text.trim() === "supported";
- if (root.compositorSupported)
- console.info("BlurService: Compositor supports ext-background-effect-v1");
- else
- console.info("BlurService: Compositor does not support ext-background-effect-v1");
- }
- }
-
- onExited: exitCode => {
- if (exitCode !== 0)
- console.warn("BlurService: blur probe failed with code:", exitCode);
- }
- }
-
- Component.onCompleted: {
- try {
- const test = Qt.createQmlObject(`
- import Quickshell
- Region { radius: 0 }
- `, root, "BlurAvailabilityTest");
- test.destroy();
- quickshellSupported = true;
- console.info("BlurService: Quickshell blur support available");
- blurProbe.running = true;
- } catch (e) {
- console.info("BlurService: BackgroundEffect not available - blur disabled. Requires a newer version of Quickshell.");
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CalendarService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CalendarService.qml
deleted file mode 100644
index 1146f7b..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CalendarService.qml
+++ /dev/null
@@ -1,317 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- property bool khalAvailable: false
- property var eventsByDate: ({})
- property bool isLoading: false
- property string lastError: ""
- property date lastStartDate
- property date lastEndDate
- property string khalDateFormat: "MM/dd/yyyy"
-
- function checkKhalAvailability() {
- if (!khalCheckProcess.running)
- khalCheckProcess.running = true
- }
-
- function detectKhalDateFormat() {
- if (!khalFormatProcess.running)
- khalFormatProcess.running = true
- }
-
- function parseKhalDateFormat(formatExample) {
- let qtFormat = formatExample.replace("12", "MM").replace("21", "dd").replace("2013", "yyyy")
- return { format: qtFormat, parser: null }
- }
-
-
- function loadCurrentMonth() {
- if (!root.khalAvailable)
- return
-
- let today = new Date()
- let firstDay = new Date(today.getFullYear(), today.getMonth(), 1)
- let lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0)
- // Add padding
- let startDate = new Date(firstDay)
- startDate.setDate(startDate.getDate() - firstDay.getDay() - 7)
- let endDate = new Date(lastDay)
- endDate.setDate(endDate.getDate() + (6 - lastDay.getDay()) + 7)
- loadEvents(startDate, endDate)
- }
-
- function loadEvents(startDate, endDate) {
- if (!root.khalAvailable) {
- return
- }
- if (eventsProcess.running) {
- return
- }
- // Store last requested date range for refresh timer
- root.lastStartDate = startDate
- root.lastEndDate = endDate
- root.isLoading = true
- // Format dates for khal using detected format
- let startDateStr = Qt.formatDate(startDate, root.khalDateFormat)
- let endDateStr = Qt.formatDate(endDate, root.khalDateFormat)
- eventsProcess.requestStartDate = startDate
- eventsProcess.requestEndDate = endDate
- eventsProcess.command = ["khal", "list", "--json", "title", "--json", "description", "--json", "start-date", "--json", "start-time", "--json", "end-date", "--json", "end-time", "--json", "all-day", "--json", "location", "--json", "url", startDateStr, endDateStr]
- eventsProcess.running = true
- }
-
- function getEventsForDate(date) {
- let dateKey = Qt.formatDate(date, "yyyy-MM-dd")
- return root.eventsByDate[dateKey] || []
- }
-
- function hasEventsForDate(date) {
- let events = getEventsForDate(date)
- return events.length > 0
- }
-
- // Initialize on component completion
- Component.onCompleted: {
- detectKhalDateFormat()
- }
-
- // Process for detecting khal date format
- Process {
- id: khalFormatProcess
-
- command: ["khal", "printformats"]
- running: false
- onExited: exitCode => {
- if (exitCode !== 0) {
- checkKhalAvailability()
- }
- }
-
- stdout: StdioCollector {
- onStreamFinished: {
- let lines = text.split('\n')
- for (let line of lines) {
- if (line.startsWith('dateformat:')) {
- let formatExample = line.substring(line.indexOf(':') + 1).trim()
- let formatInfo = parseKhalDateFormat(formatExample)
- root.khalDateFormat = formatInfo.format
- break
- }
- }
- checkKhalAvailability()
- }
- }
- }
-
- // Process for checking khal configuration
- Process {
- id: khalCheckProcess
-
- command: ["khal", "list", "today"]
- running: false
- onExited: exitCode => {
- root.khalAvailable = (exitCode === 0)
- if (exitCode === 0) {
- loadCurrentMonth()
- }
- }
- }
-
- // Process for loading events
- Process {
- id: eventsProcess
-
- property date requestStartDate
- property date requestEndDate
- property string rawOutput: ""
-
- running: false
- onExited: exitCode => {
- root.isLoading = false
- if (exitCode !== 0) {
- root.lastError = "Failed to load events (exit code: " + exitCode + ")"
- return
- }
- try {
- let newEventsByDate = {}
- let lines = eventsProcess.rawOutput.split('\n')
- for (let line of lines) {
- line = line.trim()
- if (!line || line === "[]")
- continue
-
- // Parse JSON line
- let dayEvents = JSON.parse(line)
- // Process each event in this day's array
- for (let event of dayEvents) {
- if (!event.title)
- continue
-
- // Parse start and end dates using detected format
- let startDate, endDate
- if (event['start-date']) {
- startDate = Date.fromLocaleString(I18n.locale(), event['start-date'], root.khalDateFormat)
- } else {
- startDate = new Date()
- }
- if (event['end-date']) {
- endDate = Date.fromLocaleString(I18n.locale(), event['end-date'], root.khalDateFormat)
- } else {
- endDate = new Date(startDate)
- }
- // Create start/end times
- let startTime = new Date(startDate)
- let endTime = new Date(endDate)
- if (event['start-time']
- && event['all-day'] !== "True") {
- // Parse time if available and not all-day
- let timeStr = event['start-time']
- if (timeStr) {
- // Match time with optional seconds and AM/PM
- let timeParts = timeStr.match(/(\d+):(\d+)(?::\d+)?\s*(AM|PM)?/i)
- if (timeParts) {
- let hours = parseInt(timeParts[1])
- let minutes = parseInt(timeParts[2])
-
- // Handle AM/PM conversion if present
- if (timeParts[3]) {
- let period = timeParts[3].toUpperCase()
- if (period === 'PM' && hours !== 12) {
- hours += 12
- } else if (period === 'AM' && hours === 12) {
- hours = 0
- }
- }
-
- startTime.setHours(hours, minutes)
- if (event['end-time']) {
- let endTimeParts = event['end-time'].match(
- /(\d+):(\d+)(?::\d+)?\s*(AM|PM)?/i)
- if (endTimeParts) {
- let endHours = parseInt(endTimeParts[1])
- let endMinutes = parseInt(endTimeParts[2])
-
- // Handle AM/PM conversion if present
- if (endTimeParts[3]) {
- let endPeriod = endTimeParts[3].toUpperCase()
- if (endPeriod === 'PM' && endHours !== 12) {
- endHours += 12
- } else if (endPeriod === 'AM' && endHours === 12) {
- endHours = 0
- }
- }
-
- endTime.setHours(endHours, endMinutes)
- }
- } else {
- // Default to 1 hour duration on same day
- endTime = new Date(startTime)
- endTime.setHours(
- startTime.getHours() + 1)
- }
- }
- }
- }
- // Create unique ID for this event (to track multi-day events)
- let eventId = event.title + "_" + event['start-date']
- + "_" + (event['start-time'] || 'allday')
- // Create event object template
- let extractedUrl = ""
- if (!event.url && event.description) {
- let urlMatch = event.description.match(/https?:\/\/[^\s]+/)
- if (urlMatch) {
- extractedUrl = urlMatch[0]
- }
- }
- let eventTemplate = {
- "id": eventId,
- "title": event.title || "Untitled Event",
- "start": startTime,
- "end": endTime,
- "location": event.location || "",
- "description": event.description || "",
- "url": event.url || extractedUrl,
- "calendar": "",
- "color": "",
- "allDay": event['all-day'] === "True",
- "isMultiDay": startDate.toDateString(
- ) !== endDate.toDateString()
- }
- // Add event to each day it spans
- let currentDate = new Date(startDate)
- while (currentDate <= endDate) {
- let dateKey = Qt.formatDate(currentDate,
- "yyyy-MM-dd")
- if (!newEventsByDate[dateKey])
- newEventsByDate[dateKey] = []
-
- // Check if this exact event is already added to this date (prevent duplicates)
- let existingEvent = newEventsByDate[dateKey].find(
- e => {
- return e.id === eventId
- })
- if (existingEvent) {
- // Move to next day without adding duplicate
- currentDate.setDate(currentDate.getDate() + 1)
- continue
- }
- // Create a copy of the event for this date
- let dayEvent = Object.assign({}, eventTemplate)
- // For multi-day events, adjust the display time for this specific day
- if (currentDate.getTime() === startDate.getTime()) {
- // First day - use original start time
- dayEvent.start = new Date(startTime)
- } else {
- // Subsequent days - start at beginning of day for all-day events
- dayEvent.start = new Date(currentDate)
- if (!dayEvent.allDay)
- dayEvent.start.setHours(0, 0, 0, 0)
- }
- if (currentDate.getTime() === endDate.getTime()) {
- // Last day - use original end time
- dayEvent.end = new Date(endTime)
- } else {
- // Earlier days - end at end of day for all-day events
- dayEvent.end = new Date(currentDate)
- if (!dayEvent.allDay)
- dayEvent.end.setHours(23, 59, 59, 999)
- }
- newEventsByDate[dateKey].push(dayEvent)
- // Move to next day
- currentDate.setDate(currentDate.getDate() + 1)
- }
- }
- }
- // Sort events by start time within each date
- for (let dateKey in newEventsByDate) {
- newEventsByDate[dateKey].sort((a, b) => {
- return a.start.getTime(
- ) - b.start.getTime()
- })
- }
- root.eventsByDate = newEventsByDate
- root.lastError = ""
- } catch (error) {
- root.lastError = "Failed to parse events JSON: " + error.toString()
- root.eventsByDate = {}
- }
- // Reset for next run
- eventsProcess.rawOutput = ""
- }
-
- stdout: SplitParser {
- splitMarker: "\n"
- onRead: data => {
- eventsProcess.rawOutput += data + "\n"
- }
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CavaService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CavaService.qml
deleted file mode 100644
index d3e5717..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CavaService.qml
+++ /dev/null
@@ -1,76 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-
-Singleton {
- id: root
-
- property list<int> values: Array(6)
- property int refCount: 0
- property bool cavaAvailable: false
-
- Process {
- id: cavaCheck
-
- command: ["which", "cava"]
- running: false
- onExited: exitCode => {
- root.cavaAvailable = exitCode === 0 && Quickshell.env("DMS_DISABLE_CAVA") !== "1";
- }
- }
-
- Component.onCompleted: {
- cavaCheck.running = true;
- }
-
- Process {
- id: cavaProcess
-
- running: root.cavaAvailable && root.refCount > 0
- command: ["sh", "-c", `cat <<'CAVACONF' | cava -p /dev/stdin
-[general]
-framerate=25
-bars=6
-autosens=0
-sensitivity=30
-lower_cutoff_freq=50
-higher_cutoff_freq=12000
-
-[output]
-method=raw
-raw_target=/dev/stdout
-data_format=ascii
-channels=mono
-mono_option=average
-
-[smoothing]
-noise_reduction=35
-integral=90
-gravity=95
-ignore=2
-monstercat=1.5
-CAVACONF`]
-
- onRunningChanged: {
- if (!running) {
- root.values = Array(6).fill(0);
- }
- }
-
- stdout: SplitParser {
- splitMarker: "\n"
- onRead: data => {
- if (root.refCount > 0 && data.length > 0) {
- const parts = data.split(";");
- if (parts.length >= 6) {
- const points = [parseInt(parts[0], 10), parseInt(parts[1], 10), parseInt(parts[2], 10), parseInt(parts[3], 10), parseInt(parts[4], 10), parseInt(parts[5], 10)];
- root.values = points;
- }
- }
- }
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ChangelogService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ChangelogService.qml
deleted file mode 100644
index 562a513..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ChangelogService.qml
+++ /dev/null
@@ -1,108 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtCore
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- readonly property string currentVersion: "1.4"
- readonly property bool changelogEnabled: false
-
- readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/DankMaterialShell"
- readonly property string changelogMarkerPath: configDir + "/.changelog-" + currentVersion
-
- property bool checkComplete: false
- property bool changelogDismissed: false
-
- readonly property bool shouldShowChangelog: {
- if (!checkComplete)
- return false;
- if (!changelogEnabled)
- return false;
- if (changelogDismissed)
- return false;
- if (typeof FirstLaunchService !== "undefined" && FirstLaunchService.isFirstLaunch)
- return false;
- return true;
- }
-
- signal changelogRequested
- signal changelogCompleted
-
- Component.onCompleted: {
- if (!changelogEnabled)
- return;
- if (FirstLaunchService.checkComplete)
- handleFirstLaunchResult();
- }
-
- function handleFirstLaunchResult() {
- if (FirstLaunchService.isFirstLaunch) {
- checkComplete = true;
- changelogDismissed = true;
- touchMarkerProcess.running = true;
- } else {
- changelogCheckProcess.running = true;
- }
- }
-
- Connections {
- target: FirstLaunchService
-
- function onCheckCompleteChanged() {
- if (FirstLaunchService.checkComplete && root.changelogEnabled && !root.checkComplete)
- root.handleFirstLaunchResult();
- }
- }
-
- function showChangelog() {
- changelogRequested();
- }
-
- function dismissChangelog() {
- changelogDismissed = true;
- touchMarkerProcess.running = true;
- changelogCompleted();
- }
-
- Process {
- id: changelogCheckProcess
-
- command: ["sh", "-c", "[ -f '" + changelogMarkerPath + "' ] && echo 'seen' || echo 'show'"]
- running: false
-
- stdout: SplitParser {
- onRead: data => {
- const result = data.trim();
- root.checkComplete = true;
-
- switch (result) {
- case "seen":
- root.changelogDismissed = true;
- break;
- case "show":
- root.changelogRequested();
- break;
- }
- }
- }
- }
-
- Process {
- id: touchMarkerProcess
-
- command: ["sh", "-c", "mkdir -p '" + configDir + "' && touch '" + changelogMarkerPath + "'"]
- running: false
-
- onExited: exitCode => {
- if (exitCode !== 0) {
- console.warn("ChangelogService: Failed to create changelog marker");
- }
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ClipboardService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ClipboardService.qml
deleted file mode 100644
index 4c09255..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ClipboardService.qml
+++ /dev/null
@@ -1,275 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- readonly property int longTextThreshold: 200
-
- readonly property bool clipboardAvailable: DMSService.isConnected && (DMSService.capabilities.length === 0 || DMSService.capabilities.includes("clipboard"))
- readonly property bool wtypeAvailable: SessionService.wtypeAvailable
-
- property var internalEntries: []
- property var clipboardEntries: []
- property var unpinnedEntries: []
- property var pinnedEntries: []
- property int pinnedCount: 0
- property int totalCount: 0
- property string searchText: ""
- property int selectedIndex: 0
- property bool keyboardNavigationActive: false
- property int refCount: 0
-
- signal historyCopied
- signal historyCleared
-
- Process {
- id: wtypeProcess
- command: ["wtype", "-M", "ctrl", "-P", "v", "-p", "v", "-m", "ctrl"]
- running: false
- }
-
- Timer {
- id: pasteTimer
- interval: 200
- repeat: false
- onTriggered: wtypeProcess.running = true
- }
-
- function updateFilteredModel() {
- const query = searchText.trim();
- let filtered = [];
-
- if (query.length === 0) {
- filtered = internalEntries;
- } else {
- const lowerQuery = query.toLowerCase();
- filtered = internalEntries.filter(entry => entry.preview.toLowerCase().includes(lowerQuery));
- }
-
- filtered.sort((a, b) => {
- if (a.pinned !== b.pinned)
- return b.pinned ? 1 : -1;
- return b.id - a.id;
- });
-
- clipboardEntries = filtered;
- unpinnedEntries = filtered.filter(e => !e.pinned);
- totalCount = clipboardEntries.length;
-
- if (unpinnedEntries.length === 0) {
- keyboardNavigationActive = false;
- selectedIndex = 0;
- return;
- }
- if (selectedIndex >= unpinnedEntries.length) {
- selectedIndex = unpinnedEntries.length - 1;
- }
- }
-
- function refresh() {
- if (!clipboardAvailable) {
- return;
- }
- DMSService.sendRequest("clipboard.getHistory", null, function (response) {
- if (response.error) {
- console.warn("ClipboardService: Failed to get history:", response.error);
- return;
- }
- internalEntries = response.result || [];
- pinnedEntries = internalEntries.filter(e => e.pinned);
- pinnedCount = pinnedEntries.length;
- updateFilteredModel();
- });
- }
-
- function reset() {
- searchText = "";
- selectedIndex = 0;
- keyboardNavigationActive = false;
- internalEntries = [];
- clipboardEntries = [];
- unpinnedEntries = [];
- }
-
- function copyEntry(entry, closeCallback) {
- DMSService.sendRequest("clipboard.copyEntry", {
- "id": entry.id
- }, function (response) {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to copy entry"));
- return;
- }
- ToastService.showInfo(entry.isImage ? I18n.tr("Image copied to clipboard") : I18n.tr("Copied to clipboard"));
- historyCopied();
- if (closeCallback) {
- closeCallback();
- }
- });
- }
-
- function pasteEntry(entry, closeCallback) {
- if (!wtypeAvailable) {
- ToastService.showError(I18n.tr("wtype not available - install wtype for paste support"));
- return;
- }
- DMSService.sendRequest("clipboard.copyEntry", {
- "id": entry.id
- }, function (response) {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to copy entry"));
- return;
- }
- if (closeCallback) {
- closeCallback();
- }
- pasteTimer.start();
- });
- }
-
- function pasteSelected(closeCallback) {
- if (!keyboardNavigationActive || clipboardEntries.length === 0 || selectedIndex < 0 || selectedIndex >= clipboardEntries.length) {
- return;
- }
- pasteEntry(clipboardEntries[selectedIndex], closeCallback);
- }
-
- function deleteEntry(entry) {
- DMSService.sendRequest("clipboard.deleteEntry", {
- "id": entry.id
- }, function (response) {
- if (response.error) {
- console.warn("ClipboardService: Failed to delete entry:", response.error);
- return;
- }
- internalEntries = internalEntries.filter(e => e.id !== entry.id);
- updateFilteredModel();
- if (clipboardEntries.length === 0) {
- keyboardNavigationActive = false;
- selectedIndex = 0;
- return;
- }
- if (selectedIndex >= clipboardEntries.length) {
- selectedIndex = clipboardEntries.length - 1;
- }
- });
- }
-
- function deletePinnedEntry(entry, confirmDialog) {
- if (!confirmDialog) {
- return;
- }
- confirmDialog.show(I18n.tr("Delete Saved Item?"), I18n.tr("This will permanently remove this saved clipboard item. This action cannot be undone."), function () {
- DMSService.sendRequest("clipboard.deleteEntry", {
- "id": entry.id
- }, function (response) {
- if (response.error) {
- console.warn("ClipboardService: Failed to delete entry:", response.error);
- return;
- }
- internalEntries = internalEntries.filter(e => e.id !== entry.id);
- updateFilteredModel();
- ToastService.showInfo(I18n.tr("Saved item deleted"));
- });
- }, function () {});
- }
-
- function pinEntry(entry) {
- DMSService.sendRequest("clipboard.getPinnedCount", null, function (countResponse) {
- if (countResponse.error) {
- ToastService.showError(I18n.tr("Failed to check pin limit"));
- return;
- }
-
- const maxPinned = 25;
- if (countResponse.result.count >= maxPinned) {
- ToastService.showError(I18n.tr("Maximum pinned entries reached") + " (" + maxPinned + ")");
- return;
- }
-
- DMSService.sendRequest("clipboard.pinEntry", {
- "id": entry.id
- }, function (response) {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to pin entry"));
- return;
- }
- ToastService.showInfo(I18n.tr("Entry pinned"));
- refresh();
- });
- });
- }
-
- function unpinEntry(entry) {
- DMSService.sendRequest("clipboard.unpinEntry", {
- "id": entry.id
- }, function (response) {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to unpin entry"));
- return;
- }
- ToastService.showInfo(I18n.tr("Entry unpinned"));
- refresh();
- });
- }
-
- function clearAll() {
- const hasPinned = pinnedCount > 0;
- const savedCount = pinnedCount;
- DMSService.sendRequest("clipboard.clearHistory", null, function (response) {
- if (response.error) {
- console.warn("ClipboardService: Failed to clear history:", response.error);
- return;
- }
- refresh();
- historyCleared();
- if (hasPinned) {
- ToastService.showInfo(I18n.tr("History cleared. %1 pinned entries kept.").arg(savedCount));
- }
- });
- }
-
- function getEntryPreview(entry) {
- return entry.preview || "";
- }
-
- function getEntryType(entry) {
- if (entry.isImage) {
- return "image";
- }
- if (entry.size > longTextThreshold) {
- return "long_text";
- }
- return "text";
- }
-
- function hashedPinnedEntry(entryHash) {
- if (!entryHash) {
- return false;
- }
- return pinnedEntries.some(pinnedEntry => pinnedEntry.hash === entryHash);
- }
-
- onClipboardAvailableChanged: {
- if (!clipboardAvailable || refCount <= 0)
- return;
- refresh();
- }
-
- Connections {
- target: DMSService
- enabled: root.refCount > 0
- function onClipboardStateUpdate(data) {
- const newHistory = data.history || [];
- internalEntries = newHistory;
- pinnedEntries = newHistory.filter(e => e.pinned);
- pinnedCount = pinnedEntries.length;
- updateFilteredModel();
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CompositorService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CompositorService.qml
deleted file mode 100644
index d327ea2..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CompositorService.qml
+++ /dev/null
@@ -1,677 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.I3
-import Quickshell.Wayland
-import Quickshell.Hyprland
-import qs.Common
-
-Singleton {
- id: root
-
- property bool isHyprland: false
- property bool isNiri: false
- property bool isDwl: false
- property bool isSway: false
- property bool isScroll: false
- property bool isMiracle: false
- property bool isLabwc: false
- property string compositor: "unknown"
- readonly property bool useHyprlandFocusGrab: isHyprland && Quickshell.env("DMS_HYPRLAND_EXCLUSIVE_FOCUS") !== "1"
-
- readonly property string hyprlandSignature: Quickshell.env("HYPRLAND_INSTANCE_SIGNATURE")
- readonly property string niriSocket: Quickshell.env("NIRI_SOCKET")
- readonly property string swaySocket: Quickshell.env("SWAYSOCK")
- readonly property string scrollSocket: Quickshell.env("SWAYSOCK")
- readonly property string miracleSocket: Quickshell.env("MIRACLESOCK")
- readonly property string labwcPid: Quickshell.env("LABWC_PID")
- property bool useNiriSorting: isNiri && NiriService
-
- property var randrScales: ({})
- property bool randrReady: false
- signal randrDataReady
-
- property var sortedToplevels: []
- property bool _sortScheduled: false
-
- signal toplevelsChanged
-
- function fetchRandrData() {
- Proc.runCommand("randr", ["dms", "randr", "--json"], (output, exitCode) => {
- if (exitCode === 0 && output) {
- try {
- const data = JSON.parse(output.trim());
- if (data.outputs && Array.isArray(data.outputs)) {
- const scales = {};
- for (const out of data.outputs) {
- if (out.name && out.scale > 0)
- scales[out.name] = out.scale;
- }
- randrScales = scales;
- }
- } catch (e) {
- console.warn("CompositorService: failed to parse randr data:", e);
- }
- }
- randrReady = true;
- randrDataReady();
- }, 0, 3000);
- }
-
- function getScreenScale(screen) {
- if (!screen)
- return 1;
-
- if (Quickshell.env("QT_WAYLAND_FORCE_DPI") || Quickshell.env("QT_SCALE_FACTOR")) {
- return screen.devicePixelRatio || 1;
- }
-
- const randrScale = randrScales[screen.name];
- if (randrScale !== undefined && randrScale > 0)
- return Math.round(randrScale * 20) / 20;
-
- if (WlrOutputService.wlrOutputAvailable && screen) {
- const wlrOutput = WlrOutputService.getOutput(screen.name);
- if (wlrOutput?.enabled && wlrOutput.scale !== undefined && wlrOutput.scale > 0) {
- return Math.round(wlrOutput.scale * 20) / 20;
- }
- }
-
- if (isNiri && screen) {
- const niriScale = NiriService.displayScales[screen.name];
- if (niriScale !== undefined)
- return niriScale;
- }
-
- if (isHyprland && screen) {
- const hyprlandMonitor = Hyprland.monitors.values.find(m => m.name === screen.name);
- if (hyprlandMonitor?.scale !== undefined)
- return hyprlandMonitor.scale;
- }
-
- if (isDwl && screen) {
- const dwlScale = DwlService.getOutputScale(screen.name);
- if (dwlScale !== undefined && dwlScale > 0)
- return dwlScale;
- }
-
- return screen?.devicePixelRatio || 1;
- }
-
- function getFocusedScreen() {
- let screenName = "";
- if (isHyprland && Hyprland.focusedWorkspace?.monitor)
- screenName = Hyprland.focusedWorkspace.monitor.name;
- else if (isNiri && NiriService.currentOutput)
- screenName = NiriService.currentOutput;
- else if (isSway || isScroll || isMiracle) {
- const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
- screenName = focusedWs?.monitor?.name || "";
- } else if (isDwl && DwlService.activeOutput)
- screenName = DwlService.activeOutput;
-
- if (!screenName)
- return Quickshell.screens.length > 0 ? Quickshell.screens[0] : null;
-
- for (let i = 0; i < Quickshell.screens.length; i++) {
- if (Quickshell.screens[i].name === screenName)
- return Quickshell.screens[i];
- }
- return Quickshell.screens.length > 0 ? Quickshell.screens[0] : null;
- }
-
- Timer {
- id: sortDebounceTimer
- interval: 100
- repeat: false
- onTriggered: {
- _sortScheduled = false;
- sortedToplevels = computeSortedToplevels();
- toplevelsChanged();
- }
- }
-
- function scheduleSort() {
- if (_sortScheduled)
- return;
- _sortScheduled = true;
- sortDebounceTimer.restart();
- }
-
- Connections {
- target: ToplevelManager.toplevels
- function onValuesChanged() {
- root.scheduleSort();
- }
- }
- Connections {
- target: isHyprland ? Hyprland : null
- enabled: isHyprland
-
- function onRawEvent(event) {
- if (event.name === "openwindow" || event.name === "closewindow" || event.name === "movewindow" || event.name === "movewindowv2" || event.name === "workspace" || event.name === "workspacev2" || event.name === "focusedmon" || event.name === "focusedmonv2" || event.name === "activewindow" || event.name === "activewindowv2" || event.name === "changefloatingmode" || event.name === "fullscreen" || event.name === "moveintogroup" || event.name === "moveoutofgroup") {
- try {
- Hyprland.refreshToplevels();
- } catch (e) {}
- root.scheduleSort();
- }
- }
- }
- Connections {
- target: NiriService
- function onWindowsChanged() {
- root.scheduleSort();
- }
- }
-
- Component.onCompleted: {
- fetchRandrData();
- detectCompositor();
- scheduleSort();
- Qt.callLater(() => {
- NiriService.generateNiriLayoutConfig();
- HyprlandService.generateLayoutConfig();
- DwlService.generateLayoutConfig();
- });
- }
-
- Connections {
- target: DwlService
- function onStateChanged() {
- if (isDwl && !isHyprland && !isNiri) {
- scheduleSort();
- }
- }
- }
-
- function computeSortedToplevels() {
- if (!ToplevelManager.toplevels || !ToplevelManager.toplevels.values)
- return [];
-
- if (useNiriSorting)
- return NiriService.sortToplevels(ToplevelManager.toplevels.values);
-
- if (isHyprland)
- return sortHyprlandToplevelsSafe();
-
- return Array.from(ToplevelManager.toplevels.values);
- }
-
- function _get(o, path, fallback) {
- try {
- let v = o;
- for (let i = 0; i < path.length; i++) {
- if (v === null || v === undefined)
- return fallback;
- v = v[path[i]];
- }
- return (v === undefined || v === null) ? fallback : v;
- } catch (e) {
- return fallback;
- }
- }
-
- function sortHyprlandToplevelsSafe() {
- if (!Hyprland.toplevels || !Hyprland.toplevels.values)
- return [];
-
- const items = Array.from(Hyprland.toplevels.values);
-
- function _get(o, path, fb) {
- try {
- let v = o;
- for (let k of path) {
- if (v == null)
- return fb;
- v = v[k];
- }
- return (v == null) ? fb : v;
- } catch (e) {
- return fb;
- }
- }
-
- let snap = [];
- for (let i = 0; i < items.length; i++) {
- const t = items[i];
- if (!t)
- continue;
- const addr = t.address || "";
- if (!addr)
- continue;
- const li = t.lastIpcObject || null;
-
- const monName = _get(li, ["monitor"], null) ?? _get(t, ["monitor", "name"], "");
- const monX = _get(t, ["monitor", "x"], Number.MAX_SAFE_INTEGER);
- const monY = _get(t, ["monitor", "y"], Number.MAX_SAFE_INTEGER);
-
- const wsId = _get(li, ["workspace", "id"], null) ?? _get(t, ["workspace", "id"], Number.MAX_SAFE_INTEGER);
-
- const at = _get(li, ["at"], null);
- let atX = (at !== null && at !== undefined && typeof at[0] === "number") ? at[0] : 1e9;
- let atY = (at !== null && at !== undefined && typeof at[1] === "number") ? at[1] : 1e9;
-
- const relX = Number.isFinite(monX) ? (atX - monX) : atX;
- const relY = Number.isFinite(monY) ? (atY - monY) : atY;
-
- snap.push({
- monKey: String(monName),
- monOrderX: Number.isFinite(monX) ? monX : Number.MAX_SAFE_INTEGER,
- monOrderY: Number.isFinite(monY) ? monY : Number.MAX_SAFE_INTEGER,
- wsId: (typeof wsId === "number") ? wsId : Number.MAX_SAFE_INTEGER,
- x: relX,
- y: relY,
- title: t.title || "",
- address: addr,
- wayland: t.wayland
- });
- }
-
- const groups = new Map();
- for (const it of snap) {
- const key = it.monKey + "::" + it.wsId;
- if (!groups.has(key))
- groups.set(key, []);
- groups.get(key).push(it);
- }
-
- let groupList = [];
- for (const [key, arr] of groups) {
- const repr = arr[0];
- groupList.push({
- key,
- monKey: repr.monKey,
- monOrderX: repr.monOrderX,
- monOrderY: repr.monOrderY,
- wsId: repr.wsId,
- items: arr
- });
- }
-
- groupList.sort((a, b) => {
- if (a.monOrderX !== b.monOrderX)
- return a.monOrderX - b.monOrderX;
- if (a.monOrderY !== b.monOrderY)
- return a.monOrderY - b.monOrderY;
- if (a.monKey !== b.monKey)
- return a.monKey.localeCompare(b.monKey);
- if (a.wsId !== b.wsId)
- return a.wsId - b.wsId;
- return 0;
- });
-
- const COLUMN_THRESHOLD = 48;
- const JITTER_Y = 6;
-
- let ordered = [];
- for (const g of groupList) {
- const arr = g.items;
-
- const xs = arr.map(it => it.x).filter(x => Number.isFinite(x)).sort((a, b) => a - b);
- let colCenters = [];
- if (xs.length > 0) {
- for (const x of xs) {
- if (colCenters.length === 0) {
- colCenters.push(x);
- } else {
- const last = colCenters[colCenters.length - 1];
- if (x - last >= COLUMN_THRESHOLD) {
- colCenters.push(x);
- }
- }
- }
- } else {
- colCenters = [0];
- }
-
- for (const it of arr) {
- let bestCol = 0;
- let bestDist = Number.POSITIVE_INFINITY;
- for (let ci = 0; ci < colCenters.length; ci++) {
- const d = Math.abs(it.x - colCenters[ci]);
- if (d < bestDist) {
- bestDist = d;
- bestCol = ci;
- }
- }
- it._col = bestCol;
- }
-
- arr.sort((a, b) => {
- if (a._col !== b._col)
- return a._col - b._col;
-
- const dy = a.y - b.y;
- if (Math.abs(dy) > JITTER_Y)
- return dy;
-
- if (a.title !== b.title)
- return a.title.localeCompare(b.title);
- if (a.address !== b.address)
- return a.address.localeCompare(b.address);
- return 0;
- });
-
- ordered.push.apply(ordered, arr);
- }
-
- return ordered.map(x => x.wayland).filter(w => w !== null && w !== undefined);
- }
-
- function filterCurrentWorkspace(toplevels, screen) {
- if (useNiriSorting)
- return NiriService.filterCurrentWorkspace(toplevels, screen);
- if (isHyprland)
- return filterHyprlandCurrentWorkspaceSafe(toplevels, screen);
- return toplevels;
- }
-
- function filterCurrentDisplay(toplevels, screenName) {
- if (!toplevels || toplevels.length === 0 || !screenName)
- return toplevels;
- if (useNiriSorting)
- return NiriService.filterCurrentDisplay(toplevels, screenName);
- if (isHyprland)
- return filterHyprlandCurrentDisplaySafe(toplevels, screenName);
- return toplevels;
- }
-
- function filterHyprlandCurrentDisplaySafe(toplevels, screenName) {
- if (!toplevels || toplevels.length === 0 || !Hyprland.toplevels)
- return toplevels;
-
- let monitorWindows = new Set();
- try {
- const hy = Array.from(Hyprland.toplevels.values);
- for (const t of hy) {
- const mon = _get(t, ["monitor", "name"], "");
- if (mon === screenName && t.wayland)
- monitorWindows.add(t.wayland);
- }
- } catch (e) {}
-
- return toplevels.filter(w => monitorWindows.has(w));
- }
-
- function filterHyprlandCurrentWorkspaceSafe(toplevels, screenName) {
- if (!toplevels || toplevels.length === 0 || !Hyprland.toplevels)
- return toplevels;
-
- let currentWorkspaceId = null;
- try {
- if (Hyprland.monitors) {
- const monitor = Hyprland.monitors.values.find(m => m.name === screenName);
- if (monitor)
- currentWorkspaceId = _get(monitor, ["activeWorkspace", "id"], null);
- }
-
- if (currentWorkspaceId === null) {
- const hy = Array.from(Hyprland.toplevels.values);
- for (const t of hy) {
- const mon = _get(t, ["monitor", "name"], "");
- const wsId = _get(t, ["workspace", "id"], null);
- const active = !!_get(t, ["activated"], false);
- if (mon === screenName && wsId !== null) {
- if (active) {
- currentWorkspaceId = wsId;
- break;
- }
- if (currentWorkspaceId === null)
- currentWorkspaceId = wsId;
- }
- }
- }
-
- if (currentWorkspaceId === null && Hyprland.workspaces) {
- const wss = Array.from(Hyprland.workspaces.values);
- const focusedId = _get(Hyprland, ["focusedWorkspace", "id"], null);
- for (const ws of wss) {
- const monName = _get(ws, ["monitor", "name"], "");
- const wsId = _get(ws, ["id"], null);
- if (monName === screenName && wsId !== null) {
- if (focusedId !== null && wsId === focusedId) {
- currentWorkspaceId = wsId;
- break;
- }
- if (currentWorkspaceId === null)
- currentWorkspaceId = wsId;
- }
- }
- }
- } catch (e) {
- console.warn("CompositorService: workspace snapshot failed:", e);
- }
-
- if (currentWorkspaceId === null)
- return toplevels;
-
- let map = new Map();
- try {
- const hy = Array.from(Hyprland.toplevels.values);
- for (const t of hy) {
- const wsId = _get(t, ["workspace", "id"], null);
- if (t && t.wayland && wsId !== null)
- map.set(t.wayland, wsId);
- }
- } catch (e) {}
-
- return toplevels.filter(w => map.get(w) === currentWorkspaceId);
- }
-
- Timer {
- id: compositorInitTimer
- interval: 100
- running: true
- repeat: false
- onTriggered: {
- detectCompositor();
- Qt.callLater(() => {
- NiriService.generateNiriLayoutConfig();
- HyprlandService.generateLayoutConfig();
- DwlService.generateLayoutConfig();
- });
- }
- }
-
- function detectCompositor() {
- if (hyprlandSignature && hyprlandSignature.length > 0 && !niriSocket && !swaySocket && !scrollSocket && !miracleSocket && !labwcPid) {
- isHyprland = true;
- isNiri = false;
- isDwl = false;
- isSway = false;
- isScroll = false;
- isMiracle = false;
- isLabwc = false;
- compositor = "hyprland";
- console.info("CompositorService: Detected Hyprland");
- return;
- }
-
- if (niriSocket && niriSocket.length > 0) {
- Proc.runCommand("niriSocketCheck", ["test", "-S", niriSocket], (output, exitCode) => {
- if (exitCode === 0) {
- isNiri = true;
- isHyprland = false;
- isDwl = false;
- isSway = false;
- isScroll = false;
- isMiracle = false;
- isLabwc = false;
- compositor = "niri";
- console.info("CompositorService: Detected Niri with socket:", niriSocket);
- NiriService.generateNiriBlurrule();
- }
- }, 0);
- return;
- }
-
- if (swaySocket && swaySocket.length > 0 && !scrollSocket && scrollSocket.length == 0 && !miracleSocket) {
- Proc.runCommand("swaySocketCheck", ["test", "-S", swaySocket], (output, exitCode) => {
- if (exitCode === 0) {
- isNiri = false;
- isHyprland = false;
- isDwl = false;
- isSway = true;
- isScroll = false;
- isMiracle = false;
- isLabwc = false;
- compositor = "sway";
- console.info("CompositorService: Detected Sway with socket:", swaySocket);
- }
- }, 0);
- return;
- }
-
- if (miracleSocket && miracleSocket.length > 0) {
- Proc.runCommand("miracleSocketCheck", ["test", "-S", miracleSocket], (output, exitCode) => {
- if (exitCode === 0) {
- isNiri = false;
- isHyprland = false;
- isDwl = false;
- isSway = false;
- isScroll = false;
- isMiracle = true;
- isLabwc = false;
- compositor = "miracle";
- console.info("CompositorService: Detected Miracle WM with socket:", miracleSocket);
- }
- }, 0);
- return;
- }
-
- if (scrollSocket && scrollSocket.length > 0 && !miracleSocket) {
- Proc.runCommand("scrollSocketCheck", ["test", "-S", scrollSocket], (output, exitCode) => {
- if (exitCode === 0) {
- isNiri = false;
- isHyprland = false;
- isDwl = false;
- isSway = false;
- isScroll = true;
- isMiracle = false;
- isLabwc = false;
- compositor = "scroll";
- console.info("CompositorService: Detected Scroll with socket:", scrollSocket);
- }
- }, 0);
- return;
- }
-
- if (labwcPid && labwcPid.length > 0) {
- isHyprland = false;
- isNiri = false;
- isDwl = false;
- isSway = false;
- isScroll = false;
- isMiracle = false;
- isLabwc = true;
- compositor = "labwc";
- console.info("CompositorService: Detected LabWC with PID:", labwcPid);
- return;
- }
-
- if (DMSService.dmsAvailable) {
- Qt.callLater(checkForDwl);
- } else {
- isHyprland = false;
- isNiri = false;
- isDwl = false;
- isSway = false;
- isScroll = false;
- isMiracle = false;
- isLabwc = false;
- compositor = "unknown";
- console.warn("CompositorService: No compositor detected");
- }
- }
-
- Connections {
- target: DMSService
- function onCapabilitiesReceived() {
- if (!isHyprland && !isNiri && !isDwl && !isLabwc) {
- checkForDwl();
- }
- }
- }
-
- function checkForDwl() {
- if (DMSService.apiVersion >= 12 && DMSService.capabilities.includes("dwl")) {
- isHyprland = false;
- isNiri = false;
- isDwl = true;
- isSway = false;
- isScroll = false;
- isMiracle = false;
- isLabwc = false;
- compositor = "dwl";
- console.info("CompositorService: Detected DWL via DMS capability");
- }
- }
-
- function powerOffMonitors() {
- if (isNiri)
- return NiriService.powerOffMonitors();
- if (isHyprland)
- return Hyprland.dispatch("dpms off");
- if (isDwl)
- return _dwlPowerOffMonitors();
- if (isSway || isScroll || isMiracle) {
- try {
- I3.dispatch("output * dpms off");
- } catch (_) {}
- return;
- }
- if (isLabwc) {
- Quickshell.execDetached(["dms", "dpms", "off"]);
- }
- console.warn("CompositorService: Cannot power off monitors, unknown compositor");
- }
-
- function powerOnMonitors() {
- if (isNiri)
- return NiriService.powerOnMonitors();
- if (isHyprland)
- return Hyprland.dispatch("dpms on");
- if (isDwl)
- return _dwlPowerOnMonitors();
- if (isSway || isScroll || isMiracle) {
- try {
- I3.dispatch("output * dpms on");
- } catch (_) {}
- return;
- }
- if (isLabwc) {
- Quickshell.execDetached(["dms", "dpms", "on"]);
- }
- console.warn("CompositorService: Cannot power on monitors, unknown compositor");
- }
-
- function _dwlPowerOffMonitors() {
- if (!Quickshell.screens || Quickshell.screens.length === 0) {
- console.warn("CompositorService: No screens available for DWL power off");
- return;
- }
-
- for (let i = 0; i < Quickshell.screens.length; i++) {
- const screen = Quickshell.screens[i];
- if (screen && screen.name) {
- Quickshell.execDetached(["mmsg", "-d", "disable_monitor," + screen.name]);
- }
- }
- }
-
- function _dwlPowerOnMonitors() {
- if (!Quickshell.screens || Quickshell.screens.length === 0) {
- console.warn("CompositorService: No screens available for DWL power on");
- return;
- }
-
- for (let i = 0; i < Quickshell.screens.length; i++) {
- const screen = Quickshell.screens[i];
- if (screen && screen.name) {
- Quickshell.execDetached(["mmsg", "-d", "enable_monitor," + screen.name]);
- }
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CupsService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CupsService.qml
deleted file mode 100644
index a88655d..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/CupsService.qml
+++ /dev/null
@@ -1,860 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import qs.Common
-
-Singleton {
- id: root
-
- property int refCount: 0
-
- onRefCountChanged: {
- if (refCount > 0) {
- ensureSubscription();
- } else if (refCount === 0 && DMSService.activeSubscriptions.includes("cups")) {
- DMSService.removeSubscription("cups");
- }
- }
-
- function ensureSubscription() {
- if (refCount <= 0)
- return;
- if (!DMSService.isConnected)
- return;
- if (DMSService.activeSubscriptions.includes("cups"))
- return;
- if (DMSService.activeSubscriptions.includes("all"))
- return;
- DMSService.addSubscription("cups");
- if (cupsAvailable) {
- getState();
- }
- }
-
- property var printerNames: []
- property var printers: []
- property string selectedPrinter: ""
- property string expandedPrinter: ""
-
- property bool cupsAvailable: false
- property bool stateInitialized: false
-
- property var devices: []
- property var ppds: []
- property var printerClasses: []
-
- readonly property var filteredDevices: {
- if (!devices || devices.length === 0)
- return [];
- const bareProtocols = ["ipp", "ipps", "http", "https", "lpd", "socket", "beh", "dnssd", "mdns", "smb", "file", "cups-brf"];
-
- // First pass: filter out invalid/bare protocol entries
- const validDevices = devices.filter(d => {
- if (!d.uri)
- return false;
- const uriLower = d.uri.toLowerCase();
- for (let proto of bareProtocols) {
- if (uriLower === proto || uriLower === proto + ":")
- return false;
- }
- if (d.class === "network" && d.info === "Backend Error Handler")
- return false;
- return true;
- });
-
- // Second pass: prefer IPP over LPD for the same printer
- // _printer._tcp (LPD) doesn't work well with driverless printing
- // _ipp._tcp or _ipps._tcp (IPP) should be preferred
- const ippDeviceHosts = new Set();
- for (const d of validDevices) {
- if (!d.uri)
- continue;
- // Extract hostname from dnssd URIs like dnssd://Name%20[mac]._ipp._tcp.local
- const ippMatch = d.uri.match(/dnssd:\/\/[^/]*\._ipps?\._tcp/);
- if (ippMatch) {
- // Extract the unique identifier (usually MAC address in brackets)
- const macMatch = d.uri.match(/\[([a-f0-9]+)\]/i);
- if (macMatch)
- ippDeviceHosts.add(macMatch[1].toLowerCase());
- }
- }
-
- // Filter out _printer._tcp devices when we have _ipp._tcp for the same printer
- return validDevices.filter(d => {
- if (!d.uri)
- return true;
- // If this is an LPD device, check if we have an IPP alternative
- if (d.uri.includes("._printer._tcp")) {
- const macMatch = d.uri.match(/\[([a-f0-9]+)\]/i);
- if (macMatch && ippDeviceHosts.has(macMatch[1].toLowerCase())) {
- return false; // Skip LPD device, we have IPP
- }
- }
- return true;
- });
- }
-
- function decodeUri(str) {
- if (!str)
- return "";
- try {
- return decodeURIComponent(str.replace(/\+/g, " "));
- } catch (e) {
- return str;
- }
- }
-
- function getDeviceDisplayName(device) {
- if (!device)
- return "";
- let name = "";
- if (device.info && device.info.length > 0) {
- name = decodeUri(device.info);
- } else if (device.makeModel && device.makeModel.length > 0) {
- name = decodeUri(device.makeModel);
- } else {
- return decodeUri(device.uri);
- }
- if (device.ip)
- return name + " (" + device.ip + ")";
- return name;
- }
-
- function getDeviceSubtitle(device) {
- if (!device)
- return "";
- const parts = [];
- switch (device.class) {
- case "direct":
- parts.push(I18n.tr("Local"));
- break;
- case "network":
- parts.push(I18n.tr("Network"));
- break;
- case "file":
- parts.push(I18n.tr("File"));
- break;
- default:
- if (device.class)
- parts.push(device.class);
- }
- if (device.location)
- parts.push(decodeUri(device.location));
- return parts.join(" • ");
- }
-
- function suggestPrinterName(device) {
- if (!device)
- return "";
- let name = device.info || device.makeModel || "";
- name = name.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
- return name.substring(0, 32) || "Printer";
- }
-
- function getMatchingPPDs(device) {
- if (!device || !ppds || ppds.length === 0)
- return [];
- const isDnssd = device.uri && (device.uri.startsWith("dnssd://") || device.uri.startsWith("ipp://") || device.uri.startsWith("ipps://"));
- if (isDnssd) {
- const driverless = ppds.filter(p => p.name === "driverless" || p.name === "everywhere" || (p.makeModel && p.makeModel.toLowerCase().includes("driverless")));
- if (driverless.length > 0)
- return driverless;
- }
- if (!device.makeModel)
- return [];
- const makeModelLower = device.makeModel.toLowerCase();
- const words = makeModelLower.split(/[\s_-]+/).filter(w => w.length > 2);
- return ppds.filter(p => {
- if (!p.makeModel)
- return false;
- const ppdLower = p.makeModel.toLowerCase();
- return words.some(w => ppdLower.includes(w));
- }).slice(0, 10);
- }
-
- property bool loadingDevices: false
- property bool loadingPPDs: false
- property bool loadingClasses: false
- property bool creatingPrinter: false
-
- signal cupsStateUpdate
-
- readonly property string socketPath: Quickshell.env("DMS_SOCKET")
-
- Component.onCompleted: {
- if (socketPath && socketPath.length > 0) {
- checkDMSCapabilities();
- }
- }
-
- Connections {
- target: DMSService
-
- function onConnectionStateChanged() {
- if (DMSService.isConnected) {
- checkDMSCapabilities();
- ensureSubscription();
- }
- }
- }
-
- Connections {
- target: DMSService
- enabled: DMSService.isConnected
-
- function onCupsStateUpdate(data) {
- console.log("CupsService: Subscription update received");
- getState();
- }
-
- function onCapabilitiesChanged() {
- checkDMSCapabilities();
- }
- }
-
- function checkDMSCapabilities() {
- if (!DMSService.isConnected)
- return;
- if (DMSService.capabilities.length === 0)
- return;
- cupsAvailable = DMSService.capabilities.includes("cups");
-
- if (cupsAvailable && !stateInitialized) {
- stateInitialized = true;
- getState();
- }
- }
-
- function getState() {
- if (!cupsAvailable)
- return;
- DMSService.sendRequest("cups.getPrinters", null, response => {
- if (response.result) {
- updatePrinters(response.result);
- fetchAllJobs();
- }
- });
- }
-
- function updatePrinters(printersData) {
- printerNames = printersData.map(p => p.name);
-
- let printersObj = {};
- for (var i = 0; i < printersData.length; i++) {
- let printer = printersData[i];
- printersObj[printer.name] = {
- "name": printer.name,
- "uri": printer.uri || "",
- "state": printer.state,
- "stateReason": printer.stateReason,
- "location": printer.location || "",
- "info": printer.info || "",
- "makeModel": printer.makeModel || "",
- "accepting": printer.accepting !== false,
- "jobs": []
- };
- }
- printers = printersObj;
-
- if (printerNames.length > 0) {
- if (selectedPrinter.length > 0) {
- if (!printerNames.includes(selectedPrinter)) {
- selectedPrinter = printerNames[0];
- }
- } else {
- selectedPrinter = printerNames[0];
- }
- }
- }
-
- function fetchAllJobs() {
- for (var i = 0; i < printerNames.length; i++) {
- fetchJobsForPrinter(printerNames[i]);
- }
- }
-
- function fetchJobsForPrinter(printerName) {
- const params = {
- "printerName": printerName
- };
-
- DMSService.sendRequest("cups.getJobs", params, response => {
- if (response.result && printers[printerName]) {
- let updatedPrinters = Object.assign({}, printers);
- updatedPrinters[printerName].jobs = response.result;
- printers = updatedPrinters;
- }
- });
- }
-
- function getSelectedPrinter() {
- return selectedPrinter;
- }
-
- function setSelectedPrinter(printerName) {
- if (printerNames.length > 0) {
- if (printerNames.includes(printerName)) {
- selectedPrinter = printerName;
- } else {
- selectedPrinter = printerNames[0];
- }
- }
- }
-
- function getPrintersNum() {
- if (!cupsAvailable)
- return 0;
-
- return printerNames.length;
- }
-
- function getPrintersNames() {
- if (!cupsAvailable)
- return [];
-
- return printerNames;
- }
-
- function getTotalJobsNum() {
- if (!cupsAvailable)
- return 0;
-
- var result = 0;
- for (var i = 0; i < printerNames.length; i++) {
- var printerName = printerNames[i];
- if (printers[printerName] && printers[printerName].jobs) {
- result += printers[printerName].jobs.length;
- }
- }
- return result;
- }
-
- function getCurrentPrinterState() {
- if (!cupsAvailable || !selectedPrinter)
- return "";
-
- var printer = printers[selectedPrinter];
- return printer.state;
- }
-
- function getCurrentPrinterStatePrettyShort() {
- if (!cupsAvailable || !selectedPrinter)
- return "";
-
- var printer = printers[selectedPrinter];
- return getPrinterStateTranslation(printer.state) + " (" + getPrinterStateReasonTranslation(printer.stateReason) + ")";
- }
-
- function getCurrentPrinterStatePretty() {
- if (!cupsAvailable || !selectedPrinter)
- return "";
-
- var printer = printers[selectedPrinter];
- return getPrinterStateTranslation(printer.state) + " (" + I18n.tr("Reason") + ": " + getPrinterStateReasonTranslation(printer.stateReason) + ")";
- }
-
- function getCurrentPrinterJobs() {
- if (!cupsAvailable || !selectedPrinter)
- return [];
-
- return getJobs(selectedPrinter);
- }
-
- function getJobs(printerName) {
- if (!cupsAvailable)
- return "";
-
- var printer = printers[printerName];
- return printer.jobs;
- }
-
- function getJobsNum(printerName) {
- if (!cupsAvailable)
- return 0;
-
- var printer = printers[printerName];
- return printer.jobs.length;
- }
-
- function pausePrinter(printerName) {
- if (!cupsAvailable)
- return;
- const params = {
- "printerName": printerName
- };
-
- DMSService.sendRequest("cups.pausePrinter", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to pause printer"), response.error);
- } else {
- getState();
- }
- });
- }
-
- function resumePrinter(printerName) {
- if (!cupsAvailable)
- return;
- const params = {
- "printerName": printerName
- };
-
- DMSService.sendRequest("cups.resumePrinter", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to resume printer"), response.error);
- } else {
- getState();
- }
- });
- }
-
- function cancelJob(printerName, jobID) {
- if (!cupsAvailable)
- return;
- const params = {
- "printerName": printerName,
- "jobID": jobID
- };
-
- DMSService.sendRequest("cups.cancelJob", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to cancel selected job"), response.error);
- } else {
- fetchJobsForPrinter(printerName);
- }
- });
- }
-
- function purgeJobs(printerName) {
- if (!cupsAvailable)
- return;
- const params = {
- "printerName": printerName
- };
-
- DMSService.sendRequest("cups.purgeJobs", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to cancel all jobs"), response.error);
- } else {
- fetchJobsForPrinter(printerName);
- }
- });
- }
-
- function getDevices() {
- if (!cupsAvailable)
- return;
- loadingDevices = true;
- DMSService.sendRequest("cups.getDevices", null, response => {
- loadingDevices = false;
- if (response.result) {
- devices = response.result;
- }
- });
- }
-
- function getPPDs() {
- if (!cupsAvailable)
- return;
- loadingPPDs = true;
- DMSService.sendRequest("cups.getPPDs", null, response => {
- loadingPPDs = false;
- if (response.result) {
- ppds = response.result;
- }
- });
- }
-
- function getClasses() {
- if (!cupsAvailable)
- return;
- loadingClasses = true;
- DMSService.sendRequest("cups.getClasses", null, response => {
- loadingClasses = false;
- if (response.result) {
- printerClasses = response.result;
- }
- });
- }
-
- function testConnection(host, port, protocol, callback) {
- if (!cupsAvailable)
- return;
- const params = {
- "host": host,
- "port": port,
- "protocol": protocol
- };
-
- DMSService.sendRequest("cups.testConnection", params, response => {
- if (callback)
- callback(response);
- });
- }
-
- function createPrinter(name, deviceURI, ppd, options) {
- if (!cupsAvailable)
- return;
- creatingPrinter = true;
- const params = {
- "name": name,
- "deviceURI": deviceURI,
- "ppd": ppd
- };
- if (options) {
- if (options.shared !== undefined)
- params.shared = options.shared;
- if (options.location)
- params.location = options.location;
- if (options.information)
- params.information = options.information;
- if (options.errorPolicy)
- params.errorPolicy = options.errorPolicy;
- }
-
- DMSService.sendRequest("cups.createPrinter", params, response => {
- creatingPrinter = false;
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to create printer"), response.error);
- } else {
- ToastService.showInfo(I18n.tr("Printer created successfully"));
- getState();
- }
- });
- }
-
- function deletePrinter(printerName) {
- if (!cupsAvailable)
- return;
- const params = {
- "printerName": printerName
- };
-
- DMSService.sendRequest("cups.deletePrinter", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to delete printer"), response.error);
- } else {
- ToastService.showInfo(I18n.tr("Printer deleted"));
- if (selectedPrinter === printerName) {
- selectedPrinter = "";
- }
- getState();
- }
- });
- }
-
- function acceptJobs(printerName) {
- if (!cupsAvailable)
- return;
- const params = {
- "printerName": printerName
- };
-
- DMSService.sendRequest("cups.acceptJobs", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to enable job acceptance"), response.error);
- } else {
- getState();
- }
- });
- }
-
- function rejectJobs(printerName) {
- if (!cupsAvailable)
- return;
- const params = {
- "printerName": printerName
- };
-
- DMSService.sendRequest("cups.rejectJobs", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to disable job acceptance"), response.error);
- } else {
- getState();
- }
- });
- }
-
- function setPrinterShared(printerName, shared) {
- if (!cupsAvailable)
- return;
- const params = {
- "printerName": printerName,
- "shared": shared
- };
-
- DMSService.sendRequest("cups.setPrinterShared", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to update sharing"), response.error);
- } else {
- getState();
- }
- });
- }
-
- function setPrinterLocation(printerName, location) {
- if (!cupsAvailable)
- return;
- const params = {
- "printerName": printerName,
- "location": location
- };
-
- DMSService.sendRequest("cups.setPrinterLocation", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to update location"), response.error);
- } else {
- getState();
- }
- });
- }
-
- function setPrinterInfo(printerName, info) {
- if (!cupsAvailable)
- return;
- const params = {
- "printerName": printerName,
- "info": info
- };
-
- DMSService.sendRequest("cups.setPrinterInfo", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to update description"), response.error);
- } else {
- getState();
- }
- });
- }
-
- function printTestPage(printerName) {
- if (!cupsAvailable)
- return;
- const params = {
- "printerName": printerName
- };
-
- DMSService.sendRequest("cups.printTestPage", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to print test page"), response.error);
- } else {
- ToastService.showInfo(I18n.tr("Test page sent to printer"));
- fetchJobsForPrinter(printerName);
- }
- });
- }
-
- function moveJob(jobID, destPrinter) {
- if (!cupsAvailable)
- return;
- const params = {
- "jobID": jobID,
- "destPrinter": destPrinter
- };
-
- DMSService.sendRequest("cups.moveJob", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to move job"), response.error);
- } else {
- fetchAllJobs();
- }
- });
- }
-
- function restartJob(jobID) {
- if (!cupsAvailable)
- return;
- const params = {
- "jobID": jobID
- };
-
- DMSService.sendRequest("cups.restartJob", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to restart job"), response.error);
- } else {
- fetchAllJobs();
- }
- });
- }
-
- function holdJob(jobID, holdUntil) {
- if (!cupsAvailable)
- return;
- const params = {
- "jobID": jobID
- };
- if (holdUntil) {
- params.holdUntil = holdUntil;
- }
-
- DMSService.sendRequest("cups.holdJob", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to hold job"), response.error);
- } else {
- fetchAllJobs();
- }
- });
- }
-
- function addPrinterToClass(className, printerName) {
- if (!cupsAvailable)
- return;
- const params = {
- "className": className,
- "printerName": printerName
- };
-
- DMSService.sendRequest("cups.addPrinterToClass", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to add printer to class"), response.error);
- } else {
- getClasses();
- }
- });
- }
-
- function removePrinterFromClass(className, printerName) {
- if (!cupsAvailable)
- return;
- const params = {
- "className": className,
- "printerName": printerName
- };
-
- DMSService.sendRequest("cups.removePrinterFromClass", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to remove printer from class"), response.error);
- } else {
- getClasses();
- }
- });
- }
-
- function deleteClass(className) {
- if (!cupsAvailable)
- return;
- const params = {
- "className": className
- };
-
- DMSService.sendRequest("cups.deleteClass", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to delete class"), response.error);
- } else {
- getClasses();
- }
- });
- }
-
- function getPrinterData(printerName) {
- if (!printers || !printers[printerName])
- return null;
- return printers[printerName];
- }
-
- function getJobStateTranslation(state) {
- switch (state) {
- case "pending":
- return I18n.tr("Pending");
- case "pending-held":
- return I18n.tr("Held");
- case "processing":
- return I18n.tr("Processing");
- case "processing-stopped":
- return I18n.tr("Stopped");
- case "canceled":
- return I18n.tr("Canceled");
- case "aborted":
- return I18n.tr("Aborted");
- case "completed":
- return I18n.tr("Completed");
- default:
- return state;
- }
- }
-
- readonly property var states: ({
- "idle": I18n.tr("Idle"),
- "processing": I18n.tr("Processing"),
- "stopped": I18n.tr("Stopped")
- })
-
- readonly property var reasonsGeneral: ({
- "none": I18n.tr("None"),
- "other": I18n.tr("Other")
- })
-
- readonly property var reasonsSupplies: ({
- "toner-low": I18n.tr("Toner Low"),
- "toner-empty": I18n.tr("Toner Empty"),
- "marker-supply-low": I18n.tr("Marker Supply Low"),
- "marker-supply-empty": I18n.tr("Marker Supply Empty"),
- "marker-waste-almost-full": I18n.tr("Marker Waste Almost Full"),
- "marker-waste-full": I18n.tr("Marker Waste Full")
- })
-
- readonly property var reasonsMedia: ({
- "media-low": I18n.tr("Media Low"),
- "media-empty": I18n.tr("Media Empty"),
- "media-needed": I18n.tr("Media Needed"),
- "media-jam": I18n.tr("Media Jam")
- })
-
- readonly property var reasonsParts: ({
- "cover-open": I18n.tr("Cover Open"),
- "door-open": I18n.tr("Door Open"),
- "interlock-open": I18n.tr("Interlock Open"),
- "output-tray-missing": I18n.tr("Output Tray Missing"),
- "output-area-almost-full": I18n.tr("Output Area Almost Full"),
- "output-area-full": I18n.tr("Output Area Full")
- })
-
- readonly property var reasonsErrors: ({
- "paused": I18n.tr("Paused"),
- "shutdown": I18n.tr("Shutdown"),
- "connecting-to-device": I18n.tr("Connecting to Device"),
- "timed-out": I18n.tr("Timed Out"),
- "stopping": I18n.tr("Stopping"),
- "stopped-partly": I18n.tr("Stopped Partly")
- })
-
- readonly property var reasonsService: ({
- "spool-area-full": I18n.tr("Spool Area Full"),
- "cups-missing-filter-warning": I18n.tr("CUPS Missing Filter Warning"),
- "cups-insecure-filter-warning": I18n.tr("CUPS Insecure Filter Warning")
- })
-
- readonly property var reasonsConnectivity: ({
- "offline-report": I18n.tr("Offline Report"),
- "moving-to-paused": I18n.tr("Moving to Paused")
- })
-
- readonly property var severitySuffixes: ({
- "-error": I18n.tr("Error"),
- "-warning": I18n.tr("Warning"),
- "-report": I18n.tr("Report")
- })
-
- function getPrinterStateTranslation(state) {
- return states[state] || state;
- }
-
- function getPrinterStateReasonTranslation(reason) {
- let allReasons = Object.assign({}, reasonsGeneral, reasonsSupplies, reasonsMedia, reasonsParts, reasonsErrors, reasonsService, reasonsConnectivity);
-
- let basReason = reason;
- let suffix = "";
-
- for (let s in severitySuffixes) {
- if (reason.endsWith(s)) {
- basReason = reason.slice(0, -s.length);
- suffix = severitySuffixes[s];
- break;
- }
- }
-
- let translation = allReasons[basReason] || basReason;
- return suffix ? translation + " (" + suffix + ")" : translation;
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DMSNetworkService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DMSNetworkService.qml
deleted file mode 100644
index e234cf4..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DMSNetworkService.qml
+++ /dev/null
@@ -1,944 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import qs.Common
-
-Singleton {
- id: root
-
- property bool networkAvailable: false
- property string backend: ""
-
- property string networkStatus: "disconnected"
- property string primaryConnection: ""
-
- property string ethernetIP: ""
- property string ethernetInterface: ""
- property bool ethernetConnected: false
- property string ethernetConnectionUuid: ""
- property var ethernetDevices: []
-
- property var wiredConnections: []
-
- property string wifiIP: ""
- property string wifiInterface: ""
- property bool wifiConnected: false
- property bool wifiEnabled: true
- property string wifiConnectionUuid: ""
- property string wifiDevicePath: ""
- property string activeAccessPointPath: ""
- property var wifiDevices: []
- property string wifiDeviceOverride: SessionData.wifiDeviceOverride || ""
- property string connectingDevice: ""
-
- property string currentWifiSSID: ""
- property int wifiSignalStrength: 0
- property var wifiNetworks: []
- property var savedConnections: []
- property var ssidToConnectionName: ({})
- property var wifiSignalIcon: {
- if (!wifiConnected) {
- return "wifi_off";
- }
- if (wifiSignalStrength >= 50) {
- return "wifi";
- }
- if (wifiSignalStrength >= 25) {
- return "wifi_2_bar";
- }
- return "wifi_1_bar";
- }
-
- property string userPreference: "auto"
- property bool isConnecting: false
- property string connectingSSID: ""
- property string connectionError: ""
-
- property bool isScanning: false
- property bool autoScan: false
-
- property bool wifiAvailable: true
- property bool wifiToggling: false
- property bool changingPreference: false
- property string targetPreference: ""
- property var savedWifiNetworks: []
- property string connectionStatus: ""
- property string lastConnectionError: ""
- property bool passwordDialogShouldReopen: false
- property bool autoRefreshEnabled: false
- property string wifiPassword: ""
- property string forgetSSID: ""
-
- property var vpnProfiles: []
- property var vpnActive: []
- property bool vpnAvailable: false
- property bool vpnIsBusy: false
- property string lastConnectedVpnUuid: ""
- property string pendingVpnUuid: ""
- property var vpnBusyStartTime: 0
-
- property alias profiles: root.vpnProfiles
- property alias activeConnections: root.vpnActive
- property var activeUuids: vpnActive.map(v => v.uuid).filter(u => !!u)
- property var activeNames: vpnActive.map(v => v.name).filter(n => !!n)
- property string activeUuid: activeUuids.length > 0 ? activeUuids[0] : ""
- property string activeName: activeNames.length > 0 ? activeNames[0] : ""
- property string activeDevice: vpnActive.length > 0 ? (vpnActive[0].device || "") : ""
- property string activeState: vpnActive.length > 0 ? (vpnActive[0].state || "") : ""
- property bool vpnConnected: activeUuids.length > 0
- property alias available: root.vpnAvailable
- property alias isBusy: root.vpnIsBusy
- property alias connected: root.vpnConnected
-
- property string networkInfoSSID: ""
- property string networkInfoDetails: ""
- property bool networkInfoLoading: false
-
- property string networkWiredInfoUUID: ""
- property string networkWiredInfoDetails: ""
- property bool networkWiredInfoLoading: false
-
- property int refCount: 0
- property bool stateInitialized: false
-
- property string credentialsToken: ""
- property string credentialsSSID: ""
- property string credentialsSetting: ""
- property var credentialsFields: []
- property var credentialsHints: []
- property string credentialsReason: ""
- property bool credentialsRequested: false
-
- property string pendingConnectionSSID: ""
- property var pendingConnectionStartTime: 0
- property bool wasConnecting: false
-
- signal networksUpdated
- signal connectionChanged
- signal credentialsNeeded(string token, string ssid, string setting, var fields, var hints, string reason, string connType, string connName, string vpnService, var fieldsInfo)
-
- readonly property string socketPath: Quickshell.env("DMS_SOCKET")
-
- readonly property string effectiveWifiDevice: {
- if (!wifiDeviceOverride)
- return "";
- const deviceExists = wifiDevices.some(d => d.name === wifiDeviceOverride);
- return deviceExists ? wifiDeviceOverride : "";
- }
-
- Component.onCompleted: {
- root.userPreference = SettingsData.networkPreference;
- lastConnectedVpnUuid = SessionData.vpnLastConnected || "";
- if (socketPath && socketPath.length > 0) {
- checkDMSCapabilities();
- }
- }
-
- Connections {
- target: DMSService
-
- function onNetworkStateUpdate(data) {
- const networksCount = data.wifiNetworks?.length ?? "null";
- console.log("DMSNetworkService: Subscription update received, networks:", networksCount);
- updateState(data);
- }
- }
-
- Connections {
- target: DMSService
-
- function onConnectionStateChanged() {
- if (DMSService.isConnected) {
- checkDMSCapabilities();
- }
- }
- }
-
- Connections {
- target: DMSService
- enabled: DMSService.isConnected
-
- function onCapabilitiesChanged() {
- checkDMSCapabilities();
- }
-
- function onCredentialsRequest(data) {
- handleCredentialsRequest(data);
- }
- }
-
- function checkDMSCapabilities() {
- if (!DMSService.isConnected) {
- return;
- }
-
- if (DMSService.capabilities.length === 0) {
- return;
- }
-
- networkAvailable = DMSService.capabilities.includes("network");
-
- if (networkAvailable && !stateInitialized) {
- stateInitialized = true;
- getState();
- }
- }
-
- function handleCredentialsRequest(data) {
- credentialsToken = data.token || "";
- credentialsSSID = data.ssid || "";
- credentialsSetting = data.setting || "802-11-wireless-security";
- credentialsFields = data.fields || ["psk"];
- credentialsHints = data.hints || [];
- credentialsReason = data.reason || "Credentials required";
- credentialsRequested = true;
-
- const connType = data.connType || "";
- const connName = data.name || data.connectionId || "";
- const vpnService = data.vpnService || "";
- const fInfo = data.fieldsInfo || [];
-
- credentialsNeeded(credentialsToken, credentialsSSID, credentialsSetting, credentialsFields, credentialsHints, credentialsReason, connType, connName, vpnService, fInfo);
- }
-
- function addRef() {
- refCount++;
- if (refCount === 1 && networkAvailable) {
- startAutoScan();
- }
- }
-
- function removeRef() {
- refCount = Math.max(0, refCount - 1);
- if (refCount === 0) {
- stopAutoScan();
- }
- }
-
- property bool initialStateFetched: false
-
- function getState() {
- if (!networkAvailable)
- return;
- DMSService.sendRequest("network.getState", null, response => {
- if (response.result) {
- updateState(response.result);
- if (!initialStateFetched && response.result.wifiEnabled && (!response.result.wifiNetworks || response.result.wifiNetworks.length === 0)) {
- initialStateFetched = true;
- Qt.callLater(() => scanWifi());
- }
- }
- });
- }
-
- function updateState(state) {
- const previousConnecting = isConnecting;
- const previousConnectingSSID = connectingSSID;
-
- backend = state.backend || "";
- vpnAvailable = networkAvailable && backend === "networkmanager";
- networkStatus = state.networkStatus || "disconnected";
- primaryConnection = state.primaryConnection || "";
-
- ethernetIP = state.ethernetIP || "";
- ethernetInterface = state.ethernetDevice || "";
- ethernetConnected = state.ethernetConnected || false;
- ethernetConnectionUuid = state.ethernetConnectionUuid || "";
- ethernetDevices = state.ethernetDevices || [];
-
- wiredConnections = state.wiredConnections || [];
-
- wifiIP = state.wifiIP || "";
- wifiInterface = state.wifiDevice || "";
- wifiConnected = state.wifiConnected || false;
- wifiEnabled = state.wifiEnabled !== undefined ? state.wifiEnabled : true;
- wifiConnectionUuid = state.wifiConnectionUuid || "";
- wifiDevicePath = state.wifiDevicePath || "";
- activeAccessPointPath = state.activeAccessPointPath || "";
- wifiDevices = state.wifiDevices || [];
- connectingDevice = state.connectingDevice || "";
-
- currentWifiSSID = state.wifiSSID || "";
- wifiSignalStrength = state.wifiSignal || 0;
-
- if (state.wifiNetworks) {
- wifiNetworks = state.wifiNetworks;
-
- const saved = [];
- const mapping = {};
- for (const network of state.wifiNetworks) {
- if (network.saved) {
- saved.push({
- ssid: network.ssid,
- saved: true
- });
- mapping[network.ssid] = network.ssid;
- }
- }
- savedConnections = saved;
- savedWifiNetworks = saved;
- ssidToConnectionName = mapping;
-
- networksUpdated();
- }
-
- if (state.vpnProfiles) {
- vpnProfiles = state.vpnProfiles;
- }
-
- const previousVpnActive = vpnActive;
- vpnActive = state.vpnActive || [];
-
- if (vpnConnected && activeUuid) {
- lastConnectedVpnUuid = activeUuid;
- SessionData.setVpnLastConnected(activeUuid);
- }
-
- if (vpnIsBusy) {
- const busyDuration = Date.now() - vpnBusyStartTime;
- const timeout = 30000;
-
- if (busyDuration > timeout) {
- console.warn("DMSNetworkService: VPN operation timed out after", timeout, "ms");
- vpnIsBusy = false;
- pendingVpnUuid = "";
- vpnBusyStartTime = 0;
- } else if (pendingVpnUuid) {
- const isPendingVpnActive = activeUuids.includes(pendingVpnUuid);
- if (isPendingVpnActive) {
- vpnIsBusy = false;
- pendingVpnUuid = "";
- vpnBusyStartTime = 0;
- }
- } else {
- const previousCount = previousVpnActive ? previousVpnActive.length : 0;
- const currentCount = vpnActive ? vpnActive.length : 0;
-
- if (previousCount !== currentCount) {
- vpnIsBusy = false;
- vpnBusyStartTime = 0;
- }
- }
- }
-
- isConnecting = state.isConnecting || false;
- connectingSSID = state.connectingSSID || "";
- connectionError = state.lastError || "";
- lastConnectionError = state.lastError || "";
-
- if (pendingConnectionSSID) {
- if (wifiConnected && currentWifiSSID === pendingConnectionSSID && wifiIP) {
- const elapsed = Date.now() - pendingConnectionStartTime;
- console.info("DMSNetworkService: Successfully connected to", pendingConnectionSSID, "in", elapsed, "ms");
- ToastService.showInfo(`Connected to ${pendingConnectionSSID}`);
-
- if (userPreference === "wifi" || userPreference === "auto") {
- setConnectionPriority("wifi");
- }
-
- pendingConnectionSSID = "";
- connectionStatus = "connected";
- } else if (previousConnecting && !isConnecting && !wifiConnected) {
- const isCancellationError = connectionError === "user-canceled";
- const isBadCredentials = connectionError === "bad-credentials";
-
- if (isCancellationError) {
- connectionStatus = "cancelled";
- pendingConnectionSSID = "";
- } else if (isBadCredentials) {
- connectionStatus = "invalid_password";
- pendingConnectionSSID = "";
- } else {
- if (connectionError) {
- ToastService.showError(I18n.tr("Failed to connect to %1").arg(pendingConnectionSSID));
- }
- connectionStatus = "failed";
- pendingConnectionSSID = "";
- }
- }
- }
-
- wasConnecting = isConnecting;
-
- connectionChanged();
- }
-
- function connectToSpecificWiredConfig(uuid) {
- if (!networkAvailable || isConnecting)
- return;
- isConnecting = true;
- connectionError = "";
- connectionStatus = "connecting";
-
- const params = {
- uuid: uuid
- };
-
- DMSService.sendRequest("network.ethernet.connect.config", params, response => {
- if (response.error) {
- connectionError = response.error;
- lastConnectionError = response.error;
- connectionStatus = "failed";
- ToastService.showError(I18n.tr("Failed to activate configuration"), response.error);
- } else {
- connectionError = "";
- connectionStatus = "connected";
- ToastService.showInfo(I18n.tr("Configuration activated"));
- }
-
- isConnecting = false;
- });
- }
-
- function scanWifi() {
- if (!networkAvailable || isScanning || !wifiEnabled)
- return;
- isScanning = true;
- const params = effectiveWifiDevice ? {
- device: effectiveWifiDevice
- } : null;
- DMSService.sendRequest("network.wifi.scan", params, response => {
- isScanning = false;
- if (response.error) {
- console.warn("DMSNetworkService: WiFi scan failed:", response.error);
- } else {
- Qt.callLater(() => getState());
- }
- });
- }
-
- function scanWifiNetworks() {
- scanWifi();
- }
-
- function connectToWifi(ssid, password = "", username = "", anonymousIdentity = "", domainSuffixMatch = "", hidden = false) {
- if (!networkAvailable || isConnecting)
- return;
- pendingConnectionSSID = ssid;
- pendingConnectionStartTime = Date.now();
- connectionError = "";
- connectionStatus = "connecting";
- credentialsRequested = false;
-
- const params = {
- ssid: ssid
- };
- if (effectiveWifiDevice)
- params.device = effectiveWifiDevice;
- if (hidden)
- params.hidden = true;
-
- if (DMSService.apiVersion >= 7) {
- if (password || username) {
- params.password = password;
- if (username)
- params.username = username;
- if (anonymousIdentity)
- params.anonymousIdentity = anonymousIdentity;
- if (domainSuffixMatch)
- params.domainSuffixMatch = domainSuffixMatch;
- params.interactive = false;
- } else {
- params.interactive = true;
- }
- } else {
- if (password)
- params.password = password;
- if (username)
- params.username = username;
- if (anonymousIdentity)
- params.anonymousIdentity = anonymousIdentity;
- if (domainSuffixMatch)
- params.domainSuffixMatch = domainSuffixMatch;
- }
-
- DMSService.sendRequest("network.wifi.connect", params, response => {
- if (response.error) {
- if (connectionStatus === "cancelled")
- return;
- connectionError = response.error;
- lastConnectionError = response.error;
- pendingConnectionSSID = "";
- connectionStatus = "failed";
- ToastService.showError(I18n.tr("Failed to start connection to %1").arg(ssid));
- }
- });
- }
-
- function disconnectWifi() {
- if (!networkAvailable || !wifiInterface)
- return;
- const params = effectiveWifiDevice ? {
- device: effectiveWifiDevice
- } : null;
- DMSService.sendRequest("network.wifi.disconnect", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to disconnect WiFi"), response.error);
- } else {
- ToastService.showInfo(I18n.tr("Disconnected from WiFi"));
- currentWifiSSID = "";
- connectionStatus = "";
- }
- });
- }
-
- function submitCredentials(token, secrets, save) {
- console.log("submitCredentials: networkAvailable=" + networkAvailable + " apiVersion=" + DMSService.apiVersion);
-
- if (!networkAvailable || DMSService.apiVersion < 7) {
- console.warn("submitCredentials: Aborting - networkAvailable=" + networkAvailable + " apiVersion=" + DMSService.apiVersion);
- return;
- }
-
- const params = {
- token: token,
- secrets: secrets,
- save: save || false
- };
-
- credentialsRequested = false;
-
- DMSService.sendRequest("network.credentials.submit", params, response => {
- if (response.error) {
- console.warn("DMSNetworkService: Failed to submit credentials:", response.error);
- }
- });
- }
-
- function cancelCredentials(token) {
- if (!networkAvailable || DMSService.apiVersion < 7)
- return;
- const params = {
- token: token
- };
-
- credentialsRequested = false;
- pendingConnectionSSID = "";
- connectionStatus = "cancelled";
-
- DMSService.sendRequest("network.credentials.cancel", params, response => {
- if (response.error) {
- console.warn("DMSNetworkService: Failed to cancel credentials:", response.error);
- }
- });
- }
-
- function forgetWifiNetwork(ssid) {
- if (!networkAvailable)
- return;
- forgetSSID = ssid;
- DMSService.sendRequest("network.wifi.forget", {
- ssid: ssid
- }, response => {
- if (response.error) {
- console.warn("Failed to forget network:", response.error);
- } else {
- ToastService.showInfo(I18n.tr("Forgot network %1").arg(ssid));
-
- savedConnections = savedConnections.filter(s => s.ssid !== ssid);
- savedWifiNetworks = savedWifiNetworks.filter(s => s.ssid !== ssid);
-
- const updated = [...wifiNetworks];
- for (const network of updated) {
- if (network.ssid === ssid) {
- network.saved = false;
- if (network.connected) {
- network.connected = false;
- currentWifiSSID = "";
- }
- }
- }
- wifiNetworks = updated;
- networksUpdated();
- }
- forgetSSID = "";
- });
- }
-
- function toggleWifiRadio() {
- if (!networkAvailable || wifiToggling)
- return;
- wifiToggling = true;
- DMSService.sendRequest("network.wifi.toggle", null, response => {
- wifiToggling = false;
-
- if (response.error) {
- console.warn("Failed to toggle WiFi:", response.error);
- } else if (response.result) {
- wifiEnabled = response.result.enabled;
- ToastService.showInfo(wifiEnabled ? I18n.tr("WiFi enabled") : I18n.tr("WiFi disabled"));
- }
- });
- }
-
- function enableWifiDevice() {
- if (!networkAvailable)
- return;
- DMSService.sendRequest("network.wifi.enable", null, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to enable WiFi"), response.error);
- } else {
- ToastService.showInfo(I18n.tr("WiFi enabled"));
- }
- });
- }
-
- function setNetworkPreference(preference) {
- if (!networkAvailable)
- return;
- userPreference = preference;
- changingPreference = true;
- targetPreference = preference;
- SettingsData.set("networkPreference", preference);
-
- DMSService.sendRequest("network.preference.set", {
- preference: preference
- }, response => {
- changingPreference = false;
- targetPreference = "";
-
- if (response.error) {
- console.warn("Failed to set network preference:", response.error);
- }
- });
- }
-
- function setConnectionPriority(type) {
- if (type === "wifi") {
- setNetworkPreference("wifi");
- } else if (type === "ethernet") {
- setNetworkPreference("ethernet");
- }
- }
-
- function connectToWifiAndSetPreference(ssid, password, username = "", anonymousIdentity = "", domainSuffixMatch = "", hidden = false) {
- connectToWifi(ssid, password, username, anonymousIdentity, domainSuffixMatch, hidden);
- setNetworkPreference("wifi");
- }
-
- function toggleNetworkConnection(type) {
- if (!networkAvailable)
- return;
- if (type === "ethernet") {
- if (ethernetConnected) {
- DMSService.sendRequest("network.ethernet.disconnect", null, null);
- } else {
- DMSService.sendRequest("network.ethernet.connect", null, null);
- }
- }
- }
-
- function disconnectEthernetDevice(deviceName) {
- if (!networkAvailable)
- return;
- DMSService.sendRequest("network.ethernet.disconnect", {
- device: deviceName
- }, null);
- }
-
- function startAutoScan() {
- autoScan = true;
- autoRefreshEnabled = true;
- if (networkAvailable && wifiEnabled) {
- scanWifi();
- }
- }
-
- function stopAutoScan() {
- autoScan = false;
- autoRefreshEnabled = false;
- }
-
- function fetchWiredNetworkInfo(uuid) {
- if (!networkAvailable)
- return;
- networkWiredInfoUUID = uuid;
- networkWiredInfoLoading = true;
- networkWiredInfoDetails = "Loading network information...";
-
- DMSService.sendRequest("network.ethernet.info", {
- uuid: uuid
- }, response => {
- networkWiredInfoLoading = false;
-
- if (response.error) {
- networkWiredInfoDetails = "Failed to fetch network information";
- } else if (response.result) {
- formatWiredNetworkInfo(response.result);
- }
- });
- }
-
- function formatWiredNetworkInfo(info) {
- let details = "";
-
- if (!info) {
- details = "Network information not found or network not available.";
- } else {
- details += "Interface: " + info.iface + "\\n";
- details += "Driver: " + info.driver + "\\n";
- details += "MAC Addr: " + info.hwAddr + "\\n";
- details += "Speed: " + info.speed + " Mb/s\\n\\n";
-
- details += "IPv4 information:\\n";
-
- for (const ip4 of info.IPv4s.ips) {
- details += " IPv4 address: " + ip4 + "\\n";
- }
- details += " Gateway: " + info.IPv4s.gateway + "\\n";
- details += " DNS: " + info.IPv4s.dns + "\\n";
-
- if (info.IPv6s.ips) {
- details += "\\nIPv6 information:\\n";
-
- for (const ip6 of info.IPv6s.ips) {
- details += " IPv6 address: " + ip6 + "\\n";
- }
- if (info.IPv6s.gateway.length > 0) {
- details += " Gateway: " + info.IPv6s.gateway + "\\n";
- }
- if (info.IPv6s.dns.length > 0) {
- details += " DNS: " + info.IPv6s.dns + "\\n";
- }
- }
- }
-
- networkWiredInfoDetails = details;
- }
-
- function fetchNetworkInfo(ssid) {
- if (!networkAvailable)
- return;
- networkInfoSSID = ssid;
- networkInfoLoading = true;
- networkInfoDetails = "Loading network information...";
-
- DMSService.sendRequest("network.info", {
- ssid: ssid
- }, response => {
- networkInfoLoading = false;
-
- if (response.error) {
- networkInfoDetails = "Failed to fetch network information";
- } else if (response.result) {
- formatNetworkInfo(response.result);
- }
- });
- }
-
- function formatNetworkInfo(info) {
- let details = "";
-
- if (!info || !info.bands || info.bands.length === 0) {
- details = "Network information not found or network not available.";
- } else {
- for (const band of info.bands) {
- const freqGHz = band.frequency / 1000;
- let bandName = "Unknown";
- if (band.frequency >= 2400 && band.frequency <= 2500) {
- bandName = "2.4 GHz";
- } else if (band.frequency >= 5000 && band.frequency <= 6000) {
- bandName = "5 GHz";
- } else if (band.frequency >= 6000) {
- bandName = "6 GHz";
- }
-
- const statusPrefix = band.connected ? "● " : " ";
- const statusSuffix = band.connected ? " (Connected)" : "";
-
- details += statusPrefix + bandName + statusSuffix + " - " + band.signal + "%\\n";
- details += " Channel " + band.channel + " (" + freqGHz.toFixed(1) + " GHz) • " + band.rate + " Mbit/s\\n";
- details += " BSSID: " + band.bssid + "\\n";
- details += " Mode: " + band.mode + "\\n";
- details += " Security: " + (band.secured ? "Secured" : "Open") + "\\n";
- if (band.saved) {
- details += " Status: Saved network\\n";
- }
- details += "\\n";
- }
- }
-
- networkInfoDetails = details;
- }
-
- function getNetworkInfo(ssid) {
- const network = wifiNetworks.find(n => n.ssid === ssid);
- if (!network) {
- return null;
- }
-
- return {
- "ssid": network.ssid,
- "signal": network.signal,
- "secured": network.secured,
- "saved": network.saved,
- "connected": network.connected,
- "bssid": network.bssid
- };
- }
-
- function getWiredNetworkInfo(uuid) {
- const network = wiredConnections.find(n => n.uuid === uuid);
- if (!network) {
- return null;
- }
-
- return {
- "uuid": uuid
- };
- }
-
- function refreshVpnProfiles() {
- if (!vpnAvailable)
- return;
- DMSService.sendRequest("network.vpn.profiles", null, response => {
- if (response.result) {
- vpnProfiles = response.result;
- }
- });
- }
-
- function refreshVpnActive() {
- if (!vpnAvailable)
- return;
- DMSService.sendRequest("network.vpn.active", null, response => {
- if (response.result) {
- vpnActive = response.result;
- }
- });
- }
-
- function connectVpn(uuidOrName, singleActive = false) {
- if (!vpnAvailable || vpnIsBusy)
- return;
- vpnIsBusy = true;
- pendingVpnUuid = uuidOrName;
- vpnBusyStartTime = Date.now();
-
- const params = {
- uuidOrName: uuidOrName,
- singleActive: singleActive
- };
-
- DMSService.sendRequest("network.vpn.connect", params, response => {
- if (response.error) {
- vpnIsBusy = false;
- pendingVpnUuid = "";
- vpnBusyStartTime = 0;
- ToastService.showError(I18n.tr("Failed to connect VPN"), response.error);
- }
- });
- }
-
- function connect(uuidOrName, singleActive = false) {
- connectVpn(uuidOrName, singleActive);
- }
-
- function disconnectVpn(uuidOrName) {
- if (!vpnAvailable || vpnIsBusy)
- return;
- vpnIsBusy = true;
- pendingVpnUuid = "";
- vpnBusyStartTime = Date.now();
-
- const params = {
- uuidOrName: uuidOrName
- };
-
- DMSService.sendRequest("network.vpn.disconnect", params, response => {
- if (response.error) {
- vpnIsBusy = false;
- vpnBusyStartTime = 0;
- ToastService.showError(I18n.tr("Failed to disconnect VPN"), response.error);
- }
- });
- }
-
- function disconnect(uuidOrName) {
- disconnectVpn(uuidOrName);
- }
-
- function disconnectAllVpns() {
- if (!vpnAvailable || vpnIsBusy)
- return;
- vpnIsBusy = true;
- pendingVpnUuid = "";
-
- DMSService.sendRequest("network.vpn.disconnectAll", null, response => {
- if (response.error) {
- vpnIsBusy = false;
- ToastService.showError(I18n.tr("Failed to disconnect VPNs"), response.error);
- }
- });
- }
-
- function disconnectAllActive() {
- disconnectAllVpns();
- }
-
- function toggleVpn(uuid) {
- if (uuid) {
- if (isActiveVpnUuid(uuid)) {
- disconnectVpn(uuid);
- } else {
- connectVpn(uuid);
- }
- return;
- }
-
- if (vpnConnected) {
- disconnectAllVpns();
- return;
- }
-
- const targetUuid = lastConnectedVpnUuid || (vpnProfiles.length > 0 ? vpnProfiles[0].uuid : "");
- if (targetUuid) {
- connectVpn(targetUuid);
- }
- }
-
- function toggle(uuid) {
- toggleVpn(uuid);
- }
-
- function isActiveVpnUuid(uuid) {
- return activeUuids && activeUuids.indexOf(uuid) !== -1;
- }
-
- function isActiveUuid(uuid) {
- return isActiveVpnUuid(uuid);
- }
-
- function refreshNetworkState() {
- if (networkAvailable) {
- getState();
- }
- }
-
- function setWifiDeviceOverride(deviceName) {
- SessionData.setWifiDeviceOverride(deviceName || "");
- if (networkAvailable && wifiEnabled) {
- scanWifi();
- }
- }
-
- function setWifiAutoconnect(ssid, autoconnect) {
- if (!networkAvailable || DMSService.apiVersion <= 13)
- return;
- const params = {
- ssid: ssid,
- autoconnect: autoconnect
- };
-
- DMSService.sendRequest("network.wifi.setAutoconnect", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to update autoconnect"), response.error);
- } else {
- ToastService.showInfo(autoconnect ? I18n.tr("Autoconnect enabled") : I18n.tr("Autoconnect disabled"));
- Qt.callLater(() => getState());
- }
- });
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DMSService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DMSService.qml
deleted file mode 100644
index 217b96a..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DMSService.qml
+++ /dev/null
@@ -1,757 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- property bool dmsAvailable: false
- property var capabilities: []
- property int apiVersion: 0
- property string cliVersion: ""
- readonly property int expectedApiVersion: 1
- property var availablePlugins: []
- property var installedPlugins: []
- property var availableThemes: []
- property var installedThemes: []
- property bool isConnected: false
- property bool isConnecting: false
- property bool subscribeConnected: false
- readonly property bool forceExtWorkspace: false
-
- readonly property string socketPath: Quickshell.env("DMS_SOCKET")
-
- property var pendingRequests: ({})
- property var clipboardRequestIds: ({})
- property int requestIdCounter: 0
- property bool shownOutdatedError: false
- property string updateCommand: "dms update"
- property bool checkingUpdateCommand: false
-
- signal pluginsListReceived(var plugins)
- signal installedPluginsReceived(var plugins)
- signal searchResultsReceived(var plugins)
- signal themesListReceived(var themes)
- signal installedThemesReceived(var themes)
- signal themeSearchResultsReceived(var themes)
- signal operationSuccess(string message)
- signal operationError(string error)
- signal connectionStateChanged
-
- signal networkStateUpdate(var data)
- signal cupsStateUpdate(var data)
- signal loginctlStateUpdate(var data)
- signal loginctlEvent(var event)
- signal capabilitiesReceived
- signal credentialsRequest(var data)
- signal bluetoothPairingRequest(var data)
- signal dwlStateUpdate(var data)
- signal brightnessStateUpdate(var data)
- signal brightnessDeviceUpdate(var device)
- signal extWorkspaceStateUpdate(var data)
- signal wlrOutputStateUpdate(var data)
- signal evdevStateUpdate(var data)
- signal gammaStateUpdate(var data)
- signal themeAutoStateUpdate(var data)
- signal openUrlRequested(string url)
- signal appPickerRequested(var data)
- signal screensaverStateUpdate(var data)
- signal clipboardStateUpdate(var data)
- signal locationStateUpdate(var data)
-
- property bool capsLockState: false
- property bool screensaverInhibited: false
- property var screensaverInhibitors: []
-
- property var activeSubscriptions: ["network", "network.credentials", "loginctl", "freedesktop", "freedesktop.screensaver", "gamma", "theme.auto", "bluetooth", "bluetooth.pairing", "dwl", "brightness", "wlroutput", "evdev", "browser", "dbus", "clipboard", "location"]
-
- Component.onCompleted: {
- if (socketPath && socketPath.length > 0) {
- detectUpdateCommand();
- }
- }
-
- function detectUpdateCommand() {
- checkingUpdateCommand = true;
- checkAurHelper.running = true;
- }
-
- function startSocketConnection() {
- if (socketPath && socketPath.length > 0) {
- testProcess.running = true;
- }
- }
-
- Process {
- id: checkAurHelper
- command: ["sh", "-c", "command -v paru || command -v yay"]
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const helper = text.trim();
- if (helper.includes("paru")) {
- checkDmsPackage.helper = "paru";
- checkDmsPackage.running = true;
- } else if (helper.includes("yay")) {
- checkDmsPackage.helper = "yay";
- checkDmsPackage.running = true;
- } else {
- updateCommand = "dms update";
- checkingUpdateCommand = false;
- startSocketConnection();
- }
- }
- }
-
- onExited: exitCode => {
- if (exitCode !== 0) {
- updateCommand = "dms update";
- checkingUpdateCommand = false;
- startSocketConnection();
- }
- }
- }
-
- Process {
- id: checkDmsPackage
- property string helper: ""
- command: ["sh", "-c", "pacman -Qi dms-shell-git 2>/dev/null || pacman -Qi dms-shell-bin 2>/dev/null"]
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- if (text.includes("dms-shell-git")) {
- updateCommand = checkDmsPackage.helper + " -S dms-shell-git";
- } else if (text.includes("dms-shell-bin")) {
- updateCommand = checkDmsPackage.helper + " -S dms-shell-bin";
- } else {
- updateCommand = "dms update";
- }
- checkingUpdateCommand = false;
- startSocketConnection();
- }
- }
-
- onExited: exitCode => {
- if (exitCode !== 0) {
- updateCommand = "dms update";
- checkingUpdateCommand = false;
- startSocketConnection();
- }
- }
- }
-
- Process {
- id: testProcess
- command: ["test", "-S", root.socketPath]
-
- onExited: exitCode => {
- if (exitCode === 0) {
- root.dmsAvailable = true;
- connectSocket();
- } else {
- root.dmsAvailable = false;
- }
- }
- }
-
- function connectSocket() {
- if (!dmsAvailable || isConnected || isConnecting) {
- return;
- }
-
- isConnecting = true;
- requestSocket.connected = true;
- }
-
- DankSocket {
- id: requestSocket
- path: root.socketPath
- connected: false
-
- onConnectionStateChanged: {
- if (connected) {
- root.isConnected = true;
- root.isConnecting = false;
- root.connectionStateChanged();
- subscribeSocket.connected = true;
- } else {
- root.isConnected = false;
- root.isConnecting = false;
- root.apiVersion = 0;
- root.capabilities = [];
- root.connectionStateChanged();
- }
- }
-
- parser: SplitParser {
- onRead: line => {
- if (!line || line.length === 0)
- return;
-
- let response;
- try {
- response = JSON.parse(line);
- } catch (e) {
- console.warn("DMSService: Failed to parse request response:", line.substring(0, 100));
- return;
- }
- const isClipboard = clipboardRequestIds[response.id];
- if (isClipboard)
- delete clipboardRequestIds[response.id];
- else
- console.log("DMSService: Request socket <<", line);
- handleResponse(response);
- }
- }
- }
-
- DankSocket {
- id: subscribeSocket
- path: root.socketPath
- connected: false
-
- onConnectionStateChanged: {
- root.subscribeConnected = connected;
- if (connected) {
- sendSubscribeRequest();
- }
- }
-
- parser: SplitParser {
- onRead: line => {
- if (!line || line.length === 0)
- return;
-
- let response;
- try {
- response = JSON.parse(line);
- } catch (e) {
- console.warn("DMSService: Failed to parse subscription event:", line.substring(0, 100));
- return;
- }
- if (!line.includes("clipboard"))
- console.log("DMSService: Subscribe socket <<", line);
- handleSubscriptionEvent(response);
- }
- }
- }
-
- function sendSubscribeRequest() {
- const request = {
- "method": "subscribe"
- };
-
- if (activeSubscriptions.length > 0) {
- request.params = {
- "services": activeSubscriptions
- };
- console.log("DMSService: Subscribing to services:", JSON.stringify(activeSubscriptions));
- } else {
- console.log("DMSService: Subscribing to all services");
- }
-
- subscribeSocket.send(request);
- }
-
- function subscribe(services) {
- if (!Array.isArray(services)) {
- services = [services];
- }
-
- activeSubscriptions = services;
-
- if (subscribeConnected) {
- subscribeSocket.connected = false;
- Qt.callLater(() => {
- subscribeSocket.connected = true;
- });
- }
- }
-
- function addSubscription(service) {
- if (activeSubscriptions.includes("all"))
- return;
- if (!activeSubscriptions.includes(service)) {
- const newSubs = [...activeSubscriptions, service];
- subscribe(newSubs);
- }
- }
-
- function removeSubscription(service) {
- if (activeSubscriptions.includes("all")) {
- const allServices = ["network", "loginctl", "freedesktop", "gamma", "bluetooth", "dwl", "brightness", "extworkspace", "browser", "location"];
- const filtered = allServices.filter(s => s !== service);
- subscribe(filtered);
- } else {
- const filtered = activeSubscriptions.filter(s => s !== service);
- if (filtered.length === 0) {
- console.warn("DMSService: Cannot remove last subscription");
- return;
- }
- subscribe(filtered);
- }
- }
-
- function subscribeAll() {
- subscribe(["all"]);
- }
-
- function subscribeAllExcept(excludeServices) {
- if (!Array.isArray(excludeServices)) {
- excludeServices = [excludeServices];
- }
-
- const allServices = ["network", "loginctl", "freedesktop", "gamma", "theme.auto", "bluetooth", "cups", "dwl", "brightness", "extworkspace", "browser", "dbus", "location"];
- const filtered = allServices.filter(s => !excludeServices.includes(s));
- subscribe(filtered);
- }
-
- function handleSubscriptionEvent(response) {
- if (response.error) {
- if (response.error.includes("unknown method") && response.error.includes("subscribe")) {
- if (!shownOutdatedError) {
- console.error("DMSService: Server does not support subscribe method");
- ToastService.showError(I18n.tr("DMS out of date"), I18n.tr("To update, run the following command:"), updateCommand);
- shownOutdatedError = true;
- }
- }
- return;
- }
-
- if (!response.result) {
- return;
- }
-
- const service = response.result.service;
- const data = response.result.data;
-
- if (service === "server") {
- apiVersion = data.apiVersion || 0;
- cliVersion = data.cliVersion || "";
- capabilities = data.capabilities || [];
-
- console.info("DMSService: Connected (API v" + apiVersion + ", CLI " + cliVersion + ") -", JSON.stringify(capabilities));
-
- if (apiVersion < expectedApiVersion) {
- ToastService.showError("DMS server is outdated (API v" + apiVersion + ", expected v" + expectedApiVersion + ")");
- }
-
- capabilitiesReceived();
- } else if (service === "network") {
- networkStateUpdate(data);
- } else if (service === "network.credentials") {
- credentialsRequest(data);
- } else if (service === "loginctl") {
- if (data.event) {
- loginctlEvent(data);
- } else {
- loginctlStateUpdate(data);
- }
- } else if (service === "bluetooth.pairing") {
- bluetoothPairingRequest(data);
- } else if (service === "cups") {
- cupsStateUpdate(data);
- } else if (service === "dwl") {
- dwlStateUpdate(data);
- } else if (service === "brightness") {
- brightnessStateUpdate(data);
- } else if (service === "brightness.update") {
- if (data.device) {
- brightnessDeviceUpdate(data.device);
- }
- } else if (service === "extworkspace") {
- extWorkspaceStateUpdate(data);
- } else if (service === "wlroutput") {
- wlrOutputStateUpdate(data);
- } else if (service === "evdev") {
- if (data.capsLock !== undefined) {
- capsLockState = data.capsLock;
- }
- evdevStateUpdate(data);
- } else if (service === "gamma") {
- gammaStateUpdate(data);
- } else if (service === "theme.auto") {
- themeAutoStateUpdate(data);
- } else if (service === "browser.open_requested") {
- if (data.target) {
- if (data.requestType === "url" || !data.requestType) {
- openUrlRequested(data.target);
- } else {
- appPickerRequested(data);
- }
- } else if (data.url) {
- openUrlRequested(data.url);
- }
- } else if (service === "freedesktop.screensaver") {
- screensaverInhibited = data.inhibited || false;
- screensaverInhibitors = data.inhibitors || [];
- screensaverStateUpdate(data);
- } else if (service === "dbus") {
- dbusSignalReceived(data.subscriptionId || "", data);
- } else if (service === "clipboard") {
- clipboardStateUpdate(data);
- } else if (service === "location") {
- locationStateUpdate(data);
- }
- }
-
- function sendRequest(method, params, callback) {
- if (!isConnected) {
- console.warn("DMSService.sendRequest: Not connected, method:", method);
- if (callback) {
- callback({
- "error": "not connected to DMS socket"
- });
- }
- return;
- }
-
- requestIdCounter++;
- const id = Date.now() + requestIdCounter;
- const request = {
- "id": id,
- "method": method
- };
-
- if (params) {
- request.params = params;
- }
-
- if (callback)
- pendingRequests[id] = callback;
-
- if (method.startsWith("clipboard")) {
- clipboardRequestIds[id] = true;
- } else {
- console.log("DMSService.sendRequest: Sending request id=" + id + " method=" + method);
- }
- requestSocket.send(request);
- }
-
- function handleResponse(response) {
- const callback = pendingRequests[response.id];
-
- if (callback) {
- delete pendingRequests[response.id];
- callback(response);
- }
- }
-
- function ping(callback) {
- sendRequest("ping", null, callback);
- }
-
- function listPlugins(callback) {
- sendRequest("plugins.list", null, response => {
- if (response.result) {
- availablePlugins = response.result;
- pluginsListReceived(response.result);
- }
- if (callback) {
- callback(response);
- }
- });
- }
-
- function listInstalled(callback) {
- sendRequest("plugins.listInstalled", null, response => {
- if (response.result) {
- installedPlugins = response.result;
- installedPluginsReceived(response.result);
- }
- if (callback) {
- callback(response);
- }
- });
- }
-
- function search(query, category, compositor, capability, callback) {
- const params = {
- "query": query
- };
- if (category) {
- params.category = category;
- }
- if (compositor) {
- params.compositor = compositor;
- }
- if (capability) {
- params.capability = capability;
- }
-
- sendRequest("plugins.search", params, response => {
- if (response.result) {
- searchResultsReceived(response.result);
- }
- if (callback) {
- callback(response);
- }
- });
- }
-
- function install(pluginName, callback) {
- sendRequest("plugins.install", {
- "name": pluginName
- }, response => {
- if (callback) {
- callback(response);
- }
- if (!response.error) {
- listInstalled();
- }
- });
- }
-
- function uninstall(pluginName, callback) {
- sendRequest("plugins.uninstall", {
- "name": pluginName
- }, response => {
- if (callback) {
- callback(response);
- }
- if (!response.error) {
- listInstalled();
- }
- });
- }
-
- function update(pluginName, callback) {
- sendRequest("plugins.update", {
- "name": pluginName
- }, response => {
- if (callback) {
- callback(response);
- }
- if (!response.error) {
- listInstalled();
- }
- });
- }
-
- function listThemes(callback) {
- sendRequest("themes.list", null, response => {
- if (response.result) {
- availableThemes = response.result;
- themesListReceived(response.result);
- }
- if (callback) {
- callback(response);
- }
- });
- }
-
- function listInstalledThemes(callback) {
- sendRequest("themes.listInstalled", null, response => {
- if (response.result) {
- installedThemes = response.result;
- installedThemesReceived(response.result);
- }
- if (callback) {
- callback(response);
- }
- });
- }
-
- function searchThemes(query, callback) {
- sendRequest("themes.search", {
- "query": query
- }, response => {
- if (response.result) {
- themeSearchResultsReceived(response.result);
- }
- if (callback) {
- callback(response);
- }
- });
- }
-
- function installTheme(themeName, callback) {
- sendRequest("themes.install", {
- "name": themeName
- }, response => {
- if (callback) {
- callback(response);
- }
- if (!response.error) {
- listInstalledThemes();
- }
- });
- }
-
- function uninstallTheme(themeName, callback) {
- sendRequest("themes.uninstall", {
- "name": themeName
- }, response => {
- if (callback) {
- callback(response);
- }
- if (!response.error) {
- listInstalledThemes();
- }
- });
- }
-
- function updateTheme(themeName, callback) {
- sendRequest("themes.update", {
- "name": themeName
- }, response => {
- if (callback) {
- callback(response);
- }
- if (!response.error) {
- listInstalledThemes();
- }
- });
- }
-
- function lockSession(callback) {
- sendRequest("loginctl.lock", null, callback);
- }
-
- function unlockSession(callback) {
- sendRequest("loginctl.unlock", null, callback);
- }
-
- function bluetoothPair(devicePath, callback) {
- sendRequest("bluetooth.pair", {
- "device": devicePath
- }, callback);
- }
-
- function bluetoothConnect(devicePath, callback) {
- sendRequest("bluetooth.connect", {
- "device": devicePath
- }, callback);
- }
-
- function bluetoothDisconnect(devicePath, callback) {
- sendRequest("bluetooth.disconnect", {
- "device": devicePath
- }, callback);
- }
-
- function bluetoothRemove(devicePath, callback) {
- sendRequest("bluetooth.remove", {
- "device": devicePath
- }, callback);
- }
-
- function bluetoothTrust(devicePath, callback) {
- sendRequest("bluetooth.trust", {
- "device": devicePath
- }, callback);
- }
-
- function bluetoothSubmitPairing(token, secrets, accept, callback) {
- sendRequest("bluetooth.pairing.submit", {
- "token": token,
- "secrets": secrets,
- "accept": accept
- }, callback);
- }
-
- function bluetoothCancelPairing(token, callback) {
- sendRequest("bluetooth.pairing.cancel", {
- "token": token
- }, callback);
- }
-
- signal dbusSignalReceived(string subscriptionId, var data)
-
- property var dbusSubscriptions: ({})
-
- function dbusCall(bus, dest, path, iface, method, args, callback) {
- sendRequest("dbus.call", {
- "bus": bus,
- "dest": dest,
- "path": path,
- "interface": iface,
- "method": method,
- "args": args || []
- }, callback);
- }
-
- function dbusGetProperty(bus, dest, path, iface, property, callback) {
- sendRequest("dbus.getProperty", {
- "bus": bus,
- "dest": dest,
- "path": path,
- "interface": iface,
- "property": property
- }, callback);
- }
-
- function dbusSetProperty(bus, dest, path, iface, property, value, callback) {
- sendRequest("dbus.setProperty", {
- "bus": bus,
- "dest": dest,
- "path": path,
- "interface": iface,
- "property": property,
- "value": value
- }, callback);
- }
-
- function dbusGetAllProperties(bus, dest, path, iface, callback) {
- sendRequest("dbus.getAllProperties", {
- "bus": bus,
- "dest": dest,
- "path": path,
- "interface": iface
- }, callback);
- }
-
- function dbusIntrospect(bus, dest, path, callback) {
- sendRequest("dbus.introspect", {
- "bus": bus,
- "dest": dest,
- "path": path || "/"
- }, callback);
- }
-
- function dbusListNames(bus, callback) {
- sendRequest("dbus.listNames", {
- "bus": bus
- }, callback);
- }
-
- function dbusSubscribe(bus, sender, path, iface, member, callback) {
- sendRequest("dbus.subscribe", {
- "bus": bus,
- "sender": sender || "",
- "path": path || "",
- "interface": iface || "",
- "member": member || ""
- }, response => {
- if (!response.error && response.result?.subscriptionId) {
- dbusSubscriptions[response.result.subscriptionId] = true;
- }
- if (callback)
- callback(response);
- });
- }
-
- function dbusUnsubscribe(subscriptionId, callback) {
- sendRequest("dbus.unsubscribe", {
- "subscriptionId": subscriptionId
- }, response => {
- if (!response.error) {
- delete dbusSubscriptions[subscriptionId];
- }
- if (callback)
- callback(response);
- });
- }
-
- function renameWorkspace(name, callback) {
- sendRequest("extworkspace.renameWorkspace", {
- "name": name
- }, callback);
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DSearchService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DSearchService.qml
deleted file mode 100644
index 63efcb0..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DSearchService.qml
+++ /dev/null
@@ -1,184 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- property bool dsearchAvailable: false
- property int searchIdCounter: 0
- property int indexVersion: 0
- property bool supportsTypeFilter: false
- property bool versionChecked: false
-
- signal searchResultsReceived(var results)
- signal statsReceived(var stats)
- signal errorOccurred(string error)
-
- Process {
- id: checkProcess
- command: ["sh", "-c", "command -v dsearch"]
- running: true
-
- stdout: SplitParser {
- onRead: line => {
- if (line && line.trim().length > 0) {
- root.dsearchAvailable = true;
- }
- }
- }
-
- onExited: exitCode => {
- if (exitCode !== 0) {
- root.dsearchAvailable = false;
- } else {
- root._checkVersion();
- }
- }
- }
-
- function _checkVersion() {
- Proc.runCommand("dsearch-version", ["dsearch", "version", "--json"], (stdout, exitCode) => {
- root.versionChecked = true;
- if (exitCode !== 0)
- return;
- const response = JSON.parse(stdout);
- root.indexVersion = response.index_schema || 0;
- root.supportsTypeFilter = root.indexVersion >= 2;
- });
- }
-
- function ping(callback) {
- if (!dsearchAvailable) {
- if (callback) {
- callback({
- "error": "dsearch not available"
- });
- }
- return;
- }
-
- Proc.runCommand("dsearch-ping", ["dsearch", "ping", "--json"], (stdout, exitCode) => {
- if (callback) {
- if (exitCode === 0) {
- try {
- const response = JSON.parse(stdout);
- callback({
- "result": response
- });
- } catch (e) {
- callback({
- "error": "failed to parse ping response"
- });
- }
- } else {
- callback({
- "error": "ping failed"
- });
- }
- }
- });
- }
-
- function search(query, params, callback) {
- if (!query || query.length === 0) {
- if (callback) {
- callback({
- "error": "query is required"
- });
- }
- return;
- }
-
- if (!dsearchAvailable) {
- if (callback) {
- callback({
- "error": "dsearch not available"
- });
- }
- return;
- }
-
- const args = ["dsearch", "search", query, "--json"];
-
- if (params) {
- if (params.limit !== undefined) {
- args.push("-n", String(params.limit));
- }
- if (params.type) {
- args.push("-t", params.type);
- }
- if (params.ext) {
- args.push("-e", params.ext);
- }
- if (params.folder) {
- args.push("--folder", params.folder);
- }
- if (params.field) {
- args.push("-f", params.field);
- }
- if (params.fuzzy) {
- args.push("--fuzzy");
- }
- if (params.sort) {
- args.push("--sort", params.sort);
- }
- if (params.desc !== undefined) {
- args.push("--desc=" + (params.desc ? "true" : "false"));
- }
- if (params.minSize !== undefined) {
- args.push("--min-size", String(params.minSize));
- }
- if (params.maxSize !== undefined) {
- args.push("--max-size", String(params.maxSize));
- }
- }
-
- const procId = "dsearch-search-" + (params?.type || "all");
- Proc.runCommand(procId, args, (stdout, exitCode) => {
- if (exitCode === 0) {
- try {
- const response = JSON.parse(stdout);
- searchResultsReceived(response);
- if (callback) {
- callback({
- "result": response
- });
- }
- } catch (e) {
- const error = "failed to parse search response";
- errorOccurred(error);
- if (callback) {
- callback({
- "error": error
- });
- }
- }
- } else if (exitCode === 124) {
- const error = "search timed out";
- errorOccurred(error);
- if (callback) {
- callback({
- "error": error
- });
- }
- } else {
- const error = "search failed";
- errorOccurred(error);
- if (callback) {
- callback({
- "error": error
- });
- }
- }
- }, 100, 5000);
- }
-
- function rediscover() {
- checkProcess.running = true;
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DesktopService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DesktopService.qml
deleted file mode 100644
index c9913e9..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DesktopService.qml
+++ /dev/null
@@ -1,94 +0,0 @@
-pragma Singleton
-
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-
-Singleton {
- id: root
-
- property var _cache: ({})
-
- function resolveIconPath(moddedAppId) {
- if (!moddedAppId)
- return "";
-
- if (_cache[moddedAppId] !== undefined)
- return _cache[moddedAppId];
-
- const result = (function() {
- // 1. Try heuristic lookup (standard)
- const entry = DesktopEntries.heuristicLookup(moddedAppId);
- let icon = Quickshell.iconPath(entry?.icon, true);
- if (icon && icon !== "")
- return icon;
-
- // 2. Try the appId itself as an icon name
- icon = Quickshell.iconPath(moddedAppId, true);
- if (icon && icon !== "")
- return icon;
-
- // 3. Try variations of the appId (lowercase, last part)
- const appIds = [moddedAppId.toLowerCase()];
- const lastPart = moddedAppId.split('.').pop();
- if (lastPart && lastPart !== moddedAppId) {
- appIds.push(lastPart);
- appIds.push(lastPart.toLowerCase());
- }
-
- for (const id of appIds) {
- icon = Quickshell.iconPath(id, true);
- if (icon && icon !== "")
- return icon;
- }
-
- // 4. Deep search in all desktop entries (if the above fail)
- // This is slow-ish but only happens once for failed icons
- const strippedId = moddedAppId.replace(/-bin$/, "").toLowerCase();
- const allEntries = DesktopEntries.applications.values;
- for (let i = 0; i < allEntries.length; i++) {
- const e = allEntries[i];
- const eId = (e.id || "").toLowerCase();
- const eName = (e.name || "").toLowerCase();
- const eExec = (e.execString || "").toLowerCase();
-
- if (eId.includes(strippedId) || eName.includes(strippedId) || eExec.includes(strippedId)) {
- icon = Quickshell.iconPath(e.icon, true);
- if (icon && icon !== "")
- return icon;
- }
- }
-
- // 5. Nix/Guix specific store check (as a last resort)
- for (const appId of appIds) {
- let execPath = entry?.execString?.replace(/\/bin.*/, "");
- if (!execPath)
- continue;
-
- if (execPath.startsWith("/nix/store/") || execPath.startsWith("/gnu/store/")) {
- const basePath = execPath;
- const sizes = ["256x256", "128x128", "64x64", "48x48", "32x32", "24x24", "16x16"];
-
- let iconPath = `${basePath}/share/icons/hicolor/scalable/apps/${appId}.svg`;
- icon = Quickshell.iconPath(iconPath, true);
- if (icon && icon !== "")
- return icon;
-
- for (const size of sizes) {
- iconPath = `${basePath}/share/icons/hicolor/${size}/apps/${appId}.png`;
- icon = Quickshell.iconPath(iconPath, true);
- if (icon && icon !== "")
- return icon;
- }
- }
- }
-
- return "";
- })();
-
- _cache[moddedAppId] = result;
- return result;
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DesktopWidgetRegistry.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DesktopWidgetRegistry.qml
deleted file mode 100644
index 0e2ea6f..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DesktopWidgetRegistry.qml
+++ /dev/null
@@ -1,232 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import qs.Common
-
-Singleton {
- id: root
-
- property var registeredWidgets: ({})
- property var registeredWidgetsList: []
-
- signal registryChanged
-
- Component.onCompleted: {
- registerBuiltins();
- Qt.callLater(syncPluginWidgets);
- }
-
- Connections {
- target: PluginService
- function onPluginLoaded(pluginId) {
- const plugin = PluginService.availablePlugins[pluginId];
- if (plugin?.type === "desktop")
- syncPluginWidgets();
- }
- function onPluginUnloaded(pluginId) {
- syncPluginWidgets();
- }
- function onPluginListUpdated() {
- syncPluginWidgets();
- }
- }
-
- function registerBuiltins() {
- registerWidget({
- id: "desktopClock",
- name: I18n.tr("Desktop Clock", "Desktop clock widget name"),
- icon: "schedule",
- description: I18n.tr("Analog, digital, or stacked clock display", "Desktop clock widget description"),
- type: "builtin",
- component: "qs.Modules.BuiltinDesktopPlugins.DesktopClockWidget",
- settingsComponent: "qs.Modules.Settings.DesktopWidgetSettings.ClockSettings",
- defaultConfig: getDefaultClockConfig(),
- defaultSize: {
- width: 280,
- height: 180
- }
- });
-
- registerWidget({
- id: "systemMonitor",
- name: I18n.tr("System Monitor", "System monitor widget name"),
- icon: "monitoring",
- description: I18n.tr("CPU, memory, network, and disk monitoring", "System monitor widget description"),
- type: "builtin",
- component: "qs.Modules.BuiltinDesktopPlugins.SystemMonitorWidget",
- settingsComponent: "qs.Modules.Settings.DesktopWidgetSettings.SystemMonitorSettings",
- defaultConfig: getDefaultSystemMonitorConfig(),
- defaultSize: {
- width: 320,
- height: 480
- }
- });
- }
-
- function getDefaultClockConfig() {
- return {
- style: "analog",
- transparency: 0.8,
- colorMode: "primary",
- customColor: "#ffffff",
- showDate: true,
- showAnalogNumbers: false,
- showAnalogSeconds: true,
- displayPreferences: ["all"]
- };
- }
-
- function getDefaultSystemMonitorConfig() {
- return {
- showHeader: true,
- transparency: 0.8,
- colorMode: "primary",
- customColor: "#ffffff",
- showCpu: true,
- showCpuGraph: true,
- showCpuTemp: true,
- showGpuTemp: false,
- gpuPciId: "",
- showMemory: true,
- showMemoryGraph: true,
- showNetwork: true,
- showNetworkGraph: true,
- showDisk: true,
- showTopProcesses: false,
- topProcessCount: 3,
- topProcessSortBy: "cpu",
- layoutMode: "auto",
- graphInterval: 60,
- displayPreferences: ["all"]
- };
- }
-
- function registerWidget(widgetDef) {
- if (!widgetDef?.id)
- return;
-
- const newMap = Object.assign({}, registeredWidgets);
- newMap[widgetDef.id] = widgetDef;
- registeredWidgets = newMap;
- _updateWidgetsList();
- registryChanged();
- }
-
- function unregisterWidget(widgetId) {
- if (!registeredWidgets[widgetId])
- return;
-
- const newMap = Object.assign({}, registeredWidgets);
- delete newMap[widgetId];
- registeredWidgets = newMap;
- _updateWidgetsList();
- registryChanged();
- }
-
- function getWidget(widgetType) {
- return registeredWidgets[widgetType] ?? null;
- }
-
- function getDefaultConfig(widgetType) {
- const widget = getWidget(widgetType);
- if (!widget)
- return {};
-
- if (widget.type === "builtin") {
- switch (widgetType) {
- case "desktopClock":
- return getDefaultClockConfig();
- case "systemMonitor":
- return getDefaultSystemMonitorConfig();
- default:
- return widget.defaultConfig ?? {};
- }
- }
-
- return widget.defaultConfig ?? {};
- }
-
- function getDefaultSize(widgetType) {
- const widget = getWidget(widgetType);
- return widget?.defaultSize ?? {
- width: 200,
- height: 200
- };
- }
-
- function syncPluginWidgets() {
- const desktopPlugins = PluginService.pluginDesktopComponents;
- const availablePlugins = PluginService.availablePlugins;
- const currentPluginIds = [];
-
- for (const pluginId in desktopPlugins) {
- currentPluginIds.push(pluginId);
- const plugin = availablePlugins[pluginId];
- if (!plugin)
- continue;
-
- if (registeredWidgets[pluginId]?.type === "plugin")
- continue;
-
- registerWidget({
- id: pluginId,
- name: plugin.name || pluginId,
- icon: plugin.icon || "extension",
- description: plugin.description || "",
- type: "plugin",
- component: null,
- settingsComponent: plugin.settingsPath || null,
- defaultConfig: {
- displayPreferences: ["all"]
- },
- defaultSize: {
- width: 200,
- height: 200
- },
- pluginInfo: plugin
- });
- }
-
- const toRemove = [];
- for (const widgetId in registeredWidgets) {
- const widget = registeredWidgets[widgetId];
- if (widget.type !== "plugin")
- continue;
- if (!currentPluginIds.includes(widgetId))
- toRemove.push(widgetId);
- }
-
- for (const widgetId of toRemove) {
- unregisterWidget(widgetId);
- }
- }
-
- function _updateWidgetsList() {
- const result = [];
- for (const key in registeredWidgets) {
- result.push(registeredWidgets[key]);
- }
- result.sort((a, b) => {
- if (a.type === "builtin" && b.type !== "builtin")
- return -1;
- if (a.type !== "builtin" && b.type === "builtin")
- return 1;
- return (a.name || "").localeCompare(b.name || "");
- });
- registeredWidgetsList = result;
- }
-
- function getBuiltinWidgets() {
- return registeredWidgetsList.filter(w => w.type === "builtin");
- }
-
- function getPluginWidgets() {
- return registeredWidgetsList.filter(w => w.type === "plugin");
- }
-
- function getAllWidgets() {
- return registeredWidgetsList;
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DgopService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DgopService.qml
deleted file mode 100644
index e63c5c5..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DgopService.qml
+++ /dev/null
@@ -1,778 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- property int refCount: 0
- property int updateInterval: refCount > 0 ? 3000 : 30000
- property bool isUpdating: false
- property bool dgopAvailable: false
-
- property var moduleRefCounts: ({})
- property var enabledModules: []
- property var gpuPciIds: []
- property var gpuPciIdRefCounts: ({})
- property int processLimit: 20
- property string processSort: "cpu"
- property bool noCpu: false
- property int dgopProcessPid: 0
-
- // Cursor data for accurate CPU calculations
- property string cpuCursor: ""
- property string procCursor: ""
- property int cpuSampleCount: 0
- property int processSampleCount: 0
-
- property real cpuUsage: 0
- property real cpuFrequency: 0
- property real cpuTemperature: 0
- property int cpuCores: 1
- property string cpuModel: ""
- property var perCoreCpuUsage: []
-
- property real memoryUsage: 0
- property real totalMemoryMB: 0
- property real usedMemoryMB: 0
- property real freeMemoryMB: 0
- property real availableMemoryMB: 0
- property int totalMemoryKB: 0
- property int usedMemoryKB: 0
- property int totalSwapKB: 0
- property int usedSwapKB: 0
-
- property real networkRxRate: 0
- property real networkTxRate: 0
- property var lastNetworkStats: null
- property var networkInterfaces: []
-
- property real diskReadRate: 0
- property real diskWriteRate: 0
- property var lastDiskStats: null
- property var diskMounts: []
- property var diskDevices: []
-
- property var processes: []
- property var allProcesses: []
- property string currentSort: "cpu"
- property bool sortAscending: false
- property var availableGpus: []
-
- property string kernelVersion: ""
- property string distribution: ""
- property string hostname: ""
- property string architecture: ""
- property string loadAverage: ""
- property int processCount: 0
- property int threadCount: 0
- property string bootTime: ""
- property string motherboard: ""
- property string biosVersion: ""
- property string uptime: ""
- property string shortUptime: ""
-
- property int historySize: 60
- property var cpuHistory: []
- property var memoryHistory: []
- property var networkHistory: ({
- "rx": [],
- "tx": []
- })
- property var diskHistory: ({
- "read": [],
- "write": []
- })
-
- function addRef(modules = null) {
- refCount++;
- let modulesChanged = false;
-
- if (modules) {
- const modulesToAdd = Array.isArray(modules) ? modules : [modules];
- for (const module of modulesToAdd) {
- const currentCount = moduleRefCounts[module] || 0;
- moduleRefCounts[module] = currentCount + 1;
-
- // Add to enabled modules if not already there
- if (enabledModules.indexOf(module) === -1) {
- enabledModules.push(module);
- modulesChanged = true;
- }
- }
- }
-
- if (modulesChanged || refCount === 1) {
- enabledModules = enabledModules.slice(); // Force property change
- moduleRefCounts = Object.assign({}, moduleRefCounts); // Force property change
- updateAllStats();
- } else if (gpuPciIds.length > 0 && refCount > 0) {
- // If we have GPU PCI IDs and active modules, make sure to update
- // This handles the case where PCI IDs were loaded after modules were added
- updateAllStats();
- }
- }
-
- function removeRef(modules = null) {
- refCount = Math.max(0, refCount - 1);
- let modulesChanged = false;
-
- if (modules) {
- const modulesToRemove = Array.isArray(modules) ? modules : [modules];
- for (const module of modulesToRemove) {
- const currentCount = moduleRefCounts[module] || 0;
- if (currentCount > 1) {
- moduleRefCounts[module] = currentCount - 1;
- } else if (currentCount === 1) {
- delete moduleRefCounts[module];
- const index = enabledModules.indexOf(module);
- if (index > -1) {
- enabledModules.splice(index, 1);
- modulesChanged = true;
- }
- }
- }
- }
-
- if (modulesChanged) {
- enabledModules = enabledModules.slice(); // Force property change
- moduleRefCounts = Object.assign({}, moduleRefCounts); // Force property change
-
- // Clear cursor data when CPU or process modules are no longer active
- if (!enabledModules.includes("cpu")) {
- cpuCursor = "";
- cpuSampleCount = 0;
- }
- if (!enabledModules.includes("processes")) {
- procCursor = "";
- processSampleCount = 0;
- }
- }
- }
-
- function setGpuPciIds(pciIds) {
- gpuPciIds = Array.isArray(pciIds) ? pciIds : [];
- }
-
- function addGpuPciId(pciId) {
- const currentCount = gpuPciIdRefCounts[pciId] || 0;
- gpuPciIdRefCounts[pciId] = currentCount + 1;
-
- // Add to gpuPciIds array if not already there
- if (!gpuPciIds.includes(pciId)) {
- gpuPciIds = gpuPciIds.concat([pciId]);
- }
-
- gpuPciIdRefCounts = Object.assign({}, gpuPciIdRefCounts);
- }
-
- function removeGpuPciId(pciId) {
- const currentCount = gpuPciIdRefCounts[pciId] || 0;
- if (currentCount > 1) {
- gpuPciIdRefCounts[pciId] = currentCount - 1;
- } else if (currentCount === 1) {
- // Remove completely when count reaches 0
- delete gpuPciIdRefCounts[pciId];
- const index = gpuPciIds.indexOf(pciId);
- if (index > -1) {
- gpuPciIds = gpuPciIds.slice();
- gpuPciIds.splice(index, 1);
- }
-
- // Clear temperature data for this GPU when no longer monitored
- if (availableGpus && availableGpus.length > 0) {
- const updatedGpus = availableGpus.slice();
- for (var i = 0; i < updatedGpus.length; i++) {
- if (updatedGpus[i].pciId === pciId) {
- updatedGpus[i] = Object.assign({}, updatedGpus[i], {
- "temperature": 0
- });
- }
- }
- availableGpus = updatedGpus;
- }
- }
-
- // Force property change notification
- gpuPciIdRefCounts = Object.assign({}, gpuPciIdRefCounts);
- }
-
- function setProcessOptions(limit = 20, sort = "cpu", disableCpu = false) {
- processLimit = limit;
- processSort = sort;
- noCpu = disableCpu;
- }
-
- function updateAllStats() {
- if (dgopAvailable && refCount > 0 && enabledModules.length > 0) {
- isUpdating = true;
- dgopProcess.running = true;
- } else {
- isUpdating = false;
- }
- }
-
- function initializeGpuMetadata() {
- if (!dgopAvailable)
- return;
- gpuInitProcess.running = true;
- }
-
- function initializeSystemMetadata() {
- if (!dgopAvailable)
- return;
- systemInitProcess.running = true;
- }
-
- function buildDgopCommand() {
- const cmd = ["dgop", "meta", "--json"];
-
- if (enabledModules.length === 0) {
- // Don't run if no modules are needed
- return [];
- }
-
- // Replace 'gpu' with 'gpu-temp' when we have PCI IDs to monitor
- const finalModules = [];
- for (const module of enabledModules) {
- if (module === "gpu" && gpuPciIds.length > 0) {
- finalModules.push("gpu-temp");
- } else if (module !== "gpu") {
- finalModules.push(module);
- }
- }
-
- // Add gpu-temp module automatically when we have PCI IDs to monitor
- if (gpuPciIds.length > 0 && finalModules.indexOf("gpu-temp") === -1) {
- finalModules.push("gpu-temp");
- }
-
- if (enabledModules.indexOf("all") !== -1) {
- cmd.push("--modules", "all");
- } else if (finalModules.length > 0) {
- const moduleList = finalModules.join(",");
- cmd.push("--modules", moduleList);
- } else {
- return [];
- }
-
- // Add cursor data if available for accurate CPU percentages
- if ((enabledModules.includes("cpu") || enabledModules.includes("all")) && cpuCursor) {
- cmd.push("--cpu-cursor", cpuCursor);
- }
- if ((enabledModules.includes("processes") || enabledModules.includes("all")) && procCursor) {
- cmd.push("--proc-cursor", procCursor);
- }
-
- if (gpuPciIds.length > 0) {
- cmd.push("--gpu-pci-ids", gpuPciIds.join(","));
- }
-
- if (enabledModules.indexOf("processes") !== -1 || enabledModules.indexOf("all") !== -1) {
- cmd.push("--limit", "100"); // Get more data for client sorting
- cmd.push("--sort", "cpu"); // Always get CPU sorted data
- if (noCpu) {
- cmd.push("--no-cpu");
- }
- }
-
- return cmd;
- }
-
- function parseData(data) {
- if (data.cpu) {
- const cpu = data.cpu;
- cpuSampleCount++;
-
- cpuUsage = Math.round((cpu.usage || 0) * 10) / 10;
- cpuFrequency = Math.round(cpu.frequency || 0);
- cpuTemperature = Math.round(cpu.temperature || 0);
- cpuCores = cpu.count || 1;
- cpuModel = cpu.model || "";
- perCoreCpuUsage = cpu.coreUsage || [];
- addToHistory(cpuHistory, cpuUsage);
-
- if (cpu.cursor) {
- cpuCursor = cpu.cursor;
- }
- }
-
- if (data.memory) {
- const mem = data.memory;
- const totalKB = mem.total || 0;
- const availableKB = mem.available || 0;
- const freeKB = mem.free || 0;
- const usedKB = mem.used !== undefined ? mem.used : (totalKB - availableKB);
-
- totalMemoryMB = Math.round(totalKB / 1024);
- availableMemoryMB = Math.round(availableKB / 1024);
- freeMemoryMB = Math.round(freeKB / 1024);
- usedMemoryMB = Math.round(usedKB / 1024);
- const rawMemUsage = mem.usedPercent !== undefined ? mem.usedPercent : (totalKB > 0 ? ((totalKB - availableKB) / totalKB) * 100 : 0);
- memoryUsage = Math.round(rawMemUsage * 10) / 10;
-
- totalMemoryKB = totalKB;
- usedMemoryKB = usedKB;
- totalSwapKB = mem.swaptotal || 0;
- usedSwapKB = (mem.swaptotal || 0) - (mem.swapfree || 0);
-
- addToHistory(memoryHistory, memoryUsage);
- }
-
- if (data.network && Array.isArray(data.network)) {
- networkInterfaces = data.network;
-
- let totalRx = 0;
- let totalTx = 0;
- for (const iface of data.network) {
- totalRx += iface.rx || 0;
- totalTx += iface.tx || 0;
- }
-
- if (lastNetworkStats) {
- const timeDiff = updateInterval / 1000;
- const rxDiff = totalRx - lastNetworkStats.rx;
- const txDiff = totalTx - lastNetworkStats.tx;
- networkRxRate = Math.max(0, rxDiff / timeDiff);
- networkTxRate = Math.max(0, txDiff / timeDiff);
- addToHistory(networkHistory.rx, networkRxRate / 1024);
- addToHistory(networkHistory.tx, networkTxRate / 1024);
- }
- lastNetworkStats = {
- "rx": totalRx,
- "tx": totalTx
- };
- }
-
- if (data.disk && Array.isArray(data.disk)) {
- diskDevices = data.disk;
-
- let totalRead = 0;
- let totalWrite = 0;
- for (const disk of data.disk) {
- totalRead += (disk.read || 0) * 512;
- totalWrite += (disk.write || 0) * 512;
- }
-
- if (lastDiskStats) {
- const timeDiff = updateInterval / 1000;
- const readDiff = totalRead - lastDiskStats.read;
- const writeDiff = totalWrite - lastDiskStats.write;
- diskReadRate = Math.max(0, readDiff / timeDiff);
- diskWriteRate = Math.max(0, writeDiff / timeDiff);
- addToHistory(diskHistory.read, diskReadRate / (1024 * 1024));
- addToHistory(diskHistory.write, diskWriteRate / (1024 * 1024));
- }
- lastDiskStats = {
- "read": totalRead,
- "write": totalWrite
- };
- }
-
- if (data.diskmounts) {
- diskMounts = data.diskmounts || [];
- }
-
- if (data.processes && Array.isArray(data.processes)) {
- const newProcesses = [];
- processSampleCount++;
- const ourPid = dgopProcessPid;
-
- for (const proc of data.processes) {
- if (ourPid > 0 && proc.pid === ourPid)
- continue;
-
- const cpuUsage = processSampleCount >= 2 ? (proc.cpu || 0) : 0;
-
- newProcesses.push({
- "pid": proc.pid || 0,
- "ppid": proc.ppid || 0,
- "cpu": cpuUsage,
- "memoryPercent": proc.memoryPercent || proc.pssPercent || 0,
- "memoryKB": proc.memoryKB || proc.pssKB || 0,
- "command": proc.command || "",
- "fullCommand": proc.fullCommand || "",
- "username": proc.username || "",
- "displayName": (proc.command && proc.command.length > 15) ? proc.command.substring(0, 15) + "..." : (proc.command || "")
- });
- }
- allProcesses = newProcesses;
- applySorting();
-
- if (data.cursor) {
- procCursor = data.cursor;
- }
- }
-
- const gpuData = (data.gpu && data.gpu.gpus) || data.gpus;
- if (gpuData && Array.isArray(gpuData)) {
- // Check if this is temperature update data (has PCI IDs being monitored)
- if (gpuPciIds.length > 0 && availableGpus && availableGpus.length > 0) {
- // This is temperature data - merge with existing GPU metadata
- const updatedGpus = availableGpus.slice();
- for (var i = 0; i < updatedGpus.length; i++) {
- const existingGpu = updatedGpus[i];
- const tempGpu = gpuData.find(g => g.pciId === existingGpu.pciId);
- // Only update temperature if this GPU's PCI ID is being monitored
- if (tempGpu && gpuPciIds.includes(existingGpu.pciId)) {
- updatedGpus[i] = Object.assign({}, existingGpu, {
- "temperature": tempGpu.temperature || 0
- });
- }
- }
- availableGpus = updatedGpus;
- } else {
- // This is initial GPU metadata - set the full list
- const gpuList = [];
- for (const gpu of gpuData) {
- let displayName = gpu.displayName || gpu.name || "Unknown GPU";
- let fullName = gpu.fullName || gpu.name || "Unknown GPU";
-
- gpuList.push({
- "driver": gpu.driver || "",
- "vendor": gpu.vendor || "",
- "displayName": displayName,
- "fullName": fullName,
- "pciId": gpu.pciId || "",
- "temperature": gpu.temperature || 0
- });
- }
- availableGpus = gpuList;
- }
- }
-
- if (data.system) {
- const sys = data.system;
- loadAverage = sys.loadavg || "";
- processCount = sys.processes || 0;
- threadCount = sys.threads || 0;
- bootTime = sys.boottime || "";
- updateUptime();
- }
-
- const hwData = data.hardware || (data.hostname || data.kernel || data.distro || data.arch) ? data : null;
- if (hwData) {
- hostname = hwData.hostname || "";
- kernelVersion = hwData.kernel || "";
- distribution = hwData.distro || "";
- architecture = hwData.arch || "";
- motherboard = (hwData.bios && hwData.bios.motherboard) || "";
- biosVersion = (hwData.bios && hwData.bios.version) || "";
- }
-
- isUpdating = false;
- }
-
- function addToHistory(array, value) {
- array.push(value);
- if (array.length > historySize) {
- array.shift();
- }
- }
-
- function getProcessIcon(command) {
- const cmd = command.toLowerCase();
- if (cmd.includes("firefox") || cmd.includes("chrome") || cmd.includes("browser") || cmd.includes("chromium")) {
- return "web";
- }
- if (cmd.includes("code") || cmd.includes("editor") || cmd.includes("vim")) {
- return "code";
- }
- if (cmd.includes("terminal") || cmd.includes("bash") || cmd.includes("zsh")) {
- return "terminal";
- }
- if (cmd.includes("music") || cmd.includes("audio") || cmd.includes("spotify")) {
- return "music_note";
- }
- if (cmd.includes("video") || cmd.includes("vlc") || cmd.includes("mpv")) {
- return "play_circle";
- }
- if (cmd.includes("systemd") || cmd.includes("elogind") || cmd.includes("kernel") || cmd.includes("kthread") || cmd.includes("kworker")) {
- return "settings";
- }
- return "memory";
- }
-
- function formatCpuUsage(cpu) {
- return (cpu || 0).toFixed(1) + "%";
- }
-
- function formatMemoryUsage(memoryKB) {
- const mem = memoryKB || 0;
- if (mem < 1024) {
- return mem.toFixed(0) + " KB";
- } else if (mem < 1024 * 1024) {
- return (mem / 1024).toFixed(1) + " MB";
- } else {
- return (mem / (1024 * 1024)).toFixed(1) + " GB";
- }
- }
-
- function formatSystemMemory(memoryKB) {
- const mem = memoryKB || 0;
- if (mem === 0) {
- return "--";
- }
- if (mem < 1024 * 1024) {
- return (mem / 1024).toFixed(0) + " MB";
- } else {
- return (mem / (1024 * 1024)).toFixed(1) + " GB";
- }
- }
-
- function killProcess(pid) {
- if (pid > 0) {
- Quickshell.execDetached("kill", [pid.toString()]);
- }
- }
-
- function updateUptime() {
- if (!bootTime) {
- uptime = "";
- shortUptime = "";
- return;
- }
-
- const bootDate = new Date(bootTime.replace(" ", "T"));
- if (isNaN(bootDate.getTime())) {
- uptime = "";
- shortUptime = "";
- return;
- }
-
- const now = new Date();
- const seconds = Math.floor((now - bootDate) / 1000);
- const days = Math.floor(seconds / 86400);
- const hours = Math.floor((seconds % 86400) / 3600);
- const minutes = Math.floor((seconds % 3600) / 60);
-
- const parts = [];
- if (days > 0)
- parts.push(`${days} day${days === 1 ? "" : "s"}`);
- if (hours > 0)
- parts.push(`${hours} hour${hours === 1 ? "" : "s"}`);
- if (minutes > 0)
- parts.push(`${minutes} minute${minutes === 1 ? "" : "s"}`);
-
- uptime = parts.length > 0 ? `up ${parts.join(", ")}` : `up ${seconds} seconds`;
-
- var shortStr = "up";
- if (days > 0)
- shortStr += ` ${days}d`;
- if (hours > 0)
- shortStr += ` ${hours}h`;
- if (minutes > 0)
- shortStr += ` ${minutes}m`;
- shortUptime = shortStr;
- }
-
- function setSortBy(newSortBy) {
- if (newSortBy !== currentSort) {
- currentSort = newSortBy;
- sortAscending = false;
- applySorting();
- }
- }
-
- function toggleSort(column) {
- if (column === currentSort) {
- sortAscending = !sortAscending;
- } else {
- currentSort = column;
- sortAscending = false;
- }
- applySorting();
- }
-
- function applySorting() {
- if (!allProcesses || allProcesses.length === 0)
- return;
-
- const asc = sortAscending;
- const sorted = allProcesses.slice();
- sorted.sort((a, b) => {
- let valueA, valueB, result;
-
- switch (currentSort) {
- case "cpu":
- valueA = a.cpu || 0;
- valueB = b.cpu || 0;
- result = valueB - valueA;
- break;
- case "memory":
- valueA = a.memoryKB || 0;
- valueB = b.memoryKB || 0;
- result = valueB - valueA;
- break;
- case "name":
- valueA = (a.command || "").toLowerCase();
- valueB = (b.command || "").toLowerCase();
- result = valueA.localeCompare(valueB);
- break;
- case "pid":
- valueA = a.pid || 0;
- valueB = b.pid || 0;
- result = valueA - valueB;
- break;
- default:
- return 0;
- }
- return asc ? -result : result;
- });
-
- processes = sorted.slice(0, processLimit);
- }
-
- Timer {
- id: updateTimer
- interval: root.updateInterval
- running: root.dgopAvailable && root.refCount > 0 && root.enabledModules.length > 0
- repeat: true
- triggeredOnStart: true
- onTriggered: root.updateAllStats()
- }
-
- Process {
- id: dgopProcess
- command: root.buildDgopCommand()
- running: false
- onStarted: dgopProcessPid = processId ?? 0
- onExited: exitCode => {
- if (exitCode !== 0) {
- console.warn("Dgop process failed with exit code:", exitCode);
- isUpdating = false;
- }
- }
- stdout: StdioCollector {
- onStreamFinished: {
- if (text.trim()) {
- try {
- const data = JSON.parse(text.trim());
- parseData(data);
- } catch (e) {
- console.warn("Failed to parse dgop JSON:", e);
- console.warn("Raw text was:", text.substring(0, 200));
- isUpdating = false;
- }
- }
- }
- }
- }
-
- Process {
- id: gpuInitProcess
- command: ["dgop", "gpu", "--json"]
- running: false
- onExited: exitCode => {
- if (exitCode !== 0) {
- console.warn("GPU init process failed with exit code:", exitCode);
- }
- }
- stdout: StdioCollector {
- onStreamFinished: {
- if (text.trim()) {
- try {
- const data = JSON.parse(text.trim());
- parseData(data);
- } catch (e) {
- console.warn("Failed to parse GPU init JSON:", e);
- }
- }
- }
- }
- }
-
- Process {
- id: systemInitProcess
- command: ["dgop", "hardware", "--json"]
- running: false
- onExited: exitCode => {
- if (exitCode !== 0) {
- console.warn("System init process failed with exit code:", exitCode);
- }
- }
- stdout: StdioCollector {
- onStreamFinished: {
- if (text.trim()) {
- try {
- const data = JSON.parse(text.trim());
- parseData(data);
- } catch (e) {
- console.warn("Failed to parse system init JSON:", e);
- }
- }
- }
- }
- }
-
- Process {
- id: dgopCheckProcess
- command: ["which", "dgop"]
- running: false
- onExited: exitCode => {
- dgopAvailable = (exitCode === 0);
- if (dgopAvailable) {
- initializeGpuMetadata();
- initializeSystemMetadata();
- if (SessionData.enabledGpuPciIds && SessionData.enabledGpuPciIds.length > 0) {
- for (const pciId of SessionData.enabledGpuPciIds) {
- addGpuPciId(pciId);
- }
- if (refCount > 0 && enabledModules.length > 0) {
- updateAllStats();
- }
- }
- } else {
- console.warn("dgop is not installed or not in PATH");
- }
- }
- }
-
- Process {
- id: osReleaseProcess
- command: ["cat", "/etc/os-release"]
- running: false
- onExited: exitCode => {
- if (exitCode !== 0) {
- console.warn("Failed to read /etc/os-release");
- }
- }
- stdout: StdioCollector {
- onStreamFinished: {
- if (text.trim()) {
- try {
- const lines = text.trim().split('\n');
- let prettyName = "";
- let name = "";
-
- for (const line of lines) {
- const trimmedLine = line.trim();
- if (trimmedLine.startsWith('PRETTY_NAME=')) {
- prettyName = trimmedLine.substring(12).replace(/^["']|["']$/g, '');
- } else if (trimmedLine.startsWith('NAME=')) {
- name = trimmedLine.substring(5).replace(/^["']|["']$/g, '');
- }
- }
-
- // Prefer PRETTY_NAME, fallback to NAME
- const distroName = prettyName || name || "Linux";
- distribution = distroName;
- console.info("Detected distribution:", distroName);
- } catch (e) {
- console.warn("Failed to parse /etc/os-release:", e);
- distribution = "Linux";
- }
- }
- }
- }
- }
-
- Component.onCompleted: {
- dgopCheckProcess.running = true;
- osReleaseProcess.running = true;
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DisplayService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DisplayService.qml
deleted file mode 100644
index 553dd26..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DisplayService.qml
+++ /dev/null
@@ -1,1170 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- property bool brightnessAvailable: devices.length > 0
- property var devices: []
- property var deviceBrightness: ({})
- property var deviceBrightnessUserSet: ({})
- property var deviceMaxCache: ({})
- property var userControlledDevices: ({})
- property var pendingOsdDevices: ({})
- property int brightnessVersion: 0
- property string currentDevice: ""
- property string lastIpcDevice: ""
- property int brightnessLevel: {
- brightnessVersion;
- const deviceToUse = lastIpcDevice === "" ? getDefaultDevice() : (lastIpcDevice || currentDevice);
- if (!deviceToUse) {
- return 50;
- }
-
- return getDeviceBrightness(deviceToUse);
- }
- property int maxBrightness: 100
- property bool brightnessInitialized: false
- property bool suppressOsd: true
-
- signal brightnessChanged(bool showOsd)
- signal deviceSwitched
-
- property bool nightModeActive: nightModeEnabled
-
- property bool nightModeEnabled: false
- property bool automationAvailable: false
- property bool gammaControlAvailable: false
-
- property var gammaState: ({})
- property int gammaCurrentTemp: gammaState?.currentTemp ?? 0
- property string gammaNextTransition: gammaState?.nextTransition ?? ""
- property string gammaSunriseTime: gammaState?.sunriseTime ?? ""
- property string gammaSunsetTime: gammaState?.sunsetTime ?? ""
- property string gammaDawnTime: gammaState?.dawnTime ?? ""
- property string gammaNightTime: gammaState?.nightTime ?? ""
- property bool gammaIsDay: gammaState?.isDay ?? true
- property real gammaSunPosition: gammaState?.sunPosition ?? 0
- property int gammaLowTemp: gammaState?.config?.LowTemp ?? 0
- property int gammaHighTemp: gammaState?.config?.HighTemp ?? 0
-
- function markDeviceUserControlled(deviceId) {
- const newControlled = Object.assign({}, userControlledDevices);
- newControlled[deviceId] = Date.now();
- userControlledDevices = newControlled;
- }
-
- function isDeviceUserControlled(deviceId) {
- const controlTime = userControlledDevices[deviceId];
- if (!controlTime) {
- return false;
- }
- return (Date.now() - controlTime) < 1000;
- }
-
- function clearDeviceUserControlled(deviceId) {
- const newControlled = Object.assign({}, userControlledDevices);
- delete newControlled[deviceId];
- userControlledDevices = newControlled;
- }
-
- function markDevicePendingOsd(deviceId) {
- const newPending = Object.assign({}, pendingOsdDevices);
- newPending[deviceId] = true;
- pendingOsdDevices = newPending;
- }
-
- function clearDevicePendingOsd(deviceId) {
- const newPending = Object.assign({}, pendingOsdDevices);
- delete newPending[deviceId];
- pendingOsdDevices = newPending;
- }
-
- function updateSingleDevice(device) {
- if (device.class === "leds") {
- return;
- }
-
- const isUserControlled = isDeviceUserControlled(device.id);
- if (isUserControlled) {
- return;
- }
-
- const deviceIndex = devices.findIndex(d => d.id === device.id);
- if (deviceIndex !== -1) {
- const newDevices = [...devices];
- const cachedMax = deviceMaxCache[device.id];
-
- let displayMax = cachedMax || (device.class === "ddc" ? device.max : 100);
- if (displayMax > 0 && !cachedMax) {
- const newCache = Object.assign({}, deviceMaxCache);
- newCache[device.id] = displayMax;
- deviceMaxCache = newCache;
- }
-
- newDevices[deviceIndex] = {
- "id": device.id,
- "name": device.id,
- "class": device.class,
- "current": device.current,
- "percentage": device.currentPercent,
- "max": device.max,
- "backend": device.backend,
- "displayMax": displayMax
- };
- devices = newDevices;
- }
-
- const isExponential = SessionData.getBrightnessExponential(device.id);
- const userSetValue = deviceBrightnessUserSet[device.id];
-
- let displayValue = device.currentPercent;
- if (isExponential) {
- if (userSetValue !== undefined) {
- const exponent = SessionData.getBrightnessExponent(device.id);
- const expectedHardware = Math.round(Math.pow(userSetValue / 100.0, exponent) * 100.0);
- if (Math.abs(device.currentPercent - expectedHardware) > 2) {
- const newUserSet = Object.assign({}, deviceBrightnessUserSet);
- delete newUserSet[device.id];
- deviceBrightnessUserSet = newUserSet;
- SessionData.clearBrightnessUserSetValue(device.id);
- displayValue = linearToExponential(device.currentPercent, device.id);
- } else {
- displayValue = userSetValue;
- }
- } else {
- displayValue = linearToExponential(device.currentPercent, device.id);
- }
- }
-
- const oldValue = deviceBrightness[device.id];
- const newBrightness = Object.assign({}, deviceBrightness);
- newBrightness[device.id] = displayValue;
- deviceBrightness = newBrightness;
- brightnessVersion++;
-
- const isPendingOsd = pendingOsdDevices[device.id] === true;
- if (isPendingOsd) {
- clearDevicePendingOsd(device.id);
- if (!suppressOsd) {
- brightnessChanged(true);
- }
- return;
- }
-
- if (!brightnessInitialized || oldValue === displayValue) {
- return;
- }
- if (suppressOsd) {
- return;
- }
- brightnessChanged(true);
- }
-
- function updateFromBrightnessState(state) {
- if (!state || !state.devices) {
- return;
- }
-
- const newMaxCache = Object.assign({}, deviceMaxCache);
- devices = state.devices.map(d => {
- const cachedMax = deviceMaxCache[d.id];
- let displayMax = cachedMax || (d.class === "ddc" ? d.max : 100);
- if (displayMax > 0 && !cachedMax) {
- newMaxCache[d.id] = displayMax;
- }
- return {
- "id": d.id,
- "name": d.id,
- "class": d.class,
- "current": d.current,
- "percentage": d.currentPercent,
- "max": d.max,
- "backend": d.backend,
- "displayMax": displayMax
- };
- });
- deviceMaxCache = newMaxCache;
-
- const newBrightness = {};
- let anyDeviceBrightnessChanged = false;
-
- for (const device of state.devices) {
- const isExponential = SessionData.getBrightnessExponential(device.id);
- const userSetValue = deviceBrightnessUserSet[device.id];
- const oldValue = deviceBrightness[device.id];
-
- if (isExponential) {
- if (userSetValue !== undefined) {
- newBrightness[device.id] = userSetValue;
- } else {
- newBrightness[device.id] = linearToExponential(device.currentPercent, device.id);
- }
- } else {
- newBrightness[device.id] = device.currentPercent;
- }
-
- const newValue = newBrightness[device.id];
- if (oldValue !== undefined && oldValue !== newValue) {
- anyDeviceBrightnessChanged = true;
- }
- }
- deviceBrightness = newBrightness;
- brightnessVersion++;
-
- brightnessAvailable = devices.length > 0;
-
- if (devices.length > 0 && !currentDevice) {
- const lastDevice = SessionData.lastBrightnessDevice || "";
- const deviceExists = devices.some(d => d.id === lastDevice);
- if (deviceExists) {
- setCurrentDevice(lastDevice, false);
- } else {
- const backlight = devices.find(d => d.class === "backlight");
- const nonKbdDevice = devices.find(d => !d.id.includes("kbd"));
- const defaultDevice = backlight || nonKbdDevice || devices[0];
- setCurrentDevice(defaultDevice.id, false);
- }
- }
-
- const shouldShowOsd = brightnessInitialized && anyDeviceBrightnessChanged;
-
- if (!brightnessInitialized) {
- brightnessInitialized = true;
- }
-
- if (shouldShowOsd) {
- brightnessChanged(true);
- }
- }
-
- function setBrightness(percentage, device, suppressOsd) {
- const actualDevice = device === "" ? getDefaultDevice() : (device || currentDevice || getDefaultDevice());
- if (!actualDevice) {
- console.warn("DisplayService: No device selected for brightness change");
- return;
- }
-
- if (actualDevice !== lastIpcDevice) {
- lastIpcDevice = actualDevice;
- }
-
- const deviceInfo = getCurrentDeviceInfoByName(actualDevice);
- const isExponential = SessionData.getBrightnessExponential(actualDevice);
-
- let minValue = 0;
- let maxValue = 100;
-
- switch (true) {
- case isExponential:
- minValue = 1;
- maxValue = 100;
- break;
- default:
- minValue = (deviceInfo && (deviceInfo.class === "backlight" || deviceInfo.class === "ddc")) ? 1 : 0;
- maxValue = deviceInfo?.displayMax || 100;
- break;
- }
-
- if (maxValue <= 0) {
- console.warn("DisplayService: Invalid max value for device", actualDevice, "- skipping brightness change");
- return;
- }
-
- const clampedValue = Math.max(minValue, Math.min(maxValue, percentage));
-
- if (!DMSService.isConnected) {
- console.warn("DisplayService: Not connected to DMS");
- return;
- }
-
- const isLedDevice = deviceInfo?.class === "leds";
-
- if (suppressOsd) {
- markDeviceUserControlled(actualDevice);
- } else if (!isLedDevice) {
- markDevicePendingOsd(actualDevice);
- }
-
- const newBrightness = Object.assign({}, deviceBrightness);
- newBrightness[actualDevice] = clampedValue;
- deviceBrightness = newBrightness;
- brightnessVersion++;
-
- if (isLedDevice && !suppressOsd) {
- brightnessChanged(true);
- }
-
- if (isExponential) {
- const newUserSet = Object.assign({}, deviceBrightnessUserSet);
- newUserSet[actualDevice] = clampedValue;
- deviceBrightnessUserSet = newUserSet;
- SessionData.setBrightnessUserSetValue(actualDevice, clampedValue);
- }
-
- const params = {
- "device": actualDevice,
- "percent": clampedValue
- };
- if (isExponential) {
- params.exponential = true;
- params.exponent = SessionData.getBrightnessExponent(actualDevice);
- }
-
- DMSService.sendRequest("brightness.setBrightness", params, response => {
- if (response.error) {
- console.error("DisplayService: Failed to set brightness:", response.error);
- ToastService.showError(I18n.tr("Failed to set brightness"), response.error, "", "brightness");
- } else {
- ToastService.dismissCategory("brightness");
- }
- });
- }
-
- function setCurrentDevice(deviceName, saveToSession = false) {
- if (currentDevice === deviceName) {
- return;
- }
-
- currentDevice = deviceName;
- lastIpcDevice = deviceName;
-
- if (saveToSession) {
- SessionData.setLastBrightnessDevice(deviceName);
- }
-
- deviceSwitched();
- }
-
- function getDeviceBrightness(deviceName) {
- if (!deviceName) {
- return 50;
- }
-
- if (deviceName in deviceBrightness) {
- return deviceBrightness[deviceName];
- }
-
- return 50;
- }
-
- function linearToExponential(linearPercent, deviceName) {
- const exponent = SessionData.getBrightnessExponent(deviceName);
- const hardwarePercent = linearPercent / 100.0;
- const normalizedPercent = Math.pow(hardwarePercent, 1.0 / exponent);
- return Math.round(normalizedPercent * 100.0);
- }
-
- function getDefaultDevice() {
- for (const device of devices) {
- if (device.class === "backlight") {
- return device.id;
- }
- }
- return devices.length > 0 ? devices[0].id : "";
- }
-
- function getPinnedDeviceForFocusedScreen() {
- const focusedScreen = CompositorService.getFocusedScreen();
- if (!focusedScreen)
- return "";
-
- const pins = SettingsData.brightnessDevicePins || {};
- const screenKey = SettingsData.getScreenDisplayName(focusedScreen);
- if (!screenKey)
- return "";
-
- const pinnedDevice = pins[screenKey];
- if (!pinnedDevice)
- return "";
-
- const deviceExists = devices.some(d => d.id === pinnedDevice);
- if (!deviceExists)
- return "";
-
- return pinnedDevice;
- }
-
- function getPreferredDevice() {
- const pinned = getPinnedDeviceForFocusedScreen();
- if (pinned)
- return pinned;
-
- return getDefaultDevice();
- }
-
- function getCurrentDeviceInfo() {
- const deviceToUse = lastIpcDevice === "" ? getDefaultDevice() : (lastIpcDevice || currentDevice);
- if (!deviceToUse) {
- return null;
- }
-
- for (const device of devices) {
- if (device.id === deviceToUse) {
- return device;
- }
- }
- return null;
- }
-
- function isCurrentDeviceReady() {
- const deviceToUse = lastIpcDevice === "" ? getDefaultDevice() : (lastIpcDevice || currentDevice);
- return deviceToUse !== "";
- }
-
- function getCurrentDeviceInfoByName(deviceName) {
- if (!deviceName) {
- return null;
- }
-
- for (const device of devices) {
- if (device.id === deviceName) {
- return device;
- }
- }
- return null;
- }
-
- function getDeviceMax(deviceName) {
- const deviceInfo = getCurrentDeviceInfoByName(deviceName);
- if (!deviceInfo) {
- return 100;
- }
- return deviceInfo.displayMax || 100;
- }
-
- // Night Mode Functions - Simplified
- function enableNightMode() {
- if (!gammaControlAvailable) {
- ToastService.showWarning("Night mode failed: DMS gamma control not available");
- return;
- }
-
- nightModeEnabled = true;
- SessionData.setNightModeEnabled(true);
-
- DMSService.sendRequest("wayland.gamma.setEnabled", {
- "enabled": true
- }, response => {
- if (response.error) {
- console.error("DisplayService: Failed to enable gamma control:", response.error);
- ToastService.showError(I18n.tr("Failed to enable night mode"), response.error, "", "night-mode");
- nightModeEnabled = false;
- SessionData.setNightModeEnabled(false);
- return;
- }
- ToastService.dismissCategory("night-mode");
-
- if (SessionData.nightModeAutoEnabled) {
- startAutomation();
- } else {
- applyNightModeDirectly();
- }
- });
- }
-
- function disableNightMode() {
- nightModeEnabled = false;
- SessionData.setNightModeEnabled(false);
-
- if (!gammaControlAvailable) {
- return;
- }
-
- DMSService.sendRequest("wayland.gamma.setEnabled", {
- "enabled": false
- }, response => {
- if (response.error) {
- console.error("DisplayService: Failed to disable gamma control:", response.error);
- ToastService.showError(I18n.tr("Failed to disable night mode"), response.error, "", "night-mode");
- } else {
- ToastService.dismissCategory("night-mode");
- }
- });
- }
-
- function toggleNightMode() {
- if (nightModeEnabled) {
- disableNightMode();
- } else {
- enableNightMode();
- }
- }
-
- function applyNightModeDirectly() {
- const temperature = SessionData.nightModeTemperature || 4000;
-
- DMSService.sendRequest("wayland.gamma.setManualTimes", {
- "sunrise": null,
- "sunset": null
- }, response => {
- if (response.error) {
- console.error("DisplayService: Failed to clear manual times:", response.error);
- return;
- }
-
- DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
- "use": false
- }, response => {
- if (response.error) {
- console.error("DisplayService: Failed to disable IP location:", response.error);
- return;
- }
-
- DMSService.sendRequest("wayland.gamma.setTemperature", {
- "low": temperature,
- "high": temperature
- }, response => {
- if (response.error) {
- console.error("DisplayService: Failed to set temperature:", response.error);
- ToastService.showError(I18n.tr("Failed to set night mode temperature"), response.error, "", "night-mode");
- } else {
- ToastService.dismissCategory("night-mode");
- }
- });
- });
- });
- }
-
- function startAutomation() {
- if (!automationAvailable) {
- return;
- }
-
- const mode = SessionData.nightModeAutoMode || "time";
-
- switch (mode) {
- case "time":
- startTimeBasedMode();
- break;
- case "location":
- startLocationBasedMode();
- break;
- }
- }
-
- function startTimeBasedMode() {
- const temperature = SessionData.nightModeTemperature || 4000;
- const highTemp = SessionData.nightModeHighTemperature || 6500;
- const sunriseHour = SessionData.nightModeEndHour;
- const sunriseMinute = SessionData.nightModeEndMinute;
- const sunsetHour = SessionData.nightModeStartHour;
- const sunsetMinute = SessionData.nightModeStartMinute;
-
- const sunrise = `${String(sunriseHour).padStart(2, '0')}:${String(sunriseMinute).padStart(2, '0')}`;
- const sunset = `${String(sunsetHour).padStart(2, '0')}:${String(sunsetMinute).padStart(2, '0')}`;
-
- DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
- "use": false
- }, response => {
- if (response.error) {
- console.error("DisplayService: Failed to disable IP location:", response.error);
- return;
- }
-
- DMSService.sendRequest("wayland.gamma.setTemperature", {
- "low": temperature,
- "high": highTemp
- }, response => {
- if (response.error) {
- console.error("DisplayService: Failed to set temperature:", response.error);
- ToastService.showError(I18n.tr("Failed to set night mode temperature"), response.error, "", "night-mode");
- return;
- }
-
- DMSService.sendRequest("wayland.gamma.setManualTimes", {
- "sunrise": sunrise,
- "sunset": sunset
- }, response => {
- if (response.error) {
- console.error("DisplayService: Failed to set manual times:", response.error);
- ToastService.showError(I18n.tr("Failed to set night mode schedule"), response.error, "", "night-mode");
- } else {
- ToastService.dismissCategory("night-mode");
- }
- });
- });
- });
- }
-
- function startLocationBasedMode() {
- const temperature = SessionData.nightModeTemperature || 4000;
- const highTemp = SessionData.nightModeHighTemperature || 6500;
-
- DMSService.sendRequest("wayland.gamma.setManualTimes", {
- "sunrise": null,
- "sunset": null
- }, response => {
- if (response.error) {
- console.error("DisplayService: Failed to clear manual times:", response.error);
- return;
- }
-
- DMSService.sendRequest("wayland.gamma.setTemperature", {
- "low": temperature,
- "high": highTemp
- }, response => {
- if (response.error) {
- console.error("DisplayService: Failed to set temperature:", response.error);
- ToastService.showError(I18n.tr("Failed to set night mode temperature"), response.error, "", "night-mode");
- return;
- }
-
- if (SessionData.nightModeUseIPLocation) {
- DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
- "use": true
- }, response => {
- if (response.error) {
- console.error("DisplayService: Failed to enable IP location:", response.error);
- ToastService.showError(I18n.tr("Failed to enable IP location"), response.error, "", "night-mode");
- } else {
- ToastService.dismissCategory("night-mode");
- }
- });
- } else if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) {
- DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
- "use": false
- }, response => {
- if (response.error) {
- console.error("DisplayService: Failed to disable IP location:", response.error);
- return;
- }
-
- DMSService.sendRequest("wayland.gamma.setLocation", {
- "latitude": SessionData.latitude,
- "longitude": SessionData.longitude
- }, response => {
- if (response.error) {
- console.error("DisplayService: Failed to set location:", response.error);
- ToastService.showError(I18n.tr("Failed to set night mode location"), response.error, "", "night-mode");
- } else {
- ToastService.dismissCategory("night-mode");
- }
- });
- });
- } else {
- console.warn("DisplayService: Location mode selected but no coordinates set and IP location disabled");
- }
- });
- });
- }
-
- function setNightModeAutomationMode(mode) {
- SessionData.setNightModeAutoMode(mode);
- }
-
- function evaluateNightMode() {
- if (!nightModeEnabled) {
- return;
- }
-
- if (SessionData.nightModeAutoEnabled) {
- restartTimer.nextAction = "automation";
- restartTimer.start();
- } else {
- restartTimer.nextAction = "direct";
- restartTimer.start();
- }
- }
-
- function checkGammaControlAvailability() {
- if (!DMSService.isConnected) {
- return;
- }
-
- if (DMSService.apiVersion < 6) {
- gammaControlAvailable = false;
- automationAvailable = false;
- return;
- }
-
- if (!DMSService.capabilities.includes("gamma")) {
- gammaControlAvailable = false;
- automationAvailable = false;
- return;
- }
-
- DMSService.sendRequest("wayland.gamma.getState", null, response => {
- if (response.error) {
- gammaControlAvailable = false;
- automationAvailable = false;
- console.error("DisplayService: Gamma control not available:", response.error);
- } else {
- gammaControlAvailable = true;
- automationAvailable = true;
-
- if (nightModeEnabled) {
- DMSService.sendRequest("wayland.gamma.setEnabled", {
- "enabled": true
- }, enableResponse => {
- if (enableResponse.error) {
- console.error("DisplayService: Failed to enable gamma control on startup:", enableResponse.error);
- return;
- }
-
- evaluateNightMode();
- });
- }
- }
- });
- }
-
- Timer {
- id: restartTimer
- property string nextAction: ""
- interval: 250
- repeat: false
-
- onTriggered: {
- if (nextAction === "automation") {
- startAutomation();
- } else if (nextAction === "direct") {
- applyNightModeDirectly();
- }
- nextAction = "";
- }
- }
-
- function rescanDevices() {
- if (!DMSService.isConnected) {
- return;
- }
-
- DMSService.sendRequest("brightness.rescan", null, response => {
- if (response.error) {
- console.error("DisplayService: Failed to rescan brightness devices:", response.error);
- }
- });
- }
-
- function updateDeviceBrightnessDisplay(deviceName) {
- brightnessVersion++;
- brightnessChanged();
- }
-
- Timer {
- id: osdSuppressTimer
- interval: 2000
- running: true
- onTriggered: suppressOsd = false
- }
-
- Component.onCompleted: {
- nightModeEnabled = SessionData.nightModeEnabled;
- deviceBrightnessUserSet = Object.assign({}, SessionData.brightnessUserSetValues);
- if (DMSService.isConnected) {
- checkGammaControlAvailability();
- }
- }
-
- Timer {
- id: screenChangeRescanTimer
- property int rescanAttempt: 0
- interval: 3000
- repeat: false
- onTriggered: {
- rescanDevices();
- rescanAttempt++;
- if (rescanAttempt < 3) {
- interval = rescanAttempt === 1 ? 5000 : 8000;
- restart();
- } else {
- rescanAttempt = 0;
- interval = 3000;
- }
- }
- }
-
- Connections {
- target: Quickshell
-
- function onScreensChanged() {
- screenChangeRescanTimer.rescanAttempt = 0;
- screenChangeRescanTimer.interval = 3000;
- screenChangeRescanTimer.restart();
- }
- }
-
- Connections {
- target: DMSService
-
- function onConnectionStateChanged() {
- if (DMSService.isConnected) {
- checkGammaControlAvailability();
- } else {
- brightnessAvailable = false;
- gammaControlAvailable = false;
- automationAvailable = false;
- }
- }
-
- function onCapabilitiesReceived() {
- checkGammaControlAvailability();
- }
-
- function onBrightnessStateUpdate(data) {
- updateFromBrightnessState(data);
- }
-
- function onBrightnessDeviceUpdate(device) {
- updateSingleDevice(device);
- }
-
- function onLoginctlEvent(event) {
- if (event.event === "unlock" || event.event === "resume") {
- suppressOsd = true;
- osdSuppressTimer.restart();
- evaluateNightMode();
- }
- }
-
- function onGammaStateUpdate(data) {
- root.gammaState = data;
- }
- }
-
- // Session Data Connections
- Connections {
- target: SessionData
-
- function onNightModeEnabledChanged() {
- nightModeEnabled = SessionData.nightModeEnabled;
- evaluateNightMode();
- }
-
- function onNightModeAutoEnabledChanged() {
- evaluateNightMode();
- }
- function onNightModeAutoModeChanged() {
- evaluateNightMode();
- }
- function onNightModeStartHourChanged() {
- evaluateNightMode();
- }
- function onNightModeStartMinuteChanged() {
- evaluateNightMode();
- }
- function onNightModeEndHourChanged() {
- evaluateNightMode();
- }
- function onNightModeEndMinuteChanged() {
- evaluateNightMode();
- }
- function onNightModeTemperatureChanged() {
- evaluateNightMode();
- }
- function onNightModeHighTemperatureChanged() {
- evaluateNightMode();
- }
- function onLatitudeChanged() {
- evaluateNightMode();
- }
- function onLongitudeChanged() {
- evaluateNightMode();
- }
- function onNightModeUseIPLocationChanged() {
- evaluateNightMode();
- }
- }
-
- // IPC Handler for external control
- IpcHandler {
- function set(percentage: string, device: string): string {
- if (!root.brightnessAvailable)
- return "Brightness control not available";
-
- const value = parseInt(percentage);
- if (isNaN(value))
- return "Invalid brightness value: " + percentage;
-
- const actualDevice = device || root.getPreferredDevice();
-
- if (actualDevice && !root.devices.some(d => d.id === actualDevice))
- return "Device not found: " + actualDevice;
-
- const deviceInfo = actualDevice ? root.getCurrentDeviceInfoByName(actualDevice) : null;
- const minValue = (deviceInfo && (deviceInfo.class === "backlight" || deviceInfo.class === "ddc")) ? 1 : 0;
- const clampedValue = Math.max(minValue, Math.min(100, value));
-
- root.lastIpcDevice = actualDevice;
- if (actualDevice && actualDevice !== root.currentDevice)
- root.setCurrentDevice(actualDevice, false);
-
- root.setBrightness(clampedValue, actualDevice);
-
- return actualDevice ? "Brightness set to " + clampedValue + "% on " + actualDevice : "Brightness set to " + clampedValue + "%";
- }
-
- function increment(step: string, device: string): string {
- if (!root.brightnessAvailable)
- return "Brightness control not available";
-
- const actualDevice = device || root.getPreferredDevice();
-
- if (actualDevice && !root.devices.some(d => d.id === actualDevice))
- return "Device not found: " + actualDevice;
-
- const stepValue = parseInt(step || "5");
-
- root.lastIpcDevice = actualDevice;
- if (actualDevice && actualDevice !== root.currentDevice)
- root.setCurrentDevice(actualDevice, false);
-
- const isExponential = SessionData.getBrightnessExponential(actualDevice);
- const currentBrightness = root.getDeviceBrightness(actualDevice);
- const deviceInfo = root.getCurrentDeviceInfoByName(actualDevice);
-
- const maxValue = isExponential ? 100 : (deviceInfo?.displayMax || 100);
- const newBrightness = Math.min(maxValue, currentBrightness + stepValue);
-
- root.setBrightness(newBrightness, actualDevice);
-
- return "Brightness increased by " + stepValue + "%" + (device ? " on " + actualDevice : "");
- }
-
- function decrement(step: string, device: string): string {
- if (!root.brightnessAvailable)
- return "Brightness control not available";
-
- const actualDevice = device || root.getPreferredDevice();
-
- if (actualDevice && !root.devices.some(d => d.id === actualDevice))
- return "Device not found: " + actualDevice;
-
- const stepValue = parseInt(step || "5");
-
- root.lastIpcDevice = actualDevice;
- if (actualDevice && actualDevice !== root.currentDevice)
- root.setCurrentDevice(actualDevice, false);
-
- const isExponential = SessionData.getBrightnessExponential(actualDevice);
- const currentBrightness = root.getDeviceBrightness(actualDevice);
- const deviceInfo = root.getCurrentDeviceInfoByName(actualDevice);
-
- let minValue = 0;
- switch (true) {
- case isExponential:
- minValue = 1;
- break;
- case deviceInfo && (deviceInfo.class === "backlight" || deviceInfo.class === "ddc"):
- minValue = 1;
- break;
- default:
- minValue = 0;
- break;
- }
-
- const newBrightness = Math.max(minValue, currentBrightness - stepValue);
-
- root.setBrightness(newBrightness, actualDevice);
-
- return "Brightness decreased by " + stepValue + "%" + (device ? " on " + actualDevice : "");
- }
-
- function status(): string {
- if (!root.brightnessAvailable) {
- return "Brightness control not available";
- }
-
- return "Device: " + root.currentDevice + " - Brightness: " + root.brightnessLevel + "%";
- }
-
- function list(): string {
- if (!root.brightnessAvailable) {
- return "No brightness devices available";
- }
-
- let result = "Available devices:\n";
- for (const device of root.devices) {
- const isExp = SessionData.getBrightnessExponential(device.id);
- result += device.id + " (" + device.class + ")" + (isExp ? " [exponential]" : "") + "\n";
- }
- return result;
- }
-
- function enableExponential(device: string): string {
- const targetDevice = device || root.currentDevice;
- if (!targetDevice) {
- return "No device specified";
- }
-
- if (!root.devices.some(d => d.id === targetDevice)) {
- return "Device not found: " + targetDevice;
- }
-
- SessionData.setBrightnessExponential(targetDevice, true);
- return "Exponential mode enabled for " + targetDevice;
- }
-
- function disableExponential(device: string): string {
- const targetDevice = device || root.currentDevice;
- if (!targetDevice) {
- return "No device specified";
- }
-
- if (!root.devices.some(d => d.id === targetDevice)) {
- return "Device not found: " + targetDevice;
- }
-
- SessionData.setBrightnessExponential(targetDevice, false);
- return "Exponential mode disabled for " + targetDevice;
- }
-
- function toggleExponential(device: string): string {
- const targetDevice = device || root.currentDevice;
- if (!targetDevice) {
- return "No device specified";
- }
-
- if (!root.devices.some(d => d.id === targetDevice)) {
- return "Device not found: " + targetDevice;
- }
-
- const currentState = SessionData.getBrightnessExponential(targetDevice);
- SessionData.setBrightnessExponential(targetDevice, !currentState);
- return "Exponential mode " + (!currentState ? "enabled" : "disabled") + " for " + targetDevice;
- }
-
- target: "brightness"
- }
-
- IpcHandler {
- function toggle(): string {
- root.toggleNightMode();
- return root.nightModeEnabled ? "Night mode enabled" : "Night mode disabled";
- }
-
- function enable(): string {
- root.enableNightMode();
- return "Night mode enabled";
- }
-
- function disable(): string {
- root.disableNightMode();
- return "Night mode disabled";
- }
-
- function status(): string {
- if (!root.gammaControlAvailable)
- return "Night mode: unavailable (no gamma control)";
-
- const parts = ["Night mode: " + (root.nightModeEnabled ? "enabled" : "disabled")];
-
- if (root.gammaCurrentTemp > 0)
- parts.push("Current temperature: " + root.gammaCurrentTemp + "K");
-
- parts.push("Target night temperature: " + SessionData.nightModeTemperature + "K");
-
- if (SessionData.nightModeAutoEnabled) {
- parts.push("Target day temperature: " + SessionData.nightModeHighTemperature + "K");
- parts.push("Automation: " + SessionData.nightModeAutoMode);
- parts.push("Period: " + (root.gammaIsDay ? "day" : "night"));
-
- if (root.gammaNextTransition)
- parts.push("Next transition: " + root.gammaNextTransition);
- if (root.gammaSunriseTime)
- parts.push("Sunrise: " + root.gammaSunriseTime);
- if (root.gammaSunsetTime)
- parts.push("Sunset: " + root.gammaSunsetTime);
- }
-
- return parts.join("\n");
- }
-
- function getCurrentTemp(): string {
- if (!root.gammaControlAvailable)
- return "Gamma control not available";
- if (root.gammaCurrentTemp <= 0)
- return "No current temperature reported";
- return root.gammaCurrentTemp.toString();
- }
-
- function getTargetTemp(): string {
- return SessionData.nightModeTemperature.toString();
- }
-
- function getDayTemp(): string {
- return SessionData.nightModeHighTemperature.toString();
- }
-
- function setTargetTemp(value: string): string {
- if (!value)
- return "Usage: night setTargetTemp <2500-6000>";
-
- const temp = parseInt(value);
- if (isNaN(temp))
- return "Invalid temperature: " + value;
- if (temp < 2500 || temp > 6000)
- return "Temperature must be between 2500K and 6000K";
-
- const rounded = Math.round(temp / 500) * 500;
- SessionData.setNightModeTemperature(rounded);
-
- if (root.nightModeEnabled) {
- switch (true) {
- case SessionData.nightModeAutoEnabled:
- root.startAutomation();
- break;
- default:
- root.applyNightModeDirectly();
- break;
- }
- }
-
- if (rounded !== temp)
- return "Night temperature set to " + rounded + "K (rounded from " + temp + "K)";
- return "Night temperature set to " + rounded + "K";
- }
-
- function setDayTemp(value: string): string {
- if (!value)
- return "Usage: night setDayTemp <2500-6500>";
-
- const temp = parseInt(value);
- if (isNaN(temp))
- return "Invalid temperature: " + value;
- if (temp < 2500 || temp > 6500)
- return "Temperature must be between 2500K and 6500K";
-
- const rounded = Math.round(temp / 500) * 500;
- SessionData.setNightModeHighTemperature(rounded);
-
- if (root.nightModeEnabled && SessionData.nightModeAutoEnabled)
- root.startAutomation();
-
- if (rounded !== temp)
- return "Day temperature set to " + rounded + "K (rounded from " + temp + "K)";
- return "Day temperature set to " + rounded + "K";
- }
-
- function getSchedule(): string {
- if (!SessionData.nightModeAutoEnabled)
- return "Automation disabled";
-
- const parts = ["Mode: " + SessionData.nightModeAutoMode];
- parts.push("Period: " + (root.gammaIsDay ? "day" : "night"));
-
- if (root.gammaDawnTime)
- parts.push("Dawn: " + root.gammaDawnTime);
- if (root.gammaSunriseTime)
- parts.push("Sunrise: " + root.gammaSunriseTime);
- if (root.gammaSunsetTime)
- parts.push("Sunset: " + root.gammaSunsetTime);
- if (root.gammaNightTime)
- parts.push("Night: " + root.gammaNightTime);
- if (root.gammaNextTransition)
- parts.push("Next transition: " + root.gammaNextTransition);
- if (root.gammaSunPosition > 0)
- parts.push("Sun position: " + root.gammaSunPosition.toFixed(2) + "°");
-
- return parts.join("\n");
- }
-
- target: "night"
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DwlService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DwlService.qml
deleted file mode 100644
index 564e561..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/DwlService.qml
+++ /dev/null
@@ -1,454 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtCore
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation))
- readonly property string mangoDmsDir: configDir + "/mango/dms"
- readonly property string outputsPath: mangoDmsDir + "/outputs.conf"
- readonly property string layoutPath: mangoDmsDir + "/layout.conf"
- readonly property string cursorPath: mangoDmsDir + "/cursor.conf"
-
- property int _lastGapValue: -1
-
- property bool dwlAvailable: false
- property var outputs: ({})
- property var tagCount: 9
- property var layouts: []
- property string activeOutput: ""
- property var outputScales: ({})
- property string currentKeyboardLayout: {
- if (!outputs || !activeOutput)
- return "";
- const output = outputs[activeOutput];
- return (output && output.kbLayout) || "";
- }
-
- signal stateChanged
-
- Connections {
- target: SettingsData
- function onBarConfigsChanged() {
- if (!CompositorService.isDwl)
- return;
- const newGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4));
- if (newGaps === root._lastGapValue)
- return;
- root._lastGapValue = newGaps;
- generateLayoutConfig();
- }
- }
-
- Connections {
- target: CompositorService
- function onIsDwlChanged() {
- if (CompositorService.isDwl)
- generateLayoutConfig();
- }
- }
-
- Connections {
- target: DMSService
- function onCapabilitiesReceived() {
- checkCapabilities();
- }
- function onConnectionStateChanged() {
- if (DMSService.isConnected) {
- checkCapabilities();
- } else {
- dwlAvailable = false;
- }
- }
- function onDwlStateUpdate(data) {
- if (dwlAvailable) {
- handleStateUpdate(data);
- }
- }
- }
-
- Component.onCompleted: {
- if (DMSService.dmsAvailable)
- checkCapabilities();
- if (dwlAvailable)
- refreshOutputScales();
- if (CompositorService.isDwl)
- Qt.callLater(generateLayoutConfig);
- }
-
- function checkCapabilities() {
- if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) {
- dwlAvailable = false;
- return;
- }
-
- const hasDwl = DMSService.capabilities.includes("dwl");
- if (hasDwl && !dwlAvailable) {
- dwlAvailable = true;
- console.info("DwlService: DWL capability detected");
- requestState();
- refreshOutputScales();
- } else if (!hasDwl) {
- dwlAvailable = false;
- }
- }
-
- function requestState() {
- if (!DMSService.isConnected || !dwlAvailable) {
- return;
- }
-
- DMSService.sendRequest("dwl.getState", null, response => {
- if (response.result) {
- handleStateUpdate(response.result);
- }
- });
- }
-
- function handleStateUpdate(state) {
- outputs = state.outputs || {};
- tagCount = state.tagCount || 9;
- layouts = state.layouts || [];
- activeOutput = state.activeOutput || "";
- stateChanged();
- }
-
- function setTags(outputName, tagmask, toggleTagset) {
- if (!DMSService.isConnected || !dwlAvailable) {
- return;
- }
-
- DMSService.sendRequest("dwl.setTags", {
- "output": outputName,
- "tagmask": tagmask,
- "toggleTagset": toggleTagset
- }, response => {
- if (response.error) {
- console.warn("DwlService: setTags error:", response.error);
- }
- });
- }
-
- function setClientTags(outputName, andTags, xorTags) {
- if (!DMSService.isConnected || !dwlAvailable) {
- return;
- }
-
- DMSService.sendRequest("dwl.setClientTags", {
- "output": outputName,
- "andTags": andTags,
- "xorTags": xorTags
- }, response => {
- if (response.error) {
- console.warn("DwlService: setClientTags error:", response.error);
- }
- });
- }
-
- function setLayout(outputName, index) {
- if (!DMSService.isConnected || !dwlAvailable) {
- return;
- }
-
- DMSService.sendRequest("dwl.setLayout", {
- "output": outputName,
- "index": index
- }, response => {
- if (response.error) {
- console.warn("DwlService: setLayout error:", response.error);
- }
- });
- }
-
- function getOutputState(outputName) {
- if (!outputs || !outputs[outputName]) {
- return null;
- }
- return outputs[outputName];
- }
-
- function getActiveTags(outputName) {
- const output = getOutputState(outputName);
- if (!output || !output.tags) {
- return [];
- }
- return output.tags.filter(tag => tag.state === 1).map(tag => tag.tag);
- }
-
- function getTagsWithClients(outputName) {
- const output = getOutputState(outputName);
- if (!output || !output.tags) {
- return [];
- }
- return output.tags.filter(tag => tag.clients > 0).map(tag => tag.tag);
- }
-
- function getUrgentTags(outputName) {
- const output = getOutputState(outputName);
- if (!output || !output.tags) {
- return [];
- }
- return output.tags.filter(tag => tag.state === 2).map(tag => tag.tag);
- }
-
- function switchToTag(outputName, tagIndex) {
- const tagmask = 1 << tagIndex;
- setTags(outputName, tagmask, 0);
- }
-
- function toggleTag(outputName, tagIndex) {
- const output = getOutputState(outputName);
- if (!output || !output.tags) {
- console.log("toggleTag: no output or tags for", outputName);
- return;
- }
-
- let currentMask = 0;
- output.tags.forEach(tag => {
- if (tag.state === 1) {
- currentMask |= (1 << tag.tag);
- }
- });
-
- const clickedMask = 1 << tagIndex;
- const newMask = currentMask ^ clickedMask;
-
- console.log("toggleTag:", outputName, "tag:", tagIndex, "currentMask:", currentMask.toString(2), "clickedMask:", clickedMask.toString(2), "newMask:", newMask.toString(2));
-
- if (newMask === 0) {
- console.log("toggleTag: newMask is 0, switching to tag", tagIndex);
- setTags(outputName, 1 << tagIndex, 0);
- } else {
- console.log("toggleTag: setting combined mask", newMask);
- setTags(outputName, newMask, 0);
- }
- }
-
- function quit() {
- Quickshell.execDetached(["mmsg", "-d", "quit"]);
- }
-
- Process {
- id: scaleQueryProcess
- command: ["mmsg", "-A"]
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- try {
- const newScales = {};
- const lines = text.trim().split('\n');
- for (const line of lines) {
- const parts = line.trim().split(/\s+/);
- if (parts.length >= 3 && parts[1] === "scale_factor") {
- const outputName = parts[0];
- const scale = parseFloat(parts[2]);
- if (!isNaN(scale)) {
- newScales[outputName] = scale;
- }
- }
- }
- outputScales = newScales;
- } catch (e) {
- console.warn("DwlService: Failed to parse mmsg output:", e);
- }
- }
- }
-
- onExited: exitCode => {
- if (exitCode !== 0) {
- console.warn("DwlService: mmsg failed with exit code:", exitCode);
- }
- }
- }
-
- function refreshOutputScales() {
- if (!dwlAvailable)
- return;
- scaleQueryProcess.running = true;
- }
-
- function getOutputScale(outputName) {
- return outputScales[outputName];
- }
-
- function getVisibleTags(outputName) {
- const output = getOutputState(outputName);
- if (!output || !output.tags) {
- return [];
- }
-
- const visibleTags = new Set();
-
- output.tags.forEach(tag => {
- if (tag.state === 1 || tag.clients > 0) {
- visibleTags.add(tag.tag);
- }
- });
-
- return Array.from(visibleTags).sort((a, b) => a - b);
- }
-
- function generateOutputsConfig(outputsData) {
- if (!outputsData || Object.keys(outputsData).length === 0)
- return;
- let lines = ["# Auto-generated by DMS - do not edit manually", ""];
-
- for (const outputName in outputsData) {
- const output = outputsData[outputName];
- if (!output)
- continue;
- let width = 1920;
- let height = 1080;
- let refreshRate = 60;
- if (output.modes && output.current_mode !== undefined) {
- const mode = output.modes[output.current_mode];
- if (mode) {
- width = mode.width || 1920;
- height = mode.height || 1080;
- refreshRate = Math.round((mode.refresh_rate || 60000) / 1000);
- }
- }
-
- const x = output.logical?.x ?? 0;
- const y = output.logical?.y ?? 0;
- const scale = output.logical?.scale ?? 1.0;
- const transform = transformToMango(output.logical?.transform ?? "Normal");
- const vrr = output.vrr_enabled ? 1 : 0;
-
- const rule = ["name:" + outputName, "width:" + width, "height:" + height, "refresh:" + refreshRate, "x:" + x, "y:" + y, "scale:" + scale, "rr:" + transform, "vrr:" + vrr].join(",");
-
- lines.push("monitorrule=" + rule);
- }
-
- lines.push("");
-
- const content = lines.join("\n");
-
- Proc.runCommand("mango-write-outputs", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
- if (exitCode !== 0) {
- console.warn("DwlService: Failed to write outputs config:", output);
- return;
- }
- console.info("DwlService: Generated outputs config at", outputsPath);
- if (CompositorService.isDwl)
- reloadConfig();
- });
- }
-
- function reloadConfig() {
- Proc.runCommand("mango-reload", ["mmsg", "-d", "reload_config"], (output, exitCode) => {
- if (exitCode !== 0)
- console.warn("DwlService: mmsg reload_config failed:", output);
- });
- }
-
- function generateLayoutConfig() {
- if (!CompositorService.isDwl)
- return;
-
- const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12;
- const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4;
- const defaultBorderSize = 2;
-
- const cornerRadius = (typeof SettingsData !== "undefined" && SettingsData.mangoLayoutRadiusOverride >= 0) ? SettingsData.mangoLayoutRadiusOverride : defaultRadius;
- const gaps = (typeof SettingsData !== "undefined" && SettingsData.mangoLayoutGapsOverride >= 0) ? SettingsData.mangoLayoutGapsOverride : defaultGaps;
- const borderSize = (typeof SettingsData !== "undefined" && SettingsData.mangoLayoutBorderSize >= 0) ? SettingsData.mangoLayoutBorderSize : defaultBorderSize;
-
- let content = `# Auto-generated by DMS - do not edit manually
-border_radius=${cornerRadius}
-gappih=${gaps}
-gappiv=${gaps}
-gappoh=${gaps}
-gappov=${gaps}
-borderpx=${borderSize}
-`;
-
- Proc.runCommand("mango-write-layout", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${layoutPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
- if (exitCode !== 0) {
- console.warn("DwlService: Failed to write layout config:", output);
- return;
- }
- console.info("DwlService: Generated layout config at", layoutPath);
- reloadConfig();
- });
- }
-
- function transformToMango(transform) {
- switch (transform) {
- case "Normal":
- return 0;
- case "90":
- return 1;
- case "180":
- return 2;
- case "270":
- return 3;
- case "Flipped":
- return 4;
- case "Flipped90":
- return 5;
- case "Flipped180":
- return 6;
- case "Flipped270":
- return 7;
- default:
- return 0;
- }
- }
-
- function generateCursorConfig() {
- if (!CompositorService.isDwl)
- return;
-
- console.log("DwlService: Generating cursor config...");
-
- const settings = typeof SettingsData !== "undefined" ? SettingsData.cursorSettings : null;
- if (!settings) {
- Proc.runCommand("mango-write-cursor", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => {
- if (exitCode !== 0)
- console.warn("DwlService: Failed to write cursor config:", output);
- });
- return;
- }
-
- const themeName = settings.theme === "System Default" ? (SettingsData.systemDefaultCursorTheme || "") : settings.theme;
- const size = settings.size || 24;
- const hideTimeout = settings.dwl?.cursorHideTimeout || 0;
-
- const isDefaultConfig = !themeName && size === 24 && hideTimeout === 0;
- if (isDefaultConfig) {
- Proc.runCommand("mango-write-cursor", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => {
- if (exitCode !== 0)
- console.warn("DwlService: Failed to write cursor config:", output);
- });
- return;
- }
-
- let content = `# Auto-generated by DMS - do not edit manually
-cursor_size=${size}`;
-
- if (themeName)
- content += `\ncursor_theme=${themeName}`;
-
- if (hideTimeout > 0)
- content += `\ncursor_hide_timeout=${hideTimeout}`;
-
- content += `\n`;
-
- Proc.runCommand("mango-write-cursor", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${cursorPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
- if (exitCode !== 0) {
- console.warn("DwlService: Failed to write cursor config:", output);
- return;
- }
- console.info("DwlService: Generated cursor config at", cursorPath);
- reloadConfig();
- });
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ExtWorkspaceService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ExtWorkspaceService.qml
deleted file mode 100644
index 48a8f9a..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ExtWorkspaceService.qml
+++ /dev/null
@@ -1,277 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-
-Singleton {
- id: root
-
- property bool extWorkspaceAvailable: false
- property var groups: []
- property var _cachedWorkspaces: ({})
-
- signal stateChanged
-
- Connections {
- target: DMSService
- function onCapabilitiesReceived() {
- checkCapabilities();
- }
- function onConnectionStateChanged() {
- if (DMSService.isConnected) {
- checkCapabilities();
- } else {
- extWorkspaceAvailable = false;
- }
- }
- function onExtWorkspaceStateUpdate(data) {
- if (extWorkspaceAvailable) {
- handleStateUpdate(data);
- }
- }
- }
-
- Component.onCompleted: {
- if (DMSService.dmsAvailable) {
- checkCapabilities();
- }
- }
-
- function checkCapabilities() {
- if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) {
- extWorkspaceAvailable = false;
- return;
- }
-
- const hasExtWorkspace = DMSService.capabilities.includes("extworkspace");
- if (hasExtWorkspace && !extWorkspaceAvailable) {
- if (typeof CompositorService !== "undefined") {
- const useExtWorkspace = DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && !CompositorService.isScroll && !CompositorService.isMiracle);
- if (!useExtWorkspace) {
- console.info("ExtWorkspaceService: ext-workspace available but compositor has native support");
- extWorkspaceAvailable = false;
- return;
- }
- }
- extWorkspaceAvailable = true;
- console.info("ExtWorkspaceService: ext-workspace capability detected");
- DMSService.addSubscription("extworkspace");
- requestState();
- } else if (!hasExtWorkspace) {
- extWorkspaceAvailable = false;
- }
- }
-
- function requestState() {
- if (!DMSService.isConnected || !extWorkspaceAvailable) {
- return;
- }
-
- DMSService.sendRequest("extworkspace.getState", null, response => {
- if (response.result) {
- handleStateUpdate(response.result);
- }
- });
- }
-
- function handleStateUpdate(state) {
- groups = state.groups || [];
- if (groups.length === 0) {
- console.warn("ExtWorkspaceService: Received empty workspace groups from backend");
- } else {
- console.log("ExtWorkspaceService: Updated with", groups.length, "workspace groups");
- }
- stateChanged();
- }
-
- function activateWorkspace(workspaceID, groupID = "") {
- if (!DMSService.isConnected || !extWorkspaceAvailable) {
- return;
- }
-
- DMSService.sendRequest("extworkspace.activateWorkspace", {
- "workspaceID": workspaceID,
- "groupID": groupID
- }, response => {
- if (response.error) {
- console.warn("ExtWorkspaceService: activateWorkspace error:", response.error);
- }
- });
- }
-
- function deactivateWorkspace(workspaceID, groupID = "") {
- if (!DMSService.isConnected || !extWorkspaceAvailable) {
- return;
- }
-
- DMSService.sendRequest("extworkspace.deactivateWorkspace", {
- "workspaceID": workspaceID,
- "groupID": groupID
- }, response => {
- if (response.error) {
- console.warn("ExtWorkspaceService: deactivateWorkspace error:", response.error);
- }
- });
- }
-
- function removeWorkspace(workspaceID, groupID = "") {
- if (!DMSService.isConnected || !extWorkspaceAvailable) {
- return;
- }
-
- DMSService.sendRequest("extworkspace.removeWorkspace", {
- "workspaceID": workspaceID,
- "groupID": groupID
- }, response => {
- if (response.error) {
- console.warn("ExtWorkspaceService: removeWorkspace error:", response.error);
- }
- });
- }
-
- function createWorkspace(groupID, name) {
- if (!DMSService.isConnected || !extWorkspaceAvailable) {
- return;
- }
-
- DMSService.sendRequest("extworkspace.createWorkspace", {
- "groupID": groupID,
- "name": name
- }, response => {
- if (response.error) {
- console.warn("ExtWorkspaceService: createWorkspace error:", response.error);
- }
- });
- }
-
- function getGroupForOutput(outputName) {
- for (const group of groups) {
- if (group.outputs && group.outputs.includes(outputName)) {
- return group;
- }
- }
- return null;
- }
-
- function getWorkspacesForOutput(outputName) {
- const group = getGroupForOutput(outputName);
- return group ? (group.workspaces || []) : [];
- }
-
- function getActiveWorkspaces() {
- const active = [];
- for (const group of groups) {
- if (!group.workspaces)
- continue;
- for (const ws of group.workspaces) {
- if (ws.active) {
- active.push({
- workspace: ws,
- group: group,
- outputs: group.outputs || []
- });
- }
- }
- }
- return active;
- }
-
- function getActiveWorkspaceForOutput(outputName) {
- const group = getGroupForOutput(outputName);
- if (!group || !group.workspaces)
- return null;
-
- for (const ws of group.workspaces) {
- if (ws.active) {
- return ws;
- }
- }
- return null;
- }
-
- function getVisibleWorkspaces(outputName) {
- const workspaces = getWorkspacesForOutput(outputName);
- let visible = workspaces.filter(ws => !ws.hidden);
-
- const hasValidCoordinates = visible.some(ws => ws.coordinates && ws.coordinates.length > 0);
- if (hasValidCoordinates) {
- visible = visible.sort((a, b) => {
- const coordsA = a.coordinates || [0, 0];
- const coordsB = b.coordinates || [0, 0];
- if (coordsA[0] !== coordsB[0])
- return coordsA[0] - coordsB[0];
- return coordsA[1] - coordsB[1];
- });
- }
-
- const cacheKey = outputName;
- if (!_cachedWorkspaces[cacheKey]) {
- _cachedWorkspaces[cacheKey] = {
- workspaces: [],
- lastNames: []
- };
- }
-
- const cache = _cachedWorkspaces[cacheKey];
- const currentNames = visible.map(ws => ws.name || ws.id);
- const namesChanged = JSON.stringify(cache.lastNames) !== JSON.stringify(currentNames);
-
- if (namesChanged || cache.workspaces.length !== visible.length) {
- cache.workspaces = visible.map(ws => ({
- id: ws.id,
- name: ws.name,
- coordinates: ws.coordinates,
- state: ws.state,
- active: ws.active,
- urgent: ws.urgent,
- hidden: ws.hidden
- }));
- cache.lastNames = currentNames;
- return cache.workspaces;
- }
-
- for (let i = 0; i < visible.length; i++) {
- const src = visible[i];
- const dst = cache.workspaces[i];
- dst.id = src.id;
- dst.name = src.name;
- dst.coordinates = src.coordinates;
- dst.state = src.state;
- dst.active = src.active;
- dst.urgent = src.urgent;
- dst.hidden = src.hidden;
- }
-
- return cache.workspaces;
- }
-
- function getUrgentWorkspaces() {
- const urgent = [];
- for (const group of groups) {
- if (!group.workspaces)
- continue;
- for (const ws of group.workspaces) {
- if (ws.urgent) {
- urgent.push({
- workspace: ws,
- group: group,
- outputs: group.outputs || []
- });
- }
- }
- }
- return urgent;
- }
-
- function switchToWorkspace(outputName, workspaceName) {
- const workspaces = getWorkspacesForOutput(outputName);
- for (const ws of workspaces) {
- if (ws.name === workspaceName || ws.id === workspaceName) {
- activateWorkspace(ws.name || ws.id);
- return;
- }
- }
- console.warn("ExtWorkspaceService: workspace not found:", workspaceName);
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/FirstLaunchService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/FirstLaunchService.qml
deleted file mode 100644
index 8b7acd3..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/FirstLaunchService.qml
+++ /dev/null
@@ -1,111 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtCore
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/DankMaterialShell"
- readonly property string settingsPath: configDir + "/settings.json"
- readonly property string firstLaunchMarkerPath: configDir + "/.firstlaunch"
-
- property bool isFirstLaunch: false
- property bool checkComplete: false
- property bool greeterDismissed: false
- property int requestedStartPage: 0
-
- readonly property bool shouldShowGreeter: checkComplete && isFirstLaunch && !greeterDismissed
-
- signal greeterRequested
- signal greeterCompleted
-
- function showGreeter(startPage) {
- requestedStartPage = startPage || 0;
- greeterRequested();
- }
-
- function showWelcome() {
- showGreeter(0);
- }
-
- function showDoctor() {
- showGreeter(1);
- }
-
- Component.onCompleted: {
- checkFirstLaunch();
- }
-
- function checkFirstLaunch() {
- firstLaunchCheckProcess.running = true;
- }
-
- function markFirstLaunchComplete() {
- greeterDismissed = true;
- touchMarkerProcess.running = true;
- greeterCompleted();
- }
-
- function dismissGreeter() {
- greeterDismissed = true;
- }
-
- Process {
- id: firstLaunchCheckProcess
-
- command: ["sh", "-c", `
- SETTINGS='` + settingsPath + `'
- MARKER='` + firstLaunchMarkerPath + `'
- if [ -f "$MARKER" ]; then
- echo 'skip'
- elif [ -f "$SETTINGS" ]; then
- echo 'existing_user'
- else
- echo 'first'
- fi
- `]
- running: false
-
- stdout: SplitParser {
- onRead: data => {
- const result = data.trim();
-
- if (result === "first") {
- root.isFirstLaunch = true;
- console.info("FirstLaunchService: First launch detected, greeter will be shown");
- } else if (result === "existing_user") {
- root.isFirstLaunch = false;
- console.info("FirstLaunchService: Existing user detected, silently creating marker");
- touchMarkerProcess.running = true;
- } else {
- root.isFirstLaunch = false;
- }
-
- root.checkComplete = true;
-
- if (root.isFirstLaunch)
- root.greeterRequested();
- }
- }
- }
-
- Process {
- id: touchMarkerProcess
-
- command: ["sh", "-c", "mkdir -p '" + configDir + "' && touch '" + firstLaunchMarkerPath + "'"]
- running: false
-
- onExited: exitCode => {
- if (exitCode === 0) {
- console.info("FirstLaunchService: First launch marker created");
- } else {
- console.warn("FirstLaunchService: Failed to create first launch marker");
- }
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/HyprlandService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/HyprlandService.qml
deleted file mode 100644
index 20096ef..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/HyprlandService.qml
+++ /dev/null
@@ -1,338 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtCore
-import QtQuick
-import Quickshell
-import Quickshell.Hyprland
-import qs.Common
-
-Singleton {
- id: root
-
- readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation))
- readonly property string hyprDmsDir: configDir + "/hypr/dms"
- readonly property string outputsPath: hyprDmsDir + "/outputs.conf"
- readonly property string layoutPath: hyprDmsDir + "/layout.conf"
- readonly property string cursorPath: hyprDmsDir + "/cursor.conf"
- readonly property string windowrulesPath: hyprDmsDir + "/windowrules.conf"
-
- property int _lastGapValue: -1
-
- Component.onCompleted: {
- if (CompositorService.isHyprland) {
- Qt.callLater(generateLayoutConfig);
- ensureWindowrulesConfig();
- }
- }
-
- function ensureWindowrulesConfig() {
- Proc.runCommand("hypr-ensure-windowrules", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && [ ! -f "${windowrulesPath}" ] && touch "${windowrulesPath}" || true`], (output, exitCode) => {
- if (exitCode !== 0)
- console.warn("HyprlandService: Failed to ensure windowrules.conf:", output);
- });
- }
-
- Connections {
- target: SettingsData
- function onBarConfigsChanged() {
- if (!CompositorService.isHyprland)
- return;
- const newGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4));
- if (newGaps === root._lastGapValue)
- return;
- root._lastGapValue = newGaps;
- generateLayoutConfig();
- }
- }
-
- Connections {
- target: CompositorService
- function onIsHyprlandChanged() {
- if (CompositorService.isHyprland)
- generateLayoutConfig();
- }
- }
-
- function getOutputIdentifier(output, outputName) {
- if (SettingsData.displayNameMode === "model" && output.make && output.model)
- return "desc:" + output.make + " " + output.model + " " + (output.serial || "Unknown");
- return outputName;
- }
-
- function generateOutputsConfig(outputsData, hyprlandSettings) {
- if (!outputsData || Object.keys(outputsData).length === 0)
- return;
-
- const settings = hyprlandSettings || SettingsData.hyprlandOutputSettings;
- let lines = ["# Auto-generated by DMS - do not edit manually", ""];
- let monitorv2Blocks = [];
-
- for (const outputName in outputsData) {
- const output = outputsData[outputName];
- if (!output)
- continue;
-
- const identifier = getOutputIdentifier(output, outputName);
- const outputSettings = settings[identifier] || {};
-
- if (outputSettings.disabled) {
- lines.push("monitor = " + identifier + ", disable");
- continue;
- }
-
- let resolution = "preferred";
- if (output.modes && output.current_mode !== undefined) {
- const mode = output.modes[output.current_mode];
- if (mode)
- resolution = mode.width + "x" + mode.height + "@" + (mode.refresh_rate / 1000).toFixed(3);
- }
-
- const x = output.logical?.x ?? 0;
- const y = output.logical?.y ?? 0;
- const position = x + "x" + y;
- const scale = output.logical?.scale ?? 1.0;
-
- let monitorLine = "monitor = " + identifier + ", " + resolution + ", " + position + ", " + scale;
-
- const transform = transformToHyprland(output.logical?.transform ?? "Normal");
- if (transform !== 0)
- monitorLine += ", transform, " + transform;
-
- if (output.vrr_supported) {
- const vrrMode = outputSettings.vrrFullscreenOnly ? 2 : (output.vrr_enabled ? 1 : 0);
- monitorLine += ", vrr, " + vrrMode;
- }
-
- if (output.mirror && output.mirror.length > 0)
- monitorLine += ", mirror, " + output.mirror;
-
- if (outputSettings.bitdepth && outputSettings.bitdepth !== 8)
- monitorLine += ", bitdepth, " + outputSettings.bitdepth;
-
- if (outputSettings.colorManagement && outputSettings.colorManagement !== "auto")
- monitorLine += ", cm, " + outputSettings.colorManagement;
-
- if (outputSettings.sdrBrightness !== undefined && outputSettings.sdrBrightness !== 1.0)
- monitorLine += ", sdrbrightness, " + outputSettings.sdrBrightness;
-
- if (outputSettings.sdrSaturation !== undefined && outputSettings.sdrSaturation !== 1.0)
- monitorLine += ", sdrsaturation, " + outputSettings.sdrSaturation;
-
- lines.push(monitorLine);
-
- const needsMonitorv2 = outputSettings.supportsHdr || outputSettings.supportsWideColor || outputSettings.sdrMinLuminance !== undefined || outputSettings.sdrMaxLuminance !== undefined || outputSettings.minLuminance !== undefined || outputSettings.maxLuminance !== undefined || outputSettings.maxAvgLuminance !== undefined;
-
- if (needsMonitorv2) {
- let block = "monitorv2 {\n";
- block += " output = " + identifier + "\n";
-
- if (outputSettings.supportsWideColor)
- block += " supports_wide_color = true\n";
- if (outputSettings.supportsHdr)
- block += " supports_hdr = true\n";
- if (outputSettings.sdrMinLuminance !== undefined)
- block += " sdr_min_luminance = " + outputSettings.sdrMinLuminance + "\n";
- if (outputSettings.sdrMaxLuminance !== undefined)
- block += " sdr_max_luminance = " + outputSettings.sdrMaxLuminance + "\n";
- if (outputSettings.minLuminance !== undefined)
- block += " min_luminance = " + outputSettings.minLuminance + "\n";
- if (outputSettings.maxLuminance !== undefined)
- block += " max_luminance = " + outputSettings.maxLuminance + "\n";
- if (outputSettings.maxAvgLuminance !== undefined)
- block += " max_avg_luminance = " + outputSettings.maxAvgLuminance + "\n";
-
- block += "}";
- monitorv2Blocks.push(block);
- }
- }
-
- if (monitorv2Blocks.length > 0) {
- lines.push("");
- for (const block of monitorv2Blocks)
- lines.push(block);
- }
-
- lines.push("");
-
- const content = lines.join("\n");
-
- Proc.runCommand("hypr-write-outputs", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
- if (exitCode !== 0) {
- console.warn("HyprlandService: Failed to write outputs config:", output);
- return;
- }
- console.info("HyprlandService: Generated outputs config at", outputsPath);
- if (CompositorService.isHyprland)
- reloadConfig();
- });
- }
-
- function reloadConfig() {
- Proc.runCommand("hyprctl-reload", ["hyprctl", "reload"], (output, exitCode) => {
- if (exitCode !== 0)
- console.warn("HyprlandService: hyprctl reload failed:", output);
- });
- }
-
- function generateLayoutConfig() {
- if (!CompositorService.isHyprland)
- return;
-
- const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12;
- const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4;
- const defaultBorderSize = 2;
-
- const cornerRadius = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutRadiusOverride >= 0) ? SettingsData.hyprlandLayoutRadiusOverride : defaultRadius;
- const gaps = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutGapsOverride >= 0) ? SettingsData.hyprlandLayoutGapsOverride : defaultGaps;
- const borderSize = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutBorderSize >= 0) ? SettingsData.hyprlandLayoutBorderSize : defaultBorderSize;
-
- let content = `# Auto-generated by DMS - do not edit manually
-
-general {
- gaps_in = ${gaps}
- gaps_out = ${gaps}
- border_size = ${borderSize}
-}
-
-decoration {
- rounding = ${cornerRadius}
-}
-`;
-
- Proc.runCommand("hypr-write-layout", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${layoutPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
- if (exitCode !== 0) {
- console.warn("HyprlandService: Failed to write layout config:", output);
- return;
- }
- console.info("HyprlandService: Generated layout config at", layoutPath);
- reloadConfig();
- });
- }
-
- function transformToHyprland(transform) {
- switch (transform) {
- case "Normal":
- return 0;
- case "90":
- return 1;
- case "180":
- return 2;
- case "270":
- return 3;
- case "Flipped":
- return 4;
- case "Flipped90":
- return 5;
- case "Flipped180":
- return 6;
- case "Flipped270":
- return 7;
- default:
- return 0;
- }
- }
-
- function hyprlandToTransform(value) {
- switch (value) {
- case 0:
- return "Normal";
- case 1:
- return "90";
- case 2:
- return "180";
- case 3:
- return "270";
- case 4:
- return "Flipped";
- case 5:
- return "Flipped90";
- case 6:
- return "Flipped180";
- case 7:
- return "Flipped270";
- default:
- return "Normal";
- }
- }
-
- function generateCursorConfig() {
- if (!CompositorService.isHyprland)
- return;
-
- const settings = typeof SettingsData !== "undefined" ? SettingsData.cursorSettings : null;
- if (!settings) {
- Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => {
- if (exitCode !== 0)
- console.warn("HyprlandService: Failed to write cursor config:", output);
- });
- return;
- }
-
- const themeName = settings.theme === "System Default" ? (SettingsData.systemDefaultCursorTheme || "") : settings.theme;
- const size = settings.size || 24;
- const hideOnKeyPress = settings.hyprland?.hideOnKeyPress || false;
- const hideOnTouch = settings.hyprland?.hideOnTouch || false;
- const inactiveTimeout = settings.hyprland?.inactiveTimeout || 0;
-
- const hasTheme = themeName && themeName.length > 0;
- const hasNonDefaultSize = size !== 24;
- const hasCursorSettings = hideOnKeyPress || hideOnTouch || inactiveTimeout > 0;
-
- if (!hasTheme && !hasNonDefaultSize && !hasCursorSettings) {
- Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => {
- if (exitCode !== 0)
- console.warn("HyprlandService: Failed to write cursor config:", output);
- });
- return;
- }
-
- let lines = ["# Auto-generated by DMS - do not edit manually", ""];
-
- if (hasTheme) {
- lines.push(`env = HYPRCURSOR_THEME,${themeName}`);
- lines.push(`env = XCURSOR_THEME,${themeName}`);
- }
- lines.push(`env = HYPRCURSOR_SIZE,${size}`);
- lines.push(`env = XCURSOR_SIZE,${size}`);
-
- if (hasCursorSettings) {
- lines.push("");
- lines.push("cursor {");
- if (hideOnKeyPress)
- lines.push(" hide_on_key_press = true");
- if (hideOnTouch)
- lines.push(" hide_on_touch = true");
- if (inactiveTimeout > 0)
- lines.push(` inactive_timeout = ${inactiveTimeout}`);
- lines.push("}");
- }
-
- lines.push("");
- const content = lines.join("\n");
-
- Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${cursorPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
- if (exitCode !== 0) {
- console.warn("HyprlandService: Failed to write cursor config:", output);
- return;
- }
- if (hasTheme)
- Proc.runCommand("hyprctl-setcursor", ["hyprctl", "setcursor", themeName, String(size)], () => {});
- reloadConfig();
- });
- }
-
- function renameWorkspace(newName) {
- if (!Hyprland.focusedWorkspace)
- return;
- const wsId = Hyprland.focusedWorkspace.id;
- if (!wsId)
- return;
- const fullName = wsId + " " + newName;
- Proc.runCommand("hyprland-rename-ws", ["hyprctl", "dispatch", "renameworkspace", String(wsId), fullName], (output, exitCode) => {
- if (exitCode !== 0) {
- console.warn("HyprlandService: Failed to rename workspace:", output);
- }
- });
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/IdleService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/IdleService.qml
deleted file mode 100644
index 9965e47..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/IdleService.qml
+++ /dev/null
@@ -1,191 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Wayland
-import qs.Common
-
-Singleton {
- id: root
-
- readonly property bool idleMonitorAvailable: {
- try {
- return typeof IdleMonitor !== "undefined";
- } catch (e) {
- return false;
- }
- }
-
- readonly property bool idleInhibitorAvailable: {
- try {
- return typeof IdleInhibitor !== "undefined";
- } catch (e) {
- return false;
- }
- }
-
- property bool enabled: true
- property bool respectInhibitors: true
- property bool _enableGate: true
-
- readonly property bool externalInhibitActive: DMSService.screensaverInhibited
-
- readonly property bool isOnBattery: BatteryService.batteryAvailable && !BatteryService.isPluggedIn
- readonly property int monitorTimeout: isOnBattery ? SettingsData.batteryMonitorTimeout : SettingsData.acMonitorTimeout
- readonly property int lockTimeout: isOnBattery ? SettingsData.batteryLockTimeout : SettingsData.acLockTimeout
- readonly property int suspendTimeout: isOnBattery ? SettingsData.batterySuspendTimeout : SettingsData.acSuspendTimeout
- readonly property int suspendBehavior: isOnBattery ? SettingsData.batterySuspendBehavior : SettingsData.acSuspendBehavior
-
- readonly property bool mediaPlaying: MprisController.activePlayer !== null && MprisController.activePlayer.isPlaying
-
- onMonitorTimeoutChanged: _rearmIdleMonitors()
- onLockTimeoutChanged: _rearmIdleMonitors()
- onSuspendTimeoutChanged: _rearmIdleMonitors()
-
- function _rearmIdleMonitors() {
- _enableGate = false;
- Qt.callLater(() => {
- _enableGate = true;
- });
- }
-
- signal lockRequested
- signal fadeToLockRequested
- signal cancelFadeToLock
- signal fadeToDpmsRequested
- signal cancelFadeToDpms
- signal requestMonitorOff
- signal requestMonitorOn
- signal requestSuspend
-
- property var monitorOffMonitor: null
- property var lockMonitor: null
- property var suspendMonitor: null
- property var lockComponent: null
- property bool monitorsOff: false
- property bool isShellLocked: false
-
- function wake() {
- requestMonitorOn();
- }
-
- function reapplyDpmsIfNeeded() {
- if (monitorsOff)
- CompositorService.powerOffMonitors();
- }
-
- function createIdleMonitors() {
- if (!idleMonitorAvailable) {
- console.info("IdleService: IdleMonitor not available, skipping creation");
- return;
- }
-
- try {
- const qmlString = `
- import QtQuick
- import Quickshell.Wayland
-
- IdleMonitor {
- enabled: false
- respectInhibitors: true
- timeout: 0
- }
- `;
-
- monitorOffMonitor = Qt.createQmlObject(qmlString, root, "IdleService.MonitorOffMonitor");
- monitorOffMonitor.timeout = Qt.binding(() => root.monitorTimeout > 0 ? root.monitorTimeout : 86400);
- monitorOffMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors);
- monitorOffMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.monitorTimeout > 0);
- monitorOffMonitor.isIdleChanged.connect(function () {
- if (monitorOffMonitor.isIdle) {
- if (SettingsData.fadeToDpmsEnabled) {
- root.fadeToDpmsRequested();
- } else {
- root.requestMonitorOff();
- }
- } else {
- if (SettingsData.fadeToDpmsEnabled) {
- root.cancelFadeToDpms();
- }
- root.requestMonitorOn();
- }
- });
-
- lockMonitor = Qt.createQmlObject(qmlString, root, "IdleService.LockMonitor");
- lockMonitor.timeout = Qt.binding(() => root.lockTimeout > 0 ? root.lockTimeout : 86400);
- lockMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors);
- lockMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.lockTimeout > 0);
- lockMonitor.isIdleChanged.connect(function () {
- if (lockMonitor.isIdle) {
- if (SettingsData.fadeToLockEnabled) {
- root.fadeToLockRequested();
- } else {
- root.lockRequested();
- }
- } else {
- if (SettingsData.fadeToLockEnabled) {
- root.cancelFadeToLock();
- }
- }
- });
-
- suspendMonitor = Qt.createQmlObject(qmlString, root, "IdleService.SuspendMonitor");
- suspendMonitor.timeout = Qt.binding(() => root.suspendTimeout > 0 ? root.suspendTimeout : 86400);
- suspendMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors);
- suspendMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.suspendTimeout > 0);
- suspendMonitor.isIdleChanged.connect(function () {
- if (suspendMonitor.isIdle) {
- root.requestSuspend();
- }
- });
- } catch (e) {
- console.warn("IdleService: Error creating IdleMonitors:", e);
- }
- }
-
- Connections {
- target: root
- function onRequestMonitorOff() {
- monitorsOff = true;
- CompositorService.powerOffMonitors();
- }
-
- function onRequestMonitorOn() {
- monitorsOff = false;
- CompositorService.powerOnMonitors();
- }
-
- function onRequestSuspend() {
- SessionService.suspendWithBehavior(root.suspendBehavior);
- }
- }
-
- onExternalInhibitActiveChanged: {
- if (externalInhibitActive) {
- const apps = DMSService.screensaverInhibitors.map(i => i.appName).join(", ");
- console.info("IdleService: External idle inhibit active from:", apps || "unknown");
- SessionService.idleInhibited = true;
- SessionService.inhibitReason = "External app: " + (apps || "unknown");
- } else {
- console.info("IdleService: External idle inhibit released");
- SessionService.idleInhibited = false;
- SessionService.inhibitReason = "Keep system awake";
- }
- }
-
- Component.onCompleted: {
- if (!idleMonitorAvailable) {
- console.warn("IdleService: IdleMonitor not available - power management disabled. This requires a newer version of Quickshell.");
- } else {
- console.info("IdleService: Initialized with idle monitoring support");
- createIdleMonitors();
- }
-
- if (externalInhibitActive) {
- const apps = DMSService.screensaverInhibitors.map(i => i.appName).join(", ");
- SessionService.idleInhibited = true;
- SessionService.inhibitReason = "External app: " + (apps || "unknown");
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/KeybindsService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/KeybindsService.qml
deleted file mode 100644
index 470831b..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/KeybindsService.qml
+++ /dev/null
@@ -1,528 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtCore
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import Quickshell.Wayland
-// ! Even though qmlls says this is unused, it is wrong
-import qs.Common
-import "../Common/KeybindActions.js" as Actions
-
-Singleton {
- id: root
-
- Component.onCompleted: {
- if (!shortcutInhibitorAvailable) {
- console.warn("[KeybindsService] ShortcutInhibitor is not available in this environment, keybinds editor disabled.");
- }
- }
-
- readonly property bool shortcutInhibitorAvailable: {
- try {
- return typeof ShortcutInhibitor !== "undefined";
- } catch (e) {
- return false;
- }
- }
-
- property bool available: (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl) && shortcutInhibitorAvailable
- property string currentProvider: {
- if (CompositorService.isNiri)
- return "niri";
- if (CompositorService.isHyprland)
- return "hyprland";
- if (CompositorService.isDwl)
- return "mangowc";
- return "";
- }
-
- readonly property string cheatsheetProvider: {
- if (CompositorService.isNiri)
- return "niri";
- if (CompositorService.isHyprland)
- return "hyprland";
- if (CompositorService.isDwl)
- return "mangowc";
- return "";
- }
- property bool cheatsheetAvailable: cheatsheetProvider !== ""
- property bool cheatsheetLoading: false
- property var cheatsheet: ({})
-
- property bool loading: false
- property bool saving: false
- property bool fixing: false
- property string lastError: ""
- property bool dmsBindsIncluded: true
-
- property var dmsStatus: ({
- "exists": true,
- "included": true,
- "includePosition": -1,
- "totalIncludes": 0,
- "bindsAfterDms": 0,
- "effective": true,
- "overriddenBy": 0,
- "statusMessage": ""
- })
-
- property var _rawData: null
- property var keybinds: ({})
- property var _allBinds: ({})
- property var _categories: []
- property var _flatCache: []
- property var displayList: []
- property int _dataVersion: 0
- property string _pendingSavedKey: ""
-
- readonly property var categoryOrder: Actions.getCategoryOrder()
- readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation))
- readonly property string compositorConfigDir: {
- switch (currentProvider) {
- case "niri":
- return configDir + "/niri";
- case "hyprland":
- return configDir + "/hypr";
- case "mangowc":
- return configDir + "/mango";
- default:
- return "";
- }
- }
- readonly property string dmsBindsPath: {
- switch (currentProvider) {
- case "niri":
- return compositorConfigDir + "/dms/binds.kdl";
- case "hyprland":
- case "mangowc":
- return compositorConfigDir + "/dms/binds.conf";
- default:
- return "";
- }
- }
- readonly property string mainConfigPath: {
- switch (currentProvider) {
- case "niri":
- return compositorConfigDir + "/config.kdl";
- case "hyprland":
- return compositorConfigDir + "/hyprland.conf";
- case "mangowc":
- return compositorConfigDir + "/config.conf";
- default:
- return "";
- }
- }
- readonly property var actionTypes: Actions.getActionTypes()
- readonly property var dmsActions: getDmsActions()
-
- signal bindsLoaded
- signal bindSaved(string key)
- signal bindSaveCompleted(bool success)
- signal bindRemoved(string key)
- signal dmsBindsFixed
- signal cheatsheetLoaded
-
- Connections {
- target: CompositorService
- function onCompositorChanged() {
- if (!CompositorService.isNiri)
- return;
- Qt.callLater(root.loadBinds);
- }
- }
-
- Connections {
- target: NiriService
- enabled: CompositorService.isNiri
- function onConfigReloaded() {
- Qt.callLater(root.loadBinds, false);
- }
- }
-
- Process {
- id: cheatsheetProcess
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- try {
- root.cheatsheet = JSON.parse(text);
- } catch (e) {
- console.error("[KeybindsService] Failed to parse cheatsheet:", e);
- root.cheatsheet = {};
- }
- root.cheatsheetLoading = false;
- root.cheatsheetLoaded();
- }
- }
-
- onExited: exitCode => {
- if (exitCode === 0)
- return;
- console.warn("[KeybindsService] Cheatsheet load failed with code:", exitCode);
- root.cheatsheetLoading = false;
- }
- }
-
- Process {
- id: loadProcess
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- try {
- root._rawData = JSON.parse(text);
- root._processData();
- } catch (e) {
- console.error("[KeybindsService] Failed to parse binds:", e);
- }
- root.loading = false;
- }
- }
-
- onExited: exitCode => {
- if (exitCode !== 0) {
- console.warn("[KeybindsService] Load process failed with code:", exitCode);
- root.loading = false;
- }
- }
- }
-
- Process {
- id: saveProcess
- running: false
-
- stderr: StdioCollector {
- onStreamFinished: {
- if (!text.trim())
- return;
- root.lastError = text.trim();
- ToastService.showError(I18n.tr("Failed to save keybind"), "", root.lastError, "keybinds");
- }
- }
-
- onExited: exitCode => {
- root.saving = false;
- if (exitCode !== 0) {
- console.error("[KeybindsService] Save failed with code:", exitCode);
- root.bindSaveCompleted(false);
- return;
- }
- root.lastError = "";
- root.bindSaveCompleted(true);
- root.loadBinds(false);
- }
- }
-
- Process {
- id: removeProcess
- running: false
-
- stderr: StdioCollector {
- onStreamFinished: {
- if (!text.trim())
- return;
- root.lastError = text.trim();
- ToastService.showError(I18n.tr("Failed to remove keybind"), "", root.lastError, "keybinds");
- }
- }
-
- onExited: exitCode => {
- if (exitCode !== 0) {
- console.error("[KeybindsService] Remove failed with code:", exitCode);
- return;
- }
- root.lastError = "";
- root.loadBinds(false);
- }
- }
-
- Process {
- id: fixProcess
- running: false
-
- stderr: StdioCollector {
- onStreamFinished: {
- if (!text.trim())
- return;
- root.lastError = text.trim();
- ToastService.showError(I18n.tr("Failed to add binds include"), "", root.lastError, "keybinds");
- }
- }
-
- onExited: exitCode => {
- root.fixing = false;
- if (exitCode !== 0) {
- console.error("[KeybindsService] Fix failed with code:", exitCode);
- return;
- }
- root.lastError = "";
- root.dmsBindsIncluded = true;
- root.dmsBindsFixed();
- const bindsFile = root.currentProvider === "niri" ? "dms/binds.kdl" : "dms/binds.conf";
- ToastService.showInfo(I18n.tr("Binds include added"), I18n.tr("%1 is now included in config").arg(bindsFile), "", "keybinds");
- Qt.callLater(root.forceReload);
- }
- }
-
- function fixDmsBindsInclude() {
- if (fixing || dmsBindsIncluded || !compositorConfigDir)
- return;
- fixing = true;
- const timestamp = Math.floor(Date.now() / 1000);
- const backupPath = `${mainConfigPath}.dmsbackup${timestamp}`;
- let script;
- switch (currentProvider) {
- case "niri":
- script = `mkdir -p "${compositorConfigDir}/dms" && touch "${compositorConfigDir}/dms/binds.kdl" && cp "${mainConfigPath}" "${backupPath}" && echo 'include "dms/binds.kdl"' >> "${mainConfigPath}"`;
- break;
- case "hyprland":
- script = `mkdir -p "${compositorConfigDir}/dms" && touch "${compositorConfigDir}/dms/binds.conf" && cp "${mainConfigPath}" "${backupPath}" && echo 'source = ./dms/binds.conf' >> "${mainConfigPath}"`;
- break;
- case "mangowc":
- script = `mkdir -p "${compositorConfigDir}/dms" && touch "${compositorConfigDir}/dms/binds.conf" && cp "${mainConfigPath}" "${backupPath}" && echo 'source = ./dms/binds.conf' >> "${mainConfigPath}"`;
- break;
- default:
- fixing = false;
- return;
- }
- fixProcess.command = ["sh", "-c", script];
- fixProcess.running = true;
- }
-
- function forceReload() {
- _allBinds = {};
- _flatCache = [];
- _categories = [];
- loadBinds(true);
- }
-
- function loadCheatsheet(provider) {
- if (cheatsheetProcess.running)
- return;
- const target = provider || cheatsheetProvider;
- if (!target)
- return;
- cheatsheetLoading = true;
- cheatsheetProcess.command = ["dms", "keybinds", "show", target];
- cheatsheetProcess.running = true;
- }
-
- function loadBinds(showLoading) {
- if (loadProcess.running || !available)
- return;
- const hasData = Object.keys(_allBinds).length > 0;
- loading = showLoading !== false && !hasData;
- loadProcess.command = ["dms", "keybinds", "show", currentProvider];
- loadProcess.running = true;
- }
-
- function _processData() {
- keybinds = _rawData || {};
- dmsBindsIncluded = _rawData?.dmsBindsIncluded ?? true;
- const status = _rawData?.dmsStatus;
- if (status) {
- dmsStatus = {
- "exists": status.exists ?? true,
- "included": status.included ?? true,
- "includePosition": status.includePosition ?? -1,
- "totalIncludes": status.totalIncludes ?? 0,
- "bindsAfterDms": status.bindsAfterDms ?? 0,
- "effective": status.effective ?? true,
- "overriddenBy": status.overriddenBy ?? 0,
- "statusMessage": status.statusMessage ?? ""
- };
- }
-
- if (!_rawData?.binds) {
- _allBinds = {};
- _categories = [];
- _flatCache = [];
- displayList = [];
- _dataVersion++;
- bindsLoaded();
- if (_pendingSavedKey) {
- bindSaved(_pendingSavedKey);
- _pendingSavedKey = "";
- }
- return;
- }
-
- const processed = {};
- const bindsData = _rawData.binds;
- for (const cat in bindsData) {
- const binds = bindsData[cat];
- for (var i = 0; i < binds.length; i++) {
- const bind = binds[i];
- const targetCat = Actions.isDmsAction(bind.action) ? "DMS" : cat;
- if (!processed[targetCat])
- processed[targetCat] = [];
- processed[targetCat].push(bind);
- }
- }
-
- const sortedCats = Object.keys(processed).sort((a, b) => {
- const ai = categoryOrder.indexOf(a);
- const bi = categoryOrder.indexOf(b);
- return (ai === -1 ? 999 : ai) - (bi === -1 ? 999 : bi);
- });
-
- const grouped = [];
- const actionMap = {};
- for (var ci = 0; ci < sortedCats.length; ci++) {
- const category = sortedCats[ci];
- const binds = processed[category];
- if (!binds)
- continue;
- for (var i = 0; i < binds.length; i++) {
- const bind = binds[i];
- const action = bind.action || "";
- const keyData = {
- "key": bind.key || "",
- "source": bind.source || "config",
- "isOverride": bind.source === "dms",
- "cooldownMs": bind.cooldownMs || 0,
- "flags": bind.flags || "",
- "allowWhenLocked": bind.allowWhenLocked || false,
- "allowInhibiting": bind.allowInhibiting,
- "repeat": bind.repeat
- };
- if (actionMap[action]) {
- actionMap[action].keys.push(keyData);
- if (!actionMap[action].desc && bind.desc)
- actionMap[action].desc = bind.desc;
- if (!actionMap[action].conflict && bind.conflict)
- actionMap[action].conflict = bind.conflict;
- } else {
- const entry = {
- "category": category,
- "action": action,
- "desc": bind.desc || "",
- "keys": [keyData],
- "conflict": bind.conflict || null
- };
- actionMap[action] = entry;
- grouped.push(entry);
- }
- }
- }
-
- const list = [];
- for (const cat of sortedCats) {
- list.push({
- "id": "cat:" + cat,
- "type": "category",
- "name": cat
- });
- const binds = processed[cat];
- if (!binds)
- continue;
- for (const bind of binds)
- list.push({
- "id": "bind:" + bind.key,
- "type": "bind",
- "key": bind.key,
- "desc": bind.desc
- });
- }
-
- _allBinds = processed;
- _categories = sortedCats;
- _flatCache = grouped;
- displayList = list;
- _dataVersion++;
- bindsLoaded();
- if (_pendingSavedKey) {
- bindSaved(_pendingSavedKey);
- _pendingSavedKey = "";
- }
- }
-
- function getCategories() {
- return _categories;
- }
-
- function getFlatBinds() {
- return _flatCache;
- }
-
- function saveBind(originalKey, bindData) {
- if (!bindData.key || !Actions.isValidAction(bindData.action))
- return;
- saving = true;
- const cmd = ["dms", "keybinds", "set", currentProvider, bindData.key, bindData.action, "--desc", bindData.desc || ""];
- if (originalKey && originalKey !== bindData.key)
- cmd.push("--replace-key", originalKey);
- if (bindData.cooldownMs > 0)
- cmd.push("--cooldown-ms", String(bindData.cooldownMs));
- if (bindData.allowWhenLocked)
- cmd.push("--allow-when-locked");
- if (bindData.repeat === false)
- cmd.push("--no-repeat");
- if (bindData.allowInhibiting === false)
- cmd.push("--no-inhibiting");
- if (bindData.flags)
- cmd.push("--flags", bindData.flags);
- saveProcess.command = cmd;
- saveProcess.running = true;
- _pendingSavedKey = bindData.key;
- }
-
- function removeBind(key) {
- if (!key)
- return;
- removeProcess.command = ["dms", "keybinds", "remove", currentProvider, key];
- removeProcess.running = true;
- bindRemoved(key);
- }
-
- function isDmsAction(action) {
- return Actions.isDmsAction(action);
- }
-
- function isValidAction(action) {
- return Actions.isValidAction(action);
- }
-
- function getActionType(action) {
- return Actions.getActionType(action);
- }
-
- function getActionLabel(action) {
- return Actions.getActionLabel(action, currentProvider);
- }
-
- function getCompositorCategories() {
- return Actions.getCompositorCategories(currentProvider);
- }
-
- function getCompositorActions(category) {
- return Actions.getCompositorActions(currentProvider, category);
- }
-
- function getDmsActions() {
- return Actions.getDmsActions(CompositorService.isNiri, CompositorService.isHyprland);
- }
-
- function buildSpawnAction(command, args) {
- return Actions.buildSpawnAction(command, args);
- }
-
- function buildShellAction(shellCmd, shell) {
- return Actions.buildShellAction(currentProvider, shellCmd, shell);
- }
-
- function getShellFromAction(action) {
- return Actions.getShellFromAction(action);
- }
-
- function parseSpawnCommand(action) {
- return Actions.parseSpawnCommand(action);
- }
-
- function parseShellCommand(action) {
- return Actions.parseShellCommand(action);
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/LegacyNetworkService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/LegacyNetworkService.qml
deleted file mode 100644
index 97d8745..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/LegacyNetworkService.qml
+++ /dev/null
@@ -1,987 +0,0 @@
-pragma Singleton
-
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- property bool isActive: false
- property string networkStatus: "disconnected"
- property string primaryConnection: ""
-
- property string ethernetIP: ""
- property string ethernetInterface: ""
- property bool ethernetConnected: false
- property string ethernetConnectionUuid: ""
-
- property var wiredConnections: []
-
- property string wifiIP: ""
- property string wifiInterface: ""
- property bool wifiConnected: false
- property bool wifiEnabled: true
- property string wifiConnectionUuid: ""
- property string wifiDevicePath: ""
- property string activeAccessPointPath: ""
-
- property string currentWifiSSID: ""
- property int wifiSignalStrength: 0
- property var wifiNetworks: []
- property var savedConnections: []
- property var ssidToConnectionName: {
-
- }
- property var wifiSignalIcon: {
- if (!wifiConnected || networkStatus !== "wifi") {
- return "wifi_off"
- }
- if (wifiSignalStrength >= 50) {
- return "wifi"
- }
- if (wifiSignalStrength >= 25) {
- return "wifi_2_bar"
- }
- return "wifi_1_bar"
- }
-
- property string userPreference: "auto" // "auto", "wifi", "ethernet"
- property bool isConnecting: false
- property string connectingSSID: ""
- property string connectionError: ""
-
- property bool isScanning: false
- property bool wifiAvailable: true
- property bool wifiToggling: false
- property bool changingPreference: false
- property string targetPreference: ""
- property var savedWifiNetworks: []
- property string connectionStatus: ""
- property string lastConnectionError: ""
- property bool passwordDialogShouldReopen: false
- property string wifiPassword: ""
- property string forgetSSID: ""
-
- readonly property var lowPriorityCmd: ["nice", "-n", "19", "ionice", "-c3"]
-
- property string networkInfoSSID: ""
- property string networkInfoDetails: ""
- property bool networkInfoLoading: false
-
- property string networkWiredInfoUUID: ""
- property string networkWiredInfoDetails: ""
- property bool networkWiredInfoLoading: false
-
- signal networksUpdated
- signal connectionChanged
-
- function splitNmcliFields(line) {
- const parts = []
- let cur = ""
- let escape = false
- for (var i = 0; i < line.length; i++) {
- const ch = line[i]
- if (escape) {
- cur += ch
- escape = false
- } else if (ch === '\\') {
- escape = true
- } else if (ch === ':') {
- parts.push(cur)
- cur = ""
- } else {
- cur += ch
- }
- }
- parts.push(cur)
- return parts
- }
-
- Component.onCompleted: {
- root.userPreference = SettingsData.networkPreference
- }
-
- function activate() {
- if (!isActive) {
- isActive = true
- console.info("LegacyNetworkService: Activating...")
- doRefreshNetworkState()
- }
- }
-
-
- function doRefreshNetworkState() {
- updatePrimaryConnection()
- updateDeviceStates()
- updateActiveConnections()
- updateWifiState()
- }
-
- function updatePrimaryConnection() {
- primaryConnectionQuery.running = true
- }
-
- Process {
- id: primaryConnectionQuery
- command: lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", "/org/freedesktop/NetworkManager", "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager", "PrimaryConnection"])
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const match = text.match(/objectpath '([^']+)'/)
- if (match && match[1] !== '/') {
- root.primaryConnection = match[1]
- getPrimaryConnectionType.running = true
- } else {
- root.primaryConnection = ""
- root.networkStatus = "disconnected"
- }
- }
- }
- }
-
- Process {
- id: getPrimaryConnectionType
- command: root.primaryConnection ? lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", root.primaryConnection, "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager.Connection.Active", "Type"]) : []
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- if (text.includes("802-3-ethernet")) {
- root.networkStatus = "ethernet"
- } else if (text.includes("802-11-wireless")) {
- root.networkStatus = "wifi"
- }
- root.connectionChanged()
- }
- }
- }
-
- function updateDeviceStates() {
- getEthernetDevice.running = true
- getWifiDevice.running = true
- }
-
- Process {
- id: getEthernetDevice
- command: lowPriorityCmd.concat(["nmcli", "-t", "-f", "DEVICE,TYPE", "device"])
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const lines = text.trim().split('\n')
- let ethernetInterface = ""
-
- for (const line of lines) {
- const splitParts = line.split(':')
- const device = splitParts[0]
- const type = splitParts.length > 1 ? splitParts[1] : ""
- if (type === "ethernet") {
- ethernetInterface = device
- break
- }
- }
-
- if (ethernetInterface) {
- root.ethernetInterface = ethernetInterface
- getEthernetDevicePath.command = lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", "/org/freedesktop/NetworkManager", "--method", "org.freedesktop.NetworkManager.GetDeviceByIpIface", ethernetInterface])
- getEthernetDevicePath.running = true
- } else {
- root.ethernetInterface = ""
- root.ethernetConnected = false
- }
- }
- }
- }
-
- Process {
- id: getEthernetDevicePath
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const match = text.match(/objectpath '([^']+)'/)
- if (match && match[1] !== '/') {
- checkEthernetState.command = lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", match[1], "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager.Device", "State"])
- checkEthernetState.running = true
- } else {
- root.ethernetInterface = ""
- root.ethernetConnected = false
- }
- }
- }
-
- onExited: exitCode => {
- if (exitCode !== 0) {
- root.ethernetInterface = ""
- root.ethernetConnected = false
- }
- }
- }
-
- Process {
- id: checkEthernetState
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const isConnected = text.includes("uint32 100")
- root.ethernetConnected = isConnected
- if (isConnected) {
- getEthernetIP.running = true
- } else {
- root.ethernetIP = ""
- }
- }
- }
- }
-
- Process {
- id: getEthernetIP
- command: root.ethernetInterface ? lowPriorityCmd.concat(["ip", "-4", "addr", "show", root.ethernetInterface]) : []
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const match = text.match(/inet (\d+\.\d+\.\d+\.\d+)/)
- if (match) {
- root.ethernetIP = match[1]
- }
- }
- }
- }
-
- Process {
- id: getWifiDevice
- command: lowPriorityCmd.concat(["nmcli", "-t", "-f", "DEVICE,TYPE", "device"])
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const lines = text.trim().split('\n')
- let wifiInterface = ""
-
- for (const line of lines) {
- const splitParts = line.split(':')
- const device = splitParts[0]
- const type = splitParts.length > 1 ? splitParts[1] : ""
- if (type === "wifi") {
- wifiInterface = device
- break
- }
- }
-
- if (wifiInterface) {
- root.wifiInterface = wifiInterface
- getWifiDevicePath.command = lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", "/org/freedesktop/NetworkManager", "--method", "org.freedesktop.NetworkManager.GetDeviceByIpIface", wifiInterface])
- getWifiDevicePath.running = true
- } else {
- root.wifiInterface = ""
- root.wifiConnected = false
- }
- }
- }
- }
-
- Process {
- id: getWifiDevicePath
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const match = text.match(/objectpath '([^']+)'/)
- if (match && match[1] !== '/') {
- root.wifiDevicePath = match[1]
- checkWifiState.command = lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", match[1], "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager.Device", "State"])
- checkWifiState.running = true
- } else {
- root.wifiInterface = ""
- root.wifiConnected = false
- root.wifiDevicePath = ""
- root.activeAccessPointPath = ""
- }
- }
- }
-
- onExited: exitCode => {
- if (exitCode !== 0) {
- root.wifiInterface = ""
- root.wifiConnected = false
- }
- }
- }
-
- Process {
- id: checkWifiState
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- root.wifiConnected = text.includes("uint32 100")
- if (root.wifiConnected) {
- getWifiIP.running = true
- getCurrentWifiInfo.running = true
- getActiveAccessPoint.running = true
- if (root.currentWifiSSID === "") {
- if (root.wifiConnectionUuid) {
- resolveWifiSSID.running = true
- }
- if (root.wifiInterface) {
- resolveWifiSSIDFromDevice.running = true
- }
- }
- } else {
- root.wifiIP = ""
- root.currentWifiSSID = ""
- root.wifiSignalStrength = 0
- root.activeAccessPointPath = ""
- }
- }
- }
- }
-
- Process {
- id: getWifiIP
- command: root.wifiInterface ? lowPriorityCmd.concat(["ip", "-4", "addr", "show", root.wifiInterface]) : []
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const match = text.match(/inet (\d+\.\d+\.\d+\.\d+)/)
- if (match) {
- root.wifiIP = match[1]
- }
- }
- }
- }
-
- Process {
- id: getActiveAccessPoint
- command: root.wifiDevicePath ? lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", root.wifiDevicePath, "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager.Device.Wireless", "ActiveAccessPoint"]) : []
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const match = text.match(/objectpath '([^']+)'/)
- if (match && match[1] !== '/') {
- root.activeAccessPointPath = match[1]
- } else {
- root.activeAccessPointPath = ""
- }
- }
- }
- }
-
- Process {
- id: getCurrentWifiInfo
- command: root.wifiInterface ? lowPriorityCmd.concat(["nmcli", "-t", "-f", "ACTIVE,SIGNAL,SSID", "device", "wifi", "list", "ifname", root.wifiInterface, "--rescan", "no"]) : []
- running: false
-
- stdout: SplitParser {
- splitMarker: "\n"
- onRead: line => {
- if (line.startsWith("yes:")) {
- const rest = line.substring(4)
- const parts = root.splitNmcliFields(rest)
- if (parts.length >= 2) {
- const signal = parseInt(parts[0])
- console.log("Current WiFi signal strength:", signal)
- root.wifiSignalStrength = isNaN(signal) ? 0 : signal
- root.currentWifiSSID = parts[1]
- console.log("Current WiFi SSID:", root.currentWifiSSID)
- }
- return
- }
- }
- }
- }
-
- function updateActiveConnections() {
- getActiveConnections.running = true
- }
-
- Process {
- id: getActiveConnections
- command: lowPriorityCmd.concat(["nmcli", "-t", "-f", "UUID,TYPE,DEVICE,STATE", "connection", "show", "--active"])
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const lines = text.trim().split('\n')
- for (const line of lines) {
- const parts = line.split(':')
- if (parts.length >= 4) {
- const uuid = parts[0]
- const type = parts[1]
- const device = parts[2]
- const state = parts[3]
- if (type === "802-3-ethernet" && state === "activated") {
- root.ethernetConnectionUuid = uuid
- } else if (type === "802-11-wireless" && state === "activated") {
- root.wifiConnectionUuid = uuid
- }
- }
- }
- }
- }
- }
-
- // Resolve SSID from active WiFi connection UUID when scans don't mark any row as ACTIVE.
- Process {
- id: resolveWifiSSID
- command: root.wifiConnectionUuid ? lowPriorityCmd.concat(["nmcli", "-g", "802-11-wireless.ssid", "connection", "show", "uuid", root.wifiConnectionUuid]) : []
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const ssid = text.trim()
- if (ssid) {
- root.currentWifiSSID = ssid
- }
- }
- }
- }
-
- // Fallback 2: Resolve SSID from device info (GENERAL.CONNECTION usually matches SSID for WiFi)
- Process {
- id: resolveWifiSSIDFromDevice
- command: root.wifiInterface ? lowPriorityCmd.concat(["nmcli", "-t", "-f", "GENERAL.CONNECTION", "device", "show", root.wifiInterface]) : []
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- if (!root.currentWifiSSID) {
- const name = text.trim()
- if (name) {
- root.currentWifiSSID = name
- }
- }
- }
- }
- }
-
- function updateWifiState() {
- checkWifiEnabled.running = true
- }
-
- Process {
- id: checkWifiEnabled
- command: lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", "/org/freedesktop/NetworkManager", "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager", "WirelessEnabled"])
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- root.wifiEnabled = text.includes("true")
- root.wifiAvailable = true // Always available if we can check it
- }
- }
- }
-
- function scanWifi() {
- if (root.isScanning || !root.wifiEnabled) {
- return
- }
-
- root.isScanning = true
- requestWifiScan.running = true
- }
-
- Process {
- id: requestWifiScan
- command: root.wifiInterface ? lowPriorityCmd.concat(["nmcli", "dev", "wifi", "rescan", "ifname", root.wifiInterface]) : []
- running: false
-
- onExited: exitCode => {
- if (exitCode === 0) {
- scanWifiNetworks()
- } else {
- console.warn("WiFi scan request failed")
- root.isScanning = false
- }
- }
- }
-
- function scanWifiNetworks() {
- if (!root.wifiInterface) {
- root.isScanning = false
- return
- }
-
- getWifiNetworks.running = true
- getSavedConnections.running = true
- }
-
- Process {
- id: getWifiNetworks
- command: lowPriorityCmd.concat(["nmcli", "-t", "-f", "SSID,SIGNAL,SECURITY,BSSID", "dev", "wifi", "list", "ifname", root.wifiInterface])
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const networks = []
- const lines = text.trim().split('\n')
- const seen = new Set()
-
- for (const line of lines) {
- const parts = root.splitNmcliFields(line)
- if (parts.length >= 4 && parts[0]) {
- const ssid = parts[0]
- if (!seen.has(ssid)) {
- seen.add(ssid)
- const signal = parseInt(parts[1]) || 0
-
- networks.push({
- "ssid": ssid,
- "signal": signal,
- "secured": parts[2] !== "",
- "bssid": parts[3],
- "connected": ssid === root.currentWifiSSID,
- "saved": false
- })
- }
- }
- }
-
- networks.sort((a, b) => b.signal - a.signal)
- root.wifiNetworks = networks
- root.isScanning = false
- root.networksUpdated()
- }
- }
- }
-
- Process {
- id: getSavedConnections
- command: lowPriorityCmd.concat(["bash", "-c", "nmcli -t -f NAME,TYPE connection show | grep ':802-11-wireless$' | cut -d: -f1 | while read name; do ssid=$(nmcli -g 802-11-wireless.ssid connection show \"$name\"); echo \"$ssid:$name\"; done"])
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const saved = []
- const mapping = {}
- const lines = text.trim().split('\n')
-
- for (const line of lines) {
- const parts = line.trim().split(':')
- if (parts.length >= 2) {
- const ssid = parts[0]
- const connectionName = parts[1]
- if (ssid && ssid.length > 0 && connectionName && connectionName.length > 0) {
- saved.push({
- "ssid": ssid,
- "saved": true
- })
- mapping[ssid] = connectionName
- }
- }
- }
-
- root.savedConnections = saved
- root.savedWifiNetworks = saved
- root.ssidToConnectionName = mapping
-
- const updated = [...root.wifiNetworks]
- for (const network of updated) {
- network.saved = saved.some(s => s.ssid === network.ssid)
- }
- root.wifiNetworks = updated
- }
- }
- }
-
- function connectToWifi(ssid, password = "", username = "") {
- if (root.isConnecting) {
- return
- }
-
- root.isConnecting = true
- root.connectingSSID = ssid
- root.connectionError = ""
- root.connectionStatus = "connecting"
-
- if (!password && root.ssidToConnectionName[ssid]) {
- const connectionName = root.ssidToConnectionName[ssid]
- wifiConnector.command = lowPriorityCmd.concat(["nmcli", "connection", "up", connectionName])
- } else if (password) {
- wifiConnector.command = lowPriorityCmd.concat(["nmcli", "dev", "wifi", "connect", ssid, "password", password])
- } else {
- wifiConnector.command = lowPriorityCmd.concat(["nmcli", "dev", "wifi", "connect", ssid])
- }
- wifiConnector.running = true
- }
-
- Process {
- id: wifiConnector
- running: false
-
- property bool connectionSucceeded: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- if (text.includes("successfully")) {
- wifiConnector.connectionSucceeded = true
- ToastService.showInfo(`Connected to ${root.connectingSSID}`)
- root.connectionError = ""
- root.connectionStatus = "connected"
-
- if (root.userPreference === "wifi" || root.userPreference === "auto") {
- setConnectionPriority("wifi")
- }
- }
- }
- }
-
- stderr: StdioCollector {
- onStreamFinished: {
- root.connectionError = text
- root.lastConnectionError = text
- if (!wifiConnector.connectionSucceeded && text.trim() !== "") {
- if (text.includes("password") || text.includes("authentication")) {
- root.connectionStatus = "invalid_password"
- root.passwordDialogShouldReopen = true
- } else {
- root.connectionStatus = "failed"
- }
- }
- }
- }
-
- onExited: exitCode => {
- if (exitCode === 0 || wifiConnector.connectionSucceeded) {
- if (!wifiConnector.connectionSucceeded) {
- ToastService.showInfo(`Connected to ${root.connectingSSID}`)
- root.connectionStatus = "connected"
- }
- } else {
- if (root.connectionStatus === "") {
- root.connectionStatus = "failed"
- }
- if (root.connectionStatus === "invalid_password") {
- ToastService.showError(`Invalid password for ${root.connectingSSID}`)
- } else {
- ToastService.showError(`Failed to connect to ${root.connectingSSID}`)
- }
- }
-
- wifiConnector.connectionSucceeded = false
- root.isConnecting = false
- root.connectingSSID = ""
- doRefreshNetworkState()
- }
- }
-
- function disconnectWifi() {
- if (!root.wifiInterface) {
- return
- }
-
- wifiDisconnector.command = lowPriorityCmd.concat(["nmcli", "dev", "disconnect", root.wifiInterface])
- wifiDisconnector.running = true
- }
-
- Process {
- id: wifiDisconnector
- running: false
-
- onExited: exitCode => {
- if (exitCode === 0) {
- ToastService.showInfo("Disconnected from WiFi")
- root.currentWifiSSID = ""
- root.connectionStatus = ""
- }
- doRefreshNetworkState()
- }
- }
-
- function forgetWifiNetwork(ssid) {
- root.forgetSSID = ssid
- const connectionName = root.ssidToConnectionName[ssid] || ssid
- networkForgetter.command = lowPriorityCmd.concat(["nmcli", "connection", "delete", connectionName])
- networkForgetter.running = true
- }
-
- Process {
- id: networkForgetter
- running: false
-
- onExited: exitCode => {
- if (exitCode === 0) {
- ToastService.showInfo(`Forgot network ${root.forgetSSID}`)
-
- root.savedConnections = root.savedConnections.filter(s => s.ssid !== root.forgetSSID)
- root.savedWifiNetworks = root.savedWifiNetworks.filter(s => s.ssid !== root.forgetSSID)
-
- const updated = [...root.wifiNetworks]
- for (const network of updated) {
- if (network.ssid === root.forgetSSID) {
- network.saved = false
- if (network.connected) {
- network.connected = false
- root.currentWifiSSID = ""
- }
- }
- }
- root.wifiNetworks = updated
- root.networksUpdated()
- doRefreshNetworkState()
- }
- root.forgetSSID = ""
- }
- }
-
- function toggleWifiRadio() {
- if (root.wifiToggling) {
- return
- }
-
- root.wifiToggling = true
- const targetState = root.wifiEnabled ? "off" : "on"
- wifiRadioToggler.targetState = targetState
- wifiRadioToggler.command = lowPriorityCmd.concat(["nmcli", "radio", "wifi", targetState])
- wifiRadioToggler.running = true
- }
-
- Process {
- id: wifiRadioToggler
- running: false
-
- property string targetState: ""
-
- onExited: exitCode => {
- root.wifiToggling = false
- if (exitCode === 0) {
- ToastService.showInfo(targetState === "on" ? "WiFi enabled" : "WiFi disabled")
- }
- doRefreshNetworkState()
- }
- }
-
- function setNetworkPreference(preference) {
- root.userPreference = preference
- root.changingPreference = true
- root.targetPreference = preference
- SettingsData.set("networkPreference", preference)
-
- if (preference === "wifi") {
- setConnectionPriority("wifi")
- } else if (preference === "ethernet") {
- setConnectionPriority("ethernet")
- }
- }
-
- function setConnectionPriority(type) {
- if (type === "wifi") {
- setRouteMetrics.command = lowPriorityCmd.concat(["bash", "-c", "nmcli -t -f NAME,TYPE connection show | grep 802-11-wireless | cut -d: -f1 | " + "xargs -I {} bash -c 'nmcli connection modify \"{}\" ipv4.route-metric 50 ipv6.route-metric 50'; " + "nmcli -t -f NAME,TYPE connection show | grep 802-3-ethernet | cut -d: -f1 | " + "xargs -I {} bash -c 'nmcli connection modify \"{}\" ipv4.route-metric 100 ipv6.route-metric 100'"])
- } else if (type === "ethernet") {
- setRouteMetrics.command = lowPriorityCmd.concat(["bash", "-c", "nmcli -t -f NAME,TYPE connection show | grep 802-3-ethernet | cut -d: -f1 | " + "xargs -I {} bash -c 'nmcli connection modify \"{}\" ipv4.route-metric 50 ipv6.route-metric 50'; " + "nmcli -t -f NAME,TYPE connection show | grep 802-11-wireless | cut -d: -f1 | " + "xargs -I {} bash -c 'nmcli connection modify \"{}\" ipv4.route-metric 100 ipv6.route-metric 100'"])
- }
- setRouteMetrics.running = true
- }
-
- Process {
- id: setRouteMetrics
- running: false
-
- onExited: exitCode => {
- console.log("Set route metrics process exited with code:", exitCode)
- if (exitCode === 0) {
- restartConnections.running = true
- }
- }
- }
-
- Process {
- id: restartConnections
- command: lowPriorityCmd.concat(["bash", "-c", "nmcli -t -f UUID,TYPE connection show --active | " + "grep -E '802-11-wireless|802-3-ethernet' | cut -d: -f1 | " + "xargs -I {} sh -c 'nmcli connection down {} && nmcli connection up {}'"])
- running: false
-
- onExited: {
- root.changingPreference = false
- root.targetPreference = ""
- doRefreshNetworkState()
- }
- }
-
-
- function fetchNetworkInfo(ssid) {
- root.networkInfoSSID = ssid
- root.networkInfoLoading = true
- root.networkInfoDetails = "Loading network information..."
- wifiInfoFetcher.running = true
- }
-
- Process {
- id: wifiInfoFetcher
- command: lowPriorityCmd.concat(["nmcli", "-t", "-f", "SSID,SIGNAL,SECURITY,FREQ,RATE,MODE,CHAN,WPA-FLAGS,RSN-FLAGS,ACTIVE,BSSID", "dev", "wifi", "list"])
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- let details = ""
- if (text.trim()) {
- const lines = text.trim().split('\n')
- const bands = []
-
- for (const line of lines) {
- const parts = line.split(':')
- if (parts.length >= 11 && parts[0] === root.networkInfoSSID) {
- const signal = parts[1] || "0"
- const security = parts[2] || "Open"
- const freq = parts[3] || "Unknown"
- const rate = parts[4] || "Unknown"
- const channel = parts[6] || "Unknown"
- const isActive = parts[9] === "yes"
- let colonCount = 0
- let bssidStart = -1
- for (var i = 0; i < line.length; i++) {
- if (line[i] === ':') {
- colonCount++
- if (colonCount === 10) {
- bssidStart = i + 1
- break
- }
- }
- }
- const bssid = bssidStart >= 0 ? line.substring(bssidStart).replace(/\\:/g, ":") : ""
-
- let band = "Unknown"
- const freqNum = parseInt(freq)
- if (freqNum >= 2400 && freqNum <= 2500) {
- band = "2.4 GHz"
- } else if (freqNum >= 5000 && freqNum <= 6000) {
- band = "5 GHz"
- } else if (freqNum >= 6000) {
- band = "6 GHz"
- }
-
- bands.push({
- "band": band,
- "freq": freq,
- "channel": channel,
- "signal": signal,
- "rate": rate,
- "security": security,
- "isActive": isActive,
- "bssid": bssid
- })
- }
- }
-
- if (bands.length > 0) {
- bands.sort((a, b) => {
- if (a.isActive && !b.isActive) {
- return -1
- }
- if (!a.isActive && b.isActive) {
- return 1
- }
- return parseInt(b.signal) - parseInt(a.signal)
- })
-
- for (var i = 0; i < bands.length; i++) {
- const b = bands[i]
- if (b.isActive) {
- details += "● " + b.band + " (Connected) - " + b.signal + "%\\n"
- } else {
- details += " " + b.band + " - " + b.signal + "%\\n"
- }
- details += " Channel " + b.channel + " (" + b.freq + " MHz) • " + b.rate + " Mbit/s\\n"
- details += " " + b.bssid
- if (i < bands.length - 1) {
- details += "\\n\\n"
- }
- }
- }
- }
-
- if (details === "") {
- details = "Network information not found or network not available."
- }
-
- root.networkInfoDetails = details
- root.networkInfoLoading = false
- }
- }
-
- onExited: exitCode => {
- root.networkInfoLoading = false
- if (exitCode !== 0) {
- root.networkInfoDetails = "Failed to fetch network information"
- }
- }
- }
-
- function enableWifiDevice() {
- wifiDeviceEnabler.running = true
- }
-
- Process {
- id: wifiDeviceEnabler
- command: lowPriorityCmd.concat(["sh", "-c", "WIFI_DEV=$(nmcli -t -f DEVICE,TYPE device | grep wifi | cut -d: -f1 | head -1); if [ -n \"$WIFI_DEV\" ]; then nmcli device connect \"$WIFI_DEV\"; else echo \"No WiFi device found\"; exit 1; fi"])
- running: false
-
- onExited: exitCode => {
- if (exitCode === 0) {
- ToastService.showInfo("WiFi enabled")
- } else {
- ToastService.showError("Failed to enable WiFi")
- }
- doRefreshNetworkState()
- }
- }
-
- function connectToWifiAndSetPreference(ssid, password) {
- connectToWifi(ssid, password)
- setNetworkPreference("wifi")
- }
-
- function toggleNetworkConnection(type) {
- if (type === "ethernet") {
- if (root.networkStatus === "ethernet") {
- ethernetDisconnector.running = true
- } else {
- ethernetConnector.running = true
- }
- }
- }
-
- Process {
- id: ethernetDisconnector
- command: lowPriorityCmd.concat(["sh", "-c", "nmcli device disconnect $(nmcli -t -f DEVICE,TYPE device | grep ethernet | cut -d: -f1 | head -1)"])
- running: false
-
- onExited: function (exitCode) {
- doRefreshNetworkState()
- }
- }
-
- Process {
- id: ethernetConnector
- command: lowPriorityCmd.concat(["sh", "-c", "ETH_DEV=$(nmcli -t -f DEVICE,TYPE device | grep ethernet | cut -d: -f1 | head -1); if [ -n \"$ETH_DEV\" ]; then nmcli device connect \"$ETH_DEV\"; else echo \"No ethernet device found\"; exit 1; fi"])
- running: false
-
- onExited: function (exitCode) {
- doRefreshNetworkState()
- }
- }
-
- function getNetworkInfo(ssid) {
- const network = root.wifiNetworks.find(n => n.ssid === ssid)
- if (!network) {
- return null
- }
-
- return {
- "ssid": network.ssid,
- "signal": network.signal,
- "secured": network.secured,
- "saved": network.saved,
- "connected": network.connected,
- "bssid": network.bssid
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/LocationService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/LocationService.qml
deleted file mode 100644
index 0fde587..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/LocationService.qml
+++ /dev/null
@@ -1,55 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- readonly property bool locationAvailable: DMSService.isConnected && (DMSService.capabilities.length === 0 || DMSService.capabilities.includes("location"))
- readonly property bool valid: latitude !== 0 || longitude !== 0
-
- property var latitude: 0.0
- property var longitude: 0.0
-
- signal locationChanged(var data)
-
- onLocationAvailableChanged: {
- if (locationAvailable && !valid)
- getState();
- }
-
- Connections {
- target: DMSService
-
- function onLocationStateUpdate(data) {
- if (!locationAvailable)
- return;
- handleStateUpdate(data);
- }
- }
-
- function handleStateUpdate(data) {
- const lat = data.latitude;
- const lon = data.longitude;
- if (lat === 0 && lon === 0)
- return;
-
- root.latitude = lat;
- root.longitude = lon;
- root.locationChanged(data);
- }
-
- function getState() {
- if (!locationAvailable)
- return;
-
- DMSService.sendRequest("location.getState", null, response => {
- if (response.result)
- handleStateUpdate(response.result);
- });
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/MprisController.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/MprisController.qml
deleted file mode 100644
index 44ad135..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/MprisController.qml
+++ /dev/null
@@ -1,78 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Services.Mpris
-import qs.Common
-
-Singleton {
- id: root
-
- readonly property list<MprisPlayer> availablePlayers: Mpris.players.values
- property MprisPlayer activePlayer: null
-
- onAvailablePlayersChanged: _resolveActivePlayer()
- Component.onCompleted: _resolveActivePlayer()
-
- Instantiator {
- model: root.availablePlayers
- delegate: Connections {
- required property MprisPlayer modelData
- target: modelData
- function onIsPlayingChanged() {
- if (modelData.isPlaying)
- root._resolveActivePlayer();
- }
- }
- }
-
- function _resolveActivePlayer(): void {
- const playing = availablePlayers.find(p => p.isPlaying);
- if (playing) {
- activePlayer = playing;
- _persistIdentity(playing.identity);
- return;
- }
- if (activePlayer && availablePlayers.indexOf(activePlayer) >= 0)
- return;
- const savedId = SessionData.lastPlayerIdentity;
- if (savedId) {
- const match = availablePlayers.find(p => p.identity === savedId);
- if (match) {
- activePlayer = match;
- return;
- }
- }
- activePlayer = availablePlayers.find(p => p.canControl && p.canPlay) ?? null;
- if (activePlayer)
- _persistIdentity(activePlayer.identity);
- }
-
- function setActivePlayer(player: MprisPlayer): void {
- activePlayer = player;
- if (player)
- _persistIdentity(player.identity);
- }
-
- function _persistIdentity(identity: string): void {
- if (identity && SessionData.lastPlayerIdentity !== identity)
- SessionData.set("lastPlayerIdentity", identity);
- }
-
- Timer {
- interval: 1000
- running: root.activePlayer?.playbackState === MprisPlaybackState.Playing
- repeat: true
- onTriggered: root.activePlayer?.positionChanged()
- }
-
- function previousOrRewind(): void {
- if (!activePlayer)
- return;
- if (activePlayer.position > 8 && activePlayer.canSeek)
- activePlayer.position = 0;
- else if (activePlayer.canGoPrevious)
- activePlayer.previous();
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/MultimediaService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/MultimediaService.qml
deleted file mode 100644
index f570c72..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/MultimediaService.qml
+++ /dev/null
@@ -1,35 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-
-Singleton {
- id: root
-
- property bool available: false
-
- function detectAvailability() {
- try {
- const testObj = Qt.createQmlObject(`
- import QtQuick
- import QtMultimedia
- Item {}
- `, root, "MultimediaService.TestComponent");
- if (testObj) {
- testObj.destroy();
- }
- available = true;
- return true;
- } catch (e) {
- available = false;
- return false;
- }
- }
-
- Component.onCompleted: {
- if (!detectAvailability()) {
- console.warn("MultimediaService: QtMultimedia not available");
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/MuxService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/MuxService.qml
deleted file mode 100644
index c2f941c..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/MuxService.qml
+++ /dev/null
@@ -1,230 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- property var sessions: []
- property bool loading: false
-
- property bool tmuxAvailable: false
- property bool zellijAvailable: false
- readonly property bool currentMuxAvailable: muxType === "zellij" ? zellijAvailable : tmuxAvailable
-
- readonly property string muxType: SettingsData.muxType
- readonly property string displayName: muxType === "zellij" ? "Zellij" : "Tmux"
-
- readonly property var terminalFlags: ({
- "ghostty": ["-e"],
- "kitty": ["-e"],
- "alacritty": ["-e"],
- "foot": [],
- "wezterm": ["start", "--"],
- "gnome-terminal": ["--"],
- "xterm": ["-e"],
- "konsole": ["-e"],
- "st": ["-e"],
- "terminator": ["-e"],
- "xfce4-terminal": ["-e"]
- })
-
- function getTerminalFlag(terminal) {
- return terminalFlags[terminal] ?? ["-e"]
- }
-
- readonly property string terminal: Quickshell.env("TERMINAL") || "ghostty"
-
- function _terminalPrefix() {
- return [terminal].concat(getTerminalFlag(terminal))
- }
-
- Process {
- id: tmuxCheckProcess
- command: ["which", "tmux"]
- running: false
- onExited: (code) => { root.tmuxAvailable = (code === 0) }
- }
-
- Process {
- id: zellijCheckProcess
- command: ["which", "zellij"]
- running: false
- onExited: (code) => { root.zellijAvailable = (code === 0) }
- }
-
- function checkAvailability() {
- tmuxCheckProcess.running = true
- zellijCheckProcess.running = true
- }
-
- Component.onCompleted: checkAvailability()
-
- Process {
- id: listProcess
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- try {
- if (root.muxType === "zellij")
- root._parseZellijSessions(text)
- else
- root._parseTmuxSessions(text)
- } catch (e) {
- console.error("[MuxService] Error parsing sessions:", e)
- root.sessions = []
- }
- root.loading = false
- }
- }
-
- stderr: SplitParser {
- onRead: (line) => {
- if (line.trim())
- console.error("[MuxService] stderr:", line)
- }
- }
-
- onExited: (code) => {
- if (code !== 0 && code !== 1) {
- console.warn("[MuxService] Process exited with code:", code)
- root.sessions = []
- }
- root.loading = false
- }
- }
-
- function refreshSessions() {
- if (!root.currentMuxAvailable) {
- root.sessions = []
- return
- }
-
- root.loading = true
-
- if (listProcess.running)
- listProcess.running = false
-
- if (root.muxType === "zellij")
- listProcess.command = ["zellij", "list-sessions", "--no-formatting"]
- else
- listProcess.command = ["tmux", "list-sessions", "-F", "#{session_name}|#{session_windows}|#{session_attached}"]
-
- Qt.callLater(function () {
- listProcess.running = true
- })
- }
-
- function _isSessionExcluded(name) {
- var filter = SettingsData.muxSessionFilter.trim()
- if (filter.length === 0)
- return false
- var parts = filter.split(",")
- for (var i = 0; i < parts.length; i++) {
- var pattern = parts[i].trim()
- if (pattern.length === 0)
- continue
- if (pattern.startsWith("/") && pattern.endsWith("/") && pattern.length > 2) {
- try {
- var re = new RegExp(pattern.slice(1, -1))
- if (re.test(name))
- return true
- } catch (e) {}
- } else {
- if (name.toLowerCase() === pattern.toLowerCase())
- return true
- }
- }
- return false
- }
-
- function _parseTmuxSessions(output) {
- var sessionList = []
- var lines = output.trim().split('\n')
-
- for (var i = 0; i < lines.length; i++) {
- var line = lines[i].trim()
- if (line.length === 0)
- continue
-
- var parts = line.split('|')
- if (parts.length >= 3 && !_isSessionExcluded(parts[0])) {
- sessionList.push({
- name: parts[0],
- windows: parts[1],
- attached: parts[2] === "1"
- })
- }
- }
-
- root.sessions = sessionList
- }
-
- function _parseZellijSessions(output) {
- var sessionList = []
- var lines = output.trim().split('\n')
-
- for (var i = 0; i < lines.length; i++) {
- var line = lines[i].trim()
- if (line.length === 0)
- continue
-
- var exited = line.includes("(EXITED")
- var bracketIdx = line.indexOf(" [")
- var name = (bracketIdx > 0 ? line.substring(0, bracketIdx) : line).trim()
-
- if (!_isSessionExcluded(name)) {
- sessionList.push({
- name: name,
- windows: "N/A",
- attached: !exited
- })
- }
- }
-
- root.sessions = sessionList
- }
-
- function attachToSession(name) {
- if (SettingsData.muxUseCustomCommand && SettingsData.muxCustomCommand) {
- Quickshell.execDetached([SettingsData.muxCustomCommand, name])
- } else if (root.muxType === "zellij") {
- Quickshell.execDetached(_terminalPrefix().concat(["zellij", "attach", name]))
- } else {
- Quickshell.execDetached(_terminalPrefix().concat(["tmux", "attach", "-t", name]))
- }
- }
-
- function createSession(name) {
- if (SettingsData.muxUseCustomCommand && SettingsData.muxCustomCommand) {
- Quickshell.execDetached([SettingsData.muxCustomCommand, name])
- } else if (root.muxType === "zellij") {
- Quickshell.execDetached(_terminalPrefix().concat(["zellij", "-s", name]))
- } else {
- Quickshell.execDetached(_terminalPrefix().concat(["tmux", "new-session", "-s", name]))
- }
- }
-
- readonly property bool supportsRename: muxType !== "zellij"
-
- function renameSession(oldName, newName) {
- if (root.muxType === "zellij")
- return
- Quickshell.execDetached(["tmux", "rename-session", "-t", oldName, newName])
- Qt.callLater(refreshSessions)
- }
-
- function killSession(name) {
- if (root.muxType === "zellij") {
- Quickshell.execDetached(["zellij", "kill-session", name])
- } else {
- Quickshell.execDetached(["tmux", "kill-session", "-t", name])
- }
- Qt.callLater(refreshSessions)
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NetworkService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NetworkService.qml
deleted file mode 100644
index 38383d2..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NetworkService.qml
+++ /dev/null
@@ -1,313 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-
-Singleton {
- id: root
-
- property bool networkAvailable: activeService !== null
- property string backend: activeService?.backend ?? ""
- property string networkStatus: activeService?.networkStatus ?? "disconnected"
- property string primaryConnection: activeService?.primaryConnection ?? ""
-
- property string ethernetIP: activeService?.ethernetIP ?? ""
- property string ethernetInterface: activeService?.ethernetInterface ?? ""
- property bool ethernetConnected: activeService?.ethernetConnected ?? false
- property string ethernetConnectionUuid: activeService?.ethernetConnectionUuid ?? ""
- property var ethernetDevices: activeService?.ethernetDevices ?? []
-
- property var wiredConnections: activeService?.wiredConnections ?? []
-
- property string wifiIP: activeService?.wifiIP ?? ""
- property string wifiInterface: activeService?.wifiInterface ?? ""
- property bool wifiConnected: activeService?.wifiConnected ?? false
- property bool wifiEnabled: activeService?.wifiEnabled ?? true
- property string wifiConnectionUuid: activeService?.wifiConnectionUuid ?? ""
- property string wifiDevicePath: activeService?.wifiDevicePath ?? ""
- property string activeAccessPointPath: activeService?.activeAccessPointPath ?? ""
- property var wifiDevices: activeService?.wifiDevices ?? []
- property string wifiDeviceOverride: activeService?.wifiDeviceOverride ?? ""
- property string connectingDevice: activeService?.connectingDevice ?? ""
-
- property string currentWifiSSID: activeService?.currentWifiSSID ?? ""
- property int wifiSignalStrength: activeService?.wifiSignalStrength ?? 0
- property var wifiNetworks: activeService?.wifiNetworks ?? []
- property var savedConnections: activeService?.savedConnections ?? []
- property var ssidToConnectionName: activeService?.ssidToConnectionName ?? ({})
- property var wifiSignalIcon: activeService?.wifiSignalIcon ?? "wifi_off"
-
- property string userPreference: activeService?.userPreference ?? "auto"
- property bool isConnecting: activeService?.isConnecting ?? false
- property string connectingSSID: activeService?.connectingSSID ?? ""
- property string connectionError: activeService?.connectionError ?? ""
-
- property bool isScanning: activeService?.isScanning ?? false
- property bool autoScan: activeService?.autoScan ?? false
-
- property bool wifiAvailable: activeService?.wifiAvailable ?? true
- property bool wifiToggling: activeService?.wifiToggling ?? false
- property bool changingPreference: activeService?.changingPreference ?? false
- property string targetPreference: activeService?.targetPreference ?? ""
- property var savedWifiNetworks: activeService?.savedWifiNetworks ?? []
- property string connectionStatus: activeService?.connectionStatus ?? ""
- property string lastConnectionError: activeService?.lastConnectionError ?? ""
- property bool passwordDialogShouldReopen: activeService?.passwordDialogShouldReopen ?? false
- property bool autoRefreshEnabled: activeService?.autoRefreshEnabled ?? false
- property string wifiPassword: activeService?.wifiPassword ?? ""
- property string forgetSSID: activeService?.forgetSSID ?? ""
-
- property string networkInfoSSID: activeService?.networkInfoSSID ?? ""
- property string networkInfoDetails: activeService?.networkInfoDetails ?? ""
- property bool networkInfoLoading: activeService?.networkInfoLoading ?? false
-
- property string networkWiredInfoUUID: activeService?.networkWiredInfoUUID ?? ""
- property string networkWiredInfoDetails: activeService?.networkWiredInfoDetails ?? ""
- property bool networkWiredInfoLoading: activeService?.networkWiredInfoLoading ?? false
-
- property int refCount: activeService?.refCount ?? 0
- property bool stateInitialized: activeService?.stateInitialized ?? false
-
- property bool subscriptionConnected: activeService?.subscriptionConnected ?? false
-
- property var vpnProfiles: activeService?.vpnProfiles ?? []
- property var vpnActive: activeService?.vpnActive ?? []
- property bool vpnAvailable: activeService?.vpnAvailable ?? false
- property bool vpnIsBusy: activeService?.vpnIsBusy ?? false
- property bool vpnConnected: activeService?.vpnConnected ?? false
- property string vpnActiveUuid: activeService?.activeUuid ?? ""
- property string vpnActiveName: activeService?.activeName ?? ""
-
- property string credentialsToken: activeService?.credentialsToken ?? ""
- property string credentialsSSID: activeService?.credentialsSSID ?? ""
- property string credentialsSetting: activeService?.credentialsSetting ?? ""
- property var credentialsFields: activeService?.credentialsFields ?? []
- property var credentialsHints: activeService?.credentialsHints ?? []
- property string credentialsReason: activeService?.credentialsReason ?? ""
- property bool credentialsRequested: activeService?.credentialsRequested ?? false
-
- signal networksUpdated
- signal connectionChanged
- signal credentialsNeeded(string token, string ssid, string setting, var fields, var hints, string reason, string connType, string connName, string vpnService, var fieldsInfo)
-
- property bool usingLegacy: false
- property var activeService: null
-
- readonly property string socketPath: Quickshell.env("DMS_SOCKET")
-
- Component.onCompleted: {
- console.info("NetworkService: Initializing...");
- if (!socketPath || socketPath.length === 0) {
- console.info("NetworkService: DMS_SOCKET not set, using LegacyNetworkService");
- useLegacyService();
- } else {
- console.log("NetworkService: DMS_SOCKET found, waiting for capabilities...");
- }
- }
-
- Connections {
- target: DMSNetworkService
-
- function onNetworkAvailableChanged() {
- if (!activeService && DMSNetworkService.networkAvailable) {
- console.info("NetworkService: Network capability detected, using DMSNetworkService");
- activeService = DMSNetworkService;
- usingLegacy = false;
- console.info("NetworkService: Switched to DMSNetworkService, networkAvailable:", networkAvailable);
- connectSignals();
- } else if (!activeService && !DMSNetworkService.networkAvailable && socketPath && socketPath.length > 0) {
- console.info("NetworkService: Network capability not available in DMS, using LegacyNetworkService");
- useLegacyService();
- }
- }
- }
-
- function useLegacyService() {
- activeService = LegacyNetworkService;
- usingLegacy = true;
- console.info("NetworkService: Switched to LegacyNetworkService, networkAvailable:", networkAvailable);
- if (LegacyNetworkService.activate) {
- LegacyNetworkService.activate();
- }
- connectSignals();
- }
-
- function connectSignals() {
- if (activeService) {
- if (activeService.networksUpdated) {
- activeService.networksUpdated.connect(root.networksUpdated);
- }
- if (activeService.connectionChanged) {
- activeService.connectionChanged.connect(root.connectionChanged);
- }
- if (activeService.credentialsNeeded) {
- activeService.credentialsNeeded.connect(root.credentialsNeeded);
- }
- }
- }
-
- function addRef() {
- if (activeService && activeService.addRef) {
- activeService.addRef();
- }
- }
-
- function removeRef() {
- if (activeService && activeService.removeRef) {
- activeService.removeRef();
- }
- }
-
- function getState() {
- if (activeService && activeService.getState) {
- activeService.getState();
- }
- }
-
- function scanWifi() {
- if (activeService && activeService.scanWifi) {
- activeService.scanWifi();
- }
- }
-
- function scanWifiNetworks() {
- if (activeService && activeService.scanWifiNetworks) {
- activeService.scanWifiNetworks();
- }
- }
-
- function connectToWifi(ssid, password = "", username = "", anonymousIdentity = "", domainSuffixMatch = "") {
- if (activeService && activeService.connectToWifi) {
- activeService.connectToWifi(ssid, password, username, anonymousIdentity, domainSuffixMatch);
- }
- }
-
- function disconnectWifi() {
- if (activeService && activeService.disconnectWifi) {
- activeService.disconnectWifi();
- }
- }
-
- function forgetWifiNetwork(ssid) {
- if (activeService && activeService.forgetWifiNetwork) {
- activeService.forgetWifiNetwork(ssid);
- }
- }
-
- function toggleWifiRadio() {
- if (activeService && activeService.toggleWifiRadio) {
- activeService.toggleWifiRadio();
- }
- }
-
- function enableWifiDevice() {
- if (activeService && activeService.enableWifiDevice) {
- activeService.enableWifiDevice();
- }
- }
-
- function setNetworkPreference(preference) {
- if (activeService && activeService.setNetworkPreference) {
- activeService.setNetworkPreference(preference);
- }
- }
-
- function setConnectionPriority(type) {
- if (activeService && activeService.setConnectionPriority) {
- activeService.setConnectionPriority(type);
- }
- }
-
- function connectToWifiAndSetPreference(ssid, password, username = "", anonymousIdentity = "", domainSuffixMatch = "") {
- if (activeService && activeService.connectToWifiAndSetPreference) {
- activeService.connectToWifiAndSetPreference(ssid, password, username, anonymousIdentity, domainSuffixMatch);
- }
- }
-
- function toggleNetworkConnection(type) {
- if (activeService && activeService.toggleNetworkConnection) {
- activeService.toggleNetworkConnection(type);
- }
- }
-
- function disconnectEthernetDevice(deviceName) {
- if (activeService && activeService.disconnectEthernetDevice) {
- activeService.disconnectEthernetDevice(deviceName);
- }
- }
-
- function startAutoScan() {
- if (activeService && activeService.startAutoScan) {
- activeService.startAutoScan();
- }
- }
-
- function stopAutoScan() {
- if (activeService && activeService.stopAutoScan) {
- activeService.stopAutoScan();
- }
- }
-
- function fetchNetworkInfo(ssid) {
- if (activeService && activeService.fetchNetworkInfo) {
- activeService.fetchNetworkInfo(ssid);
- }
- }
-
- function fetchWiredNetworkInfo(uuid) {
- if (activeService && activeService.fetchWiredNetworkInfo) {
- activeService.fetchWiredNetworkInfo(uuid);
- }
- }
-
- function getNetworkInfo(ssid) {
- if (activeService && activeService.getNetworkInfo) {
- return activeService.getNetworkInfo(ssid);
- }
- return null;
- }
-
- function getWiredNetworkInfo(uuid) {
- if (activeService && activeService.getWiredNetworkInfo) {
- return activeService.getWiredNetworkInfo(uuid);
- }
- return null;
- }
-
- function refreshNetworkState() {
- if (activeService && activeService.refreshNetworkState) {
- activeService.refreshNetworkState();
- }
- }
-
- function connectToSpecificWiredConfig(uuid) {
- if (activeService && activeService.connectToSpecificWiredConfig) {
- activeService.connectToSpecificWiredConfig(uuid);
- }
- }
-
- function submitCredentials(token, secrets, save) {
- if (activeService && activeService.submitCredentials) {
- activeService.submitCredentials(token, secrets, save);
- }
- }
-
- function cancelCredentials(token) {
- if (activeService && activeService.cancelCredentials) {
- activeService.cancelCredentials(token);
- }
- }
-
- function setWifiAutoconnect(ssid, autoconnect) {
- if (activeService && activeService.setWifiAutoconnect) {
- activeService.setWifiAutoconnect(ssid, autoconnect);
- }
- }
-
- function setWifiDeviceOverride(deviceName) {
- if (activeService && activeService.setWifiDeviceOverride) {
- activeService.setWifiDeviceOverride(deviceName);
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml
deleted file mode 100644
index 49748eb..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NiriService.qml
+++ /dev/null
@@ -1,1494 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtCore
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- readonly property string socketPath: Quickshell.env("NIRI_SOCKET")
-
- property var workspaces: ({})
- property var allWorkspaces: []
- property int focusedWorkspaceIndex: 0
- property string focusedWorkspaceId: ""
- property var currentOutputWorkspaces: []
- property string currentOutput: ""
-
- property var outputs: ({})
- property var windows: []
- property var displayScales: ({})
-
- property var _realOutputs: ({})
-
- property bool inOverview: false
-
- property var casts: []
- property bool hasCasts: casts.length > 0
- property bool hasActiveCast: casts.some(c => c.is_active)
-
- property int currentKeyboardLayoutIndex: 0
- property var keyboardLayoutNames: []
-
- property string configValidationOutput: ""
- property bool hasInitialConnection: false
- property bool suppressConfigToast: true
- property bool suppressNextConfigToast: false
- property bool matugenSuppression: false
- property bool configGenerationPending: false
-
- readonly property string screenshotsDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.PicturesLocation)) + "/Screenshots"
- property string pendingScreenshotPath: ""
-
- signal windowUrgentChanged
- signal configReloaded
-
- function setWorkspaces(newMap) {
- root.workspaces = newMap;
- root.allWorkspaces = Object.values(newMap).sort((a, b) => a.idx - b.idx);
- }
-
- function validate() {
- validateProcess.running = true;
- }
-
- Component.onCompleted: fetchOutputs()
-
- Timer {
- id: suppressToastTimer
- interval: 3000
- onTriggered: root.suppressConfigToast = false
- }
-
- Timer {
- id: suppressResetTimer
- interval: 5000
- onTriggered: root.matugenSuppression = false
- }
-
- Timer {
- id: configGenerationDebounce
- interval: 100
- onTriggered: root.doGenerateNiriLayoutConfig()
- }
-
- property int _lastGapValue: -1
-
- Connections {
- target: SettingsData
- function onBarConfigsChanged() {
- const newGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4));
- if (newGaps === root._lastGapValue)
- return;
- root._lastGapValue = newGaps;
- generateNiriLayoutConfig();
- }
- }
-
- Process {
- id: validateProcess
- command: ["niri", "validate"]
- running: false
-
- stderr: StdioCollector {
- onStreamFinished: {
- const lines = text.split('\n');
- const trimmedLines = lines.map(line => line.replace(/\s+$/, '')).filter(line => line.length > 0);
- configValidationOutput = trimmedLines.join('\n').trim();
- }
- }
-
- onExited: exitCode => {
- if (exitCode === 0) {
- configValidationOutput = "";
- } else if (hasInitialConnection && configValidationOutput.length > 0) {
- ToastService.showError("niri: failed to load config", configValidationOutput, "", "niri-config");
- }
- }
- }
-
- Process {
- id: writeConfigProcess
- property string configContent: ""
- property string configPath: ""
-
- onExited: exitCode => {
- if (exitCode === 0) {
- console.info("NiriService: Generated layout config at", configPath);
- return;
- }
- console.warn("NiriService: Failed to write layout config, exit code:", exitCode);
- }
- }
-
- Process {
- id: writeAlttabProcess
- property string alttabContent: ""
- property string alttabPath: ""
-
- onExited: exitCode => {
- if (exitCode === 0) {
- console.info("NiriService: Generated alttab config at", alttabPath);
- return;
- }
- console.warn("NiriService: Failed to write alttab config, exit code:", exitCode);
- }
- }
-
- Process {
- id: writeBlurruleProcess
- property string blurrulePath: ""
-
- onExited: exitCode => {
- if (exitCode === 0) {
- console.info("NiriService: Generated wpblur config at", blurrulePath);
- return;
- }
- console.warn("NiriService: Failed to write wpblur config, exit code:", exitCode);
- }
- }
-
- Process {
- id: writeCursorProcess
- property string cursorContent: ""
- property string cursorPath: ""
-
- onExited: exitCode => {
- if (exitCode === 0) {
- console.info("NiriService: Generated cursor config at", cursorPath);
- return;
- }
- console.warn("NiriService: Failed to write cursor config, exit code:", exitCode);
- }
- }
-
- DankSocket {
- id: eventStreamSocket
- path: root.socketPath
- connected: CompositorService.isNiri
-
- onConnectionStateChanged: {
- if (connected) {
- send('"EventStream"');
- fetchOutputs();
- }
- }
-
- parser: SplitParser {
- onRead: line => {
- try {
- const event = JSON.parse(line);
- handleNiriEvent(event);
- } catch (e) {
- console.warn("NiriService: Failed to parse event:", line, e);
- }
- }
- }
- }
-
- DankSocket {
- id: requestSocket
- path: root.socketPath
- connected: CompositorService.isNiri
- }
-
- function fetchOutputs() {
- if (!CompositorService.isNiri)
- return;
- Proc.runCommand("niri-fetch-outputs", ["niri", "msg", "-j", "outputs"], (output, exitCode) => {
- if (exitCode !== 0) {
- console.warn("NiriService: Failed to fetch outputs, exit code:", exitCode);
- return;
- }
- try {
- const outputsData = JSON.parse(output);
- outputs = outputsData;
- console.info("NiriService: Loaded", Object.keys(outputsData).length, "outputs");
- updateDisplayScales();
- if (windows.length > 0) {
- windows = sortWindowsByLayout(windows);
- }
- } catch (e) {
- console.warn("NiriService: Failed to parse outputs:", e);
- }
- });
- }
-
- function updateDisplayScales() {
- if (!outputs || Object.keys(outputs).length === 0)
- return;
- const scales = {};
- for (const outputName in outputs) {
- const output = outputs[outputName];
- if (output.logical && output.logical.scale !== undefined) {
- scales[outputName] = output.logical.scale;
- }
- }
-
- displayScales = scales;
- }
-
- function sortWindowsByLayout(windowList) {
- const enriched = windowList.map(w => {
- const ws = workspaces[w.workspace_id];
- if (!ws) {
- return {
- "window": w,
- "outputX": 999999,
- "outputY": 999999,
- "wsIdx": 999999,
- "col": 999999,
- "row": 999999
- };
- }
-
- const outputInfo = outputs[ws.output];
- const outputX = (outputInfo && outputInfo.logical) ? outputInfo.logical.x : 999999;
- const outputY = (outputInfo && outputInfo.logical) ? outputInfo.logical.y : 999999;
-
- const pos = w.layout?.pos_in_scrolling_layout;
- const col = (pos && pos.length >= 2) ? pos[0] : 999999;
- const row = (pos && pos.length >= 2) ? pos[1] : 999999;
-
- return {
- "window": w,
- "outputX": outputX,
- "outputY": outputY,
- "wsIdx": ws.idx,
- "col": col,
- "row": row
- };
- });
-
- enriched.sort((a, b) => {
- if (a.outputX !== b.outputX)
- return a.outputX - b.outputX;
- if (a.outputY !== b.outputY)
- return a.outputY - b.outputY;
- if (a.wsIdx !== b.wsIdx)
- return a.wsIdx - b.wsIdx;
- if (a.col !== b.col)
- return a.col - b.col;
- if (a.row !== b.row)
- return a.row - b.row;
- return a.window.id - b.window.id;
- });
-
- return enriched.map(e => e.window);
- }
-
- function handleNiriEvent(event) {
- const eventType = Object.keys(event)[0];
-
- switch (eventType) {
- case 'WorkspacesChanged':
- handleWorkspacesChanged(event.WorkspacesChanged);
- break;
- case 'WorkspaceActivated':
- handleWorkspaceActivated(event.WorkspaceActivated);
- break;
- case 'WorkspaceActiveWindowChanged':
- handleWorkspaceActiveWindowChanged(event.WorkspaceActiveWindowChanged);
- break;
- case 'WindowFocusChanged':
- handleWindowFocusChanged(event.WindowFocusChanged);
- break;
- case 'WindowsChanged':
- handleWindowsChanged(event.WindowsChanged);
- break;
- case 'WindowClosed':
- handleWindowClosed(event.WindowClosed);
- break;
- case 'WindowOpenedOrChanged':
- handleWindowOpenedOrChanged(event.WindowOpenedOrChanged);
- break;
- case 'WindowLayoutsChanged':
- handleWindowLayoutsChanged(event.WindowLayoutsChanged);
- break;
- case 'OutputsChanged':
- handleOutputsChanged(event.OutputsChanged);
- break;
- case 'OverviewOpenedOrClosed':
- handleOverviewChanged(event.OverviewOpenedOrClosed);
- break;
- case 'ConfigLoaded':
- handleConfigLoaded(event.ConfigLoaded);
- break;
- case 'KeyboardLayoutsChanged':
- handleKeyboardLayoutsChanged(event.KeyboardLayoutsChanged);
- break;
- case 'KeyboardLayoutSwitched':
- handleKeyboardLayoutSwitched(event.KeyboardLayoutSwitched);
- break;
- case 'WorkspaceUrgencyChanged':
- handleWorkspaceUrgencyChanged(event.WorkspaceUrgencyChanged);
- break;
- case 'WindowUrgencyChanged':
- handleWindowUrgencyChanged(event.WindowUrgencyChanged);
- break;
- case 'ScreenshotCaptured':
- handleScreenshotCaptured(event.ScreenshotCaptured);
- break;
- case 'CastsChanged':
- handleCastsChanged(event.CastsChanged);
- break;
- case 'CastStartedOrChanged':
- handleCastStartedOrChanged(event.CastStartedOrChanged);
- break;
- case 'CastStopped':
- handleCastStopped(event.CastStopped);
- break;
- }
- }
-
- function handleWorkspacesChanged(data) {
- const newWorkspaces = {};
-
- for (const ws of data.workspaces) {
- const oldWs = root.workspaces[ws.id];
- newWorkspaces[ws.id] = ws;
- if (oldWs && oldWs.active_window_id !== undefined) {
- newWorkspaces[ws.id].active_window_id = oldWs.active_window_id;
- }
- }
-
- setWorkspaces(newWorkspaces);
-
- focusedWorkspaceIndex = allWorkspaces.findIndex(w => w.is_focused);
- if (focusedWorkspaceIndex >= 0) {
- const focusedWs = allWorkspaces[focusedWorkspaceIndex];
- focusedWorkspaceId = focusedWs.id;
- currentOutput = focusedWs.output || "";
- } else {
- focusedWorkspaceIndex = 0;
- focusedWorkspaceId = "";
- }
-
- updateCurrentOutputWorkspaces();
- }
-
- function handleWorkspaceActivated(data) {
- const ws = root.workspaces[data.id];
- if (!ws) {
- return;
- }
- const output = ws.output;
-
- const updatedWorkspaces = {};
-
- for (const id in root.workspaces) {
- const workspace = root.workspaces[id];
- const got_activated = workspace.id === data.id;
-
- const updatedWs = {};
- for (let prop in workspace) {
- updatedWs[prop] = workspace[prop];
- }
-
- if (workspace.output === output) {
- updatedWs.is_active = got_activated;
- }
-
- if (data.focused) {
- updatedWs.is_focused = got_activated;
- }
-
- updatedWorkspaces[id] = updatedWs;
- }
-
- setWorkspaces(updatedWorkspaces);
-
- focusedWorkspaceId = data.id;
- focusedWorkspaceIndex = allWorkspaces.findIndex(w => w.id === data.id);
-
- if (focusedWorkspaceIndex >= 0) {
- currentOutput = allWorkspaces[focusedWorkspaceIndex].output || "";
- }
-
- updateCurrentOutputWorkspaces();
- }
-
- function handleWindowFocusChanged(data) {
- const focusedWindowId = data.id;
-
- let focusedWindow = null;
- const updatedWindows = [];
-
- for (var i = 0; i < windows.length; i++) {
- const w = windows[i];
- const updatedWindow = {};
-
- for (let prop in w) {
- updatedWindow[prop] = w[prop];
- }
-
- updatedWindow.is_focused = (w.id === focusedWindowId);
- if (updatedWindow.is_focused) {
- focusedWindow = updatedWindow;
- }
-
- updatedWindows.push(updatedWindow);
- }
-
- windows = updatedWindows;
-
- if (focusedWindow) {
- const ws = root.workspaces[focusedWindow.workspace_id];
- if (ws && ws.active_window_id !== focusedWindowId) {
- const updatedWs = {};
- for (let prop in ws) {
- updatedWs[prop] = ws[prop];
- }
- updatedWs.active_window_id = focusedWindowId;
-
- const updatedWorkspaces = {};
- for (const id in root.workspaces) {
- updatedWorkspaces[id] = id === focusedWindow.workspace_id ? updatedWs : root.workspaces[id];
- }
- setWorkspaces(updatedWorkspaces);
- }
- }
- }
-
- function handleWorkspaceActiveWindowChanged(data) {
- const ws = root.workspaces[data.workspace_id];
- if (ws) {
- const updatedWs = {};
- for (let prop in ws) {
- updatedWs[prop] = ws[prop];
- }
- updatedWs.active_window_id = data.active_window_id;
-
- const updatedWorkspaces = {};
- for (const id in root.workspaces) {
- updatedWorkspaces[id] = id === data.workspace_id ? updatedWs : root.workspaces[id];
- }
- setWorkspaces(updatedWorkspaces);
- }
-
- const updatedWindows = [];
-
- for (var i = 0; i < windows.length; i++) {
- const w = windows[i];
- const updatedWindow = {};
-
- for (let prop in w) {
- updatedWindow[prop] = w[prop];
- }
-
- if (data.active_window_id !== null && data.active_window_id !== undefined) {
- updatedWindow.is_focused = (w.id == data.active_window_id);
- } else {
- updatedWindow.is_focused = w.workspace_id == data.workspace_id ? false : w.is_focused;
- }
-
- updatedWindows.push(updatedWindow);
- }
-
- windows = updatedWindows;
- }
-
- function handleWindowsChanged(data) {
- windows = sortWindowsByLayout(data.windows);
- }
-
- function handleWindowClosed(data) {
- windows = windows.filter(w => w.id !== data.id);
- }
-
- function handleWindowOpenedOrChanged(data) {
- if (!data.window)
- return;
- const window = data.window;
- const existingIndex = windows.findIndex(w => w.id === window.id);
-
- if (existingIndex >= 0) {
- const updatedWindows = [...windows];
- updatedWindows[existingIndex] = window;
- windows = sortWindowsByLayout(updatedWindows);
- } else {
- windows = sortWindowsByLayout([...windows, window]);
- }
- }
-
- function handleWindowLayoutsChanged(data) {
- if (!data.changes)
- return;
- const updatedWindows = [...windows];
- let hasChanges = false;
-
- for (const change of data.changes) {
- const windowId = change[0];
- const layoutData = change[1];
-
- const windowIndex = updatedWindows.findIndex(w => w.id === windowId);
- if (windowIndex < 0)
- continue;
- const updatedWindow = {};
- for (var prop in updatedWindows[windowIndex]) {
- updatedWindow[prop] = updatedWindows[windowIndex][prop];
- }
- updatedWindow.layout = layoutData;
- updatedWindows[windowIndex] = updatedWindow;
- hasChanges = true;
- }
-
- if (!hasChanges)
- return;
- windows = sortWindowsByLayout(updatedWindows);
- }
-
- function handleOutputsChanged(data) {
- if (!data.outputs)
- return;
- outputs = data.outputs;
- updateDisplayScales();
- windows = sortWindowsByLayout(windows);
- }
-
- function handleOverviewChanged(data) {
- inOverview = data.is_open;
- }
-
- function handleConfigLoaded(data) {
- if (data.failed) {
- validateProcess.running = true;
- return;
- }
-
- configValidationOutput = "";
- ToastService.dismissCategory("niri-config");
- fetchOutputs();
- configReloaded();
-
- if (hasInitialConnection && !suppressConfigToast && !suppressNextConfigToast && !matugenSuppression) {
- ToastService.showInfo("niri: config reloaded", "", "", "niri-config");
- } else if (suppressNextConfigToast) {
- suppressNextConfigToast = false;
- suppressResetTimer.stop();
- }
-
- if (!hasInitialConnection) {
- hasInitialConnection = true;
- suppressToastTimer.start();
- }
- }
-
- function handleKeyboardLayoutsChanged(data) {
- keyboardLayoutNames = data.keyboard_layouts.names;
- currentKeyboardLayoutIndex = data.keyboard_layouts.current_idx;
- }
-
- function handleKeyboardLayoutSwitched(data) {
- currentKeyboardLayoutIndex = data.idx;
- }
-
- function handleWorkspaceUrgencyChanged(data) {
- const ws = root.workspaces[data.id];
- if (!ws)
- return;
- const updatedWs = {};
- for (let prop in ws) {
- updatedWs[prop] = ws[prop];
- }
- updatedWs.is_urgent = data.urgent;
-
- const updatedWorkspaces = {};
- for (const id in root.workspaces) {
- updatedWorkspaces[id] = id === data.id ? updatedWs : root.workspaces[id];
- }
- setWorkspaces(updatedWorkspaces);
-
- windowUrgentChanged();
- }
-
- function handleWindowUrgencyChanged(data) {
- const windowIndex = windows.findIndex(w => w.id === data.id);
- if (windowIndex < 0)
- return;
- const updatedWindows = [...windows];
- const updatedWindow = {};
- for (let prop in updatedWindows[windowIndex]) {
- updatedWindow[prop] = updatedWindows[windowIndex][prop];
- }
- updatedWindow.is_urgent = data.urgent;
- updatedWindows[windowIndex] = updatedWindow;
- windows = updatedWindows;
-
- windowUrgentChanged();
- }
-
- function handleScreenshotCaptured(data) {
- if (!data.path)
- return;
- if (pendingScreenshotPath && data.path === pendingScreenshotPath) {
- const editor = Quickshell.env("DMS_SCREENSHOT_EDITOR");
- let command;
- if (editor === "satty" || !editor) {
- command = ["satty", "-f", data.path];
- } else if (editor === "swappy") {
- command = ["swappy", "-f", data.path];
- } else {
- // Custom command with %path% placeholder
- command = editor.split(" ").map(arg => arg === "%path%" ? data.path : arg);
- }
- Quickshell.execDetached({
- "command": command
- });
- pendingScreenshotPath = "";
- }
- }
-
- function handleCastsChanged(data) {
- casts = data.casts || [];
- }
-
- function handleCastStartedOrChanged(data) {
- if (!data.cast)
- return;
- const cast = data.cast;
- const existingIndex = casts.findIndex(c => c.stream_id === cast.stream_id);
- if (existingIndex >= 0) {
- const updatedCasts = [...casts];
- updatedCasts[existingIndex] = cast;
- casts = updatedCasts;
- } else {
- casts = [...casts, cast];
- }
- }
-
- function handleCastStopped(data) {
- casts = casts.filter(c => c.stream_id !== data.stream_id);
- }
-
- function updateCurrentOutputWorkspaces() {
- if (!currentOutput) {
- currentOutputWorkspaces = allWorkspaces;
- return;
- }
-
- const outputWs = allWorkspaces.filter(w => w.output === currentOutput);
- currentOutputWorkspaces = outputWs;
- }
-
- function send(request) {
- if (!CompositorService.isNiri || !requestSocket.connected)
- return false;
- requestSocket.send(request);
- return true;
- }
-
- function doScreenTransition() {
- return send({
- "Action": {
- "DoScreenTransition": {
- "delay_ms": 0
- }
- }
- });
- }
-
- function toggleOverview() {
- return send({
- "Action": {
- "ToggleOverview": {}
- }
- });
- }
-
- function moveColumnLeft() {
- return send({
- "Action": {
- "FocusColumnLeft": {}
- }
- });
- }
-
- function moveColumnRight() {
- return send({
- "Action": {
- "FocusColumnRight": {}
- }
- });
- }
-
- function moveWorkspaceDown() {
- return send({
- "Action": {
- "FocusWorkspaceDown": {}
- }
- });
- }
-
- function moveWorkspaceUp() {
- return send({
- "Action": {
- "FocusWorkspaceUp": {}
- }
- });
- }
-
- function switchToWorkspace(workspaceIndex) {
- return send({
- "Action": {
- "FocusWorkspace": {
- "reference": {
- "Index": workspaceIndex
- }
- }
- }
- });
- }
-
- function focusWindow(windowId) {
- return send({
- "Action": {
- "FocusWindow": {
- "id": windowId
- }
- }
- });
- }
-
- function powerOffMonitors() {
- return send({
- "Action": {
- "PowerOffMonitors": {}
- }
- });
- }
-
- function powerOnMonitors() {
- return send({
- "Action": {
- "PowerOnMonitors": {}
- }
- });
- }
-
- function cycleKeyboardLayout() {
- return send({
- "Action": {
- "SwitchLayout": {
- "layout": "Next"
- }
- }
- });
- }
-
- function quit() {
- return send({
- "Action": {
- "Quit": {
- "skip_confirmation": true
- }
- }
- });
- }
-
- function screenshot() {
- pendingScreenshotPath = "";
- const timestamp = Date.now();
- const path = `${screenshotsDir}/dms-screenshot-${timestamp}.png`;
- pendingScreenshotPath = path;
-
- return send({
- "Action": {
- "Screenshot": {
- "show_pointer": true,
- "path": path
- }
- }
- });
- }
-
- function screenshotScreen() {
- pendingScreenshotPath = "";
- const timestamp = Date.now();
- const path = `${screenshotsDir}/dms-screenshot-${timestamp}.png`;
- pendingScreenshotPath = path;
-
- return send({
- "Action": {
- "ScreenshotScreen": {
- "write_to_disk": true,
- "show_pointer": true,
- "path": path
- }
- }
- });
- }
-
- function screenshotWindow() {
- pendingScreenshotPath = "";
- const timestamp = Date.now();
- const path = `${screenshotsDir}/dms-screenshot-${timestamp}.png`;
- pendingScreenshotPath = path;
-
- return send({
- "Action": {
- "ScreenshotWindow": {
- "write_to_disk": true,
- "show_pointer": true,
- "path": path
- }
- }
- });
- }
-
- function getCurrentOutputWorkspaceNumbers() {
- return currentOutputWorkspaces.map(w => w.idx + 1);
- }
-
- function getCurrentOutputWorkspaces() {
- return currentOutputWorkspaces.slice();
- }
-
- function getCurrentWorkspaceNumber() {
- if (focusedWorkspaceIndex >= 0 && focusedWorkspaceIndex < allWorkspaces.length) {
- return allWorkspaces[focusedWorkspaceIndex].idx;
- }
- return 1;
- }
-
- function getCurrentKeyboardLayoutName() {
- if (currentKeyboardLayoutIndex >= 0 && currentKeyboardLayoutIndex < keyboardLayoutNames.length) {
- return keyboardLayoutNames[currentKeyboardLayoutIndex];
- }
- return "";
- }
-
- function suppressNextToast() {
- matugenSuppression = true;
- suppressResetTimer.restart();
- }
-
- function findNiriWindow(toplevel) {
- if (!toplevel.appId)
- return null;
-
- for (var j = 0; j < windows.length; j++) {
- const niriWindow = windows[j];
- if (niriWindow.app_id === toplevel.appId) {
- if (!niriWindow.title || niriWindow.title === toplevel.title) {
- return {
- "niriIndex": j,
- "niriWindow": niriWindow
- };
- }
- }
- }
- return null;
- }
-
- function sortToplevels(toplevels) {
- if (!toplevels || toplevels.length === 0 || !CompositorService.isNiri || windows.length === 0) {
- return [...toplevels];
- }
-
- const usedToplevels = new Set();
- const enrichedToplevels = [];
-
- for (const niriWindow of sortWindowsByLayout(windows)) {
- let bestMatch = null;
- let bestScore = -1;
-
- for (const toplevel of toplevels) {
- if (usedToplevels.has(toplevel))
- continue;
- if (toplevel.appId === niriWindow.app_id) {
- let score = 1;
-
- if (niriWindow.title && toplevel.title) {
- if (toplevel.title === niriWindow.title) {
- score = 3;
- } else if (toplevel.title.includes(niriWindow.title) || niriWindow.title.includes(toplevel.title)) {
- score = 2;
- }
- }
-
- if (score > bestScore) {
- bestScore = score;
- bestMatch = toplevel;
- if (score === 3)
- break;
- }
- }
- }
-
- if (!bestMatch)
- continue;
- usedToplevels.add(bestMatch);
-
- const workspace = workspaces[niriWindow.workspace_id];
- const isFocused = niriWindow.is_focused ?? (workspace && workspace.active_window_id === niriWindow.id) ?? false;
-
- const enrichedToplevel = {
- "appId": bestMatch.appId,
- "title": bestMatch.title,
- "activated": isFocused,
- "niriWindowId": niriWindow.id,
- "niriWorkspaceId": niriWindow.workspace_id,
- "activate": function () {
- return NiriService.focusWindow(niriWindow.id);
- },
- "close": function () {
- if (bestMatch.close) {
- return bestMatch.close();
- }
- return false;
- }
- };
-
- for (let prop in bestMatch) {
- if (!(prop in enrichedToplevel)) {
- enrichedToplevel[prop] = bestMatch[prop];
- }
- }
-
- enrichedToplevels.push(enrichedToplevel);
- }
-
- for (const toplevel of toplevels) {
- if (!usedToplevels.has(toplevel)) {
- enrichedToplevels.push(toplevel);
- }
- }
-
- return enrichedToplevels;
- }
-
- function _matchAndEnrichToplevels(toplevels, niriWindows) {
- const usedToplevels = new Set();
- const result = [];
-
- for (const niriWindow of niriWindows) {
- let bestMatch = null;
- let bestScore = -1;
-
- for (const toplevel of toplevels) {
- if (usedToplevels.has(toplevel))
- continue;
- if (toplevel.appId !== niriWindow.app_id)
- continue;
-
- let score = 1;
- if (niriWindow.title && toplevel.title) {
- if (toplevel.title === niriWindow.title) {
- score = 3;
- } else if (toplevel.title.includes(niriWindow.title) || niriWindow.title.includes(toplevel.title)) {
- score = 2;
- }
- }
-
- if (score > bestScore) {
- bestScore = score;
- bestMatch = toplevel;
- if (score === 3)
- break;
- }
- }
-
- if (!bestMatch)
- continue;
- usedToplevels.add(bestMatch);
-
- const workspace = workspaces[niriWindow.workspace_id];
- const isFocused = niriWindow.is_focused ?? (workspace && workspace.active_window_id === niriWindow.id) ?? false;
-
- const enrichedToplevel = {
- "appId": bestMatch.appId,
- "title": bestMatch.title,
- "activated": isFocused,
- "niriWindowId": niriWindow.id,
- "niriWorkspaceId": niriWindow.workspace_id,
- "activate": function () {
- return NiriService.focusWindow(niriWindow.id);
- },
- "close": function () {
- if (bestMatch.close)
- return bestMatch.close();
- return false;
- }
- };
-
- for (let prop in bestMatch) {
- if (!(prop in enrichedToplevel))
- enrichedToplevel[prop] = bestMatch[prop];
- }
-
- result.push(enrichedToplevel);
- }
-
- return result;
- }
-
- function filterCurrentWorkspace(toplevels, screenName) {
- let currentWorkspaceId = null;
-
- for (var i = 0; i < allWorkspaces.length; i++) {
- const ws = allWorkspaces[i];
- if (ws.output === screenName && ws.is_active) {
- currentWorkspaceId = ws.id;
- break;
- }
- }
-
- if (currentWorkspaceId === null)
- return toplevels;
-
- if (toplevels.length > 0 && toplevels[0].niriWorkspaceId !== undefined)
- return toplevels.filter(t => t.niriWorkspaceId === currentWorkspaceId);
-
- return _matchAndEnrichToplevels(toplevels, windows.filter(nw => nw.workspace_id === currentWorkspaceId));
- }
-
- function filterCurrentDisplay(toplevels, screenName) {
- if (!toplevels || toplevels.length === 0 || !screenName)
- return toplevels;
-
- const outputWorkspaceIds = new Set();
- for (var i = 0; i < allWorkspaces.length; i++) {
- const ws = allWorkspaces[i];
- if (ws.output === screenName)
- outputWorkspaceIds.add(ws.id);
- }
-
- if (outputWorkspaceIds.size === 0)
- return toplevels;
-
- if (toplevels.length > 0 && toplevels[0].niriWorkspaceId !== undefined)
- return toplevels.filter(t => outputWorkspaceIds.has(t.niriWorkspaceId));
-
- return _matchAndEnrichToplevels(toplevels, windows.filter(nw => outputWorkspaceIds.has(nw.workspace_id)));
- }
-
- function generateNiriLayoutConfig() {
- if (!CompositorService.isNiri || configGenerationPending)
- return;
- suppressNextToast();
- configGenerationPending = true;
- configGenerationDebounce.restart();
- }
-
- function doGenerateNiriLayoutConfig() {
- console.log("NiriService: Generating layout config...");
-
- const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12;
- const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4;
- const defaultBorderSize = 2;
-
- const cornerRadius = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutRadiusOverride >= 0) ? SettingsData.niriLayoutRadiusOverride : defaultRadius;
- const gaps = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutGapsOverride >= 0) ? SettingsData.niriLayoutGapsOverride : defaultGaps;
- const borderSize = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutBorderSize >= 0) ? SettingsData.niriLayoutBorderSize : defaultBorderSize;
-
- const dmsWarning = `// ! DO NOT EDIT !
- // ! AUTO-GENERATED BY DMS !
- // ! CHANGES WILL BE OVERWRITTEN !
- // ! PLACE YOUR CUSTOM CONFIGURATION ELSEWHERE !
-
- `;
-
- const configContent = dmsWarning + `layout {
- gaps ${gaps}
-
- border {
- width ${borderSize}
- }
-
- focus-ring {
- width ${borderSize}
- }
- }
- window-rule {
- geometry-corner-radius ${cornerRadius}
- clip-to-geometry true
- tiled-state true
- draw-border-with-background false
- }`;
-
- const alttabContent = dmsWarning + `recent-windows {
- highlight {
- corner-radius ${cornerRadius}
- }
- }`;
-
- const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation));
- const niriDmsDir = configDir + "/niri/dms";
- const configPath = niriDmsDir + "/layout.kdl";
- const alttabPath = niriDmsDir + "/alttab.kdl";
-
- writeConfigProcess.configContent = configContent;
- writeConfigProcess.configPath = configPath;
- writeConfigProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${configPath}" << 'EOF'\n${configContent}\nEOF`];
- writeConfigProcess.running = true;
-
- writeAlttabProcess.alttabContent = alttabContent;
- writeAlttabProcess.alttabPath = alttabPath;
- writeAlttabProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${alttabPath}" << 'EOF'\n${alttabContent}\nEOF`];
- writeAlttabProcess.running = true;
-
- for (const name of ["outputs", "binds", "cursor", "windowrules", "colors", "alttab", "layout"]) {
- const path = niriDmsDir + "/" + name + ".kdl";
- Proc.runCommand("niri-ensure-" + name, ["sh", "-c", `mkdir -p "${niriDmsDir}" && [ ! -f "${path}" ] && touch "${path}" || true`], (output, exitCode) => {
- if (exitCode !== 0)
- console.warn("NiriService: Failed to ensure " + name + ".kdl, exit code:", exitCode);
- });
- }
-
- configGenerationPending = false;
- }
-
- function generateNiriBlurrule() {
- console.log("NiriService: Generating wpblur config...");
-
- const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation));
- const niriDmsDir = configDir + "/niri/dms";
- const blurrulePath = niriDmsDir + "/wpblur.kdl";
- const sourceBlurrulePath = Paths.strip(Qt.resolvedUrl("niri-wpblur.kdl"));
-
- writeBlurruleProcess.blurrulePath = blurrulePath;
- writeBlurruleProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && cp --no-preserve=mode "${sourceBlurrulePath}" "${blurrulePath}"`];
- writeBlurruleProcess.running = true;
- }
-
- function generateNiriCursorConfig() {
- if (!CompositorService.isNiri)
- return;
-
- console.log("NiriService: Generating cursor config...");
-
- const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation));
- const niriDmsDir = configDir + "/niri/dms";
- const cursorPath = niriDmsDir + "/cursor.kdl";
-
- const settings = typeof SettingsData !== "undefined" ? SettingsData.cursorSettings : null;
- if (!settings) {
- writeCursorProcess.cursorContent = "";
- writeCursorProcess.cursorPath = cursorPath;
- writeCursorProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && : > "${cursorPath}"`];
- writeCursorProcess.running = true;
- return;
- }
-
- const themeName = settings.theme === "System Default" ? (SettingsData.systemDefaultCursorTheme || "") : settings.theme;
- const size = settings.size || 24;
- const hideWhenTyping = settings.niri?.hideWhenTyping || false;
- const hideAfterMs = settings.niri?.hideAfterInactiveMs || 0;
-
- const isDefaultConfig = !themeName && size === 24 && !hideWhenTyping && hideAfterMs === 0;
- if (isDefaultConfig) {
- writeCursorProcess.cursorContent = "";
- writeCursorProcess.cursorPath = cursorPath;
- writeCursorProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && : > "${cursorPath}"`];
- writeCursorProcess.running = true;
- return;
- }
-
- const dmsWarning = `// ! DO NOT EDIT !
-// ! AUTO-GENERATED BY DMS !
-// ! CHANGES WILL BE OVERWRITTEN !
-// ! PLACE YOUR CUSTOM CONFIGURATION ELSEWHERE !
-
-`;
-
- let cursorContent = dmsWarning + `cursor {\n`;
-
- if (themeName)
- cursorContent += ` xcursor-theme "${themeName}"\n`;
-
- cursorContent += ` xcursor-size ${size}\n`;
-
- if (hideWhenTyping)
- cursorContent += ` hide-when-typing\n`;
-
- if (hideAfterMs > 0)
- cursorContent += ` hide-after-inactive-ms ${hideAfterMs}\n`;
-
- cursorContent += `}`;
-
- writeCursorProcess.cursorContent = cursorContent;
- writeCursorProcess.cursorPath = cursorPath;
-
- const escapedCursorContent = cursorContent.replace(/'/g, "'\\''");
-
- writeCursorProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && printf '%s' '${escapedCursorContent}' > "${cursorPath}"`];
- writeCursorProcess.running = true;
- }
-
- function updateOutputPosition(outputName, x, y) {
- if (!outputs || !outputs[outputName])
- return;
- const updatedOutputs = {};
- for (const name in outputs) {
- const output = outputs[name];
- if (name === outputName && output.logical) {
- updatedOutputs[name] = JSON.parse(JSON.stringify(output));
- updatedOutputs[name].logical.x = x;
- updatedOutputs[name].logical.y = y;
- } else {
- updatedOutputs[name] = output;
- }
- }
- outputs = updatedOutputs;
- }
-
- function applyOutputConfig(outputName, config, callback) {
- if (!CompositorService.isNiri || !outputName) {
- if (callback)
- callback(false, "Invalid config");
- return;
- }
-
- const commands = [];
-
- if (config.position !== undefined) {
- commands.push(`niri msg output "${outputName}" position ${config.position.x} ${config.position.y}`);
- }
-
- if (config.mode !== undefined) {
- commands.push(`niri msg output "${outputName}" mode ${config.mode}`);
- }
-
- if (config.vrr !== undefined) {
- commands.push(`niri msg output "${outputName}" vrr ${config.vrr ? "on" : "off"}`);
- }
-
- if (config.scale !== undefined) {
- commands.push(`niri msg output "${outputName}" scale ${config.scale}`);
- }
-
- if (config.transform !== undefined) {
- commands.push(`niri msg output "${outputName}" transform "${config.transform}"`);
- }
-
- if (commands.length === 0) {
- if (callback)
- callback(true, "No changes");
- return;
- }
-
- const fullCommand = commands.join(" && ");
- Proc.runCommand("niri-output-config", ["sh", "-c", fullCommand], (output, exitCode) => {
- if (exitCode !== 0) {
- console.warn("NiriService: Failed to apply output config:", output);
- if (callback)
- callback(false, output);
- return;
- }
- console.info("NiriService: Applied output config for", outputName);
- fetchOutputs();
- if (callback)
- callback(true, "Success");
- });
- }
-
- function getOutputIdentifier(output, outputName) {
- if (SettingsData.displayNameMode === "model" && output.make && output.model) {
- const serial = output.serial || "Unknown";
- return output.make + " " + output.model + " " + serial;
- }
- return outputName;
- }
-
- function generateOutputsConfig(outputsData) {
- const data = outputsData || outputs;
- if (!data || Object.keys(data).length === 0)
- return;
- let kdlContent = `// Auto-generated by DMS - do not edit manually\n\n`;
-
- const sortedNames = Object.keys(data).sort((a, b) => {
- const la = data[a].logical || {};
- const lb = data[b].logical || {};
- return (la.x ?? 0) - (lb.x ?? 0) || (la.y ?? 0) - (lb.y ?? 0);
- });
- for (const outputName of sortedNames) {
- const output = data[outputName];
- const identifier = getOutputIdentifier(output, outputName);
- const niriSettings = SettingsData.getNiriOutputSettings(identifier);
-
- kdlContent += `output "${identifier}" {\n`;
-
- if (niriSettings.disabled) {
- kdlContent += ` off\n`;
- }
-
- if (output.current_mode !== undefined && output.modes && output.modes[output.current_mode]) {
- const mode = output.modes[output.current_mode];
- kdlContent += ` mode "${mode.width}x${mode.height}@${(mode.refresh_rate / 1000).toFixed(3)}"\n`;
- }
-
- if (output.logical) {
- kdlContent += ` scale ${output.logical.scale || 1.0}\n`;
-
- if (output.logical.transform && output.logical.transform !== "Normal") {
- const transformMap = {
- "Normal": "normal",
- "90": "90",
- "180": "180",
- "270": "270",
- "Flipped": "flipped",
- "Flipped90": "flipped-90",
- "Flipped180": "flipped-180",
- "Flipped270": "flipped-270"
- };
- kdlContent += ` transform "${transformMap[output.logical.transform] || "normal"}"\n`;
- }
-
- if (output.logical.x !== undefined && output.logical.y !== undefined) {
- kdlContent += ` position x=${output.logical.x} y=${output.logical.y}\n`;
- }
- }
-
- if (output.vrr_enabled || niriSettings.vrrOnDemand) {
- const vrrOnDemand = niriSettings.vrrOnDemand ?? false;
- kdlContent += vrrOnDemand ? ` variable-refresh-rate on-demand=true\n` : ` variable-refresh-rate\n`;
- }
-
- if (niriSettings.focusAtStartup) {
- kdlContent += ` focus-at-startup\n`;
- }
-
- if (niriSettings.backdropColor) {
- kdlContent += ` backdrop-color "${niriSettings.backdropColor}"\n`;
- }
-
- kdlContent += generateHotCornersBlock(niriSettings);
- kdlContent += generateLayoutBlock(niriSettings);
-
- kdlContent += `}\n\n`;
- }
-
- const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation));
- const niriDmsDir = configDir + "/niri/dms";
- const outputsPath = niriDmsDir + "/outputs.kdl";
-
- Proc.runCommand("niri-write-outputs", ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${kdlContent}EOF`], (output, exitCode) => {
- if (exitCode !== 0) {
- console.warn("NiriService: Failed to write outputs config:", output);
- return;
- }
- console.info("NiriService: Generated outputs config at", outputsPath);
- });
- }
-
- function generateHotCornersBlock(niriSettings) {
- if (!niriSettings.hotCorners)
- return "";
- const hc = niriSettings.hotCorners;
- if (hc.off)
- return ` hot-corners {\n off\n }\n`;
- const corners = hc.corners || [];
- if (corners.length === 0)
- return "";
- let block = ` hot-corners {\n`;
- for (const corner of corners) {
- block += ` ${corner}\n`;
- }
- block += ` }\n`;
- return block;
- }
-
- function generateLayoutBlock(niriSettings) {
- if (!niriSettings.layout)
- return "";
- const layout = niriSettings.layout;
- const hasSettings = layout.gaps !== undefined || layout.defaultColumnWidth || layout.presetColumnWidths || layout.alwaysCenterSingleColumn !== undefined;
- if (!hasSettings)
- return "";
- let block = ` layout {\n`;
- if (layout.gaps !== undefined)
- block += ` gaps ${layout.gaps}\n`;
- if (layout.defaultColumnWidth?.type === "proportion") {
- const val = layout.defaultColumnWidth.value;
- const formatted = Number.isInteger(val) ? val.toFixed(1) : val.toString();
- block += ` default-column-width { proportion ${formatted}; }\n`;
- }
- if (layout.presetColumnWidths && layout.presetColumnWidths.length > 0) {
- block += ` preset-column-widths {\n`;
- for (const preset of layout.presetColumnWidths) {
- if (preset.type === "proportion") {
- const val = preset.value;
- const formatted = Number.isInteger(val) ? val.toFixed(1) : val.toString();
- block += ` proportion ${formatted}\n`;
- }
- }
- block += ` }\n`;
- }
- if (layout.alwaysCenterSingleColumn !== undefined)
- block += layout.alwaysCenterSingleColumn ? ` always-center-single-column\n` : ` always-center-single-column false\n`;
- block += ` }\n`;
- return block;
- }
-
- function renameWorkspace(name) {
- if (!name || name.trim() === "") {
- return send({
- "Action": {
- "UnsetWorkspaceName": {
- "workspace": null
- }
- }
- });
- }
- return send({
- "Action": {
- "SetWorkspaceName": {
- "name": name,
- "workspace": null
- }
- }
- });
- }
-
- function moveWorkspaceToIndex(workspaceIdx, targetIndex) {
- return send({
- "Action": {
- "MoveWorkspaceToIndex": {
- "index": targetIndex,
- "reference": {
- "Index": workspaceIdx
- }
- }
- }
- });
- }
-
- IpcHandler {
- function screenshot(): string {
- if (!CompositorService.isNiri) {
- return "NIRI_NOT_AVAILABLE";
- }
- if (NiriService.screenshot()) {
- return "SCREENSHOT_SUCCESS";
- }
- return "SCREENSHOT_FAILED";
- }
-
- function screenshotScreen(): string {
- if (!CompositorService.isNiri) {
- return "NIRI_NOT_AVAILABLE";
- }
- if (NiriService.screenshotScreen()) {
- return "SCREENSHOT_SCREEN_SUCCESS";
- }
- return "SCREENSHOT_SCREEN_FAILED";
- }
-
- function screenshotWindow(): string {
- if (!CompositorService.isNiri) {
- return "NIRI_NOT_AVAILABLE";
- }
- if (NiriService.screenshotWindow()) {
- return "SCREENSHOT_WINDOW_SUCCESS";
- }
- return "SCREENSHOT_WINDOW_FAILED";
- }
-
- target: "niri"
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NotepadStorageService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NotepadStorageService.qml
deleted file mode 100644
index 3a6257a..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NotepadStorageService.qml
+++ /dev/null
@@ -1,473 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import QtCore
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- property int refCount: 0
-
- readonly property string baseDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericStateLocation) + "/DankMaterialShell")
- readonly property string filesDir: baseDir + "/notepad-files"
- readonly property string metadataPath: baseDir + "/notepad-session.json"
-
- property var tabs: []
- property int currentTabIndex: 0
- property var tabsBeingCreated: ({})
- property bool metadataLoaded: false
-
- Component.onCompleted: {
- ensureDirectories()
- }
-
- FileView {
- id: metadataFile
- path: root.refCount > 0 ? root.metadataPath : ""
- blockWrites: true
- atomicWrites: true
-
- onLoaded: {
- try {
- var data = JSON.parse(text())
- root.tabs = data.tabs || []
- root.currentTabIndex = data.currentTabIndex || 0
- root.metadataLoaded = true
- root.validateTabs()
- } catch(e) {
- console.warn("Failed to parse notepad metadata:", e)
- root.createDefaultTab()
- }
- }
-
- onLoadFailed: {
- root.createDefaultTab()
- }
- }
-
- onRefCountChanged: {
- if (refCount === 1 && !metadataLoaded) {
- metadataFile.path = ""
- metadataFile.path = root.metadataPath
- }
- }
-
- function ensureDirectories() {
- mkdirProcess.running = true
- }
-
- function loadMetadata() {
- metadataFile.path = ""
- metadataFile.path = root.metadataPath
- }
-
- function createDefaultTab() {
- var id = Date.now()
- var filePath = "notepad-files/untitled-" + id + ".txt"
- var fullPath = baseDir + "/" + filePath
-
- var newTabsBeingCreated = Object.assign({}, tabsBeingCreated)
- newTabsBeingCreated[id] = true
- tabsBeingCreated = newTabsBeingCreated
-
- root.createEmptyFile(fullPath, function() {
- root.tabs = [{
- id: id,
- title: I18n.tr("Untitled"),
- filePath: filePath,
- isTemporary: true,
- lastModified: new Date().toISOString(),
- cursorPosition: 0,
- scrollPosition: 0
- }]
- root.currentTabIndex = 0
-
- var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated)
- delete updatedTabsBeingCreated[id]
- tabsBeingCreated = updatedTabsBeingCreated
- root.saveMetadata()
- })
- }
-
- function saveMetadata() {
- var metadata = {
- version: 1,
- currentTabIndex: currentTabIndex,
- tabs: tabs
- }
- metadataFile.setText(JSON.stringify(metadata, null, 2))
- }
-
- function getTabById(tabId) {
- for (var i = 0; i < tabs.length; i++) {
- if (tabs[i].id === tabId)
- return tabs[i]
- }
- return null
- }
-
- function loadTabContent(tabIndex, callback) {
- if (tabIndex < 0 || tabIndex >= tabs.length) {
- callback("")
- return
- }
-
- var tab = tabs[tabIndex]
- var requestTabId = tab.id
- var fullPath = tab.isTemporary
- ? baseDir + "/" + tab.filePath
- : tab.filePath
-
- if (tabsBeingCreated[tab.id]) {
- Qt.callLater(() => {
- loadTabContent(tabIndex, callback)
- })
- return
- }
-
- var fileChecker = fileExistsComponent.createObject(root, {
- path: fullPath,
- callback: (exists) => {
- var currentTab = root.getTabById(requestTabId)
- var currentPath = currentTab
- ? (currentTab.isTemporary ? baseDir + "/" + currentTab.filePath : currentTab.filePath)
- : ""
-
- if (!currentTab || currentPath !== fullPath) {
- callback("")
- return
- }
-
- if (exists) {
- var loader = tabFileLoaderComponent.createObject(root, {
- path: fullPath,
- callback: callback
- })
- } else {
- console.warn("Tab file does not exist:", fullPath)
- callback("")
- }
- }
- })
- }
-
- function saveTabContent(tabIndex, content) {
- if (tabIndex < 0 || tabIndex >= tabs.length) return
-
- var tab = tabs[tabIndex]
- var fullPath = tab.isTemporary
- ? baseDir + "/" + tab.filePath
- : tab.filePath
-
- var saver = tabFileSaverComponent.createObject(root, {
- path: fullPath,
- content: content,
- tabIndex: tabIndex
- })
- }
-
- function createNewTab() {
- var id = Date.now()
- var filePath = "notepad-files/untitled-" + id + ".txt"
- var fullPath = baseDir + "/" + filePath
-
- var newTab = {
- id: id,
- title: I18n.tr("Untitled"),
- filePath: filePath,
- isTemporary: true,
- lastModified: new Date().toISOString(),
- cursorPosition: 0,
- scrollPosition: 0
- }
-
- var newTabsBeingCreated = Object.assign({}, tabsBeingCreated)
- newTabsBeingCreated[id] = true
- tabsBeingCreated = newTabsBeingCreated
- createEmptyFile(fullPath, function() {
- var newTabs = tabs.slice()
- newTabs.push(newTab)
- tabs = newTabs
- currentTabIndex = tabs.length - 1
-
- var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated)
- delete updatedTabsBeingCreated[id]
- tabsBeingCreated = updatedTabsBeingCreated
- saveMetadata()
- })
-
- return newTab
- }
-
- function closeTab(tabIndex) {
- if (tabIndex < 0 || tabIndex >= tabs.length) return
-
- var newTabs = tabs.slice()
-
- if (newTabs.length <= 1) {
- var id = Date.now()
- var filePath = "notepad-files/untitled-" + id + ".txt"
-
- var newTabsBeingCreated = Object.assign({}, tabsBeingCreated)
- newTabsBeingCreated[id] = true
- tabsBeingCreated = newTabsBeingCreated
- createEmptyFile(baseDir + "/" + filePath, function() {
- newTabs[0] = {
- id: id,
- title: I18n.tr("Untitled"),
- filePath: filePath,
- isTemporary: true,
- lastModified: new Date().toISOString(),
- cursorPosition: 0,
- scrollPosition: 0
- }
- currentTabIndex = 0
- tabs = newTabs
-
- var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated)
- delete updatedTabsBeingCreated[id]
- tabsBeingCreated = updatedTabsBeingCreated
- saveMetadata()
- })
- return
- } else {
- var tabToDelete = newTabs[tabIndex]
- if (tabToDelete && tabToDelete.isTemporary) {
- deleteFile(baseDir + "/" + tabToDelete.filePath)
- }
-
- newTabs.splice(tabIndex, 1)
- if (currentTabIndex >= newTabs.length) {
- currentTabIndex = newTabs.length - 1
- } else if (currentTabIndex > tabIndex) {
- currentTabIndex -= 1
- }
- }
-
- tabs = newTabs
- saveMetadata()
-
- }
-
- function switchToTab(tabIndex) {
- if (tabIndex < 0 || tabIndex >= tabs.length) return
-
- currentTabIndex = tabIndex
- saveMetadata()
- }
-
- function reorderTab(fromIndex, toIndex) {
- if (fromIndex < 0 || fromIndex >= tabs.length || toIndex < 0 || toIndex >= tabs.length)
- return
- if (fromIndex === toIndex)
- return
-
- var newTabs = tabs.slice()
- var moved = newTabs.splice(fromIndex, 1)[0]
- newTabs.splice(toIndex, 0, moved)
- tabs = newTabs
-
- if (currentTabIndex === fromIndex) {
- currentTabIndex = toIndex
- } else if (fromIndex < currentTabIndex && toIndex >= currentTabIndex) {
- currentTabIndex--
- } else if (fromIndex > currentTabIndex && toIndex <= currentTabIndex) {
- currentTabIndex++
- }
-
- saveMetadata()
- }
-
- function saveTabAs(tabIndex, userPath) {
- if (tabIndex < 0 || tabIndex >= tabs.length) return
-
- var tab = tabs[tabIndex]
- var fileName = userPath.split('/').pop()
-
- if (tab.isTemporary) {
- var tempPath = baseDir + "/" + tab.filePath
- copyFile(tempPath, userPath)
- deleteFile(tempPath)
- }
-
- var newTabs = tabs.slice()
- newTabs[tabIndex] = Object.assign({}, tab, {
- title: fileName,
- filePath: userPath,
- isTemporary: false,
- lastModified: new Date().toISOString()
- })
- tabs = newTabs
- saveMetadata()
-
- }
-
- function updateTabMetadata(tabIndex, properties) {
- if (tabIndex < 0 || tabIndex >= tabs.length) return
-
- var newTabs = tabs.slice()
- var updatedTab = Object.assign({}, newTabs[tabIndex], properties)
- updatedTab.lastModified = new Date().toISOString()
- newTabs[tabIndex] = updatedTab
- tabs = newTabs
- saveMetadata()
-
- }
-
- function validateTabs() {
- var validTabs = []
- for (var i = 0; i < tabs.length; i++) {
- var tab = tabs[i]
- validTabs.push(tab)
- }
- tabs = validTabs
-
- if (tabs.length === 0) {
- root.createDefaultTab()
- }
- }
-
- Component {
- id: tabFileLoaderComponent
- FileView {
- property var callback
- blockLoading: true
- preload: true
-
- onLoaded: {
- callback(text())
- destroy()
- }
-
- onLoadFailed: {
- callback("")
- destroy()
- }
- }
- }
-
- Component {
- id: fileExistsComponent
- Process {
- property string path
- property var callback
- command: ["test", "-f", path]
-
- Component.onCompleted: running = true
-
- onExited: (exitCode) => {
- callback(exitCode === 0)
- destroy()
- }
- }
- }
-
- Component {
- id: tabFileSaverComponent
- FileView {
- property string content
- property int tabIndex
- property var creationCallback
-
- blockWrites: false
- atomicWrites: true
-
- Component.onCompleted: setText(content)
-
- onSaved: {
- if (tabIndex >= 0) {
- root.updateTabMetadata(tabIndex, {})
- }
- if (creationCallback) {
- creationCallback()
- }
- destroy()
- }
-
- onSaveFailed: {
- console.error("Failed to save tab content")
- if (creationCallback) {
- creationCallback()
- }
- destroy()
- }
- }
- }
-
- function createEmptyFile(path, callback) {
- var cleanPath = decodeURI(path.toString())
-
- if (!cleanPath.startsWith("/")) {
- cleanPath = baseDir + "/" + cleanPath
- }
-
- var creator = fileCreatorComponent.createObject(root, {
- filePath: cleanPath,
- creationCallback: callback
- })
- }
-
- function copyFile(source, destination) {
- copyProcess.source = source
- copyProcess.destination = destination
- copyProcess.running = true
- }
-
- function deleteFile(path) {
- deleteProcess.filePath = path
- deleteProcess.running = true
- }
-
- Component {
- id: fileCreatorComponent
- QtObject {
- property string filePath
- property var creationCallback
-
- Component.onCompleted: {
- var touchProcess = touchProcessComponent.createObject(this, {
- filePath: filePath,
- callback: creationCallback
- })
- }
- }
- }
-
- Component {
- id: touchProcessComponent
- Process {
- property string filePath
- property var callback
- command: ["touch", filePath]
-
- Component.onCompleted: running = true
-
- onExited: (exitCode) => {
- if (callback) callback()
- destroy()
- }
- }
- }
-
- Process {
- id: copyProcess
- property string source
- property string destination
- command: ["cp", source, destination]
- }
-
- Process {
- id: deleteProcess
- property string filePath
- command: ["rm", "-f", filePath]
- }
-
- Process {
- id: mkdirProcess
- command: ["mkdir", "-p", root.baseDir, root.filesDir]
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NotificationService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NotificationService.qml
deleted file mode 100644
index 0615b58..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/NotificationService.qml
+++ /dev/null
@@ -1,1237 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import Quickshell.Services.Notifications
-import qs.Common
-import "../Common/markdown2html.js" as Markdown2Html
-
-Singleton {
- id: root
-
- readonly property list<NotifWrapper> notifications: []
- readonly property list<NotifWrapper> allWrappers: []
- readonly property list<NotifWrapper> popups: allWrappers.filter(n => n && n.popup)
-
- property var historyList: []
- readonly property string historyFile: Paths.strip(Paths.cache) + "/notification_history.json"
- readonly property string imageCacheDir: Paths.strip(Paths.cache) + "/notification_images"
- property bool historyLoaded: false
- property int historyEntryCounter: 0
-
- property list<NotifWrapper> notificationQueue: []
- property list<NotifWrapper> visibleNotifications: []
- property int maxVisibleNotifications: 4
- property bool addGateBusy: false
- property int enterAnimMs: 400
- property int seqCounter: 0
- property bool bulkDismissing: false
-
- property int maxQueueSize: 32
- property int maxIngressPerSecond: 20
- property double _lastIngressSec: 0
- property int _ingressCountThisSec: 0
-
- property var _dismissQueue: []
- property int _dismissBatchSize: 8
- property int _dismissTickMs: 8
- property bool _suspendGrouping: false
- property var _groupCache: ({
- "notifications": [],
- "popups": []
- })
- property bool _groupsDirty: false
-
- Component.onCompleted: {
- _recomputeGroups();
- Quickshell.execDetached(["mkdir", "-p", Paths.strip(Paths.cache)]);
- Quickshell.execDetached(["mkdir", "-p", imageCacheDir]);
- }
-
- FileView {
- id: historyFileView
- path: root.historyFile
- printErrors: false
- onLoaded: root.loadHistory()
- onLoadFailed: error => {
- if (error === 2) {
- root.historyLoaded = true;
- historyFileView.writeAdapter();
- }
- }
-
- JsonAdapter {
- id: historyAdapter
- property var notifications: []
- }
- }
-
- Timer {
- id: historySaveTimer
- interval: 200
- onTriggered: root.performSaveHistory()
- }
-
- function _makeHistoryEntryId(sourceId, timestamp) {
- historyEntryCounter += 1;
- const safeSource = sourceId && sourceId !== "" ? sourceId : "notification";
- return safeSource + "_" + (timestamp || Date.now()) + "_" + historyEntryCounter;
- }
-
- function getImageCachePath(wrapper) {
- const ts = wrapper.time ? wrapper.time.getTime() : Date.now();
- const id = wrapper.notification?.id?.toString() || "0";
- return imageCacheDir + "/notif_" + ts + "_" + id + ".png";
- }
-
- function updateHistoryImage(wrapperId, imagePath) {
- const idx = historyList.findIndex(n => n.sourceNotificationId === wrapperId || n.id === wrapperId);
- if (idx < 0)
- return;
- const item = historyList[idx];
- const updated = {
- id: item.id,
- sourceNotificationId: item.sourceNotificationId || item.id,
- summary: item.summary,
- body: item.body,
- htmlBody: item.htmlBody,
- appName: item.appName,
- appIcon: item.appIcon,
- image: "file://" + imagePath,
- urgency: item.urgency,
- timestamp: item.timestamp,
- desktopEntry: item.desktopEntry
- };
- const newList = historyList.slice();
- newList[idx] = updated;
- historyList = newList;
- saveHistory();
- }
-
- function addToHistory(wrapper) {
- if (!wrapper)
- return;
- const urg = typeof wrapper.urgency === "number" ? wrapper.urgency : 1;
- const imageUrl = wrapper.image || "";
- let persistableImage = "";
- if (wrapper.persistedImagePath) {
- persistableImage = "file://" + wrapper.persistedImagePath;
- } else if (imageUrl && !imageUrl.startsWith("image://qsimage/")) {
- persistableImage = imageUrl;
- }
- const sourceNotificationId = wrapper.notification?.id?.toString() || "";
- const timestamp = wrapper.time.getTime();
- const data = {
- id: _makeHistoryEntryId(sourceNotificationId, timestamp),
- sourceNotificationId: sourceNotificationId,
- summary: wrapper.summary || "",
- body: wrapper.body || "",
- htmlBody: wrapper.htmlBody || wrapper.body || "",
- appName: wrapper.appName || "",
- appIcon: wrapper.appIcon || "",
- image: persistableImage,
- urgency: urg,
- timestamp: timestamp,
- desktopEntry: wrapper.desktopEntry || ""
- };
- let newList = [data, ...historyList];
- if (newList.length > SettingsData.notificationHistoryMaxCount) {
- newList = newList.slice(0, SettingsData.notificationHistoryMaxCount);
- }
- historyList = newList;
- saveHistory();
- }
-
- function saveHistory() {
- historySaveTimer.restart();
- }
-
- function performSaveHistory() {
- try {
- historyAdapter.notifications = historyList;
- historyFileView.writeAdapter();
- } catch (e) {
- console.warn("NotificationService: save history failed:", e);
- }
- }
-
- function loadHistory() {
- try {
- const maxAgeDays = SettingsData.notificationHistoryMaxAgeDays;
- const now = Date.now();
- const maxAgeMs = maxAgeDays > 0 ? maxAgeDays * 24 * 60 * 60 * 1000 : 0;
- const loaded = [];
- const seenIds = {};
- let needsRewrite = false;
-
- for (const item of historyAdapter.notifications || []) {
- if (maxAgeMs > 0 && (now - item.timestamp) > maxAgeMs)
- continue;
- const urg = typeof item.urgency === "number" ? item.urgency : 1;
- const body = item.body || "";
- let htmlBody = item.htmlBody || _resolveHtmlBody(body);
- if (htmlBody) {
- htmlBody = htmlBody.replace(/<img\b[^>]*>/gi, "");
- }
- const sourceNotificationId = (item.sourceNotificationId || item.id || "").toString();
- let historyId = (item.id || "").toString();
- if (!historyId || seenIds[historyId]) {
- historyId = _makeHistoryEntryId(sourceNotificationId, item.timestamp || now);
- needsRewrite = true;
- }
- if (!item.sourceNotificationId)
- needsRewrite = true;
- seenIds[historyId] = true;
- loaded.push({
- id: historyId,
- sourceNotificationId: sourceNotificationId,
- summary: item.summary || "",
- body: body,
- htmlBody: htmlBody,
- appName: item.appName || "",
- appIcon: item.appIcon || "",
- image: item.image || "",
- urgency: urg,
- timestamp: item.timestamp || 0,
- desktopEntry: item.desktopEntry || ""
- });
- }
- historyList = loaded;
- historyLoaded = true;
- if ((maxAgeMs > 0 && loaded.length !== (historyAdapter.notifications || []).length) || needsRewrite)
- saveHistory();
- } catch (e) {
- console.warn("NotificationService: load history failed:", e);
- historyLoaded = true;
- }
- }
-
- function _deleteCachedImage(imagePath) {
- if (!imagePath || !imagePath.startsWith("file://"))
- return;
- const filePath = imagePath.replace("file://", "");
- if (filePath.startsWith(imageCacheDir)) {
- Quickshell.execDetached(["rm", "-f", filePath]);
- }
- }
-
- function removeFromHistory(notificationId) {
- const idx = historyList.findIndex(n => n.id === notificationId);
- if (idx >= 0) {
- _deleteCachedImage(historyList[idx].image);
- historyList = historyList.filter((_, i) => i !== idx);
- saveHistory();
- return true;
- }
- return false;
- }
-
- function clearHistory() {
- for (const item of historyList) {
- _deleteCachedImage(item.image);
- }
- historyList = [];
- saveHistory();
- }
-
- function getHistoryTimeRange(timestamp) {
- const now = new Date();
- const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
- const itemDate = new Date(timestamp);
- const itemDay = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate());
- const diffDays = Math.floor((today - itemDay) / (1000 * 60 * 60 * 24));
- if (diffDays === 0)
- return 0;
- if (diffDays === 1)
- return 1;
- return 2;
- }
-
- function getHistoryCountForRange(range) {
- if (range === -1)
- return historyList.length;
- return historyList.filter(n => getHistoryTimeRange(n.timestamp) === range).length;
- }
-
- function formatHistoryTime(timestamp) {
- root.timeUpdateTick;
- root.clockFormatChanged;
- const now = new Date();
- const date = new Date(timestamp);
- const diff = now.getTime() - timestamp;
- const minutes = Math.floor(diff / 60000);
- const hours = Math.floor(minutes / 60);
- if (hours < 1) {
- if (minutes < 1)
- return I18n.tr("now");
- return I18n.tr("%1m ago").arg(minutes);
- }
- const nowDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());
- const itemDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
- const daysDiff = Math.floor((nowDate - itemDate) / (1000 * 60 * 60 * 24));
- const timeStr = SettingsData.use24HourClock ? date.toLocaleTimeString(Qt.locale(), "HH:mm") : date.toLocaleTimeString(Qt.locale(), "h:mm AP");
- if (daysDiff === 0)
- return timeStr;
- try {
- const localeName = (typeof I18n !== "undefined" && I18n.locale) ? I18n.locale().name : "en-US";
- const weekday = date.toLocaleDateString(localeName, {
- weekday: "long"
- });
- return weekday + ", " + timeStr;
- } catch (e) {
- return timeStr;
- }
- }
-
- function _nowSec() {
- return Date.now() / 1000.0;
- }
-
- function _ingressAllowed(urgency) {
- const t = _nowSec();
- if (t - _lastIngressSec >= 1.0) {
- _lastIngressSec = t;
- _ingressCountThisSec = 0;
- }
- _ingressCountThisSec += 1;
- if (urgency === NotificationUrgency.Critical) {
- return true;
- }
- return _ingressCountThisSec <= maxIngressPerSecond;
- }
-
- function _enqueuePopup(wrapper) {
- if (notificationQueue.length >= maxQueueSize) {
- const gk = getGroupKey(wrapper);
- let idx = notificationQueue.findIndex(w => w && getGroupKey(w) === gk && w.urgency !== NotificationUrgency.Critical);
- if (idx === -1) {
- idx = notificationQueue.findIndex(w => w && w.urgency !== NotificationUrgency.Critical);
- }
- if (idx === -1) {
- idx = 0;
- }
- const victim = notificationQueue[idx];
- if (victim) {
- victim.popup = false;
- }
- notificationQueue.splice(idx, 1);
- }
- notificationQueue = [...notificationQueue, wrapper];
- }
-
- function _initWrapperPersistence(wrapper) {
- const timeoutMs = wrapper.timer ? wrapper.timer.interval : 5000;
- const isCritical = wrapper && wrapper.urgency === NotificationUrgency.Critical;
- wrapper.isPersistent = isCritical || (timeoutMs === 0);
- }
-
- function _shouldSaveToHistory(urgency, forceDisable) {
- if (forceDisable === true)
- return false;
- if (!SettingsData.notificationHistoryEnabled)
- return false;
- switch (urgency) {
- case NotificationUrgency.Low:
- return SettingsData.notificationHistorySaveLow;
- case NotificationUrgency.Critical:
- return SettingsData.notificationHistorySaveCritical;
- default:
- return SettingsData.notificationHistorySaveNormal;
- }
- }
-
- function _resolveAppNameForRule(notif) {
- if (!notif)
- return "";
- if (notif.appName && notif.appName !== "")
- return notif.appName;
- const entry = DesktopEntries.heuristicLookup(notif.desktopEntry);
- if (entry && entry.name)
- return entry.name;
- return "";
- }
-
- function _ruleFieldValue(field, info) {
- switch ((field || "").toString()) {
- case "desktopEntry":
- return info.desktopEntry;
- case "summary":
- return info.summary;
- case "body":
- return info.body;
- case "appName":
- default:
- return info.appName;
- }
- }
-
- function _coerceRuleUrgency(value, fallbackUrgency) {
- if (typeof value === "number" && value >= NotificationUrgency.Low && value <= NotificationUrgency.Critical)
- return value;
-
- const mapped = (value || "default").toString().toLowerCase();
- switch (mapped) {
- case "low":
- return NotificationUrgency.Low;
- case "normal":
- return NotificationUrgency.Normal;
- case "critical":
- return NotificationUrgency.Critical;
- default:
- return fallbackUrgency;
- }
- }
-
- function _matchesNotificationRule(rule, info) {
- if (!rule)
- return false;
- if (rule.enabled === false)
- return false;
-
- const pattern = (rule.pattern || "").toString();
- if (!pattern.trim())
- return false;
-
- const value = (_ruleFieldValue(rule.field, info) || "").toString();
- const matchType = (rule.matchType || "contains").toString().toLowerCase();
-
- if (matchType === "exact")
- return value.toLowerCase() === pattern.toLowerCase();
- if (matchType === "regex") {
- try {
- return new RegExp(pattern, "i").test(value);
- } catch (e) {
- console.warn("NotificationService: invalid notification rule regex:", pattern);
- return false;
- }
- }
-
- return value.toLowerCase().includes(pattern.toLowerCase());
- }
-
- function _evaluateNotificationPolicy(notif) {
- const baseUrgency = typeof notif.urgency === "number" ? notif.urgency : NotificationUrgency.Normal;
- const policy = {
- "drop": false,
- "disablePopup": false,
- "hideFromCenter": false,
- "disableHistory": false,
- "urgency": baseUrgency
- };
-
- const rules = SettingsData.notificationRules || [];
- if (!rules.length)
- return policy;
-
- const info = {
- "appName": _resolveAppNameForRule(notif),
- "desktopEntry": notif.desktopEntry || "",
- "summary": notif.summary || "",
- "body": notif.body || ""
- };
-
- for (const rule of rules) {
- if (!_matchesNotificationRule(rule, info))
- continue;
-
- const action = (rule.action || "default").toString().toLowerCase();
- switch (action) {
- case "ignore":
- policy.drop = true;
- break;
- case "mute":
- policy.disablePopup = true;
- break;
- case "popup_only":
- policy.hideFromCenter = true;
- policy.disableHistory = true;
- break;
- case "no_history":
- policy.disableHistory = true;
- break;
- default:
- break;
- }
-
- policy.urgency = _coerceRuleUrgency(rule.urgency, policy.urgency);
- return policy;
- }
-
- return policy;
- }
-
- function pruneHistory() {
- const maxAgeDays = SettingsData.notificationHistoryMaxAgeDays;
- if (maxAgeDays <= 0)
- return;
-
- const now = Date.now();
- const maxAgeMs = maxAgeDays * 24 * 60 * 60 * 1000;
- const toRemove = historyList.filter(item => (now - item.timestamp) > maxAgeMs);
- const pruned = historyList.filter(item => (now - item.timestamp) <= maxAgeMs);
-
- if (pruned.length !== historyList.length) {
- for (const item of toRemove) {
- _deleteCachedImage(item.image);
- }
- historyList = pruned;
- saveHistory();
- }
- }
-
- function deleteHistory() {
- for (const item of historyList) {
- _deleteCachedImage(item.image);
- }
- historyList = [];
- historyAdapter.notifications = [];
- historyFileView.writeAdapter();
- }
-
- function onOverlayOpen() {
- popupsDisabled = true;
- addGate.stop();
- addGateBusy = false;
-
- notificationQueue = [];
- for (const w of visibleNotifications) {
- if (w) {
- w.popup = false;
- }
- }
- visibleNotifications = [];
- _recomputeGroupsLater();
- pruneHistory();
- }
-
- function onOverlayClose() {
- popupsDisabled = false;
- processQueue();
- }
-
- Timer {
- id: addGate
- interval: 80
- running: false
- repeat: false
- onTriggered: {
- addGateBusy = false;
- processQueue();
- }
- }
-
- Timer {
- id: timeUpdateTimer
- interval: 30000
- repeat: true
- running: root.allWrappers.length > 0 || visibleNotifications.length > 0
- triggeredOnStart: false
- onTriggered: {
- root.timeUpdateTick = !root.timeUpdateTick;
- }
- }
-
- Timer {
- id: dismissPump
- interval: _dismissTickMs
- repeat: true
- running: false
- onTriggered: {
- let n = Math.min(_dismissBatchSize, _dismissQueue.length);
- for (var i = 0; i < n; ++i) {
- const w = _dismissQueue.pop();
- try {
- if (w && w.notification) {
- w.notification.dismiss();
- }
- } catch (e) {}
- }
- if (_dismissQueue.length === 0) {
- dismissPump.stop();
- _suspendGrouping = false;
- bulkDismissing = false;
- popupsDisabled = false;
- _recomputeGroupsLater();
- }
- }
- }
-
- Timer {
- id: groupsDebounce
- interval: 16
- repeat: false
- onTriggered: _recomputeGroups()
- }
-
- property bool timeUpdateTick: false
- property bool clockFormatChanged: false
-
- readonly property var groupedNotifications: _groupCache.notifications
- readonly property var groupedPopups: _groupCache.popups
-
- property var expandedGroups: ({})
- property var expandedMessages: ({})
- property bool popupsDisabled: false
-
- NotificationServer {
- id: server
-
- keepOnReload: false
- actionsSupported: true
- actionIconsSupported: true
- bodyHyperlinksSupported: true
- bodyImagesSupported: true
- bodyMarkupSupported: true
- imageSupported: true
- inlineReplySupported: true
- persistenceSupported: true
-
- onNotification: notif => {
- notif.tracked = true;
-
- const policy = _evaluateNotificationPolicy(notif);
- if (policy.drop) {
- try {
- notif.dismiss();
- } catch (e) {}
- return;
- }
-
- if (!_ingressAllowed(policy.urgency)) {
- if (policy.urgency !== NotificationUrgency.Critical) {
- try {
- notif.dismiss();
- } catch (e) {}
- return;
- }
- }
-
- if (SettingsData.soundsEnabled && SettingsData.soundNewNotification) {
- if (policy.urgency === NotificationUrgency.Critical) {
- AudioService.playCriticalNotificationSound();
- } else {
- AudioService.playNormalNotificationSound();
- }
- }
-
- const shouldShowPopup = !root.popupsDisabled && !SessionData.doNotDisturb && !policy.disablePopup;
- const isTransient = notif.transient;
- const shouldKeepInCenter = !isTransient && !policy.hideFromCenter;
-
- if (!shouldShowPopup && !shouldKeepInCenter) {
- try {
- notif.dismiss();
- } catch (e) {}
- return;
- }
-
- const wrapper = notifComponent.createObject(root, {
- "popup": shouldShowPopup,
- "notification": notif,
- "urgencyOverride": policy.urgency
- });
-
- if (wrapper) {
- root.allWrappers.push(wrapper);
- if (shouldKeepInCenter) {
- root.notifications.push(wrapper);
- if (_shouldSaveToHistory(wrapper.urgency, policy.disableHistory)) {
- root.addToHistory(wrapper);
- }
- }
- Qt.callLater(() => {
- _initWrapperPersistence(wrapper);
- });
-
- if (shouldShowPopup) {
- _enqueuePopup(wrapper);
- processQueue();
- }
- }
-
- _recomputeGroupsLater();
- }
- }
-
- component NotifWrapper: QtObject {
- id: wrapper
-
- property bool popup: false
- property bool removedByLimit: false
- property bool isPersistent: true
- property int seq: 0
- property string persistedImagePath: ""
-
- onPopupChanged: {
- if (!popup) {
- removeFromVisibleNotifications(wrapper);
- }
- }
-
- readonly property Timer timer: Timer {
- interval: {
- if (!wrapper.notification)
- return 5000;
- switch (wrapper.urgency) {
- case NotificationUrgency.Low:
- return SettingsData.notificationTimeoutLow;
- case NotificationUrgency.Critical:
- return SettingsData.notificationTimeoutCritical;
- default:
- return SettingsData.notificationTimeoutNormal;
- }
- }
- repeat: false
- running: false
- onTriggered: {
- if (interval > 0) {
- wrapper.popup = false;
- }
- }
- }
-
- readonly property date time: new Date()
- readonly property string timeStr: {
- root.timeUpdateTick;
- root.clockFormatChanged;
-
- const now = new Date();
- const diff = now.getTime() - time.getTime();
- const minutes = Math.floor(diff / 60000);
- const hours = Math.floor(minutes / 60);
-
- if (hours < 1) {
- if (minutes < 1) {
- return "now";
- }
- return `${minutes}m ago`;
- }
-
- const nowDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());
- const timeDate = new Date(time.getFullYear(), time.getMonth(), time.getDate());
- const daysDiff = Math.floor((nowDate - timeDate) / (1000 * 60 * 60 * 24));
-
- if (daysDiff === 0) {
- return formatTime(time);
- }
-
- try {
- const localeName = (typeof I18n !== "undefined" && I18n.locale) ? I18n.locale().name : "en-US";
- const weekday = time.toLocaleDateString(localeName, {
- weekday: "long"
- });
- return `${weekday}, ${formatTime(time)}`;
- } catch (e) {
- return formatTime(time);
- }
- }
-
- function formatTime(date) {
- let use24Hour = true;
- try {
- if (typeof SettingsData !== "undefined" && SettingsData.use24HourClock !== undefined) {
- use24Hour = SettingsData.use24HourClock;
- }
- } catch (e) {
- use24Hour = true;
- }
-
- if (use24Hour) {
- return date.toLocaleTimeString(Qt.locale(), "HH:mm");
- } else {
- return date.toLocaleTimeString(Qt.locale(), "h:mm AP");
- }
- }
-
- required property Notification notification
- readonly property string summary: (notification?.summary ?? "").replace(/<img\b[^>]*>/gi, "")
- readonly property string body: (notification?.body ?? "").replace(/<img\b[^>]*>/gi, "")
- readonly property string htmlBody: root._resolveHtmlBody(body)
- readonly property string appIcon: notification?.appIcon ?? ""
- readonly property string appName: {
- if (!notification)
- return "app";
- if (notification.appName == "") {
- const entry = DesktopEntries.heuristicLookup(notification.desktopEntry);
- if (entry && entry.name)
- return entry.name.toLowerCase();
- }
- return notification.appName || "app";
- }
- readonly property string desktopEntry: notification?.desktopEntry ?? ""
- readonly property string image: notification?.image ?? ""
- readonly property string cleanImage: {
- if (!image)
- return "";
- return Paths.strip(image);
- }
- property int urgencyOverride: notification?.urgency ?? NotificationUrgency.Normal
- readonly property int urgency: urgencyOverride
- readonly property list<NotificationAction> actions: notification?.actions ?? []
-
- readonly property Connections conn: Connections {
- target: wrapper.notification?.Retainable ?? null
-
- function onDropped(): void {
- root.allWrappers = root.allWrappers.filter(w => w !== wrapper);
- root.notifications = root.notifications.filter(w => w !== wrapper);
-
- if (root.bulkDismissing) {
- return;
- }
-
- const groupKey = getGroupKey(wrapper);
- const remainingInGroup = root.notifications.filter(n => getGroupKey(n) === groupKey);
-
- if (remainingInGroup.length <= 1) {
- clearGroupExpansionState(groupKey);
- }
-
- cleanupExpansionStates();
- root._recomputeGroupsLater();
- }
-
- function onAboutToDestroy(): void {
- wrapper.destroy();
- }
- }
- }
-
- Component {
- id: notifComponent
- NotifWrapper {}
- }
-
- function dismissAllPopups() {
- for (const w of visibleNotifications) {
- if (w) {
- w.popup = false;
- }
- }
- visibleNotifications = [];
- notificationQueue = [];
- }
-
- function clearAllNotifications() {
- if (!notifications.length) {
- return;
- }
- bulkDismissing = true;
- popupsDisabled = true;
- addGate.stop();
- addGateBusy = false;
- notificationQueue = [];
-
- for (const w of allWrappers) {
- if (w) {
- w.popup = false;
- }
- }
- visibleNotifications = [];
-
- _dismissQueue = notifications.slice();
- if (notifications.length) {
- notifications = [];
- }
- expandedGroups = {};
- expandedMessages = {};
-
- _suspendGrouping = true;
-
- if (!dismissPump.running && _dismissQueue.length) {
- dismissPump.start();
- }
- }
-
- function dismissNotification(wrapper) {
- if (!wrapper || !wrapper.notification) {
- return;
- }
- wrapper.popup = false;
- wrapper.notification.dismiss();
- }
-
- function disablePopups(disable) {
- popupsDisabled = disable;
- if (disable) {
- notificationQueue = [];
- for (const notif of visibleNotifications) {
- notif.popup = false;
- }
- visibleNotifications = [];
- }
- }
-
- property bool _processingQueue: false
-
- function processQueue() {
- if (addGateBusy || _processingQueue)
- return;
- if (popupsDisabled)
- return;
- if (SessionData.doNotDisturb)
- return;
- if (notificationQueue.length === 0)
- return;
-
- _processingQueue = true;
-
- const next = notificationQueue.shift();
- if (!next) {
- _processingQueue = false;
- return;
- }
-
- next.seq = ++seqCounter;
-
- const activePopups = visibleNotifications.filter(n => n && n.popup);
- let evicted = null;
- if (activePopups.length >= maxVisibleNotifications) {
- const unhovered = activePopups.filter(n => n.timer?.running);
- const pool = unhovered.length > 0 ? unhovered : activePopups;
- evicted = pool.reduce((min, n) => (n.seq < min.seq) ? n : min, pool[0]);
- if (evicted)
- evicted.removedByLimit = true;
- }
-
- if (evicted) {
- visibleNotifications = [...visibleNotifications.filter(n => n !== evicted), next];
- } else {
- visibleNotifications = [...visibleNotifications, next];
- }
-
- if (evicted)
- evicted.popup = false;
- next.popup = true;
-
- if (next.timer.interval > 0)
- next.timer.start();
-
- addGateBusy = true;
- addGate.restart();
- _processingQueue = false;
- }
-
- function removeFromVisibleNotifications(wrapper) {
- visibleNotifications = visibleNotifications.filter(n => n !== wrapper);
- processQueue();
- }
-
- function releaseWrapper(w) {
- visibleNotifications = visibleNotifications.filter(n => n !== w);
- notificationQueue = notificationQueue.filter(n => n !== w);
-
- if (w && w.destroy && !w.isPersistent && notifications.indexOf(w) === -1) {
- Qt.callLater(() => {
- try {
- w.destroy();
- } catch (e) {}
- });
- }
- }
-
- function _decodeEntities(s) {
- s = s.replace(/&#(\d+);/g, (_, n) => String.fromCodePoint(parseInt(n, 10)));
- s = s.replace(/&#x([0-9a-fA-F]+);/g, (_, n) => String.fromCodePoint(parseInt(n, 16)));
- return s.replace(/&([a-zA-Z][a-zA-Z0-9]*);/g, (match, name) => {
- switch (name) {
- case "amp":
- return "&";
- case "lt":
- return "<";
- case "gt":
- return ">";
- case "quot":
- return "\"";
- case "apos":
- return "'";
- case "nbsp":
- return "\u00A0";
- case "ndash":
- return "\u2013";
- case "mdash":
- return "\u2014";
- case "lsquo":
- return "\u2018";
- case "rsquo":
- return "\u2019";
- case "ldquo":
- return "\u201C";
- case "rdquo":
- return "\u201D";
- case "bull":
- return "\u2022";
- case "hellip":
- return "\u2026";
- case "trade":
- return "\u2122";
- case "copy":
- return "\u00A9";
- case "reg":
- return "\u00AE";
- case "deg":
- return "\u00B0";
- case "plusmn":
- return "\u00B1";
- case "times":
- return "\u00D7";
- case "divide":
- return "\u00F7";
- case "micro":
- return "\u00B5";
- case "middot":
- return "\u00B7";
- case "laquo":
- return "\u00AB";
- case "raquo":
- return "\u00BB";
- case "larr":
- return "\u2190";
- case "rarr":
- return "\u2192";
- case "uarr":
- return "\u2191";
- case "darr":
- return "\u2193";
- default:
- return match;
- }
- });
- }
-
- function _resolveHtmlBody(body) {
- if (!body)
- return "";
-
- let result = body;
-
- if (/<\/?[a-z][\s\S]*>/i.test(body)) {
- result = body;
- } else {
- // Decode percent-encoded URLs (e.g. https%3A%2F%2F → https://)
- let processed = body.replace(/\bhttps?%3A%2F%2F[^\s]+/gi, match => {
- try {
- return decodeURIComponent(match);
- } catch (e) {
- return match;
- }
- });
-
- if (/&(#\d+|#x[0-9a-fA-F]+|[a-zA-Z][a-zA-Z0-9]+);/.test(processed)) {
- const decoded = _decodeEntities(processed);
- if (/<\/?[a-z][\s\S]*>/i.test(decoded))
- result = decoded;
- else
- result = Markdown2Html.markdownToHtml(decoded);
- } else {
- result = Markdown2Html.markdownToHtml(processed);
- }
- }
-
- // Strip out image tags to prevent IP tracking
- return result.replace(/<img\b[^>]*>/gi, "");
- }
-
- function getGroupKey(wrapper) {
- if (wrapper.desktopEntry && wrapper.desktopEntry !== "") {
- return wrapper.desktopEntry.toLowerCase();
- }
-
- return wrapper.appName.toLowerCase();
- }
-
- function _recomputeGroups() {
- if (_suspendGrouping) {
- _groupsDirty = true;
- return;
- }
- _groupCache = {
- "notifications": _calcGroupedNotifications(),
- "popups": _calcGroupedPopups()
- };
- _groupsDirty = false;
- }
-
- function _recomputeGroupsLater() {
- _groupsDirty = true;
- if (!groupsDebounce.running) {
- groupsDebounce.start();
- }
- }
-
- function _calcGroupedNotifications() {
- const groups = {};
-
- for (const notif of notifications) {
- if (!notif || !notif.notification)
- continue;
- const groupKey = getGroupKey(notif);
- if (!groups[groupKey]) {
- groups[groupKey] = {
- "key": groupKey,
- "appName": notif.appName,
- "notifications": [],
- "latestNotification": null,
- "count": 0,
- "hasInlineReply": false
- };
- }
-
- groups[groupKey].notifications.unshift(notif);
- groups[groupKey].latestNotification = groups[groupKey].notifications[0];
- groups[groupKey].count = groups[groupKey].notifications.length;
-
- if (notif.notification?.hasInlineReply)
- groups[groupKey].hasInlineReply = true;
- }
-
- return Object.values(groups).sort((a, b) => {
- if (!a.latestNotification || !b.latestNotification)
- return 0;
- const aUrgency = a.latestNotification.urgency ?? NotificationUrgency.Low;
- const bUrgency = b.latestNotification.urgency ?? NotificationUrgency.Low;
- if (aUrgency !== bUrgency) {
- return bUrgency - aUrgency;
- }
- return b.latestNotification.time.getTime() - a.latestNotification.time.getTime();
- });
- }
-
- function _calcGroupedPopups() {
- const groups = {};
-
- for (const notif of popups) {
- if (!notif || !notif.notification)
- continue;
- const groupKey = getGroupKey(notif);
- if (!groups[groupKey]) {
- groups[groupKey] = {
- "key": groupKey,
- "appName": notif.appName,
- "notifications": [],
- "latestNotification": null,
- "count": 0,
- "hasInlineReply": false
- };
- }
-
- groups[groupKey].notifications.unshift(notif);
- groups[groupKey].latestNotification = groups[groupKey].notifications[0];
- groups[groupKey].count = groups[groupKey].notifications.length;
-
- if (notif.notification?.hasInlineReply)
- groups[groupKey].hasInlineReply = true;
- }
-
- return Object.values(groups).sort((a, b) => {
- if (!a.latestNotification || !b.latestNotification)
- return 0;
- return b.latestNotification.time.getTime() - a.latestNotification.time.getTime();
- });
- }
-
- function toggleGroupExpansion(groupKey) {
- let newExpandedGroups = {};
- for (const key in expandedGroups) {
- newExpandedGroups[key] = expandedGroups[key];
- }
- newExpandedGroups[groupKey] = !newExpandedGroups[groupKey];
- expandedGroups = newExpandedGroups;
- }
-
- function dismissGroup(groupKey) {
- const group = groupedNotifications.find(g => g.key === groupKey);
- if (group) {
- for (const notif of group.notifications) {
- if (notif && notif.notification) {
- notif.notification.dismiss();
- }
- }
- } else {
- for (const notif of allWrappers) {
- if (notif && notif.notification && getGroupKey(notif) === groupKey) {
- notif.notification.dismiss();
- }
- }
- }
- }
-
- function clearGroupExpansionState(groupKey) {
- let newExpandedGroups = {};
- for (const key in expandedGroups) {
- if (key !== groupKey && expandedGroups[key]) {
- newExpandedGroups[key] = true;
- }
- }
- expandedGroups = newExpandedGroups;
- }
-
- function cleanupExpansionStates() {
- const currentGroupKeys = new Set(groupedNotifications.map(g => g.key));
- const currentMessageIds = new Set();
- for (const group of groupedNotifications) {
- for (const notif of group.notifications) {
- if (notif && notif.notification) {
- currentMessageIds.add(notif.notification.id);
- }
- }
- }
- let newExpandedGroups = {};
- for (const key in expandedGroups) {
- if (currentGroupKeys.has(key) && expandedGroups[key]) {
- newExpandedGroups[key] = true;
- }
- }
- expandedGroups = newExpandedGroups;
- let newExpandedMessages = {};
- for (const messageId in expandedMessages) {
- if (currentMessageIds.has(messageId) && expandedMessages[messageId]) {
- newExpandedMessages[messageId] = true;
- }
- }
- expandedMessages = newExpandedMessages;
- }
-
- function toggleMessageExpansion(messageId) {
- let newExpandedMessages = {};
- for (const key in expandedMessages) {
- newExpandedMessages[key] = expandedMessages[key];
- }
- newExpandedMessages[messageId] = !newExpandedMessages[messageId];
- expandedMessages = newExpandedMessages;
- }
-
- Connections {
- target: SessionData
- function onDoNotDisturbChanged() {
- if (SessionData.doNotDisturb) {
- // Hide all current popups when DND is enabled
- for (const notif of visibleNotifications) {
- notif.popup = false;
- }
- visibleNotifications = [];
- notificationQueue = [];
- } else {
- // Re-enable popup processing when DND is disabled
- processQueue();
- }
- }
- }
-
- Connections {
- target: typeof SettingsData !== "undefined" ? SettingsData : null
- function onUse24HourClockChanged() {
- root.clockFormatChanged = !root.clockFormatChanged;
- }
- function onNotificationHistoryMaxAgeDaysChanged() {
- root.pruneHistory();
- }
- function onNotificationHistoryEnabledChanged() {
- if (!SettingsData.notificationHistoryEnabled) {
- root.deleteHistory();
- }
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PluginService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PluginService.qml
deleted file mode 100644
index 03f9be6..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PluginService.qml
+++ /dev/null
@@ -1,876 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtCore
-import QtQuick
-import Qt.labs.folderlistmodel
-import Quickshell
-import qs.Common
-import qs.Services
-
-Singleton {
- id: root
-
- property var availablePlugins: ({})
- property var loadedPlugins: ({})
- property var pluginWidgetComponents: ({})
- property var pluginDaemonComponents: ({})
- property var pluginLauncherComponents: ({})
- property var pluginDesktopComponents: ({})
- property var availablePluginsList: []
- property string pluginDirectory: {
- var configDir = StandardPaths.writableLocation(StandardPaths.ConfigLocation);
- var configDirStr = configDir.toString();
- if (configDirStr.startsWith("file://")) {
- configDirStr = configDirStr.substring(7);
- }
- return configDirStr + "/DankMaterialShell/plugins";
- }
- property string systemPluginDirectory: "/etc/xdg/quickshell/dms-plugins"
-
- property var knownManifests: ({})
- property var pathToPluginId: ({})
- property var pluginInstances: ({})
- property var globalVars: ({})
-
- property var _stateCache: ({})
- property var _stateLoaded: ({})
- property var _stateWriters: ({})
- property var _stateDirtyPlugins: ({})
- property bool _stateDirCreated: false
-
- signal pluginLoaded(string pluginId)
- signal pluginUnloaded(string pluginId)
- signal pluginLoadFailed(string pluginId, string error)
- signal pluginDataChanged(string pluginId)
- signal pluginStateChanged(string pluginId)
- signal pluginListUpdated
- signal globalVarChanged(string pluginId, string varName)
- signal requestLauncherUpdate(string pluginId)
-
- Timer {
- id: resyncDebounce
- interval: 120
- repeat: false
- onTriggered: resyncAll()
- }
-
- Timer {
- id: _stateWriteTimer
- interval: 150
- repeat: false
- onTriggered: root._flushDirtyStates()
- }
-
- Component.onCompleted: {
- userWatcher.folder = Paths.toFileUrl(root.pluginDirectory);
- systemWatcher.folder = Paths.toFileUrl(root.systemPluginDirectory);
- Qt.callLater(resyncAll);
- }
-
- FolderListModel {
- id: userWatcher
- showDirs: true
- showFiles: false
- showDotAndDotDot: false
-
- onCountChanged: resyncDebounce.restart()
- onStatusChanged: {
- if (status === FolderListModel.Ready)
- resyncDebounce.restart();
- }
- }
-
- FolderListModel {
- id: systemWatcher
- showDirs: true
- showFiles: false
- showDotAndDotDot: false
-
- onCountChanged: 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;
- for (let i = 0; i < n; i++) {
- let dirPath = model.get(i, "filePath");
- if (dirPath.startsWith("file://")) {
- dirPath = dirPath.substring(7);
- }
- if (!dirPath.startsWith(baseDir)) {
- continue;
- }
- const manifestPath = dirPath + "/plugin.json";
- out.push({
- path: manifestPath,
- source: sourceTag
- });
- }
- return out;
- }
-
- function resyncAll() {
- 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];
- if (!prev) {
- 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]);
-
- const removed = [];
- for (const path in knownManifests) {
- if (!seenPaths[path])
- removed.push(path);
- }
- if (removed.length) {
- removed.forEach(function (path) {
- const pid = pathToPluginId[path];
- if (pid) {
- unregisterPluginByPath(path, pid);
- }
- delete knownManifests[path];
- delete pathToPluginId[path];
- });
- _updateAvailablePluginsList();
- pluginListUpdated();
- }
- }
-
- function loadPluginManifestFile(manifestPathNoScheme, sourceTag, mtimeEpochMs) {
- const manifestId = "m_" + Math.random().toString(36).slice(2);
- const qml = `
- import QtQuick
- import Quickshell.Io
- FileView {
- id: fv
- property string absPath: ""
- onLoaded: {
- try {
- let raw = text()
- if (raw.charCodeAt(0) === 0xFEFF) raw = raw.slice(1)
- const manifest = JSON.parse(raw)
- root._onManifestParsed(absPath, manifest, "${sourceTag}", ${mtimeEpochMs})
- } catch (e) {
- console.error("PluginService: bad manifest", absPath, e.message)
- knownManifests[absPath] = { mtime: ${mtimeEpochMs}, source: "${sourceTag}", bad: true }
- }
- fv.destroy()
- }
- onLoadFailed: (err) => {
- console.warn("PluginService: manifest load failed", absPath, err)
- fv.destroy()
- }
- }
- `;
-
- 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;
- }
-
- 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];
-
- let perms = manifest.permissions;
- if (typeof perms === "string") {
- perms = perms.split(/\s*,\s*/);
- }
- if (!Array.isArray(perms)) {
- perms = [];
- }
- 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.requires_dms = manifest.requires_dms || null;
-
- 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);
- }
- 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 = info.type === "desktop" || 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;
- }
- }
-
- function unregisterPluginByPath(absPath, 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;
- }
- }
-
- function loadPlugin(pluginId, bustCache) {
- const plugin = availablePlugins[pluginId];
- if (!plugin) {
- console.error("PluginService: Plugin not found:", pluginId);
- pluginLoadFailed(pluginId, "Plugin not found");
- return false;
- }
-
- if (plugin.loaded) {
- return true;
- }
-
- 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) {
- prevInstance.destroy();
- const newInstances = Object.assign({}, pluginInstances);
- delete newInstances[pluginId];
- pluginInstances = newInstances;
- }
-
- try {
- 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;
- }
-
- if (isDaemon) {
- const newDaemons = Object.assign({}, pluginDaemonComponents);
- newDaemons[pluginId] = comp;
- pluginDaemonComponents = newDaemons;
- } else if (isLauncher) {
- const instance = comp.createObject(root, {
- "pluginService": root
- });
- if (!instance) {
- console.error("PluginService: failed to instantiate plugin:", pluginId, comp.errorString());
- pluginLoadFailed(pluginId, comp.errorString());
- return false;
- }
- const newInstances = Object.assign({}, pluginInstances);
- newInstances[pluginId] = instance;
- pluginInstances = newInstances;
-
- 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;
- pluginWidgetComponents = newComponents;
- }
-
- 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;
- }
- }
-
- function unloadPlugin(pluginId) {
- const plugin = loadedPlugins[pluginId];
- if (!plugin) {
- 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 isDesktop = plugin.type === "desktop";
-
- const instance = pluginInstances[pluginId];
- if (instance) {
- 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;
- } else if (isLauncher && pluginLauncherComponents[pluginId]) {
- 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];
- pluginWidgetComponents = newComponents;
- }
-
- plugin.loaded = false;
- const newLoaded = Object.assign({}, loadedPlugins);
- delete newLoaded[pluginId];
- loadedPlugins = newLoaded;
-
- _cleanupPluginStateWriter(pluginId);
- pluginUnloaded(pluginId);
- return true;
- } catch (error) {
- console.error("PluginService: Error unloading plugin:", pluginId, "Error:", error.message);
- return false;
- }
- }
-
- function getWidgetComponents() {
- return pluginWidgetComponents;
- }
-
- function getDaemonComponents() {
- return pluginDaemonComponents;
- }
-
- function getDesktopComponents() {
- return pluginDesktopComponents;
- }
-
- function getAvailablePlugins() {
- return availablePluginsList;
- }
-
- function _updateAvailablePluginsList() {
- const result = [];
- for (const key in availablePlugins) {
- result.push(availablePlugins[key]);
- }
- availablePluginsList = result;
- }
-
- function getPluginVariants(pluginId) {
- const plugin = availablePlugins[pluginId];
- if (!plugin) {
- return [];
- }
- const variants = SettingsData.getPluginSetting(pluginId, "variants", []);
- return variants;
- }
-
- function getAllPluginVariants() {
- const result = [];
- for (const pluginId in availablePlugins) {
- const plugin = availablePlugins[pluginId];
- if (plugin.type !== "widget") {
- continue;
- }
- const variants = getPluginVariants(pluginId);
- if (variants.length === 0) {
- result.push({
- pluginId: pluginId,
- variantId: null,
- fullId: pluginId,
- name: plugin.name,
- 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];
- result.push({
- pluginId: pluginId,
- variantId: variant.id,
- fullId: pluginId + ":" + variant.id,
- name: plugin.name + " - " + variant.name,
- icon: variant.icon || plugin.icon || "extension",
- description: variant.description || plugin.description || "Plugin widget variant",
- loaded: plugin.loaded
- });
- }
- }
- }
- return result;
- }
-
- function createPluginVariant(pluginId, variantName, variantConfig) {
- 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;
- }
-
- function removePluginVariant(pluginId, variantId) {
- 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);
-
- pluginDataChanged(pluginId);
- }
-
- function removeWidgetFromDankBar(widgetId) {
- function filterWidget(widget) {
- const id = typeof widget === "string" ? widget : widget.id;
- return id !== widgetId;
- }
-
- const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default");
- if (!defaultBar)
- return;
- 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);
-
- if (newLeft.length !== leftWidgets.length) {
- SettingsData.setDankBarLeftWidgets(newLeft);
- }
- if (newCenter.length !== centerWidgets.length) {
- SettingsData.setDankBarCenterWidgets(newCenter);
- }
- if (newRight.length !== rightWidgets.length) {
- SettingsData.setDankBarRightWidgets(newRight);
- }
- }
-
- function updatePluginVariant(pluginId, variantId, variantConfig) {
- 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;
- }
- }
- SettingsData.setPluginSetting(pluginId, "variants", variants);
- pluginDataChanged(pluginId);
- }
-
- function getPluginVariantData(pluginId, variantId) {
- const variants = getPluginVariants(pluginId);
- for (let i = 0; i < variants.length; i++) {
- if (variants[i].id === variantId) {
- return variants[i];
- }
- }
- return null;
- }
-
- function getLoadedPlugins() {
- const result = [];
- for (const key in loadedPlugins) {
- result.push(loadedPlugins[key]);
- }
- return result;
- }
-
- function isPluginLoaded(pluginId) {
- return loadedPlugins[pluginId] !== undefined;
- }
-
- function enablePlugin(pluginId) {
- SettingsData.setPluginSetting(pluginId, "enabled", true);
- return loadPlugin(pluginId);
- }
-
- function disablePlugin(pluginId) {
- SettingsData.setPluginSetting(pluginId, "enabled", false);
- return unloadPlugin(pluginId);
- }
-
- function reloadPlugin(pluginId) {
- if (isPluginLoaded(pluginId))
- unloadPlugin(pluginId);
- return loadPlugin(pluginId, true);
- }
-
- function togglePlugin(pluginId) {
- let instance = pluginInstances[pluginId];
-
- // Lazy instantiate daemon plugins on first toggle
- // This respects the daemon lifecycle (not instantiated on load)
- // while supporting toggle functionality for slideout-capable daemons
- if (!instance && pluginDaemonComponents[pluginId]) {
- const comp = pluginDaemonComponents[pluginId];
- const newInstance = comp.createObject(root, {
- "pluginId": pluginId,
- "pluginService": root
- });
- if (newInstance) {
- const newInstances = Object.assign({}, pluginInstances);
- newInstances[pluginId] = newInstance;
- pluginInstances = newInstances;
- instance = newInstance;
- }
- }
-
- if (instance && typeof instance.toggle === "function") {
- instance.toggle();
- return true;
- }
- return false;
- }
-
- function savePluginData(pluginId, key, value) {
- SettingsData.setPluginSetting(pluginId, key, value);
- pluginDataChanged(pluginId);
- return true;
- }
-
- function loadPluginData(pluginId, key, defaultValue) {
- return SettingsData.getPluginSetting(pluginId, key, defaultValue);
- }
-
- function getPluginPath(pluginId) {
- const plugin = availablePlugins[pluginId];
- if (!plugin)
- return "";
- return plugin.pluginDirectory || "";
- }
-
- function saveAllPluginSettings() {
- SettingsData.savePluginSettings();
- }
-
- function getPluginStatePath(pluginId) {
- return Paths.strip(Paths.state) + "/plugins/" + pluginId + "_state.json";
- }
-
- function loadPluginState(pluginId, key, defaultValue) {
- if (!_stateLoaded[pluginId])
- _loadStateFromDisk(pluginId);
- const state = _stateCache[pluginId];
- if (!state)
- return defaultValue;
- return state[key] !== undefined ? state[key] : defaultValue;
- }
-
- function savePluginState(pluginId, key, value) {
- if (!_stateLoaded[pluginId])
- _loadStateFromDisk(pluginId);
- if (!_stateCache[pluginId])
- _stateCache[pluginId] = {};
- _stateCache[pluginId][key] = value;
- _stateDirtyPlugins[pluginId] = true;
- _stateWriteTimer.restart();
- pluginStateChanged(pluginId);
- }
-
- function clearPluginState(pluginId) {
- _stateCache[pluginId] = {};
- _stateLoaded[pluginId] = true;
- _flushStateToDisk(pluginId);
- pluginStateChanged(pluginId);
- }
-
- function removePluginStateKey(pluginId, key) {
- if (!_stateCache[pluginId])
- return;
- delete _stateCache[pluginId][key];
- _stateDirtyPlugins[pluginId] = true;
- _stateWriteTimer.restart();
- pluginStateChanged(pluginId);
- }
-
- function _ensureStateDir() {
- if (_stateDirCreated)
- return;
- _stateDirCreated = true;
- Paths.mkdir(Paths.state + "/plugins");
- }
-
- function _loadStateFromDisk(pluginId) {
- _stateLoaded[pluginId] = true;
- _ensureStateDir();
- const path = getPluginStatePath(pluginId);
- const escapedPath = path.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
- try {
- const qml = 'import QtQuick; import Quickshell.Io; FileView { path: "' + escapedPath + '"; blockLoading: true; blockWrites: true; atomicWrites: true }';
- const fv = Qt.createQmlObject(qml, root, "sf_" + pluginId);
- const raw = fv.text();
- if (raw && raw.trim()) {
- _stateCache[pluginId] = JSON.parse(raw);
- } else {
- _stateCache[pluginId] = {};
- }
- _stateWriters[pluginId] = fv;
- } catch (e) {
- _stateCache[pluginId] = {};
- }
- }
-
- function _flushStateToDisk(pluginId) {
- _ensureStateDir();
- const content = JSON.stringify(_stateCache[pluginId] || {}, null, 2);
- if (_stateWriters[pluginId]) {
- _stateWriters[pluginId].setText(content);
- return;
- }
- const path = getPluginStatePath(pluginId);
- const escapedPath = path.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
- try {
- const qml = 'import QtQuick; import Quickshell.Io; FileView { path: "' + escapedPath + '"; blockWrites: true; atomicWrites: true }';
- const fv = Qt.createQmlObject(qml, root, "sw_" + pluginId);
- _stateWriters[pluginId] = fv;
- fv.loaded.connect(function () {
- fv.setText(content);
- });
- fv.loadFailed.connect(function () {
- fv.setText(content);
- });
- } catch (e) {
- console.warn("PluginService: Failed to write state for", pluginId, e.message);
- }
- }
-
- function _flushDirtyStates() {
- const dirty = _stateDirtyPlugins;
- _stateDirtyPlugins = {};
- for (const pluginId in dirty)
- _flushStateToDisk(pluginId);
- }
-
- function _cleanupPluginStateWriter(pluginId) {
- if (!_stateWriters[pluginId])
- return;
- _stateWriters[pluginId].destroy();
- delete _stateWriters[pluginId];
- }
-
- function scanPlugins() {
- const userUrl = Paths.toFileUrl(root.pluginDirectory);
- const systemUrl = Paths.toFileUrl(root.systemPluginDirectory);
- userWatcher.folder = "";
- userWatcher.folder = userUrl;
- systemWatcher.folder = "";
- systemWatcher.folder = systemUrl;
- resyncDebounce.restart();
- }
-
- function forceRescanPlugin(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());
- }
- }
-
- function createPluginDirectory() {
- 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) {
- if (exitCode !== 0) {
- console.error("PluginService: Failed to create plugin directory, exit code:", exitCode);
- }
- process.destroy();
- });
- process.running = true;
- return true;
- } else {
- console.error("PluginService: Failed to create mkdir process");
- return false;
- }
- }
-
- // Launcher plugin helper functions
- function getLauncherPlugins() {
- const launchers = {};
-
- // Check plugins that have launcher components
- for (const pluginId in pluginLauncherComponents) {
- const plugin = availablePlugins[pluginId];
- if (plugin && plugin.loaded) {
- launchers[pluginId] = plugin;
- }
- }
- return launchers;
- }
-
- function getLauncherPlugin(pluginId) {
- const plugin = availablePlugins[pluginId];
- if (plugin && plugin.loaded && pluginLauncherComponents[pluginId]) {
- return plugin;
- }
- return null;
- }
-
- function getPluginTrigger(pluginId) {
- const plugin = getLauncherPlugin(pluginId);
- if (plugin) {
- // Check if noTrigger is set (always active mode)
- const noTrigger = SettingsData.getPluginSetting(pluginId, "noTrigger", false);
- if (noTrigger) {
- return "";
- }
- // Otherwise load the custom trigger, defaulting to plugin manifest trigger
- const customTrigger = SettingsData.getPluginSetting(pluginId, "trigger", plugin.trigger || "!");
- return customTrigger;
- }
- return null;
- }
-
- function getAllPluginTriggers() {
- const triggers = {};
- const launchers = getLauncherPlugins();
-
- for (const pluginId in launchers) {
- const trigger = getPluginTrigger(pluginId);
- if (trigger && trigger.trim() !== "") {
- triggers[trigger] = pluginId;
- }
- }
- return triggers;
- }
-
- function getPluginsWithEmptyTrigger() {
- const plugins = [];
- const launchers = getLauncherPlugins();
-
- for (const pluginId in launchers) {
- const trigger = getPluginTrigger(pluginId);
- if (!trigger || trigger.trim() === "") {
- plugins.push(pluginId);
- }
- }
- return plugins;
- }
-
- function getPluginViewPreference(pluginId) {
- const plugin = availablePlugins[pluginId];
- if (!plugin)
- return null;
-
- return {
- mode: plugin.viewMode || null,
- enforced: plugin.viewModeEnforced === true
- };
- }
-
- function getGlobalVar(pluginId, varName, defaultValue) {
- if (globalVars[pluginId] && varName in globalVars[pluginId]) {
- return globalVars[pluginId][varName];
- }
- return defaultValue;
- }
-
- function setGlobalVar(pluginId, varName, value) {
- const newGlobals = Object.assign({}, globalVars);
- if (!newGlobals[pluginId]) {
- newGlobals[pluginId] = {};
- }
- newGlobals[pluginId] = Object.assign({}, newGlobals[pluginId]);
- newGlobals[pluginId][varName] = value;
- 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;
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PolkitService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PolkitService.qml
deleted file mode 100644
index 5238d04..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PolkitService.qml
+++ /dev/null
@@ -1,40 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-
-Singleton {
- id: root
-
- readonly property bool disablePolkitIntegration: Quickshell.env("DMS_DISABLE_POLKIT") === "1"
-
- property bool polkitAvailable: false
- property var agent: null
-
- function createPolkitAgent() {
- try {
- const qmlString = `
- import QtQuick
- import Quickshell.Services.Polkit
-
- PolkitAgent {
- }
- `
-
- agent = Qt.createQmlObject(qmlString, root, "PolkitService.Agent")
- polkitAvailable = true
- console.info("PolkitService: Initialized successfully")
- } catch (e) {
- polkitAvailable = false
- console.warn("PolkitService: Polkit not available - authentication prompts disabled. This requires a newer version of Quickshell.")
- }
- }
-
- Component.onCompleted: {
- if (disablePolkitIntegration) {
- return
- }
- createPolkitAgent()
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PopoutService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PopoutService.qml
deleted file mode 100644
index c6e8a09..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PopoutService.qml
+++ /dev/null
@@ -1,709 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-import QtQuick
-import Quickshell
-import Quickshell.Wayland
-import qs.Common
-
-Singleton {
- id: root
-
- property var controlCenterPopout: null
- property var controlCenterLoader: null
- property var notificationCenterPopout: null
- property var notificationCenterLoader: null
- property var appDrawerPopout: null
- property var appDrawerLoader: null
- property var processListPopout: null
- property var processListPopoutLoader: null
- property var dankDashPopout: null
- property var dankDashPopoutLoader: null
- property var batteryPopout: null
- property var batteryPopoutLoader: null
- property var vpnPopout: null
- property var vpnPopoutLoader: null
- property var systemUpdatePopout: null
- property var systemUpdateLoader: null
- property var layoutPopout: null
- property var layoutPopoutLoader: null
- property var clipboardHistoryPopout: null
- property var clipboardHistoryPopoutLoader: null
-
- property var settingsModal: null
- property var settingsModalLoader: null
- property var clipboardHistoryModal: null
- property var dankLauncherV2Modal: null
- property var dankLauncherV2ModalLoader: null
- property var powerMenuModal: null
- property var processListModal: null
- property var processListModalLoader: null
- property var colorPickerModal: null
- property var notificationModal: null
- property var wifiPasswordModal: null
- property var wifiPasswordModalLoader: null
- property var wifiQRCodeModal: null
- property var wifiQRCodeModalLoader: null
- property var polkitAuthModal: null
- property var polkitAuthModalLoader: null
- property var bluetoothPairingModal: null
- property var networkInfoModal: null
- property var windowRuleModalLoader: null
-
- property var notepadSlideouts: []
-
- property string pendingThemeInstall: ""
- property string pendingPluginInstall: ""
-
- function setPosition(popout, x, y, width, section, screen) {
- if (popout && popout.setTriggerPosition && arguments.length >= 6) {
- popout.setTriggerPosition(x, y, width, section, screen);
- }
- }
-
- function openControlCenter(x, y, width, section, screen) {
- if (controlCenterPopout) {
- setPosition(controlCenterPopout, x, y, width, section, screen);
- controlCenterPopout.open();
- }
- }
-
- function closeControlCenter() {
- controlCenterPopout?.close();
- }
-
- function unloadControlCenter() {
- if (!controlCenterLoader)
- return;
- controlCenterPopout = null;
- controlCenterLoader.active = false;
- }
-
- function toggleControlCenter(x, y, width, section, screen) {
- if (controlCenterPopout) {
- setPosition(controlCenterPopout, x, y, width, section, screen);
- controlCenterPopout.toggle();
- }
- }
-
- function openNotificationCenter(x, y, width, section, screen) {
- if (notificationCenterPopout) {
- setPosition(notificationCenterPopout, x, y, width, section, screen);
- notificationCenterPopout.open();
- }
- }
-
- function closeNotificationCenter() {
- notificationCenterPopout?.close();
- }
-
- function unloadNotificationCenter() {
- if (!notificationCenterLoader)
- return;
- notificationCenterPopout = null;
- notificationCenterLoader.active = false;
- }
-
- function toggleNotificationCenter(x, y, width, section, screen) {
- if (notificationCenterPopout) {
- setPosition(notificationCenterPopout, x, y, width, section, screen);
- notificationCenterPopout.toggle();
- }
- }
-
- function openAppDrawer(x, y, width, section, screen) {
- if (appDrawerPopout) {
- setPosition(appDrawerPopout, x, y, width, section, screen);
- appDrawerPopout.open();
- }
- }
-
- function closeAppDrawer() {
- appDrawerPopout?.close();
- }
-
- function unloadAppDrawer() {
- if (!appDrawerLoader)
- return;
- appDrawerPopout = null;
- appDrawerLoader.active = false;
- }
-
- function toggleAppDrawer(x, y, width, section, screen) {
- if (appDrawerPopout) {
- setPosition(appDrawerPopout, x, y, width, section, screen);
- appDrawerPopout.toggle();
- }
- }
-
- function openProcessList(x, y, width, section, screen) {
- if (processListPopout) {
- setPosition(processListPopout, x, y, width, section, screen);
- processListPopout.open();
- }
- }
-
- function closeProcessList() {
- processListPopout?.close();
- }
-
- function unloadProcessListPopout() {
- if (!processListPopoutLoader)
- return;
- processListPopout = null;
- processListPopoutLoader.active = false;
- }
-
- function toggleProcessList(x, y, width, section, screen) {
- if (processListPopout) {
- setPosition(processListPopout, x, y, width, section, screen);
- processListPopout.toggle();
- }
- }
-
- property bool _dankDashWantsOpen: false
- property bool _dankDashWantsToggle: false
- property int _dankDashPendingTab: 0
- property real _dankDashPendingX: 0
- property real _dankDashPendingY: 0
- property real _dankDashPendingWidth: 0
- property string _dankDashPendingSection: ""
- property var _dankDashPendingScreen: null
- property bool _dankDashHasPosition: false
-
- function _storeDankDashPosition(x, y, width, section, screen, hasPos) {
- _dankDashPendingX = x;
- _dankDashPendingY = y;
- _dankDashPendingWidth = width;
- _dankDashPendingSection = section;
- _dankDashPendingScreen = screen;
- _dankDashHasPosition = hasPos;
- }
-
- function openDankDash(tabIndex, x, y, width, section, screen) {
- _dankDashPendingTab = tabIndex || 0;
- if (dankDashPopout) {
- if (arguments.length >= 6)
- setPosition(dankDashPopout, x, y, width, section, screen);
- dankDashPopout.currentTabIndex = _dankDashPendingTab;
- dankDashPopout.dashVisible = true;
- return;
- }
- if (!dankDashPopoutLoader)
- return;
- _storeDankDashPosition(x, y, width, section, screen, arguments.length >= 6);
- _dankDashWantsOpen = true;
- _dankDashWantsToggle = false;
- dankDashPopoutLoader.active = true;
- }
-
- function closeDankDash() {
- if (dankDashPopout)
- dankDashPopout.dashVisible = false;
- }
-
- function unloadDankDash() {
- if (!dankDashPopoutLoader)
- return;
- dankDashPopout = null;
- dankDashPopoutLoader.active = false;
- }
-
- function toggleDankDash(tabIndex, x, y, width, section, screen) {
- _dankDashPendingTab = tabIndex || 0;
- if (dankDashPopout) {
- if (arguments.length >= 6)
- setPosition(dankDashPopout, x, y, width, section, screen);
- if (dankDashPopout.dashVisible) {
- dankDashPopout.dashVisible = false;
- } else {
- dankDashPopout.currentTabIndex = _dankDashPendingTab;
- dankDashPopout.dashVisible = true;
- }
- return;
- }
- if (!dankDashPopoutLoader)
- return;
- _storeDankDashPosition(x, y, width, section, screen, arguments.length >= 6);
- _dankDashWantsToggle = true;
- _dankDashWantsOpen = false;
- dankDashPopoutLoader.active = true;
- }
-
- function _onDankDashPopoutLoaded() {
- if (!dankDashPopout)
- return;
-
- if (_dankDashHasPosition)
- setPosition(dankDashPopout, _dankDashPendingX, _dankDashPendingY, _dankDashPendingWidth, _dankDashPendingSection, _dankDashPendingScreen);
-
- if (_dankDashWantsOpen) {
- _dankDashWantsOpen = false;
- dankDashPopout.currentTabIndex = _dankDashPendingTab;
- dankDashPopout.dashVisible = true;
- return;
- }
- if (_dankDashWantsToggle) {
- _dankDashWantsToggle = false;
- if (dankDashPopout.dashVisible) {
- dankDashPopout.dashVisible = false;
- } else {
- dankDashPopout.currentTabIndex = _dankDashPendingTab;
- dankDashPopout.dashVisible = true;
- }
- }
- }
-
- function openBattery(x, y, width, section, screen) {
- if (batteryPopout) {
- setPosition(batteryPopout, x, y, width, section, screen);
- batteryPopout.open();
- }
- }
-
- function closeBattery() {
- batteryPopout?.close();
- }
-
- function unloadBattery() {
- if (!batteryPopoutLoader)
- return;
- batteryPopout = null;
- batteryPopoutLoader.active = false;
- }
-
- function toggleBattery(x, y, width, section, screen) {
- if (batteryPopout) {
- setPosition(batteryPopout, x, y, width, section, screen);
- batteryPopout.toggle();
- }
- }
-
- function openVpn(x, y, width, section, screen) {
- if (vpnPopout) {
- setPosition(vpnPopout, x, y, width, section, screen);
- vpnPopout.open();
- }
- }
-
- function closeVpn() {
- vpnPopout?.close();
- }
-
- function unloadVpn() {
- if (!vpnPopoutLoader)
- return;
- vpnPopout = null;
- vpnPopoutLoader.active = false;
- }
-
- function toggleVpn(x, y, width, section, screen) {
- if (vpnPopout) {
- setPosition(vpnPopout, x, y, width, section, screen);
- vpnPopout.toggle();
- }
- }
-
- function openSystemUpdate(x, y, width, section, screen) {
- if (systemUpdatePopout) {
- setPosition(systemUpdatePopout, x, y, width, section, screen);
- systemUpdatePopout.open();
- }
- }
-
- function closeSystemUpdate() {
- systemUpdatePopout?.close();
- }
-
- function unloadSystemUpdate() {
- if (!systemUpdateLoader)
- return;
- systemUpdatePopout = null;
- systemUpdateLoader.active = false;
- }
-
- function toggleSystemUpdate(x, y, width, section, screen) {
- if (systemUpdatePopout) {
- setPosition(systemUpdatePopout, x, y, width, section, screen);
- systemUpdatePopout.toggle();
- }
- }
-
- property bool _settingsWantsOpen: false
- property bool _settingsWantsToggle: false
-
- property string _settingsPendingTab: ""
- property int _settingsPendingTabIndex: -1
-
- function openSettings() {
- if (settingsModal) {
- settingsModal.show();
- } else if (settingsModalLoader) {
- _settingsWantsOpen = true;
- _settingsWantsToggle = false;
- settingsModalLoader.activeAsync = true;
- }
- }
-
- function openSettingsWithTab(tabName: string) {
- if (settingsModal) {
- settingsModal.showWithTabName(tabName);
- return;
- }
- if (settingsModalLoader) {
- _settingsPendingTab = tabName;
- _settingsWantsOpen = true;
- _settingsWantsToggle = false;
- settingsModalLoader.activeAsync = true;
- }
- }
-
- function openSettingsWithTabIndex(tabIndex: int) {
- if (settingsModal) {
- settingsModal.showWithTab(tabIndex);
- return;
- }
- if (settingsModalLoader) {
- _settingsPendingTabIndex = tabIndex;
- _settingsWantsOpen = true;
- _settingsWantsToggle = false;
- settingsModalLoader.activeAsync = true;
- }
- }
-
- function closeSettings() {
- settingsModal?.close();
- }
-
- function toggleSettings() {
- if (settingsModal) {
- settingsModal.toggle();
- } else if (settingsModalLoader) {
- _settingsWantsToggle = true;
- _settingsWantsOpen = false;
- settingsModalLoader.activeAsync = true;
- }
- }
-
- function toggleSettingsWithTab(tabName: string) {
- if (settingsModal) {
- var idx = settingsModal.resolveTabIndex(tabName);
- if (idx >= 0)
- settingsModal.currentTabIndex = idx;
- settingsModal.toggle();
- return;
- }
- if (settingsModalLoader) {
- _settingsPendingTab = tabName;
- _settingsWantsToggle = true;
- _settingsWantsOpen = false;
- settingsModalLoader.activeAsync = true;
- }
- }
-
- function focusOrToggleSettings() {
- if (settingsModal?.visible) {
- const settingsTitle = I18n.tr("Settings", "settings window title");
- for (const toplevel of ToplevelManager.toplevels.values) {
- if (toplevel.title !== "Settings" && toplevel.title !== settingsTitle)
- continue;
- if (toplevel.activated) {
- settingsModal.hide();
- return;
- }
- toplevel.activate();
- return;
- }
- }
- openSettings();
- }
-
- function focusOrToggleSettingsWithTab(tabName: string) {
- if (settingsModal?.visible) {
- const settingsTitle = I18n.tr("Settings", "settings window title");
- for (const toplevel of ToplevelManager.toplevels.values) {
- if (toplevel.title !== "Settings" && toplevel.title !== settingsTitle)
- continue;
- if (toplevel.activated) {
- settingsModal.hide();
- return;
- }
- var idx = settingsModal.resolveTabIndex(tabName);
- if (idx >= 0)
- settingsModal.currentTabIndex = idx;
- toplevel.activate();
- return;
- }
- }
- openSettingsWithTab(tabName);
- }
-
- function unloadSettings() {
- if (settingsModalLoader) {
- settingsModal = null;
- settingsModalLoader.active = false;
- }
- }
-
- function _onSettingsModalLoaded() {
- if (_settingsWantsOpen) {
- _settingsWantsOpen = false;
- if (_settingsPendingTabIndex >= 0) {
- settingsModal?.showWithTab(_settingsPendingTabIndex);
- _settingsPendingTabIndex = -1;
- } else if (_settingsPendingTab) {
- settingsModal?.showWithTabName(_settingsPendingTab);
- _settingsPendingTab = "";
- } else {
- settingsModal?.show();
- }
- return;
- }
- if (_settingsWantsToggle) {
- _settingsWantsToggle = false;
- if (_settingsPendingTabIndex >= 0) {
- settingsModal.currentTabIndex = _settingsPendingTabIndex;
- _settingsPendingTabIndex = -1;
- } else if (_settingsPendingTab) {
- var idx = settingsModal?.resolveTabIndex(_settingsPendingTab) ?? -1;
- if (idx >= 0)
- settingsModal.currentTabIndex = idx;
- _settingsPendingTab = "";
- }
- settingsModal?.toggle();
- }
- }
-
- function openClipboardHistory() {
- clipboardHistoryModal?.show();
- }
-
- function closeClipboardHistory() {
- clipboardHistoryModal?.close();
- }
-
- function unloadClipboardHistoryPopout() {
- if (!clipboardHistoryPopoutLoader)
- return;
- clipboardHistoryPopout = null;
- clipboardHistoryPopoutLoader.active = false;
- }
-
- function unloadLayoutPopout() {
- if (!layoutPopoutLoader)
- return;
- layoutPopout = null;
- layoutPopoutLoader.active = false;
- }
-
- property bool _dankLauncherV2WantsOpen: false
- property bool _dankLauncherV2WantsToggle: false
- property string _dankLauncherV2PendingQuery: ""
- property string _dankLauncherV2PendingMode: ""
-
- function openDankLauncherV2() {
- if (dankLauncherV2Modal) {
- dankLauncherV2Modal.show();
- } else if (dankLauncherV2ModalLoader) {
- _dankLauncherV2WantsOpen = true;
- _dankLauncherV2WantsToggle = false;
- dankLauncherV2ModalLoader.active = true;
- }
- }
-
- function openDankLauncherV2WithQuery(query: string) {
- if (dankLauncherV2Modal) {
- dankLauncherV2Modal.showWithQuery(query);
- } else if (dankLauncherV2ModalLoader) {
- _dankLauncherV2PendingQuery = query;
- _dankLauncherV2WantsOpen = true;
- _dankLauncherV2WantsToggle = false;
- dankLauncherV2ModalLoader.active = true;
- }
- }
-
- function openDankLauncherV2WithMode(mode: string) {
- if (dankLauncherV2Modal) {
- dankLauncherV2Modal.showWithMode(mode);
- } else if (dankLauncherV2ModalLoader) {
- _dankLauncherV2PendingMode = mode;
- _dankLauncherV2WantsOpen = true;
- _dankLauncherV2WantsToggle = false;
- dankLauncherV2ModalLoader.active = true;
- }
- }
-
- function closeDankLauncherV2() {
- dankLauncherV2Modal?.hide();
- }
-
- function unloadDankLauncherV2() {
- if (dankLauncherV2ModalLoader) {
- dankLauncherV2Modal = null;
- dankLauncherV2ModalLoader.active = false;
- }
- }
-
- function toggleDankLauncherV2() {
- if (dankLauncherV2Modal) {
- dankLauncherV2Modal.toggle();
- } else if (dankLauncherV2ModalLoader) {
- _dankLauncherV2WantsToggle = true;
- _dankLauncherV2WantsOpen = false;
- dankLauncherV2ModalLoader.active = true;
- }
- }
-
- function toggleDankLauncherV2WithMode(mode: string) {
- if (dankLauncherV2Modal) {
- dankLauncherV2Modal.toggleWithMode(mode);
- } else if (dankLauncherV2ModalLoader) {
- _dankLauncherV2PendingMode = mode;
- _dankLauncherV2WantsToggle = true;
- _dankLauncherV2WantsOpen = false;
- dankLauncherV2ModalLoader.active = true;
- }
- }
-
- function toggleDankLauncherV2WithQuery(query: string) {
- if (dankLauncherV2Modal) {
- dankLauncherV2Modal.toggleWithQuery(query);
- } else if (dankLauncherV2ModalLoader) {
- _dankLauncherV2PendingQuery = query;
- _dankLauncherV2WantsOpen = true;
- _dankLauncherV2WantsToggle = false;
- dankLauncherV2ModalLoader.active = true;
- }
- }
-
- function _onDankLauncherV2ModalLoaded() {
- if (_dankLauncherV2WantsOpen) {
- _dankLauncherV2WantsOpen = false;
- if (_dankLauncherV2PendingQuery) {
- dankLauncherV2Modal?.showWithQuery(_dankLauncherV2PendingQuery);
- _dankLauncherV2PendingQuery = "";
- } else if (_dankLauncherV2PendingMode) {
- dankLauncherV2Modal?.showWithMode(_dankLauncherV2PendingMode);
- _dankLauncherV2PendingMode = "";
- } else {
- dankLauncherV2Modal?.show();
- }
- return;
- }
- if (_dankLauncherV2WantsToggle) {
- _dankLauncherV2WantsToggle = false;
- if (_dankLauncherV2PendingMode) {
- dankLauncherV2Modal?.toggleWithMode(_dankLauncherV2PendingMode);
- _dankLauncherV2PendingMode = "";
- } else {
- dankLauncherV2Modal?.toggle();
- }
- }
- }
-
- function openPowerMenu() {
- powerMenuModal?.openCentered();
- }
-
- function closePowerMenu() {
- powerMenuModal?.close();
- }
-
- function togglePowerMenu() {
- if (powerMenuModal) {
- if (powerMenuModal.shouldBeVisible) {
- powerMenuModal.close();
- } else {
- powerMenuModal.openCentered();
- }
- }
- }
-
- function showProcessListModal() {
- if (processListModal) {
- processListModal.show();
- } else if (processListModalLoader) {
- processListModalLoader.active = true;
- Qt.callLater(() => processListModal?.show());
- }
- }
-
- function hideProcessListModal() {
- processListModal?.hide();
- }
-
- function toggleProcessListModal() {
- if (processListModal) {
- processListModal.toggle();
- } else if (processListModalLoader) {
- processListModalLoader.active = true;
- Qt.callLater(() => processListModal?.show());
- }
- }
-
- function showColorPicker() {
- colorPickerModal?.show();
- }
-
- function hideColorPicker() {
- colorPickerModal?.close();
- }
-
- function showNotificationModal() {
- notificationModal?.show();
- }
-
- function hideNotificationModal() {
- notificationModal?.close();
- }
-
- function showWifiPasswordModal(ssid) {
- if (wifiPasswordModalLoader)
- wifiPasswordModalLoader.active = true;
- if (wifiPasswordModal)
- wifiPasswordModal.show(ssid);
- }
-
- function showWifiQRCodeModal(ssid) {
- if (wifiQRCodeModalLoader)
- wifiQRCodeModalLoader.active = true;
- if (wifiQRCodeModal)
- wifiQRCodeModal.show(ssid);
- }
-
- function showHiddenNetworkModal() {
- if (wifiPasswordModalLoader)
- wifiPasswordModalLoader.active = true;
- if (wifiPasswordModal)
- wifiPasswordModal.showHidden();
- }
-
- function hideWifiPasswordModal() {
- wifiPasswordModal?.hide();
- }
-
- function showNetworkInfoModal() {
- networkInfoModal?.show();
- }
-
- function hideNetworkInfoModal() {
- networkInfoModal?.close();
- }
-
- function openNotepad() {
- if (notepadSlideouts.length > 0) {
- notepadSlideouts[0]?.show();
- }
- }
-
- function closeNotepad() {
- if (notepadSlideouts.length > 0) {
- notepadSlideouts[0]?.hide();
- }
- }
-
- function toggleNotepad() {
- if (notepadSlideouts.length > 0) {
- notepadSlideouts[0]?.toggle();
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PortalService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PortalService.qml
deleted file mode 100644
index 73c0a9f..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PortalService.qml
+++ /dev/null
@@ -1,316 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- property bool accountsServiceAvailable: false
- property string systemProfileImage: ""
- property string profileImage: ""
- property bool settingsPortalAvailable: false
- property int systemColorScheme: 0
-
- property bool freedeskAvailable: false
- property string colorSchemeCommand: ""
- property string pendingProfileImage: ""
-
- readonly property string socketPath: Quickshell.env("DMS_SOCKET")
-
- function init() {
- }
-
- function getSystemProfileImage() {
- if (!freedeskAvailable)
- return;
- const username = Quickshell.env("USER");
- if (!username)
- return;
- DMSService.sendRequest("freedesktop.accounts.getUserIconFile", {
- "username": username
- }, response => {
- if (response.result && response.result.success) {
- const iconFile = response.result.value || "";
- if (iconFile && iconFile !== "" && iconFile !== "/var/lib/AccountsService/icons/") {
- systemProfileImage = iconFile;
- if (!profileImage || profileImage === "") {
- profileImage = iconFile;
- }
- }
- }
- });
- }
-
- function getUserProfileImage(username) {
- if (!username) {
- profileImage = "";
- return;
- }
- if (Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true") {
- profileImage = "";
- return;
- }
-
- if (!freedeskAvailable) {
- profileImage = "";
- return;
- }
-
- DMSService.sendRequest("freedesktop.accounts.getUserIconFile", {
- "username": username
- }, response => {
- if (response.result && response.result.success) {
- const icon = response.result.value || "";
- if (icon && icon !== "" && icon !== "/var/lib/AccountsService/icons/") {
- profileImage = icon;
- } else {
- profileImage = "";
- }
- } else {
- profileImage = "";
- }
- });
- }
-
- function setProfileImage(imagePath) {
- if (accountsServiceAvailable) {
- pendingProfileImage = imagePath;
- setSystemProfileImage(imagePath || "");
- } else {
- profileImage = imagePath;
- }
- }
-
- function getSystemColorScheme() {
- if (typeof SettingsData !== "undefined" && SettingsData.syncModeWithPortal === false) {
- return;
- }
- if (!freedeskAvailable)
- return;
- DMSService.sendRequest("freedesktop.settings.getColorScheme", null, response => {
- if (response.result) {
- systemColorScheme = response.result.value || 0;
- }
- });
- }
-
- function setLightMode(isLightMode) {
- if (typeof SettingsData !== "undefined" && SettingsData.syncModeWithPortal === false) {
- return;
- }
- setSystemColorScheme(isLightMode);
- }
-
- function setSystemColorScheme(isLightMode) {
- if (typeof SettingsData !== "undefined" && SettingsData.syncModeWithPortal === false) {
- return;
- }
-
- const targetScheme = isLightMode ? "default" : "prefer-dark";
-
- if (colorSchemeCommand === "gsettings") {
- Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", targetScheme]);
- }
- if (colorSchemeCommand === "dconf") {
- Quickshell.execDetached(["dconf", "write", "/org/gnome/desktop/interface/color-scheme", `'${targetScheme}'`]);
- }
- }
-
- function setSystemIconTheme(themeName) {
- if (!settingsPortalAvailable || !freedeskAvailable)
- return;
- DMSService.sendRequest("freedesktop.settings.setIconTheme", {
- "iconTheme": themeName
- }, response => {
- if (response.error) {
- console.warn("PortalService: Failed to set icon theme:", response.error);
- }
- });
- }
-
- function setSystemProfileImage(imagePath) {
- if (!accountsServiceAvailable || !freedeskAvailable)
- return;
- DMSService.sendRequest("freedesktop.accounts.setIconFile", {
- "path": imagePath || ""
- }, response => {
- if (response.error) {
- console.warn("PortalService: Failed to set icon file:", response.error);
-
- const errorMsg = response.error.toString();
- let userMessage = I18n.tr("Failed to set profile image");
-
- if (errorMsg.includes("too large")) {
- userMessage = I18n.tr("Profile image is too large. Please use a smaller image.");
- } else if (errorMsg.includes("permission")) {
- userMessage = I18n.tr("Permission denied to set profile image.");
- } else if (errorMsg.includes("not found") || errorMsg.includes("does not exist")) {
- userMessage = I18n.tr("Selected image file not found.");
- } else {
- userMessage = I18n.tr("Failed to set profile image: %1").arg(errorMsg.split(":").pop().trim());
- }
-
- Quickshell.execDetached(["notify-send", "-u", "normal", "-a", "DMS", "-i", "error", I18n.tr("Profile Image Error"), userMessage]);
-
- pendingProfileImage = "";
- } else {
- profileImage = pendingProfileImage;
- pendingProfileImage = "";
- Qt.callLater(() => getSystemProfileImage());
- }
- });
- }
-
- Component.onCompleted: {
- if (socketPath && socketPath.length > 0) {
- checkDMSCapabilities();
- } else {
- console.info("PortalService: DMS_SOCKET not set");
- }
- colorSchemeDetector.running = true;
- }
-
- Connections {
- target: DMSService
-
- function onConnectionStateChanged() {
- if (DMSService.isConnected) {
- checkDMSCapabilities();
- }
- }
- }
-
- Connections {
- target: DMSService
- enabled: DMSService.isConnected
-
- function onCapabilitiesChanged() {
- checkDMSCapabilities();
- }
- }
-
- function checkDMSCapabilities() {
- if (!DMSService.isConnected) {
- return;
- }
-
- if (DMSService.capabilities.length === 0) {
- return;
- }
-
- freedeskAvailable = DMSService.capabilities.includes("freedesktop");
- if (freedeskAvailable) {
- checkAccountsService();
- checkSettingsPortal();
- } else {
- console.info("PortalService: freedesktop capability not available in DMS");
- }
- }
-
- function checkAccountsService() {
- if (!freedeskAvailable)
- return;
- DMSService.sendRequest("freedesktop.getState", null, response => {
- if (response.result && response.result.accounts) {
- accountsServiceAvailable = response.result.accounts.available || false;
- if (accountsServiceAvailable) {
- getSystemProfileImage();
- }
- }
- });
- }
-
- function checkSettingsPortal() {
- if (!freedeskAvailable)
- return;
- DMSService.sendRequest("freedesktop.getState", null, response => {
- if (response.result && response.result.settings) {
- settingsPortalAvailable = response.result.settings.available || false;
- if (settingsPortalAvailable && SettingsData.syncModeWithPortal) {
- getSystemColorScheme();
- }
- }
- });
- }
-
- function getGreeterUserProfileImage(username) {
- if (!username) {
- profileImage = "";
- return;
- }
- userProfileCheckProcess.command = ["bash", "-c", `uid=$(id -u ${username} 2>/dev/null) && [ -n "$uid" ] && dbus-send --system --print-reply --dest=org.freedesktop.Accounts /org/freedesktop/Accounts/User$uid org.freedesktop.DBus.Properties.Get string:org.freedesktop.Accounts.User string:IconFile 2>/dev/null | grep -oP 'string "\\K[^"]+' || echo ""`];
- userProfileCheckProcess.running = true;
- }
-
- Process {
- id: userProfileCheckProcess
- command: []
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const trimmed = text.trim();
- if (trimmed && trimmed !== "" && !trimmed.includes("Error") && trimmed !== "/var/lib/AccountsService/icons/") {
- root.profileImage = trimmed;
- } else {
- root.profileImage = "";
- }
- }
- }
-
- onExited: exitCode => {
- if (exitCode !== 0) {
- root.profileImage = "";
- }
- }
- }
-
- Process {
- id: colorSchemeDetector
- command: ["bash", "-c", "command -v gsettings || command -v dconf"]
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const cmd = text.trim();
- if (cmd.includes("gsettings")) {
- root.colorSchemeCommand = "gsettings";
- } else if (cmd.includes("dconf")) {
- root.colorSchemeCommand = "dconf";
- }
- }
- }
- }
-
- IpcHandler {
- target: "profile"
-
- function getImage(): string {
- return root.profileImage;
- }
-
- function setImage(path: string): string {
- if (!path) {
- return "ERROR: No path provided";
- }
-
- const absolutePath = path.startsWith("/") ? path : `${StandardPaths.writableLocation(StandardPaths.HomeLocation)}/${path}`;
-
- try {
- root.setProfileImage(absolutePath);
- return "SUCCESS: Profile image set to " + absolutePath;
- } catch (e) {
- return "ERROR: Failed to set profile image: " + e.toString();
- }
- }
-
- function clearImage(): string {
- root.setProfileImage("");
- return "SUCCESS: Profile image cleared";
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PowerProfileWatcher.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PowerProfileWatcher.qml
deleted file mode 100644
index bab3517..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PowerProfileWatcher.qml
+++ /dev/null
@@ -1,36 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Services.UPower
-
-Singleton {
- id: root
-
- property int currentProfile: -1
- property int previousProfile: -1
-
- signal profileChanged(int profile)
-
- Connections {
- target: typeof PowerProfiles !== "undefined" ? PowerProfiles : null
-
- function onProfileChanged() {
- if (typeof PowerProfiles !== "undefined") {
- root.previousProfile = root.currentProfile;
- root.currentProfile = PowerProfiles.profile;
- if (root.previousProfile !== -1) {
- root.profileChanged(root.currentProfile);
- }
- }
- }
- }
-
- Component.onCompleted: {
- if (typeof PowerProfiles !== "undefined") {
- root.currentProfile = PowerProfiles.profile;
- root.previousProfile = PowerProfiles.profile;
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PrivacyService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PrivacyService.qml
deleted file mode 100644
index 4908862..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/PrivacyService.qml
+++ /dev/null
@@ -1,155 +0,0 @@
-pragma Singleton
-
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import Quickshell.Services.Pipewire
-import qs.Services
-
-Singleton {
- id: root
-
- readonly property bool microphoneActive: {
- if (!Pipewire.ready || !Pipewire.nodes?.values) {
- return false
- }
-
- for (let i = 0; i < Pipewire.nodes.values.length; i++) {
- const node = Pipewire.nodes.values[i]
- if (!node) {
- continue
- }
-
- if ((node.type & PwNodeType.AudioInStream) === PwNodeType.AudioInStream) {
- if (!looksLikeSystemVirtualMic(node)) {
- if (node.audio && node.audio.muted) {
- return false
- }
- return true
- }
- }
- }
- return false
- }
-
- PwObjectTracker {
- objects: Pipewire.nodes.values.filter(node => !node.isStream)
- }
-
- readonly property bool cameraActive: {
- if (!Pipewire.ready || !Pipewire.nodes?.values) {
- return false
- }
-
- for (let i = 0; i < Pipewire.nodes.values.length; i++) {
- const node = Pipewire.nodes.values[i]
- if (!node || !node.ready) {
- continue
- }
-
- if (node.properties && node.properties["media.class"] === "Stream/Input/Video") {
- if (node.properties["stream.is-live"] === "true") {
- return true
- }
- }
- }
- return false
- }
-
- readonly property bool screensharingActive: {
- if (CompositorService.isNiri && NiriService.hasActiveCast) {
- return true
- }
-
- if (!Pipewire.ready || !Pipewire.nodes?.values) {
- return false
- }
-
- for (let i = 0; i < Pipewire.nodes.values.length; i++) {
- const node = Pipewire.nodes.values[i]
- if (!node || !node.ready) {
- continue
- }
-
- if ((node.type & PwNodeType.VideoSource) === PwNodeType.VideoSource) {
- if (looksLikeScreencast(node)) {
- return true
- }
- }
-
- if (node.properties && node.properties["media.class"] === "Stream/Output/Video") {
- if (looksLikeScreencast(node)) {
- return true
- }
- }
-
- if (node.properties && node.properties["media.class"] === "Stream/Input/Audio") {
- const mediaName = (node.properties["media.name"] || "").toLowerCase()
- const appName = (node.properties["application.name"] || "").toLowerCase()
-
- if (mediaName.includes("desktop") || appName.includes("screen") || appName === "obs") {
- if (node.properties["stream.is-live"] === "true") {
- if (node.audio && node.audio.muted) {
- return false
- }
- return true
- }
- }
- }
- }
- return false
- }
-
- readonly property bool anyPrivacyActive: microphoneActive || cameraActive || screensharingActive
-
- function looksLikeSystemVirtualMic(node) {
- if (!node) {
- return false
- }
- const name = (node.name || "").toLowerCase()
- const mediaName = (node.properties && node.properties["media.name"] || "").toLowerCase()
- const appName = (node.properties && node.properties["application.name"] || "").toLowerCase()
- const combined = name + " " + mediaName + " " + appName
- return /cava|monitor|system/.test(combined)
- }
-
- function looksLikeScreencast(node) {
- if (!node) {
- return false
- }
- const appName = (node.properties && node.properties["application.name"] || "").toLowerCase()
- const nodeName = (node.name || "").toLowerCase()
- const mediaName = (node.properties && node.properties["media.name"] || "").toLowerCase()
- const combined = appName + " " + nodeName + " " + mediaName
- return /xdg-desktop-portal|xdpw|screencast|screen-cast|screen|gnome shell|kwin|obs|niri/.test(combined)
- }
-
- function getMicrophoneStatus() {
- return microphoneActive ? "active" : "inactive"
- }
-
- function getCameraStatus() {
- return cameraActive ? "active" : "inactive"
- }
-
- function getScreensharingStatus() {
- return screensharingActive ? "active" : "inactive"
- }
-
- function getPrivacySummary() {
- const active = []
- if (microphoneActive) {
- active.push("microphone")
- }
- if (cameraActive) {
- active.push("camera")
- }
- if (screensharingActive) {
- active.push("screensharing")
- }
-
- return active.length > 0 ? `Privacy active: ${active.join(", ")}` : "No privacy concerns detected"
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/SessionService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/SessionService.qml
deleted file mode 100644
index 7f5a1ed..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/SessionService.qml
+++ /dev/null
@@ -1,619 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import Quickshell.Hyprland
-import Quickshell.I3
-import Quickshell.Wayland
-import qs.Common
-
-Singleton {
- id: root
-
- property bool hasUwsm: false
- property bool isElogind: false
- property bool hibernateSupported: false
- property bool inhibitorAvailable: true
- property bool idleInhibited: false
- property string inhibitReason: "Keep system awake"
- property string nvidiaCommand: ""
-
- readonly property bool nativeInhibitorAvailable: {
- try {
- return typeof IdleInhibitor !== "undefined";
- } catch (e) {
- return false;
- }
- }
-
- property bool loginctlAvailable: false
- property bool wtypeAvailable: false
- property string sessionId: ""
- property string sessionPath: ""
- property bool locked: false
- property bool active: false
- property bool idleHint: false
- property bool lockedHint: false
- property bool preparingForSleep: false
- property string sessionType: ""
- property string userName: ""
- property string seat: ""
- property string display: ""
-
- signal sessionLocked
- signal sessionUnlocked
- signal sessionResumed
- signal loginctlStateChanged
-
- property bool stateInitialized: false
-
- readonly property string socketPath: Quickshell.env("DMS_SOCKET")
-
- Timer {
- id: sessionInitTimer
- interval: 200
- running: true
- repeat: false
- onTriggered: {
- detectElogindProcess.running = true;
- detectHibernateProcess.running = true;
- detectPrimeRunProcess.running = true;
- detectWtypeProcess.running = true;
- console.info("SessionService: Native inhibitor available:", nativeInhibitorAvailable);
- if (!SettingsData.loginctlLockIntegration) {
- console.log("SessionService: loginctl lock integration disabled by user");
- return;
- }
- if (socketPath && socketPath.length > 0) {
- checkDMSCapabilities();
- } else {
- console.log("SessionService: DMS_SOCKET not set");
- }
- }
- }
-
- Process {
- id: detectUwsmProcess
- running: false
- command: ["which", "uwsm"]
-
- onExited: function (exitCode) {
- hasUwsm = (exitCode === 0);
- }
- }
-
- Process {
- id: detectElogindProcess
- running: false
- command: ["sh", "-c", "ps -eo comm= | grep -E '^(elogind|elogind-daemon)$'"]
-
- onExited: function (exitCode) {
- console.log("SessionService: Elogind detection exited with code", exitCode);
- isElogind = (exitCode === 0);
- }
- }
-
- Process {
- id: detectHibernateProcess
- running: false
- command: ["grep", "-q", "disk", "/sys/power/state"]
-
- onExited: function (exitCode) {
- hibernateSupported = (exitCode === 0);
- }
- }
-
- Process {
- id: hibernateProcess
- running: false
-
- property string errorOutput: ""
-
- stderr: SplitParser {
- splitMarker: "\n"
- onRead: data => hibernateProcess.errorOutput += data.trim()
- }
-
- onExited: function (exitCode) {
- if (exitCode === 0) {
- errorOutput = "";
- return;
- }
- ToastService.showError("Hibernate failed", errorOutput);
- errorOutput = "";
- }
- }
-
- Process {
- id: detectWtypeProcess
- running: false
- command: ["which", "wtype"]
- onExited: exitCode => {
- wtypeAvailable = (exitCode === 0);
- }
- }
-
- Process {
- id: detectPrimeRunProcess
- running: false
- command: ["which", "prime-run"]
-
- onExited: function (exitCode) {
- if (exitCode === 0) {
- nvidiaCommand = "prime-run";
- } else {
- detectNvidiaOffloadProcess.running = true;
- }
- }
- }
-
- Process {
- id: detectNvidiaOffloadProcess
- running: false
- command: ["which", "nvidia-offload"]
-
- onExited: function (exitCode) {
- if (exitCode === 0) {
- nvidiaCommand = "nvidia-offload";
- }
- }
- }
-
- Process {
- id: uwsmLogout
- command: ["uwsm", "stop"]
- running: false
-
- stdout: SplitParser {
- splitMarker: "\n"
- onRead: data => {
- if (data.trim().toLowerCase().includes("not running")) {
- _logout();
- }
- }
- }
-
- onExited: function (exitCode) {
- if (exitCode === 0) {
- return;
- }
- _logout();
- }
- }
-
- function escapeShellArg(arg) {
- return "'" + arg.replace(/'/g, "'\\''") + "'";
- }
-
- function needsShellExecution(prefix) {
- if (!prefix || prefix.length === 0)
- return false;
- return /[;&|<>()$`\\"']/.test(prefix);
- }
-
- function parseEnvVars(envVarsStr) {
- if (!envVarsStr || envVarsStr.trim().length === 0)
- return {};
- const envObj = {};
- const pairs = envVarsStr.trim().split(/\s+/);
- for (const pair of pairs) {
- const eqIndex = pair.indexOf("=");
- if (eqIndex > 0) {
- const key = pair.substring(0, eqIndex);
- const value = pair.substring(eqIndex + 1);
- envObj[key] = value;
- }
- }
- return envObj;
- }
-
- function launchDesktopEntry(desktopEntry, useNvidia) {
- let cmd = desktopEntry.command;
-
- const appId = desktopEntry.id || desktopEntry.execString || desktopEntry.exec || "";
- const override = SessionData.getAppOverride(appId);
-
- const dgpu = useNvidia || (override?.launchOnDgpu && nvidiaCommand);
- if (dgpu && nvidiaCommand)
- cmd = [nvidiaCommand].concat(cmd);
-
- if (override?.extraFlags) {
- const extraArgs = override.extraFlags.trim().split(/\s+/).filter(arg => arg.length > 0);
- cmd = cmd.concat(extraArgs);
- }
-
- const userPrefix = SettingsData.launchPrefix?.trim() || "";
- const defaultPrefix = Quickshell.env("DMS_DEFAULT_LAUNCH_PREFIX") || "";
- const prefix = userPrefix.length > 0 ? userPrefix : defaultPrefix;
- const workDir = desktopEntry.workingDirectory || Quickshell.env("HOME");
- const cursorEnv = typeof SettingsData.getCursorEnvironment === "function" ? SettingsData.getCursorEnvironment() : {};
-
- const overrideEnv = override?.envVars ? parseEnvVars(override.envVars) : {};
- const finalEnv = Object.assign({}, cursorEnv, overrideEnv);
-
- if (desktopEntry.runInTerminal) {
- const terminal = Quickshell.env("TERMINAL") || "xterm";
- const escapedCmd = cmd.map(arg => escapeShellArg(arg)).join(" ");
- const shellCmd = prefix.length > 0 ? `${prefix} ${escapedCmd}` : escapedCmd;
- Quickshell.execDetached({
- command: [terminal, "-e", "sh", "-c", shellCmd],
- workingDirectory: workDir,
- environment: finalEnv
- });
- return;
- }
-
- if (prefix.length > 0 && needsShellExecution(prefix)) {
- const escapedCmd = cmd.map(arg => escapeShellArg(arg)).join(" ");
- Quickshell.execDetached({
- command: ["sh", "-c", `${prefix} ${escapedCmd}`],
- workingDirectory: workDir,
- environment: finalEnv
- });
- return;
- }
-
- if (prefix.length > 0)
- cmd = prefix.split(" ").concat(cmd);
-
- Quickshell.execDetached({
- command: cmd,
- workingDirectory: workDir,
- environment: finalEnv
- });
- }
-
- function launchDesktopAction(desktopEntry, action, useNvidia) {
- let cmd = action.command;
-
- const appId = desktopEntry.id || desktopEntry.execString || desktopEntry.exec || "";
- const override = SessionData.getAppOverride(appId);
- const dgpu = useNvidia || (override?.launchOnDgpu && nvidiaCommand);
- if (dgpu && nvidiaCommand)
- cmd = [nvidiaCommand].concat(cmd);
-
- const userPrefix = SettingsData.launchPrefix?.trim() || "";
- const defaultPrefix = Quickshell.env("DMS_DEFAULT_LAUNCH_PREFIX") || "";
- const prefix = userPrefix.length > 0 ? userPrefix : defaultPrefix;
- const workDir = desktopEntry.workingDirectory || Quickshell.env("HOME");
- const cursorEnv = typeof SettingsData.getCursorEnvironment === "function" ? SettingsData.getCursorEnvironment() : {};
-
- if (prefix.length > 0 && needsShellExecution(prefix)) {
- const escapedCmd = cmd.map(arg => escapeShellArg(arg)).join(" ");
- Quickshell.execDetached({
- command: ["sh", "-c", `${prefix} ${escapedCmd}`],
- workingDirectory: workDir,
- environment: cursorEnv
- });
- return;
- }
-
- if (prefix.length > 0)
- cmd = prefix.split(" ").concat(cmd);
-
- Quickshell.execDetached({
- command: cmd,
- workingDirectory: workDir,
- environment: cursorEnv
- });
- }
-
- // * Session management
- function logout() {
- if (hasUwsm) {
- uwsmLogout.running = true;
- }
- _logout();
- }
-
- function _logout() {
- if (SettingsData.customPowerActionLogout.length === 0) {
- if (CompositorService.isNiri) {
- NiriService.quit();
- return;
- }
-
- if (CompositorService.isDwl) {
- DwlService.quit();
- return;
- }
-
- if (CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) {
- try {
- I3.dispatch("exit");
- } catch (_) {}
- return;
- }
-
- Hyprland.dispatch("exit");
- } else {
- Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionLogout]);
- }
- }
-
- function suspend() {
- if (SettingsData.customPowerActionSuspend.length === 0) {
- Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "suspend"]);
- } else {
- Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionSuspend]);
- }
- }
-
- function hibernate() {
- hibernateProcess.errorOutput = "";
- if (SettingsData.customPowerActionHibernate.length > 0) {
- hibernateProcess.command = ["sh", "-c", SettingsData.customPowerActionHibernate];
- } else {
- hibernateProcess.command = [isElogind ? "loginctl" : "systemctl", "hibernate"];
- }
- hibernateProcess.running = true;
- }
-
- function suspendThenHibernate() {
- Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "suspend-then-hibernate"]);
- }
-
- function suspendWithBehavior(behavior) {
- if (behavior === SettingsData.SuspendBehavior.Hibernate) {
- hibernate();
- } else if (behavior === SettingsData.SuspendBehavior.SuspendThenHibernate) {
- suspendThenHibernate();
- } else {
- suspend();
- }
- }
-
- function reboot() {
- if (SettingsData.customPowerActionReboot.length === 0) {
- Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "reboot"]);
- } else {
- Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionReboot]);
- }
- }
-
- function poweroff() {
- if (SettingsData.customPowerActionPowerOff.length === 0) {
- Quickshell.execDetached([isElogind ? "loginctl" : "systemctl", "poweroff"]);
- } else {
- Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionPowerOff]);
- }
- }
-
- // * Idle Inhibitor
- signal inhibitorChanged
-
- function enableIdleInhibit() {
- if (idleInhibited) {
- return;
- }
- console.log("SessionService: Enabling idle inhibit (native:", nativeInhibitorAvailable, ")");
- idleInhibited = true;
- inhibitorChanged();
- }
-
- function disableIdleInhibit() {
- if (!idleInhibited) {
- return;
- }
- console.log("SessionService: Disabling idle inhibit (native:", nativeInhibitorAvailable, ")");
- idleInhibited = false;
- inhibitorChanged();
- }
-
- function toggleIdleInhibit() {
- if (idleInhibited) {
- disableIdleInhibit();
- } else {
- enableIdleInhibit();
- }
- }
-
- function setInhibitReason(reason) {
- inhibitReason = reason;
-
- if (idleInhibited && !nativeInhibitorAvailable) {
- const wasActive = idleInhibited;
- idleInhibited = false;
-
- Qt.callLater(() => {
- if (wasActive) {
- idleInhibited = true;
- }
- });
- }
- }
-
- Process {
- id: idleInhibitProcess
-
- command: {
- if (!idleInhibited || nativeInhibitorAvailable) {
- return ["true"];
- }
-
- console.log("SessionService: Starting systemd/elogind inhibit process");
- return [isElogind ? "elogind-inhibit" : "systemd-inhibit", "--what=idle", "--who=quickshell", `--why=${inhibitReason}`, "--mode=block", "sleep", "infinity"];
- }
-
- running: idleInhibited && !nativeInhibitorAvailable
-
- onRunningChanged: {
- console.log("SessionService: Inhibit process running:", running, "(native:", nativeInhibitorAvailable, ")");
- }
-
- onExited: function (exitCode) {
- if (idleInhibited && exitCode !== 0 && !nativeInhibitorAvailable) {
- console.warn("SessionService: Inhibitor process crashed with exit code:", exitCode);
- idleInhibited = false;
- ToastService.showWarning("Idle inhibitor failed");
- }
- }
- }
-
- Connections {
- target: DMSService
-
- function onConnectionStateChanged() {
- if (DMSService.isConnected) {
- checkDMSCapabilities();
- }
- }
-
- function onCapabilitiesReceived() {
- syncSleepInhibitor();
- }
- }
-
- Connections {
- target: DMSService
- enabled: DMSService.isConnected
-
- function onCapabilitiesChanged() {
- checkDMSCapabilities();
- }
- }
-
- Connections {
- target: SettingsData
-
- function onLoginctlLockIntegrationChanged() {
- if (SettingsData.loginctlLockIntegration) {
- if (socketPath && socketPath.length > 0 && loginctlAvailable) {
- if (!stateInitialized) {
- stateInitialized = true;
- getLoginctlState();
- syncLockBeforeSuspend();
- }
- }
- } else {
- stateInitialized = false;
- }
- syncSleepInhibitor();
- }
-
- function onLockBeforeSuspendChanged() {
- if (SettingsData.loginctlLockIntegration) {
- syncLockBeforeSuspend();
- }
- syncSleepInhibitor();
- }
- }
-
- Connections {
- target: DMSService
- enabled: SettingsData.loginctlLockIntegration
-
- function onLoginctlStateUpdate(data) {
- updateLoginctlState(data);
- }
-
- function onLoginctlEvent(event) {
- handleLoginctlEvent(event);
- }
- }
-
- function checkDMSCapabilities() {
- if (!DMSService.isConnected) {
- return;
- }
-
- if (DMSService.capabilities.length === 0) {
- return;
- }
-
- if (DMSService.capabilities.includes("loginctl")) {
- loginctlAvailable = true;
- if (SettingsData.loginctlLockIntegration && !stateInitialized) {
- stateInitialized = true;
- getLoginctlState();
- syncLockBeforeSuspend();
- }
- } else {
- loginctlAvailable = false;
- console.log("SessionService: loginctl capability not available in DMS");
- }
- }
-
- function getLoginctlState() {
- if (!loginctlAvailable)
- return;
- DMSService.sendRequest("loginctl.getState", null, response => {
- if (response.result) {
- updateLoginctlState(response.result);
- }
- });
- }
-
- function syncLockBeforeSuspend() {
- if (!loginctlAvailable)
- return;
- DMSService.sendRequest("loginctl.setLockBeforeSuspend", {
- enabled: SettingsData.lockBeforeSuspend
- }, response => {
- if (response.error) {
- console.warn("SessionService: Failed to sync lock before suspend:", response.error);
- } else {
- console.log("SessionService: Synced lock before suspend:", SettingsData.lockBeforeSuspend);
- }
- });
- }
-
- function syncSleepInhibitor() {
- if (!loginctlAvailable)
- return;
- if (!DMSService.apiVersion || DMSService.apiVersion < 4)
- return;
- DMSService.sendRequest("loginctl.setSleepInhibitorEnabled", {
- enabled: SettingsData.loginctlLockIntegration && SettingsData.lockBeforeSuspend
- }, response => {
- if (response.error) {
- console.warn("SessionService: Failed to sync sleep inhibitor:", response.error);
- } else {
- console.log("SessionService: Synced sleep inhibitor:", SettingsData.loginctlLockIntegration);
- }
- });
- }
-
- function updateLoginctlState(state) {
- const wasLocked = locked;
- const wasSleeping = preparingForSleep;
-
- sessionId = state.sessionId || "";
- sessionPath = state.sessionPath || "";
- locked = state.locked || false;
- active = state.active || false;
- idleHint = state.idleHint || false;
- lockedHint = state.lockedHint || false;
- preparingForSleep = state.preparingForSleep || false;
- sessionType = state.sessionType || "";
- userName = state.userName || "";
- seat = state.seat || "";
- display = state.display || "";
-
- if (locked && !wasLocked) {
- sessionLocked();
- } else if (!locked && wasLocked) {
- sessionUnlocked();
- }
-
- if (wasSleeping && !preparingForSleep) {
- sessionResumed();
- }
-
- loginctlStateChanged();
- }
-
- function handleLoginctlEvent(event) {
- if (event.event === "Lock") {
- locked = true;
- lockedHint = true;
- sessionLocked();
- } else if (event.event === "Unlock") {
- locked = false;
- lockedHint = false;
- sessionUnlocked();
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/SettingsSearchService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/SettingsSearchService.qml
deleted file mode 100644
index 97e5d11..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/SettingsSearchService.qml
+++ /dev/null
@@ -1,240 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- property string query: ""
- property var results: []
- property string targetSection: ""
- property string highlightSection: ""
- property var registeredCards: ({})
- property var settingsIndex: []
- property bool indexLoaded: false
- property var _translatedCache: []
-
- readonly property var conditionMap: ({
- "isNiri": () => CompositorService.isNiri,
- "isHyprland": () => CompositorService.isHyprland,
- "isDwl": () => CompositorService.isDwl,
- "keybindsAvailable": () => KeybindsService.available,
- "soundsAvailable": () => AudioService.soundsAvailable,
- "cupsAvailable": () => CupsService.cupsAvailable,
- "networkNotLegacy": () => !NetworkService.usingLegacy,
- "dmsConnected": () => DMSService.isConnected && DMSService.apiVersion >= 23,
- "matugenAvailable": () => Theme.matugenAvailable
- })
-
- Component.onCompleted: indexFile.reload()
-
- FileView {
- id: indexFile
- path: Qt.resolvedUrl("../translations/settings_search_index.json")
- onLoaded: {
- try {
- root.settingsIndex = JSON.parse(text());
- root.indexLoaded = true;
- root._rebuildTranslationCache();
- } catch (e) {
- console.warn("SettingsSearchService: Failed to parse index:", e);
- root.settingsIndex = [];
- root._translatedCache = [];
- }
- }
- onLoadFailed: error => console.warn("SettingsSearchService: Failed to load index:", error)
- }
-
- function registerCard(settingKey, item, flickable) {
- if (!settingKey)
- return;
- registeredCards[settingKey] = {
- item: item,
- flickable: flickable
- };
- if (targetSection === settingKey)
- scrollTimer.restart();
- }
-
- function unregisterCard(settingKey) {
- if (!settingKey)
- return;
- let cards = registeredCards;
- delete cards[settingKey];
- registeredCards = cards;
- }
-
- function navigateToSection(section) {
- targetSection = section;
- if (registeredCards[section])
- scrollTimer.restart();
- }
-
- function scrollToTarget() {
- if (!targetSection)
- return;
- const entry = registeredCards[targetSection];
- if (!entry || !entry.item || !entry.flickable)
- return;
- const flickable = entry.flickable;
- const item = entry.item;
- const contentItem = flickable.contentItem;
-
- if (!contentItem)
- return;
- const mapped = item.mapToItem(contentItem, 0, 0);
- const maxY = Math.max(0, flickable.contentHeight - flickable.height);
- const targetY = Math.min(maxY, Math.max(0, mapped.y - 16));
- flickable.contentY = targetY;
-
- highlightSection = targetSection;
- targetSection = "";
- highlightTimer.restart();
- }
-
- function clearHighlight() {
- highlightSection = "";
- }
-
- Timer {
- id: scrollTimer
- interval: 50
- onTriggered: root.scrollToTarget()
- }
-
- Timer {
- id: highlightTimer
- interval: 2500
- onTriggered: root.highlightSection = ""
- }
-
- function checkCondition(item) {
- if (!item.conditionKey)
- return true;
- const condFn = conditionMap[item.conditionKey];
- if (!condFn)
- return true;
- return condFn();
- }
-
- function translateItem(item) {
- return {
- section: item.section,
- label: I18n.tr(item.label),
- tabIndex: item.tabIndex,
- category: I18n.tr(item.category),
- keywords: item.keywords || [],
- icon: item.icon || "settings",
- description: item.description ? I18n.tr(item.description) : "",
- conditionKey: item.conditionKey
- };
- }
-
- function _rebuildTranslationCache() {
- var cache = [];
- for (var i = 0; i < settingsIndex.length; i++) {
- var item = settingsIndex[i];
- var t = translateItem(item);
- cache.push({
- section: t.section,
- label: t.label,
- tabIndex: t.tabIndex,
- category: t.category,
- keywords: t.keywords,
- icon: t.icon,
- description: t.description,
- conditionKey: t.conditionKey,
- labelLower: t.label.toLowerCase(),
- categoryLower: t.category.toLowerCase()
- });
- }
- _translatedCache = cache;
- }
-
- function search(text) {
- query = text;
- if (!text) {
- results = [];
- return;
- }
-
- var queryLower = text.toLowerCase().trim();
- var queryWords = queryLower.split(/\s+/).filter(w => w.length > 0);
- var scored = [];
- var cache = _translatedCache;
-
- for (var i = 0; i < cache.length; i++) {
- var entry = cache[i];
- if (!checkCondition(entry))
- continue;
-
- var labelLower = entry.labelLower;
- var categoryLower = entry.categoryLower;
- var score = 0;
-
- if (labelLower === queryLower) {
- score = 10000;
- } else if (labelLower.startsWith(queryLower)) {
- score = 5000;
- } else if (labelLower.includes(queryLower)) {
- score = 1000;
- } else if (categoryLower.includes(queryLower)) {
- score = 500;
- }
-
- if (score === 0) {
- var keywords = entry.keywords;
- for (var k = 0; k < keywords.length; k++) {
- if (keywords[k].startsWith(queryLower)) {
- score = 800;
- break;
- }
- if (keywords[k].includes(queryLower) && score < 400) {
- score = 400;
- }
- }
- }
-
- if (score === 0 && queryWords.length > 1) {
- var allMatch = true;
- for (var w = 0; w < queryWords.length; w++) {
- var word = queryWords[w];
- if (labelLower.includes(word))
- continue;
- var inKeywords = false;
- for (var k = 0; k < entry.keywords.length; k++) {
- if (entry.keywords[k].includes(word)) {
- inKeywords = true;
- break;
- }
- }
- if (!inKeywords && !categoryLower.includes(word)) {
- allMatch = false;
- break;
- }
- }
- if (allMatch)
- score = 300;
- }
-
- if (score > 0) {
- scored.push({
- item: entry,
- score: score
- });
- }
- }
-
- scored.sort((a, b) => b.score - a.score);
- results = scored.slice(0, 15).map(s => s.item);
- }
-
- function clear() {
- query = "";
- results = [];
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/SystemUpdateService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/SystemUpdateService.qml
deleted file mode 100644
index 53ca7ad..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/SystemUpdateService.qml
+++ /dev/null
@@ -1,396 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-
-Singleton {
- id: root
-
- property int refCount: 0
- property var availableUpdates: []
- property bool isChecking: false
- property bool hasError: false
- property string errorMessage: ""
- property string updChecker: ""
- property string pkgManager: ""
- property string distribution: ""
- property bool distributionSupported: false
- property string shellVersion: ""
- property string shellCodename: ""
- property string semverVersion: ""
-
- function getParsedShellVersion() {
- return parseVersion(semverVersion);
- }
-
- readonly property var archBasedUCSettings: {
- "listUpdatesSettings": {
- "params": [],
- "correctExitCodes": [0, 2] // Exit code 0 = updates available, 2 = no updates
- },
- "parserSettings": {
- "lineRegex": /^(\S+)\s+([^\s]+)\s+->\s+([^\s]+)$/,
- "entryProducer": function (match) {
- return {
- "name": match[1],
- "currentVersion": match[2],
- "newVersion": match[3],
- "description": `${match[1]} ${match[2]} → ${match[3]}`
- };
- }
- }
- }
-
- readonly property var archBasedPMSettings: function(requiresSudo) {
- return {
- "listUpdatesSettings": {
- "params": ["-Qu"],
- "correctExitCodes": [0, 1] // Exit code 0 = updates available, 1 = no updates
- },
- "upgradeSettings": {
- "params": ["-Syu"],
- "requiresSudo": requiresSudo
- },
- "parserSettings": {
- "lineRegex": /^(\S+)\s+([^\s]+)\s+->\s+([^\s]+)$/,
- "entryProducer": function (match) {
- return {
- "name": match[1],
- "currentVersion": match[2],
- "newVersion": match[3],
- "description": `${match[1]} ${match[2]} → ${match[3]}`
- };
- }
- }
- }
- }
-
- readonly property var fedoraBasedPMSettings: {
- "listUpdatesSettings": {
- "params": ["list", "--upgrades", "--quiet", "--color=never"],
- "correctExitCodes": [0, 1] // Exit code 0 = updates available, 1 = no updates
- },
- "upgradeSettings": {
- "params": ["upgrade"],
- "requiresSudo": true
- },
- "parserSettings": {
- "lineRegex": /^([^\s]+)\s+([^\s]+)\s+.*$/,
- "entryProducer": function (match) {
- return {
- "name": match[1],
- "currentVersion": "",
- "newVersion": match[2],
- "description": `${match[1]} → ${match[2]}`
- };
- }
- }
- }
-
- readonly property var updateCheckerParams: {
- "checkupdates": archBasedUCSettings
- }
- readonly property var packageManagerParams: {
- "yay": archBasedPMSettings(false),
- "paru": archBasedPMSettings(false),
- "pacman": archBasedPMSettings(true),
- "dnf": fedoraBasedPMSettings
- }
- readonly property list<string> supportedDistributions: ["arch", "artix", "cachyos", "manjaro", "endeavouros", "fedora"]
- readonly property int updateCount: availableUpdates.length
- readonly property bool helperAvailable: pkgManager !== "" && distributionSupported
-
- Process {
- id: distributionDetection
- command: ["sh", "-c", "cat /etc/os-release | grep '^ID=' | cut -d'=' -f2 | tr -d '\"'"]
- running: true
-
- onExited: exitCode => {
- if (exitCode === 0) {
- distribution = stdout.text.trim().toLowerCase();
- distributionSupported = supportedDistributions.includes(distribution);
-
- if (distributionSupported) {
- updateFinderDetection.running = true;
- pkgManagerDetection.running = true;
- checkForUpdates();
- } else {
- console.warn("SystemUpdate: Unsupported distribution:", distribution);
- }
- } else {
- console.warn("SystemUpdate: Failed to detect distribution");
- }
- }
-
- stdout: StdioCollector {}
-
- Component.onCompleted: {
- versionDetection.running = true;
- }
- }
-
- Process {
- id: versionDetection
- command: ["sh", "-c", `cd "${Quickshell.shellDir}" && if [ -d .git ]; then echo "(git) $(git rev-parse --short HEAD)"; elif [ -f VERSION ]; then cat VERSION; fi`]
-
- stdout: StdioCollector {
- onStreamFinished: {
- shellVersion = text.trim();
- }
- }
- }
-
- 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`]
- running: true
-
- stdout: StdioCollector {
- onStreamFinished: {
- shellCodename = text.trim();
- }
- }
- }
-
- Process {
- id: updateFinderDetection
- command: ["sh", "-c", "which checkupdates"]
-
- onExited: exitCode => {
- if (exitCode === 0) {
- const exeFound = stdout.text.trim();
- updChecker = exeFound.split('/').pop();
- } else {
- console.warn("SystemUpdate: No update checker found. Will use package manager.");
- }
- }
-
- stdout: StdioCollector {}
- }
-
- Process {
- id: pkgManagerDetection
- command: ["sh", "-c", "which paru || which yay || which pacman || which dnf"]
-
- onExited: exitCode => {
- if (exitCode === 0) {
- const exeFound = stdout.text.trim();
- pkgManager = exeFound.split('/').pop();
- } else {
- console.warn("SystemUpdate: No package manager found");
- }
- }
-
- stdout: StdioCollector {}
- }
-
- Process {
- id: updateChecker
-
- onExited: exitCode => {
- isChecking = false;
- const correctExitCodes = updChecker.length > 0 ? [updChecker].concat(updateCheckerParams[updChecker].listUpdatesSettings.correctExitCodes) : [pkgManager].concat(packageManagerParams[pkgManager].listUpdatesSettings.correctExitCodes);
- if (correctExitCodes.includes(exitCode)) {
- parseUpdates(stdout.text);
- hasError = false;
- errorMessage = "";
- } else {
- hasError = true;
- errorMessage = "Failed to check for updates";
- console.warn("SystemUpdate: Update check failed with code:", exitCode);
- }
- }
-
- stdout: StdioCollector {}
- }
-
- Process {
- id: updater
- onExited: exitCode => {
- checkForUpdates();
- }
- }
-
- function checkForUpdates() {
- if (!distributionSupported || (!pkgManager && !updChecker) || isChecking)
- return;
- isChecking = true;
- hasError = false;
- if (pkgManager === "paru" || pkgManager === "yay") {
- const repoCmd = updChecker.length > 0 ? updChecker : `${pkgManager} -Qu`;
- updateChecker.command = ["sh", "-c", `(${repoCmd} 2>/dev/null; ${pkgManager} -Qua 2>/dev/null) || true`];
- } else if (updChecker.length > 0) {
- updateChecker.command = [updChecker].concat(updateCheckerParams[updChecker].listUpdatesSettings.params);
- } else {
- updateChecker.command = [pkgManager].concat(packageManagerParams[pkgManager].listUpdatesSettings.params);
- }
- updateChecker.running = true;
- }
-
- function parseUpdates(output) {
- const lines = output.trim().split('\n').filter(line => line.trim());
- const updates = [];
-
- const regex = packageManagerParams[pkgManager].parserSettings.lineRegex;
- const entryProducer = packageManagerParams[pkgManager].parserSettings.entryProducer;
-
- for (const line of lines) {
- const match = line.match(regex);
- if (match) {
- updates.push(entryProducer(match));
- }
- }
-
- availableUpdates = updates;
- }
-
- function runUpdates() {
- if (!distributionSupported || !pkgManager || updateCount === 0)
- return;
- const terminal = Quickshell.env("TERMINAL") || "xterm";
-
- if (SettingsData.updaterUseCustomCommand && SettingsData.updaterCustomCommand.length > 0) {
- const updateCommand = `${SettingsData.updaterCustomCommand} && echo -n "Updates complete! " ; echo "Press Enter to close..." && read`;
- const termClass = SettingsData.updaterTerminalAdditionalParams;
-
- var finalCommand = [terminal];
- if (termClass.length > 0) {
- finalCommand = finalCommand.concat(termClass.split(" "));
- }
- finalCommand.push("-e");
- finalCommand.push("sh");
- finalCommand.push("-c");
- finalCommand.push(updateCommand);
- updater.command = finalCommand;
- } else {
- const params = packageManagerParams[pkgManager].upgradeSettings.params.join(" ");
- const sudo = packageManagerParams[pkgManager].upgradeSettings.requiresSudo ? "sudo" : "";
- const updateCommand = `${sudo} ${pkgManager} ${params} && echo -n "Updates complete! " ; echo "Press Enter to close..." && read`;
-
- updater.command = [terminal, "-e", "sh", "-c", updateCommand];
- }
- updater.running = true;
- }
-
- Timer {
- interval: 30 * 60 * 1000
- repeat: true
- running: refCount > 0 && distributionSupported && (pkgManager || updChecker)
- onTriggered: checkForUpdates()
- }
-
- IpcHandler {
- target: "systemupdater"
-
- function updatestatus(): string {
- if (root.isChecking) {
- return "ERROR: already checking";
- }
- if (!distributionSupported) {
- return "ERROR: distribution not supported";
- }
- if (!pkgManager && !updChecker) {
- return "ERROR: update checker not available";
- }
- root.checkForUpdates();
- 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;
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ToastService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ToastService.qml
deleted file mode 100644
index 7684f90..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/ToastService.qml
+++ /dev/null
@@ -1,174 +0,0 @@
-pragma Singleton
-
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-
-Singleton {
- id: root
-
- readonly property int levelInfo: 0
- readonly property int levelWarn: 1
- readonly property int levelError: 2
- property string currentMessage: ""
- property int currentLevel: levelInfo
- property bool toastVisible: false
- property var toastQueue: []
- property string currentDetails: ""
- property string currentCommand: ""
- property bool hasDetails: false
- property string wallpaperErrorStatus: ""
- property int maxQueueSize: 3
- property var lastErrorTime: ({})
- property int errorThrottleMs: 1000
- property string currentCategory: ""
-
- function showToast(message, level = levelInfo, details = "", command = "", category = "") {
- const now = Date.now()
- const messageKey = message + level
-
- if (level === levelError) {
- const lastTime = lastErrorTime[messageKey] || 0
- if (now - lastTime < errorThrottleMs) {
- return
- }
- lastErrorTime[messageKey] = now
- }
-
- if (category && level === levelError) {
- if (currentCategory === category && toastVisible && currentLevel === levelError) {
- currentMessage = message
- currentDetails = details || ""
- currentCommand = command || ""
- hasDetails = currentDetails.length > 0 || currentCommand.length > 0
- resetToastState()
- if (hasDetails) {
- toastTimer.interval = 8000
- } else {
- toastTimer.interval = 5000
- }
- toastTimer.restart()
- return
- }
-
- toastQueue = toastQueue.filter(t => t.category !== category)
- }
-
- const isDuplicate = toastQueue.some(toast =>
- toast.message === message && toast.level === level
- )
- if (isDuplicate) {
- return
- }
-
- if (toastQueue.length >= maxQueueSize) {
- if (level === levelError) {
- toastQueue = toastQueue.filter(t => t.level !== levelError).slice(0, maxQueueSize - 1)
- } else {
- return
- }
- }
-
- toastQueue.push({
- "message": message,
- "level": level,
- "details": details,
- "command": command,
- "category": category
- })
- if (!toastVisible) {
- processQueue()
- }
- }
-
- function showInfo(message, details = "", command = "", category = "") {
- showToast(message, levelInfo, details, command, category)
- }
-
- function showWarning(message, details = "", command = "", category = "") {
- showToast(message, levelWarn, details, command, category)
- }
-
- function showError(message, details = "", command = "", category = "") {
- showToast(message, levelError, details, command, category)
- }
-
- function dismissCategory(category) {
- if (!category) {
- return
- }
-
- if (currentCategory === category && toastVisible) {
- hideToast()
- return
- }
-
- toastQueue = toastQueue.filter(t => t.category !== category)
- }
-
- function hideToast() {
- toastVisible = false
- currentMessage = ""
- currentDetails = ""
- currentCommand = ""
- currentCategory = ""
- hasDetails = false
- currentLevel = levelInfo
- toastTimer.stop()
- resetToastState()
- if (toastQueue.length > 0) {
- processQueue()
- }
- }
-
- function processQueue() {
- if (toastQueue.length === 0) {
- return
- }
-
- const toast = toastQueue.shift()
- currentMessage = toast.message
- currentLevel = toast.level
- currentDetails = toast.details || ""
- currentCommand = toast.command || ""
- currentCategory = toast.category || ""
- hasDetails = currentDetails.length > 0 || currentCommand.length > 0
- toastVisible = true
- resetToastState()
-
- if (toast.level === levelError && hasDetails) {
- toastTimer.interval = 8000
- toastTimer.start()
- } else {
- toastTimer.interval = toast.level === levelError ? 5000 : toast.level === levelWarn ? 3000 : 1500
- toastTimer.start()
- }
- }
-
- signal resetToastState
-
- function stopTimer() {
- toastTimer.stop()
- }
-
- function restartTimer() {
- if (hasDetails && currentLevel === levelError) {
- toastTimer.interval = 8000
- toastTimer.restart()
- }
- }
-
- function clearWallpaperError() {
- wallpaperErrorStatus = ""
- }
-
- Timer {
- id: toastTimer
-
- interval: 5000
- running: false
- repeat: false
- onTriggered: hideToast()
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/TrackArtService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/TrackArtService.qml
deleted file mode 100644
index e2c6ea5..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/TrackArtService.qml
+++ /dev/null
@@ -1,49 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import Quickshell
-import QtQuick
-import Quickshell.Services.Mpris
-import qs.Common
-
-Singleton {
- id: root
-
- property string _lastArtUrl: ""
- property string _bgArtSource: ""
- property bool loading: false
-
- function loadArtwork(url) {
- if (!url || url === "") {
- _bgArtSource = "";
- _lastArtUrl = "";
- loading = false;
- return;
- }
- if (url === _lastArtUrl)
- return;
- _lastArtUrl = url;
-
- if (url.startsWith("http://") || url.startsWith("https://")) {
- _bgArtSource = url;
- loading = false;
- return;
- }
-
- loading = true;
- const localUrl = url;
- const filePath = url.startsWith("file://") ? url.substring(7) : url;
- Proc.runCommand("trackart", ["test", "-f", filePath], (output, exitCode) => {
- if (_lastArtUrl !== localUrl)
- return;
- _bgArtSource = exitCode === 0 ? localUrl : "";
- loading = false;
- }, 200);
- }
-
- property MprisPlayer activePlayer: MprisController.activePlayer
-
- onActivePlayerChanged: {
- loadArtwork(activePlayer?.trackArtUrl ?? "");
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/UserInfoService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/UserInfoService.qml
deleted file mode 100644
index 8378e01..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/UserInfoService.qml
+++ /dev/null
@@ -1,35 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import qs.Common
-
-Singleton {
- id: root
-
- property string username: ""
- property string fullName: ""
- property string profilePicture: ""
- property string hostname: ""
- property bool profileAvailable: false
-
- function getUserInfo() {
- Proc.runCommand("userInfo", ["sh", "-c", "echo \"$USER|$(getent passwd $USER | cut -d: -f5 | cut -d, -f1)|$(hostname)\""], (output, exitCode) => {
- if (exitCode !== 0) {
- root.username = "User";
- root.fullName = "User";
- root.hostname = "System";
- return;
- }
- const parts = output.trim().split("|");
- if (parts.length >= 3) {
- root.username = parts[0] || "";
- root.fullName = parts[1] || parts[0] || "";
- root.hostname = parts[2] || "";
- }
- }, 0);
- }
-
- Component.onCompleted: getUserInfo()
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/VPNService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/VPNService.qml
deleted file mode 100644
index effc54e..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/VPNService.qml
+++ /dev/null
@@ -1,221 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import qs.Common
-
-Singleton {
- id: root
-
- readonly property bool available: DMSNetworkService.vpnAvailable
-
- property var plugins: []
- property var allExtensions: []
- property bool importing: false
- property string importError: ""
-
- property var editConfig: null
- property bool configLoading: false
-
- property bool pluginsLoading: false
-
- signal importComplete(string uuid, string name)
- signal configLoaded(var config)
- signal configUpdated
- signal vpnDeleted(string uuid)
-
- Component.onCompleted: {
- if (available) {
- fetchPlugins();
- }
- }
-
- Connections {
- target: DMSNetworkService
- function onVpnAvailableChanged() {
- if (DMSNetworkService.vpnAvailable && plugins.length === 0) {
- fetchPlugins();
- }
- }
- }
-
- function fetchPlugins() {
- if (!available || pluginsLoading)
- return;
- pluginsLoading = true;
-
- DMSService.sendRequest("network.vpn.plugins", null, response => {
- pluginsLoading = false;
- if (response.error) {
- console.warn("VPNService: Failed to fetch plugins:", response.error);
- return;
- }
- if (!response.result)
- return;
- plugins = response.result;
- const extSet = new Set();
- for (const plugin of response.result) {
- for (const ext of plugin.fileExtensions || []) {
- extSet.add(ext);
- }
- }
- allExtensions = Array.from(extSet);
- });
- }
-
- function importVpn(filePath, name = "") {
- if (!available || importing)
- return;
- importing = true;
- importError = "";
-
- const params = {
- file: filePath
- };
- if (name)
- params.name = name;
-
- DMSService.sendRequest("network.vpn.import", params, response => {
- importing = false;
-
- if (response.error) {
- importError = response.error;
- ToastService.showError(I18n.tr("Failed to import VPN"), response.error);
- return;
- }
-
- if (!response.result)
- return;
- if (response.result.success) {
- ToastService.showInfo(I18n.tr("VPN imported: %1").arg(response.result.name || ""));
- DMSNetworkService.refreshVpnProfiles();
- importComplete(response.result.uuid || "", response.result.name || "");
- return;
- }
-
- importError = response.result.error || "Import failed";
- ToastService.showError(I18n.tr("Failed to import VPN"), importError);
- });
- }
-
- function getConfig(uuidOrName) {
- if (!available)
- return;
- configLoading = true;
- editConfig = null;
-
- DMSService.sendRequest("network.vpn.getConfig", {
- uuid: uuidOrName
- }, response => {
- configLoading = false;
-
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to load VPN config"), response.error);
- return;
- }
-
- if (response.result) {
- editConfig = response.result;
- configLoaded(response.result);
- }
- });
- }
-
- function updateConfig(uuid, updates) {
- if (!available)
- return;
- const params = {
- uuid: uuid
- };
- if (updates.name !== undefined)
- params.name = updates.name;
- if (updates.autoconnect !== undefined)
- params.autoconnect = updates.autoconnect;
- if (updates.data !== undefined)
- params.data = updates.data;
-
- DMSService.sendRequest("network.vpn.updateConfig", params, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to update VPN"), response.error);
- return;
- }
- ToastService.showInfo(I18n.tr("VPN configuration updated"));
- DMSNetworkService.refreshVpnProfiles();
- getConfig(uuid);
- configUpdated();
- });
- }
-
- function deleteVpn(uuidOrName) {
- if (!available)
- return;
- DMSService.sendRequest("network.vpn.delete", {
- uuid: uuidOrName
- }, response => {
- if (response.error) {
- ToastService.showError(I18n.tr("Failed to delete VPN"), response.error);
- return;
- }
- ToastService.showInfo(I18n.tr("VPN deleted"));
- DMSNetworkService.refreshVpnProfiles();
- vpnDeleted(uuidOrName);
- });
- }
-
- function getFileFilter() {
- if (allExtensions.length === 0) {
- return ["*.ovpn", "*.conf"];
- }
- return allExtensions.map(e => "*" + e);
- }
-
- function getExtensionsForPlugin(serviceType) {
- const plugin = plugins.find(p => p.serviceType === serviceType);
- if (!plugin)
- return ["*.conf"];
- return (plugin.fileExtensions || [".conf"]).map(e => "*" + e);
- }
-
- function getPluginName(serviceType) {
- if (!serviceType)
- return "VPN";
-
- const plugin = plugins.find(p => p.serviceType === serviceType);
- if (plugin)
- return plugin.name;
-
- const svc = serviceType.toLowerCase();
- if (svc.includes("openvpn"))
- return "OpenVPN";
- if (svc.includes("wireguard"))
- return "WireGuard";
- if (svc.includes("openconnect"))
- return "OpenConnect";
- if (svc.includes("fortissl") || svc.includes("forti"))
- return "Fortinet";
- if (svc.includes("strongswan"))
- return "IPsec (strongSwan)";
- if (svc.includes("libreswan"))
- return "IPsec (Libreswan)";
- if (svc.includes("l2tp"))
- return "L2TP/IPsec";
- if (svc.includes("pptp"))
- return "PPTP";
- if (svc.includes("vpnc"))
- return "Cisco (vpnc)";
- if (svc.includes("sstp"))
- return "SSTP";
-
- const parts = serviceType.split('.');
- return parts[parts.length - 1] || "VPN";
- }
-
- function getVpnTypeFromProfile(profile) {
- if (!profile)
- return "VPN";
- if (profile.type === "wireguard")
- return "WireGuard";
- return getPluginName(profile.serviceType);
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/WallpaperCyclingService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/WallpaperCyclingService.qml
deleted file mode 100644
index a07c563..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/WallpaperCyclingService.qml
+++ /dev/null
@@ -1,495 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import Quickshell.Wayland
-import qs.Common
-import qs.Services
-
-Singleton {
- id: root
-
- property bool cyclingActive: false
- readonly property bool fullscreenShowing: {
- if (!ToplevelManager.toplevels?.values)
- return false;
- for (const toplevel of ToplevelManager.toplevels.values) {
- if (toplevel.fullscreen && toplevel.activated)
- return true;
- }
- return false;
- }
- readonly property bool shouldPauseCycling: fullscreenShowing || SessionService.locked
- property string cachedCyclingTime: SessionData.wallpaperCyclingTime
- property int cachedCyclingInterval: SessionData.wallpaperCyclingInterval
- property string lastTimeCheck: ""
- property var monitorTimers: ({})
- property var monitorLastTimeChecks: ({})
- property var monitorProcesses: ({})
-
- Component {
- id: monitorTimerComponent
- Timer {
- property string targetScreen: ""
- running: false
- repeat: true
- onTriggered: {
- if (typeof WallpaperCyclingService !== "undefined" && targetScreen !== "" && !WallpaperCyclingService.shouldPauseCycling) {
- WallpaperCyclingService.cycleNextForMonitor(targetScreen);
- }
- }
- }
- }
-
- Component {
- id: monitorProcessComponent
- Process {
- property string targetScreenName: ""
- property string currentWallpaper: ""
- property bool goToPrevious: false
- running: false
- stdout: StdioCollector {
- onStreamFinished: {
- if (text && text.trim()) {
- const files = text.trim().split('\n').filter(file => file.length > 0);
- if (files.length <= 1)
- return;
- const wallpaperList = files.sort();
- const currentPath = currentWallpaper;
- let currentIndex = wallpaperList.findIndex(path => path === currentPath);
- if (currentIndex === -1)
- currentIndex = 0;
- let targetIndex;
- if (goToPrevious) {
- targetIndex = currentIndex === 0 ? wallpaperList.length - 1 : currentIndex - 1;
- } else {
- targetIndex = (currentIndex + 1) % wallpaperList.length;
- }
- const targetWallpaper = wallpaperList[targetIndex];
- if (targetWallpaper && targetWallpaper !== currentPath) {
- if (targetScreenName) {
- SessionData.setMonitorWallpaper(targetScreenName, targetWallpaper);
- } else {
- SessionData.setWallpaper(targetWallpaper);
- }
- }
- }
- }
- }
- }
- }
-
- Connections {
- target: SessionData
-
- function onWallpaperCyclingEnabledChanged() {
- updateCyclingState();
- }
-
- function onWallpaperCyclingModeChanged() {
- updateCyclingState();
- }
-
- function onWallpaperCyclingIntervalChanged() {
- cachedCyclingInterval = SessionData.wallpaperCyclingInterval;
- if (SessionData.wallpaperCyclingMode === "interval") {
- updateCyclingState();
- }
- }
-
- function onWallpaperCyclingTimeChanged() {
- cachedCyclingTime = SessionData.wallpaperCyclingTime;
- if (SessionData.wallpaperCyclingMode === "time") {
- updateCyclingState();
- }
- }
-
- function onPerMonitorWallpaperChanged() {
- updateCyclingState();
- }
-
- function onMonitorCyclingSettingsChanged() {
- updateCyclingState();
- }
- }
-
- Connections {
- target: SessionService
-
- function onSessionUnlocked() {
- if (SessionData.wallpaperCyclingEnabled || SessionData.perMonitorWallpaper) {
- updateCyclingState();
- }
- }
- }
-
- function updateCyclingState() {
- if (SessionData.perMonitorWallpaper) {
- stopCycling();
- updatePerMonitorCycling();
- } else if (SessionData.wallpaperCyclingEnabled && SessionData.wallpaperPath) {
- startCycling();
- stopAllMonitorCycling();
- } else {
- stopCycling();
- stopAllMonitorCycling();
- }
- }
-
- function updatePerMonitorCycling() {
- if (typeof Quickshell === "undefined")
- return;
- var screens = Quickshell.screens;
- for (var i = 0; i < screens.length; i++) {
- var screenName = screens[i].name;
- var settings = SessionData.getMonitorCyclingSettings(screenName);
- var wallpaper = SessionData.getMonitorWallpaper(screenName);
-
- if (settings.enabled && wallpaper && !wallpaper.startsWith("#")) {
- startMonitorCycling(screenName, settings);
- } else {
- stopMonitorCycling(screenName);
- }
- }
- }
-
- function stopAllMonitorCycling() {
- var screenNames = Object.keys(monitorTimers);
- for (var i = 0; i < screenNames.length; i++) {
- stopMonitorCycling(screenNames[i]);
- }
- }
-
- function startCycling() {
- switch (SessionData.wallpaperCyclingMode) {
- case "interval":
- lastTimeCheck = "";
- intervalTimer.interval = cachedCyclingInterval * 1000;
- intervalTimer.start();
- cyclingActive = true;
- break;
- case "time":
- intervalTimer.stop();
- cyclingActive = true;
- checkTimeBasedCycling();
- break;
- }
- }
-
- function stopCycling() {
- intervalTimer.stop();
- cyclingActive = false;
- }
-
- function startMonitorCycling(screenName, settings) {
- switch (settings.mode) {
- case "interval":
- {
- var newChecks = Object.assign({}, monitorLastTimeChecks);
- delete newChecks[screenName];
- monitorLastTimeChecks = newChecks;
-
- var timer = monitorTimers[screenName];
- if (!timer && monitorTimerComponent && monitorTimerComponent.status === Component.Ready) {
- var newTimers = Object.assign({}, monitorTimers);
- var newTimer = monitorTimerComponent.createObject(root);
- newTimer.targetScreen = screenName;
- newTimers[screenName] = newTimer;
- monitorTimers = newTimers;
- timer = newTimer;
- }
- if (timer) {
- timer.interval = settings.interval * 1000;
- timer.start();
- }
- break;
- }
- case "time":
- {
- var existingTimer = monitorTimers[screenName];
- if (existingTimer) {
- existingTimer.stop();
- existingTimer.destroy();
- var newTimers = Object.assign({}, monitorTimers);
- delete newTimers[screenName];
- monitorTimers = newTimers;
- }
-
- var newChecks = Object.assign({}, monitorLastTimeChecks);
- newChecks[screenName] = "";
- monitorLastTimeChecks = newChecks;
- break;
- }
- }
- }
-
- function stopMonitorCycling(screenName) {
- var timer = monitorTimers[screenName];
- if (timer) {
- timer.stop();
- timer.destroy();
- var newTimers = Object.assign({}, monitorTimers);
- delete newTimers[screenName];
- monitorTimers = newTimers;
- }
-
- var process = monitorProcesses[screenName];
- if (process) {
- process.destroy();
- var newProcesses = Object.assign({}, monitorProcesses);
- delete newProcesses[screenName];
- monitorProcesses = newProcesses;
- }
-
- var newChecks = Object.assign({}, monitorLastTimeChecks);
- delete newChecks[screenName];
- monitorLastTimeChecks = newChecks;
- }
-
- function cycleToNextWallpaper(screenName, wallpaperPath) {
- const currentWallpaper = wallpaperPath || SessionData.wallpaperPath;
- if (!currentWallpaper)
- return;
- const wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/'));
-
- if (screenName && monitorProcessComponent && monitorProcessComponent.status === Component.Ready) {
- // Use per-monitor process
- var process = monitorProcesses[screenName];
- if (!process) {
- var newProcesses = Object.assign({}, monitorProcesses);
- var newProcess = monitorProcessComponent.createObject(root);
- newProcesses[screenName] = newProcess;
- monitorProcesses = newProcesses;
- process = newProcess;
- }
-
- if (process) {
- process.command = ["sh", "-c", `find -L "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`];
- process.targetScreenName = screenName;
- process.currentWallpaper = currentWallpaper;
- process.goToPrevious = false;
- process.running = true;
- }
- } else {
- // Use global process for fallback
- cyclingProcess.command = ["sh", "-c", `find -L "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`];
- cyclingProcess.targetScreenName = screenName || "";
- cyclingProcess.currentWallpaper = currentWallpaper;
- cyclingProcess.running = true;
- }
- }
-
- function cycleToPrevWallpaper(screenName, wallpaperPath) {
- const currentWallpaper = wallpaperPath || SessionData.wallpaperPath;
- if (!currentWallpaper)
- return;
- const wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/'));
-
- if (screenName && monitorProcessComponent && monitorProcessComponent.status === Component.Ready) {
- // Use per-monitor process (same as next, but with prev flag)
- var process = monitorProcesses[screenName];
- if (!process) {
- var newProcesses = Object.assign({}, monitorProcesses);
- var newProcess = monitorProcessComponent.createObject(root);
- newProcesses[screenName] = newProcess;
- monitorProcesses = newProcesses;
- process = newProcess;
- }
-
- if (process) {
- process.command = ["sh", "-c", `find -L "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`];
- process.targetScreenName = screenName;
- process.currentWallpaper = currentWallpaper;
- process.goToPrevious = true;
- process.running = true;
- }
- } else {
- // Use global process for fallback
- prevCyclingProcess.command = ["sh", "-c", `find -L "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`];
- prevCyclingProcess.targetScreenName = screenName || "";
- prevCyclingProcess.currentWallpaper = currentWallpaper;
- prevCyclingProcess.running = true;
- }
- }
-
- function cycleNextManually() {
- if (SessionData.wallpaperPath) {
- cycleToNextWallpaper();
- // Restart timers if cycling is active
- if (cyclingActive && SessionData.wallpaperCyclingEnabled) {
- if (SessionData.wallpaperCyclingMode === "interval") {
- intervalTimer.interval = cachedCyclingInterval * 1000;
- intervalTimer.restart();
- }
- }
- }
- }
-
- function cyclePrevManually() {
- if (SessionData.wallpaperPath) {
- cycleToPrevWallpaper();
- // Restart timers if cycling is active
- if (cyclingActive && SessionData.wallpaperCyclingEnabled) {
- if (SessionData.wallpaperCyclingMode === "interval") {
- intervalTimer.interval = cachedCyclingInterval * 1000;
- intervalTimer.restart();
- }
- }
- }
- }
-
- function cycleNextForMonitor(screenName) {
- if (!screenName)
- return;
- var currentWallpaper = SessionData.getMonitorWallpaper(screenName);
- if (currentWallpaper) {
- cycleToNextWallpaper(screenName, currentWallpaper);
- }
- }
-
- function cyclePrevForMonitor(screenName) {
- if (!screenName)
- return;
- var currentWallpaper = SessionData.getMonitorWallpaper(screenName);
- if (currentWallpaper) {
- cycleToPrevWallpaper(screenName, currentWallpaper);
- }
- }
-
- function checkTimeBasedCycling() {
- if (shouldPauseCycling)
- return;
- const currentTime = Qt.formatTime(systemClock.date, "hh:mm");
-
- if (!SessionData.perMonitorWallpaper) {
- if (currentTime === cachedCyclingTime && currentTime !== lastTimeCheck) {
- lastTimeCheck = currentTime;
- cycleToNextWallpaper();
- } else if (currentTime !== cachedCyclingTime) {
- lastTimeCheck = "";
- }
- } else {
- checkPerMonitorTimeBasedCycling(currentTime);
- }
- }
-
- function checkPerMonitorTimeBasedCycling(currentTime) {
- if (typeof Quickshell === "undefined")
- return;
- var screens = Quickshell.screens;
- for (var i = 0; i < screens.length; i++) {
- var screenName = screens[i].name;
- var settings = SessionData.getMonitorCyclingSettings(screenName);
- var wallpaper = SessionData.getMonitorWallpaper(screenName);
-
- if (settings.enabled && settings.mode === "time" && wallpaper && !wallpaper.startsWith("#")) {
- var lastCheck = monitorLastTimeChecks[screenName] || "";
-
- if (currentTime === settings.time && currentTime !== lastCheck) {
- var newChecks = Object.assign({}, monitorLastTimeChecks);
- newChecks[screenName] = currentTime;
- monitorLastTimeChecks = newChecks;
- cycleNextForMonitor(screenName);
- } else if (currentTime !== settings.time) {
- var newChecks = Object.assign({}, monitorLastTimeChecks);
- newChecks[screenName] = "";
- monitorLastTimeChecks = newChecks;
- }
- }
- }
- }
-
- Timer {
- id: intervalTimer
- interval: cachedCyclingInterval * 1000
- running: false
- repeat: true
- onTriggered: {
- if (shouldPauseCycling)
- return;
- cycleToNextWallpaper();
- }
- }
-
- SystemClock {
- id: systemClock
- precision: SystemClock.Minutes
- onDateChanged: {
- if ((SessionData.wallpaperCyclingMode === "time" && cyclingActive) || SessionData.perMonitorWallpaper) {
- checkTimeBasedCycling();
- }
- }
- }
-
- Process {
- id: cyclingProcess
-
- property string targetScreenName: ""
- property string currentWallpaper: ""
-
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- if (text && text.trim()) {
- const files = text.trim().split('\n').filter(file => file.length > 0);
- if (files.length <= 1)
- return;
- const wallpaperList = files.sort();
- const currentPath = cyclingProcess.currentWallpaper;
- let currentIndex = wallpaperList.findIndex(path => path === currentPath);
- if (currentIndex === -1)
- currentIndex = 0;
-
- const nextIndex = (currentIndex + 1) % wallpaperList.length;
- const nextWallpaper = wallpaperList[nextIndex];
-
- if (nextWallpaper && nextWallpaper !== currentPath) {
- if (cyclingProcess.targetScreenName) {
- SessionData.setMonitorWallpaper(cyclingProcess.targetScreenName, nextWallpaper);
- } else {
- SessionData.setWallpaper(nextWallpaper);
- }
- }
- }
- }
- }
- }
-
- Process {
- id: prevCyclingProcess
-
- property string targetScreenName: ""
- property string currentWallpaper: ""
-
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- if (text && text.trim()) {
- const files = text.trim().split('\n').filter(file => file.length > 0);
- if (files.length <= 1)
- return;
- const wallpaperList = files.sort();
- const currentPath = prevCyclingProcess.currentWallpaper;
- let currentIndex = wallpaperList.findIndex(path => path === currentPath);
- if (currentIndex === -1)
- currentIndex = 0;
-
- const prevIndex = currentIndex === 0 ? wallpaperList.length - 1 : currentIndex - 1;
- const prevWallpaper = wallpaperList[prevIndex];
-
- if (prevWallpaper && prevWallpaper !== currentPath) {
- if (prevCyclingProcess.targetScreenName) {
- SessionData.setMonitorWallpaper(prevCyclingProcess.targetScreenName, prevWallpaper);
- } else {
- SessionData.setWallpaper(prevWallpaper);
- }
- }
- }
- }
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/WeatherService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/WeatherService.qml
deleted file mode 100644
index 134789e..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/WeatherService.qml
+++ /dev/null
@@ -1,914 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-import qs.Modules.Greetd
-import "../Common/suncalc.js" as SunCalc
-
-Singleton {
- id: root
-
- property int refCount: 0
-
- property var selectedDate: new Date()
- property var weather: ({
- "available": false,
- "loading": true,
- "temp": 0,
- "tempF": 0,
- "feelsLike": 0,
- "feelsLikeF": 0,
- "city": "",
- "country": "",
- "wCode": 0,
- "humidity": 0,
- "wind": "",
- "sunrise": "06:00",
- "sunset": "18:00",
- "uv": 0,
- "pressure": 0,
- "precipitationProbability": 0,
- "isDay": true,
- "forecast": []
- })
-
- property var location: null
- property int updateInterval: 900000 // 15 minutes
- property int retryAttempts: 0
- property int maxRetryAttempts: 3
- property int retryDelay: 30000
- property int lastFetchTime: 0
- property int minFetchInterval: 30000
- property int persistentRetryCount: 0
-
- readonly property var lowPriorityCmd: ["nice", "-n", "19", "ionice", "-c3"]
- readonly property var curlBaseCmd: ["curl", "-sS", "--fail", "--connect-timeout", "3", "--max-time", "6", "--limit-rate", "100k", "--compressed"]
-
- property var weatherIcons: ({
- "0": "clear_day",
- "1": "clear_day",
- "2": "partly_cloudy_day",
- "3": "cloud",
- "45": "foggy",
- "48": "foggy",
- "51": "rainy",
- "53": "rainy",
- "55": "rainy",
- "56": "rainy",
- "57": "rainy",
- "61": "rainy",
- "63": "rainy",
- "65": "rainy",
- "66": "rainy",
- "67": "rainy",
- "71": "cloudy_snowing",
- "73": "cloudy_snowing",
- "75": "snowing_heavy",
- "77": "cloudy_snowing",
- "80": "rainy",
- "81": "rainy",
- "82": "rainy",
- "85": "cloudy_snowing",
- "86": "snowing_heavy",
- "95": "thunderstorm",
- "96": "thunderstorm",
- "99": "thunderstorm"
- })
-
- property var nightWeatherIcons: ({
- "0": "clear_night",
- "1": "clear_night",
- "2": "partly_cloudy_night",
- "3": "cloud",
- "45": "foggy",
- "48": "foggy",
- "51": "rainy",
- "53": "rainy",
- "55": "rainy",
- "56": "rainy",
- "57": "rainy",
- "61": "rainy",
- "63": "rainy",
- "65": "rainy",
- "66": "rainy",
- "67": "rainy",
- "71": "cloudy_snowing",
- "73": "cloudy_snowing",
- "75": "snowing_heavy",
- "77": "cloudy_snowing",
- "80": "rainy",
- "81": "rainy",
- "82": "rainy",
- "85": "cloudy_snowing",
- "86": "snowing_heavy",
- "95": "thunderstorm",
- "96": "thunderstorm",
- "99": "thunderstorm"
- })
-
- function getWeatherIcon(code, isDay) {
- if (typeof isDay === "undefined") {
- isDay = weather.isDay;
- }
- const iconMap = isDay ? weatherIcons : nightWeatherIcons;
- return iconMap[String(code)] || "cloud";
- }
-
- function getWeatherCondition(code) {
- const conditions = {
- "0": I18n.tr("Clear Sky"),
- "1": I18n.tr("Clear Sky"),
- "2": I18n.tr("Partly Cloudy"),
- "3": I18n.tr("Overcast"),
- "45": I18n.tr("Fog"),
- "48": I18n.tr("Fog"),
- "51": I18n.tr("Drizzle"),
- "53": I18n.tr("Drizzle"),
- "55": I18n.tr("Drizzle"),
- "56": I18n.tr("Freezing Drizzle"),
- "57": I18n.tr("Freezing Drizzle"),
- "61": I18n.tr("Light Rain"),
- "63": I18n.tr("Rain"),
- "65": I18n.tr("Heavy Rain"),
- "66": I18n.tr("Light Rain"),
- "67": I18n.tr("Heavy Rain"),
- "71": I18n.tr("Light Snow"),
- "73": I18n.tr("Snow"),
- "75": I18n.tr("Heavy Snow"),
- "77": I18n.tr("Snow"),
- "80": I18n.tr("Light Rain"),
- "81": I18n.tr("Rain"),
- "82": I18n.tr("Heavy Rain"),
- "85": I18n.tr("Light Snow Showers"),
- "86": I18n.tr("Heavy Snow Showers"),
- "95": I18n.tr("Thunderstorm"),
- "96": I18n.tr("Thunderstorm with Hail"),
- "99": I18n.tr("Thunderstorm with Hail")
- };
- return conditions[String(code)] || I18n.tr("Unknown");
- }
-
- property var moonPhaseNames: ["moon_new", "moon_waxing_crescent", "moon_first_quarter", "moon_waxing_gibbous", "moon_full", "moon_waning_gibbous", "moon_last_quarter", "moon_waning_crescent"]
-
- function getMoonPhase(date) {
- const phases = moonPhaseNames;
- const iconCount = phases.length;
- const moon = SunCalc.getMoonIllumination(date);
- const index = ((Math.floor(moon.phase * iconCount + 0.5) % iconCount) + iconCount) % iconCount;
-
- return phases[index];
- }
-
- function getMoonAngle(date) {
- if (!location) {
- return;
- }
- const pos = SunCalc.getMoonPosition(date, location.latitude, location.longitude);
- return pos.parralacticAngle;
- }
-
- function getLocation() {
- return location;
- }
-
- function getSunDeclination(date) {
- return SunCalc.sunCoords(SunCalc.toDays(date)).dec * 180 / Math.PI;
- }
-
- function getSunTimes(date) {
- if (!location) {
- return null;
- }
- return SunCalc.getTimes(date, location.latitude, location.longitude, location.elevation);
- }
-
- function getEcliptic(date, points = 60) {
- if (!location) {
- return null;
- }
- const lat = location.latitude;
- const lon = location.longitude;
- const times = SunCalc.getTimes(date, lat, lon);
- const solarNoon = times.solarNoon;
-
- const eclipticPoints = [];
-
- const sunIsNorth = getSunDeclination(date) > lat;
- const transitAzimuth = sunIsNorth ? 0 : Math.PI;
-
- for (let i = 0; i <= points; i++) {
- const t = new Date(solarNoon.getTime() + (i / points) * 24 * 60 * 60 * 1000);
- const pos = SunCalc.getPosition(t, lat, lon);
-
- let h = (((pos.azimuth - transitAzimuth) / (2 * Math.PI)) + 1) % 1;
- h = Math.max(0, Math.min(1, h));
- let v = Math.sin(pos.altitude);
- v = Math.max(-1, Math.min(1, v));
-
- eclipticPoints.push({
- h,
- v
- });
- }
-
- const sortedEntries = eclipticPoints.sort((a, b) => a.h - b.h);
- return sortedEntries;
- }
-
- function getCurrentSunTime(date) {
- const times = getSunTimes(date);
- if (!times) {
- return;
- }
- const dateObj = new Date(date);
-
- const periods = [
- {
- name: I18n.tr("Dawn (Astronomical Twilight)"),
- start: new Date(times.nightEnd),
- end: new Date(times.nauticalDawn)
- },
- {
- name: I18n.tr("Dawn (Nautical Twilight)"),
- start: new Date(times.nauticalDawn),
- end: new Date(times.dawn)
- },
- {
- name: I18n.tr("Dawn (Civil Twilight)"),
- start: new Date(times.dawn),
- end: new Date(times.sunrise)
- },
- {
- name: I18n.tr("Sunrise"),
- start: new Date(times.sunrise),
- end: new Date(times.sunriseEnd)
- },
- {
- name: I18n.tr("Golden Hour"),
- start: new Date(times.sunriseEnd),
- end: new Date(times.goldenHourEnd)
- },
- {
- name: I18n.tr("Morning"),
- start: new Date(times.goldenHourEnd),
- end: new Date(times.solarNoon)
- },
- {
- name: I18n.tr("Afternoon"),
- start: new Date(times.solarNoon),
- end: new Date(times.goldenHour)
- },
- {
- name: I18n.tr("Golden Hour"),
- start: new Date(times.goldenHour),
- end: new Date(times.sunsetStart)
- },
- {
- name: I18n.tr("Sunset"),
- start: new Date(times.sunsetStart),
- end: new Date(times.sunset)
- },
- {
- name: I18n.tr("Dusk (Civil Twighlight)"),
- start: new Date(times.sunset),
- end: new Date(times.dusk)
- },
- {
- name: I18n.tr("Dusk (Nautical Twilight)"),
- start: new Date(times.dusk),
- end: new Date(times.nauticalDusk)
- },
- {
- name: I18n.tr("Dusk (Astronomical Twilight)"),
- start: new Date(times.nauticalDusk),
- end: new Date(times.night)
- },
- ];
-
- const sunrise = new Date(times.nightEnd);
- const sunset = new Date(times.night);
- const dayPercent = dateObj > sunrise && dateObj < sunset ? (dateObj - sunrise) / (sunset - sunrise) : 0;
-
- for (let i = 0; i < periods.length; i++) {
- const {
- name,
- start,
- end
- } = periods[i];
- if (dateObj >= start && dateObj < end) {
- const percent = (dateObj - start) / (end - start);
- return {
- period: name,
- periodIndex: i,
- periodPercent: Math.min(Math.max(percent, 0), 1),
- dayPercent: dayPercent
- };
- }
- }
-
- return {
- period: I18n.tr("Night"),
- periodIndex: 0,
- periodPercent: 0,
- dayPercent: dayPercent
- };
- }
-
- function getSkyArcPosition(date, isSun) {
- if (!location) {
- return null;
- }
- const lat = location.latitude;
- const lon = location.longitude;
-
- const pos = isSun ? SunCalc.getPosition(date, lat, lon) : SunCalc.getMoonPosition(date, lat, lon);
-
- const sunIsNorth = getSunDeclination(date) > lat;
- const transitAzimuth = sunIsNorth ? 0 : Math.PI;
-
- let h = (((pos.azimuth - transitAzimuth) / (2 * Math.PI)) + 1) % 1;
- h = Math.max(0, Math.min(1, h));
- // let v = pos.altitude / (Math.PI/2)
- let v = Math.sin(pos.altitude);
- v = Math.max(-1, Math.min(1, v));
-
- return {
- h,
- v
- };
- }
-
- function formatTemp(celsius, includeUnits = true, unitsShort = true) {
- if (celsius == null) {
- return null;
- }
- const value = SettingsData.useFahrenheit ? Math.round(celsius * (9 / 5) + 32) : celsius;
- const unit = unitsShort ? "°" : (SettingsData.useFahrenheit ? "°F" : "°C");
- return includeUnits ? value + unit : value;
- }
-
- function formatSpeed(kmh, includeUnits = true) {
- if (kmh == null) {
- return null;
- }
- if (SettingsData.useFahrenheit) {
- const value = Math.round(kmh * 0.621371);
- return includeUnits ? value + " mph" : value;
- }
- if (SettingsData.windSpeedUnit === "ms") {
- const value = (kmh / 3.6).toFixed(1);
- return includeUnits ? value + " m/s" : value;
- }
- return includeUnits ? kmh + " km/h" : kmh;
- }
-
- function formatPressure(hpa, includeUnits = true) {
- if (hpa == null) {
- return null;
- }
- const value = SettingsData.useFahrenheit ? (hpa * 0.02953).toFixed(2) : hpa;
- const unit = SettingsData.useFahrenheit ? "inHg" : "hPa";
- return includeUnits ? value + " " + unit : value;
- }
-
- function formatPercent(percent, includeUnits = true) {
- if (percent == null) {
- return null;
- }
- const value = percent;
- const unit = "%";
- return includeUnits ? value + unit : value;
- }
-
- function formatVisibility(distance) {
- if (distance == null) {
- return null;
- }
- var value;
- var unit;
- if (SettingsData.useFahrenheit) {
- value = (distance / 1609.344).toFixed(1);
- unit = "mi";
- if (value < 1) {
- value = Math.round(value * 5280 / 50) * 50;
- unit = "ft";
- }
- } else {
- value = distance;
- unit = "m";
- if (value > 1000) {
- value = (value / 1000).toFixed(1);
- unit = "km";
- }
- }
-
- return value + " " + unit;
- }
-
- function formatTime(isoString) {
- if (!isoString)
- return "--";
-
- try {
- const date = new Date(isoString);
- const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP";
- return date.toLocaleTimeString(Qt.locale(), format);
- } catch (e) {
- return "--";
- }
- }
-
- function calendarDayDifference(date1, date2) {
- const d1 = Date.UTC(date1.getFullYear(), date1.getMonth(), date1.getDate());
- const d2 = Date.UTC(date2.getFullYear(), date2.getMonth(), date2.getDate());
- return Math.floor((d2 - d1) / (1000 * 60 * 60 * 24));
- }
-
- function calendarHourDifference(date1, date2) {
- const d1 = Date.UTC(date1.getFullYear(), date1.getMonth(), date1.getDate(), date1.getHours());
- const d2 = Date.UTC(date2.getFullYear(), date2.getMonth(), date2.getDate(), date2.getHours());
- return Math.floor((d2 - d1) / (1000 * 60 * 60));
- }
-
- function formatForecastDay(isoString, index) {
- if (!isoString)
- return "--";
-
- if (index === 0)
- return I18n.tr("Today");
- if (index === 1)
- return I18n.tr("Tomorrow");
-
- const date = new Date();
- date.setDate(date.getDate() + index);
- const locale = I18n.locale();
- return locale.dayName(date.getDay(), Locale.ShortFormat);
- }
-
- function getWeatherApiUrl() {
- if (!location) {
- return null;
- }
-
- const params = ["latitude=" + location.latitude, "longitude=" + location.longitude, "current=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,precipitation,weather_code,surface_pressure,wind_speed_10m", "daily=sunrise,sunset,temperature_2m_max,temperature_2m_min,weather_code,precipitation_probability_max", "hourly=temperature_2m,weather_code,precipitation_probability,wind_speed_10m,apparent_temperature,relative_humidity_2m,surface_pressure,visibility,cloud_cover", "timezone=auto", "forecast_days=7"];
-
- return "https://api.open-meteo.com/v1/forecast?" + params.join('&');
- }
-
- function getGeocodingUrl(query) {
- return "https://geocoding-api.open-meteo.com/v1/search?name=" + encodeURIComponent(query) + "&count=1&language=en&format=json";
- }
-
- function addRef() {
- refCount++;
-
- if (refCount === 1 && !weather.available && SettingsData.weatherEnabled) {
- fetchWeather();
- }
- }
-
- function removeRef() {
- refCount = Math.max(0, refCount - 1);
- }
-
- function updateLocation() {
- const useAuto = SessionData.isGreeterMode ? GreetdSettings.useAutoLocation : SettingsData.useAutoLocation;
- const coords = SessionData.isGreeterMode ? GreetdSettings.weatherCoordinates : SettingsData.weatherCoordinates;
- const cityName = SessionData.isGreeterMode ? GreetdSettings.weatherLocation : SettingsData.weatherLocation;
-
- if (useAuto) {
- getLocationFromService();
- return;
- }
-
- if (coords) {
- const parts = coords.split(",");
- if (parts.length === 2) {
- const lat = parseFloat(parts[0]);
- const lon = parseFloat(parts[1]);
- if (!isNaN(lat) && !isNaN(lon)) {
- getLocationFromCoords(lat, lon);
- return;
- }
- }
- }
-
- if (cityName)
- getLocationFromCity(cityName);
- }
-
- function getLocationFromCoords(lat, lon) {
- const url = "https://nominatim.openstreetmap.org/reverse?lat=" + lat + "&lon=" + lon + "&format=json&addressdetails=1&accept-language=en";
- reverseGeocodeFetcher.command = lowPriorityCmd.concat(curlBaseCmd).concat(["-H", "User-Agent: DankMaterialShell Weather Widget", url]);
- reverseGeocodeFetcher.running = true;
- }
-
- function getLocationFromCity(city) {
- cityGeocodeFetcher.command = lowPriorityCmd.concat(curlBaseCmd).concat([getGeocodingUrl(city)]);
- cityGeocodeFetcher.running = true;
- }
-
- function getLocationFromService() {
- if (!LocationService.valid)
- return;
- getLocationFromCoords(LocationService.latitude, LocationService.longitude);
- }
-
- function fetchWeather() {
- if (root.refCount === 0 || !SettingsData.weatherEnabled) {
- return;
- }
-
- if (!location) {
- updateLocation();
- return;
- }
-
- if (weatherFetcher.running) {
- return;
- }
-
- const now = Date.now();
- if (now - root.lastFetchTime < root.minFetchInterval) {
- return;
- }
-
- const apiUrl = getWeatherApiUrl();
- if (!apiUrl) {
- return;
- }
-
- root.lastFetchTime = now;
- root.weather.loading = true;
- const weatherCmd = lowPriorityCmd.concat(["curl", "-sS", "--fail", "--connect-timeout", "3", "--max-time", "6", "--limit-rate", "150k", "--compressed"]);
- weatherFetcher.command = weatherCmd.concat([apiUrl]);
- weatherFetcher.running = true;
- }
-
- function forceRefresh() {
- root.lastFetchTime = 0; // Reset throttle
- fetchWeather();
- }
-
- function nextInterval() {
- const jitter = Math.floor(Math.random() * 15000) - 7500;
- return Math.max(60000, root.updateInterval + jitter);
- }
-
- function handleWeatherSuccess() {
- root.retryAttempts = 0;
- root.persistentRetryCount = 0;
- if (persistentRetryTimer.running) {
- persistentRetryTimer.stop();
- }
- if (updateTimer.interval !== root.updateInterval) {
- updateTimer.interval = root.updateInterval;
- }
- }
-
- function handleWeatherFailure() {
- root.retryAttempts++;
- if (root.retryAttempts < root.maxRetryAttempts) {
- retryTimer.start();
- } else {
- root.retryAttempts = 0;
- if (!root.weather.available) {
- root.weather.loading = false;
- }
- const backoffDelay = Math.min(60000 * Math.pow(2, persistentRetryCount), 300000);
- persistentRetryCount++;
- persistentRetryTimer.interval = backoffDelay;
- persistentRetryTimer.start();
- }
- }
-
- Process {
- id: reverseGeocodeFetcher
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const raw = text.trim();
- if (!raw || raw[0] !== "{") {
- root.handleWeatherFailure();
- return;
- }
-
- try {
- const data = JSON.parse(raw);
- const address = data.address || {};
-
- root.location = {
- city: address.hamlet || address.city || address.town || address.village || I18n.tr("Unknown"),
- country: address.country || I18n.tr("Unknown"),
- latitude: parseFloat(data.lat),
- longitude: parseFloat(data.lon)
- };
-
- fetchWeather();
- } catch (e) {
- root.handleWeatherFailure();
- }
- }
- }
-
- onExited: exitCode => {
- if (exitCode !== 0) {
- root.handleWeatherFailure();
- }
- }
- }
-
- Process {
- id: cityGeocodeFetcher
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const raw = text.trim();
- if (!raw || raw[0] !== "{") {
- root.handleWeatherFailure();
- return;
- }
-
- try {
- const data = JSON.parse(raw);
- const results = data.results;
-
- if (!results || results.length === 0) {
- throw new Error("No results found");
- }
-
- const result = results[0];
-
- root.location = {
- city: result.name,
- country: result.country,
- latitude: result.latitude,
- longitude: result.longitude,
- elevation: data.elevation
- };
-
- fetchWeather();
- } catch (e) {
- root.handleWeatherFailure();
- }
- }
- }
-
- onExited: exitCode => {
- if (exitCode !== 0) {
- root.handleWeatherFailure();
- }
- }
- }
-
- Process {
- id: weatherFetcher
- running: false
-
- stdout: StdioCollector {
- onStreamFinished: {
- const raw = text.trim();
- if (!raw || raw[0] !== "{") {
- root.handleWeatherFailure();
- return;
- }
-
- try {
- const data = JSON.parse(raw);
-
- if (!data.current || !data.daily || !data.hourly) {
- throw new Error("Required weather data fields missing");
- }
-
- const hourly = data.hourly;
- const hourly_forecast = [];
- if (hourly.time && hourly.time.length > 0) {
- for (let i = 0; i < hourly.time.length; i++) {
- const tempMinC = hourly.temperature_2m_min?.[i] || 0;
- const tempMaxC = hourly.temperature_2m_max?.[i] || 0;
- const tempMinF = tempMinC * 9 / 5 + 32;
- const tempMaxF = tempMaxC * 9 / 5 + 32;
-
- const tempC = hourly.temperature_2m?.[i] || 0;
- const tempF = tempC * 9 / 5 + 32;
- const feelsLikeC = hourly.apparent_temperature?.[i] || tempC;
- const feelsLikeF = feelsLikeC * 9 / 5 + 32;
-
- const sunrise = new Date(data.daily.sunrise?.[Math.floor(i / 24)]);
- const sunset = new Date(data.daily.sunset?.[Math.floor(i / 24)]);
- const time = new Date(hourly.time[i]);
- const isDay = sunrise < time && time < sunset;
-
- hourly_forecast.push({
- "time": formatTime(hourly.time[i]),
- "rawTime": hourly.time[i],
- "temp": Math.round(tempC),
- "tempF": Math.round(tempF),
- "feelsLike": Math.round(feelsLikeC),
- "feelsLikeF": Math.round(feelsLikeF),
- "wCode": hourly.weather_code?.[i] || 0,
- "humidity": Math.round(hourly.relative_humidity_2m?.[i] || 0),
- "wind": Math.round(hourly.wind_speed_10m?.[i] || 0),
- "pressure": Math.round(hourly.surface_pressure?.[i] || 0),
- "precipitationProbability": Math.round(hourly.precipitation_probability?.[i] || 0),
- "visibility": Math.round(hourly.visibility?.[i] || 0),
- "isDay": isDay
- });
- }
- }
-
- const daily = data.daily;
- const forecast = [];
- if (daily.time && daily.time.length > 0) {
- for (let i = 0; i < daily.time.length; i++) {
- const tempMinC = daily.temperature_2m_min?.[i] || 0;
- const tempMaxC = daily.temperature_2m_max?.[i] || 0;
- const tempMinF = (tempMinC * 9 / 5 + 32);
- const tempMaxF = (tempMaxC * 9 / 5 + 32);
-
- forecast.push({
- "day": formatForecastDay(daily.time[i], i),
- "wCode": daily.weather_code?.[i] || 0,
- "tempMin": Math.round(tempMinC),
- "tempMax": Math.round(tempMaxC),
- "tempMinF": Math.round(tempMinF),
- "tempMaxF": Math.round(tempMaxF),
- "precipitationProbability": Math.round(daily.precipitation_probability_max?.[i] || 0),
- "sunrise": daily.sunrise?.[i] ? formatTime(daily.sunrise[i]) : "",
- "sunset": daily.sunset?.[i] ? formatTime(daily.sunset[i]) : "",
- "rawSunrise": daily.sunrise?.[i] || "",
- "rawSunset": daily.sunset?.[i] || ""
- });
- }
- }
-
- const current = data.current;
- const currentUnits = data.current_units || {};
-
- const tempC = current.temperature_2m || 0;
- const tempF = tempC * 9 / 5 + 32;
- const feelsLikeC = current.apparent_temperature || tempC;
- const feelsLikeF = feelsLikeC * 9 / 5 + 32;
-
- root.weather = {
- "available": true,
- "loading": false,
- "temp": Math.round(tempC),
- "tempF": Math.round(tempF),
- "feelsLike": Math.round(feelsLikeC),
- "feelsLikeF": Math.round(feelsLikeF),
- "city": root.location?.city || I18n.tr("Unknown"),
- "country": root.location?.country || I18n.tr("Unknown"),
- "wCode": current.weather_code || 0,
- "humidity": Math.round(current.relative_humidity_2m || 0),
- "wind": Math.round(current.wind_speed_10m || 0),
- "sunrise": formatTime(daily.sunrise?.[0]) || "06:00",
- "sunset": formatTime(daily.sunset?.[0]) || "18:00",
- "rawSunrise": daily.sunrise?.[0] || "",
- "rawSunset": daily.sunset?.[0] || "",
- "uv": 0,
- "pressure": Math.round(current.surface_pressure || 0),
- "precipitationProbability": Math.round(daily.precipitation_probability_max?.[0] || 0),
- "isDay": Boolean(current.is_day),
- "forecast": forecast,
- "hourlyForecast": hourly_forecast
- };
- root.handleWeatherSuccess();
- } catch (e) {
- root.handleWeatherFailure();
- }
- }
- }
-
- onExited: exitCode => {
- if (exitCode !== 0) {
- root.handleWeatherFailure();
- }
- }
- }
-
- Timer {
- id: updateTimer
- interval: nextInterval()
- running: root.refCount > 0 && SettingsData.weatherEnabled && !SessionData.isGreeterMode
- repeat: true
- triggeredOnStart: true
- onTriggered: {
- root.fetchWeather();
- interval = nextInterval();
- }
- }
-
- Timer {
- id: retryTimer
- interval: root.retryDelay
- running: false
- repeat: false
- onTriggered: {
- root.fetchWeather();
- }
- }
-
- Timer {
- id: persistentRetryTimer
- interval: 60000
- running: false
- repeat: false
- onTriggered: {
- if (!root.weather.available) {
- root.weather.loading = true;
- }
- root.fetchWeather();
- }
- }
-
- Connections {
- target: LocationService
-
- function onLocationChanged(data) {
- if (!SettingsData.useAutoLocation)
- return;
- if (data.latitude === 0 && data.longitude === 0)
- return;
- root.getLocationFromCoords(data.latitude, data.longitude);
- }
- }
-
- Component.onCompleted: {
- SettingsData.weatherCoordinatesChanged.connect(() => {
- root.location = null;
- root.weather = {
- "available": false,
- "loading": true,
- "temp": 0,
- "tempF": 0,
- "feelsLike": 0,
- "feelsLikeF": 0,
- "city": "",
- "country": "",
- "wCode": 0,
- "humidity": 0,
- "wind": "",
- "sunrise": "06:00",
- "sunset": "18:00",
- "uv": 0,
- "pressure": 0,
- "precipitationProbability": 0,
- "isDay": true,
- "forecast": []
- };
- root.lastFetchTime = 0;
- root.forceRefresh();
- });
-
- SettingsData.weatherLocationChanged.connect(() => {
- root.location = null;
- root.lastFetchTime = 0;
- root.forceRefresh();
- });
-
- SettingsData.useAutoLocationChanged.connect(() => {
- root.location = null;
- root.weather = {
- "available": false,
- "loading": true,
- "temp": 0,
- "tempF": 0,
- "feelsLike": 0,
- "feelsLikeF": 0,
- "city": "",
- "country": "",
- "wCode": 0,
- "humidity": 0,
- "wind": "",
- "sunrise": "06:00",
- "sunset": "18:00",
- "uv": 0,
- "pressure": 0,
- "precipitationProbability": 0,
- "isDay": true,
- "forecast": []
- };
- root.lastFetchTime = 0;
- root.forceRefresh();
- });
-
- SettingsData.weatherEnabledChanged.connect(() => {
- if (SettingsData.weatherEnabled && root.refCount > 0 && !root.weather.available) {
- root.forceRefresh();
- } else if (!SettingsData.weatherEnabled) {
- updateTimer.stop();
- retryTimer.stop();
- persistentRetryTimer.stop();
- if (weatherFetcher.running) {
- weatherFetcher.running = false;
- }
- }
- });
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/WlrOutputService.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/WlrOutputService.qml
deleted file mode 100644
index 655a485..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/WlrOutputService.qml
+++ /dev/null
@@ -1,346 +0,0 @@
-pragma Singleton
-pragma ComponentBehavior: Bound
-
-import QtQuick
-import Quickshell
-
-Singleton {
- id: root
-
- property bool wlrOutputAvailable: false
- property var outputs: []
- property int serial: 0
-
- signal stateChanged
- signal configurationApplied(bool success, string message)
-
- Connections {
- target: DMSService
-
- function onCapabilitiesReceived() {
- checkCapabilities();
- }
-
- function onConnectionStateChanged() {
- if (DMSService.isConnected) {
- checkCapabilities();
- return;
- }
- wlrOutputAvailable = false;
- }
-
- function onWlrOutputStateUpdate(data) {
- if (!wlrOutputAvailable) {
- return;
- }
- handleStateUpdate(data);
- }
- }
-
- Component.onCompleted: {
- if (!DMSService.dmsAvailable) {
- return;
- }
- checkCapabilities();
- }
-
- function checkCapabilities() {
- if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) {
- wlrOutputAvailable = false;
- return;
- }
-
- const hasWlrOutput = DMSService.capabilities.includes("wlroutput");
- if (hasWlrOutput && !wlrOutputAvailable) {
- wlrOutputAvailable = true;
- console.info("WlrOutputService: wlr-output-management capability detected");
- requestState();
- return;
- }
-
- if (!hasWlrOutput) {
- wlrOutputAvailable = false;
- }
- }
-
- function requestState() {
- if (!DMSService.isConnected || !wlrOutputAvailable) {
- return;
- }
-
- DMSService.sendRequest("wlroutput.getState", null, response => {
- if (!response.result) {
- return;
- }
- handleStateUpdate(response.result);
- });
- }
-
- function handleStateUpdate(state) {
- outputs = state.outputs || [];
- serial = state.serial || 0;
-
- if (outputs.length === 0) {
- console.warn("WlrOutputService: Received empty outputs list");
- } else {
- console.log("WlrOutputService: Updated with", outputs.length, "outputs, serial:", serial);
- outputs.forEach((output, index) => {
- console.log("WlrOutputService: Output", index, "-", output.name, "enabled:", output.enabled, "mode:", output.currentMode ? output.currentMode.width + "x" + output.currentMode.height + "@" + (output.currentMode.refresh / 1000) + "Hz" : "none");
- });
- }
- stateChanged();
- }
-
- function getOutput(name) {
- for (const output of outputs) {
- if (output.name === name) {
- return output;
- }
- }
- return null;
- }
-
- function getEnabledOutputs() {
- return outputs.filter(output => output.enabled);
- }
-
- function applyConfiguration(heads, callback) {
- if (!DMSService.isConnected || !wlrOutputAvailable) {
- if (callback) {
- callback(false, "Not connected");
- }
- return;
- }
-
- console.log("WlrOutputService: Applying configuration for", heads.length, "outputs");
- heads.forEach((head, index) => {
- console.log("WlrOutputService: Head", index, "- name:", head.name, "enabled:", head.enabled, "modeId:", head.modeId, "customMode:", JSON.stringify(head.customMode), "position:", JSON.stringify(head.position), "scale:", head.scale, "transform:", head.transform, "adaptiveSync:", head.adaptiveSync);
- });
-
- DMSService.sendRequest("wlroutput.applyConfiguration", {
- "heads": heads
- }, response => {
- const success = !response.error;
- const message = response.error || response.result?.message || "";
-
- if (response.error) {
- console.warn("WlrOutputService: applyConfiguration error:", response.error);
- } else {
- console.log("WlrOutputService: Configuration applied successfully");
- }
-
- configurationApplied(success, message);
- if (callback) {
- callback(success, message);
- }
- });
- }
-
- function testConfiguration(heads, callback) {
- if (!DMSService.isConnected || !wlrOutputAvailable) {
- if (callback) {
- callback(false, "Not connected");
- }
- return;
- }
-
- console.log("WlrOutputService: Testing configuration for", heads.length, "outputs");
-
- DMSService.sendRequest("wlroutput.testConfiguration", {
- "heads": heads
- }, response => {
- const success = !response.error;
- const message = response.error || response.result?.message || "";
-
- if (response.error) {
- console.warn("WlrOutputService: testConfiguration error:", response.error);
- } else {
- console.log("WlrOutputService: Configuration test passed");
- }
-
- if (callback) {
- callback(success, message);
- }
- });
- }
-
- function setOutputEnabled(outputName, enabled, callback) {
- const output = getOutput(outputName);
- if (!output) {
- console.warn("WlrOutputService: Output not found:", outputName);
- if (callback) {
- callback(false, "Output not found");
- }
- return;
- }
-
- const heads = [
- {
- "name": outputName,
- "enabled": enabled
- }
- ];
-
- if (enabled && output.currentMode) {
- heads[0].modeId = output.currentMode.id;
- }
-
- applyConfiguration(heads, callback);
- }
-
- function setOutputMode(outputName, modeId, callback) {
- const heads = [
- {
- "name": outputName,
- "enabled": true,
- "modeId": modeId
- }
- ];
-
- applyConfiguration(heads, callback);
- }
-
- function setOutputCustomMode(outputName, width, height, refresh, callback) {
- const heads = [
- {
- "name": outputName,
- "enabled": true,
- "customMode": {
- "width": width,
- "height": height,
- "refresh": refresh
- }
- }
- ];
-
- applyConfiguration(heads, callback);
- }
-
- function setOutputPosition(outputName, x, y, callback) {
- const heads = [
- {
- "name": outputName,
- "enabled": true,
- "position": {
- "x": x,
- "y": y
- }
- }
- ];
-
- applyConfiguration(heads, callback);
- }
-
- function setOutputScale(outputName, scale, callback) {
- const heads = [
- {
- "name": outputName,
- "enabled": true,
- "scale": scale
- }
- ];
-
- applyConfiguration(heads, callback);
- }
-
- function setOutputTransform(outputName, transform, callback) {
- const heads = [
- {
- "name": outputName,
- "enabled": true,
- "transform": transform
- }
- ];
-
- applyConfiguration(heads, callback);
- }
-
- function setOutputAdaptiveSync(outputName, state, callback) {
- const heads = [
- {
- "name": outputName,
- "enabled": true,
- "adaptiveSync": state
- }
- ];
-
- applyConfiguration(heads, callback);
- }
-
- function configureOutput(config, callback) {
- const heads = [config];
- applyConfiguration(heads, callback);
- }
-
- function configureMultipleOutputs(configs, callback) {
- applyConfiguration(configs, callback);
- }
-
- // High-level apply matching the generateOutputsConfig() pattern used by
- // NiriService, HyprlandService and DwlService. Instead of writing a
- // config file, the changes are applied directly via the
- // wlr-output-management protocol.
- function applyOutputsConfig(outputsData, connectedOutputs) {
- if (!wlrOutputAvailable)
- return;
- const heads = [];
- for (const name in outputsData) {
- if (!connectedOutputs[name])
- continue;
- const output = outputsData[name];
- const mode = (output.modes && output.current_mode >= 0) ? output.modes[output.current_mode] : null;
- const enabled = !!mode;
- const head = {
- "name": name,
- "enabled": enabled
- };
-
- if (enabled) {
- if (mode.id !== undefined)
- head.modeId = mode.id;
- else
- head.customMode = {
- "width": mode.width,
- "height": mode.height,
- "refresh": mode.refresh_rate
- };
-
- if (output.logical) {
- head.position = {
- "x": output.logical.x ?? 0,
- "y": output.logical.y ?? 0
- };
- head.scale = output.logical.scale ?? 1.0;
- head.transform = transformFromName(output.logical.transform);
- }
- }
- heads.push(head);
- }
-
- if (heads.length > 0)
- applyConfiguration(heads);
- }
-
- function transformFromName(name) {
- switch (name) {
- case "Normal":
- return 0;
- case "90":
- return 1;
- case "180":
- return 2;
- case "270":
- return 3;
- case "Flipped":
- return 4;
- case "Flipped90":
- return 5;
- case "Flipped180":
- return 6;
- case "Flipped270":
- return 7;
- default:
- return 0;
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/niri-wpblur.kdl b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/niri-wpblur.kdl
deleted file mode 100644
index 3d58802..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Services/niri-wpblur.kdl
+++ /dev/null
@@ -1,9 +0,0 @@
-// ! DO NOT EDIT !
-// ! AUTO-GENERATED BY DMS !
-// ! CHANGES WILL BE OVERWRITTEN !
-// ! PLACE YOUR CUSTOM CONFIGURATION ELSEWHERE !
-
-layer-rule {
- match namespace="dms:blurwallpaper"
- place-within-backdrop true
-}