mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-05-15 08:42:47 -04:00
feat(settings): Added Default Apps page to settings (#2416)
* feat(settings): Added Default Apps page to settings Added a new page to settings. This page relies on xdg-mime and gio, so their existence is checked to show the page. This logic and the mime type stuff was added to DesktopService.qml. Slightly reordered the settings sidebar to include an Applications category * fix(settings): read xdg-terminals.list directly read the file directly instead of using xdg-terminal-exec which might not be installed
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
import Quickshell.Io
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
@@ -8,6 +9,27 @@ Singleton {
|
||||
id: root
|
||||
|
||||
property var _cache: ({})
|
||||
property bool gioAvailable: false;
|
||||
// For the queue that setDefaultApp uses
|
||||
property var _setDefaultAppQueue: []
|
||||
property bool _isProcessingQueue: false
|
||||
|
||||
Component.onCompleted: {
|
||||
checkGioAndXdgMime.running = true;
|
||||
}
|
||||
|
||||
Process {
|
||||
id: checkGioAndXdgMime
|
||||
command: ["sh", "-c", "which gio && which xdg-mime"]
|
||||
running: false
|
||||
onExited: (exitCode) => {
|
||||
if (exitCode === 0) {
|
||||
root.gioAvailable = true;
|
||||
} else {
|
||||
root.gioAvailable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resolveIconPath(moddedAppId) {
|
||||
if (!moddedAppId)
|
||||
@@ -89,4 +111,181 @@ Singleton {
|
||||
_cache[moddedAppId] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Set default app for a MIME type
|
||||
Component {
|
||||
id: gioSetDefaultApp
|
||||
|
||||
Process {
|
||||
property string targetMimeType: ""
|
||||
property string targetDesktopFileId: ""
|
||||
property string callbackId: ""
|
||||
|
||||
// Check if the app actually supports the MIME type before setting it as default
|
||||
// This uses a shell script
|
||||
command: ["sh", "-c", `
|
||||
apps=$(gio mime "${targetMimeType}" 2>/dev/null | grep -v "^Default" | awk '{print $1}')
|
||||
if echo "$apps" | grep -Fxq "${targetDesktopFileId}"; then
|
||||
xdg-mime default "${targetDesktopFileId}" "${targetMimeType}"
|
||||
gio mime "${targetMimeType}" "${targetDesktopFileId}"
|
||||
fi
|
||||
`]
|
||||
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
const success = (exitCode === 0)
|
||||
if (!success) {
|
||||
log.error("DesktopService: failed to set default app for", targetMimeType, "to", targetDesktopFileId, "(exit code:", exitCode + ")")
|
||||
}
|
||||
root._processDefaultAppQueue()
|
||||
destroy()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setDefaultApp(mimeType, desktopFileId, callbackId = "") {
|
||||
// Add .desktop in case it's missing, xdg-mime needs it
|
||||
if (!desktopFileId.endsWith(".desktop")) {
|
||||
desktopFileId += ".desktop";
|
||||
}
|
||||
|
||||
// Queue the request to avoid race conditions
|
||||
_setDefaultAppQueue.push({
|
||||
mimeType: mimeType,
|
||||
desktopFileId: desktopFileId,
|
||||
callbackId: callbackId
|
||||
})
|
||||
|
||||
// Start processing the queue if not already running
|
||||
if (!_isProcessingQueue) {
|
||||
_processDefaultAppQueue()
|
||||
}
|
||||
}
|
||||
|
||||
function _processDefaultAppQueue() {
|
||||
if (_setDefaultAppQueue.length === 0) {
|
||||
_isProcessingQueue = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_isProcessingQueue = true;
|
||||
const request = _setDefaultAppQueue.shift();
|
||||
|
||||
const proc = gioSetDefaultApp.createObject(root, {
|
||||
targetMimeType: request.mimeType,
|
||||
targetDesktopFileId: request.desktopFileId,
|
||||
callbackId: request.callbackId,
|
||||
running: true
|
||||
})
|
||||
|
||||
if (!proc) {
|
||||
log.warn("DesktopService: couldn't create process for", request.mimeType, request.desktopFileId)
|
||||
_processDefaultAppQueue()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Get default app for a MIME type
|
||||
Component {
|
||||
id: xdgGetDefaultApp
|
||||
|
||||
Process {
|
||||
property string targetMimeType: ""
|
||||
property string callbackId: ""
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const desktopFileId = text.trim();
|
||||
root.getDefaultAppResult(targetMimeType, desktopFileId, callbackId);
|
||||
}
|
||||
}
|
||||
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text.trim().length > 0) {
|
||||
log.error("DesktopService: xdg-mime query error:", text, "mime:", targetMimeType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: (exitCode, exitStatus) => { destroy() }
|
||||
}
|
||||
}
|
||||
|
||||
function getDefaultApp(mimeType, callbackId = "") {
|
||||
const proc = xdgGetDefaultApp.createObject(root, {
|
||||
targetMimeType: mimeType,
|
||||
callbackId: callbackId,
|
||||
command: ["xdg-mime", "query", "default", mimeType],
|
||||
running: true
|
||||
})
|
||||
|
||||
if (!proc) {
|
||||
log.warn("DesktopService: couldn't create process for", mimeType)
|
||||
}
|
||||
}
|
||||
|
||||
signal getDefaultAppResult(string mimeType, string desktopFileId, string callbackId)
|
||||
|
||||
|
||||
|
||||
// Get apps that support a MIME type
|
||||
Component {
|
||||
id: gioGetAppsForMime
|
||||
|
||||
Process {
|
||||
property string targetMimeType: ""
|
||||
property string callbackId: ""
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const lines = text.split("\n");
|
||||
let appIds = [];
|
||||
let seen = {};
|
||||
|
||||
for (let line of lines) {
|
||||
const trimmed = line.trim();
|
||||
if (
|
||||
trimmed &&
|
||||
trimmed.endsWith(".desktop") &&
|
||||
!trimmed.startsWith("Default") &&
|
||||
!trimmed.startsWith("default=")
|
||||
) {
|
||||
if (!seen[trimmed]) {
|
||||
seen[trimmed] = true;
|
||||
appIds.push(trimmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
root.getAppsForMimeResult(targetMimeType, appIds, callbackId);
|
||||
}
|
||||
}
|
||||
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text.trim().length > 0) {
|
||||
log.error("DesktopService: gio mime query error:", text, "command:", command, "mime:", targetMimeType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: (exitCode, exitStatus) => { destroy() }
|
||||
}
|
||||
}
|
||||
|
||||
function getAppsForMimeType(mimeType, callbackId = "") {
|
||||
const proc = gioGetAppsForMime.createObject(root, {
|
||||
targetMimeType: mimeType,
|
||||
callbackId: callbackId,
|
||||
command: ["gio", "mime", mimeType],
|
||||
running: true
|
||||
});
|
||||
|
||||
if (!proc) {
|
||||
log.warn("DesktopService: couldn't create process for", mimeType)
|
||||
}
|
||||
}
|
||||
|
||||
signal getAppsForMimeResult(string mimeType, var appIds, string callbackId)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user