mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-22 19:15:24 -04:00
theme/icons: add separate light/dark path, hot-reload, detect external
DMS maangedand reset fixes #608 closes #2674
This commit is contained in:
+22
-12
@@ -74,6 +74,15 @@ Singleton {
|
|||||||
return appId;
|
return appId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function themedIconPath(name: string): string {
|
||||||
|
if (!name)
|
||||||
|
return "";
|
||||||
|
const themed = (typeof IconThemeService !== "undefined") ? IconThemeService.resolve(name) : "";
|
||||||
|
if (themed)
|
||||||
|
return themed;
|
||||||
|
return Quickshell.iconPath(name, true);
|
||||||
|
}
|
||||||
|
|
||||||
function resolveIconPath(iconName: string): string {
|
function resolveIconPath(iconName: string): string {
|
||||||
if (!iconName)
|
if (!iconName)
|
||||||
return "";
|
return "";
|
||||||
@@ -83,23 +92,24 @@ Singleton {
|
|||||||
return toFileUrl(expandTilde(moddedId));
|
return toFileUrl(expandTilde(moddedId));
|
||||||
if (moddedId.startsWith("file://"))
|
if (moddedId.startsWith("file://"))
|
||||||
return moddedId;
|
return moddedId;
|
||||||
return Quickshell.iconPath(moddedId, true);
|
return themedIconPath(moddedId);
|
||||||
}
|
}
|
||||||
return Quickshell.iconPath(iconName, true) || DesktopService.resolveIconPath(iconName);
|
return themedIconPath(iconName) || DesktopService.resolveIconPath(iconName);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveIconUrl(iconName: string): string {
|
function resolveIconUrl(iconName: string): string {
|
||||||
if (!iconName)
|
if (!iconName)
|
||||||
return "";
|
return "";
|
||||||
const moddedId = moddedAppId(iconName);
|
const moddedId = moddedAppId(iconName);
|
||||||
if (moddedId !== iconName) {
|
const target = (moddedId !== iconName) ? moddedId : iconName;
|
||||||
if (moddedId.startsWith("~") || moddedId.startsWith("/"))
|
if (target.startsWith("~") || target.startsWith("/"))
|
||||||
return toFileUrl(expandTilde(moddedId));
|
return toFileUrl(expandTilde(target));
|
||||||
if (moddedId.startsWith("file://"))
|
if (target.startsWith("file://"))
|
||||||
return moddedId;
|
return target;
|
||||||
return "image://icon/" + moddedId;
|
const themed = (typeof IconThemeService !== "undefined") ? IconThemeService.resolve(target) : "";
|
||||||
}
|
if (themed)
|
||||||
return "image://icon/" + iconName;
|
return themed;
|
||||||
|
return "image://icon/" + target;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAppIcon(appId: string, desktopEntry: var): string {
|
function getAppIcon(appId: string, desktopEntry: var): string {
|
||||||
@@ -113,10 +123,10 @@ Singleton {
|
|||||||
return resolveIconPath(appId);
|
return resolveIconPath(appId);
|
||||||
|
|
||||||
if (desktopEntry && desktopEntry.icon) {
|
if (desktopEntry && desktopEntry.icon) {
|
||||||
return Quickshell.iconPath(desktopEntry.icon, true);
|
return themedIconPath(desktopEntry.icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
const icon = Quickshell.iconPath(appId, true);
|
const icon = themedIconPath(appId);
|
||||||
if (icon && icon !== "")
|
if (icon && icon !== "")
|
||||||
return icon;
|
return icon;
|
||||||
|
|
||||||
|
|||||||
@@ -487,7 +487,11 @@ Singleton {
|
|||||||
|
|
||||||
property string networkPreference: "auto"
|
property string networkPreference: "auto"
|
||||||
|
|
||||||
property string iconTheme: "System Default"
|
property string iconThemeDark: "System Default"
|
||||||
|
property string iconThemeLight: "System Default"
|
||||||
|
property bool iconThemePerMode: false
|
||||||
|
property string lastAppliedIconTheme: ""
|
||||||
|
readonly property string iconTheme: resolveIconTheme()
|
||||||
property var availableIconThemes: ["System Default"]
|
property var availableIconThemes: ["System Default"]
|
||||||
property string systemDefaultIconTheme: ""
|
property string systemDefaultIconTheme: ""
|
||||||
property bool qt5ctAvailable: false
|
property bool qt5ctAvailable: false
|
||||||
@@ -1279,14 +1283,67 @@ Singleton {
|
|||||||
MangoService.generateLayoutConfig();
|
MangoService.generateLayoutConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveIconTheme() {
|
||||||
|
if (iconThemePerMode && typeof SessionData !== "undefined" && SessionData.isLightMode)
|
||||||
|
return iconThemeLight;
|
||||||
|
return iconThemeDark;
|
||||||
|
}
|
||||||
|
|
||||||
function applyStoredIconTheme() {
|
function applyStoredIconTheme() {
|
||||||
updateGtkIconTheme();
|
updateGtkIconTheme();
|
||||||
updateQtIconTheme();
|
updateQtIconTheme();
|
||||||
updateCosmicIconTheme();
|
updateCosmicIconTheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setIconThemeUnmanaged() {
|
||||||
|
iconThemePerMode = false;
|
||||||
|
iconThemeDark = "System Default";
|
||||||
|
iconThemeLight = "System Default";
|
||||||
|
lastAppliedIconTheme = "";
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkIconThemeDrift() {
|
||||||
|
if (isGreeterMode)
|
||||||
|
return;
|
||||||
|
if (resolveIconTheme() === "System Default")
|
||||||
|
return;
|
||||||
|
if (!lastAppliedIconTheme)
|
||||||
|
return;
|
||||||
|
const script = `if command -v gsettings >/dev/null 2>&1; then
|
||||||
|
gsettings get org.gnome.desktop.interface icon-theme 2>/dev/null | sed "s/'//g"
|
||||||
|
elif command -v dconf >/dev/null 2>&1; then
|
||||||
|
dconf read /org/gnome/desktop/interface/icon-theme 2>/dev/null | sed "s/'//g"
|
||||||
|
fi`;
|
||||||
|
|
||||||
|
Proc.runCommand("iconThemeDriftCheck", ["sh", "-c", script], (output, exitCode) => {
|
||||||
|
const platform = (output || "").trim();
|
||||||
|
if (!platform)
|
||||||
|
return;
|
||||||
|
if (platform === root.lastAppliedIconTheme || platform === root.iconThemeDark || platform === root.iconThemeLight)
|
||||||
|
return;
|
||||||
|
root.setIconThemeUnmanaged();
|
||||||
|
ToastService.showWarning(I18n.tr("Icon theme changed outside DMS; switched to System Default", "shown when an external tool overrides the icon theme DMS applied"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: typeof SessionData !== "undefined" ? SessionData : null
|
||||||
|
function onIsLightModeChanged() {
|
||||||
|
if (!SessionData.isSwitchingMode)
|
||||||
|
return;
|
||||||
|
if (!root.iconThemePerMode)
|
||||||
|
return;
|
||||||
|
if (root.iconThemeLight === root.iconThemeDark)
|
||||||
|
return;
|
||||||
|
root.applyStoredIconTheme();
|
||||||
|
root.saveSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateCosmicIconTheme() {
|
function updateCosmicIconTheme() {
|
||||||
let cosmicThemeName = (iconTheme === "System Default") ? systemDefaultIconTheme : iconTheme;
|
const resolved = resolveIconTheme();
|
||||||
|
let cosmicThemeName = (resolved === "System Default") ? systemDefaultIconTheme : resolved;
|
||||||
if (!cosmicThemeName || cosmicThemeName === "System Default") {
|
if (!cosmicThemeName || cosmicThemeName === "System Default") {
|
||||||
const detectScript = `if command -v gsettings >/dev/null 2>&1; then
|
const detectScript = `if command -v gsettings >/dev/null 2>&1; then
|
||||||
gsettings get org.gnome.desktop.interface icon-theme 2>/dev/null | sed "s/'//g"
|
gsettings get org.gnome.desktop.interface icon-theme 2>/dev/null | sed "s/'//g"
|
||||||
@@ -1322,9 +1379,11 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateGtkIconTheme() {
|
function updateGtkIconTheme() {
|
||||||
const gtkThemeName = (iconTheme === "System Default") ? systemDefaultIconTheme : iconTheme;
|
const resolved = resolveIconTheme();
|
||||||
|
const gtkThemeName = (resolved === "System Default") ? systemDefaultIconTheme : resolved;
|
||||||
if (gtkThemeName === "System Default" || gtkThemeName === "")
|
if (gtkThemeName === "System Default" || gtkThemeName === "")
|
||||||
return;
|
return;
|
||||||
|
lastAppliedIconTheme = gtkThemeName;
|
||||||
if (typeof DMSService !== "undefined" && DMSService.apiVersion >= 3 && typeof PortalService !== "undefined") {
|
if (typeof DMSService !== "undefined" && DMSService.apiVersion >= 3 && typeof PortalService !== "undefined") {
|
||||||
PortalService.setSystemIconTheme(gtkThemeName);
|
PortalService.setSystemIconTheme(gtkThemeName);
|
||||||
}
|
}
|
||||||
@@ -1349,13 +1408,20 @@ Singleton {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if command -v gsettings >/dev/null 2>&1; then
|
||||||
|
gsettings set org.gnome.desktop.interface icon-theme '${gtkThemeName}' 2>/dev/null || true
|
||||||
|
elif command -v dconf >/dev/null 2>&1; then
|
||||||
|
dconf write /org/gnome/desktop/interface/icon-theme "'${gtkThemeName}'" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
pkill -HUP -f 'gtk' 2>/dev/null || true`;
|
pkill -HUP -f 'gtk' 2>/dev/null || true`;
|
||||||
|
|
||||||
Quickshell.execDetached(["sh", "-lc", configScript]);
|
Quickshell.execDetached(["sh", "-lc", configScript]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateQtIconTheme() {
|
function updateQtIconTheme() {
|
||||||
const qtThemeName = (iconTheme === "System Default") ? "" : iconTheme;
|
const resolved = resolveIconTheme();
|
||||||
|
const qtThemeName = (resolved === "System Default") ? "" : resolved;
|
||||||
if (!qtThemeName)
|
if (!qtThemeName)
|
||||||
return;
|
return;
|
||||||
const home = _homeUrl.replace("file://", "").replace(/'/g, "'\\''");
|
const home = _homeUrl.replace("file://", "").replace(/'/g, "'\\''");
|
||||||
@@ -1442,6 +1508,9 @@ Singleton {
|
|||||||
if (obj?.directionalAnimationMode === 3 && frameMode !== "connected")
|
if (obj?.directionalAnimationMode === 3 && frameMode !== "connected")
|
||||||
frameMode = "connected";
|
frameMode = "connected";
|
||||||
|
|
||||||
|
if (obj?.iconTheme !== undefined && obj?.iconThemeDark === undefined)
|
||||||
|
iconThemeDark = obj.iconTheme;
|
||||||
|
|
||||||
if (obj?.weatherLocation !== undefined)
|
if (obj?.weatherLocation !== undefined)
|
||||||
_legacyWeatherLocation = obj.weatherLocation;
|
_legacyWeatherLocation = obj.weatherLocation;
|
||||||
if (obj?.weatherCoordinates !== undefined)
|
if (obj?.weatherCoordinates !== undefined)
|
||||||
@@ -1457,6 +1526,7 @@ Singleton {
|
|||||||
applyStoredTheme();
|
applyStoredTheme();
|
||||||
updateCompositorCursor();
|
updateCompositorCursor();
|
||||||
Processes.detectQtTools();
|
Processes.detectQtTools();
|
||||||
|
Qt.callLater(checkIconThemeDrift);
|
||||||
|
|
||||||
_checkSettingsWritable();
|
_checkSettingsWritable();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -2464,10 +2534,24 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setIconTheme(themeName) {
|
function setIconTheme(themeName) {
|
||||||
iconTheme = themeName;
|
const light = iconThemePerMode && typeof SessionData !== "undefined" && SessionData.isLightMode;
|
||||||
updateGtkIconTheme();
|
setIconThemeForMode(themeName, light);
|
||||||
updateQtIconTheme();
|
}
|
||||||
updateCosmicIconTheme();
|
|
||||||
|
function setIconThemeForMode(themeName, light) {
|
||||||
|
if (light)
|
||||||
|
iconThemeLight = themeName;
|
||||||
|
else
|
||||||
|
iconThemeDark = themeName;
|
||||||
|
applyStoredIconTheme();
|
||||||
|
saveSettings();
|
||||||
|
if (typeof Theme !== "undefined" && Theme.currentTheme === Theme.dynamic)
|
||||||
|
Theme.generateSystemThemesFromCurrentTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setIconThemePerMode(enabled) {
|
||||||
|
iconThemePerMode = enabled;
|
||||||
|
applyStoredIconTheme();
|
||||||
saveSettings();
|
saveSettings();
|
||||||
if (typeof Theme !== "undefined" && Theme.currentTheme === Theme.dynamic)
|
if (typeof Theme !== "undefined" && Theme.currentTheme === Theme.dynamic)
|
||||||
Theme.generateSystemThemesFromCurrentTheme();
|
Theme.generateSystemThemesFromCurrentTheme();
|
||||||
|
|||||||
@@ -244,7 +244,10 @@ var SPEC = {
|
|||||||
|
|
||||||
networkPreference: { def: "auto" },
|
networkPreference: { def: "auto" },
|
||||||
|
|
||||||
iconTheme: { def: "System Default", onChange: "applyStoredIconTheme" },
|
iconThemeDark: { def: "System Default", onChange: "applyStoredIconTheme" },
|
||||||
|
iconThemeLight: { def: "System Default", onChange: "applyStoredIconTheme" },
|
||||||
|
iconThemePerMode: { def: false, onChange: "applyStoredIconTheme" },
|
||||||
|
lastAppliedIconTheme: { def: "" },
|
||||||
availableIconThemes: { def: ["System Default"], persist: false },
|
availableIconThemes: { def: ["System Default"], persist: false },
|
||||||
systemDefaultIconTheme: { def: "", persist: false },
|
systemDefaultIconTheme: { def: "", persist: false },
|
||||||
qt5ctAvailable: { def: false, persist: false },
|
qt5ctAvailable: { def: false, persist: false },
|
||||||
|
|||||||
@@ -191,6 +191,12 @@ Item {
|
|||||||
PopoutService.colorPickerModal.show();
|
PopoutService.colorPickerModal.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function warnIfMissingQtTheme() {
|
||||||
|
if (Quickshell.env("QT_QPA_PLATFORMTHEME") === "gtk3" || Quickshell.env("QT_QPA_PLATFORMTHEME") === "qt6ct" || Quickshell.env("QT_QPA_PLATFORMTHEME_QT6") === "qt6ct")
|
||||||
|
return;
|
||||||
|
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) {
|
function formatThemeAutoTime(isoString) {
|
||||||
if (!isoString)
|
if (!isoString)
|
||||||
return "";
|
return "";
|
||||||
@@ -2264,22 +2270,67 @@ Item {
|
|||||||
settingKey: "iconTheme"
|
settingKey: "iconTheme"
|
||||||
iconName: "interests"
|
iconName: "interests"
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
tab: "theme"
|
||||||
|
tags: ["icon", "theme", "light", "dark", "mode"]
|
||||||
|
settingKey: "iconThemePerMode"
|
||||||
|
text: I18n.tr("Separate Light & Dark Themes")
|
||||||
|
description: I18n.tr("Use different icon themes for light and dark mode")
|
||||||
|
checked: SettingsData.iconThemePerMode
|
||||||
|
onToggled: checked => SettingsData.setIconThemePerMode(checked)
|
||||||
|
}
|
||||||
|
|
||||||
SettingsDropdownRow {
|
SettingsDropdownRow {
|
||||||
tab: "theme"
|
tab: "theme"
|
||||||
tags: ["icon", "theme", "system"]
|
tags: ["icon", "theme", "system"]
|
||||||
settingKey: "iconTheme"
|
settingKey: "iconTheme"
|
||||||
text: I18n.tr("Icon Theme")
|
text: I18n.tr("Icon Theme")
|
||||||
description: I18n.tr("DankShell & System Icons (requires restart)")
|
description: I18n.tr("DankShell & System Icons (requires restart)")
|
||||||
currentValue: SettingsData.iconTheme
|
visible: !SettingsData.iconThemePerMode
|
||||||
|
currentValue: SettingsData.iconThemeDark
|
||||||
enableFuzzySearch: true
|
enableFuzzySearch: true
|
||||||
popupWidthOffset: 100
|
popupWidthOffset: 100
|
||||||
maxPopupHeight: 236
|
maxPopupHeight: 236
|
||||||
options: cachedIconThemes
|
options: cachedIconThemes
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
SettingsData.setIconTheme(value);
|
SettingsData.setIconThemeForMode(value, false);
|
||||||
if (Quickshell.env("QT_QPA_PLATFORMTHEME") != "gtk3" && Quickshell.env("QT_QPA_PLATFORMTHEME") != "qt6ct" && Quickshell.env("QT_QPA_PLATFORMTHEME_QT6") != "qt6ct") {
|
warnIfMissingQtTheme();
|
||||||
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"));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsDropdownRow {
|
||||||
|
tab: "theme"
|
||||||
|
tags: ["icon", "theme", "system", "dark"]
|
||||||
|
settingKey: "iconThemeDark"
|
||||||
|
text: I18n.tr("Dark Mode Icon Theme")
|
||||||
|
description: I18n.tr("DankShell & System Icons (requires restart)")
|
||||||
|
visible: SettingsData.iconThemePerMode
|
||||||
|
currentValue: SettingsData.iconThemeDark
|
||||||
|
enableFuzzySearch: true
|
||||||
|
popupWidthOffset: 100
|
||||||
|
maxPopupHeight: 236
|
||||||
|
options: cachedIconThemes
|
||||||
|
onValueChanged: value => {
|
||||||
|
SettingsData.setIconThemeForMode(value, false);
|
||||||
|
warnIfMissingQtTheme();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDropdownRow {
|
||||||
|
tab: "theme"
|
||||||
|
tags: ["icon", "theme", "system", "light"]
|
||||||
|
settingKey: "iconThemeLight"
|
||||||
|
text: I18n.tr("Light Mode Icon Theme")
|
||||||
|
description: I18n.tr("DankShell & System Icons (requires restart)")
|
||||||
|
visible: SettingsData.iconThemePerMode
|
||||||
|
currentValue: SettingsData.iconThemeLight
|
||||||
|
enableFuzzySearch: true
|
||||||
|
popupWidthOffset: 100
|
||||||
|
maxPopupHeight: 236
|
||||||
|
options: cachedIconThemes
|
||||||
|
onValueChanged: value => {
|
||||||
|
SettingsData.setIconThemeForMode(value, true);
|
||||||
|
warnIfMissingQtTheme();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -422,13 +422,6 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: Theme.shortDuration
|
|
||||||
easing.type: Theme.standardEasing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on height {
|
Behavior on height {
|
||||||
enabled: false
|
enabled: false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtCore
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
readonly property var log: Log.scoped("IconThemeService")
|
||||||
|
|
||||||
|
readonly property string managedTheme: {
|
||||||
|
if (typeof SettingsData === "undefined")
|
||||||
|
return "";
|
||||||
|
const t = SettingsData.resolveIconTheme();
|
||||||
|
return (!t || t === "System Default") ? "" : t;
|
||||||
|
}
|
||||||
|
|
||||||
|
property var _searchDirs: []
|
||||||
|
property string _dirsForTheme: ""
|
||||||
|
property var _cache: ({})
|
||||||
|
property int revision: 0
|
||||||
|
property bool _bumpPending: false
|
||||||
|
|
||||||
|
readonly property var _baseDirs: {
|
||||||
|
const xdg = Quickshell.env("XDG_DATA_DIRS") || "";
|
||||||
|
const localData = Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericDataLocation));
|
||||||
|
const home = Paths.strip(StandardPaths.writableLocation(StandardPaths.HomeLocation));
|
||||||
|
const dataDirs = xdg.trim() !== "" ? xdg.split(":").concat([localData]) : ["/usr/share", "/usr/local/share", localData];
|
||||||
|
return dataDirs.map(d => d + "/icons").concat([home + "/.icons"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
onManagedThemeChanged: _rebuild()
|
||||||
|
Component.onCompleted: _rebuild()
|
||||||
|
|
||||||
|
function _bumpRevision() {
|
||||||
|
if (_bumpPending)
|
||||||
|
return;
|
||||||
|
_bumpPending = true;
|
||||||
|
Qt.callLater(() => {
|
||||||
|
_bumpPending = false;
|
||||||
|
revision++;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function _rebuild() {
|
||||||
|
_cache = ({});
|
||||||
|
if (!managedTheme) {
|
||||||
|
_searchDirs = [];
|
||||||
|
_dirsForTheme = "";
|
||||||
|
_bumpRevision();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const theme = managedTheme;
|
||||||
|
const bases = _baseDirs.join(" ");
|
||||||
|
const script = `BASES="${bases}"
|
||||||
|
find_index() { for b in $BASES; do [ -f "$b/$1/index.theme" ] && { echo "$b/$1/index.theme"; return 0; }; done; return 1; }
|
||||||
|
visited=""; queue="${theme}"; order=""
|
||||||
|
while [ -n "$queue" ]; do
|
||||||
|
cur=\${queue%% *}; rest=\${queue#"$cur"}; queue=\${rest# }
|
||||||
|
[ -z "$cur" ] && continue
|
||||||
|
case " $visited " in *" $cur "*) continue;; esac
|
||||||
|
visited="$visited $cur"; order="$order $cur"
|
||||||
|
idx=$(find_index "$cur") || continue
|
||||||
|
inh=$(sed -n 's/^Inherits=//p' "$idx" | head -1 | tr -d '"' | tr ',' ' ')
|
||||||
|
queue="$queue $inh"
|
||||||
|
done
|
||||||
|
case " $visited " in *" hicolor "*) ;; *) order="$order hicolor";; esac
|
||||||
|
for t in $order; do for b in $BASES; do d="$b/$t"; [ -d "$d" ] && echo "$d"; done; done`;
|
||||||
|
|
||||||
|
Proc.runCommand("iconChain:" + theme, ["sh", "-c", script], (out, code) => {
|
||||||
|
if (root.managedTheme !== theme)
|
||||||
|
return;
|
||||||
|
root._searchDirs = (out || "").trim().split("\n").filter(s => s);
|
||||||
|
root._dirsForTheme = theme;
|
||||||
|
root._cache = ({});
|
||||||
|
root._bumpRevision();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolve(name) {
|
||||||
|
const _dep = revision;
|
||||||
|
if (!managedTheme || !name)
|
||||||
|
return "";
|
||||||
|
if (name.startsWith("/") || name.startsWith("file://") || name.startsWith("image://") || name.startsWith("~"))
|
||||||
|
return "";
|
||||||
|
if (!/^[\w.+-]+$/.test(name))
|
||||||
|
return "";
|
||||||
|
if (_dirsForTheme !== managedTheme || _searchDirs.length === 0)
|
||||||
|
return "";
|
||||||
|
if (name in _cache)
|
||||||
|
return _cache[name] || "";
|
||||||
|
_cache[name] = null;
|
||||||
|
_resolveAsync(name);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function _resolveAsync(name) {
|
||||||
|
const dirs = _searchDirs.join(" ");
|
||||||
|
const script = `find -L ${dirs} \\( -name '${name}.svg' -o -name '${name}.png' \\) 2>/dev/null`;
|
||||||
|
Proc.runCommand("iconResolve:" + name, ["sh", "-c", script], (out, code) => {
|
||||||
|
const paths = (out || "").trim().split("\n").filter(s => s);
|
||||||
|
const best = root._pickBest(paths);
|
||||||
|
const c = root._cache;
|
||||||
|
c[name] = best ? Paths.toFileUrl(best) : "";
|
||||||
|
root._cache = c;
|
||||||
|
root._bumpRevision();
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _pickBest(paths) {
|
||||||
|
let best = "";
|
||||||
|
let bestScore = -1;
|
||||||
|
for (let i = 0; i < paths.length; i++) {
|
||||||
|
const s = _score(paths[i]);
|
||||||
|
if (s > bestScore) {
|
||||||
|
bestScore = s;
|
||||||
|
best = paths[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _chainIndex(path) {
|
||||||
|
for (let i = 0; i < _searchDirs.length; i++) {
|
||||||
|
if (path.startsWith(_searchDirs[i] + "/"))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return _searchDirs.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _score(path) {
|
||||||
|
let s = 0;
|
||||||
|
if (path.includes("/apps/"))
|
||||||
|
s += 3000000000;
|
||||||
|
else if (path.includes("/categories/"))
|
||||||
|
s += 1000000000;
|
||||||
|
else if (path.includes("/places/") || path.includes("/devices/") || path.includes("/mimetypes/") || path.includes("/status/") || path.includes("/actions/"))
|
||||||
|
s += 100000000;
|
||||||
|
|
||||||
|
s += Math.max(0, (64 - _chainIndex(path))) * 1000000;
|
||||||
|
|
||||||
|
if (path.endsWith(".svg"))
|
||||||
|
s += 100000;
|
||||||
|
|
||||||
|
if (path.includes("/scalable/")) {
|
||||||
|
s += 1000;
|
||||||
|
} else {
|
||||||
|
const m = path.match(/\/(\d+)(?:x\d+)?(?:@\d+x)?\//);
|
||||||
|
if (m)
|
||||||
|
s += Math.min(parseInt(m[1]), 999);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3207,6 +3207,30 @@
|
|||||||
],
|
],
|
||||||
"description": "Blend between Surface High and the selected custom color"
|
"description": "Blend between Surface High and the selected custom color"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"section": "iconThemeDark",
|
||||||
|
"label": "Dark Mode Icon Theme",
|
||||||
|
"tabIndex": 10,
|
||||||
|
"category": "Theme & Colors",
|
||||||
|
"keywords": [
|
||||||
|
"appearance",
|
||||||
|
"colors",
|
||||||
|
"colour",
|
||||||
|
"dankshell",
|
||||||
|
"dark",
|
||||||
|
"dark mode",
|
||||||
|
"icon",
|
||||||
|
"icons",
|
||||||
|
"look",
|
||||||
|
"mode",
|
||||||
|
"night",
|
||||||
|
"scheme",
|
||||||
|
"style",
|
||||||
|
"system",
|
||||||
|
"theme"
|
||||||
|
],
|
||||||
|
"description": "DankShell & System Icons (requires restart)"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"section": "matugenTemplateNeovimSettings",
|
"section": "matugenTemplateNeovimSettings",
|
||||||
"label": "Dark mode base",
|
"label": "Dark mode base",
|
||||||
@@ -3446,17 +3470,24 @@
|
|||||||
"appearance",
|
"appearance",
|
||||||
"colors",
|
"colors",
|
||||||
"colour",
|
"colour",
|
||||||
"dankshell",
|
"dark",
|
||||||
|
"dark mode",
|
||||||
|
"day",
|
||||||
|
"different",
|
||||||
"icon",
|
"icon",
|
||||||
"icons",
|
"light",
|
||||||
|
"light mode",
|
||||||
"look",
|
"look",
|
||||||
|
"mode",
|
||||||
|
"night",
|
||||||
"scheme",
|
"scheme",
|
||||||
"style",
|
"style",
|
||||||
"system",
|
"system",
|
||||||
"theme"
|
"theme",
|
||||||
|
"themes"
|
||||||
],
|
],
|
||||||
"icon": "interests",
|
"icon": "interests",
|
||||||
"description": "DankShell & System Icons (requires restart)"
|
"description": "Use different icon themes for light and dark mode"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"section": "matugenTemplateKcolorscheme",
|
"section": "matugenTemplateKcolorscheme",
|
||||||
@@ -3564,6 +3595,30 @@
|
|||||||
],
|
],
|
||||||
"description": "Use light theme instead of dark theme"
|
"description": "Use light theme instead of dark theme"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"section": "iconThemeLight",
|
||||||
|
"label": "Light Mode Icon Theme",
|
||||||
|
"tabIndex": 10,
|
||||||
|
"category": "Theme & Colors",
|
||||||
|
"keywords": [
|
||||||
|
"appearance",
|
||||||
|
"colors",
|
||||||
|
"colour",
|
||||||
|
"dankshell",
|
||||||
|
"day",
|
||||||
|
"icon",
|
||||||
|
"icons",
|
||||||
|
"light",
|
||||||
|
"light mode",
|
||||||
|
"look",
|
||||||
|
"mode",
|
||||||
|
"scheme",
|
||||||
|
"style",
|
||||||
|
"system",
|
||||||
|
"theme"
|
||||||
|
],
|
||||||
|
"description": "DankShell & System Icons (requires restart)"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"section": "matugenContrast",
|
"section": "matugenContrast",
|
||||||
"label": "Matugen Contrast",
|
"label": "Matugen Contrast",
|
||||||
@@ -3783,6 +3838,33 @@
|
|||||||
"user"
|
"user"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"section": "iconThemePerMode",
|
||||||
|
"label": "Separate Light & Dark Themes",
|
||||||
|
"tabIndex": 10,
|
||||||
|
"category": "Theme & Colors",
|
||||||
|
"keywords": [
|
||||||
|
"appearance",
|
||||||
|
"colors",
|
||||||
|
"colour",
|
||||||
|
"dark",
|
||||||
|
"dark mode",
|
||||||
|
"day",
|
||||||
|
"different",
|
||||||
|
"icon",
|
||||||
|
"light",
|
||||||
|
"light mode",
|
||||||
|
"look",
|
||||||
|
"mode",
|
||||||
|
"night",
|
||||||
|
"scheme",
|
||||||
|
"separate",
|
||||||
|
"style",
|
||||||
|
"theme",
|
||||||
|
"themes"
|
||||||
|
],
|
||||||
|
"description": "Use different icon themes for light and dark mode"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"section": "m3ElevationColorMode",
|
"section": "m3ElevationColorMode",
|
||||||
"label": "Shadow Color",
|
"label": "Shadow Color",
|
||||||
|
|||||||
Reference in New Issue
Block a user