From c67b1850765c0263e87973af8d81f54b89dfd1b4 Mon Sep 17 00:00:00 2001
From: bbedward $1
');
html = html.replace(/^## (.*?)$/gm, '$1
');
html = html.replace(/^# (.*?)$/gm, '$1
');
@@ -58,20 +50,16 @@ function markdownToHtml(text) {
html = html.replace(/__(.*?)__/g, '$1');
html = html.replace(/_(.*?)_/g, '$1');
- // Links
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1');
- // Lists
html = html.replace(/^\* (.*?)$/gm, '' + match + '
';
});
- // Restore extracted URLs as anchor tags (preserves raw & in href)
html = html.replace(/\x00URL(\d+)\x00/g, (_, index) => {
const url = urls[parseInt(index)];
const display = url.replace(/&/g, '&').replace(//g, '>');
@@ -87,30 +75,23 @@ function markdownToHtml(text) {
return inlineCode[parseInt(index)];
});
- // Line breaks (after code blocks are restored)
html = html.replace(/\n\n/g, '
');
html = html.replace(/\n/g, '
');
- // Wrap in paragraph tags if not already wrapped
if (!html.startsWith('<')) {
html = '
' + html + '
'; } - // Clean up the final HTML - // Remove/g, '');
html = html.replace(/
\s*\s*<\/p>/g, ''); html = html.replace(/
\s*
\s*<\/p>/g, '');
- // Remove excessive line breaks
- html = html.replace(/(
){3,}/g, '
'); // Max 2 consecutive line breaks
- html = html.replace(/(<\/p>)\s*(
)/g, '$1$2'); // Remove whitespace between paragraphs
+ html = html.replace(/(
){3,}/g, '
');
+ html = html.replace(/(<\/p>)\s*(
)/g, '$1$2');
- // Remove leading/trailing whitespace
html = html.trim();
return html;
diff --git a/quickshell/Common/settings/Processes.qml b/quickshell/Common/settings/Processes.qml
index 4af5a8f68..992d23001 100644
--- a/quickshell/Common/settings/Processes.qml
+++ b/quickshell/Common/settings/Processes.qml
@@ -5,11 +5,13 @@ import QtQuick
import Quickshell
import Quickshell.Io
import qs.Common
-import qs.Services
Singleton {
id: root
+ signal toastRequested(int severity, string title, string body, string command, string category)
+ signal toastCategoryDismissed(string category)
+
property var settingsRoot: null
onSettingsRootChanged: {
@@ -317,7 +319,7 @@ Singleton {
function launchAuthApplyTerminalFallback(fromPrecheck, details) {
authApplyTerminalFallbackFromPrecheck = fromPrecheck;
if (details && details !== "")
- ToastService.showInfo(I18n.tr("Authentication changes need sudo. Opening terminal so you can use password or fingerprint."), details, "", "auth-sync");
+ toastRequested(0, I18n.tr("Authentication changes need sudo. Opening terminal so you can use password or fingerprint."), details, "", "auth-sync");
authApplyTerminalFallbackStderr = "";
authApplyTerminalFallbackProcess.running = true;
}
@@ -364,21 +366,21 @@ Singleton {
}
function deferGreeterAutoLoginSyncToPill(details) {
- ToastService.dismissCategory("greeter-autologin-sync");
+ toastCategoryDismissed("greeter-autologin-sync");
if (settingsRoot)
settingsRoot.set("greeterSyncPending", true);
- ToastService.showWarning(I18n.tr("Auto-login change needs a sync"), I18n.tr("Administrator access is required. Use the Sync button in Settings → Greeter to apply.") + (details ? "\n\n" + details : ""), "dms-greeter sync --autologin", "greeter-autologin-sync");
+ toastRequested(1, I18n.tr("Auto-login change needs a sync"), I18n.tr("Administrator access is required. Use the Sync button in Settings → Greeter to apply.") + (details ? "\n\n" + details : ""), "dms-greeter sync --autologin", "greeter-autologin-sync");
finishGreeterAutoLoginSync();
}
function greeterAutoLoginSyncSuccessToast(details) {
const enabling = settingsRoot && settingsRoot.greeterAutoLogin;
// Clear the sticky in-progress toast, then confirm with an auto-dismissing toast.
- ToastService.dismissCategory("greeter-autologin-sync");
+ toastCategoryDismissed("greeter-autologin-sync");
if (enabling) {
- ToastService.showWarning(I18n.tr("Auto-login enabled"), I18n.tr("You'll skip the greeter password after the next reboot. The lock screen and signing out still require your password.") + (details ? "\n\n" + details : ""));
+ toastRequested(1, I18n.tr("Auto-login enabled"), I18n.tr("You'll skip the greeter password after the next reboot. The lock screen and signing out still require your password.") + (details ? "\n\n" + details : ""), "", "");
} else {
- ToastService.showInfo(I18n.tr("Auto-login disabled"), I18n.tr("You'll enter your password at the greeter after the next reboot.") + (details ? "\n\n" + details : ""));
+ toastRequested(0, I18n.tr("Auto-login disabled"), I18n.tr("You'll enter your password at the greeter after the next reboot.") + (details ? "\n\n" + details : ""), "", "");
}
}
@@ -575,7 +577,7 @@ Singleton {
onExited: exitCode => {
const enabling = root.settingsRoot && root.settingsRoot.greeterAutoLogin;
if (exitCode === 0) {
- ToastService.showWarning(enabling ? I18n.tr("Applying auto-login on startup...") : I18n.tr("Disabling auto-login on startup..."), "", "dms-greeter sync --autologin", "greeter-autologin-sync");
+ root.toastRequested(1, enabling ? I18n.tr("Applying auto-login on startup...") : I18n.tr("Disabling auto-login on startup..."), "", "dms-greeter sync --autologin", "greeter-autologin-sync");
root.greeterAutoLoginSyncProcess.running = true;
return;
}
@@ -604,7 +606,7 @@ Singleton {
let details = out;
if (err !== "")
details = details !== "" ? details + "\n\nstderr:\n" + err : "stderr:\n" + err;
- ToastService.showInfo(I18n.tr("Authentication changes applied"), details, "", "auth-sync");
+ root.toastRequested(0, I18n.tr("Authentication changes applied"), details, "", "auth-sync");
root.detectAuthCapabilities();
root.finishAuthApply();
return;
@@ -615,7 +617,7 @@ Singleton {
details = out;
if (err !== "")
details = details !== "" ? details + "\n\nstderr:\n" + err : "stderr:\n" + err;
- ToastService.showWarning(I18n.tr("Background authentication sync failed. Trying terminal mode."), details, "", "auth-sync");
+ root.toastRequested(1, I18n.tr("Background authentication sync failed. Trying terminal mode."), details, "", "auth-sync");
root.launchAuthApplyTerminalFallback(false, "");
}
}
@@ -631,7 +633,7 @@ Singleton {
onExited: exitCode => {
const err = (root.authApplySudoProbeStderr || "").trim();
if (exitCode === 0) {
- ToastService.showInfo(I18n.tr("Applying authentication changes..."), "", "", "auth-sync");
+ root.toastRequested(0, I18n.tr("Applying authentication changes..."), "", "", "auth-sync");
root.authApplyProcess.running = true;
return;
}
@@ -651,10 +653,10 @@ Singleton {
onExited: exitCode => {
if (exitCode === 0) {
const message = root.authApplyTerminalFallbackFromPrecheck ? I18n.tr("Terminal opened. Complete authentication there; it will close automatically when done.") : I18n.tr("Terminal fallback opened. Complete authentication there; it will close automatically when done.");
- ToastService.showInfo(message, "", "", "auth-sync");
+ root.toastRequested(0, message, "", "", "auth-sync");
} else {
let details = (root.authApplyTerminalFallbackStderr || "").trim();
- ToastService.showError(I18n.tr("Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.") + " (exit " + exitCode + ")", details, "", "auth-sync");
+ root.toastRequested(2, I18n.tr("Terminal fallback failed. Install a supported terminal emulator or run 'dms auth sync' manually.") + " (exit " + exitCode + ")", details, "", "auth-sync");
}
root.finishAuthApply();
}
diff --git a/quickshell/Common/settings/SessionStore.js b/quickshell/Common/settings/SessionStore.js
index c1e21906e..7fcdb65fe 100644
--- a/quickshell/Common/settings/SessionStore.js
+++ b/quickshell/Common/settings/SessionStore.js
@@ -75,26 +75,3 @@ function migrateToVersion(obj, targetVersion, settingsData) {
return session;
}
-
-function cleanup(fileText) {
- var getValidKeys = SpecModule.getValidKeys;
- if (!fileText || !fileText.trim()) return null;
-
- try {
- var session = JSON.parse(fileText);
- var validKeys = getValidKeys();
- var needsSave = false;
-
- for (var key in session) {
- if (validKeys.indexOf(key) < 0) {
- delete session[key];
- needsSave = true;
- }
- }
-
- return needsSave ? JSON.stringify(session, null, 2) : null;
- } catch (e) {
- console.warn("SessionData: Failed to cleanup unused keys:", e.message);
- return null;
- }
-}
diff --git a/quickshell/Common/settings/SettingsStore.js b/quickshell/Common/settings/SettingsStore.js
index 1a4720831..e10ad9527 100644
--- a/quickshell/Common/settings/SettingsStore.js
+++ b/quickshell/Common/settings/SettingsStore.js
@@ -291,26 +291,3 @@ function migrateToVersion(obj, targetVersion) {
return settings;
}
-
-function cleanup(fileText) {
- var getValidKeys = SpecModule.getValidKeys;
- if (!fileText || !fileText.trim()) return;
-
- try {
- var settings = JSON.parse(fileText);
- var validKeys = getValidKeys();
- var needsSave = false;
-
- for (var key in settings) {
- if (validKeys.indexOf(key) < 0) {
- delete settings[key];
- needsSave = true;
- }
- }
-
- return needsSave ? JSON.stringify(settings, null, 2) : null;
- } catch (e) {
- console.warn("SettingsData: Failed to cleanup unused keys:", e.message);
- return null;
- }
-}
diff --git a/quickshell/Common/suncalc.js b/quickshell/Common/suncalc.js
index db55b9a34..a3dda81a4 100644
--- a/quickshell/Common/suncalc.js
+++ b/quickshell/Common/suncalc.js
@@ -122,11 +122,6 @@ const times = [
// adds a custom time to the times config
-function addTime(angle, riseName, setName) {
- times.push([angle, riseName, setName]);
-};
-
-
// calculations for sun times
const J0 = 0.0009;
@@ -246,63 +241,3 @@ function getMoonIllumination(date) {
angle
};
};
-
-
-function hoursLater(date, h) {
- return new Date(date.valueOf() + h * dayMs / 24);
-}
-
-// calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article
-
-function getMoonTimes(date, lat, lng, inUTC) {
- const t = new Date(date);
- if (inUTC) t.setUTCHours(0, 0, 0, 0);
- else t.setHours(0, 0, 0, 0);
-
- const hc = 0.133 * rad;
- let h0 = getMoonPosition(t, lat, lng).altitude - hc,
- rise, set, ye;
-
- // go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set)
- for (let i = 1; i <= 24; i += 2) {
- const h1 = getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc;
- const h2 = getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc;
- const a = (h0 + h2) / 2 - h1;
- const b = (h2 - h0) / 2;
- const xe = -b / (2 * a);
- const d = b * b - 4 * a * h1;
- let roots = 0, x1 = 0, x2 = 0;
- ye = (a * xe + b) * xe + h1;
-
- if (d >= 0) {
- const dx = Math.sqrt(d) / (Math.abs(a) * 2);
- x1 = xe - dx;
- x2 = xe + dx;
- if (Math.abs(x1) <= 1) roots++;
- if (Math.abs(x2) <= 1) roots++;
- if (x1 < -1) x1 = x2;
- }
-
- if (roots === 1) {
- if (h0 < 0) rise = i + x1;
- else set = i + x1;
-
- } else if (roots === 2) {
- rise = i + (ye < 0 ? x2 : x1);
- set = i + (ye < 0 ? x1 : x2);
- }
-
- if (rise && set) break;
-
- h0 = h2;
- }
-
- const result = {};
-
- if (rise) result.rise = hoursLater(t, rise);
- if (set) result.set = hoursLater(t, set);
-
- if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true;
-
- return result;
-};
diff --git a/quickshell/DMSShell.qml b/quickshell/DMSShell.qml
index 136c93404..da78a151a 100644
--- a/quickshell/DMSShell.qml
+++ b/quickshell/DMSShell.qml
@@ -233,6 +233,11 @@ Item {
PolkitService.polkitAvailable;
DisplayConfigState.hasOutputBackend;
PortalService.systemColorScheme;
+ IconThemeService.revision;
+ DesktopService.isSystemd;
+ TrashService.count;
+ WallpaperCyclingService.cyclingActive;
+ ThemeAutoService.active;
}
Loader {
diff --git a/quickshell/Modals/Common/DankModalConnected.qml b/quickshell/Modals/Common/DankModalConnected.qml
index 238002b6a..ea49ebd6a 100644
--- a/quickshell/Modals/Common/DankModalConnected.qml
+++ b/quickshell/Modals/Common/DankModalConnected.qml
@@ -314,26 +314,20 @@ Item {
readonly property real alignedWidth: Theme.px(modalWidth, dpr)
readonly property real alignedHeight: Theme.px(modalHeight, dpr)
- function _frameEdgeInset(side) {
- if (!effectiveScreen)
- return 0;
- return SettingsData.frameEdgeInsetForSide(effectiveScreen, side);
- }
-
readonly property real _connectedAlignedX: {
switch (resolvedConnectedBarSide) {
case "top":
case "bottom":
{
- const insetL = _frameEdgeInset("left");
- const insetR = _frameEdgeInset("right");
+ const insetL = SettingsData.frameEdgeInsetForSide(effectiveScreen, "left");
+ const insetR = SettingsData.frameEdgeInsetForSide(effectiveScreen, "right");
const usable = Math.max(0, screenWidth - insetL - insetR);
return insetL + Math.max(0, (usable - alignedWidth) / 2);
}
case "left":
- return _frameEdgeInset("left");
+ return SettingsData.frameEdgeInsetForSide(effectiveScreen, "left");
case "right":
- return screenWidth - alignedWidth - _frameEdgeInset("right");
+ return screenWidth - alignedWidth - SettingsData.frameEdgeInsetForSide(effectiveScreen, "right");
}
return 0;
}
@@ -341,14 +335,14 @@ Item {
readonly property real _connectedAlignedY: {
switch (resolvedConnectedBarSide) {
case "top":
- return _frameEdgeInset("top");
+ return SettingsData.frameEdgeInsetForSide(effectiveScreen, "top");
case "bottom":
- return screenHeight - alignedHeight - _frameEdgeInset("bottom");
+ return screenHeight - alignedHeight - SettingsData.frameEdgeInsetForSide(effectiveScreen, "bottom");
case "left":
case "right":
{
- const insetT = _frameEdgeInset("top");
- const insetB = _frameEdgeInset("bottom");
+ const insetT = SettingsData.frameEdgeInsetForSide(effectiveScreen, "top");
+ const insetB = SettingsData.frameEdgeInsetForSide(effectiveScreen, "bottom");
const usable = Math.max(0, screenHeight - insetT - insetB);
return insetT + Math.max(0, (usable - alignedHeight) / 2);
}
diff --git a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml
index c06fcb768..89da4b2e0 100644
--- a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml
+++ b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml
@@ -105,12 +105,6 @@ Item {
}
readonly property bool _dockBlocksEmergence: frameOwnsConnectedChrome && _dockOccupiesSide(resolvedConnectedBarSide)
- function _frameEdgeInset(side) {
- if (!effectiveScreen)
- return 0;
- return SettingsData.frameEdgeInsetForSide(effectiveScreen, side);
- }
-
readonly property var _connectedModalPos: {
const fallback = {
"x": (screenWidth - modalWidth) / 2,
@@ -120,10 +114,10 @@ Item {
case "top":
case "bottom":
{
- const insetL = _frameEdgeInset("left");
- const insetR = _frameEdgeInset("right");
- const insetT = _frameEdgeInset("top");
- const insetB = _frameEdgeInset("bottom");
+ const insetL = SettingsData.frameEdgeInsetForSide(effectiveScreen, "left");
+ const insetR = SettingsData.frameEdgeInsetForSide(effectiveScreen, "right");
+ const insetT = SettingsData.frameEdgeInsetForSide(effectiveScreen, "top");
+ const insetB = SettingsData.frameEdgeInsetForSide(effectiveScreen, "bottom");
const usable = Math.max(0, screenWidth - insetL - insetR);
const usableH = Math.max(0, screenHeight - insetT - insetB);
return {
@@ -134,11 +128,11 @@ Item {
case "left":
case "right":
{
- const insetT = _frameEdgeInset("top");
- const insetB = _frameEdgeInset("bottom");
+ const insetT = SettingsData.frameEdgeInsetForSide(effectiveScreen, "top");
+ const insetB = SettingsData.frameEdgeInsetForSide(effectiveScreen, "bottom");
const usable = Math.max(0, screenHeight - insetT - insetB);
return {
- "x": resolvedConnectedBarSide === "left" ? _frameEdgeInset("left") : screenWidth - modalWidth - _frameEdgeInset("right"),
+ "x": resolvedConnectedBarSide === "left" ? SettingsData.frameEdgeInsetForSide(effectiveScreen, "left") : screenWidth - modalWidth - SettingsData.frameEdgeInsetForSide(effectiveScreen, "right"),
"y": insetT + Math.max(0, (usable - modalHeight) / 2)
};
}
@@ -188,16 +182,16 @@ Item {
readonly property real _connectedChromeY: {
if (!launcherArcExtenderActive)
return alignedY;
- return resolvedConnectedBarSide === "top" ? Theme.snap(_frameEdgeInset("top"), dpr) : alignedY;
+ return resolvedConnectedBarSide === "top" ? Theme.snap(SettingsData.frameEdgeInsetForSide(effectiveScreen, "top"), dpr) : alignedY;
}
readonly property real _connectedChromeWidth: alignedWidth
readonly property real _connectedChromeHeight: {
if (!launcherArcExtenderActive)
return alignedHeight;
if (resolvedConnectedBarSide === "top")
- return Theme.snap(Math.max(alignedHeight, alignedY + alignedHeight - _frameEdgeInset("top")), dpr);
+ return Theme.snap(Math.max(alignedHeight, alignedY + alignedHeight - SettingsData.frameEdgeInsetForSide(effectiveScreen, "top")), dpr);
if (resolvedConnectedBarSide === "bottom")
- return Theme.snap(Math.max(alignedHeight, screenHeight - _frameEdgeInset("bottom") - alignedY), dpr);
+ return Theme.snap(Math.max(alignedHeight, screenHeight - SettingsData.frameEdgeInsetForSide(effectiveScreen, "bottom") - alignedY), dpr);
return alignedHeight;
}
readonly property real contentSurfaceHeight: launcherArcExtenderActive ? _connectedChromeHeight : alignedHeight
diff --git a/quickshell/Modals/DankLauncherV2/Scorer.js b/quickshell/Modals/DankLauncherV2/Scorer.js
index 4d3a6707f..de28288ee 100644
--- a/quickshell/Modals/DankLauncherV2/Scorer.js
+++ b/quickshell/Modals/DankLauncherV2/Scorer.js
@@ -89,15 +89,6 @@ function fuzzyScore(text, query) {
return bestScore
}
-function getTimeBucketWeight(daysSinceUsed) {
- for (var i = 0; i < TimeBuckets.length; i++) {
- if (daysSinceUsed <= TimeBuckets[i].maxDays) {
- return TimeBuckets[i].weight
- }
- }
- return 10
-}
-
function calculateTextScore(name, query) {
if (name === query) return Weights.exactMatch
if (name.startsWith(query)) return Weights.prefixMatch
diff --git a/quickshell/Modals/PowerProfileModal.qml b/quickshell/Modals/PowerProfileModal.qml
index cdb9e862f..8815c7761 100644
--- a/quickshell/Modals/PowerProfileModal.qml
+++ b/quickshell/Modals/PowerProfileModal.qml
@@ -18,6 +18,19 @@ DankModal {
open();
}
+ function getPowerProfileDescription(profile) {
+ switch (profile) {
+ case 0:
+ return I18n.tr("Extend battery life", "power profile description");
+ case 1:
+ return I18n.tr("Balance power and performance", "power profile description");
+ case 2:
+ return I18n.tr("Prioritize performance", "power profile description");
+ default:
+ return I18n.tr("Custom power profile", "power profile description");
+ }
+ }
+
function hideDialog() {
close();
}
@@ -244,7 +257,7 @@ DankModal {
// Selected power profile description
StyledText {
- text: (root.selectedIndex >= 0 && root.selectedIndex < root.profileModel.length) ? Theme.getPowerProfileDescription(root.profileModel[root.selectedIndex]) : ""
+ text: (root.selectedIndex >= 0 && root.selectedIndex < root.profileModel.length) ? root.getPowerProfileDescription(root.profileModel[root.selectedIndex]) : ""
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceTextMedium
horizontalAlignment: Text.AlignHCenter
diff --git a/quickshell/Modals/ProcessListModal.qml b/quickshell/Modals/ProcessListModal.qml
index 59d76752a..08f75f677 100644
--- a/quickshell/Modals/ProcessListModal.qml
+++ b/quickshell/Modals/ProcessListModal.qml
@@ -6,6 +6,7 @@ import qs.Common
import qs.Modules.ProcessList
import qs.Services
import qs.Widgets
+import "../Common/Format.js" as Format
FloatingWindow {
id: processListModal
@@ -67,16 +68,6 @@ FloatingWindow {
show();
}
- function formatBytes(bytes) {
- if (bytes < 1024)
- return bytes.toFixed(0) + " B/s";
- if (bytes < 1024 * 1024)
- return (bytes / 1024).toFixed(1) + " KB/s";
- if (bytes < 1024 * 1024 * 1024)
- return (bytes / (1024 * 1024)).toFixed(1) + " MB/s";
- return (bytes / (1024 * 1024 * 1024)).toFixed(2) + " GB/s";
- }
-
function nextTab() {
currentTab = (currentTab + 1) % 4;
}
@@ -541,7 +532,7 @@ FloatingWindow {
}
StyledText {
- text: "↓" + formatBytes(DgopService.networkRxRate) + " ↑" + formatBytes(DgopService.networkTxRate)
+ text: "↓" + Format.formatRate(DgopService.networkRxRate) + " ↑" + Format.formatRate(DgopService.networkTxRate)
font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily
color: Theme.surfaceText
@@ -559,7 +550,7 @@ FloatingWindow {
}
StyledText {
- text: "↓" + formatBytes(DgopService.diskReadRate) + " ↑" + formatBytes(DgopService.diskWriteRate)
+ text: "↓" + Format.formatRate(DgopService.diskReadRate) + " ↑" + Format.formatRate(DgopService.diskWriteRate)
font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily
color: Theme.surfaceText
diff --git a/quickshell/Modules/BlurredWallpaperLive.qml b/quickshell/Modules/BlurredWallpaperLive.qml
index 16753b1ac..592a720a4 100644
--- a/quickshell/Modules/BlurredWallpaperLive.qml
+++ b/quickshell/Modules/BlurredWallpaperLive.qml
@@ -25,29 +25,6 @@ Item {
property bool effectActive: false
property bool useNextForEffect: false
- function getFillMode(modeName) {
- switch (modeName) {
- case "Stretch":
- return Image.Stretch;
- case "Fit":
- case "PreserveAspectFit":
- return Image.PreserveAspectFit;
- case "Fill":
- case "PreserveAspectCrop":
- return Image.PreserveAspectCrop;
- case "Tile":
- return Image.Tile;
- case "TileVertically":
- return Image.TileVertically;
- case "TileHorizontally":
- return Image.TileHorizontally;
- case "Pad":
- return Image.Pad;
- default:
- return Image.PreserveAspectCrop;
- }
- }
-
Component.onCompleted: {
if (initialSource && initialSource !== wallpaperSource && !(CompositorService.isNiri && SessionData.isSwitchingMode)) {
currentWallpaper.source = initialSource;
@@ -144,7 +121,7 @@ Item {
smooth: true
cache: true
sourceSize: root.blurTextureSize
- fillMode: root.getFillMode(SessionData.getMonitorWallpaperFillMode(root.screenName))
+ fillMode: Theme.getFillMode(SessionData.getMonitorWallpaperFillMode(root.screenName))
onStatusChanged: {
if (status === Image.Error) {
@@ -166,7 +143,7 @@ Item {
smooth: true
cache: true
sourceSize: root.blurTextureSize
- fillMode: root.getFillMode(SessionData.getMonitorWallpaperFillMode(root.screenName))
+ fillMode: Theme.getFillMode(SessionData.getMonitorWallpaperFillMode(root.screenName))
onStatusChanged: {
if (status === Image.Error) {
diff --git a/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml b/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml
index 8402842a9..b482e93a7 100644
--- a/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml
+++ b/quickshell/Modules/BuiltinDesktopPlugins/SystemMonitorWidget.qml
@@ -4,6 +4,7 @@ import Quickshell
import qs.Common
import qs.Services
import qs.Widgets
+import "../../Common/Format.js" as Format
Item {
id: root
@@ -188,16 +189,6 @@ Item {
return DgopService.availableGpus.find(g => g.pciId === selectedGpuPciId);
}
- function formatBytes(bytes) {
- if (bytes < 1024)
- return bytes.toFixed(0) + "B";
- if (bytes < 1024 * 1024)
- return (bytes / 1024).toFixed(0) + "K";
- if (bytes < 1024 * 1024 * 1024)
- return (bytes / (1024 * 1024)).toFixed(1) + "M";
- return (bytes / (1024 * 1024 * 1024)).toFixed(1) + "G";
- }
-
function formatMemKB(kb) {
if (kb < 1024)
return kb.toFixed(0) + "K";
@@ -206,26 +197,18 @@ Item {
return (kb / (1024 * 1024)).toFixed(1) + "G";
}
- function addToHistory(arr, val) {
- var newArr = arr.slice();
- newArr.push(val);
- if (newArr.length > historySize)
- newArr.shift();
- return newArr;
- }
-
function sampleData() {
if (showCpuGraph)
- cpuHistory = addToHistory(cpuHistory, DgopService.cpuUsage);
+ cpuHistory = Format.addToHistory(cpuHistory, DgopService.cpuUsage, historySize);
if (showMemoryGraph)
- memHistory = addToHistory(memHistory, DgopService.memoryUsage);
+ memHistory = Format.addToHistory(memHistory, DgopService.memoryUsage, historySize);
if (showNetworkGraph) {
- netRxHistory = addToHistory(netRxHistory, DgopService.networkRxRate);
- netTxHistory = addToHistory(netTxHistory, DgopService.networkTxRate);
+ netRxHistory = Format.addToHistory(netRxHistory, DgopService.networkRxRate, historySize);
+ netTxHistory = Format.addToHistory(netTxHistory, DgopService.networkTxRate, historySize);
}
if (showDisk) {
- diskReadHistory = addToHistory(diskReadHistory, DgopService.diskReadRate);
- diskWriteHistory = addToHistory(diskWriteHistory, DgopService.diskWriteRate);
+ diskReadHistory = Format.addToHistory(diskReadHistory, DgopService.diskReadRate, historySize);
+ diskWriteHistory = Format.addToHistory(diskWriteHistory, DgopService.diskWriteRate, historySize);
}
}
@@ -519,7 +502,7 @@ Item {
color: root.accentColor
}
StyledText {
- text: root.formatBytes(DgopService.networkRxRate) + "/s"
+ text: Format.formatBytes(DgopService.networkRxRate) + "/s"
isMonospace: true
font.pixelSize: Theme.fontSizeMedium
color: root.textColor
@@ -533,7 +516,7 @@ Item {
color: root.dimColor
}
StyledText {
- text: root.formatBytes(DgopService.networkTxRate) + "/s"
+ text: Format.formatBytes(DgopService.networkTxRate) + "/s"
isMonospace: true
font.pixelSize: Theme.fontSizeMedium
color: root.textColor
@@ -552,7 +535,7 @@ Item {
color: root.accentColor
}
StyledText {
- text: root.formatBytes(DgopService.diskReadRate) + "/s"
+ text: Format.formatBytes(DgopService.diskReadRate) + "/s"
isMonospace: true
font.pixelSize: Theme.fontSizeMedium
color: root.textColor
@@ -566,7 +549,7 @@ Item {
color: root.dimColor
}
StyledText {
- text: root.formatBytes(DgopService.diskWriteRate) + "/s"
+ text: Format.formatBytes(DgopService.diskWriteRate) + "/s"
isMonospace: true
font.pixelSize: Theme.fontSizeMedium
color: root.textColor
diff --git a/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml b/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml
index 978da4747..75b69d867 100644
--- a/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml
+++ b/quickshell/Modules/ControlCenter/BuiltinPlugins/VpnWidget.qml
@@ -1,7 +1,7 @@
import QtQuick
import qs.Common
import qs.Services
-import qs.Widgets
+import qs.Modules.ControlCenter.Details
import qs.Modules.Plugins
PluginComponent {
diff --git a/quickshell/Modules/ControlCenter/Components/ActionTile.qml b/quickshell/Modules/ControlCenter/Components/ActionTile.qml
deleted file mode 100644
index 2f8bc47a2..000000000
--- a/quickshell/Modules/ControlCenter/Components/ActionTile.qml
+++ /dev/null
@@ -1,131 +0,0 @@
-import QtQuick
-import qs.Common
-import qs.Widgets
-
-Rectangle {
- id: root
-
- LayoutMirroring.enabled: I18n.isRtl
- LayoutMirroring.childrenInherit: true
-
- property string iconName: ""
- property string text: ""
- property string secondaryText: ""
- property bool isActive: false
- property int widgetIndex: 0
- property var widgetData: null
- property bool editMode: false
-
- signal clicked
-
- width: parent ? parent.width : 200
- height: 60
- radius: {
- if (Theme.cornerRadius === 0)
- return 0;
- return isActive ? Theme.cornerRadius : Theme.cornerRadius + 4;
- }
-
- readonly property color _tileBgActive: Theme.ccTileActiveBg
- readonly property color _tileBgInactive: Theme.ccPillInactiveBg
- readonly property color _tileRingActive: Theme.ccTileRing
-
- color: isActive ? _tileBgActive : _tileBgInactive
- border.color: isActive ? _tileRingActive : Theme.outlineMedium
- border.width: isActive ? 1 : Theme.layerOutlineWidth
- opacity: enabled ? 1.0 : 0.6
-
- function hoverTint(base) {
- const factor = 1.2;
- return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor);
- }
-
- Rectangle {
- anchors.fill: parent
- radius: Theme.cornerRadius
- color: mouseArea.containsMouse ? hoverTint(root.color) : Theme.withAlpha(hoverTint(root.color), 0)
- opacity: mouseArea.containsMouse ? 0.08 : 0.0
-
- Behavior on opacity {
- NumberAnimation {
- duration: Theme.shortDuration
- }
- }
- }
-
- Row {
- anchors.fill: parent
- anchors.leftMargin: Theme.spacingL + 2
- anchors.rightMargin: Theme.spacingM
- spacing: Theme.spacingM
-
- DankIcon {
- name: root.iconName
- size: Theme.iconSize
- color: isActive ? Theme.ccTileActiveText : Theme.ccTileInactiveIcon
- anchors.verticalCenter: parent.verticalCenter
- }
-
- Item {
- width: parent.width - Theme.iconSize - parent.spacing
- height: parent.height
-
- Column {
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.verticalCenter: parent.verticalCenter
- spacing: Theme.spacingXXS
-
- Typography {
- width: parent.width
- text: root.text
- style: Typography.Style.Body
- color: isActive ? Theme.ccTileActiveText : Theme.surfaceText
- elide: Text.ElideRight
- wrapMode: Text.NoWrap
- horizontalAlignment: Text.AlignLeft
- }
-
- Typography {
- width: parent.width
- text: root.secondaryText
- style: Typography.Style.Caption
- color: isActive ? Theme.ccTileActiveText : Theme.surfaceVariantText
- visible: text.length > 0
- elide: Text.ElideRight
- wrapMode: Text.NoWrap
- horizontalAlignment: Text.AlignLeft
- }
- }
- }
- }
-
- DankRipple {
- id: ripple
- cornerRadius: root.radius
- }
-
- MouseArea {
- id: mouseArea
- anchors.fill: parent
- hoverEnabled: true
- cursorShape: Qt.PointingHandCursor
- enabled: root.enabled
- onPressed: mouse => ripple.trigger(mouse.x, mouse.y)
- onClicked: root.clicked()
- }
-
- Behavior on color {
- ColorAnimation {
- duration: Theme.shortDuration
- easing.type: Theme.standardEasing
- }
- }
-
- Behavior on radius {
- NumberAnimation {
- duration: Theme.shortDuration
- easing.type: Theme.standardEasing
- }
- }
-}
diff --git a/quickshell/Modules/ControlCenter/Components/DragDropDetailHost.qml b/quickshell/Modules/ControlCenter/Components/DragDropDetailHost.qml
deleted file mode 100644
index 4a7ff19f0..000000000
--- a/quickshell/Modules/ControlCenter/Components/DragDropDetailHost.qml
+++ /dev/null
@@ -1,91 +0,0 @@
-import QtQuick
-import qs.Common
-import qs.Modules.ControlCenter.Details
-
-Item {
- id: root
-
- property string expandedSection: ""
- property var expandedWidgetData: null
-
- height: active ? 250 : 0
- visible: active
-
- readonly property bool active: expandedSection !== ""
-
- Loader {
- anchors.fill: parent
- anchors.topMargin: Theme.spacingS
- sourceComponent: {
- if (!root.active)
- return null;
-
- if (expandedSection.startsWith("diskUsage_")) {
- return diskUsageDetailComponent;
- }
-
- switch (expandedSection) {
- case "wifi":
- return networkDetailComponent;
- case "bluetooth":
- return bluetoothDetailComponent;
- case "audioOutput":
- return audioOutputDetailComponent;
- case "audioInput":
- return audioInputDetailComponent;
- case "battery":
- return batteryDetailComponent;
- default:
- return null;
- }
- }
- }
-
- Component {
- id: networkDetailComponent
- NetworkDetail {}
- }
-
- Component {
- id: bluetoothDetailComponent
- BluetoothDetail {}
- }
-
- Component {
- id: audioOutputDetailComponent
- AudioOutputDetail {}
- }
-
- Component {
- id: audioInputDetailComponent
- AudioInputDetail {}
- }
-
- Component {
- id: batteryDetailComponent
- BatteryDetail {}
- }
-
- Component {
- id: diskUsageDetailComponent
- DiskUsageDetail {
- currentMountPath: root.expandedWidgetData?.mountPath || "/"
- instanceId: root.expandedWidgetData?.instanceId || ""
-
- onMountPathChanged: newMountPath => {
- if (root.expandedWidgetData && root.expandedWidgetData.id === "diskUsage") {
- const widgets = SettingsData.controlCenterWidgets || [];
- const newWidgets = widgets.map(w => {
- if (w.id === "diskUsage" && w.instanceId === root.expandedWidgetData.instanceId) {
- const updatedWidget = Object.assign({}, w);
- updatedWidget.mountPath = newMountPath;
- return updatedWidget;
- }
- return w;
- });
- SettingsData.set("controlCenterWidgets", newWidgets);
- }
- }
- }
- }
-}
diff --git a/quickshell/Modules/ControlCenter/Components/PowerButton.qml b/quickshell/Modules/ControlCenter/Components/PowerButton.qml
deleted file mode 100644
index e8c474906..000000000
--- a/quickshell/Modules/ControlCenter/Components/PowerButton.qml
+++ /dev/null
@@ -1,55 +0,0 @@
-import QtQuick
-import qs.Common
-import qs.Widgets
-
-Rectangle {
- id: root
-
- LayoutMirroring.enabled: I18n.isRtl
- LayoutMirroring.childrenInherit: true
-
- property string iconName: ""
- property string text: ""
-
- signal pressed
-
- height: 34
- radius: Theme.cornerRadius
- color: mouseArea.containsMouse ? Theme.primaryHover : Theme.withAlpha(Theme.surfaceVariant, 0.5)
-
- Row {
- anchors.centerIn: parent
- spacing: Theme.spacingXS
-
- DankIcon {
- name: root.iconName
- size: Theme.fontSizeSmall
- color: mouseArea.containsMouse ? Theme.primary : Theme.surfaceText
- anchors.verticalCenter: parent.verticalCenter
- }
-
- Typography {
- text: root.text
- style: Typography.Style.Button
- color: mouseArea.containsMouse ? Theme.primary : Theme.surfaceText
- anchors.verticalCenter: parent.verticalCenter
- }
- }
-
- DankRipple {
- id: ripple
- cornerRadius: root.radius
- }
-
- MouseArea {
- id: mouseArea
-
- anchors.fill: parent
- hoverEnabled: true
- cursorShape: Qt.PointingHandCursor
- onPressed: mouse => {
- ripple.trigger(mouse.x, mouse.y);
- root.pressed();
- }
- }
-}
diff --git a/quickshell/Modules/ControlCenter/Details/AudioInputDetail.qml b/quickshell/Modules/ControlCenter/Details/AudioInputDetail.qml
index 120774525..bc3a8abaa 100644
--- a/quickshell/Modules/ControlCenter/Details/AudioInputDetail.qml
+++ b/quickshell/Modules/ControlCenter/Details/AudioInputDetail.qml
@@ -4,6 +4,7 @@ import Quickshell.Services.Pipewire
import qs.Common
import qs.Services
import qs.Widgets
+import "../../../Common/QmlUtils.js" as QmlUtils
Rectangle {
id: root
@@ -150,17 +151,9 @@ Rectangle {
property int maxPinnedInputs: 3
- function normalizePinList(value) {
- if (Array.isArray(value))
- return value.filter(v => v);
- if (typeof value === "string" && value.length > 0)
- return [value];
- return [];
- }
-
function getPinnedInputs() {
const pins = CacheData.audioInputDevicePins || {};
- return normalizePinList(pins["preferredInput"]);
+ return QmlUtils.normalizePinList(pins["preferredInput"]);
}
Column {
@@ -316,7 +309,7 @@ Rectangle {
onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y)
onClicked: {
const pins = JSON.parse(JSON.stringify(CacheData.audioInputDevicePins || {}));
- let pinnedList = audioContent.normalizePinList(pins["preferredInput"]);
+ let pinnedList = QmlUtils.normalizePinList(pins["preferredInput"]);
const pinIndex = pinnedList.indexOf(modelData.name);
if (pinIndex !== -1) {
diff --git a/quickshell/Modules/ControlCenter/Details/AudioOutputDetail.qml b/quickshell/Modules/ControlCenter/Details/AudioOutputDetail.qml
index 2bbec13c4..974377838 100644
--- a/quickshell/Modules/ControlCenter/Details/AudioOutputDetail.qml
+++ b/quickshell/Modules/ControlCenter/Details/AudioOutputDetail.qml
@@ -4,6 +4,7 @@ import Quickshell.Services.Pipewire
import qs.Common
import qs.Services
import qs.Widgets
+import "../../../Common/QmlUtils.js" as QmlUtils
Rectangle {
id: root
@@ -160,17 +161,9 @@ Rectangle {
property int maxPinnedOutputs: 3
- function normalizePinList(value) {
- if (Array.isArray(value))
- return value.filter(v => v);
- if (typeof value === "string" && value.length > 0)
- return [value];
- return [];
- }
-
function getPinnedOutputs() {
const pins = CacheData.audioOutputDevicePins || {};
- return normalizePinList(pins["preferredOutput"]);
+ return QmlUtils.normalizePinList(pins["preferredOutput"]);
}
Column {
@@ -325,7 +318,7 @@ Rectangle {
onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y)
onClicked: {
const pins = JSON.parse(JSON.stringify(CacheData.audioOutputDevicePins || {}));
- let pinnedList = audioContent.normalizePinList(pins["preferredOutput"]);
+ let pinnedList = QmlUtils.normalizePinList(pins["preferredOutput"]);
const pinIndex = pinnedList.indexOf(modelData.name);
if (pinIndex !== -1) {
diff --git a/quickshell/Modules/ControlCenter/Details/BluetoothDetail.qml b/quickshell/Modules/ControlCenter/Details/BluetoothDetail.qml
index ba277eddc..b44d3edf8 100644
--- a/quickshell/Modules/ControlCenter/Details/BluetoothDetail.qml
+++ b/quickshell/Modules/ControlCenter/Details/BluetoothDetail.qml
@@ -5,6 +5,7 @@ import Quickshell.Bluetooth
import qs.Common
import qs.Services
import qs.Widgets
+import "../../../Common/QmlUtils.js" as QmlUtils
Rectangle {
id: root
@@ -95,17 +96,9 @@ Rectangle {
BluetoothService.updateDeviceCodec(deviceAddress, codecName);
}
- function normalizePinList(value) {
- if (Array.isArray(value))
- return value.filter(v => v);
- if (typeof value === "string" && value.length > 0)
- return [value];
- return [];
- }
-
function getPinnedDevices() {
const pins = CacheData.bluetoothDevicePins || {};
- return normalizePinList(pins["preferredDevice"]);
+ return QmlUtils.normalizePinList(pins["preferredDevice"]);
}
Row {
@@ -396,7 +389,7 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onClicked: {
const pins = JSON.parse(JSON.stringify(CacheData.bluetoothDevicePins || {}));
- let pinnedList = root.normalizePinList(pins["preferredDevice"]);
+ let pinnedList = QmlUtils.normalizePinList(pins["preferredDevice"]);
const pinIndex = pinnedList.indexOf(pairedDelegate.modelData.address);
if (pinIndex !== -1) {
diff --git a/quickshell/Modules/ControlCenter/Details/DoNotDisturbDetail.qml b/quickshell/Modules/ControlCenter/Details/DoNotDisturbDetail.qml
index 7613f7eaf..dd5c10b12 100644
--- a/quickshell/Modules/ControlCenter/Details/DoNotDisturbDetail.qml
+++ b/quickshell/Modules/ControlCenter/Details/DoNotDisturbDetail.qml
@@ -1,6 +1,7 @@
import QtQuick
import qs.Common
import qs.Widgets
+import "../../../Common/Format.js" as Format
Rectangle {
id: root
@@ -23,33 +24,8 @@ Rectangle {
onTriggered: root.nowMs = Date.now()
}
- function _pad2(n) {
- return n < 10 ? "0" + n : "" + n;
- }
-
- function formatUntil(ts) {
- if (!ts)
- return "";
- const d = new Date(ts);
- const use24h = (typeof SettingsData !== "undefined") ? SettingsData.use24HourClock : true;
- if (use24h)
- return _pad2(d.getHours()) + ":" + _pad2(d.getMinutes());
- const suffix = d.getHours() >= 12 ? "PM" : "AM";
- const h12 = ((d.getHours() + 11) % 12) + 1;
- return h12 + ":" + _pad2(d.getMinutes()) + " " + suffix;
- }
-
function formatRemaining(ms) {
- if (ms <= 0)
- return "";
- const totalMinutes = Math.ceil(ms / 60000);
- if (totalMinutes < 60)
- return I18n.tr("%1 min left").arg(totalMinutes);
- const hours = Math.floor(totalMinutes / 60);
- const mins = totalMinutes - hours * 60;
- if (mins === 0)
- return I18n.tr("%1 h left").arg(hours);
- return I18n.tr("%1 h %2 m left").arg(hours).arg(mins);
+ return Format.formatRemaining(ms, "", I18n.tr("%1 min left"), I18n.tr("%1 h left"), I18n.tr("%1 h %2 m left"));
}
function minutesUntilTomorrowMorning() {
@@ -125,7 +101,7 @@ Rectangle {
if (SessionData.doNotDisturbUntil <= 0)
return I18n.tr("On indefinitely");
const remaining = Math.max(0, SessionData.doNotDisturbUntil - root.nowMs);
- return root.formatRemaining(remaining) + " · " + I18n.tr("until %1").arg(root.formatUntil(SessionData.doNotDisturbUntil));
+ return root.formatRemaining(remaining) + " · " + I18n.tr("until %1").arg(Format.formatUntil(SessionData.doNotDisturbUntil, SettingsData.use24HourClock));
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
diff --git a/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml b/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml
index 79abb4853..684534157 100644
--- a/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml
+++ b/quickshell/Modules/ControlCenter/Details/NetworkDetail.qml
@@ -7,6 +7,7 @@ import qs.Services
import qs.Widgets
import qs.Modals
import qs.Modals.Common
+import "../../../Common/QmlUtils.js" as QmlUtils
Rectangle {
id: root
@@ -66,17 +67,9 @@ Rectangle {
PopoutService.openSettingsWithTab("network_wifi");
}
- function normalizePinList(value) {
- if (Array.isArray(value))
- return value.filter(v => v);
- if (typeof value === "string" && value.length > 0)
- return [value];
- return [];
- }
-
function getPinnedNetworks() {
const pins = CacheData.wifiNetworkPins || {};
- return normalizePinList(pins["preferredWifi"]);
+ return QmlUtils.normalizePinList(pins["preferredWifi"]);
}
property int currentPreferenceIndex: {
@@ -908,7 +901,7 @@ Rectangle {
onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y)
onClicked: {
const pins = JSON.parse(JSON.stringify(CacheData.wifiNetworkPins || {}));
- let pinnedList = root.normalizePinList(pins["preferredWifi"]);
+ let pinnedList = QmlUtils.normalizePinList(pins["preferredWifi"]);
const pinIndex = pinnedList.indexOf(modelData.ssid);
if (pinIndex !== -1) {
diff --git a/quickshell/Widgets/VpnDetailContent.qml b/quickshell/Modules/ControlCenter/Details/VpnDetailContent.qml
similarity index 100%
rename from quickshell/Widgets/VpnDetailContent.qml
rename to quickshell/Modules/ControlCenter/Details/VpnDetailContent.qml
diff --git a/quickshell/Widgets/VpnProfileDelegate.qml b/quickshell/Modules/ControlCenter/Details/VpnProfileDelegate.qml
similarity index 100%
rename from quickshell/Widgets/VpnProfileDelegate.qml
rename to quickshell/Modules/ControlCenter/Details/VpnProfileDelegate.qml
diff --git a/quickshell/Modules/ControlCenter/Widgets/CompactSlider.qml b/quickshell/Modules/ControlCenter/Widgets/CompactSlider.qml
deleted file mode 100644
index 405e5392e..000000000
--- a/quickshell/Modules/ControlCenter/Widgets/CompactSlider.qml
+++ /dev/null
@@ -1,72 +0,0 @@
-import QtQuick
-import qs.Common
-import qs.Widgets
-
-Rectangle {
- id: root
-
- LayoutMirroring.enabled: I18n.isRtl
- LayoutMirroring.childrenInherit: true
-
- property string iconName: ""
- property color iconColor: Theme.surfaceText
- property string labelText: ""
- property real value: 0.0
- property real maximumValue: 1.0
- property real minimumValue: 0.0
-
- signal sliderValueChanged(real value)
-
- width: parent ? parent.width : 200
- height: 60
- radius: Theme.cornerRadius
- color: Theme.nestedSurface
- border.color: Theme.outlineMedium
- border.width: Theme.layerOutlineWidth
- opacity: enabled ? 1.0 : 0.6
-
- Row {
- anchors.left: parent.left
- anchors.verticalCenter: parent.verticalCenter
- anchors.leftMargin: Theme.spacingM
- anchors.right: sliderContainer.left
- anchors.rightMargin: Theme.spacingS
- spacing: Theme.spacingS
-
- DankIcon {
- name: root.iconName
- size: Theme.iconSize
- color: root.iconColor
- anchors.verticalCenter: parent.verticalCenter
- }
-
- StyledText {
- text: root.labelText
- font.pixelSize: Theme.fontSizeMedium
- color: Theme.surfaceText
- font.weight: Font.Medium
- anchors.verticalCenter: parent.verticalCenter
- }
- }
-
- Rectangle {
- id: sliderContainer
- anchors.right: parent.right
- anchors.verticalCenter: parent.verticalCenter
- anchors.rightMargin: Theme.spacingM
- width: 120
- height: parent.height - Theme.spacingS * 2
-
- DankSlider {
- anchors.centerIn: parent
- width: parent.width
- enabled: root.enabled
- minimum: Math.round(root.minimumValue * 100)
- maximum: Math.round(root.maximumValue * 100)
- value: Math.round(root.value * 100)
- trackColor: Theme.ccSliderTrackColor
- trackOpacity: Theme.ccSliderTrackOpacity
- onSliderValueChanged: root.sliderValueChanged(newValue / 100.0)
- }
- }
-}
diff --git a/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml b/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml
index 50f910b8e..e09c4472e 100644
--- a/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml
+++ b/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml
@@ -25,11 +25,6 @@ Rectangle {
height: 60
radius: Theme.cornerRadius
- function hoverTint(base) {
- const factor = 1.2;
- return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor);
- }
-
readonly property color _containerBg: Theme.ccPillInactiveBg
color: {
@@ -61,7 +56,7 @@ Rectangle {
radius: root.radius
z: 0
visible: false
- color: hoverTint(_containerBg)
+ color: Theme.hoverTint(_containerBg)
opacity: 0.08
antialiasing: true
Behavior on opacity {
@@ -98,7 +93,7 @@ Rectangle {
Rectangle {
anchors.fill: parent
radius: _tileRadius
- color: hoverTint(iconTile.color)
+ color: Theme.hoverTint(iconTile.color)
opacity: tileMouse.pressed ? 0.3 : (tileMouse.containsMouse ? 0.2 : 0.0)
visible: opacity > 0
antialiasing: true
diff --git a/quickshell/Modules/ControlCenter/Widgets/DetailView.qml b/quickshell/Modules/ControlCenter/Widgets/DetailView.qml
deleted file mode 100644
index 2d946f395..000000000
--- a/quickshell/Modules/ControlCenter/Widgets/DetailView.qml
+++ /dev/null
@@ -1,23 +0,0 @@
-import QtQuick
-
-Rectangle {
- id: root
-
- property string title: ""
- property Component content: null
- property bool isVisible: true
- property int contentHeight: 300
-
- width: parent ? parent.width : 400
- implicitHeight: isVisible ? contentHeight : 0
- height: implicitHeight
- color: "transparent"
- clip: true
-
- Loader {
- id: contentLoader
- anchors.fill: parent
- sourceComponent: root.content
- asynchronous: true
- }
-}
diff --git a/quickshell/Modules/ControlCenter/Widgets/SmallBatteryButton.qml b/quickshell/Modules/ControlCenter/Widgets/SmallBatteryButton.qml
index 0eb730f8c..0fc6e6ad3 100644
--- a/quickshell/Modules/ControlCenter/Widgets/SmallBatteryButton.qml
+++ b/quickshell/Modules/ControlCenter/Widgets/SmallBatteryButton.qml
@@ -22,11 +22,6 @@ Rectangle {
return isActive ? Theme.cornerRadius : Theme.cornerRadius + 4;
}
- function hoverTint(base) {
- const factor = 1.2;
- return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor);
- }
-
readonly property color _tileBgActive: Theme.ccTileActiveBg
readonly property color _tileBgInactive: Theme.ccPillInactiveBg
readonly property color _tileRingActive: Theme.ccTileRing
@@ -47,7 +42,7 @@ Rectangle {
Rectangle {
anchors.fill: parent
radius: parent.radius
- color: hoverTint(root.color)
+ color: Theme.hoverTint(root.color)
opacity: mouseArea.pressed ? 0.3 : (mouseArea.containsMouse ? 0.2 : 0.0)
visible: opacity > 0
antialiasing: true
diff --git a/quickshell/Modules/ControlCenter/Widgets/SmallColorPickerButton.qml b/quickshell/Modules/ControlCenter/Widgets/SmallColorPickerButton.qml
index d2d761df6..b1cd7c199 100644
--- a/quickshell/Modules/ControlCenter/Widgets/SmallColorPickerButton.qml
+++ b/quickshell/Modules/ControlCenter/Widgets/SmallColorPickerButton.qml
@@ -16,11 +16,6 @@ Rectangle {
height: 48
radius: Theme.cornerRadius === 0 ? 0 : Theme.cornerRadius
- function hoverTint(base) {
- const factor = 1.2;
- return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor);
- }
-
color: Theme.primary
border.color: Theme.ccTileRing
border.width: 1
@@ -29,7 +24,7 @@ Rectangle {
Rectangle {
anchors.fill: parent
radius: parent.radius
- color: hoverTint(root.color)
+ color: Theme.hoverTint(root.color)
opacity: mouseArea.pressed ? 0.3 : (mouseArea.containsMouse ? 0.2 : 0.0)
visible: opacity > 0
antialiasing: true
diff --git a/quickshell/Modules/ControlCenter/Widgets/SmallCompoundButton.qml b/quickshell/Modules/ControlCenter/Widgets/SmallCompoundButton.qml
index bb9d2417c..8d7a22aa9 100644
--- a/quickshell/Modules/ControlCenter/Widgets/SmallCompoundButton.qml
+++ b/quickshell/Modules/ControlCenter/Widgets/SmallCompoundButton.qml
@@ -25,11 +25,6 @@ Rectangle {
return isActive ? Theme.cornerRadius : Theme.cornerRadius + 4;
}
- function hoverTint(base) {
- const factor = 1.2;
- return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor);
- }
-
readonly property color _tileBgActive: Theme.ccTileActiveBg
readonly property color _tileBgInactive: Theme.ccPillInactiveBg
readonly property color _tileRingActive: Theme.ccTileRing
@@ -50,7 +45,7 @@ Rectangle {
Rectangle {
anchors.fill: parent
radius: parent.radius
- color: hoverTint(root.color)
+ color: Theme.hoverTint(root.color)
opacity: mouseArea.pressed ? 0.3 : (mouseArea.containsMouse ? 0.2 : 0.0)
visible: opacity > 0
antialiasing: true
diff --git a/quickshell/Modules/ControlCenter/Widgets/SmallDiskUsageButton.qml b/quickshell/Modules/ControlCenter/Widgets/SmallDiskUsageButton.qml
index 32db097a4..564eab5cf 100644
--- a/quickshell/Modules/ControlCenter/Widgets/SmallDiskUsageButton.qml
+++ b/quickshell/Modules/ControlCenter/Widgets/SmallDiskUsageButton.qml
@@ -34,11 +34,6 @@ Rectangle {
height: 48
radius: Theme.cornerRadius + 4
- function hoverTint(base) {
- const factor = 1.2;
- return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor);
- }
-
readonly property color _tileBg: Theme.ccPillInactiveBg
color: mouseArea.containsMouse ? Theme.ccPillInactiveHoverBg : _tileBg
@@ -50,7 +45,7 @@ Rectangle {
Rectangle {
anchors.fill: parent
radius: parent.radius
- color: hoverTint(root.color)
+ color: Theme.hoverTint(root.color)
opacity: mouseArea.pressed ? 0.3 : (mouseArea.containsMouse ? 0.2 : 0.0)
visible: opacity > 0
antialiasing: true
diff --git a/quickshell/Modules/ControlCenter/Widgets/SmallToggleButton.qml b/quickshell/Modules/ControlCenter/Widgets/SmallToggleButton.qml
index 7ea5a3bb9..d3c156249 100644
--- a/quickshell/Modules/ControlCenter/Widgets/SmallToggleButton.qml
+++ b/quickshell/Modules/ControlCenter/Widgets/SmallToggleButton.qml
@@ -20,11 +20,6 @@ Rectangle {
return isActive ? Theme.cornerRadius : Theme.cornerRadius + 4;
}
- function hoverTint(base) {
- const factor = 1.2;
- return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor);
- }
-
readonly property color _tileBgActive: Theme.ccTileActiveBg
readonly property color _tileBgInactive: Theme.ccPillInactiveBg
readonly property color _tileRingActive: Theme.ccTileRing
@@ -45,7 +40,7 @@ Rectangle {
Rectangle {
anchors.fill: parent
radius: parent.radius
- color: hoverTint(root.color)
+ color: Theme.hoverTint(root.color)
opacity: mouseArea.pressed ? 0.3 : (mouseArea.containsMouse ? 0.2 : 0.0)
visible: opacity > 0
antialiasing: true
diff --git a/quickshell/Modules/ControlCenter/Widgets/ToggleButton.qml b/quickshell/Modules/ControlCenter/Widgets/ToggleButton.qml
index 6042b0cb2..11cfb3791 100644
--- a/quickshell/Modules/ControlCenter/Widgets/ToggleButton.qml
+++ b/quickshell/Modules/ControlCenter/Widgets/ToggleButton.qml
@@ -39,17 +39,12 @@ Rectangle {
border.width: isActive ? 1 : Theme.layerOutlineWidth
opacity: enabled ? 1.0 : 0.6
- function hoverTint(base) {
- const factor = 1.2;
- return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor);
- }
-
readonly property color _containerBg: Theme.ccPillInactiveBg
Rectangle {
anchors.fill: parent
radius: Theme.cornerRadius
- color: mouseArea.containsMouse ? hoverTint(_containerBg) : Theme.withAlpha(_containerBg, 0)
+ color: mouseArea.containsMouse ? Theme.hoverTint(_containerBg) : Theme.withAlpha(_containerBg, 0)
opacity: mouseArea.containsMouse ? 0.08 : 0.0
Behavior on opacity {
diff --git a/quickshell/Modules/DankBar/DankBarContent.qml b/quickshell/Modules/DankBar/DankBarContent.qml
index c96423590..7eab90e20 100644
--- a/quickshell/Modules/DankBar/DankBarContent.qml
+++ b/quickshell/Modules/DankBar/DankBarContent.qml
@@ -274,22 +274,6 @@ Item {
return ws.num !== -1 ? ws.num : ws.name;
}
- function escapeSwayWorkspaceName(name) {
- return String(name ?? "").replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
- }
-
- function dispatchSwayWorkspace(ws) {
- if (!ws)
- return;
- try {
- if (ws.num !== undefined && ws.num !== -1) {
- I3.dispatch(`workspace number ${ws.num}`);
- } else if (ws.name) {
- I3.dispatch(`workspace "${escapeSwayWorkspaceName(ws.name)}"`);
- }
- } catch (_) {}
- }
-
function switchWorkspace(direction) {
const realWorkspaces = getRealWorkspaces();
if (realWorkspaces.length < 2) {
@@ -334,7 +318,7 @@ Item {
const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0);
if (nextIndex !== validIndex) {
- dispatchSwayWorkspace(realWorkspaces[nextIndex]);
+ CompositorService.dispatchSwayWorkspace(realWorkspaces[nextIndex]);
}
}
}
diff --git a/quickshell/Modules/DankBar/Popouts/VpnPopout.qml b/quickshell/Modules/DankBar/Popouts/VpnPopout.qml
index 064f5782f..1d363fd2f 100644
--- a/quickshell/Modules/DankBar/Popouts/VpnPopout.qml
+++ b/quickshell/Modules/DankBar/Popouts/VpnPopout.qml
@@ -3,6 +3,7 @@ import QtQuick.Layouts
import qs.Common
import qs.Services
import qs.Widgets
+import qs.Modules.ControlCenter.Details
DankPopout {
id: root
diff --git a/quickshell/Modules/DankBar/Widgets/NetworkMonitor.qml b/quickshell/Modules/DankBar/Widgets/NetworkMonitor.qml
index 69ab31f46..5d60fc6f1 100644
--- a/quickshell/Modules/DankBar/Widgets/NetworkMonitor.qml
+++ b/quickshell/Modules/DankBar/Widgets/NetworkMonitor.qml
@@ -3,22 +3,11 @@ import qs.Common
import qs.Modules.Plugins
import qs.Services
import qs.Widgets
+import "../../../Common/Format.js" as Format
BasePill {
id: root
- function formatNetworkSpeed(bytesPerSec) {
- if (bytesPerSec < 1024) {
- return bytesPerSec.toFixed(0) + " B/s";
- } else if (bytesPerSec < 1024 * 1024) {
- return (bytesPerSec / 1024).toFixed(1) + " KB/s";
- } else if (bytesPerSec < 1024 * 1024 * 1024) {
- return (bytesPerSec / (1024 * 1024)).toFixed(1) + " MB/s";
- } else {
- return (bytesPerSec / (1024 * 1024 * 1024)).toFixed(1) + " GB/s";
- }
- }
-
Component.onCompleted: {
DgopService.addRef(["network"]);
}
@@ -97,7 +86,7 @@ BasePill {
}
StyledText {
- text: DgopService.networkRxRate > 0 ? root.formatNetworkSpeed(DgopService.networkRxRate) : "0 B/s"
+ text: DgopService.networkRxRate > 0 ? Format.formatRate(DgopService.networkRxRate, 1) : "0 B/s"
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
@@ -126,7 +115,7 @@ BasePill {
}
StyledText {
- text: DgopService.networkTxRate > 0 ? root.formatNetworkSpeed(DgopService.networkTxRate) : "0 B/s"
+ text: DgopService.networkTxRate > 0 ? Format.formatRate(DgopService.networkTxRate, 1) : "0 B/s"
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
diff --git a/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml b/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml
index e94a4c49a..79533929f 100644
--- a/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml
+++ b/quickshell/Modules/DankBar/Widgets/WorkspaceSwitcher.qml
@@ -228,22 +228,6 @@ Item {
return ws.num !== -1 ? ws.num : ws.name;
}
- function escapeSwayWorkspaceName(name) {
- return String(name ?? "").replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
- }
-
- function dispatchSwayWorkspace(ws) {
- if (!ws)
- return;
- try {
- if (ws.num !== undefined && ws.num !== -1) {
- I3.dispatch(`workspace number ${ws.num}`);
- } else if (ws.name) {
- I3.dispatch(`workspace "${escapeSwayWorkspaceName(ws.name)}"`);
- }
- } catch (_) {}
- }
-
function getSwayActiveWorkspace() {
if (!root.screenName || SettingsData.workspaceFollowFocus) {
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
@@ -711,7 +695,7 @@ Item {
case "sway":
case "scroll":
case "miracle":
- dispatchSwayWorkspace(data);
+ CompositorService.dispatchSwayWorkspace(data);
break;
}
}
@@ -818,7 +802,7 @@ Item {
return;
}
- dispatchSwayWorkspace(realWorkspaces[nextIndex]);
+ CompositorService.dispatchSwayWorkspace(realWorkspaces[nextIndex]);
}
}
@@ -1486,7 +1470,7 @@ Item {
} else if (root.isMango && modelData?.tag !== undefined) {
MangoService.switchToTag(root.screenName, modelData.tag);
} else if ((CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) && modelData?.num !== undefined) {
- root.dispatchSwayWorkspace(modelData);
+ CompositorService.dispatchSwayWorkspace(modelData);
}
} else if (mouse.button === Qt.RightButton) {
if (CompositorService.isNiri) {
diff --git a/quickshell/Modules/DankDash/MediaDropdownOverlay.qml b/quickshell/Modules/DankDash/MediaDropdownOverlay.qml
index 0916d4e7d..34ae3ae62 100644
--- a/quickshell/Modules/DankDash/MediaDropdownOverlay.qml
+++ b/quickshell/Modules/DankDash/MediaDropdownOverlay.qml
@@ -415,11 +415,24 @@ Item {
}
}
onWheel: wheelEvent => {
- if (SettingsData.audioDeviceScrollVolumeEnabled && wheelEvent.x >= deviceMouseArea.width / 2) {
- AudioService.handleNodeVolumeWheel(modelData, wheelEvent);
- } else {
+ if (!SettingsData.audioDeviceScrollVolumeEnabled || wheelEvent.x < deviceMouseArea.width / 2) {
wheelEvent.accepted = false;
+ return;
}
+ if (!modelData?.audio)
+ return;
+ SessionData.suppressOSDTemporarily();
+ const delta = wheelEvent.angleDelta.y;
+ if (delta === 0)
+ return;
+ const current = Math.round(modelData.audio.volume * 100);
+ const maxVol = AudioService.getMaxVolumePercent(modelData);
+ const newVolume = delta > 0 ? Math.min(maxVol, current + AudioService.wheelVolumeStep) : Math.max(0, current - AudioService.wheelVolumeStep);
+ modelData.audio.muted = false;
+ modelData.audio.volume = newVolume / 100;
+ if (modelData === AudioService.sink)
+ AudioService.playVolumeChangeSoundIfEnabled();
+ wheelEvent.accepted = true;
}
onClicked: mouse => {
if (mouse.button === Qt.RightButton) {
diff --git a/quickshell/Modules/DankDash/MediaPlayerTab.qml b/quickshell/Modules/DankDash/MediaPlayerTab.qml
index 167e6a210..61411403f 100644
--- a/quickshell/Modules/DankDash/MediaPlayerTab.qml
+++ b/quickshell/Modules/DankDash/MediaPlayerTab.qml
@@ -451,6 +451,9 @@ Item {
height: width
anchors.centerIn: parent
activePlayer: root.activePlayer
+ artUrl: TrackArtService.resolvedArtUrl
+ accentColor: MediaAccentService.accent
+ cavaService: CavaService
}
}
@@ -522,6 +525,10 @@ Item {
height: 20
anchors.horizontalCenter: parent.horizontalCenter
activePlayer: root.activePlayer
+ stableLength: MprisController.activePlayerStableLength
+ accentColor: MediaAccentService.accent
+ accentTrackColor: MediaAccentService.accentTrack
+ accentSubtleColor: MediaAccentService.accentSubtle
isSeeking: root.isSeeking
onIsSeekingChanged: root.isSeeking = isSeeking
}
diff --git a/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml b/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml
index 2d48e2fe7..9b68a7119 100644
--- a/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml
+++ b/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml
@@ -77,6 +77,9 @@ Card {
height: 80
anchors.centerIn: parent
activePlayer: root.activePlayer
+ artUrl: TrackArtService.resolvedArtUrl
+ accentColor: MediaAccentService.accent
+ cavaService: CavaService
albumSize: 76
animationScale: 1.05
}
@@ -114,6 +117,10 @@ Card {
height: 20
x: -2
activePlayer: root.activePlayer
+ stableLength: MprisController.activePlayerStableLength
+ accentColor: MediaAccentService.accent
+ accentTrackColor: MediaAccentService.accentTrack
+ accentSubtleColor: MediaAccentService.accentSubtle
isSeeking: root.isSeeking
onIsSeekingChanged: root.isSeeking = isSeeking
}
diff --git a/quickshell/Modules/Dock/DockBody.qml b/quickshell/Modules/Dock/DockBody.qml
index c509b5f55..ab8803d90 100644
--- a/quickshell/Modules/Dock/DockBody.qml
+++ b/quickshell/Modules/Dock/DockBody.qml
@@ -114,10 +114,6 @@ Item {
readonly property real positionSpacing: barSpacing + effectiveDockBottomGap + effectiveDockMargin
readonly property real joinedEdgeMargin: dockGeometry.joinedEdgeMargin
readonly property real _dpr: (dock.screen && dock.screen.devicePixelRatio) ? dock.screen.devicePixelRatio : 1
- function px(v) {
- return Math.round(v * _dpr) / _dpr;
- }
-
DockGeometry {
id: dockGeometry
@@ -397,8 +393,8 @@ Item {
property real animationHeadroom: Math.ceil(SettingsData.dockIconSize * 0.35)
- readonly property real surfaceImplicitWidth: isVertical ? (px(dockGeometry.surfaceThickness + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
- readonly property real surfaceImplicitHeight: !isVertical ? (px(dockGeometry.surfaceThickness + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
+ readonly property real surfaceImplicitWidth: isVertical ? (Theme.px(dockGeometry.surfaceThickness + SettingsData.dockIconSize * 0.3, _dpr) + animationHeadroom) : 0
+ readonly property real surfaceImplicitHeight: !isVertical ? (Theme.px(dockGeometry.surfaceThickness + SettingsData.dockIconSize * 0.3, _dpr) + animationHeadroom) : 0
readonly property real blurX: dockBackground.x + dockContainer.x + dockMouseArea.x + dockCore.x + dockSlide.x
readonly property real blurY: dockBackground.y + dockContainer.y + dockMouseArea.y + dockCore.y + dockSlide.y
@@ -585,11 +581,11 @@ Item {
// Keep the taller hit area regardless of the reveal state to prevent shrinking loop
return Math.min(Math.max(dockBackground.height + 64, 200), maxDockHeight);
}
- return dock.reveal ? px(dockGeometry.motionThickness) : 1;
+ return dock.reveal ? Theme.px(dockGeometry.motionThickness, _dpr) : 1;
}
width: {
if (dock.isVertical) {
- return dock.reveal ? px(dockGeometry.motionThickness) : 1;
+ return dock.reveal ? Theme.px(dockGeometry.motionThickness, _dpr) : 1;
}
// Keep the wider hit area regardless of the reveal state to prevent shrinking loop
return Math.min(dockBackground.width + 8 + dock.borderThickness, maxDockWidth);
diff --git a/quickshell/Modules/Dock/DockGeometry.qml b/quickshell/Modules/Dock/DockGeometry.qml
index 611739b7f..b4a8c9342 100644
--- a/quickshell/Modules/Dock/DockGeometry.qml
+++ b/quickshell/Modules/Dock/DockGeometry.qml
@@ -19,10 +19,6 @@ QtObject {
property real barSpacing: 0
property real dpr: 1
- function px(value) {
- return Math.round(value * dpr) / dpr;
- }
-
readonly property bool frameExclusionActive: CompositorService.frameWindowVisibleForScreen(screen)
readonly property bool usesConnectedFrameChrome: CompositorService.usesConnectedFrameChromeForScreen(screen)
readonly property bool connectedBarActiveOnEdge: usesConnectedFrameChrome && !!screen && SettingsData.getActiveBarEdgesForScreen(screen).includes(edge)
@@ -56,6 +52,6 @@ QtObject {
// Frame/bar edge exclusions already reserve the edge itself, so the dock
// reservation covers only the dock body and user offset beyond that edge.
- readonly property real reserveZone: px(bodyThickness + reserveOffset + effectiveMargin)
+ readonly property real reserveZone: Theme.px(bodyThickness + reserveOffset + effectiveMargin, dpr)
readonly property bool shouldReserveSpace: dockVisible && !autoHide && barSpacing <= 0
}
diff --git a/quickshell/Modules/Notifications/Center/DndDurationMenu.qml b/quickshell/Modules/Notifications/Center/DndDurationMenu.qml
index df8478de2..23d852348 100644
--- a/quickshell/Modules/Notifications/Center/DndDurationMenu.qml
+++ b/quickshell/Modules/Notifications/Center/DndDurationMenu.qml
@@ -2,6 +2,7 @@ import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
+import "../../../Common/Format.js" as Format
Rectangle {
id: root
@@ -22,36 +23,8 @@ Rectangle {
onTriggered: root.nowMs = Date.now()
}
- function _pad2(n) {
- return n < 10 ? "0" + n : "" + n;
- }
-
function formatRemaining(ms) {
- if (ms <= 0)
- return I18n.tr("Off");
- const totalMinutes = Math.ceil(ms / 60000);
- if (totalMinutes < 60)
- return I18n.tr("%1 min left").arg(totalMinutes);
- const hours = Math.floor(totalMinutes / 60);
- const mins = totalMinutes - hours * 60;
- if (mins === 0)
- return I18n.tr("%1 h left").arg(hours);
- return I18n.tr("%1 h %2 m left").arg(hours).arg(mins);
- }
-
- function formatUntilTimestamp(ts) {
- if (!ts)
- return "";
- const d = new Date(ts);
- const hours = d.getHours();
- const minutes = d.getMinutes();
- const use24h = (typeof SettingsData !== "undefined") ? SettingsData.use24HourClock : true;
- if (use24h) {
- return _pad2(hours) + ":" + _pad2(minutes);
- }
- const suffix = hours >= 12 ? "PM" : "AM";
- const h12 = ((hours + 11) % 12) + 1;
- return h12 + ":" + _pad2(minutes) + " " + suffix;
+ return Format.formatRemaining(ms, I18n.tr("Off"), I18n.tr("%1 min left"), I18n.tr("%1 h left"), I18n.tr("%1 h %2 m left"));
}
function minutesUntilTomorrowMorning() {
@@ -149,7 +122,7 @@ Rectangle {
visible: root.currentlyActive
text: {
if (SessionData.doNotDisturbUntil > 0) {
- return root.formatRemaining(root.currentRemainingMs) + " · " + I18n.tr("until %1").arg(root.formatUntilTimestamp(SessionData.doNotDisturbUntil));
+ return root.formatRemaining(root.currentRemainingMs) + " · " + I18n.tr("until %1").arg(Format.formatUntil(SessionData.doNotDisturbUntil, SettingsData.use24HourClock));
}
return I18n.tr("On indefinitely");
}
diff --git a/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml b/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml
index 7e51e945a..29ac502c7 100644
--- a/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml
+++ b/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml
@@ -27,6 +27,36 @@ Rectangle {
readonly property real collapsedContentHeight: iconSize + cardPadding
readonly property real baseCardHeight: cardPadding * 2 + collapsedContentHeight
+ function formatHistoryTime(timestamp) {
+ NotificationService.timeUpdateTick;
+ NotificationService.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;
+ }
+ }
+
width: parent ? parent.width : 400
height: baseCardHeight + contentItem.extraHeight
radius: Theme.cornerRadius
@@ -219,7 +249,7 @@ Rectangle {
}
StyledText {
id: historyTimeText
- text: NotificationService.formatHistoryTime(historyItem.timestamp)
+ text: root.formatHistoryTime(historyItem.timestamp)
color: Theme.surfaceTextMedium
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Normal
diff --git a/quickshell/Modules/Plugins/ColorSetting.qml b/quickshell/Modules/Plugins/ColorSetting.qml
index 5ef31905f..57780541e 100644
--- a/quickshell/Modules/Plugins/ColorSetting.qml
+++ b/quickshell/Modules/Plugins/ColorSetting.qml
@@ -2,6 +2,7 @@ import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
+import "../../Common/QmlUtils.js" as QmlUtils
Column {
id: root
@@ -18,7 +19,7 @@ Column {
property bool isInitialized: false
function loadValue() {
- const settings = findSettings();
+ const settings = QmlUtils.findSettings(root.parent);
if (settings && settings.pluginService) {
const loadedValue = settings.loadValue(settingKey, defaultValue);
value = loadedValue;
@@ -33,23 +34,12 @@ Column {
onValueChanged: {
if (!isInitialized)
return;
- const settings = findSettings();
+ const settings = QmlUtils.findSettings(root.parent);
if (settings) {
settings.saveValue(settingKey, value);
}
}
- function findSettings() {
- let item = parent;
- while (item) {
- if (item.saveValue !== undefined && item.loadValue !== undefined) {
- return item;
- }
- item = item.parent;
- }
- return null;
- }
-
StyledText {
text: root.label
font.pixelSize: Theme.fontSizeMedium
diff --git a/quickshell/Modules/Plugins/ListSetting.qml b/quickshell/Modules/Plugins/ListSetting.qml
index c90a9f18f..e8213750e 100644
--- a/quickshell/Modules/Plugins/ListSetting.qml
+++ b/quickshell/Modules/Plugins/ListSetting.qml
@@ -1,6 +1,7 @@
import QtQuick
import qs.Common
import qs.Widgets
+import "../../Common/QmlUtils.js" as QmlUtils
Column {
id: root
@@ -16,30 +17,19 @@ Column {
spacing: Theme.spacingM
Component.onCompleted: {
- const settings = findSettings();
+ const settings = QmlUtils.findSettings(root.parent);
if (settings) {
items = settings.loadValue(settingKey, defaultValue);
}
}
onItemsChanged: {
- const settings = findSettings();
+ const settings = QmlUtils.findSettings(root.parent);
if (settings) {
settings.saveValue(settingKey, items);
}
}
- function findSettings() {
- let item = parent;
- while (item) {
- if (item.saveValue !== undefined && item.loadValue !== undefined) {
- return item;
- }
- item = item.parent;
- }
- return null;
- }
-
function addItem(item) {
items = items.concat([item]);
}
diff --git a/quickshell/Modules/Plugins/ListSettingWithInput.qml b/quickshell/Modules/Plugins/ListSettingWithInput.qml
index 941c6995f..ebe808991 100644
--- a/quickshell/Modules/Plugins/ListSettingWithInput.qml
+++ b/quickshell/Modules/Plugins/ListSettingWithInput.qml
@@ -1,6 +1,7 @@
import QtQuick
import qs.Common
import qs.Widgets
+import "../../Common/QmlUtils.js" as QmlUtils
Column {
id: root
@@ -22,7 +23,7 @@ Column {
}
function loadValue() {
- const settings = findSettings();
+ const settings = QmlUtils.findSettings(root.parent);
if (settings) {
isLoading = true;
items = settings.loadValue(settingKey, defaultValue);
@@ -34,23 +35,12 @@ Column {
if (isLoading) {
return;
}
- const settings = findSettings();
+ const settings = QmlUtils.findSettings(root.parent);
if (settings) {
settings.saveValue(settingKey, items);
}
}
- function findSettings() {
- let item = parent;
- while (item) {
- if (item.saveValue !== undefined && item.loadValue !== undefined) {
- return item;
- }
- item = item.parent;
- }
- return null;
- }
-
function addItem(item) {
items = items.concat([item]);
}
diff --git a/quickshell/Modules/Plugins/PluginControlCenterWrapper.qml b/quickshell/Modules/Plugins/PluginControlCenterWrapper.qml
deleted file mode 100644
index b5ccd4fb9..000000000
--- a/quickshell/Modules/Plugins/PluginControlCenterWrapper.qml
+++ /dev/null
@@ -1,43 +0,0 @@
-import QtQuick
-import qs.Common
-import qs.Services
-import qs.Widgets
-
-Item {
- id: root
-
- property string pluginId: ""
- property var pluginInstance: null
- property bool isCompoundPill: false
- property bool isSmallToggle: false
-
- readonly property bool hasDetail: pluginInstance?.ccDetailContent !== null
- readonly property string iconName: pluginInstance?.ccWidgetIcon || "extension"
- readonly property string primaryText: pluginInstance?.ccWidgetPrimaryText || "Plugin"
- readonly property string secondaryText: pluginInstance?.ccWidgetSecondaryText || ""
- readonly property bool isActive: pluginInstance?.ccWidgetIsActive || false
- readonly property Component detailContent: pluginInstance?.ccDetailContent || null
- readonly property real detailHeight: pluginInstance?.ccDetailHeight || 250
-
- signal toggled
- signal expanded
-
- Component.onCompleted: {
- if (pluginInstance) {
- pluginInstance.ccWidgetToggled.connect(toggled);
- pluginInstance.ccWidgetExpanded.connect(expanded);
- }
- }
-
- function invokeToggle() {
- if (pluginInstance) {
- pluginInstance.ccWidgetToggled();
- }
- }
-
- function invokeExpand() {
- if (pluginInstance) {
- pluginInstance.ccWidgetExpanded();
- }
- }
-}
diff --git a/quickshell/Modules/Plugins/SelectionSetting.qml b/quickshell/Modules/Plugins/SelectionSetting.qml
index 0f8fac08e..7f9d6b8d6 100644
--- a/quickshell/Modules/Plugins/SelectionSetting.qml
+++ b/quickshell/Modules/Plugins/SelectionSetting.qml
@@ -1,6 +1,7 @@
import QtQuick
import qs.Common
import qs.Widgets
+import "../../Common/QmlUtils.js" as QmlUtils
Column {
id: root
@@ -16,68 +17,57 @@ Column {
spacing: Theme.spacingS
function loadValue() {
- const settings = findSettings()
+ const settings = QmlUtils.findSettings(root.parent);
if (settings && settings.pluginService) {
- value = settings.loadValue(settingKey, defaultValue)
+ value = settings.loadValue(settingKey, defaultValue);
}
}
Component.onCompleted: {
- loadValue()
+ loadValue();
}
readonly property var optionLabels: {
- const labels = []
+ const labels = [];
for (let i = 0; i < options.length; i++) {
- labels.push(options[i].label || options[i])
+ labels.push(options[i].label || options[i]);
}
- return labels
+ return labels;
}
readonly property var valueToLabel: {
- const map = {}
+ const map = {};
for (let i = 0; i < options.length; i++) {
- const opt = options[i]
+ const opt = options[i];
if (typeof opt === 'object') {
- map[opt.value] = opt.label
+ map[opt.value] = opt.label;
} else {
- map[opt] = opt
+ map[opt] = opt;
}
}
- return map
+ return map;
}
readonly property var labelToValue: {
- const map = {}
+ const map = {};
for (let i = 0; i < options.length; i++) {
- const opt = options[i]
+ const opt = options[i];
if (typeof opt === 'object') {
- map[opt.label] = opt.value
+ map[opt.label] = opt.value;
} else {
- map[opt] = opt
+ map[opt] = opt;
}
}
- return map
+ return map;
}
onValueChanged: {
- const settings = findSettings()
+ const settings = QmlUtils.findSettings(root.parent);
if (settings) {
- settings.saveValue(settingKey, value)
+ settings.saveValue(settingKey, value);
}
}
- function findSettings() {
- let item = parent
- while (item) {
- if (item.saveValue !== undefined && item.loadValue !== undefined) {
- return item
- }
- item = item.parent
- }
- return null
- }
-
DankDropdown {
width: parent.width
text: root.label
@@ -85,7 +75,7 @@ Column {
currentValue: root.valueToLabel[root.value] || root.value
options: root.optionLabels
onValueChanged: newValue => {
- root.value = root.labelToValue[newValue] || newValue
+ root.value = root.labelToValue[newValue] || newValue;
}
}
}
diff --git a/quickshell/Modules/Plugins/SliderSetting.qml b/quickshell/Modules/Plugins/SliderSetting.qml
index a349a475f..c2936993f 100644
--- a/quickshell/Modules/Plugins/SliderSetting.qml
+++ b/quickshell/Modules/Plugins/SliderSetting.qml
@@ -1,6 +1,7 @@
import QtQuick
import qs.Common
import qs.Widgets
+import "../../Common/QmlUtils.js" as QmlUtils
Column {
id: root
@@ -20,7 +21,7 @@ Column {
spacing: Theme.spacingS
function loadValue() {
- const settings = findSettings();
+ const settings = QmlUtils.findSettings(root.parent);
if (settings && settings.pluginService) {
value = settings.loadValue(settingKey, defaultValue);
}
@@ -31,23 +32,12 @@ Column {
}
onValueChanged: {
- const settings = findSettings();
+ const settings = QmlUtils.findSettings(root.parent);
if (settings) {
settings.saveValue(settingKey, value);
}
}
- function findSettings() {
- let item = parent;
- while (item) {
- if (item.saveValue !== undefined && item.loadValue !== undefined) {
- return item;
- }
- item = item.parent;
- }
- return null;
- }
-
StyledText {
text: root.label
font.pixelSize: Theme.fontSizeMedium
diff --git a/quickshell/Modules/Plugins/StringSetting.qml b/quickshell/Modules/Plugins/StringSetting.qml
index 849807b95..9c15b7f44 100644
--- a/quickshell/Modules/Plugins/StringSetting.qml
+++ b/quickshell/Modules/Plugins/StringSetting.qml
@@ -1,6 +1,7 @@
import QtQuick
import qs.Common
import qs.Widgets
+import "../../Common/QmlUtils.js" as QmlUtils
Column {
id: root
@@ -18,7 +19,7 @@ Column {
property bool isInitialized: false
function loadValue() {
- const settings = findSettings();
+ const settings = QmlUtils.findSettings(root.parent);
if (settings && settings.pluginService) {
const loadedValue = settings.loadValue(settingKey, defaultValue);
if (textField.activeFocus && isInitialized)
@@ -39,22 +40,11 @@ Column {
if (textField.text === value)
return;
value = textField.text;
- const settings = findSettings();
+ const settings = QmlUtils.findSettings(root.parent);
if (settings)
settings.saveValue(settingKey, value);
}
- function findSettings() {
- let item = parent;
- while (item) {
- if (item.saveValue !== undefined && item.loadValue !== undefined) {
- return item;
- }
- item = item.parent;
- }
- return null;
- }
-
StyledText {
text: root.label
font.pixelSize: Theme.fontSizeMedium
diff --git a/quickshell/Modules/Plugins/ToggleSetting.qml b/quickshell/Modules/Plugins/ToggleSetting.qml
index 51b9125ad..6d9b61665 100644
--- a/quickshell/Modules/Plugins/ToggleSetting.qml
+++ b/quickshell/Modules/Plugins/ToggleSetting.qml
@@ -1,6 +1,7 @@
import QtQuick
import qs.Common
import qs.Widgets
+import "../../Common/QmlUtils.js" as QmlUtils
Row {
id: root
@@ -17,7 +18,7 @@ Row {
property bool isInitialized: false
function loadValue() {
- const settings = findSettings();
+ const settings = QmlUtils.findSettings(root.parent);
if (settings && settings.pluginService) {
const loadedValue = settings.loadValue(settingKey, defaultValue);
value = loadedValue;
@@ -32,23 +33,12 @@ Row {
onValueChanged: {
if (!isInitialized)
return;
- const settings = findSettings();
+ const settings = QmlUtils.findSettings(root.parent);
if (settings) {
settings.saveValue(settingKey, value);
}
}
- function findSettings() {
- let item = parent;
- while (item) {
- if (item.saveValue !== undefined && item.loadValue !== undefined) {
- return item;
- }
- item = item.parent;
- }
- return null;
- }
-
Column {
width: parent.width - toggle.width - Theme.spacingM
spacing: Theme.spacingXS
diff --git a/quickshell/Modules/ProcessList/DisksView.qml b/quickshell/Modules/ProcessList/DisksView.qml
index fb8b04f07..485121e11 100644
--- a/quickshell/Modules/ProcessList/DisksView.qml
+++ b/quickshell/Modules/ProcessList/DisksView.qml
@@ -3,20 +3,11 @@ import QtQuick.Layouts
import qs.Common
import qs.Services
import qs.Widgets
+import "../../Common/Format.js" as Format
Item {
id: root
- function formatSpeed(bytesPerSec) {
- if (bytesPerSec < 1024)
- return bytesPerSec.toFixed(0) + " B/s";
- if (bytesPerSec < 1024 * 1024)
- return (bytesPerSec / 1024).toFixed(1) + " KB/s";
- if (bytesPerSec < 1024 * 1024 * 1024)
- return (bytesPerSec / (1024 * 1024)).toFixed(1) + " MB/s";
- return (bytesPerSec / (1024 * 1024 * 1024)).toFixed(2) + " GB/s";
- }
-
Component.onCompleted: {
DgopService.addRef(["disk", "diskmounts"]);
}
@@ -76,7 +67,7 @@ Item {
}
StyledText {
- text: root.formatSpeed(DgopService.diskReadRate)
+ text: Format.formatRate(DgopService.diskReadRate)
font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily
font.weight: Font.Bold
@@ -94,7 +85,7 @@ Item {
}
StyledText {
- text: root.formatSpeed(DgopService.diskWriteRate)
+ text: Format.formatRate(DgopService.diskWriteRate)
font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily
font.weight: Font.Bold
diff --git a/quickshell/Modules/ProcessList/PerformanceView.qml b/quickshell/Modules/ProcessList/PerformanceView.qml
index a847107c7..244474ac8 100644
--- a/quickshell/Modules/ProcessList/PerformanceView.qml
+++ b/quickshell/Modules/ProcessList/PerformanceView.qml
@@ -4,6 +4,7 @@ import Quickshell
import qs.Common
import qs.Services
import qs.Widgets
+import "../../Common/Format.js" as Format
Item {
id: root
@@ -17,31 +18,13 @@ Item {
property var diskReadHistory: []
property var diskWriteHistory: []
- function formatBytes(bytes) {
- if (bytes < 1024)
- return bytes.toFixed(0) + " B/s";
- if (bytes < 1024 * 1024)
- return (bytes / 1024).toFixed(1) + " KB/s";
- if (bytes < 1024 * 1024 * 1024)
- return (bytes / (1024 * 1024)).toFixed(1) + " MB/s";
- return (bytes / (1024 * 1024 * 1024)).toFixed(2) + " GB/s";
- }
-
- function addToHistory(arr, val) {
- const newArr = arr.slice();
- newArr.push(val);
- if (newArr.length > historySize)
- newArr.shift();
- return newArr;
- }
-
function sampleData() {
- cpuHistory = addToHistory(cpuHistory, DgopService.cpuUsage);
- memoryHistory = addToHistory(memoryHistory, DgopService.memoryUsage);
- networkRxHistory = addToHistory(networkRxHistory, DgopService.networkRxRate);
- networkTxHistory = addToHistory(networkTxHistory, DgopService.networkTxRate);
- diskReadHistory = addToHistory(diskReadHistory, DgopService.diskReadRate);
- diskWriteHistory = addToHistory(diskWriteHistory, DgopService.diskWriteRate);
+ cpuHistory = Format.addToHistory(cpuHistory, DgopService.cpuUsage, historySize);
+ memoryHistory = Format.addToHistory(memoryHistory, DgopService.memoryUsage, historySize);
+ networkRxHistory = Format.addToHistory(networkRxHistory, DgopService.networkRxRate, historySize);
+ networkTxHistory = Format.addToHistory(networkTxHistory, DgopService.networkTxRate, historySize);
+ diskReadHistory = Format.addToHistory(diskReadHistory, DgopService.diskReadRate, historySize);
+ diskWriteHistory = Format.addToHistory(diskWriteHistory, DgopService.diskWriteRate, historySize);
}
Component.onCompleted: {
@@ -111,8 +94,8 @@ Item {
Layout.fillHeight: true
title: I18n.tr("Network")
icon: "swap_horiz"
- value: "↓ " + root.formatBytes(DgopService.networkRxRate)
- subtitle: "↑ " + root.formatBytes(DgopService.networkTxRate)
+ value: "↓ " + Format.formatRate(DgopService.networkRxRate)
+ subtitle: "↑ " + Format.formatRate(DgopService.networkTxRate)
accentColor: Theme.info
history: root.networkRxHistory
history2: root.networkTxHistory
@@ -127,8 +110,8 @@ Item {
Layout.fillHeight: true
title: I18n.tr("Disk")
icon: "storage"
- value: "R: " + root.formatBytes(DgopService.diskReadRate)
- subtitle: "W: " + root.formatBytes(DgopService.diskWriteRate)
+ value: "R: " + Format.formatRate(DgopService.diskReadRate)
+ subtitle: "W: " + Format.formatRate(DgopService.diskWriteRate)
accentColor: Theme.warning
history: root.diskReadHistory
history2: root.diskWriteHistory
diff --git a/quickshell/Modules/ProcessList/ProcessesView.qml b/quickshell/Modules/ProcessList/ProcessesView.qml
index 1c9bb703f..efa6015f7 100644
--- a/quickshell/Modules/ProcessList/ProcessesView.qml
+++ b/quickshell/Modules/ProcessList/ProcessesView.qml
@@ -36,6 +36,36 @@ Item {
cachedProcesses = filteredProcesses;
}
+ 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";
+ if (mem < 1024 * 1024)
+ return (mem / 1024).toFixed(1) + " MB";
+ return (mem / (1024 * 1024)).toFixed(1) + " GB";
+ }
+
readonly property var filteredProcesses: {
if (!DgopService.allProcesses || DgopService.allProcesses.length === 0)
return [];
@@ -521,7 +551,7 @@ Item {
spacing: Theme.spacingS
DankIcon {
- name: DgopService.getProcessIcon(processItemRoot.processCmd)
+ name: root.getProcessIcon(processItemRoot.processCmd)
size: Theme.iconSize - 4
color: {
if (processItemRoot.processCpu > 80)
@@ -566,7 +596,7 @@ Item {
StyledText {
anchors.centerIn: parent
- text: DgopService.formatCpuUsage(processItemRoot.processCpu)
+ text: root.formatCpuUsage(processItemRoot.processCpu)
font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily
font.weight: Font.Bold
@@ -600,7 +630,7 @@ Item {
StyledText {
anchors.centerIn: parent
- text: DgopService.formatMemoryUsage(processItemRoot.processMemKB)
+ text: root.formatMemoryUsage(processItemRoot.processMemKB)
font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily
font.weight: Font.Bold
diff --git a/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml b/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml
index b36475211..0c013b2d3 100644
--- a/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml
+++ b/quickshell/Modules/Settings/DisplayConfig/DisplayConfigState.qml
@@ -387,7 +387,6 @@ Singleton {
});
}
- // Extract neutral per-output config from current live state
function extractOutputNeutralConfig(outputName, outputData, niriSettings, hyprlandSettings) {
const modeData = (outputData.modes && outputData.current_mode !== undefined) ? outputData.modes[outputData.current_mode] : null;
const modeStr = modeData ? modeData.width + "x" + modeData.height + "@" + (modeData.refresh_rate / 1000).toFixed(3) : null;
@@ -421,7 +420,6 @@ Singleton {
return cfg;
}
- // Convert monitors.json config entry → internal outputsData map
function profileKeyMatchesOutput(outputId, output, name) {
if (name === outputId || getOutputIdentifier(output, name) === outputId)
return true;
@@ -438,7 +436,6 @@ Singleton {
const cfgOutputs = configEntry.outputs || {};
for (const outputId in cfgOutputs) {
const cfg = cfgOutputs[outputId];
- // Find matching live output to get modes list
let liveOutput = null;
for (const name in outputs) {
if (profileKeyMatchesOutput(outputId, outputs[name], name)) {
@@ -476,7 +473,6 @@ Singleton {
return result;
}
- // Extract niri settings map from a neutral config entry.
function getNiriSettingsFromConfig(configEntry) {
const result = {};
for (const outputId in (configEntry.outputs || {})) {
@@ -490,7 +486,6 @@ Singleton {
return result;
}
- // Extract hyprland settings map from neutral config entry
function getHyprlandSettingsFromConfig(configEntry) {
const result = {};
for (const outputId in (configEntry.outputs || {})) {
@@ -537,7 +532,6 @@ Singleton {
return true;
}
- // Write compositor config from a neutral config entry and optionally reload
function applyConfigEntry(configEntry, configId, profileName, isManual) {
if (CompositorService.isHyprland && readOnly) {
if (isManual) {
@@ -580,8 +574,6 @@ Singleton {
});
}
- // ── Profile management ─────────────────────────────────────────────────
-
function validateProfiles() {
log.info("Validating profiles against current outputs...");
readMonitorsJson(data => {
@@ -2072,7 +2064,6 @@ Singleton {
return pending !== undefined ? pending : originalValue;
}
- // Returns true if the given output can currently be disabled.
// Prevents disabling all outputs and prevents disabling the only output
// in a single-display configuration.
function canDisableOutput() {
diff --git a/quickshell/Modules/Settings/GammaControlTab.qml b/quickshell/Modules/Settings/GammaControlTab.qml
index 1482d5f87..60c4df67a 100644
--- a/quickshell/Modules/Settings/GammaControlTab.qml
+++ b/quickshell/Modules/Settings/GammaControlTab.qml
@@ -3,23 +3,11 @@ import qs.Common
import qs.Services
import qs.Widgets
import qs.Modules.Settings.Widgets
+import "../../Common/Format.js" as Format
Item {
id: root
- function formatGammaTime(isoString) {
- if (!isoString)
- return "";
- try {
- const date = new Date(isoString);
- if (isNaN(date.getTime()))
- return "";
- return date.toLocaleTimeString(Qt.locale(), "HH:mm");
- } catch (e) {
- return "";
- }
- }
-
DankFlickable {
anchors.fill: parent
clip: true
@@ -195,7 +183,7 @@ Item {
}
onTabClicked: index => {
- DisplayService.setNightModeAutomationMode(index === 1 ? "location" : "time");
+ SessionData.setNightModeAutoMode(index === 1 ? "location" : "time");
currentIndex = index;
}
@@ -562,7 +550,7 @@ Item {
}
StyledText {
- text: root.formatGammaTime(DisplayService.gammaSunriseTime)
+ text: Format.formatIsoTime(DisplayService.gammaSunriseTime)
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
@@ -598,7 +586,7 @@ Item {
}
StyledText {
- text: root.formatGammaTime(DisplayService.gammaSunsetTime)
+ text: Format.formatIsoTime(DisplayService.gammaSunsetTime)
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
@@ -645,7 +633,7 @@ Item {
}
StyledText {
- text: root.formatGammaTime(DisplayService.gammaNextTransition)
+ text: Format.formatIsoTime(DisplayService.gammaNextTransition)
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
diff --git a/quickshell/Widgets/KeybindItem.qml b/quickshell/Modules/Settings/KeybindItem.qml
similarity index 99%
rename from quickshell/Widgets/KeybindItem.qml
rename to quickshell/Modules/Settings/KeybindItem.qml
index d0aa6dcac..94147626e 100644
--- a/quickshell/Widgets/KeybindItem.qml
+++ b/quickshell/Modules/Settings/KeybindItem.qml
@@ -6,8 +6,8 @@ import Quickshell.Wayland
import qs.Common
import qs.Services
import qs.Widgets
-import "../Common/KeyUtils.js" as KeyUtils
-import "../Common/KeybindActions.js" as Actions
+import "../../Common/KeyUtils.js" as KeyUtils
+import "../../Common/KeybindActions.js" as Actions
Item {
id: root
diff --git a/quickshell/Modules/Settings/NetworkVpnTab.qml b/quickshell/Modules/Settings/NetworkVpnTab.qml
index c00bf21e9..05e89878c 100644
--- a/quickshell/Modules/Settings/NetworkVpnTab.qml
+++ b/quickshell/Modules/Settings/NetworkVpnTab.qml
@@ -240,7 +240,7 @@ Item {
required property var modelData
required property int index
- readonly property bool isActive: DMSNetworkService.isActiveUuid(modelData.uuid)
+ readonly property bool isActive: DMSNetworkService.isActiveVpnUuid(modelData.uuid)
readonly property bool isTransient: !!modelData.transient
readonly property bool canExpand: modelData.canExpand !== false
readonly property bool canDelete: modelData.canDelete !== false
diff --git a/quickshell/Modules/Settings/NetworkWifiTab.qml b/quickshell/Modules/Settings/NetworkWifiTab.qml
index 6567dc373..bbde650a4 100644
--- a/quickshell/Modules/Settings/NetworkWifiTab.qml
+++ b/quickshell/Modules/Settings/NetworkWifiTab.qml
@@ -9,6 +9,7 @@ import qs.Modules.Settings.Widgets
import qs.Modals.Common
import qs.Services
import qs.Widgets
+import "../../Common/QmlUtils.js" as QmlUtils
Item {
id: networkWifiTab
@@ -46,22 +47,14 @@ Item {
property string expandedSavedWifiSsid: ""
property int maxPinnedWifiNetworks: 3
- function normalizePinList(value) {
- if (Array.isArray(value))
- return value.filter(v => v);
- if (typeof value === "string" && value.length > 0)
- return [value];
- return [];
- }
-
function getPinnedWifiNetworks() {
const pins = CacheData.wifiNetworkPins || {};
- return normalizePinList(pins["preferredWifi"]);
+ return QmlUtils.normalizePinList(pins["preferredWifi"]);
}
function toggleWifiPin(ssid) {
const pins = JSON.parse(JSON.stringify(CacheData.wifiNetworkPins || {}));
- let pinnedList = normalizePinList(pins["preferredWifi"]);
+ let pinnedList = QmlUtils.normalizePinList(pins["preferredWifi"]);
const pinIndex = pinnedList.indexOf(ssid);
if (pinIndex !== -1) {
diff --git a/quickshell/Modules/Settings/NotificationsTab.qml b/quickshell/Modules/Settings/NotificationsTab.qml
index 8c93482fa..46f544fdd 100644
--- a/quickshell/Modules/Settings/NotificationsTab.qml
+++ b/quickshell/Modules/Settings/NotificationsTab.qml
@@ -1,5 +1,6 @@
import QtQuick
import qs.Common
+import qs.Services
import qs.Widgets
import qs.Modules.Settings.Widgets
@@ -215,7 +216,7 @@ Item {
currentValue: (SettingsData.notificationSummaryFontSize || I18n.tr("Unset")).toString()
onValueChanged: value => {
SettingsData.set("notificationSummaryFontSize", Number(value === I18n.tr("Unset") ? 0 : value));
- SettingsData.sendTestNotifications();
+ NotificationService.sendTestNotifications();
}
}
@@ -228,7 +229,7 @@ Item {
currentValue: (SettingsData.notificationBodyFontSize || I18n.tr("Unset")).toString()
onValueChanged: value => {
SettingsData.set("notificationBodyFontSize", Number(value === I18n.tr("Unset") ? 0 : value));
- SettingsData.sendTestNotifications();
+ NotificationService.sendTestNotifications();
}
}
@@ -277,7 +278,7 @@ Item {
SettingsData.set("notificationPopupPosition", SettingsData.Position.Bottom);
break;
}
- SettingsData.sendTestNotifications();
+ NotificationService.sendTestNotifications();
}
}
diff --git a/quickshell/Modules/Settings/ThemeColorsTab.qml b/quickshell/Modules/Settings/ThemeColorsTab.qml
index b49d45fd3..356df8d66 100644
--- a/quickshell/Modules/Settings/ThemeColorsTab.qml
+++ b/quickshell/Modules/Settings/ThemeColorsTab.qml
@@ -8,6 +8,7 @@ import qs.Services
import qs.Widgets
import qs.Modules.Settings.Widgets
import "../../Common/ConfigIncludeResolve.js" as ConfigIncludeResolve
+import "../../Common/Format.js" as Format
Item {
id: themeColorsTab
@@ -215,19 +216,6 @@ Item {
ToastService.showError(I18n.tr("Missing Environment Variables", "qt theme env error title"), I18n.tr("You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.", "qt theme env error body"));
}
- function formatThemeAutoTime(isoString) {
- if (!isoString)
- return "";
- try {
- const date = new Date(isoString);
- if (isNaN(date.getTime()))
- return "";
- return date.toLocaleTimeString(Qt.locale(), "HH:mm");
- } catch (e) {
- return "";
- }
- }
-
function refreshMatugenSchemePreviews() {
if (!Theme.matugenAvailable)
return;
@@ -1566,7 +1554,7 @@ Item {
}
StyledText {
- text: themeColorsTab.formatThemeAutoTime(SessionData.themeModeNextTransition)
+ text: Format.formatIsoTime(SessionData.themeModeNextTransition)
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
diff --git a/quickshell/Modules/Settings/Widgets/SettingsButtonGroupRow.qml b/quickshell/Modules/Settings/Widgets/SettingsButtonGroupRow.qml
index b435bed38..8e128bbe3 100644
--- a/quickshell/Modules/Settings/Widgets/SettingsButtonGroupRow.qml
+++ b/quickshell/Modules/Settings/Widgets/SettingsButtonGroupRow.qml
@@ -4,6 +4,7 @@ import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
+import "../../../Common/QmlUtils.js" as QmlUtils
Item {
id: root
@@ -20,16 +21,6 @@ Item {
readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey
- function findParentFlickable() {
- let p = root.parent;
- while (p) {
- if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem"))
- return p;
- p = p.parent;
- }
- return null;
- }
-
Component.onCompleted: {
if (!settingKey)
return;
@@ -37,7 +28,7 @@ Item {
Qt.callLater(() => {
if (!root.parent)
return;
- var flickable = findParentFlickable();
+ var flickable = QmlUtils.findParentFlickable(root.parent);
if (flickable)
SettingsSearchService.registerCard(key, root, flickable);
});
diff --git a/quickshell/Modules/Settings/Widgets/SettingsCard.qml b/quickshell/Modules/Settings/Widgets/SettingsCard.qml
index 6e3d69090..40fbf103e 100644
--- a/quickshell/Modules/Settings/Widgets/SettingsCard.qml
+++ b/quickshell/Modules/Settings/Widgets/SettingsCard.qml
@@ -4,6 +4,7 @@ import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
+import "../../../Common/QmlUtils.js" as QmlUtils
StyledRect {
id: root
@@ -43,17 +44,6 @@ StyledRect {
readonly property bool hasHeader: root.title !== "" || root.iconName !== ""
property bool userToggledCollapse: false
- function findParentFlickable() {
- let p = root.parent;
- while (p) {
- if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem")) {
- return p;
- }
- p = p.parent;
- }
- return null;
- }
-
Component.onCompleted: {
if (!settingKey)
return;
@@ -61,7 +51,7 @@ StyledRect {
Qt.callLater(() => {
if (!root.parent)
return;
- var flickable = findParentFlickable();
+ var flickable = QmlUtils.findParentFlickable(root.parent);
if (flickable)
SettingsSearchService.registerCard(key, root, flickable);
});
diff --git a/quickshell/Modules/Settings/Widgets/SettingsDropdownRow.qml b/quickshell/Modules/Settings/Widgets/SettingsDropdownRow.qml
index 3b622a210..e57cd27ac 100644
--- a/quickshell/Modules/Settings/Widgets/SettingsDropdownRow.qml
+++ b/quickshell/Modules/Settings/Widgets/SettingsDropdownRow.qml
@@ -4,6 +4,7 @@ import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
+import "../../../Common/QmlUtils.js" as QmlUtils
DankDropdown {
id: root
@@ -35,16 +36,6 @@ DankDropdown {
}
}
- function findParentFlickable() {
- let p = root.parent;
- while (p) {
- if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem"))
- return p;
- p = p.parent;
- }
- return null;
- }
-
Component.onCompleted: {
if (!settingKey)
return;
@@ -52,7 +43,7 @@ DankDropdown {
Qt.callLater(() => {
if (!root.parent)
return;
- var flickable = findParentFlickable();
+ var flickable = QmlUtils.findParentFlickable(root.parent);
if (flickable)
SettingsSearchService.registerCard(key, root, flickable);
});
diff --git a/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml b/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml
index 3ae7800c1..e1a08c4b8 100644
--- a/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml
+++ b/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml
@@ -4,6 +4,7 @@ import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
+import "../../../Common/QmlUtils.js" as QmlUtils
StyledRect {
id: root
@@ -36,16 +37,6 @@ StyledRect {
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
- function findParentFlickable() {
- let p = root.parent;
- while (p) {
- if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem"))
- return p;
- p = p.parent;
- }
- return null;
- }
-
Component.onCompleted: {
if (!settingKey)
return;
@@ -53,7 +44,7 @@ StyledRect {
Qt.callLater(() => {
if (!root.parent)
return;
- const flickable = findParentFlickable();
+ const flickable = QmlUtils.findParentFlickable(root.parent);
if (flickable)
SettingsSearchService.registerCard(key, root, flickable);
});
diff --git a/quickshell/Modules/Settings/Widgets/SettingsSliderRow.qml b/quickshell/Modules/Settings/Widgets/SettingsSliderRow.qml
index fb09f43e4..efac69ad6 100644
--- a/quickshell/Modules/Settings/Widgets/SettingsSliderRow.qml
+++ b/quickshell/Modules/Settings/Widgets/SettingsSliderRow.qml
@@ -4,6 +4,7 @@ import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
+import "../../../Common/QmlUtils.js" as QmlUtils
Item {
id: root
@@ -20,16 +21,6 @@ Item {
readonly property bool isHighlighted: settingKey !== "" && SettingsSearchService.highlightSection === settingKey
- function findParentFlickable() {
- let p = root.parent;
- while (p) {
- if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem"))
- return p;
- p = p.parent;
- }
- return null;
- }
-
Component.onCompleted: {
if (!settingKey)
return;
@@ -37,7 +28,7 @@ Item {
Qt.callLater(() => {
if (!root.parent)
return;
- var flickable = findParentFlickable();
+ var flickable = QmlUtils.findParentFlickable(root.parent);
if (flickable)
SettingsSearchService.registerCard(key, root, flickable);
});
diff --git a/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml b/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml
index aa7ed6580..94c55dd8b 100644
--- a/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml
+++ b/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml
@@ -4,6 +4,7 @@ import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
+import "../../../Common/QmlUtils.js" as QmlUtils
StyledRect {
id: root
@@ -30,16 +31,6 @@ StyledRect {
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
- function findParentFlickable() {
- let p = root.parent;
- while (p) {
- if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem"))
- return p;
- p = p.parent;
- }
- return null;
- }
-
Component.onCompleted: {
if (!settingKey)
return;
@@ -47,7 +38,7 @@ StyledRect {
Qt.callLater(() => {
if (!root.parent)
return;
- const flickable = findParentFlickable();
+ const flickable = QmlUtils.findParentFlickable(root.parent);
if (flickable)
SettingsSearchService.registerCard(key, root, flickable);
});
diff --git a/quickshell/Modules/Settings/Widgets/SettingsToggleRow.qml b/quickshell/Modules/Settings/Widgets/SettingsToggleRow.qml
index aa7969b74..a54589496 100644
--- a/quickshell/Modules/Settings/Widgets/SettingsToggleRow.qml
+++ b/quickshell/Modules/Settings/Widgets/SettingsToggleRow.qml
@@ -4,6 +4,7 @@ import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
+import "../../../Common/QmlUtils.js" as QmlUtils
DankToggle {
id: root
@@ -19,16 +20,6 @@ DankToggle {
width: parent?.width ?? 0
- function findParentFlickable() {
- let p = root.parent;
- while (p) {
- if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem"))
- return p;
- p = p.parent;
- }
- return null;
- }
-
Component.onCompleted: {
if (!settingKey)
return;
@@ -36,7 +27,7 @@ DankToggle {
Qt.callLater(() => {
if (!root.parent)
return;
- var flickable = findParentFlickable();
+ var flickable = QmlUtils.findParentFlickable(root.parent);
if (flickable)
SettingsSearchService.registerCard(key, root, flickable);
});
diff --git a/quickshell/Modules/Settings/WorkspacesTab.qml b/quickshell/Modules/Settings/WorkspacesTab.qml
index 2b0143857..94277838a 100644
--- a/quickshell/Modules/Settings/WorkspacesTab.qml
+++ b/quickshell/Modules/Settings/WorkspacesTab.qml
@@ -207,7 +207,7 @@ Item {
iconName: "label"
title: I18n.tr("Named Workspace Icons")
settingKey: "workspaceIcons"
- visible: SettingsData.hasNamedWorkspaces()
+ visible: NiriService.hasNamedWorkspaces()
StyledText {
width: parent.width
@@ -218,7 +218,7 @@ Item {
}
Repeater {
- model: SettingsData.getNamedWorkspaces()
+ model: NiriService.getNamedWorkspaces()
Rectangle {
width: parent.width
diff --git a/quickshell/Modules/WallpaperBackground.qml b/quickshell/Modules/WallpaperBackground.qml
index 151369c7a..a8ee0fe28 100644
--- a/quickshell/Modules/WallpaperBackground.qml
+++ b/quickshell/Modules/WallpaperBackground.qml
@@ -114,7 +114,7 @@ Variants {
}
property real transitionProgress: 0
- property real shaderFillMode: getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name))
+ property real shaderFillMode: Theme.getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name))
property vector4d fillColor: Qt.vector4d(0, 0, 0, 1)
property real edgeSmoothness: 0.1
@@ -321,31 +321,6 @@ Variants {
Qt.callLater(() => root.changeWallpaper(pending, true));
}
- function getFillMode(modeName) {
- switch (modeName) {
- case "Scrolling":
- return Image.PreserveAspectCrop;
- case "Stretch":
- return Image.Stretch;
- case "Fit":
- case "PreserveAspectFit":
- return Image.PreserveAspectFit;
- case "Fill":
- case "PreserveAspectCrop":
- return Image.PreserveAspectCrop;
- case "Tile":
- return Image.Tile;
- case "TileVertically":
- return Image.TileVertically;
- case "TileHorizontally":
- return Image.TileHorizontally;
- case "Pad":
- return Image.Pad;
- default:
- return Image.PreserveAspectCrop;
- }
- }
-
function updateWorkspaceData() {
if (!scrollingEnabled)
return;
@@ -740,7 +715,7 @@ Variants {
cache: true
sourceSize: Qt.size(root.textureWidth, root.textureHeight)
- fillMode: root.getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name))
+ fillMode: Theme.getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name))
onStatusChanged: {
if (status === Image.Error) {
@@ -772,7 +747,7 @@ Variants {
cache: true
sourceSize: Qt.size(root.textureWidth, root.textureHeight)
- fillMode: root.getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name))
+ fillMode: Theme.getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name))
onStatusChanged: {
if (status === Image.Error) {
diff --git a/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml b/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml
index 6897f5a4d..4454b96aa 100644
--- a/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml
+++ b/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml
@@ -218,13 +218,21 @@ Scope {
}
if (event.key === Qt.Key_Up) {
- NiriService.moveWorkspaceUp();
+ NiriService.send({
+ "Action": {
+ "FocusWorkspaceUp": {}
+ }
+ });
event.accepted = true;
return;
}
if (event.key === Qt.Key_Down) {
- NiriService.moveWorkspaceDown();
+ NiriService.send({
+ "Action": {
+ "FocusWorkspaceDown": {}
+ }
+ });
event.accepted = true;
return;
}
diff --git a/quickshell/Services/AppSearchService.qml b/quickshell/Services/AppSearchService.qml
index 4f066a71d..22c2a5073 100644
--- a/quickshell/Services/AppSearchService.qml
+++ b/quickshell/Services/AppSearchService.qml
@@ -791,23 +791,6 @@ Singleton {
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 [];
@@ -915,21 +898,6 @@ Singleton {
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;
@@ -950,21 +918,6 @@ Singleton {
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 [];
@@ -1001,15 +954,4 @@ Singleton {
log.warn("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/quickshell/Services/AudioService.qml b/quickshell/Services/AudioService.qml
index 2116c5213..f01f20e6f 100644
--- a/quickshell/Services/AudioService.qml
+++ b/quickshell/Services/AudioService.qml
@@ -85,7 +85,6 @@ Singleton {
}
}
- // Used in playLoginSoundIfApplicable()
Process {
id: loginSoundChecker
onExited: exitCode => {
@@ -720,15 +719,10 @@ EOFCONFIG
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) {
@@ -736,22 +730,18 @@ EOFCONFIG
}
}
- // 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";
}
@@ -773,10 +763,6 @@ EOFCONFIG
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";
}
@@ -790,19 +776,16 @@ EOFCONFIG
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;
}
@@ -889,28 +872,6 @@ EOFCONFIG
return root.sink.audio.muted ? "Audio muted" : "Audio unmuted";
}
- function handleNodeVolumeWheel(node, wheelEvent) {
- if (!node?.audio)
- return;
-
- SessionData.suppressOSDTemporarily();
- const delta = wheelEvent.angleDelta.y;
- if (delta === 0)
- return;
-
- const current = Math.round(node.audio.volume * 100);
- const maxVol = getMaxVolumePercent(node);
- const newVolume = delta > 0 ? Math.min(maxVol, current + root.wheelVolumeStep) : Math.max(0, current - root.wheelVolumeStep);
-
- node.audio.muted = false;
- node.audio.volume = newVolume / 100;
-
- if (node === sink) {
- playVolumeChangeSoundIfEnabled();
- }
- wheelEvent.accepted = true;
- }
-
function setMicVolume(percentage) {
if (!root.source?.audio) {
return "No audio source available";
diff --git a/quickshell/Services/BluetoothService.qml b/quickshell/Services/BluetoothService.qml
index f18ed3c1d..47ca13bd6 100644
--- a/quickshell/Services/BluetoothService.qml
+++ b/quickshell/Services/BluetoothService.qml
@@ -354,28 +354,6 @@ Singleton {
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;
@@ -622,40 +600,6 @@ Singleton {
});
}
- function getCurrentCodec(device, callback) {
- if (!device || !device.connected || !isAudioDevice(device)) {
- callback("");
- return;
- }
-
- whenCodecBackendReady(() => {
- if (root.wpexecAvailable) {
- root.queryCardProfiles(device, (codecs, current) => {
- if (current) {
- callback(current);
- return;
- }
- if (!root.dbusBridgeAvailable) {
- callback("");
- return;
- }
- root.queryBluezCodecState(device, (bluezCodecs, bluezCurrent) => {
- callback(bluezCurrent || "");
- });
- });
- return;
- }
-
- if (!root.dbusBridgeAvailable) {
- callback("");
- return;
- }
- root.queryBluezCodecState(device, (codecs, current) => {
- callback(current || "");
- });
- });
- }
-
function getAvailableCodecs(device, callback) {
if (!device || !device.connected || !isAudioDevice(device)) {
callback([], "");
diff --git a/quickshell/Services/BlurService.qml b/quickshell/Services/BlurService.qml
index 4fd484455..41a37a4b1 100644
--- a/quickshell/Services/BlurService.qml
+++ b/quickshell/Services/BlurService.qml
@@ -41,6 +41,12 @@ Singleton {
return Theme.withAlpha(baseColor, hoverAlpha ?? 0.15);
}
+ Binding {
+ target: Theme
+ property: "blurLayersActive"
+ value: root.enabled
+ }
+
Process {
id: blurProbe
running: false
diff --git a/quickshell/Services/CompositorService.qml b/quickshell/Services/CompositorService.qml
index ccfecbf95..e00fa0b33 100644
--- a/quickshell/Services/CompositorService.qml
+++ b/quickshell/Services/CompositorService.qml
@@ -1087,4 +1087,58 @@ Singleton {
}
log.warn("Cannot power on monitors, unknown compositor");
}
+ function escapeSwayWorkspaceName(name) {
+ return String(name ?? "").replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
+ }
+
+ function dispatchSwayWorkspace(ws) {
+ if (!ws)
+ return;
+ try {
+ if (ws.num !== undefined && ws.num !== -1) {
+ I3.dispatch(`workspace number ${ws.num}`);
+ } else if (ws.name) {
+ I3.dispatch(`workspace "${escapeSwayWorkspaceName(ws.name)}"`);
+ }
+ } catch (_) {}
+ }
+
+ Binding {
+ target: SettingsData
+ property: "activeCompositor"
+ value: root.compositor
+ }
+
+ Connections {
+ target: SettingsData
+
+ function onCompositorLayoutRefreshNeeded(frame) {
+ if (root.isNiri && typeof NiriService !== "undefined")
+ NiriService.generateNiriLayoutConfig(frame);
+ if (root.isHyprland && typeof HyprlandService !== "undefined")
+ HyprlandService.generateLayoutConfig(frame);
+ if (!frame && root.isMango && typeof MangoService !== "undefined")
+ MangoService.generateLayoutConfig();
+ }
+
+ function onCompositorInputRefreshNeeded() {
+ if (root.isNiri && typeof NiriService !== "undefined")
+ NiriService.generateNiriInputConfig();
+ }
+
+ function onCompositorCursorRefreshNeeded() {
+ if (root.isNiri && typeof NiriService !== "undefined") {
+ NiriService.generateNiriCursorConfig();
+ return;
+ }
+ if (root.isHyprland && typeof HyprlandService !== "undefined") {
+ HyprlandService.generateCursorConfig();
+ return;
+ }
+ if (root.isMango && typeof MangoService !== "undefined") {
+ MangoService.generateCursorConfig();
+ return;
+ }
+ }
+ }
}
diff --git a/quickshell/Services/CupsService.qml b/quickshell/Services/CupsService.qml
index 57d774411..962fc8474 100644
--- a/quickshell/Services/CupsService.qml
+++ b/quickshell/Services/CupsService.qml
@@ -349,14 +349,6 @@ Singleton {
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 [];
@@ -372,14 +364,6 @@ Singleton {
return printer.jobs;
}
- function getJobsNum(printerName) {
- if (!cupsAvailable)
- return 0;
-
- var printer = printers[printerName];
- return printer.jobs.length;
- }
-
function pausePrinter(printerName) {
if (!cupsAvailable)
return;
@@ -579,57 +563,6 @@ Singleton {
});
}
- 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;
@@ -647,23 +580,6 @@ Singleton {
});
}
- 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;
@@ -699,40 +615,6 @@ Singleton {
});
}
- 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;
diff --git a/quickshell/Services/DMSNetworkService.qml b/quickshell/Services/DMSNetworkService.qml
index 95c84d8d0..524cf330a 100644
--- a/quickshell/Services/DMSNetworkService.qml
+++ b/quickshell/Services/DMSNetworkService.qml
@@ -1049,10 +1049,6 @@ Singleton {
return activeUuids && activeUuids.indexOf(uuid) !== -1;
}
- function isActiveUuid(uuid) {
- return isActiveVpnUuid(uuid);
- }
-
function refreshNetworkState() {
if (networkAvailable) {
getState();
diff --git a/quickshell/Services/DMSService.qml b/quickshell/Services/DMSService.qml
index 339ab4b22..3e936f4ad 100644
--- a/quickshell/Services/DMSService.qml
+++ b/quickshell/Services/DMSService.qml
@@ -301,20 +301,6 @@ Singleton {
}
}
- function subscribeAll() {
- subscribe(["all"]);
- }
-
- function subscribeAllExcept(excludeServices) {
- if (!Array.isArray(excludeServices)) {
- excludeServices = [excludeServices];
- }
-
- const allServices = ["network", "loginctl", "freedesktop", "gamma", "theme.auto", "bluetooth", "cups", "brightness", "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")) {
@@ -453,10 +439,6 @@ Singleton {
}
}
- function ping(callback) {
- sendRequest("ping", null, callback);
- }
-
function listPlugins(callback) {
sendRequest("plugins.list", null, response => {
if (response.result) {
@@ -481,30 +463,6 @@ Singleton {
});
}
- 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
@@ -568,19 +526,6 @@ Singleton {
});
}
- 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
@@ -607,19 +552,6 @@ Singleton {
});
}
- 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);
}
@@ -640,30 +572,12 @@ Singleton {
}, 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,
diff --git a/quickshell/Services/DesktopService.qml b/quickshell/Services/DesktopService.qml
index d54d0309f..23b832655 100644
--- a/quickshell/Services/DesktopService.qml
+++ b/quickshell/Services/DesktopService.qml
@@ -18,7 +18,10 @@ Singleton {
property bool systemdAutostartTargetChecked: false
readonly property bool autostartAvailable: root.systemdAutostartTargetChecked && (!root.isSystemd || root.systemdAutostartTargetActive)
- Component.onCompleted: initSystemCheckProcess.running = true
+ Component.onCompleted: {
+ Paths.desktopIconResolver = name => resolveIconPath(name);
+ initSystemCheckProcess.running = true;
+ }
Process {
id: initSystemCheckProcess
diff --git a/quickshell/Services/DgopService.qml b/quickshell/Services/DgopService.qml
index 99a7b4451..406bdf4cc 100644
--- a/quickshell/Services/DgopService.qml
+++ b/quickshell/Services/DgopService.qml
@@ -156,10 +156,6 @@ Singleton {
}
}
- function setGpuPciIds(pciIds) {
- gpuPciIds = Array.isArray(pciIds) ? pciIds : [];
- }
-
function addGpuPciId(pciId) {
const currentCount = gpuPciIdRefCounts[pciId] || 0;
gpuPciIdRefCounts[pciId] = currentCount + 1;
@@ -203,12 +199,6 @@ Singleton {
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;
@@ -476,44 +466,6 @@ Singleton {
}
}
- 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) {
@@ -526,12 +478,6 @@ Singleton {
}
}
- function killProcess(pid) {
- if (pid > 0) {
- Quickshell.execDetached("kill", [pid.toString()]);
- }
- }
-
function updateUptime() {
if (!bootTime) {
uptime = "";
diff --git a/quickshell/Services/DisplayService.qml b/quickshell/Services/DisplayService.qml
index 88c5d611d..8ad163acc 100644
--- a/quickshell/Services/DisplayService.qml
+++ b/quickshell/Services/DisplayService.qml
@@ -1228,10 +1228,6 @@ Singleton {
});
}
- function setNightModeAutomationMode(mode) {
- SessionData.setNightModeAutoMode(mode);
- }
-
function evaluateNightMode() {
if (!nightModeEnabled) {
return;
@@ -1355,6 +1351,14 @@ Singleton {
brightnessChanged();
}
+ Connections {
+ target: SessionData
+
+ function onBrightnessDisplayHintChanged(deviceName) {
+ root.updateDeviceBrightnessDisplay(deviceName);
+ }
+ }
+
Timer {
id: osdSuppressTimer
interval: 2000
diff --git a/quickshell/Services/IconThemeService.qml b/quickshell/Services/IconThemeService.qml
index b44129562..2541a5daa 100644
--- a/quickshell/Services/IconThemeService.qml
+++ b/quickshell/Services/IconThemeService.qml
@@ -37,7 +37,10 @@ Singleton {
}
onManagedThemeChanged: _rebuild()
- Component.onCompleted: _rebuild()
+ Component.onCompleted: {
+ Paths.iconResolver = name => resolve(name);
+ _rebuild();
+ }
function _bumpRevision() {
if (_bumpPending)
diff --git a/quickshell/Services/KeybindsService.qml b/quickshell/Services/KeybindsService.qml
index 5f9b8c720..0ea0bad74 100644
--- a/quickshell/Services/KeybindsService.qml
+++ b/quickshell/Services/KeybindsService.qml
@@ -574,18 +574,6 @@ Singleton {
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);
}
@@ -601,24 +589,4 @@ Singleton {
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/quickshell/Services/MangoService.qml b/quickshell/Services/MangoService.qml
index ba82ed2a0..d3b50c4f2 100644
--- a/quickshell/Services/MangoService.qml
+++ b/quickshell/Services/MangoService.qml
@@ -48,7 +48,6 @@ Singleton {
// windowsChanged is auto-generated by the `windows` property's change signal.
signal stateChanged
- // ── State sockets ──────────────────────────────────────────────────────
// One connection per watch target; mango streams a fresh full snapshot on
// every change, so each line is treated as the complete state.
@@ -272,8 +271,6 @@ Singleton {
root.windows = data.clients;
}
- // ── Tag API (dwl-style tag model) ──────────────────────────────────────
-
function getOutputState(outputName) {
return (outputs && outputs[outputName]) ? outputs[outputName] : null;
}
@@ -296,20 +293,6 @@ Singleton {
return at.length === 0 || at.every(t => t === 0);
}
- 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 getVisibleTags(outputName) {
const output = getOutputState(outputName);
if (!output || !output.tags)
@@ -328,7 +311,6 @@ Singleton {
return displayScales[outputName];
}
- // ── Window list ↔ wlr toplevel matching (per-tag sort/filter) ──────────
// Match mango clients to wlr foreign-toplevels by appId+title to enrich them
// with owning tags/monitor for per-tag filtering and stable ordering.
@@ -452,8 +434,6 @@ Singleton {
return _matchAndEnrich(toplevels, clients);
}
- // ── Commands (mango verb IPC: dispatch