mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 13:32:50 -05:00
632 lines
16 KiB
Go
632 lines
16 KiB
Go
package matugen
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"syscall"
|
|
|
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/dank16"
|
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/utils"
|
|
)
|
|
|
|
var (
|
|
matugenVersionOnce sync.Once
|
|
matugenSupportsCOE bool
|
|
)
|
|
|
|
type Options struct {
|
|
StateDir string
|
|
ShellDir string
|
|
ConfigDir string
|
|
Kind string
|
|
Value string
|
|
Mode string
|
|
IconTheme string
|
|
MatugenType string
|
|
RunUserTemplates bool
|
|
StockColors string
|
|
SyncModeWithPortal bool
|
|
TerminalsAlwaysDark bool
|
|
SkipTemplates string
|
|
}
|
|
|
|
type ColorsOutput struct {
|
|
Colors struct {
|
|
Dark map[string]string `json:"dark"`
|
|
Light map[string]string `json:"light"`
|
|
} `json:"colors"`
|
|
}
|
|
|
|
func (o *Options) ColorsOutput() string {
|
|
return filepath.Join(o.StateDir, "dms-colors.json")
|
|
}
|
|
|
|
func (o *Options) ShouldSkipTemplate(name string) bool {
|
|
if o.SkipTemplates == "" {
|
|
return false
|
|
}
|
|
for _, skip := range strings.Split(o.SkipTemplates, ",") {
|
|
if strings.TrimSpace(skip) == name {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func Run(opts Options) error {
|
|
if opts.StateDir == "" {
|
|
return fmt.Errorf("state-dir is required")
|
|
}
|
|
if opts.ShellDir == "" {
|
|
return fmt.Errorf("shell-dir is required")
|
|
}
|
|
if opts.ConfigDir == "" {
|
|
return fmt.Errorf("config-dir is required")
|
|
}
|
|
if opts.Kind == "" {
|
|
return fmt.Errorf("kind is required")
|
|
}
|
|
if opts.Value == "" {
|
|
return fmt.Errorf("value is required")
|
|
}
|
|
if opts.Mode == "" {
|
|
opts.Mode = "dark"
|
|
}
|
|
if opts.MatugenType == "" {
|
|
opts.MatugenType = "scheme-tonal-spot"
|
|
}
|
|
if opts.IconTheme == "" {
|
|
opts.IconTheme = "System Default"
|
|
}
|
|
|
|
if err := os.MkdirAll(opts.StateDir, 0755); err != nil {
|
|
return fmt.Errorf("failed to create state dir: %w", err)
|
|
}
|
|
|
|
log.Infof("Building theme: %s %s (%s)", opts.Kind, opts.Value, opts.Mode)
|
|
|
|
if err := buildOnce(&opts); err != nil {
|
|
return err
|
|
}
|
|
|
|
if opts.SyncModeWithPortal {
|
|
syncColorScheme(opts.Mode)
|
|
}
|
|
|
|
log.Info("Done")
|
|
return nil
|
|
}
|
|
|
|
func buildOnce(opts *Options) error {
|
|
cfgFile, err := os.CreateTemp("", "matugen-config-*.toml")
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create temp config: %w", err)
|
|
}
|
|
defer os.Remove(cfgFile.Name())
|
|
defer cfgFile.Close()
|
|
|
|
tmpDir, err := os.MkdirTemp("", "matugen-templates-*")
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create temp dir: %w", err)
|
|
}
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
if err := buildMergedConfig(opts, cfgFile, tmpDir); err != nil {
|
|
return fmt.Errorf("failed to build config: %w", err)
|
|
}
|
|
cfgFile.Close()
|
|
|
|
var primaryDark, primaryLight, surface string
|
|
var dank16JSON string
|
|
var importArgs []string
|
|
|
|
if opts.StockColors != "" {
|
|
log.Info("Using stock/custom theme colors with matugen base")
|
|
primaryDark = extractNestedColor(opts.StockColors, "primary", "dark")
|
|
primaryLight = extractNestedColor(opts.StockColors, "primary", "light")
|
|
surface = extractNestedColor(opts.StockColors, "surface", "dark")
|
|
|
|
if primaryDark == "" {
|
|
return fmt.Errorf("failed to extract primary dark from stock colors")
|
|
}
|
|
if primaryLight == "" {
|
|
primaryLight = primaryDark
|
|
}
|
|
|
|
dank16JSON = generateDank16Variants(primaryDark, primaryLight, surface, opts.Mode)
|
|
importData := fmt.Sprintf(`{"colors": %s, "dank16": %s}`, opts.StockColors, dank16JSON)
|
|
importArgs = []string{"--import-json-string", importData}
|
|
|
|
log.Info("Running matugen color hex with stock color overrides")
|
|
args := []string{"color", "hex", primaryDark, "-m", opts.Mode, "-t", opts.MatugenType, "-c", cfgFile.Name()}
|
|
args = append(args, importArgs...)
|
|
if err := runMatugen(args); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
log.Infof("Using dynamic theme from %s: %s", opts.Kind, opts.Value)
|
|
|
|
matJSON, err := runMatugenDryRun(opts)
|
|
if err != nil {
|
|
return fmt.Errorf("matugen dry-run failed: %w", err)
|
|
}
|
|
|
|
primaryDark = extractMatugenColor(matJSON, "primary", "dark")
|
|
primaryLight = extractMatugenColor(matJSON, "primary", "light")
|
|
surface = extractMatugenColor(matJSON, "surface", "dark")
|
|
|
|
if primaryDark == "" {
|
|
return fmt.Errorf("failed to extract primary color")
|
|
}
|
|
if primaryLight == "" {
|
|
primaryLight = primaryDark
|
|
}
|
|
|
|
dank16JSON = generateDank16Variants(primaryDark, primaryLight, surface, opts.Mode)
|
|
importData := fmt.Sprintf(`{"dank16": %s}`, dank16JSON)
|
|
importArgs = []string{"--import-json-string", importData}
|
|
|
|
log.Infof("Running matugen %s with dank16 injection", opts.Kind)
|
|
var args []string
|
|
switch opts.Kind {
|
|
case "hex":
|
|
args = []string{"color", "hex", opts.Value}
|
|
default:
|
|
args = []string{opts.Kind, opts.Value}
|
|
}
|
|
args = append(args, "-m", opts.Mode, "-t", opts.MatugenType, "-c", cfgFile.Name())
|
|
args = append(args, importArgs...)
|
|
if err := runMatugen(args); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
refreshGTK(opts.ConfigDir, opts.Mode)
|
|
signalTerminals()
|
|
|
|
return nil
|
|
}
|
|
|
|
func buildMergedConfig(opts *Options, cfgFile *os.File, tmpDir string) error {
|
|
userConfigPath := filepath.Join(opts.ConfigDir, "matugen", "config.toml")
|
|
|
|
wroteConfig := false
|
|
if opts.RunUserTemplates {
|
|
if data, err := os.ReadFile(userConfigPath); err == nil {
|
|
configSection := extractTOMLSection(string(data), "[config]", "[templates]")
|
|
if configSection != "" {
|
|
cfgFile.WriteString(configSection)
|
|
cfgFile.WriteString("\n")
|
|
wroteConfig = true
|
|
}
|
|
}
|
|
}
|
|
if !wroteConfig {
|
|
cfgFile.WriteString("[config]\n\n")
|
|
}
|
|
|
|
baseConfigPath := filepath.Join(opts.ShellDir, "matugen", "configs", "base.toml")
|
|
if data, err := os.ReadFile(baseConfigPath); err == nil {
|
|
content := string(data)
|
|
lines := strings.Split(content, "\n")
|
|
for _, line := range lines {
|
|
if strings.TrimSpace(line) == "[config]" {
|
|
continue
|
|
}
|
|
cfgFile.WriteString(substituteShellDir(line, opts.ShellDir) + "\n")
|
|
}
|
|
cfgFile.WriteString("\n")
|
|
}
|
|
|
|
fmt.Fprintf(cfgFile, `[templates.dank]
|
|
input_path = '%s/matugen/templates/dank.json'
|
|
output_path = '%s'
|
|
|
|
`, opts.ShellDir, opts.ColorsOutput())
|
|
|
|
if !opts.ShouldSkipTemplate("gtk") {
|
|
switch opts.Mode {
|
|
case "light":
|
|
appendConfig(opts, cfgFile, "skip", "gtk3-light.toml")
|
|
default:
|
|
appendConfig(opts, cfgFile, "skip", "gtk3-dark.toml")
|
|
}
|
|
}
|
|
|
|
if !opts.ShouldSkipTemplate("niri") {
|
|
appendConfig(opts, cfgFile, "niri", "niri.toml")
|
|
}
|
|
if !opts.ShouldSkipTemplate("qt5ct") {
|
|
appendConfig(opts, cfgFile, "qt5ct", "qt5ct.toml")
|
|
}
|
|
if !opts.ShouldSkipTemplate("qt6ct") {
|
|
appendConfig(opts, cfgFile, "qt6ct", "qt6ct.toml")
|
|
}
|
|
if !opts.ShouldSkipTemplate("firefox") {
|
|
appendConfig(opts, cfgFile, "firefox", "firefox.toml")
|
|
}
|
|
if !opts.ShouldSkipTemplate("pywalfox") {
|
|
appendConfig(opts, cfgFile, "pywalfox", "pywalfox.toml")
|
|
}
|
|
if !opts.ShouldSkipTemplate("vesktop") {
|
|
appendConfig(opts, cfgFile, "vesktop", "vesktop.toml")
|
|
}
|
|
|
|
if !opts.ShouldSkipTemplate("ghostty") {
|
|
appendTerminalConfig(opts, cfgFile, tmpDir, "ghostty", "ghostty.toml")
|
|
}
|
|
if !opts.ShouldSkipTemplate("kitty") {
|
|
appendTerminalConfig(opts, cfgFile, tmpDir, "kitty", "kitty.toml")
|
|
}
|
|
if !opts.ShouldSkipTemplate("foot") {
|
|
appendTerminalConfig(opts, cfgFile, tmpDir, "foot", "foot.toml")
|
|
}
|
|
if !opts.ShouldSkipTemplate("alacritty") {
|
|
appendTerminalConfig(opts, cfgFile, tmpDir, "alacritty", "alacritty.toml")
|
|
}
|
|
if !opts.ShouldSkipTemplate("wezterm") {
|
|
appendTerminalConfig(opts, cfgFile, tmpDir, "wezterm", "wezterm.toml")
|
|
}
|
|
if !opts.ShouldSkipTemplate("nvim") {
|
|
appendTerminalConfig(opts, cfgFile, tmpDir, "nvim", "neovim.toml")
|
|
}
|
|
|
|
if !opts.ShouldSkipTemplate("dgop") {
|
|
appendConfig(opts, cfgFile, "dgop", "dgop.toml")
|
|
}
|
|
|
|
if !opts.ShouldSkipTemplate("kcolorscheme") {
|
|
appendConfig(opts, cfgFile, "skip", "kcolorscheme.toml")
|
|
}
|
|
|
|
if !opts.ShouldSkipTemplate("vscode") {
|
|
homeDir, _ := os.UserHomeDir()
|
|
appendVSCodeConfig(cfgFile, "vscode", filepath.Join(homeDir, ".vscode/extensions/local.dynamic-base16-dankshell-0.0.1"), opts.ShellDir)
|
|
appendVSCodeConfig(cfgFile, "codium", filepath.Join(homeDir, ".vscode-oss/extensions/local.dynamic-base16-dankshell-0.0.1"), opts.ShellDir)
|
|
appendVSCodeConfig(cfgFile, "codeoss", filepath.Join(homeDir, ".config/Code - OSS/extensions/local.dynamic-base16-dankshell-0.0.1"), opts.ShellDir)
|
|
appendVSCodeConfig(cfgFile, "cursor", filepath.Join(homeDir, ".cursor/extensions/local.dynamic-base16-dankshell-0.0.1"), opts.ShellDir)
|
|
appendVSCodeConfig(cfgFile, "windsurf", filepath.Join(homeDir, ".windsurf/extensions/local.dynamic-base16-dankshell-0.0.1"), opts.ShellDir)
|
|
}
|
|
|
|
if opts.RunUserTemplates {
|
|
if data, err := os.ReadFile(userConfigPath); err == nil {
|
|
templatesSection := extractTOMLSection(string(data), "[templates]", "")
|
|
if templatesSection != "" {
|
|
cfgFile.WriteString(templatesSection)
|
|
cfgFile.WriteString("\n")
|
|
}
|
|
}
|
|
}
|
|
|
|
userPluginConfigDir := filepath.Join(opts.ConfigDir, "matugen", "dms", "configs")
|
|
if entries, err := os.ReadDir(userPluginConfigDir); err == nil {
|
|
for _, entry := range entries {
|
|
if !strings.HasSuffix(entry.Name(), ".toml") {
|
|
continue
|
|
}
|
|
if data, err := os.ReadFile(filepath.Join(userPluginConfigDir, entry.Name())); err == nil {
|
|
cfgFile.WriteString(string(data))
|
|
cfgFile.WriteString("\n")
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func appendConfig(opts *Options, cfgFile *os.File, checkCmd, fileName string) {
|
|
configPath := filepath.Join(opts.ShellDir, "matugen", "configs", fileName)
|
|
if _, err := os.Stat(configPath); err != nil {
|
|
return
|
|
}
|
|
if checkCmd != "skip" && !utils.CommandExists(checkCmd) {
|
|
return
|
|
}
|
|
data, err := os.ReadFile(configPath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
cfgFile.WriteString(substituteShellDir(string(data), opts.ShellDir))
|
|
cfgFile.WriteString("\n")
|
|
}
|
|
|
|
func appendTerminalConfig(opts *Options, cfgFile *os.File, tmpDir, checkCmd, fileName string) {
|
|
configPath := filepath.Join(opts.ShellDir, "matugen", "configs", fileName)
|
|
if _, err := os.Stat(configPath); err != nil {
|
|
return
|
|
}
|
|
if checkCmd != "skip" && !utils.CommandExists(checkCmd) {
|
|
return
|
|
}
|
|
data, err := os.ReadFile(configPath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
content := string(data)
|
|
|
|
if !opts.TerminalsAlwaysDark {
|
|
cfgFile.WriteString(substituteShellDir(content, opts.ShellDir))
|
|
cfgFile.WriteString("\n")
|
|
return
|
|
}
|
|
|
|
lines := strings.Split(content, "\n")
|
|
for _, line := range lines {
|
|
if !strings.Contains(line, "input_path") || !strings.Contains(line, "SHELL_DIR/matugen/templates/") {
|
|
continue
|
|
}
|
|
|
|
start := strings.Index(line, "'SHELL_DIR/matugen/templates/")
|
|
if start == -1 {
|
|
continue
|
|
}
|
|
end := strings.Index(line[start+1:], "'")
|
|
if end == -1 {
|
|
continue
|
|
}
|
|
templateName := line[start+len("'SHELL_DIR/matugen/templates/") : start+1+end]
|
|
origPath := filepath.Join(opts.ShellDir, "matugen", "templates", templateName)
|
|
|
|
origData, err := os.ReadFile(origPath)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
modified := strings.ReplaceAll(string(origData), ".default.", ".dark.")
|
|
tmpPath := filepath.Join(tmpDir, templateName)
|
|
if err := os.WriteFile(tmpPath, []byte(modified), 0644); err != nil {
|
|
continue
|
|
}
|
|
|
|
content = strings.ReplaceAll(content,
|
|
fmt.Sprintf("'SHELL_DIR/matugen/templates/%s'", templateName),
|
|
fmt.Sprintf("'%s'", tmpPath))
|
|
}
|
|
|
|
cfgFile.WriteString(substituteShellDir(content, opts.ShellDir))
|
|
cfgFile.WriteString("\n")
|
|
}
|
|
|
|
func appendVSCodeConfig(cfgFile *os.File, name, extDir, shellDir string) {
|
|
if _, err := os.Stat(extDir); err != nil {
|
|
return
|
|
}
|
|
templateDir := filepath.Join(shellDir, "matugen", "templates")
|
|
fmt.Fprintf(cfgFile, `[templates.dms%sdefault]
|
|
input_path = '%s/vscode-color-theme-default.json'
|
|
output_path = '%s/themes/dankshell-default.json'
|
|
|
|
[templates.dms%sdark]
|
|
input_path = '%s/vscode-color-theme-dark.json'
|
|
output_path = '%s/themes/dankshell-dark.json'
|
|
|
|
[templates.dms%slight]
|
|
input_path = '%s/vscode-color-theme-light.json'
|
|
output_path = '%s/themes/dankshell-light.json'
|
|
|
|
`, name, templateDir, extDir,
|
|
name, templateDir, extDir,
|
|
name, templateDir, extDir)
|
|
log.Infof("Added %s theme config (extension found at %s)", name, extDir)
|
|
}
|
|
|
|
func substituteShellDir(content, shellDir string) string {
|
|
return strings.ReplaceAll(content, "'SHELL_DIR/", "'"+shellDir+"/")
|
|
}
|
|
|
|
func extractTOMLSection(content, startMarker, endMarker string) string {
|
|
startIdx := strings.Index(content, startMarker)
|
|
if startIdx == -1 {
|
|
return ""
|
|
}
|
|
|
|
if endMarker == "" {
|
|
return content[startIdx:]
|
|
}
|
|
|
|
endIdx := strings.Index(content[startIdx:], endMarker)
|
|
if endIdx == -1 {
|
|
return content[startIdx:]
|
|
}
|
|
return content[startIdx : startIdx+endIdx]
|
|
}
|
|
|
|
func checkMatugenVersion() {
|
|
matugenVersionOnce.Do(func() {
|
|
cmd := exec.Command("matugen", "--version")
|
|
output, err := cmd.Output()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
versionStr := strings.TrimSpace(string(output))
|
|
versionStr = strings.TrimPrefix(versionStr, "matugen ")
|
|
|
|
parts := strings.Split(versionStr, ".")
|
|
if len(parts) < 2 {
|
|
return
|
|
}
|
|
|
|
major, err := strconv.Atoi(parts[0])
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
minor, err := strconv.Atoi(parts[1])
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
matugenSupportsCOE = major > 3 || (major == 3 && minor >= 1)
|
|
if matugenSupportsCOE {
|
|
log.Infof("Matugen %s supports --continue-on-error", versionStr)
|
|
}
|
|
})
|
|
}
|
|
|
|
func runMatugen(args []string) error {
|
|
checkMatugenVersion()
|
|
|
|
if matugenSupportsCOE {
|
|
args = append([]string{"--continue-on-error"}, args...)
|
|
}
|
|
|
|
cmd := exec.Command("matugen", args...)
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
return cmd.Run()
|
|
}
|
|
|
|
func runMatugenDryRun(opts *Options) (string, error) {
|
|
var args []string
|
|
switch opts.Kind {
|
|
case "hex":
|
|
args = []string{"color", "hex", opts.Value}
|
|
default:
|
|
args = []string{opts.Kind, opts.Value}
|
|
}
|
|
args = append(args, "-m", "dark", "-t", opts.MatugenType, "--json", "hex", "--dry-run")
|
|
|
|
cmd := exec.Command("matugen", args...)
|
|
output, err := cmd.Output()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return strings.ReplaceAll(string(output), "\n", ""), nil
|
|
}
|
|
|
|
func extractMatugenColor(jsonStr, colorName, variant string) string {
|
|
var data map[string]any
|
|
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
|
|
return ""
|
|
}
|
|
|
|
colors, ok := data["colors"].(map[string]any)
|
|
if !ok {
|
|
return ""
|
|
}
|
|
|
|
colorData, ok := colors[colorName].(map[string]any)
|
|
if !ok {
|
|
return ""
|
|
}
|
|
|
|
variantData, ok := colorData[variant].(string)
|
|
if !ok {
|
|
return ""
|
|
}
|
|
|
|
return variantData
|
|
}
|
|
|
|
func extractNestedColor(jsonStr, colorName, variant string) string {
|
|
var data map[string]any
|
|
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
|
|
return ""
|
|
}
|
|
|
|
colorData, ok := data[colorName].(map[string]any)
|
|
if !ok {
|
|
return ""
|
|
}
|
|
|
|
variantData, ok := colorData[variant].(map[string]any)
|
|
if !ok {
|
|
return ""
|
|
}
|
|
|
|
color, ok := variantData["color"].(string)
|
|
if !ok {
|
|
return ""
|
|
}
|
|
|
|
return color
|
|
}
|
|
|
|
func generateDank16Variants(primaryDark, primaryLight, surface, mode string) string {
|
|
variantOpts := dank16.VariantOptions{
|
|
PrimaryDark: primaryDark,
|
|
PrimaryLight: primaryLight,
|
|
Background: surface,
|
|
UseDPS: true,
|
|
IsLightMode: mode == "light",
|
|
}
|
|
variantColors := dank16.GenerateVariantPalette(variantOpts)
|
|
return dank16.GenerateVariantJSON(variantColors)
|
|
}
|
|
|
|
func refreshGTK(configDir, mode string) {
|
|
gtkCSS := filepath.Join(configDir, "gtk-3.0", "gtk.css")
|
|
|
|
info, err := os.Lstat(gtkCSS)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
shouldRun := false
|
|
if info.Mode()&os.ModeSymlink != 0 {
|
|
target, err := os.Readlink(gtkCSS)
|
|
if err == nil && strings.Contains(target, "dank-colors.css") {
|
|
shouldRun = true
|
|
}
|
|
} else {
|
|
data, err := os.ReadFile(gtkCSS)
|
|
if err == nil && strings.Contains(string(data), "dank-colors.css") {
|
|
shouldRun = true
|
|
}
|
|
}
|
|
|
|
if !shouldRun {
|
|
return
|
|
}
|
|
|
|
exec.Command("gsettings", "set", "org.gnome.desktop.interface", "gtk-theme", "").Run()
|
|
exec.Command("gsettings", "set", "org.gnome.desktop.interface", "gtk-theme", "adw-gtk3-"+mode).Run()
|
|
}
|
|
|
|
func signalTerminals() {
|
|
signalByName("kitty", syscall.SIGUSR1)
|
|
signalByName("ghostty", syscall.SIGUSR2)
|
|
signalByName(".kitty-wrapped", syscall.SIGUSR1)
|
|
signalByName(".ghostty-wrappe", syscall.SIGUSR2)
|
|
}
|
|
|
|
func signalByName(name string, sig syscall.Signal) {
|
|
entries, err := os.ReadDir("/proc")
|
|
if err != nil {
|
|
return
|
|
}
|
|
for _, entry := range entries {
|
|
pid, err := strconv.Atoi(entry.Name())
|
|
if err != nil {
|
|
continue
|
|
}
|
|
comm, err := os.ReadFile(filepath.Join("/proc", entry.Name(), "comm"))
|
|
if err != nil {
|
|
continue
|
|
}
|
|
if strings.TrimSpace(string(comm)) == name {
|
|
syscall.Kill(pid, sig)
|
|
}
|
|
}
|
|
}
|
|
|
|
func syncColorScheme(mode string) {
|
|
scheme := "prefer-dark"
|
|
if mode == "light" {
|
|
scheme = "default"
|
|
}
|
|
|
|
if err := exec.Command("gsettings", "set", "org.gnome.desktop.interface", "color-scheme", scheme).Run(); err != nil {
|
|
exec.Command("dconf", "write", "/org/gnome/desktop/interface/color-scheme", "'"+scheme+"'").Run()
|
|
}
|
|
}
|