diff --git a/quickshell/DMSShell.qml b/quickshell/DMSShell.qml index 563afe18..c3e930e7 100644 --- a/quickshell/DMSShell.qml +++ b/quickshell/DMSShell.qml @@ -606,6 +606,10 @@ Item { active: false + Component.onCompleted: { + PopoutService.processListModalLoader = processListModalLoader; + } + ProcessListModal { id: processListModal @@ -642,6 +646,17 @@ Item { expandedWidthValue: 960 customTransparency: SettingsData.notepadTransparencyOverride + Component.onCompleted: { + PopoutService.notepadSlideouts.push(notepadSlideout); + } + + Component.onDestruction: { + const index = PopoutService.notepadSlideouts.indexOf(notepadSlideout); + if (index > -1) { + PopoutService.notepadSlideouts.splice(index, 1); + } + } + content: Component { Notepad { onHideRequested: { diff --git a/quickshell/Modals/Spotlight/SpotlightModal.qml b/quickshell/Modals/Spotlight/SpotlightModal.qml index 2c12f221..95e60010 100644 --- a/quickshell/Modals/Spotlight/SpotlightModal.qml +++ b/quickshell/Modals/Spotlight/SpotlightModal.qml @@ -23,6 +23,7 @@ DankModal { if (!spotlightContent) return; if (spotlightContent.appLauncher) { + spotlightContent.appLauncher.suppressUpdatesWhileLaunching = false; spotlightContent.appLauncher.searchQuery = ""; spotlightContent.appLauncher.selectedIndex = 0; spotlightContent.appLauncher.setCategory(I18n.tr("All")); diff --git a/quickshell/Services/AppSearchService.qml b/quickshell/Services/AppSearchService.qml index 328983a2..9300c3b3 100644 --- a/quickshell/Services/AppSearchService.qml +++ b/quickshell/Services/AppSearchService.qml @@ -44,25 +44,25 @@ Singleton { readonly property var coreApps: [ { - name: "DMS Settings", - icon: Qt.resolvedUrl("../assets/danklogo2.svg"), - comment: "Manage DMS configuration", + name: I18n.tr("DMS"), + icon: "svg:../assets/danklogo2.svg", + comment: I18n.tr("Settings"), action: "ipc:settings", categories: ["Settings", "System"], isCore: true }, { - name: "DMS Notepad", + name: I18n.tr("DMS"), icon: "material:description", - comment: "Quick notes", + comment: I18n.tr("Notepad"), action: "ipc:notepad", categories: ["Office", "Utility"], isCore: true }, { - name: "DMS System Monitor", + name: I18n.tr("DMS"), icon: "material:monitor_heart", - comment: "System monitor and process list", + comment: I18n.tr("System Monitor"), action: "ipc:processlist", categories: ["System", "Monitor"], isCore: true @@ -91,13 +91,13 @@ Singleton { if (actionType === "ipc") { if (actionTarget === "settings") { - Quickshell.execDetached(["dms", "ipc", "call", "settings", "toggle"]); + PopoutService.focusOrToggleSettings(); return true; } else if (actionTarget === "notepad") { - Quickshell.execDetached(["dms", "ipc", "call", "notepad", "toggle"]); + PopoutService.toggleNotepad(); return true; } else if (actionTarget === "processlist") { - Quickshell.execDetached(["dms", "ipc", "call", "processlist", "focusOrToggle"]); + PopoutService.toggleProcessListModal(); return true; } } diff --git a/quickshell/Services/PopoutService.qml b/quickshell/Services/PopoutService.qml index 9df3d2da..f1042827 100644 --- a/quickshell/Services/PopoutService.qml +++ b/quickshell/Services/PopoutService.qml @@ -23,6 +23,7 @@ Singleton { property var spotlightModal: null property var powerMenuModal: null property var processListModal: null + property var processListModalLoader: null property var colorPickerModal: null property var notificationModal: null property var wifiPasswordModal: null @@ -357,6 +358,9 @@ Singleton { } function showProcessListModal() { + if (processListModalLoader) { + processListModalLoader.active = true; + } processListModal?.show(); } @@ -365,6 +369,9 @@ Singleton { } function toggleProcessListModal() { + if (processListModalLoader) { + processListModalLoader.active = true; + } processListModal?.toggle(); } diff --git a/quickshell/Widgets/AppIconRenderer.qml b/quickshell/Widgets/AppIconRenderer.qml index f4acebe5..77cf6ccd 100644 --- a/quickshell/Widgets/AppIconRenderer.qml +++ b/quickshell/Widgets/AppIconRenderer.qml @@ -24,9 +24,13 @@ Item { readonly property bool isMaterial: iconValue.startsWith("material:") readonly property bool isUnicode: iconValue.startsWith("unicode:") + readonly property bool isSvg: iconValue.startsWith("svg:") readonly property string materialName: isMaterial ? iconValue.substring(9) : "" readonly property string unicodeChar: isUnicode ? iconValue.substring(8) : "" - readonly property string iconPath: isMaterial || isUnicode ? "" : Quickshell.iconPath(iconValue, true) || DesktopService.resolveIconPath(iconValue) + readonly property string svgPath: isSvg ? iconValue.substring(4) : "" + readonly property bool isFileUrl: iconValue.startsWith("file://") || iconValue.startsWith("qrc:/") + readonly property string iconPath: (isMaterial || isUnicode || isSvg || isFileUrl) ? "" : Quickshell.iconPath(iconValue, true) || DesktopService.resolveIconPath(iconValue) + readonly property string resolvedIconPath: isSvg ? Qt.resolvedUrl(svgPath) : (isFileUrl ? iconValue : iconPath) visible: iconValue !== undefined && iconValue !== "" @@ -46,6 +50,21 @@ Item { visible: root.isUnicode } + Image { + id: svgOrFileUrlImg + + anchors.fill: parent + source: root.resolvedIconPath + sourceSize.width: root.iconSize * 2 + sourceSize.height: root.iconSize * 2 + smooth: true + mipmap: true + asynchronous: true + cache: true + fillMode: Image.PreserveAspectFit + visible: (root.isSvg || root.isFileUrl) && status === Image.Ready + } + IconImage { id: iconImg @@ -53,7 +72,7 @@ Item { source: root.iconPath smooth: true asynchronous: true - visible: !root.isMaterial && !root.isUnicode && root.iconPath !== "" && status === Image.Ready + visible: !root.isMaterial && !root.isUnicode && !root.isSvg && !root.isFileUrl && root.iconPath !== "" && status === Image.Ready } Rectangle { @@ -64,7 +83,7 @@ Item { anchors.rightMargin: root.fallbackRightMargin anchors.topMargin: root.fallbackTopMargin anchors.bottomMargin: root.fallbackBottomMargin - visible: !root.isMaterial && !root.isUnicode && (root.iconPath === "" || iconImg.status !== Image.Ready) + visible: !root.isMaterial && !root.isUnicode && !root.isSvg && !root.isFileUrl && (root.iconPath === "" || iconImg.status !== Image.Ready) color: root.fallbackBackgroundColor radius: Theme.cornerRadius border.width: 0 diff --git a/quickshell/Widgets/DankSVGIcon.qml b/quickshell/Widgets/DankSVGIcon.qml new file mode 100644 index 00000000..964e8320 --- /dev/null +++ b/quickshell/Widgets/DankSVGIcon.qml @@ -0,0 +1,83 @@ +import QtQuick +import QtQuick.Effects +import Quickshell.Widgets +import qs.Common +import qs.Widgets + +Item { + id: root + + required property string source + property int size: 24 + property string cornerIcon: "" + property int cornerIconSize: Math.max(10, size * 0.4) + property color cornerIconColor: Theme.surfaceText + property color cornerIconBackground: Theme.surface + property color colorOverride: "transparent" + property real brightnessOverride: 0.0 + property real contrastOverride: 0.0 + property real saturationOverride: 0.0 + + readonly property bool hasCornerIcon: cornerIcon !== "" + readonly property bool hasColorOverride: colorOverride.a > 0 + readonly property bool hasColorEffect: hasColorOverride || brightnessOverride !== 0.0 || contrastOverride !== 0.0 || saturationOverride !== 0.0 + readonly property string resolvedSource: { + if (!source) + return ""; + if (source.startsWith("file://")) + return source; + if (source.startsWith("/")) + return "file://" + source; + if (source.startsWith("qrc:")) + return source; + return source; + } + + implicitWidth: size + implicitHeight: size + + Image { + id: iconImage + + anchors.fill: parent + source: root.resolvedSource + sourceSize.width: root.size * 2 + sourceSize.height: root.size * 2 + smooth: true + mipmap: true + asynchronous: true + cache: true + fillMode: Image.PreserveAspectFit + layer.enabled: root.hasColorEffect + layer.smooth: true + layer.mipmap: true + layer.effect: MultiEffect { + saturation: root.saturationOverride + colorization: root.hasColorOverride ? 1 : 0 + colorizationColor: root.colorOverride + brightness: root.brightnessOverride + contrast: root.contrastOverride + } + } + + Rectangle { + visible: root.hasCornerIcon + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.rightMargin: -2 + anchors.bottomMargin: -2 + width: root.cornerIconSize + 4 + height: root.cornerIconSize + 4 + radius: width / 2 + color: root.cornerIconBackground + border.width: 1 + border.color: Theme.surfaceLight + + DankIcon { + anchors.centerIn: parent + name: root.cornerIcon + size: root.cornerIconSize + color: root.cornerIconColor + } + } +}