from std/osproc import execProcess, ProcessOption, startProcess, waitForExit, close from std/strutils import split, endsWith, contains from std/strformat import fmt import pkg/owlkettle type Theme = tuple[color, shade, style: string] const themeShades* = ["Light", "", "Dark"] themeStyles* = ["Default", "Nord", "Dracula", "Catppuccin", "Everforest", "Gruvbox"] accentColors* = ["Blue", "Red", "Purple", "Pink", "Teal", "Green", "Yellow", "Orange", "Grey"] appID* = "com.tromjaro.ThemeSwitcher" appLogo* = "tromjaro-theme-switcher" proc getCurrentTheme*(): Theme = let currentThemeString = execProcess("/usr/bin/xfconf-query", args=["--channel=xsettings", "--property=/Net/ThemeName"], options={})[0 .. ^2] # Split the theme string into words let words = currentThemeString.split('-') if words[0] != "Colloid": return var currentTheme: Theme = (color: "Blue", shade: "", style: "Default") case len(words): of 1: discard # Match against Colloid-Color, Colloid-Shade, Colloid-Style of 2: let word1 = words[1] if word1 in accentColors: currentTheme.color = word1 elif word1 in themeShades: currentTheme.shade = word1 elif word1 in themeStyles: currentTheme.style = word1 else: return # Match against Colloid-Color-Shade, Colloid-Shade-Style of 3: let word1 = words[1] word2 = words[2] if (word1 in accentColors) and (word2 in themeShades): currentTheme.color = word1 currentTheme.shade = word2 elif (word1 in themeShades) and (word2 in themeStyles): currentTheme.shade = word1 currentTheme.style = word2 else: return # Match against Colloid-Color-Shade-Style of 4: let word1 = words[1] word2 = words[2] word3 = words[3] if (word1 in accentColors) and (word2 in themeShades) and (word3 in themeStyles): currentTheme.color = word1 currentTheme.shade = word2 currentTheme.style = word3 else: return else: return return currentTheme proc runCommand(command: string, args: openArray[string]): bool = ## This will run a command with the given args and return true upon success let process = startProcess(command, args=args, options={poParentStreams}) result = process.waitForExit() == 0 process.close() proc setIconTheme(iconName: string) = # Change icon theme in XFCE discard runCommand("/usr/bin/xfconf-query", args=["--channel=xsettings", "--property=/Net/IconThemeName", "--create", "--type=string", "--set", iconName]) proc enableDarkPanels(): bool = # Return if dark panels is already enabled if execProcess("/usr/bin/xfconf-query", args=["--channel=xfce4-panel", "--property=/panels/dark-mode"], options={}) == "true\n": return # Try to enable it and return true upon success result = runCommand("/usr/bin/xfconf-query", args=["--channel=xfce4-panel", "--property=/panels/dark-mode", "--create", "--type=bool", "--set=true"]) proc setTheme*(themeName: string) = var panelNotification: string # Set the icon theme and panel color according to the chosen theme if themeName.endsWith("-Dark") or themeName.contains("-Dark-"): setIconTheme("zafiro-dark") else: setIconTheme("zafiro") if enableDarkPanels(): panelNotification = " with dark panels" # Change the main theme to the chosen one discard runCommand("/usr/bin/xfconf-query", args=["--channel=xsettings", "--property=/Net/ThemeName", "--create", "--type=string", "--set", themeName]) # Send notification about the theme change sendNotification(appID, "Theme Switcher", fmt"{themeName} theme{panelNotification} is enabled", icon=appLogo)