Fix dynamic theming: enable filesystem writes and add theme switching

- Add LD_LIBRARY_PATH and ILLOGICAL_IMPULSE_VIRTUAL_ENV to quickshell service
- Set ProtectSystem=false to allow color generation scripts to write files
- Fix MaterialThemeLoader to properly detect file changes with onFileChanged
- Add switchwall-wrapper.sh to source environment variables dynamically
- Fix light/dark mode buttons to use Process with current wallpaper
- Add --choose flag to switchwall.sh for wallpaper selection dialog
- Add IPC commands 'dark' and 'light' for console theme switching
- Update keybinds: Ctrl+Super+T (choose), Ctrl+Super+Shift+T (random)
- Fix terminal color application in applycolor.sh
This commit is contained in:
Celes Renata
2025-11-29 18:57:23 -08:00
parent 3655e7aaee
commit d192bee3d9
9 changed files with 333 additions and 70 deletions
+1
View File
@@ -0,0 +1 @@
export LD_LIBRARY_PATH="/nix/store/xm08aqdd7pxcdhm0ak6aqb1v7hw5q6ri-gcc-14.3.0-lib/lib:/nix/store/xx7cm72qy2c0643cm1ipngd87aqwkcdp-glibc-2.40-66/lib:/nix/store/l7xwm1f6f3zj2x8jwdbi8gdyfbx07sh7-zlib-1.3.1/lib:/nix/store/b9p0zpa93hwvh4d0r1rmgc2500yx2ldn-libffi-3.5.2/lib:/nix/store/61i74yjkj9p1qphfl7018ja4sdwkipx0-openssl-3.6.0/lib:/nix/store/xgavznqg1ay2hycpp7yy9ia1n751jcla-bzip2-1.0.8/lib:/nix/store/q5vlz5jl6p7mv220s2vf6z5pqi1n935z-xz-5.8.1/lib:/nix/store/yijhn548p2589pkybgvbhll09bqsxy0q-ncurses-6.5/lib:/nix/store/41cgbkwax6pd1sgi8l81mamv6rvarryj-readline-8.3p1/lib:/nix/store/l30c488dws7z5mazacqsmj25izb9jlp2-sqlite-3.50.4/lib"
+23 -23
View File
@@ -1,3 +1,5 @@
import qs.modules.common
import qs
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
@@ -15,34 +17,19 @@ Singleton {
property bool osdVolumeOpen: false property bool osdVolumeOpen: false
property bool oskOpen: false property bool oskOpen: false
property bool overviewOpen: false property bool overviewOpen: false
property bool sessionOpen: false
property bool workspaceShowNumbers: false
property bool superReleaseMightTrigger: true
property bool screenLocked: false property bool screenLocked: false
property bool screenLockContainsCharacters: false property bool screenLockContainsCharacters: false
property bool sessionOpen: false
property bool superDown: false
property bool superReleaseMightTrigger: true
property bool workspaceShowNumbers: false
property real screenZoom: 1 property real screenZoom: 1
onScreenZoomChanged: { onScreenZoomChanged: {
Quickshell.execDetached(["hyprctl", "keyword", "cursor:zoom_factor", root.screenZoom.toString()]); Quickshell.execDetached(["hyprctl", "keyword", "cursor:zoom_factor", root.screenZoom.toString()]);
} }
Behavior on screenZoom { Behavior on screenZoom {
NumberAnimation { duration: 200; easing.type: Easing.OutCubic } animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
// animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
// When user is not reluctant while pressing super, they probably don't need to see workspace numbers
onSuperReleaseMightTriggerChanged: {
workspaceShowNumbersTimer.stop()
}
Timer {
id: workspaceShowNumbersTimer
interval: 500 // Config.options.bar.workspaces.showNumberDelay
// interval: 0
repeat: false
onTriggered: {
workspaceShowNumbers = true
}
} }
GlobalShortcut { GlobalShortcut {
@@ -50,11 +37,10 @@ Singleton {
description: "Hold to show workspace numbers, release to show icons" description: "Hold to show workspace numbers, release to show icons"
onPressed: { onPressed: {
workspaceShowNumbersTimer.start() root.superDown = true
} }
onReleased: { onReleased: {
workspaceShowNumbersTimer.stop() root.superDown = false
workspaceShowNumbers = false
} }
} }
@@ -69,4 +55,18 @@ Singleton {
screenZoom = Math.max(screenZoom - 0.4, 1) screenZoom = Math.max(screenZoom - 0.4, 1)
} }
} }
IpcHandler {
target: "theme"
function dark() {
const wallpaper = Config.options.background.wallpaperPath || `${Quickshell.env("HOME")}/Pictures/Wallpapers/konachan_random_image.png`
Quickshell.execDetached(["bash", `${Quickshell.env("HOME")}/.config/quickshell/scripts/colors/switchwall-wrapper.sh`, wallpaper, "--mode", "dark"])
}
function light() {
const wallpaper = Config.options.background.wallpaperPath || `${Quickshell.env("HOME")}/Pictures/Wallpapers/konachan_random_image.png`
Quickshell.execDetached(["bash", `${Quickshell.env("HOME")}/.config/quickshell/scripts/colors/switchwall-wrapper.sh`, wallpaper, "--mode", "light"])
}
}
} }
@@ -5,6 +5,7 @@ import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import Quickshell.Io
import Quickshell.Services.Pipewire import Quickshell.Services.Pipewire
import Quickshell.Services.UPower import Quickshell.Services.UPower
@@ -14,6 +15,20 @@ Item {
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2 implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
implicitHeight: rowLayout.implicitHeight implicitHeight: rowLayout.implicitHeight
Process {
id: themeSwitchProcess
running: false
stdout: SplitParser {
onRead: data => console.log("switchwall:", data)
}
stderr: SplitParser {
onRead: data => console.log("switchwall err:", data)
}
onExited: (code, status) => {
console.log("switchwall exited:", code)
}
}
RowLayout { RowLayout {
id: rowLayout id: rowLayout
@@ -25,7 +40,7 @@ Item {
visible: Config.options.bar.utilButtons.showScreenSnip visible: Config.options.bar.utilButtons.showScreenSnip
sourceComponent: CircleUtilButton { sourceComponent: CircleUtilButton {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
onClicked: Quickshell.execDetached(["qs", "-p", Quickshell.shellPath("screenshot.qml")]) onClicked: Quickshell.execDetached(["quickshell", "-p", Quickshell.shellPath("screenshot.qml")])
MaterialSymbol { MaterialSymbol {
horizontalAlignment: Qt.AlignHCenter horizontalAlignment: Qt.AlignHCenter
fill: 1 fill: 1
@@ -90,11 +105,11 @@ Item {
sourceComponent: CircleUtilButton { sourceComponent: CircleUtilButton {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
onClicked: event => { onClicked: event => {
if (Appearance.m3colors.darkmode) { const mode = Appearance.m3colors.darkmode ? "light" : "dark"
Hyprland.dispatch(`exec ${Directories.wallpaperSwitchScriptPath} --mode light --noswitch`); const wallpaper = Config.options.background.wallpaperPath || `${Quickshell.env("HOME")}/Pictures/Wallpapers/konachan_random_image.png`
} else { themeSwitchProcess.command = ["bash", `${Directories.scriptPath}/colors/switchwall-wrapper.sh`, wallpaper, "--mode", mode]
Hyprland.dispatch(`exec ${Directories.wallpaperSwitchScriptPath} --mode dark --noswitch`); themeSwitchProcess.running = false
} themeSwitchProcess.running = true
} }
MaterialSymbol { MaterialSymbol {
horizontalAlignment: Qt.AlignHCenter horizontalAlignment: Qt.AlignHCenter
@@ -129,9 +144,9 @@ Item {
horizontalAlignment: Qt.AlignHCenter horizontalAlignment: Qt.AlignHCenter
fill: 0 fill: 0
text: switch(PowerProfiles.profile) { text: switch(PowerProfiles.profile) {
case PowerProfile.PowerSaver: return "battery_saver" case PowerProfile.PowerSaver: return "energy_savings_leaf"
case PowerProfile.Balanced: return "dynamic_form" case PowerProfile.Balanced: return "settings_slow_motion"
case PowerProfile.Performance: return "speed" case PowerProfile.Performance: return "local_fire_department"
} }
iconSize: Appearance.font.pixelSize.large iconSize: Appearance.font.pixelSize.large
color: Appearance.colors.colOnLayer2 color: Appearance.colors.colOnLayer2
@@ -17,7 +17,7 @@ GroupButton {
colBackground: Appearance.colors.colLayer2 colBackground: Appearance.colors.colLayer2
toggled: Appearance.m3colors.darkmode === dark toggled: Appearance.m3colors.darkmode === dark
onClicked: { onClicked: {
Quickshell.execDetached(["bash", "-c", `${Directories.wallpaperSwitchScriptPath} --mode ${dark ? "dark" : "light"} --noswitch`]) Quickshell.execDetached(["bash", `${Directories.scriptPath}/colors/switchwall-wrapper.sh`, "--mode", dark ? "dark" : "light", "--noswitch"])
} }
contentItem: Item { contentItem: Item {
anchors.centerIn: parent anchors.centerIn: parent
@@ -2,6 +2,7 @@
import argparse import argparse
import math import math
import json import json
import os
from PIL import Image from PIL import Image
from materialyoucolor.quantize import QuantizeCelebi from materialyoucolor.quantize import QuantizeCelebi
from materialyoucolor.score.score import Score from materialyoucolor.score.score import Score
@@ -86,6 +87,11 @@ if args.path is not None:
elif args.color is not None: elif args.color is not None:
argb = hex_to_argb(args.color) argb = hex_to_argb(args.color)
hct = Hct.from_int(argb) hct = Hct.from_int(argb)
elif args.cache is not None and os.path.exists(args.cache):
with open(args.cache, 'r') as file:
cached_color = file.read().strip()
argb = hex_to_argb(cached_color)
hct = Hct.from_int(argb)
if args.scheme == 'scheme-fruit-salad': if args.scheme == 'scheme-fruit-salad':
from materialyoucolor.scheme.scheme_fruit_salad import SchemeFruitSalad as Scheme from materialyoucolor.scheme.scheme_fruit_salad import SchemeFruitSalad as Scheme
+13
View File
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
# Wrapper to set up environment for switchwall.sh
# Source environment config
[ -f "$HOME/.config/quickshell/env.sh" ] && source "$HOME/.config/quickshell/env.sh"
export ILLOGICAL_IMPULSE_VIRTUAL_ENV="${ILLOGICAL_IMPULSE_VIRTUAL_ENV:-$HOME/.local/state/quickshell/.venv}"
echo "[wrapper] Called with args: $@" >> /tmp/switchwall-wrapper.log
echo "[wrapper] LD_LIBRARY_PATH: $LD_LIBRARY_PATH" >> /tmp/switchwall-wrapper.log
# Run switchwall.sh with all arguments
exec "$(dirname "$0")/switchwall.sh" "$@"
@@ -1,5 +1,16 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Log execution
LOG="/tmp/switchwall.log"
echo "[$(date)] switchwall.sh started" >> "$LOG"
echo "ILLOGICAL_IMPULSE_VIRTUAL_ENV=$ILLOGICAL_IMPULSE_VIRTUAL_ENV" >> "$LOG"
# Ensure LD_LIBRARY_PATH is set for Python venv
if [ -z "$LD_LIBRARY_PATH" ]; then
export LD_LIBRARY_PATH="/run/current-system/sw/lib"
echo "Set LD_LIBRARY_PATH=$LD_LIBRARY_PATH" >> "$LOG"
fi
QUICKSHELL_CONFIG_NAME="ii" QUICKSHELL_CONFIG_NAME="ii"
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}" XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
@@ -84,9 +95,10 @@ check_and_prompt_upscale() {
img_height=$(identify -format "%h" "$img" 2>/dev/null) img_height=$(identify -format "%h" "$img" 2>/dev/null)
fi fi
if [[ "$img_width" -lt "$min_width_desired" || "$img_height" -lt "$min_height_desired" ]]; then if [[ "$img_width" -lt "$min_width_desired" || "$img_height" -lt "$min_height_desired" ]]; then
action=$(notify-send "Upscale?" \ action=$(timeout 5 notify-send "Upscale?" \
"Image resolution (${img_width}x${img_height}) is lower than screen resolution (${min_width_desired}x${min_height_desired})" \ "Image resolution (${img_width}x${img_height}) is lower than screen resolution (${min_width_desired}x${min_height_desired})" \
-A "open_upscayl=Open Upscayl"\ -A "open_upscayl=Open Upscayl"\
-t 5000 \
-a "Wallpaper switcher") -a "Wallpaper switcher")
if [[ "$action" == "open_upscayl" ]]; then if [[ "$action" == "open_upscayl" ]]; then
if command -v upscayl &>/dev/null; then if command -v upscayl &>/dev/null; then
@@ -187,7 +199,10 @@ switch() {
exit 0 exit 0
fi fi
check_and_prompt_upscale "$imgpath" & # Only check upscale if not using --noswitch
if [[ -z "$noswitch_flag" ]]; then
check_and_prompt_upscale "$imgpath" &
fi
kill_existing_mpvpaper kill_existing_mpvpaper
if is_video "$imgpath"; then if is_video "$imgpath"; then
@@ -281,11 +296,34 @@ switch() {
fi fi
matugen "${matugen_args[@]}" matugen "${matugen_args[@]}"
source "$(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate" echo "[$(date)] Running python script" >> "$LOG"
python3 "$SCRIPT_DIR/generate_colors_material.py" "${generate_colors_material_args[@]}" \ "$(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/python3" "$SCRIPT_DIR/generate_colors_material.py" "${generate_colors_material_args[@]}" \
> "$STATE_DIR"/user/generated/material_colors.scss > "$STATE_DIR"/user/generated/material_colors.scss 2>> "$LOG"
"$SCRIPT_DIR"/applycolor.sh echo "[$(date)] Python done, scss size: $(wc -l < "$STATE_DIR"/user/generated/material_colors.scss)" >> "$LOG"
deactivate
# Only convert to JSON if SCSS was generated successfully
if [ -s "$STATE_DIR"/user/generated/material_colors.scss ]; then
# Convert SCSS to JSON for quickshell MaterialThemeLoader
echo "[$(date)] Converting SCSS to JSON" >> "$LOG"
awk -F': ' '/^\$/ {gsub(/\$|;/, "", $0); print "\"" $1 "\": \"" $2 "\","}' \
"$STATE_DIR"/user/generated/material_colors.scss | \
sed '$ s/,$//' | \
(echo "{"; cat; echo "}") > "$STATE_DIR"/user/generated/colors.json.tmp
mv "$STATE_DIR"/user/generated/colors.json.tmp "$STATE_DIR"/user/generated/colors.json
sync "$STATE_DIR"/user/generated/colors.json
echo "[$(date)] JSON created, size: $(wc -l < "$STATE_DIR"/user/generated/colors.json)" >> "$LOG"
else
echo "[$(date)] SCSS generation failed, skipping JSON creation" >> "$LOG"
fi
"$XDG_CONFIG_HOME/quickshell/scripts/colors/applycolor.sh"
# Wait for all file operations to complete
wait
sleep 1
# Trigger quickshell to reload theme via IPC (doesn't restart the process)
quickshell ipc -c ii call materialTheme reload 2>/dev/null || true
# Pass screen width, height, and wallpaper path to post_process # Pass screen width, height, and wallpaper path to post_process
max_width_desired="$(hyprctl monitors -j | jq '([.[].width] | min)' | xargs)" max_width_desired="$(hyprctl monitors -j | jq '([.[].width] | min)' | xargs)"
@@ -300,6 +338,7 @@ main() {
color_flag="" color_flag=""
color="" color=""
noswitch_flag="" noswitch_flag=""
choose_flag=""
get_type_from_config() { get_type_from_config() {
jq -r '.appearance.palette.type' "$SHELL_CONFIG_FILE" 2>/dev/null || echo "auto" jq -r '.appearance.palette.type' "$SHELL_CONFIG_FILE" 2>/dev/null || echo "auto"
@@ -339,6 +378,10 @@ main() {
imgpath=$(jq -r '.background.wallpaperPath' "$SHELL_CONFIG_FILE" 2>/dev/null || echo "") imgpath=$(jq -r '.background.wallpaperPath' "$SHELL_CONFIG_FILE" 2>/dev/null || echo "")
shift shift
;; ;;
--choose)
choose_flag="1"
shift
;;
*) *)
if [[ -z "$imgpath" ]]; then if [[ -z "$imgpath" ]]; then
imgpath="$1" imgpath="$1"
@@ -369,8 +412,17 @@ main() {
# Only prompt for wallpaper if not using --color and not using --noswitch and no imgpath set # Only prompt for wallpaper if not using --color and not using --noswitch and no imgpath set
if [[ -z "$imgpath" && -z "$color_flag" && -z "$noswitch_flag" ]]; then if [[ -z "$imgpath" && -z "$color_flag" && -z "$noswitch_flag" ]]; then
cd "$(xdg-user-dir PICTURES)/Wallpapers/showcase" 2>/dev/null || cd "$(xdg-user-dir PICTURES)/Wallpapers" 2>/dev/null || cd "$(xdg-user-dir PICTURES)" || return 1 # Try to pick a random wallpaper from Wallpapers directory
imgpath="$(kdialog --getopenfilename . --title 'Choose wallpaper')" WALLPAPER_DIR="$(xdg-user-dir PICTURES)/Wallpapers"
if [[ -d "$WALLPAPER_DIR" ]] && [[ -z "$choose_flag" ]]; then
imgpath=$(find "$WALLPAPER_DIR" -type f \( -name "*.jpg" -o -name "*.png" \) 2>/dev/null | shuf -n 1)
fi
# If --choose flag is set or still no wallpaper, prompt with kdialog
if [[ -n "$choose_flag" ]] || [[ -z "$imgpath" ]]; then
cd "$(xdg-user-dir PICTURES)/Wallpapers/showcase" 2>/dev/null || cd "$(xdg-user-dir PICTURES)/Wallpapers" 2>/dev/null || cd "$(xdg-user-dir PICTURES)" || return 1
imgpath="$(kdialog --getopenfilename . --title 'Choose wallpaper')"
fi
fi fi
# If type_flag is 'auto', detect scheme type from image (after imgpath is set) # If type_flag is 'auto', detect scheme type from image (after imgpath is set)
@@ -2,6 +2,7 @@ pragma Singleton
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import qs.modules.common import qs.modules.common
import qs.modules.common.functions
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
@@ -14,31 +15,37 @@ Singleton {
id: root id: root
property string filePath: Directories.generatedMaterialThemePath property string filePath: Directories.generatedMaterialThemePath
function reapplyTheme() { Component.onCompleted: delayedFileRead.restart()
themeFileView.reload()
}
function applyColors(fileContent) { function reapplyTheme() {
const json = JSON.parse(fileContent) delayedFileRead.restart()
for (const key in json) {
if (json.hasOwnProperty(key)) {
// Convert snake_case to CamelCase
const camelCaseKey = key.replace(/_([a-z])/g, (g) => g[1].toUpperCase())
const m3Key = `m3${camelCaseKey}`
Appearance.m3colors[m3Key] = json[key]
}
}
Appearance.m3colors.darkmode = (Appearance.m3colors.m3background.hslLightness < 0.5)
} }
Timer { Timer {
id: delayedFileRead id: delayedFileRead
interval: Config.options?.hacks?.arbitraryRaceConditionDelay ?? 100 interval: Config.options?.hacks?.arbitraryRaceConditionDelay ?? 300
repeat: false repeat: false
running: false running: false
onTriggered: { onTriggered: {
root.applyColors(themeFileView.text()) console.log("MaterialThemeLoader: Timer triggered")
const fileContent = themeFileView.text()
console.log("MaterialThemeLoader: Read", fileContent.length, "bytes")
const json = JSON.parse(fileContent)
let colorCount = 0
for (const key in json) {
if (json.hasOwnProperty(key)) {
if (key === 'darkmode' || key === 'transparent' || key.includes('paletteKeyColor') || key.startsWith('term')) {
continue
}
const camelCaseKey = key.replace(/_([a-z])/g, (g) => g[1].toUpperCase())
const m3Key = `m3${camelCaseKey}`
Appearance.m3colors[m3Key] = json[key]
colorCount++
}
}
console.log("MaterialThemeLoader: Applied", colorCount, "colors")
console.log("MaterialThemeLoader: m3primary =", Appearance.m3colors.m3primary)
Appearance.m3colors.darkmode = (Appearance.m3colors.m3background.hslLightness < 0.5)
} }
} }
@@ -48,11 +55,8 @@ Singleton {
watchChanges: true watchChanges: true
onFileChanged: { onFileChanged: {
this.reload() this.reload()
delayedFileRead.start() delayedFileRead.restart()
}
onLoadedChanged: {
const fileContent = themeFileView.text()
root.applyColors(fileContent)
} }
onLoadedChanged: if (loaded) delayedFileRead.restart()
} }
} }
+178 -6
View File
@@ -9,7 +9,22 @@ CACHE_DIR="$XDG_CACHE_HOME/quickshell"
STATE_DIR="$XDG_STATE_HOME/quickshell" STATE_DIR="$XDG_STATE_HOME/quickshell"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
term_alpha=100 #Set this to < 100 make all your terminals transparent term_alpha=60
# Check transparency setting and adjust term_alpha accordingly
if [ -f "$STATE_DIR/user/generated/terminal/transparency" ]; then
transparency_mode=$(cat "$STATE_DIR/user/generated/terminal/transparency")
if [ "$transparency_mode" = "opaque" ]; then
term_alpha=100
else
# For transparent mode, use the opacity setting from config or default to 80
if [ -f "$STATE_DIR/user/generated/terminal/opacity" ]; then
term_alpha=$(cat "$STATE_DIR/user/generated/terminal/opacity")
else
term_alpha=80
fi
fi
fi
# sleep 0 # idk i wanted some delay or colors dont get applied properly # sleep 0 # idk i wanted some delay or colors dont get applied properly
if [ ! -d "$STATE_DIR"/user/generated ]; then if [ ! -d "$STATE_DIR"/user/generated ]; then
mkdir -p "$STATE_DIR"/user/generated mkdir -p "$STATE_DIR"/user/generated
@@ -26,6 +41,7 @@ colorstrings=$(cat $STATE_DIR/user/generated/material_colors.scss | cut -d: -f2
IFS=$'\n' IFS=$'\n'
colorlist=($colornames) # Array of color names colorlist=($colornames) # Array of color names
colorvalues=($colorstrings) # Array of color values colorvalues=($colorstrings) # Array of color values
export colorlist colorvalues
apply_term() { apply_term() {
# Check if terminal escape sequence template exists # Check if terminal escape sequence template exists
@@ -43,13 +59,13 @@ apply_term() {
sed -i "s/\$alpha/$term_alpha/g" "$STATE_DIR/user/generated/terminal/sequences.txt" sed -i "s/\$alpha/$term_alpha/g" "$STATE_DIR/user/generated/terminal/sequences.txt"
# Send escape sequences to all terminals
for file in /dev/pts/*; do for file in /dev/pts/*; do
if [[ $file =~ ^/dev/pts/[0-9]+$ ]]; then if [[ $file =~ ^/dev/pts/[0-9]+$ ]]; then
{ cat "$STATE_DIR"/user/generated/terminal/sequences.txt >"$file" 2>/dev/null &
cat "$STATE_DIR"/user/generated/terminal/sequences.txt >"$file"
} & disown || true
fi fi
done done
wait
} }
apply_qt() { apply_qt() {
@@ -57,16 +73,172 @@ apply_qt() {
python "$CONFIG_DIR/scripts/kvantum/changeAdwColors.py" # apply config colors python "$CONFIG_DIR/scripts/kvantum/changeAdwColors.py" # apply config colors
} }
apply_foot() {
# Check if foot template exists
if [ ! -f "$SCRIPT_DIR/foot/foot.ini" ]; then
echo "Template file not found for Foot. Skipping that."
return
fi
# Copy template
mkdir -p "$STATE_DIR/user/generated/foot"
cp "$SCRIPT_DIR/foot/foot.ini" "$STATE_DIR/user/generated/foot/foot.ini"
# Apply colors (skip non-color variables like $darkmode, $transparent)
# Sort by variable name length (longest first) to avoid partial replacement issues
# e.g., $term10 must be replaced before $term1 to avoid "AC72FF0" malformed colors
filtered_indices=()
for i in "${!colorlist[@]}"; do
# Skip variables that don't start with color names or contain special values
if [[ "${colorlist[$i]}" == *"darkmode"* ]] || [[ "${colorlist[$i]}" == *"transparent"* ]] || [[ "${colorlist[$i]}" == *"palette"* ]]; then
continue
fi
filtered_indices+=($i)
done
# Sort indices by variable name length (longest first)
IFS=$'\n' sorted_indices=($(for idx in "${filtered_indices[@]}"; do
echo "${#colorlist[$idx]} $idx"
done | sort -rn | cut -d' ' -f2))
for i in "${sorted_indices[@]}"; do
# Escape the $ in the color name for sed
color_name="${colorlist[$i]//$/\\$}"
# Remove # prefix from color value for foot compatibility
color_value="${colorvalues[$i]}"
color_value="${color_value#\#}" # Remove leading # if present
sed -i "s/${color_name}/${color_value}/g" "$STATE_DIR/user/generated/foot/foot.ini"
done
# After all color replacements, ensure no # prefixes remain in color values
# This handles any edge cases where # prefixes weren't removed properly
sed -i 's/=\s*#\([0-9A-Fa-f]\{6\}\)/=\1/g' "$STATE_DIR/user/generated/foot/foot.ini"
# Convert term_alpha percentage to decimal for foot (e.g., 70 -> 0.7)
foot_alpha=$(echo "scale=2; $term_alpha / 100" | bc)
# Use line number replacement to avoid sed pattern issues
sed -i "/^alpha=/c\\alpha=$foot_alpha" "$STATE_DIR/user/generated/foot/foot.ini"
# Copy to actual config location
mkdir -p "$XDG_CONFIG_HOME/foot"
cp "$STATE_DIR/user/generated/foot/foot.ini" "$XDG_CONFIG_HOME/foot/foot.ini"
}
apply_fuzzel() {
# Check if fuzzel template exists
if [ ! -f "$SCRIPT_DIR/fuzzel/fuzzel.ini" ]; then
echo "Template file not found for Fuzzel. Skipping that."
return
fi
# Copy template
mkdir -p "$STATE_DIR/user/generated/fuzzel"
cp "$SCRIPT_DIR/fuzzel/fuzzel.ini" "$STATE_DIR/user/generated/fuzzel/fuzzel.ini"
# Apply colors (skip non-color variables like $darkmode, $transparent)
# Sort by variable name length (longest first) to avoid partial replacement issues
filtered_indices=()
for i in "${!colorlist[@]}"; do
# Skip variables that don't start with color names or contain special values
if [[ "${colorlist[$i]}" == *"darkmode"* ]] || [[ "${colorlist[$i]}" == *"transparent"* ]] || [[ "${colorlist[$i]}" == *"palette"* ]]; then
continue
fi
filtered_indices+=($i)
done
# Sort indices by variable name length (longest first)
IFS=$'\n' sorted_indices=($(for idx in "${filtered_indices[@]}"; do
echo "${#colorlist[$idx]} $idx"
done | sort -rn | cut -d' ' -f2))
for i in "${sorted_indices[@]}"; do
# Escape the $ in the color name for sed
color_name="${colorlist[$i]//$/\\$}"
# Keep # prefix for fuzzel (unlike foot)
color_value="${colorvalues[$i]}"
sed -i "s/${color_name}/${color_value}/g" "$STATE_DIR/user/generated/fuzzel/fuzzel.ini"
done
# Copy to actual config location
mkdir -p "$XDG_CONFIG_HOME/fuzzel"
cp "$STATE_DIR/user/generated/fuzzel/fuzzel.ini" "$XDG_CONFIG_HOME/fuzzel/fuzzel.ini"
}
# Function to convert hex color to RGB values
dehex() {
local hex="$1"
# Remove # if present
hex="${hex#\#}"
# Convert to RGB
printf "%d, %d, %d" "0x${hex:0:2}" "0x${hex:2:2}" "0x${hex:4:2}"
}
apply_wofi() {
# Check if wofi template exists
if [ ! -f "$SCRIPT_DIR/wofi/style.css" ]; then
echo "Template file not found for Wofi colors. Skipping that."
return
fi
# Copy template
mkdir -p "$XDG_CONFIG_HOME/wofi"
cp "$SCRIPT_DIR/wofi/style.css" "$XDG_CONFIG_HOME/wofi/style_new.css"
chmod +w "$XDG_CONFIG_HOME/wofi/style_new.css"
# Apply colors (skip non-color variables like $darkmode, $transparent)
# Sort by variable name length (longest first) to avoid partial replacement issues
filtered_indices=()
for i in "${!colorlist[@]}"; do
# Skip variables that don't start with color names or contain special values
if [[ "${colorlist[$i]}" == *"darkmode"* ]] || [[ "${colorlist[$i]}" == *"transparent"* ]] || [[ "${colorlist[$i]}" == *"palette"* ]]; then
continue
fi
filtered_indices+=($i)
done
# Sort indices by variable name length (longest first)
IFS=$'\n' sorted_indices=($(for idx in "${filtered_indices[@]}"; do
echo "${#colorlist[$idx]} $idx"
done | sort -rn | cut -d' ' -f2))
# Apply hex colors (without # prefix) - use {{ $variable }} syntax
for i in "${sorted_indices[@]}"; do
# Remove $ prefix for the template pattern
color_name="${colorlist[$i]#\$}"
# Remove # prefix for wofi
color_value="${colorvalues[$i]}"
color_value="${color_value#\#}"
sed -i "s/{{ \$${color_name} }}/${color_value}/g" "$XDG_CONFIG_HOME/wofi/style_new.css"
done
# Apply RGB colors - use {{ $variable-rgb }} syntax
for i in "${sorted_indices[@]}"; do
# Remove $ prefix for the template pattern
color_name="${colorlist[$i]#\$}"
# Convert to RGB
dehexed=$(dehex "${colorvalues[$i]}")
sed -i "s/{{ \$${color_name}-rgb }}/${dehexed}/g" "$XDG_CONFIG_HOME/wofi/style_new.css"
done
mv "$XDG_CONFIG_HOME/wofi/style_new.css" "$XDG_CONFIG_HOME/wofi/style.css"
}
# Check if terminal theming is enabled in config # Check if terminal theming is enabled in config
CONFIG_FILE="$XDG_CONFIG_HOME/illogical-impulse/config.json" CONFIG_FILE="$XDG_CONFIG_HOME/illogical-impulse/config.json"
if [ -f "$CONFIG_FILE" ]; then if [ -f "$CONFIG_FILE" ]; then
enable_terminal=$(jq -r '.appearance.wallpaperTheming.enableTerminal' "$CONFIG_FILE") enable_terminal=$(jq -r '.appearance.wallpaperTheming.enableTerminal' "$CONFIG_FILE")
if [ "$enable_terminal" = "true" ]; then if [ "$enable_terminal" = "true" ]; then
apply_term & apply_term
apply_foot
apply_fuzzel
apply_wofi
fi fi
else else
echo "Config file not found at $CONFIG_FILE. Applying terminal theming by default." echo "Config file not found at $CONFIG_FILE. Applying terminal theming by default."
apply_term & apply_term
apply_foot
apply_fuzzel
apply_wofi
fi fi
# apply_qt & # Qt theming is already handled by kde-material-colors # apply_qt & # Qt theming is already handled by kde-material-colors