diff --git a/quickshell/Modals/DankLauncherV2/Controller.qml b/quickshell/Modals/DankLauncherV2/Controller.qml
index 67cb6060..9cbba3e7 100644
--- a/quickshell/Modals/DankLauncherV2/Controller.qml
+++ b/quickshell/Modals/DankLauncherV2/Controller.qml
@@ -1442,7 +1442,8 @@ Item {
section: it.section || "",
isCore: it.isCore || false,
isBuiltInLauncher: it.isBuiltInLauncher || false,
- pluginId: it.pluginId || ""
+ pluginId: it.pluginId || "",
+ source: it.source || ""
});
}
serializable.push({
@@ -1497,6 +1498,7 @@ Item {
isCore: it.isCore || false,
isBuiltInLauncher: it.isBuiltInLauncher || false,
pluginId: it.pluginId || "",
+ source: it.source || "",
data: {
id: it.id
},
diff --git a/quickshell/Modals/DankLauncherV2/ControllerUtils.js b/quickshell/Modals/DankLauncherV2/ControllerUtils.js
index a06285fd..b4f5ebe3 100644
--- a/quickshell/Modals/DankLauncherV2/ControllerUtils.js
+++ b/quickshell/Modals/DankLauncherV2/ControllerUtils.js
@@ -101,6 +101,39 @@ function detectIconType(iconName) {
return "material";
}
+function classifyAppSource(app) {
+ if (!app)
+ return "";
+
+ var execRaw = app.execString || app.exec || "";
+ if (!execRaw && !app.id)
+ return "";
+
+ var exec = execRaw.toLowerCase();
+ var cmd0 = (app.command && app.command.length > 0) ? String(app.command[0]).toLowerCase() : "";
+ var id = (app.id || "").toLowerCase();
+
+ if (cmd0 === "flatpak" || exec.indexOf("flatpak run ") !== -1)
+ return "flatpak";
+
+ if (cmd0 === "snap"
+ || exec.indexOf("bamf_desktop_file_hint=") !== -1
+ || exec.indexOf("/snap/bin/") !== -1
+ || exec.indexOf("/snap/core") !== -1
+ || exec.indexOf("snap run ") === 0)
+ return "snap";
+
+ if (/\.appimage(\s|$|")/i.test(execRaw) || id.indexOf("appimagekit_") === 0)
+ return "appimage";
+
+ if (exec.indexOf("/nix/store/") !== -1
+ || exec.indexOf("/run/current-system/sw/") !== -1
+ || exec.indexOf("/etc/profiles/per-user/") !== -1)
+ return "nix";
+
+ return "system";
+}
+
function sortPluginIdsByOrder(pluginIds, order) {
if (!order || order.length === 0)
return pluginIds;
diff --git a/quickshell/Modals/DankLauncherV2/GridItem.qml b/quickshell/Modals/DankLauncherV2/GridItem.qml
index a7f39c33..5d812ae1 100644
--- a/quickshell/Modals/DankLauncherV2/GridItem.qml
+++ b/quickshell/Modals/DankLauncherV2/GridItem.qml
@@ -44,6 +44,15 @@ Rectangle {
cornerRadius: root.radius
}
+ SourceBadge {
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.margins: Theme.spacingXS
+ source: root.item?.type === "app" ? (root.item.source || "") : ""
+ glyphSize: 14
+ z: 1
+ }
+
Column {
anchors.centerIn: parent
anchors.margins: Theme.spacingS
diff --git a/quickshell/Modals/DankLauncherV2/ItemTransformers.js b/quickshell/Modals/DankLauncherV2/ItemTransformers.js
index 61c108ca..d85dee98 100644
--- a/quickshell/Modals/DankLauncherV2/ItemTransformers.js
+++ b/quickshell/Modals/DankLauncherV2/ItemTransformers.js
@@ -27,6 +27,7 @@ function transformApp(app, override, defaultActions, primaryActionLabel) {
data: app,
keywords: app.keywords || [],
actions: actions,
+ source: Utils.classifyAppSource(app),
primaryAction: {
name: primaryActionLabel,
icon: "open_in_new",
diff --git a/quickshell/Modals/DankLauncherV2/ResultItem.qml b/quickshell/Modals/DankLauncherV2/ResultItem.qml
index 0a50cd3e..de00caa9 100644
--- a/quickshell/Modals/DankLauncherV2/ResultItem.qml
+++ b/quickshell/Modals/DankLauncherV2/ResultItem.qml
@@ -191,6 +191,12 @@ Rectangle {
color: Theme.surfaceVariantText
}
}
+
+ SourceBadge {
+ anchors.verticalCenter: parent.verticalCenter
+ source: root.item?.type === "app" ? (root.item.source || "") : ""
+ glyphSize: 14
+ }
}
}
}
diff --git a/quickshell/Modals/DankLauncherV2/SourceBadge.qml b/quickshell/Modals/DankLauncherV2/SourceBadge.qml
new file mode 100644
index 00000000..98ec2414
--- /dev/null
+++ b/quickshell/Modals/DankLauncherV2/SourceBadge.qml
@@ -0,0 +1,32 @@
+import QtQuick
+import Quickshell.Widgets
+
+Item {
+ id: root
+
+ property string source: ""
+ property int glyphSize: 14
+
+ readonly property var sourceAsset: ({
+ "flatpak": "../../assets/package-sources/flatpak.svg",
+ "snap": "../../assets/package-sources/snap.svg",
+ "appimage": "../../assets/package-sources/appimage.svg",
+ "nix": "../../assets/package-sources/nix.svg"
+ })
+
+ readonly property string assetPath: sourceAsset[source] || ""
+
+ visible: assetPath.length > 0
+ implicitWidth: glyphSize
+ implicitHeight: glyphSize
+
+ IconImage {
+ anchors.fill: parent
+ source: root.assetPath ? Qt.resolvedUrl(root.assetPath) : ""
+ implicitSize: root.glyphSize * 2
+ backer.sourceSize: Qt.size(root.glyphSize * 2, root.glyphSize * 2)
+ smooth: true
+ mipmap: true
+ asynchronous: true
+ }
+}
diff --git a/quickshell/Modals/DankLauncherV2/TileItem.qml b/quickshell/Modals/DankLauncherV2/TileItem.qml
index 0b488025..d4837412 100644
--- a/quickshell/Modals/DankLauncherV2/TileItem.qml
+++ b/quickshell/Modals/DankLauncherV2/TileItem.qml
@@ -168,6 +168,15 @@ Rectangle {
mipmap: true
}
}
+
+ SourceBadge {
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.margins: Theme.spacingXS
+ source: root.item?.type === "app" ? (root.item.source || "") : ""
+ glyphSize: 16
+ visible: !root.isSelected && !!source
+ }
}
}
diff --git a/quickshell/assets/package-sources/appimage.svg b/quickshell/assets/package-sources/appimage.svg
new file mode 100644
index 00000000..8ffb922c
--- /dev/null
+++ b/quickshell/assets/package-sources/appimage.svg
@@ -0,0 +1,278 @@
+
+
+
+
diff --git a/quickshell/assets/package-sources/flatpak.svg b/quickshell/assets/package-sources/flatpak.svg
new file mode 100644
index 00000000..8c27b54a
--- /dev/null
+++ b/quickshell/assets/package-sources/flatpak.svg
@@ -0,0 +1 @@
+
diff --git a/quickshell/assets/package-sources/nix.svg b/quickshell/assets/package-sources/nix.svg
new file mode 100644
index 00000000..2a065bc9
--- /dev/null
+++ b/quickshell/assets/package-sources/nix.svg
@@ -0,0 +1,187 @@
+
+
+
+
diff --git a/quickshell/assets/package-sources/snap.svg b/quickshell/assets/package-sources/snap.svg
new file mode 100644
index 00000000..b2c50ea1
--- /dev/null
+++ b/quickshell/assets/package-sources/snap.svg
@@ -0,0 +1 @@
+