diff --git a/kittens/desktop_ui/main.go b/kittens/desktop_ui/main.go index 6bc7dad87..fee938f7a 100644 --- a/kittens/desktop_ui/main.go +++ b/kittens/desktop_ui/main.go @@ -3,6 +3,7 @@ package desktop_ui import ( "fmt" + "github.com/kovidgoyal/dbus" "github.com/kovidgoyal/kitty/tools/cli" "github.com/kovidgoyal/kitty/tools/utils" ) @@ -10,12 +11,15 @@ import ( var _ = fmt.Print type Options struct { - Color_scheme string + Color_scheme, AccentColor, Contrast string } func run_server(opts *Options) (err error) { - portal := NewPortal(opts) - if err = portal.Start(); err != nil { + portal, err := NewPortal(opts) + if err == nil { + err = portal.Start() + } + if err != nil { return } c := make(chan string) @@ -50,6 +54,17 @@ func EntryPoint(root *cli.Command) { Completer: cli.NamesCompleter("Choices for color-scheme", "no-preference", "light", "dark"), Help: "The color scheme for your system. This sets the initial value of the color scheme. It can be changed subsequently by using the color-scheme sub-command.", }) + rs.Add(cli.OptionSpec{ + Name: `--accent-color`, + Help: "The RGB accent color for your system, can be specified as a color name or in hex a decimal format.", + Default: "cyan", + }) + rs.Add(cli.OptionSpec{ + Name: `--contrast`, Type: "choices", Choices: "normal, high", + Help: "The preferred contrast level. Choices: normal, high", + Default: "normal", + }) + parent.AddSubCommand(&cli.Command{ Name: "enable-portal", ShortDescription: "This will create or edit the various files needed so that the portal from this kitten is used by xdg-desktop-portal", @@ -61,6 +76,7 @@ func EntryPoint(root *cli.Command) { parent.AddSubCommand(&cli.Command{ Name: "set-color-scheme", ShortDescription: "Change the color scheme", + ArgCompleter: cli.NamesCompleter("Choices for color-scheme", "no-preference", "light", "dark", "toggle"), Usage: " light|dark|no-preference|toggle", Run: func(cmd *cli.Command, args []string) (rc int, err error) { if len(args) != 1 { @@ -71,6 +87,45 @@ func EntryPoint(root *cli.Command) { return utils.IfElse(err == nil, 0, 1), err }, }) + parent.AddSubCommand(&cli.Command{ + Name: "set-accent-color", + ShortDescription: "Change the accent color", + Usage: " color_as_hex_or_name", + Run: func(cmd *cli.Command, args []string) (rc int, err error) { + if len(args) != 1 { + cmd.ShowHelp() + return 1, fmt.Errorf("must specify the new accent color value") + } + var v dbus.Variant + if v, err = to_color(args[0]); err == nil { + err = set_variant_setting(PORTAL_APPEARANCE_NAMESPACE, PORTAL_ACCENT_COLOR_KEY, v, false) + } + return utils.IfElse(err == nil, 0, 1), err + }, + }) + parent.AddSubCommand(&cli.Command{ + Name: "set-contrast", + ShortDescription: "Change the contrast. Can be high or normal.", + Usage: " high|normal", + Run: func(cmd *cli.Command, args []string) (rc int, err error) { + if len(args) != 1 { + cmd.ShowHelp() + return 1, fmt.Errorf("must specify the new contrast value") + } + + var v dbus.Variant + switch args[0] { + case "normal": + v = dbus.MakeVariant(uint32(0)) + case "high": + v = dbus.MakeVariant(uint32(1)) + default: + return 1, fmt.Errorf("%s is not a valid contrast value", args[0]) + } + err = set_variant_setting(PORTAL_APPEARANCE_NAMESPACE, PORTAL_CONTRAST_KEY, v, false) + return utils.IfElse(err == nil, 0, 1), err + }, + }) st := parent.AddSubCommand(&cli.Command{ Name: "set-setting", ShortDescription: "Change an arbitrary setting", diff --git a/kittens/desktop_ui/portal.go b/kittens/desktop_ui/portal.go index 54307b9b4..70804d098 100644 --- a/kittens/desktop_ui/portal.go +++ b/kittens/desktop_ui/portal.go @@ -13,6 +13,7 @@ import ( "github.com/kovidgoyal/dbus/introspect" "github.com/kovidgoyal/dbus/prop" "github.com/kovidgoyal/kitty/tools/utils" + "github.com/kovidgoyal/kitty/tools/utils/style" "golang.org/x/sys/unix" ) @@ -20,6 +21,8 @@ var _ = fmt.Print const PORTAL_APPEARANCE_NAMESPACE = "org.freedesktop.appearance" const PORTAL_COLOR_SCHEME_KEY = "color-scheme" +const PORTAL_ACCENT_COLOR_KEY = "accent-color" +const PORTAL_CONTRAST_KEY = "contrast" const PORTAL_BUS_NAME = "org.freedesktop.impl.portal.desktop.kitty" const SETTINGS_OBJECT_PATH = "/org/freedesktop/portal/desktop" const SETTINGS_INTERFACE = "org.freedesktop.impl.portal.Settings" @@ -47,7 +50,14 @@ type Portal struct { lock sync.Mutex } -func NewPortal(opts *Options) *Portal { +func to_color(spec string) (v dbus.Variant, err error) { + if col, err := style.ParseColor(spec); err == nil { + return dbus.MakeVariant([]float64{float64(col.Red) / 255., float64(col.Green) / 255., float64(col.Blue) / 255.}), nil + } + return +} + +func NewPortal(opts *Options) (p *Portal, err error) { ans := Portal{} ans.settings = SettingsMap{ SETTINGS_CANARY_NAMESPACE: map[string]dbus.Variant{ @@ -63,7 +73,13 @@ func NewPortal(opts *Options) *Portal { default: ans.settings[PORTAL_APPEARANCE_NAMESPACE][PORTAL_COLOR_SCHEME_KEY] = dbus.MakeVariant(uint32(NO_PREFERENCE)) } - return &ans + ans.settings[PORTAL_APPEARANCE_NAMESPACE][PORTAL_ACCENT_COLOR_KEY], err = to_color(opts.AccentColor) + var contrast uint32 + if opts.Contrast == "high" { + contrast = 1 + } + ans.settings[PORTAL_APPEARANCE_NAMESPACE][PORTAL_CONTRAST_KEY] = dbus.MakeVariant(contrast) + return &ans, nil } type PropSpec map[string]*prop.Prop @@ -422,21 +438,17 @@ type SetOptions struct { Namespace, DataType string } -func set_setting(key, value string, opts *SetOptions) (err error) { +func set_variant_setting(namespace, key string, v dbus.Variant, remove_setting bool) (err error) { conn, err := dbus.SessionBus() if err != nil { return fmt.Errorf("failed to connect to system bus with error: %w", err) } defer conn.Close() method := "ChangeSetting" - var vals = []any{opts.Namespace, key} - if value == "" { + var vals = []any{namespace, key} + if remove_setting { method = "RemoveSetting" } else { - v, err := ParseValueWithSignature(value, opts.DataType) - if err != nil { - return err - } vals = append(vals, v) } obj := conn.Object(PORTAL_BUS_NAME, dbus.ObjectPath(CHANGE_SETTINGS_OBJECT_PATH)) @@ -447,6 +459,19 @@ func set_setting(key, value string, opts *SetOptions) (err error) { return } +func set_setting(key, value string, opts *SetOptions) (err error) { + remove_setting := false + var v dbus.Variant + if value == "" { + remove_setting = true + } else { + if v, err = ParseValueWithSignature(value, opts.DataType); err != nil { + return err + } + } + return set_variant_setting(opts.Namespace, key, v, remove_setting) +} + func set_color_scheme(which string) (err error) { conn, err := dbus.SessionBus() if err != nil {