safe
This commit is contained in:
+107
-33
@@ -4,7 +4,7 @@ import GObject, { register, getter, gtype, property, setter } from "ags/gobject"
|
||||
|
||||
import Gio from "gi://Gio?version=2.0";
|
||||
import GLib from "gi://GLib?version=2.0";
|
||||
import { createSubscription, encoder } from "./utils";
|
||||
import { createSubscription } from "./utils";
|
||||
import { Notifications } from "./notifications";
|
||||
import { generalConfig } from "../config";
|
||||
import { createRoot, getScope, Scope } from "ags";
|
||||
@@ -161,37 +161,45 @@ class Wallpaper extends GObject.Object {
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
private writeChanges(): void {
|
||||
this.#hyprpaperFile.replace_async(null, false,
|
||||
Gio.FileCreateFlags.REPLACE_DESTINATION,
|
||||
GLib.PRIORITY_DEFAULT, null, (_, result) => {
|
||||
const res = this.#hyprpaperFile.replace_finish(result);
|
||||
if(!res) {
|
||||
console.error(`Wallpaper: an error occurred when trying to replace the hyprpaper file`);
|
||||
private writeChanges(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const content = `# This file was automatically generated by colorshell
|
||||
|
||||
preload = ${this.#wallpaper}
|
||||
splash = ${this.#splash}
|
||||
wallpaper = , ${this.positioning === "cover" ? "" : `${this.positioning}:`}${this.#wallpaper}
|
||||
`;
|
||||
|
||||
// Use synchronous file writing for reliability
|
||||
const filePath = this.#hyprpaperFile.get_path();
|
||||
if(!filePath) {
|
||||
reject(new Error("Could not get hyprpaper file path"));
|
||||
return;
|
||||
}
|
||||
|
||||
// success
|
||||
res.write_bytes_async(encoder.encode(`\
|
||||
# This file was automatically generated by colorshell
|
||||
// Ensure directory exists
|
||||
const parentDir = this.#hyprpaperFile.get_parent();
|
||||
if(parentDir && !parentDir.query_exists(null)) {
|
||||
parentDir.make_directory_with_parents(null);
|
||||
}
|
||||
|
||||
preload = ${this.#wallpaper}
|
||||
splash = ${this.#splash}
|
||||
wallpaper = , ${this.positioning === "cover" ? "" : `${this.positioning}:`}${
|
||||
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;
|
||||
// Write file synchronously using GLib
|
||||
const success = GLib.file_set_contents(filePath, content);
|
||||
if(success) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error("Failed to write hyprpaper config file"));
|
||||
}
|
||||
} catch (e: any) {
|
||||
reject(new Error(`Failed to write config file: ${e.message}`));
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public getData(): WalData {
|
||||
const content = readFile(`${GLib.getenv("XDG_CACHE_HOME")}/wal/colors.json`);
|
||||
const cacheHome = GLib.getenv("XDG_CACHE_HOME") || `${GLib.get_home_dir()}/.cache`;
|
||||
const content = readFile(`${cacheHome}/wal/colors.json`);
|
||||
return JSON.parse(content) as WalData;
|
||||
}
|
||||
|
||||
@@ -210,10 +218,41 @@ class Wallpaper extends GObject.Object {
|
||||
}
|
||||
|
||||
public reloadColors(): void {
|
||||
execAsync(`wal -t --cols16 ${this.colorMode} -i "${this.#wallpaper}"`).then(() => {
|
||||
const cacheHome = GLib.getenv("XDG_CACHE_HOME") || `${GLib.get_home_dir()}/.cache`;
|
||||
const colorsKittyPath = `${cacheHome}/wal/colors-kitty.conf`;
|
||||
const kittyConfigPath = `${GLib.get_user_config_dir()}/kitty/kitty.conf`;
|
||||
|
||||
const runWal = (extraArgs: string = "") =>
|
||||
execAsync(`wal -t --cols16 ${this.colorMode} ${extraArgs} -i "${this.#wallpaper}"`);
|
||||
|
||||
// First try default backend; if it fails (e.g. some images on aarch64),
|
||||
// fall back to a more forgiving backend like "colorz".
|
||||
runWal().catch((e: Error) => {
|
||||
console.error(`Wallpaper: Couldn't update shell colors with default backend. Stderr: ${e.message}`);
|
||||
console.log("Wallpaper: Falling back to pywal backend 'colorz'");
|
||||
return runWal("--backend colorz");
|
||||
}).then(() => {
|
||||
console.log("Wallpaper: reloaded shell colors");
|
||||
|
||||
// First, try to set colors on all existing kitty instances
|
||||
execAsync(`kitty @ set-colors --all ${colorsKittyPath}`).then(() => {
|
||||
console.log("Wallpaper: reloaded colors in existing kitty instances");
|
||||
}).catch((e: Error) => {
|
||||
// It's okay if this fails (e.g., no kitty instances running)
|
||||
console.log(`Wallpaper: Couldn't reload kitty colors in existing instances: ${e.message}`);
|
||||
});
|
||||
|
||||
// Then, update the configured colors for future kitty instances
|
||||
// This is critical - it tells kitty to use these colors for new windows
|
||||
execAsync(`kitty @ set-colors --configured ${colorsKittyPath}`).then(() => {
|
||||
console.log("Wallpaper: configured colors for future kitty instances");
|
||||
}).catch((e: Error) => {
|
||||
// If no kitty instances are running, we can't set configured colors
|
||||
// In this case, new instances should still pick up colors from the include directive
|
||||
console.log(`Wallpaper: Couldn't set configured colors (new instances will use include directive): ${e.message}`);
|
||||
});
|
||||
}).catch((e: Error) => {
|
||||
console.error(`Wallpaper: Couldn't update shell colors. Stderr: ${e.message}`);
|
||||
console.error(`Wallpaper: Couldn't update shell colors even with fallback backend. Stderr: ${e.message}`);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -221,10 +260,39 @@ class Wallpaper extends GObject.Object {
|
||||
if(this.wallpaper.trim() === "")
|
||||
return;
|
||||
|
||||
await execAsync(`hyprctl hyprpaper reload \", ${
|
||||
this.positioning === "cover" ? "" : `${this.positioning}:`
|
||||
}${this.wallpaper}\"`);
|
||||
write && this.writeChanges();
|
||||
const wallpaperPath = this.#wallpaper.trim();
|
||||
|
||||
try {
|
||||
// Write config file first if needed
|
||||
if(write) {
|
||||
await this.writeChanges();
|
||||
}
|
||||
|
||||
// Unload all current wallpapers
|
||||
await execAsync(`hyprctl hyprpaper unload all`).catch(() => {
|
||||
// Ignore errors - this is usually fine
|
||||
});
|
||||
|
||||
// Preload the new wallpaper
|
||||
await execAsync(`hyprctl hyprpaper preload "${wallpaperPath}"`);
|
||||
|
||||
// Set wallpaper on all monitors
|
||||
await execAsync(`hyprctl hyprpaper wallpaper ", ${wallpaperPath}"`);
|
||||
|
||||
// Note: We don't need to reload or restart hyprpaper here
|
||||
// The preload and wallpaper commands should apply the change immediately
|
||||
// The config file is written for persistence across hyprpaper restarts
|
||||
|
||||
} catch (e: any) {
|
||||
console.error(`Wallpaper: Error reloading wallpaper: ${e.message}`);
|
||||
console.error(`Wallpaper: Stack trace: ${e.stack}`);
|
||||
Notifications.getDefault().sendNotification({
|
||||
appName: "colorshell",
|
||||
summary: "Failed to set wallpaper",
|
||||
body: `Error: ${e.message}`
|
||||
});
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public setWallpaper(path: string|Gio.File, write: boolean = true): void {
|
||||
@@ -244,10 +312,16 @@ class Wallpaper extends GObject.Object {
|
||||
|
||||
public async pickWallpaper(): Promise<string|undefined> {
|
||||
return (await execAsync(`zenity --file-selection`).then(wall => {
|
||||
if(!wall.trim()) return undefined;
|
||||
const trimmedWall = wall.trim();
|
||||
if(!trimmedWall) return undefined;
|
||||
|
||||
this.setWallpaper(wall);
|
||||
return wall;
|
||||
// Ensure path is absolute
|
||||
const absolutePath = GLib.path_is_absolute(trimmedWall)
|
||||
? trimmedWall
|
||||
: GLib.build_filenamev([GLib.get_current_dir(), trimmedWall]);
|
||||
|
||||
this.setWallpaper(absolutePath);
|
||||
return absolutePath;
|
||||
}).catch((e: Error) => {
|
||||
console.error(`Wallpaper: Couldn't pick wallpaper, is \`zenity\` installed? Stderr: ${e.message}`);
|
||||
return undefined;
|
||||
|
||||
Reference in New Issue
Block a user