diff --git a/quickshell/Common/ModalManager.qml b/quickshell/Common/ModalManager.qml index 2197fb96..224436e8 100644 --- a/quickshell/Common/ModalManager.qml +++ b/quickshell/Common/ModalManager.qml @@ -8,6 +8,9 @@ Singleton { id: modalManager signal closeAllModalsExcept(var excludedModal) + signal modalChanged + + property var currentModalsByScreen: ({}) function openModal(modal) { if (!modal.allowStacking) { @@ -17,5 +20,17 @@ Singleton { PopoutManager.closeAllPopouts(); } TrayMenuManager.closeAllMenus(); + + const screenName = modal.effectiveScreen?.name ?? "unknown"; + currentModalsByScreen[screenName] = modal; + modalChanged(); + } + + function closeModal(modal) { + const screenName = modal.effectiveScreen?.name ?? "unknown"; + if (currentModalsByScreen[screenName] === modal) { + delete currentModalsByScreen[screenName]; + modalChanged(); + } } } diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index ff3ad46d..dd462a32 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -715,7 +715,42 @@ Singleton { } function detectAvailableIconThemes() { - Processes.detectIcons(); + const xdgDataDirs = Quickshell.env("XDG_DATA_DIRS") || ""; + const localData = Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericDataLocation)); + const homeDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.HomeLocation)); + + const dataDirs = xdgDataDirs.trim() !== "" ? xdgDataDirs.split(":").concat([localData]) : ["/usr/share", "/usr/local/share", localData]; + + const iconPaths = dataDirs.map(d => d + "/icons").concat([homeDir + "/.icons"]); + const pathsArg = iconPaths.join(" "); + + const script = ` + echo "SYSDEFAULT:$(gsettings get org.gnome.desktop.interface icon-theme 2>/dev/null | sed "s/'//g" || echo '')" + for dir in ${pathsArg}; do + [ -d "$dir" ] || continue + for theme in "$dir"/*/; do + [ -d "$theme" ] || continue + basename "$theme" + done + done | grep -v '^icons$' | grep -v '^default$' | grep -v '^hicolor$' | grep -v '^locolor$' | sort -u + `; + + Proc.runCommand("detectIconThemes", ["sh", "-c", script], (output, exitCode) => { + const themes = ["System Default"]; + if (output && output.trim()) { + const lines = output.trim().split('\n'); + for (let i = 0; i < lines.length; i++) { + const line = lines[i].trim(); + if (line.startsWith("SYSDEFAULT:")) { + systemDefaultIconTheme = line.substring(11).trim(); + continue; + } + if (line) + themes.push(line); + } + } + availableIconThemes = themes; + }); } function getEffectiveTimeFormat() { diff --git a/quickshell/Common/settings/Processes.qml b/quickshell/Common/settings/Processes.qml index 3dfb45f3..dc8cb48e 100644 --- a/quickshell/Common/settings/Processes.qml +++ b/quickshell/Common/settings/Processes.qml @@ -1,5 +1,4 @@ pragma Singleton - pragma ComponentBehavior: Bound import QtQuick @@ -11,61 +10,20 @@ Singleton { property var settingsRoot: null - function detectIcons() { - systemDefaultDetectionProcess.running = true - } - function detectQtTools() { - qtToolsDetectionProcess.running = true + qtToolsDetectionProcess.running = true; } function detectFprintd() { - fprintdDetectionProcess.running = true + fprintdDetectionProcess.running = true; } function checkPluginSettings() { - pluginSettingsCheckProcess.running = true + pluginSettingsCheckProcess.running = true; } function checkDefaultSettings() { - defaultSettingsCheckProcess.running = true - } - - property var systemDefaultDetectionProcess: Process { - command: ["sh", "-c", "gsettings get org.gnome.desktop.interface icon-theme 2>/dev/null | sed \"s/'//g\" || echo ''"] - running: false - onExited: function(exitCode) { - if (!settingsRoot) return; - if (exitCode === 0 && stdout && stdout.length > 0) { - settingsRoot.systemDefaultIconTheme = stdout.trim(); - } else { - settingsRoot.systemDefaultIconTheme = ""; - } - iconThemeDetectionProcess.running = true; - } - } - - property var iconThemeDetectionProcess: Process { - - command: ["sh", "-c", "find /usr/share/icons ~/.local/share/icons ~/.icons -maxdepth 1 -type d 2>/dev/null | sed 's|.*/||' | grep -v '^icons$' | sort -u"] - running: false - - stdout: StdioCollector { - onStreamFinished: { - if (!settingsRoot) return - var detectedThemes = ["System Default"] - if (text && text.trim()) { - var themes = text.trim().split('\n') - for (var i = 0; i < themes.length; i++) { - var theme = themes[i].trim() - if (theme && theme !== "" && theme !== "default" && theme !== "hicolor" && theme !== "locolor") { - detectedThemes.push(theme) - } - } - } - settingsRoot.availableIconThemes = detectedThemes - } - } + defaultSettingsCheckProcess.running = true; } property var qtToolsDetectionProcess: Process { @@ -74,7 +32,8 @@ Singleton { stdout: StdioCollector { onStreamFinished: { - if (!settingsRoot) return; + if (!settingsRoot) + return; if (text && text.trim()) { var lines = text.trim().split('\n'); for (var i = 0; i < lines.length; i++) { @@ -95,8 +54,9 @@ Singleton { property var defaultSettingsCheckProcess: Process { command: ["sh", "-c", "CONFIG_DIR=\"" + (settingsRoot?._configDir || "") + "/DankMaterialShell\"; if [ -f \"$CONFIG_DIR/default-settings.json\" ] && [ ! -f \"$CONFIG_DIR/settings.json\" ]; then cp --no-preserve=mode \"$CONFIG_DIR/default-settings.json\" \"$CONFIG_DIR/settings.json\" && echo 'copied'; else echo 'not_found'; fi"] running: false - onExited: function(exitCode) { - if (!settingsRoot) return; + onExited: function (exitCode) { + if (!settingsRoot) + return; if (exitCode === 0) { console.info("Copied default-settings.json to settings.json"); if (settingsRoot.settingsFile) { @@ -113,8 +73,9 @@ Singleton { property var fprintdDetectionProcess: Process { command: ["sh", "-c", "command -v fprintd-list >/dev/null 2>&1"] running: false - onExited: function(exitCode) { - if (!settingsRoot) return; + onExited: function (exitCode) { + if (!settingsRoot) + return; settingsRoot.fprintdAvailable = (exitCode === 0); } } @@ -123,8 +84,9 @@ Singleton { command: ["test", "-f", settingsRoot?.pluginSettingsPath || ""] running: false - onExited: function(exitCode) { - if (!settingsRoot) return; + onExited: function (exitCode) { + if (!settingsRoot) + return; settingsRoot.pluginSettingsFileExists = (exitCode === 0); } } diff --git a/quickshell/Modals/Common/DankModal.qml b/quickshell/Modals/Common/DankModal.qml index 48f05aae..18776f7b 100644 --- a/quickshell/Modals/Common/DankModal.qml +++ b/quickshell/Modals/Common/DankModal.qml @@ -83,6 +83,7 @@ Item { function close() { shouldBeVisible = false; shouldHaveFocus = false; + ModalManager.closeModal(root); closeTimer.restart(); } @@ -90,6 +91,7 @@ Item { animationsEnabled = false; shouldBeVisible = false; shouldHaveFocus = false; + ModalManager.closeModal(root); closeTimer.stop(); contentWindow.visible = false; if (useBackgroundWindow) diff --git a/quickshell/Modules/Settings/ThemeColorsTab.qml b/quickshell/Modules/Settings/ThemeColorsTab.qml index 0ae7eacb..91f86da0 100644 --- a/quickshell/Modules/Settings/ThemeColorsTab.qml +++ b/quickshell/Modules/Settings/ThemeColorsTab.qml @@ -10,15 +10,11 @@ import qs.Modules.Settings.Widgets Item { id: themeColorsTab - property var cachedIconThemes: [] - property var cachedMatugenSchemes: [] + property var cachedIconThemes: SettingsData.availableIconThemes + property var cachedMatugenSchemes: Theme.availableMatugenSchemes.map(option => option.label) Component.onCompleted: { SettingsData.detectAvailableIconThemes(); - cachedIconThemes = SettingsData.availableIconThemes; - cachedMatugenSchemes = Theme.availableMatugenSchemes.map(function (option) { - return option.label; - }); } DankFlickable { diff --git a/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml b/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml index 81464ce8..96454ab6 100644 --- a/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml +++ b/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml @@ -92,6 +92,7 @@ Scope { readonly property bool shouldShowSpotlight: niriOverviewScope.searchActive && screen.name === niriOverviewScope.searchActiveScreen && !niriOverviewScope.isClosing readonly property bool isSpotlightScreen: screen.name === niriOverviewScope.searchActiveScreen property bool hasActivePopout: !!PopoutManager.currentPopoutsByScreen[screen.name] + property bool hasActiveModal: !!ModalManager.currentModalsByScreen[screen.name] Connections { target: PopoutManager @@ -100,6 +101,13 @@ Scope { } } + Connections { + target: ModalManager + function onModalChanged() { + overlayWindow.hasActiveModal = !!ModalManager.currentModalsByScreen[overlayWindow.screen.name]; + } + } + screen: modelData visible: NiriService.inOverview || niriOverviewScope.isClosing color: "transparent" @@ -114,7 +122,7 @@ Scope { return WlrKeyboardFocus.None; if (niriOverviewScope.releaseKeyboard) return WlrKeyboardFocus.None; - if (hasActivePopout) + if (hasActivePopout || hasActiveModal) return WlrKeyboardFocus.None; return WlrKeyboardFocus.Exclusive; }