From 9eeccfee278c713955f1267cd1515353c35a6ab2 Mon Sep 17 00:00:00 2001 From: Wendel Silva Date: Wed, 29 Apr 2026 17:06:47 -0300 Subject: [PATCH] fix(wallpaper): support matugen 4.x output format and TTY-less invocation Two related bugs prevented theme regeneration when running with matugen >= 4.x (current Arch Extra version): 1. matugen requires `--prefer` when multiple source colors can be extracted from an image and there is no TTY, which is always the case under `exec_sh_async`. Without it, the subprocess aborts silently. The user_settings JSON is updated, but the SCSS / GTK / Qt color files stay stale, so the next reload shows the previous palette and the toggle appears broken. 2. matugen 4.x changed the JSON shape of `--json hex` from raw hex strings to `{"color": "#hex"}` dicts. `generatePreviews()` writes `color_value` straight into preview-colors.scss, which now produces invalid SCSS like $palette-content-background: {'color': '#fcfaec'}; This crashes Sass compilation on `ignis reload` and the shell silently dies (no stylesheet -> no UI). This patch: - Adds `--prefer saturation` to all 8 `matugen image` invocations (3 in `setWall`, 3 in `setColors`/`setDarkMode`, 2 in `generatePreviews`). Saturation matches the visual intent of the selected scheme without UI input. - In `generatePreviews()`, unboxes `color_value` when it is a dict by reading `color`/`hex` keys (matugen 4.x) and falls back to the first value otherwise. Backwards compatible with matugen-bin 3.x and matugen-git, which already returned strings. Closes #37 Co-Authored-By: Claude Opus 4.7 (1M context) --- ignis/scripts/wallpaper.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/ignis/scripts/wallpaper.py b/ignis/scripts/wallpaper.py index ed43d4f..03ce596 100644 --- a/ignis/scripts/wallpaper.py +++ b/ignis/scripts/wallpaper.py @@ -33,13 +33,13 @@ def setWall(path): if colorScheme in schemes: asyncio.create_task( utils.exec_sh_async( - f"matugen image -t scheme-{colorScheme} '{path}' -m '{mode}'" + f"matugen image -t scheme-{colorScheme} '{path}' -m '{mode}' --prefer saturation" ) ) else: asyncio.create_task( utils.exec_sh_async( - f"matugen image -t scheme-tonal-spot '{path}' -m '{mode}'" + f"matugen image -t scheme-tonal-spot '{path}' -m '{mode}' --prefer saturation" ) ) @@ -68,13 +68,13 @@ def setColors(colorScheme): if colorScheme in schemes: asyncio.create_task( utils.exec_sh_async( - f"matugen image -t scheme-{colorScheme} '{path}' -m '{mode}'" + f"matugen image -t scheme-{colorScheme} '{path}' -m '{mode}' --prefer saturation" ) ) else: asyncio.create_task( utils.exec_sh_async( - f"matugen image -t scheme-tonal-spot '{path}' -m '{mode}'" + f"matugen image -t scheme-tonal-spot '{path}' -m '{mode}' --prefer saturation" ) ) @@ -116,7 +116,7 @@ def setDarkMode(active): if colorScheme in schemes: asyncio.create_task( utils.exec_sh_async( - f"matugen image -t scheme-{colorScheme} '{path}' -m '{mode}'" + f"matugen image -t scheme-{colorScheme} '{path}' -m '{mode}' --prefer saturation" ) ) asyncio.create_task( @@ -127,7 +127,7 @@ def setDarkMode(active): else: asyncio.create_task( utils.exec_sh_async( - f"matugen image -t scheme-tonal-spot '{path}' -m '{mode}'" + f"matugen image -t scheme-tonal-spot '{path}' -m '{mode}' --prefer saturation" ) ) asyncio.create_task( @@ -168,12 +168,12 @@ async def do_generate(): tasks_palette = [] for scheme in schemes: - command = f"matugen image -t scheme-{scheme} '{path}' -m {current_mode} --json hex --dry-run" + command = f"matugen image -t scheme-{scheme} '{path}' -m {current_mode} --prefer saturation --json hex --dry-run" tasks_palette.append(utils.exec_sh_async(command)) tasks_theme = [] for mode in ["light", "dark"]: - command = f"matugen image -t scheme-{current_scheme} '{path}' -m {mode} --json hex --dry-run" + command = f"matugen image -t scheme-{current_scheme} '{path}' -m {mode} --prefer saturation --json hex --dry-run" tasks_theme.append(utils.exec_sh_async(command)) all_results = await asyncio.gather(*(tasks_palette + tasks_theme)) @@ -200,6 +200,8 @@ async def do_generate(): for color_name, values in data["colors"].items(): if current_mode in values: color_value = values[current_mode] + if isinstance(color_value, dict): + color_value = color_value.get("color") or color_value.get("hex") or next(iter(color_value.values())) variable_name = f"palette-{scheme}-{color_name.replace('_', '-')}" scss_content += ( f"${variable_name}: {color_value};\n" @@ -228,6 +230,8 @@ async def do_generate(): for color_name, values in data["colors"].items(): if mode in values: color_value = values[mode] + if isinstance(color_value, dict): + color_value = color_value.get("color") or color_value.get("hex") or next(iter(color_value.values())) variable_name = ( f"theme-{mode}-{color_name.replace('_', '-')}" )