From ae1d29bc891bcd789c559b41378834f746c1e5b7 Mon Sep 17 00:00:00 2001 From: retrozinndev Date: Sun, 11 May 2025 20:51:35 -0300 Subject: [PATCH] :boom: ags(scripts/wallpapers): fix writeChanges and a lot of stuff --- ags/scripts/wallpaper.ts | 154 ++++++++++++++++++++++++--------------- 1 file changed, 97 insertions(+), 57 deletions(-) diff --git a/ags/scripts/wallpaper.ts b/ags/scripts/wallpaper.ts index 31826b1..471ae4e 100644 --- a/ags/scripts/wallpaper.ts +++ b/ags/scripts/wallpaper.ts @@ -1,4 +1,4 @@ -import { execAsync, Gio, GLib, GObject, monitorFile, property, register } from "astal"; +import { AstalIO, execAsync, Gio, GLib, GObject, monitorFile, property, register, timeout } from "astal"; export { Wallpaper }; @@ -10,14 +10,13 @@ class Wallpaper extends GObject.Object { #monitor: Gio.FileMonitor; #hyprpaperFile: Gio.File; #wallpapersPath: string; + #ignoreWatch: boolean = false; @property(Boolean) public get splash() { return this.#splash; } public set splash(showSplash: boolean) { this.#splash = showSplash; this.notify("splash"); - - this.writeChanges(); } @property(String) @@ -28,31 +27,59 @@ class Wallpaper extends GObject.Object { constructor() { super(); + this.#wallpapersPath = GLib.getenv("WALLPAPERS") ?? `${GLib.get_home_dir()}/wallpapers`; this.#hyprpaperFile = Gio.File.new_for_path(`${GLib.get_user_config_dir()}/hypr/hyprpaper.conf`); - this.getWallpaper().then((wall) => this.#wallpaper = wall).catch(r => { - throw new Error(`Wallpaper: Couldn't get wallpaper. Stderr: ${r}`) + this.getWallpaper().then((wall) => { + if(wall?.trim()) this.#wallpaper = wall.trim(); }); - this.#monitor = monitorFile(this.#hyprpaperFile.get_path()!, async (_, event) => { - if(event == Gio.FileMonitorEvent.CHANGED) { - const [loaded, , content ] = this.#hyprpaperFile.load_contents(null); - if(loaded) - for(const line of content.split('\n')) { - const [ key, value ] = line.split('='); - if(key.trim().startsWith('#')) - continue; + let tmeout: (AstalIO.Time|undefined) = undefined; - switch(key) { - case "splash": - this.#splash = /(yes|true|on)/.test(value.trim()) ? true : false; - break; + this.#monitor = monitorFile(this.#hyprpaperFile.get_path()!, (_, event) => { + if(event !== Gio.FileMonitorEvent.CHANGED && event !== Gio.FileMonitorEvent.CREATED && + event !== Gio.FileMonitorEvent.MOVED_IN) + return; - case "wallpaper": - this.#wallpaper = value; - break; - } - }; + if(tmeout) return; + else tmeout = timeout(1500, () => tmeout = undefined); + + if(this.#ignoreWatch) { + this.#ignoreWatch = false; + return; + } + + const [ loaded, text ] = this.#hyprpaperFile.load_contents(null); + if(!loaded) + console.error("Wallpaper: Couldn't read changes inside the hyprpaper file!"); + + const content = new TextDecoder().decode(text); + + if(content) { + let setWall: boolean = true; + + for(const line of content.split('\n')) { + if(line.trim().startsWith('#')) + continue; + + const lineSplit = line.split('='); + const key = lineSplit[0].trim(), + value = lineSplit.filter((_, i) => i !== 0).join('=').trim(); + + switch(key) { + case "splash": + this.splash = /(yes|true|on|enable|enabled)/.test(value) ? true : false; + break; + + case "wallpaper": + if(this.#wallpaper !== value && setWall) { + this.setWallpaper(value, false); + setWall = false; // wallpaper already set + } + + break; + } + } } }); } @@ -68,70 +95,83 @@ class Wallpaper extends GObject.Object { return this.instance; } - private async writeChanges(): Promise { - if(!this.#wallpaper) return; + private writeChanges(): void { + this.#ignoreWatch = true; // tell monitor to ignore file replace + this.#hyprpaperFile.replace_async(null, false, + Gio.FileCreateFlags.REPLACE_DESTINATION, + GLib.PRIORITY_DEFAULT, null, (_, result) => { + const res = this.#hyprpaperFile.replace_finish(result); + if(res) { + // success + this.#ignoreWatch = true; // tell monitor to ignore this change + res.write_bytes_async(new TextEncoder().encode(`# This file was automatically generated by color-shell - const hyprpaperFile = Gio.File.new_for_path(`${GLib.get_user_config_dir()}/hypr/hyprpaper.conf`); - hyprpaperFile.create(Gio.FileCreateFlags.REPLACE_DESTINATION, null); - return hyprpaperFile.replace_contents_async(`# This file is automatically generated when choosing a new wallpaper in colorshell - preload = ${this.#wallpaper} - splash = ${this.#splash} - wallpaper = , ${this.#wallpaper}`.split('\n').map(str => str.trimStart()).join('\n'), null, false, - Gio.FileCreateFlags.REPLACE_DESTINATION, null - ).then(() => {}).catch(r => { - throw new Error(`Wallpaper: Couldn't write hyprpaper file. Stderr: ${r}`); - }); + preload = ${this.#wallpaper} + splash = ${this.#splash} + wallpaper = , ${this.#wallpaper}`.split('\n').map(str => str.trimStart()).join('\n')), + GLib.PRIORITY_DEFAULT, null, (_, asyncRes) => { + if(_!.write_finish(asyncRes)) res.flush(null); + res.close(null); + } + ); + + return; + } + + console.error(`Wallpaper: an error occurred when trying to replace the hyprpaper file`); + } + ); } public async getWallpaper(): Promise { - return await execAsync("hyprctl hyprpaper listactive | tail -n 1").then(stdout => { + return await execAsync("sh -c \"hyprctl hyprpaper listactive | tail -n 1\"").then(stdout => { const loaded: (string|undefined) = stdout.split('=')[1]?.trim(); + if(!loaded) - throw new Error(`Wallpaper: Couldn't get wallpaper. There are no loaded wallpaper(s)`); + console.warn(`Wallpaper: Couldn't get wallpaper. There is(are) no loaded wallpaper(s)`); return loaded; - }).catch(stderr => { - throw new Error(`Wallpaper: Couldn't get wallpaper. Stderr: ${stderr}`); + }).catch((err: Gio.IOErrorEnum) => { + console.error(`Wallpaper: Couldn't get wallpaper. Stderr: \n${err.message ? `${err.message} /` : ""} Stack: \n ${err.stack}`); + return undefined; }); } - public async reloadColors(): Promise { - return await execAsync(`wal -t --cols16 darken -i "${this.#wallpaper}"`).then(() => { + public reloadColors(): void { + execAsync(`wal -t --cols16 darken -i "${this.#wallpaper}"`).then(() => { + console.log("Wallpaper: reloaded shell colors"); }).catch(r => { - throw new Error(`Wallpaper: Couldn't update shell colors. Stderr: ${r}`); + console.error(`Wallpaper: Couldn't update shell colors. Stderr: ${r}`); }); } - public async setWallpaper(path: string|Gio.File): Promise { - return await execAsync("hyprctl hyprpaper unload all").then(async () => - await execAsync(`hyprctl hyprpaper preload ${path}`).then(async () => - await execAsync(`hyprctl hyprpaper wallpaper ${path}`).then(async () => { + public setWallpaper(path: string|Gio.File, write: boolean = true): void { + execAsync("hyprctl hyprpaper unload all").then(() => + execAsync(`hyprctl hyprpaper preload ${path}`).then(() => + execAsync(`hyprctl hyprpaper wallpaper ${path}`).then(() => { this.#wallpaper = (typeof path === "string") ? path : path.get_path()!; this.reloadColors(); - this.writeChanges().catch(r => { - throw new Error(`Wallpaper: Couldn't write changes to hyprpaper config file. Stderr: ${r}`); - }); + write && this.writeChanges(); }).catch(r => { - throw new Error(`Wallpaper: Couldn't set wallpaper. Stderr: ${r}`); + console.error(`Wallpaper: Couldn't set wallpaper. Stderr: ${r}`); }) ).catch(r => { - throw new Error(`Wallpaper: Couldn't preload image. Stderr: ${r}`); + console.error(`Wallpaper: Couldn't preload image. Stderr: ${r}`); }) ).catch(r => { - throw new Error(`Wallpaper: Couldn't unload images from memory. Stderr: ${r}`); + console.error(`Wallpaper: Couldn't unload images from memory. Stderr: ${r}`); }); } public async pickWallpaper(): Promise { - return execAsync(`zenity --file-selection`).then(wall => { + return (await execAsync(`zenity --file-selection`).then(wall => { if(!wall.trim()) return undefined; - this.setWallpaper(wall).catch(r => { - throw new Error(`Wallpaper: An error occurred in \`setWallpaper()\`. Stderr: ${r}`); - }); + this.setWallpaper(wall); return wall; }).catch(r => { - throw new Error(`Wallpaper: Couldn't pick wallpaper, is zenity installed? Stderr: ${r}`); - }); + console.error(`Wallpaper: Couldn't pick wallpaper, is \`zenity\` installed? Stderr: ${r}`); + return undefined; + })); } }