1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 21:42:51 -05:00

compositor+matugen: border override, hypr/mango layout overrides, new

templates, respect XDG paths
- Add Hyprland and MangoWC templates
- Add GUI gaps, window radius, and border thickness overrides for niri,
  Hyprland, and MangoWC
- Add replacement support in matugen templates for DATA_DIR, CACHE_DIR,
  CONFIG_DIR
fixes #1274
fixes #1273
This commit is contained in:
bbedward
2026-01-05 11:25:13 -05:00
parent 4005a55bf2
commit 64310854a6
49 changed files with 1017 additions and 207 deletions

View File

@@ -118,8 +118,56 @@ Singleton {
parseSettings(greeterSessionFile.text());
return;
}
parseSettings(settingsFile.text());
_checkSessionWritable();
try {
const txt = settingsFile.text();
let obj = (txt && txt.trim()) ? JSON.parse(txt) : null;
if (obj?.brightnessLogarithmicDevices && !obj?.brightnessExponentialDevices)
obj.brightnessExponentialDevices = obj.brightnessLogarithmicDevices;
if (obj?.nightModeStartTime !== undefined) {
const parts = obj.nightModeStartTime.split(":");
obj.nightModeStartHour = parseInt(parts[0]) || 18;
obj.nightModeStartMinute = parseInt(parts[1]) || 0;
}
if (obj?.nightModeEndTime !== undefined) {
const parts = obj.nightModeEndTime.split(":");
obj.nightModeEndHour = parseInt(parts[0]) || 6;
obj.nightModeEndMinute = parseInt(parts[1]) || 0;
}
const oldVersion = obj?.configVersion ?? 0;
if (obj && oldVersion === 0)
migrateFromUndefinedToV1(obj);
if (obj && oldVersion < sessionConfigVersion) {
const settingsDataRef = (typeof SettingsData !== "undefined") ? SettingsData : null;
const migrated = Store.migrateToVersion(obj, sessionConfigVersion, settingsDataRef);
if (migrated) {
_pendingMigration = migrated;
obj = migrated;
}
}
Store.parse(root, obj);
_loadedSessionSnapshot = getCurrentSessionJson();
_hasLoaded = true;
if (!isGreeterMode && typeof Theme !== "undefined")
Theme.generateSystemThemesFromCurrentTheme();
if (typeof WallpaperCyclingService !== "undefined")
WallpaperCyclingService.updateCyclingState();
_checkSessionWritable();
} catch (e) {
_parseError = true;
const msg = e.message;
console.error("SessionData: Failed to parse session.json - file will not be overwritten. Error:", msg);
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse session.json"), msg));
}
}
function _checkSessionWritable() {
@@ -158,29 +206,27 @@ Singleton {
function parseSettings(content) {
_parseError = false;
try {
let obj = (content && content.trim()) ? JSON.parse(content) : {};
let obj = (content && content.trim()) ? JSON.parse(content) : null;
if (obj.brightnessLogarithmicDevices && !obj.brightnessExponentialDevices) {
if (obj?.brightnessLogarithmicDevices && !obj?.brightnessExponentialDevices)
obj.brightnessExponentialDevices = obj.brightnessLogarithmicDevices;
}
if (obj.nightModeStartTime !== undefined) {
if (obj?.nightModeStartTime !== undefined) {
const parts = obj.nightModeStartTime.split(":");
obj.nightModeStartHour = parseInt(parts[0]) || 18;
obj.nightModeStartMinute = parseInt(parts[1]) || 0;
}
if (obj.nightModeEndTime !== undefined) {
if (obj?.nightModeEndTime !== undefined) {
const parts = obj.nightModeEndTime.split(":");
obj.nightModeEndHour = parseInt(parts[0]) || 6;
obj.nightModeEndMinute = parseInt(parts[1]) || 0;
}
const oldVersion = obj.configVersion ?? 0;
if (oldVersion === 0) {
const oldVersion = obj?.configVersion ?? 0;
if (obj && oldVersion === 0)
migrateFromUndefinedToV1(obj);
}
if (oldVersion < sessionConfigVersion) {
if (obj && oldVersion < sessionConfigVersion) {
const settingsDataRef = (typeof SettingsData !== "undefined") ? SettingsData : null;
const migrated = Store.migrateToVersion(obj, sessionConfigVersion, settingsDataRef);
if (migrated) {
@@ -191,22 +237,14 @@ Singleton {
Store.parse(root, obj);
if (wallpaperPath && wallpaperPath.startsWith("we:")) {
console.warn("WallpaperEngine wallpaper detected, resetting wallpaper");
wallpaperPath = "";
Quickshell.execDetached(["notify-send", "-u", "critical", "-a", "DMS", "-i", "dialog-warning", "WallpaperEngine Support Moved", "WallpaperEngine support has been moved to a plugin. Please enable the Linux Wallpaper Engine plugin in Settings → Plugins to continue using WallpaperEngine."]);
}
_hasLoaded = true;
_loadedSessionSnapshot = getCurrentSessionJson();
_hasLoaded = true;
if (!isGreeterMode && typeof Theme !== "undefined") {
if (!isGreeterMode && typeof Theme !== "undefined")
Theme.generateSystemThemesFromCurrentTheme();
}
if (typeof WallpaperCyclingService !== "undefined") {
if (typeof WallpaperCyclingService !== "undefined")
WallpaperCyclingService.updateCyclingState();
}
} catch (e) {
_parseError = true;
const msg = e.message;

View File

@@ -81,6 +81,13 @@ Singleton {
property real cornerRadius: 12
property int niriLayoutGapsOverride: -1
property int niriLayoutRadiusOverride: -1
property int niriLayoutBorderSize: -1
property int hyprlandLayoutGapsOverride: -1
property int hyprlandLayoutRadiusOverride: -1
property int hyprlandLayoutBorderSize: -1
property int mangoLayoutGapsOverride: -1
property int mangoLayoutRadiusOverride: -1
property int mangoLayoutBorderSize: -1
property bool use24HourClock: true
property bool showSeconds: false
@@ -295,6 +302,8 @@ Singleton {
property bool runDmsMatugenTemplates: true
property bool matugenTemplateGtk: true
property bool matugenTemplateNiri: true
property bool matugenTemplateHyprland: true
property bool matugenTemplateMangowc: true
property bool matugenTemplateQt5ct: true
property bool matugenTemplateQt6ct: true
property bool matugenTemplateFirefox: true
@@ -699,10 +708,15 @@ Singleton {
}
}
function updateNiriLayout() {
if (typeof NiriService !== "undefined" && typeof CompositorService !== "undefined" && CompositorService.isNiri) {
function updateCompositorLayout() {
if (typeof CompositorService === "undefined")
return;
if (CompositorService.isNiri && typeof NiriService !== "undefined")
NiriService.generateNiriLayoutConfig();
}
if (CompositorService.isHyprland && typeof HyprlandService !== "undefined")
HyprlandService.generateLayoutConfig();
if (CompositorService.isDwl && typeof DwlService !== "undefined")
DwlService.generateLayoutConfig();
}
function applyStoredIconTheme() {
@@ -778,7 +792,7 @@ Singleton {
readonly property var _hooks: ({
"applyStoredTheme": applyStoredTheme,
"regenSystemThemes": regenSystemThemes,
"updateNiriLayout": updateNiriLayout,
"updateCompositorLayout": updateCompositorLayout,
"applyStoredIconTheme": applyStoredIconTheme,
"updateBarConfigs": updateBarConfigs
})
@@ -1459,7 +1473,7 @@ Singleton {
function setCornerRadius(radius) {
set("cornerRadius", radius);
NiriService.generateNiriLayoutConfig();
updateCompositorLayout();
}
function setWeatherLocation(displayName, coordinates) {
@@ -1541,9 +1555,7 @@ Singleton {
"spacing": spacing
});
}
if (typeof NiriService !== "undefined" && CompositorService.isNiri) {
NiriService.generateNiriLayoutConfig();
}
updateCompositorLayout();
}
function setDankBarPosition(position) {

View File

@@ -910,6 +910,10 @@ Singleton {
skipTemplates.push("gtk");
if (!SettingsData.matugenTemplateNiri)
skipTemplates.push("niri");
if (!SettingsData.matugenTemplateHyprland)
skipTemplates.push("hyprland");
if (!SettingsData.matugenTemplateMangowc)
skipTemplates.push("mangowc");
if (!SettingsData.matugenTemplateQt5ct)
skipTemplates.push("qt5ct");
if (!SettingsData.matugenTemplateQt6ct)

View File

@@ -19,9 +19,16 @@ var SPEC = {
widgetBackgroundColor: { def: "sch" },
widgetColorMode: { def: "default" },
cornerRadius: { def: 12, onChange: "updateNiriLayout" },
niriLayoutGapsOverride: { def: -1, onChange: "updateNiriLayout" },
niriLayoutRadiusOverride: { def: -1, onChange: "updateNiriLayout" },
cornerRadius: { def: 12, onChange: "updateCompositorLayout" },
niriLayoutGapsOverride: { def: -1, onChange: "updateCompositorLayout" },
niriLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" },
niriLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" },
hyprlandLayoutGapsOverride: { def: -1, onChange: "updateCompositorLayout" },
hyprlandLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" },
hyprlandLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" },
mangoLayoutGapsOverride: { def: -1, onChange: "updateCompositorLayout" },
mangoLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" },
mangoLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" },
use24HourClock: { def: true },
showSeconds: { def: false },
@@ -185,6 +192,8 @@ var SPEC = {
runDmsMatugenTemplates: { def: true },
matugenTemplateGtk: { def: true },
matugenTemplateNiri: { def: true },
matugenTemplateHyprland: { def: true },
matugenTemplateMangowc: { def: true },
matugenTemplateQt5ct: { def: true },
matugenTemplateQt6ct: { def: true },
matugenTemplateFirefox: { def: true },

View File

@@ -727,7 +727,7 @@ FocusScope {
id: gridScrollbar
}
ScrollBar.horizontal: ScrollBar {
ScrollBar.horizontal: DankScrollbar {
policy: ScrollBar.AlwaysOff
}

View File

@@ -1,6 +1,7 @@
import QtQuick
import QtQuick.Effects
import Quickshell
import Quickshell.Io
import qs.Common
import qs.Modals.FileBrowser
import qs.Services
@@ -13,6 +14,27 @@ Item {
property var cachedIconThemes: SettingsData.availableIconThemes
property var cachedMatugenSchemes: Theme.availableMatugenSchemes.map(option => option.label)
property var installedRegistryThemes: []
property var templateDetection: ({})
function isTemplateDetected(templateId) {
if (!templateDetection || Object.keys(templateDetection).length === 0)
return true;
return templateDetection[templateId] !== false;
}
function getTemplateDescription(templateId, baseDescription) {
if (isTemplateDetected(templateId))
return baseDescription;
if (baseDescription)
return baseDescription + " · " + I18n.tr("Not detected");
return I18n.tr("Not detected");
}
function getTemplateDescriptionColor(templateId) {
if (isTemplateDetected(templateId))
return Theme.surfaceVariantText;
return Theme.warning;
}
Component.onCompleted: {
SettingsData.detectAvailableIconThemes();
@@ -20,6 +42,28 @@ Item {
DMSService.listInstalledThemes();
if (PopoutService.pendingThemeInstall)
Qt.callLater(() => themeBrowser.show());
templateCheckProcess.running = true;
}
Process {
id: templateCheckProcess
command: ["dms", "matugen", "check"]
running: false
stdout: StdioCollector {
onStreamFinished: {
try {
const results = JSON.parse(text);
const detection = {};
for (const item of results) {
detection[item.id] = item.detected;
}
themeColorsTab.templateDetection = detection;
} catch (e) {
console.warn("ThemeColorsTab: Failed to parse template check:", e);
}
}
}
}
Connections {
@@ -918,7 +962,7 @@ Item {
SettingsCard {
tab: "theme"
tags: ["niri", "layout", "gaps", "radius", "window"]
tags: ["niri", "layout", "gaps", "radius", "window", "border"]
title: I18n.tr("Niri Layout Overrides")
settingKey: "niriLayout"
iconName: "crop_square"
@@ -986,6 +1030,243 @@ Item {
defaultValue: SettingsData.cornerRadius
onSliderValueChanged: newValue => SettingsData.set("niriLayoutRadiusOverride", newValue)
}
SettingsToggleRow {
tab: "theme"
tags: ["niri", "border", "override"]
settingKey: "niriLayoutBorderSizeEnabled"
text: I18n.tr("Override Border Size")
description: I18n.tr("Use custom border/focus-ring width")
checked: SettingsData.niriLayoutBorderSize >= 0
onToggled: checked => {
if (checked) {
SettingsData.set("niriLayoutBorderSize", 2);
return;
}
SettingsData.set("niriLayoutBorderSize", -1);
}
}
SettingsSliderRow {
tab: "theme"
tags: ["niri", "border", "override"]
settingKey: "niriLayoutBorderSize"
text: I18n.tr("Border Size")
description: I18n.tr("Width of window border and focus ring")
visible: SettingsData.niriLayoutBorderSize >= 0
value: Math.max(0, SettingsData.niriLayoutBorderSize)
minimum: 0
maximum: 10
unit: "px"
defaultValue: 2
onSliderValueChanged: newValue => SettingsData.set("niriLayoutBorderSize", newValue)
}
}
SettingsCard {
tab: "theme"
tags: ["hyprland", "layout", "gaps", "radius", "window", "border", "rounding"]
title: I18n.tr("Hyprland Layout Overrides")
settingKey: "hyprlandLayout"
iconName: "crop_square"
visible: CompositorService.isHyprland
SettingsToggleRow {
tab: "theme"
tags: ["hyprland", "gaps", "override"]
settingKey: "hyprlandLayoutGapsOverrideEnabled"
text: I18n.tr("Override Gaps")
description: I18n.tr("Use custom gaps instead of bar spacing")
checked: SettingsData.hyprlandLayoutGapsOverride >= 0
onToggled: checked => {
if (checked) {
const currentGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4));
SettingsData.set("hyprlandLayoutGapsOverride", currentGaps);
return;
}
SettingsData.set("hyprlandLayoutGapsOverride", -1);
}
}
SettingsSliderRow {
tab: "theme"
tags: ["hyprland", "gaps", "override"]
settingKey: "hyprlandLayoutGapsOverride"
text: I18n.tr("Window Gaps")
description: I18n.tr("Space between windows (gaps_in and gaps_out)")
visible: SettingsData.hyprlandLayoutGapsOverride >= 0
value: Math.max(0, SettingsData.hyprlandLayoutGapsOverride)
minimum: 0
maximum: 50
unit: "px"
defaultValue: Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4))
onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutGapsOverride", newValue)
}
SettingsToggleRow {
tab: "theme"
tags: ["hyprland", "radius", "override", "rounding"]
settingKey: "hyprlandLayoutRadiusOverrideEnabled"
text: I18n.tr("Override Corner Radius")
description: I18n.tr("Use custom window rounding instead of theme radius")
checked: SettingsData.hyprlandLayoutRadiusOverride >= 0
onToggled: checked => {
if (checked) {
SettingsData.set("hyprlandLayoutRadiusOverride", SettingsData.cornerRadius);
return;
}
SettingsData.set("hyprlandLayoutRadiusOverride", -1);
}
}
SettingsSliderRow {
tab: "theme"
tags: ["hyprland", "radius", "override", "rounding"]
settingKey: "hyprlandLayoutRadiusOverride"
text: I18n.tr("Window Rounding")
description: I18n.tr("Rounded corners for windows (decoration.rounding)")
visible: SettingsData.hyprlandLayoutRadiusOverride >= 0
value: Math.max(0, SettingsData.hyprlandLayoutRadiusOverride)
minimum: 0
maximum: 100
unit: "px"
defaultValue: SettingsData.cornerRadius
onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutRadiusOverride", newValue)
}
SettingsToggleRow {
tab: "theme"
tags: ["hyprland", "border", "override"]
settingKey: "hyprlandLayoutBorderSizeEnabled"
text: I18n.tr("Override Border Size")
description: I18n.tr("Use custom border size")
checked: SettingsData.hyprlandLayoutBorderSize >= 0
onToggled: checked => {
if (checked) {
SettingsData.set("hyprlandLayoutBorderSize", 2);
return;
}
SettingsData.set("hyprlandLayoutBorderSize", -1);
}
}
SettingsSliderRow {
tab: "theme"
tags: ["hyprland", "border", "override"]
settingKey: "hyprlandLayoutBorderSize"
text: I18n.tr("Border Size")
description: I18n.tr("Width of window border (general.border_size)")
visible: SettingsData.hyprlandLayoutBorderSize >= 0
value: Math.max(0, SettingsData.hyprlandLayoutBorderSize)
minimum: 0
maximum: 10
unit: "px"
defaultValue: 2
onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutBorderSize", newValue)
}
}
SettingsCard {
tab: "theme"
tags: ["mangowc", "mango", "dwl", "layout", "gaps", "radius", "window", "border"]
title: I18n.tr("MangoWC Layout Overrides")
settingKey: "mangoLayout"
iconName: "crop_square"
visible: CompositorService.isDwl
SettingsToggleRow {
tab: "theme"
tags: ["mangowc", "mango", "gaps", "override"]
settingKey: "mangoLayoutGapsOverrideEnabled"
text: I18n.tr("Override Gaps")
description: I18n.tr("Use custom gaps instead of bar spacing")
checked: SettingsData.mangoLayoutGapsOverride >= 0
onToggled: checked => {
if (checked) {
const currentGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4));
SettingsData.set("mangoLayoutGapsOverride", currentGaps);
return;
}
SettingsData.set("mangoLayoutGapsOverride", -1);
}
}
SettingsSliderRow {
tab: "theme"
tags: ["mangowc", "mango", "gaps", "override"]
settingKey: "mangoLayoutGapsOverride"
text: I18n.tr("Window Gaps")
description: I18n.tr("Space between windows (gappih/gappiv/gappoh/gappov)")
visible: SettingsData.mangoLayoutGapsOverride >= 0
value: Math.max(0, SettingsData.mangoLayoutGapsOverride)
minimum: 0
maximum: 50
unit: "px"
defaultValue: Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4))
onSliderValueChanged: newValue => SettingsData.set("mangoLayoutGapsOverride", newValue)
}
SettingsToggleRow {
tab: "theme"
tags: ["mangowc", "mango", "radius", "override"]
settingKey: "mangoLayoutRadiusOverrideEnabled"
text: I18n.tr("Override Corner Radius")
description: I18n.tr("Use custom window radius instead of theme radius")
checked: SettingsData.mangoLayoutRadiusOverride >= 0
onToggled: checked => {
if (checked) {
SettingsData.set("mangoLayoutRadiusOverride", SettingsData.cornerRadius);
return;
}
SettingsData.set("mangoLayoutRadiusOverride", -1);
}
}
SettingsSliderRow {
tab: "theme"
tags: ["mangowc", "mango", "radius", "override"]
settingKey: "mangoLayoutRadiusOverride"
text: I18n.tr("Window Corner Radius")
description: I18n.tr("Rounded corners for windows (border_radius)")
visible: SettingsData.mangoLayoutRadiusOverride >= 0
value: Math.max(0, SettingsData.mangoLayoutRadiusOverride)
minimum: 0
maximum: 100
unit: "px"
defaultValue: SettingsData.cornerRadius
onSliderValueChanged: newValue => SettingsData.set("mangoLayoutRadiusOverride", newValue)
}
SettingsToggleRow {
tab: "theme"
tags: ["mangowc", "mango", "border", "override"]
settingKey: "mangoLayoutBorderSizeEnabled"
text: I18n.tr("Override Border Size")
description: I18n.tr("Use custom border size")
checked: SettingsData.mangoLayoutBorderSize >= 0
onToggled: checked => {
if (checked) {
SettingsData.set("mangoLayoutBorderSize", 2);
return;
}
SettingsData.set("mangoLayoutBorderSize", -1);
}
}
SettingsSliderRow {
tab: "theme"
tags: ["mangowc", "mango", "border", "override"]
settingKey: "mangoLayoutBorderSize"
text: I18n.tr("Border Size")
description: I18n.tr("Width of window border (borderpx)")
visible: SettingsData.mangoLayoutBorderSize >= 0
value: Math.max(0, SettingsData.mangoLayoutBorderSize)
minimum: 0
maximum: 10
unit: "px"
defaultValue: 2
onSliderValueChanged: newValue => SettingsData.set("mangoLayoutBorderSize", newValue)
}
}
SettingsCard {
@@ -1066,7 +1347,8 @@ Item {
tags: ["matugen", "gtk", "template"]
settingKey: "matugenTemplateGtk"
text: "GTK"
description: ""
description: getTemplateDescription("gtk", "")
descriptionColor: getTemplateDescriptionColor("gtk")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateGtk
onToggled: checked => SettingsData.set("matugenTemplateGtk", checked)
@@ -1077,18 +1359,44 @@ Item {
tags: ["matugen", "niri", "template"]
settingKey: "matugenTemplateNiri"
text: "niri"
description: ""
description: getTemplateDescription("niri", "")
descriptionColor: getTemplateDescriptionColor("niri")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateNiri
onToggled: checked => SettingsData.set("matugenTemplateNiri", checked)
}
SettingsToggleRow {
tab: "theme"
tags: ["matugen", "hyprland", "template"]
settingKey: "matugenTemplateHyprland"
text: "Hyprland"
description: getTemplateDescription("hyprland", "")
descriptionColor: getTemplateDescriptionColor("hyprland")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateHyprland
onToggled: checked => SettingsData.set("matugenTemplateHyprland", checked)
}
SettingsToggleRow {
tab: "theme"
tags: ["matugen", "mangowc", "template"]
settingKey: "matugenTemplateMangowc"
text: "mangowc"
description: getTemplateDescription("mangowc", "")
descriptionColor: getTemplateDescriptionColor("mangowc")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateMangowc
onToggled: checked => SettingsData.set("matugenTemplateMangowc", checked)
}
SettingsToggleRow {
tab: "theme"
tags: ["matugen", "qt5ct", "template"]
settingKey: "matugenTemplateQt5ct"
text: "qt5ct"
description: ""
description: getTemplateDescription("qt5ct", "")
descriptionColor: getTemplateDescriptionColor("qt5ct")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateQt5ct
onToggled: checked => SettingsData.set("matugenTemplateQt5ct", checked)
@@ -1099,7 +1407,8 @@ Item {
tags: ["matugen", "qt6ct", "template"]
settingKey: "matugenTemplateQt6ct"
text: "qt6ct"
description: ""
description: getTemplateDescription("qt6ct", "")
descriptionColor: getTemplateDescriptionColor("qt6ct")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateQt6ct
onToggled: checked => SettingsData.set("matugenTemplateQt6ct", checked)
@@ -1110,7 +1419,8 @@ Item {
tags: ["matugen", "firefox", "template"]
settingKey: "matugenTemplateFirefox"
text: "Firefox"
description: ""
description: getTemplateDescription("firefox", "")
descriptionColor: getTemplateDescriptionColor("firefox")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateFirefox
onToggled: checked => SettingsData.set("matugenTemplateFirefox", checked)
@@ -1121,7 +1431,8 @@ Item {
tags: ["matugen", "pywalfox", "template"]
settingKey: "matugenTemplatePywalfox"
text: "pywalfox"
description: ""
description: getTemplateDescription("pywalfox", "")
descriptionColor: getTemplateDescriptionColor("pywalfox")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplatePywalfox
onToggled: checked => SettingsData.set("matugenTemplatePywalfox", checked)
@@ -1132,7 +1443,8 @@ Item {
tags: ["matugen", "zenbrowser", "template"]
settingKey: "matugenTemplateZenBrowser"
text: "zenbrowser"
description: ""
description: getTemplateDescription("zenbrowser", "")
descriptionColor: getTemplateDescriptionColor("zenbrowser")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateZenBrowser
onToggled: checked => SettingsData.set("matugenTemplateZenBrowser", checked)
@@ -1143,7 +1455,8 @@ Item {
tags: ["matugen", "vesktop", "discord", "template"]
settingKey: "matugenTemplateVesktop"
text: "vesktop"
description: ""
description: getTemplateDescription("vesktop", "")
descriptionColor: getTemplateDescriptionColor("vesktop")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateVesktop
onToggled: checked => SettingsData.set("matugenTemplateVesktop", checked)
@@ -1154,7 +1467,8 @@ Item {
tags: ["matugen", "equibop", "discord", "template"]
settingKey: "matugenTemplateEquibop"
text: "equibop"
description: ""
description: getTemplateDescription("equibop", "")
descriptionColor: getTemplateDescriptionColor("equibop")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateEquibop
onToggled: checked => SettingsData.set("matugenTemplateEquibop", checked)
@@ -1165,7 +1479,8 @@ Item {
tags: ["matugen", "ghostty", "terminal", "template"]
settingKey: "matugenTemplateGhostty"
text: "Ghostty"
description: ""
description: getTemplateDescription("ghostty", "")
descriptionColor: getTemplateDescriptionColor("ghostty")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateGhostty
onToggled: checked => SettingsData.set("matugenTemplateGhostty", checked)
@@ -1176,7 +1491,8 @@ Item {
tags: ["matugen", "kitty", "terminal", "template"]
settingKey: "matugenTemplateKitty"
text: "kitty"
description: ""
description: getTemplateDescription("kitty", "")
descriptionColor: getTemplateDescriptionColor("kitty")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateKitty
onToggled: checked => SettingsData.set("matugenTemplateKitty", checked)
@@ -1187,17 +1503,20 @@ Item {
tags: ["matugen", "foot", "terminal", "template"]
settingKey: "matugenTemplateFoot"
text: "foot"
description: ""
description: getTemplateDescription("foot", "")
descriptionColor: getTemplateDescriptionColor("foot")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateFoot
onToggled: checked => SettingsData.set("matugenTemplateFoot", checked)
}
SettingsToggleRow {
tab: "theme"
tags: ["matugen", "neovim", "terminal", "template"]
settingKey: "matugenTemplateNeovim"
text: "neovim"
description: "Requires lazy plugin manager"
description: getTemplateDescription("nvim", "Requires lazy plugin manager")
descriptionColor: getTemplateDescriptionColor("nvim")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateNeovim
onToggled: checked => SettingsData.set("matugenTemplateNeovim", checked)
@@ -1208,7 +1527,8 @@ Item {
tags: ["matugen", "alacritty", "terminal", "template"]
settingKey: "matugenTemplateAlacritty"
text: "Alacritty"
description: ""
description: getTemplateDescription("alacritty", "")
descriptionColor: getTemplateDescriptionColor("alacritty")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateAlacritty
onToggled: checked => SettingsData.set("matugenTemplateAlacritty", checked)
@@ -1219,7 +1539,8 @@ Item {
tags: ["matugen", "wezterm", "terminal", "template"]
settingKey: "matugenTemplateWezterm"
text: "WezTerm"
description: ""
description: getTemplateDescription("wezterm", "")
descriptionColor: getTemplateDescriptionColor("wezterm")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateWezterm
onToggled: checked => SettingsData.set("matugenTemplateWezterm", checked)
@@ -1230,7 +1551,8 @@ Item {
tags: ["matugen", "dgop", "template"]
settingKey: "matugenTemplateDgop"
text: "dgop"
description: ""
description: getTemplateDescription("dgop", "")
descriptionColor: getTemplateDescriptionColor("dgop")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateDgop
onToggled: checked => SettingsData.set("matugenTemplateDgop", checked)
@@ -1241,7 +1563,8 @@ Item {
tags: ["matugen", "kcolorscheme", "kde", "template"]
settingKey: "matugenTemplateKcolorscheme"
text: "KColorScheme"
description: ""
description: getTemplateDescription("kcolorscheme", "")
descriptionColor: getTemplateDescriptionColor("kcolorscheme")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateKcolorscheme
onToggled: checked => SettingsData.set("matugenTemplateKcolorscheme", checked)
@@ -1252,7 +1575,8 @@ Item {
tags: ["matugen", "vscode", "code", "template"]
settingKey: "matugenTemplateVscode"
text: "VS Code"
description: ""
description: getTemplateDescription("vscode", "")
descriptionColor: getTemplateDescriptionColor("vscode")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateVscode
onToggled: checked => SettingsData.set("matugenTemplateVscode", checked)

View File

@@ -137,7 +137,11 @@ Singleton {
Component.onCompleted: {
detectCompositor();
scheduleSort();
Qt.callLater(() => NiriService.generateNiriLayoutConfig());
Qt.callLater(() => {
NiriService.generateNiriLayoutConfig();
HyprlandService.generateLayoutConfig();
DwlService.generateLayoutConfig();
});
}
Connections {
@@ -396,7 +400,11 @@ Singleton {
repeat: false
onTriggered: {
detectCompositor();
Qt.callLater(() => NiriService.generateNiriLayoutConfig());
Qt.callLater(() => {
NiriService.generateNiriLayoutConfig();
HyprlandService.generateLayoutConfig();
DwlService.generateLayoutConfig();
});
}
}

View File

@@ -13,6 +13,9 @@ Singleton {
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation))
readonly property string mangoDmsDir: configDir + "/mango/dms"
readonly property string outputsPath: mangoDmsDir + "/outputs.conf"
readonly property string layoutPath: mangoDmsDir + "/layout.conf"
property int _lastGapValue: -1
property bool dwlAvailable: false
property var outputs: ({})
@@ -29,6 +32,27 @@ Singleton {
signal stateChanged
Connections {
target: SettingsData
function onBarConfigsChanged() {
if (!CompositorService.isDwl)
return;
const newGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4));
if (newGaps === root._lastGapValue)
return;
root._lastGapValue = newGaps;
generateLayoutConfig();
}
}
Connections {
target: CompositorService
function onIsDwlChanged() {
if (CompositorService.isDwl)
generateLayoutConfig();
}
}
Connections {
target: DMSService
function onCapabilitiesReceived() {
@@ -49,12 +73,12 @@ Singleton {
}
Component.onCompleted: {
if (DMSService.dmsAvailable) {
if (DMSService.dmsAvailable)
checkCapabilities();
}
if (dwlAvailable) {
if (dwlAvailable)
refreshOutputScales();
}
if (CompositorService.isDwl)
Qt.callLater(generateLayoutConfig);
}
function checkCapabilities() {
@@ -323,6 +347,37 @@ Singleton {
});
}
function generateLayoutConfig() {
if (!CompositorService.isDwl)
return;
const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12;
const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4;
const defaultBorderSize = 2;
const cornerRadius = (typeof SettingsData !== "undefined" && SettingsData.mangoLayoutRadiusOverride >= 0) ? SettingsData.mangoLayoutRadiusOverride : defaultRadius;
const gaps = (typeof SettingsData !== "undefined" && SettingsData.mangoLayoutGapsOverride >= 0) ? SettingsData.mangoLayoutGapsOverride : defaultGaps;
const borderSize = (typeof SettingsData !== "undefined" && SettingsData.mangoLayoutBorderSize >= 0) ? SettingsData.mangoLayoutBorderSize : defaultBorderSize;
let content = `# Auto-generated by DMS - do not edit manually
border_radius=${cornerRadius}
gappih=${gaps}
gappiv=${gaps}
gappoh=${gaps}
gappov=${gaps}
borderpx=${borderSize}
`;
Proc.runCommand("mango-write-layout", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${layoutPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
if (exitCode !== 0) {
console.warn("DwlService: Failed to write layout config:", output);
return;
}
console.info("DwlService: Generated layout config at", layoutPath);
reloadConfig();
});
}
function transformToMango(transform) {
switch (transform) {
case "Normal":

View File

@@ -12,6 +12,35 @@ Singleton {
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation))
readonly property string hyprDmsDir: configDir + "/hypr/dms"
readonly property string outputsPath: hyprDmsDir + "/outputs.conf"
readonly property string layoutPath: hyprDmsDir + "/layout.conf"
property int _lastGapValue: -1
Component.onCompleted: {
if (CompositorService.isHyprland)
Qt.callLater(generateLayoutConfig);
}
Connections {
target: SettingsData
function onBarConfigsChanged() {
if (!CompositorService.isHyprland)
return;
const newGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4));
if (newGaps === root._lastGapValue)
return;
root._lastGapValue = newGaps;
generateLayoutConfig();
}
}
Connections {
target: CompositorService
function onIsHyprlandChanged() {
if (CompositorService.isHyprland)
generateLayoutConfig();
}
}
function getOutputIdentifier(output, outputName) {
if (SettingsData.displayNameMode === "model" && output.make && output.model)
@@ -132,6 +161,41 @@ Singleton {
});
}
function generateLayoutConfig() {
if (!CompositorService.isHyprland)
return;
const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12;
const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4;
const defaultBorderSize = 2;
const cornerRadius = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutRadiusOverride >= 0) ? SettingsData.hyprlandLayoutRadiusOverride : defaultRadius;
const gaps = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutGapsOverride >= 0) ? SettingsData.hyprlandLayoutGapsOverride : defaultGaps;
const borderSize = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutBorderSize >= 0) ? SettingsData.hyprlandLayoutBorderSize : defaultBorderSize;
let content = `# Auto-generated by DMS - do not edit manually
general {
gaps_in = ${gaps}
gaps_out = ${gaps}
border_size = ${borderSize}
}
decoration {
rounding = ${cornerRadius}
}
`;
Proc.runCommand("hypr-write-layout", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${layoutPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
if (exitCode !== 0) {
console.warn("HyprlandService: Failed to write layout config:", output);
return;
}
console.info("HyprlandService: Generated layout config at", layoutPath);
reloadConfig();
});
}
function transformToHyprland(transform) {
switch (transform) {
case "Normal":

View File

@@ -1012,9 +1012,11 @@ Singleton {
const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12;
const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4;
const defaultBorderSize = 2;
const cornerRadius = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutRadiusOverride >= 0) ? SettingsData.niriLayoutRadiusOverride : defaultRadius;
const gaps = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutGapsOverride >= 0) ? SettingsData.niriLayoutGapsOverride : defaultGaps;
const borderSize = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutBorderSize >= 0) ? SettingsData.niriLayoutBorderSize : defaultBorderSize;
const dmsWarning = `// ! DO NOT EDIT !
// ! AUTO-GENERATED BY DMS !
@@ -1027,11 +1029,11 @@ Singleton {
gaps ${gaps}
border {
width 2
width ${borderSize}
}
focus-ring {
width 2
width ${borderSize}
}
}
window-rule {

View File

@@ -12,7 +12,7 @@ ScrollBar {
policy: (parent && parent.contentHeight > parent.height) ? ScrollBar.AsNeeded : ScrollBar.AlwaysOff
minimumSize: 0.08
implicitWidth: 8
implicitWidth: 10
interactive: true
hoverEnabled: true
z: 1000

View File

@@ -14,6 +14,7 @@ Item {
property bool toggling: false
property string text: ""
property string description: ""
property color descriptionColor: Theme.surfaceVariantText
property bool hideText: false
signal clicked
@@ -79,7 +80,7 @@ Item {
StyledText {
text: toggle.description
font.pixelSize: Appearance.fontSize.small
color: Theme.surfaceVariantText
color: toggle.descriptionColor
wrapMode: Text.WordWrap
width: Math.min(implicitWidth, toggle.width - 120)
visible: toggle.description.length > 0

View File

@@ -1,3 +1,3 @@
[templates.dmsalacritty]
input_path = 'SHELL_DIR/matugen/templates/alacritty.toml'
output_path = '~/.config/alacritty/dank-theme.toml'
output_path = 'CONFIG_DIR/alacritty/dank-theme.toml'

View File

@@ -1,3 +1,3 @@
[templates.dmsdgop]
input_path = 'SHELL_DIR/matugen/templates/dgop.json'
output_path = '~/.config/dgop/colors.json'
output_path = 'CONFIG_DIR/dgop/colors.json'

View File

@@ -1,3 +1,3 @@
[templates.dmsequibop]
input_path = 'SHELL_DIR/matugen/templates/vesktop.css'
output_path = '~/.config/equibop/themes/dank-discord.css'
output_path = 'CONFIG_DIR/equibop/themes/dank-discord.css'

View File

@@ -1,3 +1,3 @@
[templates.dmsfirefox]
input_path = 'SHELL_DIR/matugen/templates/firefox-userchrome.css'
output_path = '~/.config/DankMaterialShell/firefox.css'
output_path = 'CONFIG_DIR/DankMaterialShell/firefox.css'

View File

@@ -1,3 +1,3 @@
[templates.dmsfoot]
input_path = 'SHELL_DIR/matugen/templates/foot.ini'
output_path = '~/.config/foot/dank-colors.ini'
output_path = 'CONFIG_DIR/foot/dank-colors.ini'

View File

@@ -1,3 +1,3 @@
[templates.dmsghostty]
input_path = 'SHELL_DIR/matugen/templates/ghostty.conf'
output_path = '~/.config/ghostty/themes/dankcolors'
output_path = 'CONFIG_DIR/ghostty/themes/dankcolors'

View File

@@ -1,7 +1,7 @@
[templates.dmsgtk3]
input_path = 'SHELL_DIR/matugen/templates/gtk-colors.css'
output_path = '~/.config/gtk-3.0/dank-colors.css'
output_path = 'CONFIG_DIR/gtk-3.0/dank-colors.css'
[templates.dmsgtk4]
input_path = 'SHELL_DIR/matugen/templates/gtk-colors.css'
output_path = '~/.config/gtk-4.0/dank-colors.css'
output_path = 'CONFIG_DIR/gtk-4.0/dank-colors.css'

View File

@@ -1,7 +1,7 @@
[templates.dmsgtk3]
input_path = 'SHELL_DIR/matugen/templates/gtk-light-colors.css'
output_path = '~/.config/gtk-3.0/dank-colors.css'
output_path = 'CONFIG_DIR/gtk-3.0/dank-colors.css'
[templates.dmsgtk4]
input_path = 'SHELL_DIR/matugen/templates/gtk-colors.css'
output_path = '~/.config/gtk-4.0/dank-colors.css'
output_path = 'CONFIG_DIR/gtk-4.0/dank-colors.css'

View File

@@ -0,0 +1,3 @@
[templates.dmshyprland]
input_path = 'SHELL_DIR/matugen/templates/hypr-colors.conf'
output_path = 'CONFIG_DIR/hypr/dms/colors.conf'

View File

@@ -1,11 +1,11 @@
[templates.dmskcolorscheme]
input_path = 'SHELL_DIR/matugen/templates/kcolorscheme.colors'
output_path = '~/.local/share/color-schemes/DankMatugen.colors'
output_path = 'DATA_DIR/color-schemes/DankMatugen.colors'
[templates.dmslightkcolorscheme]
input_path = 'SHELL_DIR/matugen/templates/light-kcolorscheme.colors'
output_path = '~/.local/share/color-schemes/DankMatugenLight.colors'
output_path = 'DATA_DIR/color-schemes/DankMatugenLight.colors'
[templates.dmsdarkkcolorscheme]
input_path = 'SHELL_DIR/matugen/templates/dark-kcolorscheme.colors'
output_path = '~/.local/share/color-schemes/DankMatugenDark.colors'
output_path = 'DATA_DIR/color-schemes/DankMatugenDark.colors'

View File

@@ -1,7 +1,7 @@
[templates.dmskitty]
input_path = 'SHELL_DIR/matugen/templates/kitty.conf'
output_path = '~/.config/kitty/dank-theme.conf'
output_path = 'CONFIG_DIR/kitty/dank-theme.conf'
[templates.dmskittytabs]
input_path = 'SHELL_DIR/matugen/templates/kitty-tabs.conf'
output_path = '~/.config/kitty/dank-tabs.conf'
output_path = 'CONFIG_DIR/kitty/dank-tabs.conf'

View File

@@ -0,0 +1,3 @@
[templates.dmsmango]
input_path = 'SHELL_DIR/matugen/templates/mango-colors.conf'
output_path = 'CONFIG_DIR/mango/dms/colors.conf'

View File

@@ -1,3 +1,3 @@
[templates.dmsneovim]
input_path = 'SHELL_DIR/matugen/templates/neovim.lua'
output_path = '~/.config/nvim/lua/plugins/dankcolors.lua'
output_path = 'CONFIG_DIR/nvim/lua/plugins/dankcolors.lua'

View File

@@ -1,3 +1,3 @@
[templates.dmsniri]
input_path = 'SHELL_DIR/matugen/templates/niri-colors.kdl'
output_path = '~/.config/niri/dms/colors.kdl'
output_path = 'CONFIG_DIR/niri/dms/colors.kdl'

View File

@@ -1,4 +1,4 @@
[templates.dmspywalfox]
input_path = 'SHELL_DIR/matugen/templates/pywalfox-colors.json'
output_path = '~/.cache/wal/dank-pywalfox.json'
output_path = 'CACHE_DIR/wal/dank-pywalfox.json'
post_hook = 'sh -c "command -v pywalfox && test -f ~/.cache/wal/colors.json && pywalfox update"'

View File

@@ -1,3 +1,3 @@
[templates.dmsqt5ct]
input_path = 'SHELL_DIR/matugen/templates/qtct-colors.conf'
output_path = '~/.config/qt5ct/colors/matugen.conf'
output_path = 'CONFIG_DIR/qt5ct/colors/matugen.conf'

View File

@@ -1,3 +1,3 @@
[templates.dmsqt6ct]
input_path = 'SHELL_DIR/matugen/templates/qtct-colors.conf'
output_path = '~/.config/qt6ct/colors/matugen.conf'
output_path = 'CONFIG_DIR/qt6ct/colors/matugen.conf'

View File

@@ -1,3 +1,3 @@
[templates.dmsvesktop]
input_path = 'SHELL_DIR/matugen/templates/vesktop.css'
output_path = '~/.config/vesktop/themes/dank-discord.css'
output_path = 'CONFIG_DIR/vesktop/themes/dank-discord.css'

View File

@@ -1,3 +1,3 @@
[templates.dmswezterm]
input_path = 'SHELL_DIR/matugen/templates/wezterm.toml'
output_path = '~/.config/wezterm/colors/dank-theme.toml'
output_path = 'CONFIG_DIR/wezterm/colors/dank-theme.toml'

View File

@@ -1,3 +1,3 @@
[templates.dmszenbrowser]
input_path = 'SHELL_DIR/matugen/templates/zen-userchrome.css'
output_path = '~/.config/DankMaterialShell/zen.css'
output_path = 'CONFIG_DIR/DankMaterialShell/zen.css'

View File

@@ -0,0 +1,25 @@
# ! Auto-generated file. Do not edit directly.
# Remove source = ./dms/colors.conf from your config to override.
$primary = rgb({{colors.primary.default.hex_stripped}})
$outline = rgb({{colors.outline.default.hex_stripped}})
$error = rgb({{colors.error.default.hex_stripped}})
general {
col.active_border = $primary
col.inactive_border = $outline
}
group {
col.border_active = $primary
col.border_inactive = $outline
col.border_locked_active = $error
col.border_locked_inactive = $outline
groupbar {
col.active = $primary
col.inactive = $outline
col.locked_active = $error
col.locked_inactive = $outline
}
}

View File

@@ -0,0 +1,6 @@
# ! Auto-generated file. Do not edit directly.
# Remove source = ./dms/colors.conf from your config to override.
bordercolor = 0x{{colors.outline.default.hex_stripped}}ff
focuscolor = 0x{{colors.primary.default.hex_stripped}}ff
urgentcolor = 0x{{colors.error.default.hex_stripped}}ff

View File

@@ -1,3 +1,6 @@
// ! Auto-generated file. Do not edit directly.
// Remove `include "dms/colors.kdl"` from your config to override.
layout {
background-color "transparent"

View File

@@ -3,6 +3,7 @@
//@ pragma Env QT_FFMPEG_DECODING_HW_DEVICE_TYPES=vaapi
//@ pragma Env QT_FFMPEG_ENCODING_HW_DEVICE_TYPES=vaapi
//@ pragma Env QT_WAYLAND_DISABLE_WINDOWDECORATION=1
//@ pragma Env QT_QUICK_CONTROLS_STYLE=Material
//@ pragma UseQApplication
import QtQuick