Skip to content

Commit

Permalink
Implement improved settings with 100% api coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
Jacalz committed Mar 16, 2024
1 parent 72b3402 commit 28b9503
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 181 deletions.
28 changes: 28 additions & 0 deletions settings/all.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package settings

import (
"github.com/godbus/dbus/v5"
"github.com/rymdport/portal/internal/apis"
)

const readAllCallPath = settingsCallPath + ".ReadAll"

// ReadAll returns all values for the corresponding namespaces passed.
// If namespaces is an empty array or contains an empty string it matches all.
// Globbing is supported but only for trailing sections, e.g. “org.example.*”.
func ReadAll(namespaces []string) (map[string](map[string]dbus.Variant), error) {
conn, err := dbus.SessionBus() // Shared connection, don't close.
if err != nil {
return nil, err
}

obj := conn.Object(apis.ObjectName, apis.ObjectPath)
call := obj.Call(readAllCallPath, 0, namespaces)
if call.Err != nil {
return nil, call.Err
}

var value map[string](map[string]dbus.Variant)
err = call.Store(&value)
return value, err
}
4 changes: 4 additions & 0 deletions settings/appearance/appearance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Package appearance is a helper package for reading appearance settings.
package appearance

const appearanceNamespace = "org.freedesktop.appearance"
76 changes: 76 additions & 0 deletions settings/appearance/color.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package appearance

import (
"errors"
"image/color"

"github.com/rymdport/portal/settings"
)

// ErrNotSet indicates that the value is not set.
var ErrNotSet = errors.New("not set")

// ColorScheme indicates the system’s preferred color scheme.
type ColorScheme uint8

const (
NoPreference = ColorScheme(iota) // No preference.
Dark // Prefer dark appearance.
Light // Prefer light appearance.
)

// GetColorScheme returns the currently set color scheme.
func GetColorScheme() (ColorScheme, error) {
value, err := settings.ReadOne(appearanceNamespace, "color-scheme")
if err != nil {
return NoPreference, err
}

result := value.(uint32)
if result > 2 {
result = 0 // Unknown values should be treated as 0 (no preference).
}

return ColorScheme(result), nil
}

// GetAccentColor returns the currently set accent color.
// If not set, the ErrorNotSet will be returned.
func GetAccentColor() (*color.RGBA, error) {
value, err := settings.ReadOne(appearanceNamespace, "accent-color")
if err != nil {
return nil, ErrNotSet
}

result := value.([]float64)
if len(result) != 4 {
return nil, ErrNotSet
}

red := result[0] * 255
if red < 0 || red > 255 {
return nil, ErrNotSet
}

green := result[1] * 255
if green < 0 || green > 255 {
return nil, ErrNotSet
}

blue := result[2] * 255
if blue < 0 || blue > 255 {
return nil, ErrNotSet
}

alpha := result[3] * 255
if alpha < 0 || alpha > 255 {
return nil, ErrNotSet
}

return &color.RGBA{
R: uint8(red),
G: uint8(green),
B: uint8(blue),
A: uint8(alpha),
}, nil
}
26 changes: 26 additions & 0 deletions settings/appearance/contrast.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package appearance

import "github.com/rymdport/portal/settings"

// Contrast indicates the system’s preferred contrast level.
type Contrast uint8

const (
NormalContrast = Contrast(iota) // No preference (normal contrast)
HigherContrast // Higher contrast
)

// GetContrast returns the currently set contrast setting.
func GetContrast() (Contrast, error) {
value, err := settings.ReadOne(appearanceNamespace, "color-scheme")
if err != nil {
return NormalContrast, err
}

result := value.(uint32)
if result > 1 {
result = 0 // Unknown values should be treated as 0 (no preference).
}

return Contrast(result), nil
}
48 changes: 48 additions & 0 deletions settings/changed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package settings

import (
"github.com/godbus/dbus/v5"
"github.com/rymdport/portal"
"github.com/rymdport/portal/internal/apis"
)

// Changed is the result given when a setting changes its value.
type Changed struct {
Namespace string // Namespace of changed setting.
Key string // The key of changed setting.
Value any // The new value.
}

// OnSignalSettingChanged listens for the SettingChanged signal.
// This signal is emitted when a setting changes.
func OnSignalSettingChanged(callback func(changed Changed)) error {
conn, err := dbus.SessionBus()
if err != nil {
return err
}

if err := conn.AddMatchSignal(
dbus.WithMatchObjectPath(apis.ObjectPath),
dbus.WithMatchInterface(settingsCallPath),
dbus.WithMatchMember("SettingChanged"),
); err != nil {
return err
}

dbusChan := make(chan *dbus.Signal)
conn.Signal(dbusChan)

for sig := range dbusChan {
if len(sig.Body) != 3 {
return portal.ErrUnexpectedResponse
}

callback(Changed{
Namespace: sig.Body[0].(string),
Key: sig.Body[1].(string),
Value: sig.Body[2],
})
}

return nil
}
147 changes: 0 additions & 147 deletions settings/color.go

This file was deleted.

26 changes: 26 additions & 0 deletions settings/one.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package settings

import (
"github.com/godbus/dbus/v5"
"github.com/rymdport/portal/internal/apis"
)

const readOneCallPath = settingsCallPath + ".ReadOne"

// ReadOne reads a single value which may be any valid DBus type. Returns an error on any unknown namespace or key.
func ReadOne(namespace, key string) (any, error) {
conn, err := dbus.SessionBus() // Shared connection, don't close.
if err != nil {
return nil, err
}

obj := conn.Object(apis.ObjectName, apis.ObjectPath)
call := obj.Call(readOneCallPath, 0, namespace, key)
if call.Err != nil {
return nil, call.Err
}

var value any
err = call.Store(&value)
return value, err
}
4 changes: 4 additions & 0 deletions settings/settings.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// Package settings provides read-only access to a small number of host settings required for toolkits similar to XSettings. It is not for general purpose settings.
// Upstream API documentation can be found at https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Settings.html.
package settings

import "github.com/rymdport/portal/internal/apis"

const settingsCallPath = apis.CallBaseName + ".Settings"
Loading

0 comments on commit 28b9503

Please sign in to comment.