Background: on the hunt again

This commit is contained in:
ItsLemmy
2025-10-03 09:26:45 -04:00
parent d2a5150f10
commit 9c024e35c3
4 changed files with 230 additions and 163 deletions
+69 -69
View File
@@ -9,76 +9,76 @@ import qs.Commons
// - Assets/Matugen/templates/
// - ~/.config/matugen/ (when enableUserTemplates is true)
Singleton {
id: root
id: root
// Build the base TOML using current settings
function buildConfigToml() {
var lines = [];
lines.push("[config]");
var mode = Settings.data.colorSchemes.darkMode ? "dark" : "light";
// Always include noctalia colors output for the shell
lines.push("[templates.noctalia]");
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/noctalia.json"');
lines.push('output_path = "' + Settings.configDir + 'colors.json"');
// Build the base TOML using current settings
function buildConfigToml() {
var lines = []
lines.push("[config]")
var mode = Settings.data.colorSchemes.darkMode ? "dark" : "light"
// Always include noctalia colors output for the shell
lines.push("[templates.noctalia]")
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/noctalia.json"')
lines.push('output_path = "' + Settings.configDir + 'colors.json"')
if (Settings.data.matugen.gtk4) {
lines.push("\n[templates.gtk4]");
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/gtk4.css"');
lines.push('output_path = "~/.config/gtk-4.0/gtk.css"');
lines.push("post_hook = 'gsettings set org.gnome.desktop.interface color-scheme prefer-" + mode + "'");
}
if (Settings.data.matugen.gtk3) {
lines.push("\n[templates.gtk3]");
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/gtk3.css"');
lines.push('output_path = "~/.config/gtk-3.0/gtk.css"');
lines.push("post_hook = 'gsettings set org.gnome.desktop.interface color-scheme prefer-" + mode + "'");
}
if (Settings.data.matugen.qt6) {
lines.push("\n[templates.qt6]");
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/qtct.conf"');
lines.push('output_path = "~/.config/qt6ct/colors/noctalia.conf"');
}
if (Settings.data.matugen.qt5) {
lines.push("\n[templates.qt5]");
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/qtct.conf"');
lines.push('output_path = "~/.config/qt5ct/colors/noctalia.conf"');
}
if (Settings.data.matugen.kitty) {
lines.push("\n[templates.kitty]");
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/kitty.conf"');
lines.push('output_path = "~/.config/kitty/themes/noctalia.conf"');
lines.push("post_hook = 'kitty +kitten themes --reload-in=all noctalia'");
}
if (Settings.data.matugen.ghostty) {
lines.push("\n[templates.ghostty]");
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/ghostty.conf"');
lines.push('output_path = "~/.config/ghostty/themes/noctalia"');
lines.push("post_hook = \"grep -q '^theme *= *' ~/.config/ghostty/config; and sed -i 's/^theme *= *.*/theme = noctalia/' ~/.config/ghostty/config; or echo 'theme = noctalia' >> ~/.config/ghostty/config; and pkill -SIGUSR2 ghostty\"");
}
if (Settings.data.matugen.foot) {
lines.push("\n[templates.foot]");
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/foot.conf"');
lines.push('output_path = "~/.config/foot/themes/noctalia"');
lines.push('post_hook = "sed -i /themes/d ~/.config/foot/foot.ini && echo include=~/.config/foot/themes/noctalia >> ~/.config/foot/foot.ini"');
}
if (Settings.data.matugen.fuzzel) {
lines.push("\n[templates.fuzzel]");
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/fuzzel.conf"');
lines.push('output_path = "~/.config/fuzzel/themes/noctalia"');
lines.push('post_hook = "sed -i /themes/d ~/.config/fuzzel/fuzzel.ini && echo include=~/.config/fuzzel/themes/noctalia >> ~/.config/fuzzel/fuzzel.ini"');
}
if (Settings.data.matugen.vesktop) {
lines.push("\n[templates.vesktop]");
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/vesktop.css"');
lines.push('output_path = "~/.config/vesktop/themes/noctalia.theme.css"');
}
if (Settings.data.matugen.pywalfox) {
lines.push("\n[templates.pywalfox]");
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/pywalfox.json"');
lines.push('output_path = "~/.cache/wal/colors.json"');
lines.push('post_hook = "pywalfox update"');
}
return lines.join("\n") + "\n";
if (Settings.data.matugen.gtk4) {
lines.push("\n[templates.gtk4]")
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/gtk4.css"')
lines.push('output_path = "~/.config/gtk-4.0/gtk.css"')
lines.push("post_hook = 'gsettings set org.gnome.desktop.interface color-scheme prefer-" + mode + "'")
}
if (Settings.data.matugen.gtk3) {
lines.push("\n[templates.gtk3]")
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/gtk3.css"')
lines.push('output_path = "~/.config/gtk-3.0/gtk.css"')
lines.push("post_hook = 'gsettings set org.gnome.desktop.interface color-scheme prefer-" + mode + "'")
}
if (Settings.data.matugen.qt6) {
lines.push("\n[templates.qt6]")
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/qtct.conf"')
lines.push('output_path = "~/.config/qt6ct/colors/noctalia.conf"')
}
if (Settings.data.matugen.qt5) {
lines.push("\n[templates.qt5]")
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/qtct.conf"')
lines.push('output_path = "~/.config/qt5ct/colors/noctalia.conf"')
}
if (Settings.data.matugen.kitty) {
lines.push("\n[templates.kitty]")
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/kitty.conf"')
lines.push('output_path = "~/.config/kitty/themes/noctalia.conf"')
lines.push("post_hook = 'kitty +kitten themes --reload-in=all noctalia'")
}
if (Settings.data.matugen.ghostty) {
lines.push("\n[templates.ghostty]")
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/ghostty.conf"')
lines.push('output_path = "~/.config/ghostty/themes/noctalia"')
lines.push("post_hook = \"grep -q '^theme *= *' ~/.config/ghostty/config; and sed -i 's/^theme *= *.*/theme = noctalia/' ~/.config/ghostty/config; or echo 'theme = noctalia' >> ~/.config/ghostty/config; and pkill -SIGUSR2 ghostty\"")
}
if (Settings.data.matugen.foot) {
lines.push("\n[templates.foot]")
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/foot.conf"')
lines.push('output_path = "~/.config/foot/themes/noctalia"')
lines.push('post_hook = "sed -i /themes/d ~/.config/foot/foot.ini && echo include=~/.config/foot/themes/noctalia >> ~/.config/foot/foot.ini"')
}
if (Settings.data.matugen.fuzzel) {
lines.push("\n[templates.fuzzel]")
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/fuzzel.conf"')
lines.push('output_path = "~/.config/fuzzel/themes/noctalia"')
lines.push('post_hook = "sed -i /themes/d ~/.config/fuzzel/fuzzel.ini && echo include=~/.config/fuzzel/themes/noctalia >> ~/.config/fuzzel/fuzzel.ini"')
}
if (Settings.data.matugen.vesktop) {
lines.push("\n[templates.vesktop]")
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/vesktop.css"')
lines.push('output_path = "~/.config/vesktop/themes/noctalia.theme.css"')
}
if (Settings.data.matugen.pywalfox) {
lines.push("\n[templates.pywalfox]")
lines.push('input_path = "' + Quickshell.shellDir + '/Assets/Matugen/templates/pywalfox.json"')
lines.push('output_path = "~/.cache/wal/colors.json"')
lines.push('post_hook = "pywalfox update"')
}
return lines.join("\n") + "\n"
}
}
+160 -92
View File
@@ -46,6 +46,14 @@ Variants {
Component.onCompleted: setWallpaperInitial()
Component.onDestruction: {
transitionAnimation.stop()
debounceTimer.stop()
shaderLoader.active = false
currentWallpaper.source = ""
nextWallpaper.source = ""
}
Connections {
target: Settings.data.wallpaper
function onFillModeChanged() {
@@ -97,6 +105,11 @@ Variants {
visible: false
cache: false
asynchronous: true
onStatusChanged: {
if (status === Image.Error) {
Logger.warn("Current wallpaper failed to load:", source)
}
}
}
Image {
@@ -107,108 +120,139 @@ Variants {
visible: false
cache: false
asynchronous: true
onStatusChanged: {
if (status === Image.Error) {
Logger.warn("Next wallpaper failed to load:", source)
}
}
}
// Fade or None transition shader
ShaderEffect {
id: fadeShader
// Dynamic shader loader - only loads the active transition shader
Loader {
id: shaderLoader
anchors.fill: parent
visible: transitionType === "fade" || transitionType === "none"
active: true
property variant source1: currentWallpaper
property variant source2: nextWallpaper
property real progress: root.transitionProgress
// Fill mode properties
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: source1.sourceSize.width
property real imageHeight1: source1.sourceSize.height
property real imageWidth2: source2.sourceSize.width
property real imageHeight2: source2.sourceSize.height
property real screenWidth: width
property real screenHeight: height
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/wp_fade.frag.qsb")
sourceComponent: {
switch (transitionType) {
case "wipe":
return wipeShaderComponent
case "disc":
return discShaderComponent
case "stripes":
return stripesShaderComponent
case "fade":
case "none":
default:
return fadeShaderComponent
}
}
}
// Wipe transition shader
ShaderEffect {
id: wipeShader
anchors.fill: parent
visible: transitionType === "wipe"
// Fade or None transition shader component
Component {
id: fadeShaderComponent
ShaderEffect {
anchors.fill: parent
property variant source1: currentWallpaper
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real direction: root.wipeDirection
property variant source1: currentWallpaper
property variant source2: nextWallpaper
property real progress: root.transitionProgress
// Fill mode properties
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: source1.sourceSize.width
property real imageHeight1: source1.sourceSize.height
property real imageWidth2: source2.sourceSize.width
property real imageHeight2: source2.sourceSize.height
property real screenWidth: width
property real screenHeight: height
// Fill mode properties
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: source1.sourceSize.width
property real imageHeight1: source1.sourceSize.height
property real imageWidth2: source2.sourceSize.width
property real imageHeight2: source2.sourceSize.height
property real screenWidth: width
property real screenHeight: height
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/wp_wipe.frag.qsb")
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/wp_fade.frag.qsb")
}
}
// Disc reveal transition shader
ShaderEffect {
id: discShader
anchors.fill: parent
visible: transitionType === "disc"
// Wipe transition shader component
Component {
id: wipeShaderComponent
ShaderEffect {
anchors.fill: parent
property variant source1: currentWallpaper
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real aspectRatio: root.width / root.height
property real centerX: root.discCenterX
property real centerY: root.discCenterY
property variant source1: currentWallpaper
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real direction: root.wipeDirection
// Fill mode properties
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: source1.sourceSize.width
property real imageHeight1: source1.sourceSize.height
property real imageWidth2: source2.sourceSize.width
property real imageHeight2: source2.sourceSize.height
property real screenWidth: width
property real screenHeight: height
// Fill mode properties
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: source1.sourceSize.width
property real imageHeight1: source1.sourceSize.height
property real imageWidth2: source2.sourceSize.width
property real imageHeight2: source2.sourceSize.height
property real screenWidth: width
property real screenHeight: height
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/wp_disc.frag.qsb")
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/wp_wipe.frag.qsb")
}
}
// Diagonal stripes transition shader
ShaderEffect {
id: stripesShader
anchors.fill: parent
visible: transitionType === "stripes"
// Disc reveal transition shader component
Component {
id: discShaderComponent
ShaderEffect {
anchors.fill: parent
property variant source1: currentWallpaper
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real aspectRatio: root.width / root.height
property real stripeCount: root.stripesCount
property real angle: root.stripesAngle
property variant source1: currentWallpaper
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real aspectRatio: root.width / root.height
property real centerX: root.discCenterX
property real centerY: root.discCenterY
// Fill mode properties
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: source1.sourceSize.width
property real imageHeight1: source1.sourceSize.height
property real imageWidth2: source2.sourceSize.width
property real imageHeight2: source2.sourceSize.height
property real screenWidth: width
property real screenHeight: height
// Fill mode properties
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: source1.sourceSize.width
property real imageHeight1: source1.sourceSize.height
property real imageWidth2: source2.sourceSize.width
property real imageHeight2: source2.sourceSize.height
property real screenWidth: width
property real screenHeight: height
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/wp_stripes.frag.qsb")
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/wp_disc.frag.qsb")
}
}
// Diagonal stripes transition shader component
Component {
id: stripesShaderComponent
ShaderEffect {
anchors.fill: parent
property variant source1: currentWallpaper
property variant source2: nextWallpaper
property real progress: root.transitionProgress
property real smoothness: root.edgeSmoothness
property real aspectRatio: root.width / root.height
property real stripeCount: root.stripesCount
property real angle: root.stripesAngle
// Fill mode properties
property real fillMode: root.fillMode
property vector4d fillColor: root.fillColor
property real imageWidth1: source1.sourceSize.width
property real imageHeight1: source1.sourceSize.height
property real imageWidth2: source2.sourceSize.width
property real imageHeight2: source2.sourceSize.height
property real screenWidth: width
property real screenHeight: height
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/wp_stripes.frag.qsb")
}
}
// Animation for the transition progress
@@ -222,13 +266,19 @@ Variants {
duration: transitionType == "stripes" ? Settings.data.wallpaper.transitionDuration * 1.6 : Settings.data.wallpaper.transitionDuration
easing.type: Easing.InOutCubic
onFinished: {
// Swap images after transition completes
currentWallpaper.source = ""
currentWallpaper.source = nextWallpaper.source
// Swap images while keeping shader active to prevent flickering
const tempSource = nextWallpaper.source
nextWallpaper.source = ""
transitionProgress = 0.0
currentWallpaper.source = ""
// Use Qt.callLater to allow GC to clean up before reassignment
Qt.callLater(() => {
currentWallpaper.asynchronous = true
currentWallpaper.source = tempSource
transitionProgress = 0.0
Qt.callLater(() => {
currentWallpaper.asynchronous = true
})
})
}
}
@@ -246,9 +296,14 @@ Variants {
function setWallpaperImmediate(source) {
transitionAnimation.stop()
transitionProgress = 0.0
currentWallpaper.source = ""
currentWallpaper.source = source
// Clear with proper delay to allow GC
nextWallpaper.source = ""
currentWallpaper.source = ""
Qt.callLater(() => {
currentWallpaper.source = source
})
}
function setWallpaperWithTransition(source) {
@@ -257,15 +312,28 @@ Variants {
}
if (transitioning) {
// We are interrupting a transition
// We are interrupting a transition - handle cleanup properly
transitionAnimation.stop()
transitionProgress = 0
const newCurrentSource = nextWallpaper.source
// Clear both properly while keeping shader active
currentWallpaper.source = ""
nextWallpaper.source = ""
currentWallpaper.source = newCurrentSource
// Defer the reassignment to allow cleanup
Qt.callLater(() => {
currentWallpaper.source = newCurrentSource
// Now set the next wallpaper after a brief delay
Qt.callLater(() => {
nextWallpaper.source = source
currentWallpaper.asynchronous = false
transitionAnimation.start()
})
})
return
}
nextWallpaper.source = source
+1 -1
View File
@@ -37,7 +37,7 @@ Variants {
}
}
}
Connections {
target: WallpaperService
function onIsInitializedChanged() {
-1
View File
@@ -38,7 +38,6 @@ import qs.Modules.Notification
import qs.Modules.OSD
import qs.Modules.Settings
import qs.Modules.Toast
import qs.Modules.Tooltip
import qs.Modules.Wallpaper
ShellRoot {