Icons and styles use xyz.holanet.Nasin config

This commit is contained in:
Sasha Koshka 2024-08-23 01:10:54 -04:00
parent a69c726482
commit f512deb96e
4 changed files with 106 additions and 37 deletions

View File

@ -144,15 +144,43 @@ func RunApplication (application Application) {
} }
flag.Parse() flag.Parse()
// open config
globalConfig, err := ApplicationConfig(GlobalApplicationDescription())
if err != nil { log.Fatalln("nasin: could not open config:", err) }
defer globalConfig.Close()
styleConfigKey := "Style"
iconSetConfigKey := "IconSet"
// registry
// TODO: rebuild registry around the config
reg := new(registrar.Registrar) reg := new(registrar.Registrar)
backend, err := reg.SetBackend() backend, err := reg.SetBackend()
if err != nil { log.Fatalln("nasin: could not register backend:", err) } if err != nil { log.Fatalln("nasin: could not register backend:", err) }
err = reg.SetTheme()
if err != nil { log.Fatalln("nasin: could not set theme:", err) }
err = reg.SetIconSet()
if err != nil { log.Fatalln("nasin: could not set icon set:", err) }
err = reg.SetFaceSet() err = reg.SetFaceSet()
if err != nil { log.Fatalln("nasin: could not set face set:", err) } if err != nil { log.Fatalln("nasin: could not set face set:", err) }
updateStyle := func () {
value, err := globalConfig.GetString(styleConfigKey, "")
if err != nil { log.Fatalln("nasin: could not set theme:", err) }
err = reg.SetStyle(value)
if err != nil { log.Fatalln("nasin: could not set theme:", err) }
}
updateIconSet := func () {
value, err := globalConfig.GetString(iconSetConfigKey, "")
if err != nil { log.Fatalln("nasin: could not set icon set:", err) }
err = reg.SetIconSet(value)
if err != nil { log.Fatalln("nasin: could not set icon set:", err) }
}
updateStyle()
updateIconSet()
globalConfig.OnChange(func (key string) {
switch key {
case styleConfigKey: updateStyle()
case iconSetConfigKey: updateIconSet()
}
})
// init application
err = application.Init() err = application.Init()
if err != nil { log.Fatalln("nasin: could not run application:", err) } if err != nil { log.Fatalln("nasin: could not run application:", err) }

View File

@ -6,9 +6,10 @@ import _ "embed"
import _ "image/png" import _ "image/png"
import "git.tebibyte.media/tomo/tomo" import "git.tebibyte.media/tomo/tomo"
import "git.tebibyte.media/tomo/tomo/data" import "git.tebibyte.media/tomo/tomo/data"
import "git.tebibyte.media/tomo/nasin/internal/util" import "git.tebibyte.media/tomo/tomo/event"
import "git.tebibyte.media/tomo/tomo/canvas" import "git.tebibyte.media/tomo/tomo/canvas"
import "git.tebibyte.media/tomo/backend/style" import "git.tebibyte.media/tomo/backend/style"
import "git.tebibyte.media/tomo/nasin/internal/util"
//go:embed assets/icons-small.png //go:embed assets/icons-small.png
var atlasSmallBytes []byte var atlasSmallBytes []byte
@ -35,7 +36,7 @@ const (
iconXOfficeSpreadsheet = tomo.Icon("x-office-spreadsheet") iconXOfficeSpreadsheet = tomo.Icon("x-office-spreadsheet")
) )
func generateSource (data []byte, width int) map[tomo.Icon] canvas.Texture { func generateSource (data []byte, width int) (canvas.TextureCloser, map[tomo.Icon] canvas.Texture) {
atlasImage, _, err := image.Decode(bytes.NewReader(data)) atlasImage, _, err := image.Decode(bytes.NewReader(data))
if err != nil { panic(err) } if err != nil { panic(err) }
atlasTexture := tomo.NewTexture(atlasImage) atlasTexture := tomo.NewTexture(atlasImage)
@ -448,23 +449,26 @@ func generateSource (data []byte, width int) map[tomo.Icon] canvas.Texture {
col(tomo.IconWeatherSnow) col(tomo.IconWeatherSnow)
col(tomo.IconWeatherStorm) col(tomo.IconWeatherStorm)
return source return atlasTexture, source
} }
type iconSet struct { type iconSet struct {
atlasSmall canvas.TextureCloser
atlasLarge canvas.TextureCloser
texturesSmall map[tomo.Icon] canvas.Texture texturesSmall map[tomo.Icon] canvas.Texture
texturesLarge map[tomo.Icon] canvas.Texture texturesLarge map[tomo.Icon] canvas.Texture
} }
// New creates a new fallback icon set. // New creates a new fallback icon set.
func New () style.IconSet { func New () (style.IconSet, event.Cookie) {
return new(iconSet) iconSet := new(iconSet)
return iconSet, iconSet
} }
func (this *iconSet) ensure () { func (this *iconSet) ensure () {
if this.texturesSmall != nil { return } if this.texturesSmall != nil { return }
this.texturesSmall = generateSource(atlasSmallBytes, 16) this.atlasSmall, this.texturesSmall = generateSource(atlasSmallBytes, 16)
this.texturesLarge = generateSource(atlasLargeBytes, 32) this.atlasLarge, this.texturesLarge = generateSource(atlasLargeBytes, 32)
} }
func (this *iconSet) selectSource (size tomo.IconSize) map[tomo.Icon] canvas.Texture { func (this *iconSet) selectSource (size tomo.IconSize) map[tomo.Icon] canvas.Texture {
@ -500,3 +504,12 @@ func (this *iconSet) MimeIcon (mime data.Mime, size tomo.IconSize) canvas.Textur
return source[tomo.Icon(iconApplicationXGeneric)] return source[tomo.Icon(iconApplicationXGeneric)]
} }
} }
func (this *iconSet) Close () {
if this.atlasSmall != nil {
this.atlasSmall.Close()
}
if this.atlasLarge != nil {
this.atlasLarge.Close()
}
}

View File

@ -9,6 +9,7 @@ import "strings"
import _ "image/png" import _ "image/png"
import "git.tebibyte.media/tomo/tomo" import "git.tebibyte.media/tomo/tomo"
import "git.tebibyte.media/tomo/tomo/data" import "git.tebibyte.media/tomo/tomo/data"
import "git.tebibyte.media/tomo/tomo/event"
import "git.tebibyte.media/tomo/tomo/canvas" import "git.tebibyte.media/tomo/tomo/canvas"
import "git.tebibyte.media/tomo/backend/style" import "git.tebibyte.media/tomo/backend/style"
import "git.tebibyte.media/tomo/nasin/internal/util" import "git.tebibyte.media/tomo/nasin/internal/util"
@ -17,27 +18,27 @@ import xdgIconTheme "git.tebibyte.media/tomo/xdg/icon-theme"
type iconTheme struct { type iconTheme struct {
xdg xdgIconTheme.Theme xdg xdgIconTheme.Theme
fallback style.IconSet fallback style.IconSet
texturesSmall map[tomo.Icon] canvas.Texture texturesSmall map[tomo.Icon] canvas.TextureCloser
texturesMedium map[tomo.Icon] canvas.Texture texturesMedium map[tomo.Icon] canvas.TextureCloser
texturesLarge map[tomo.Icon] canvas.Texture texturesLarge map[tomo.Icon] canvas.TextureCloser
} }
func FindThemeWarn (name string, fallback style.IconSet, path ...string) (style.IconSet, error) { func FindThemeWarn (name string, fallback style.IconSet, path ...string) (style.IconSet, event.Cookie, error) {
this := &iconTheme { this := &iconTheme {
fallback: fallback, fallback: fallback,
texturesLarge: make(map[tomo.Icon] canvas.Texture), texturesLarge: make(map[tomo.Icon] canvas.TextureCloser),
texturesMedium: make(map[tomo.Icon] canvas.Texture), texturesMedium: make(map[tomo.Icon] canvas.TextureCloser),
texturesSmall: make(map[tomo.Icon] canvas.Texture), texturesSmall: make(map[tomo.Icon] canvas.TextureCloser),
} }
xdg, err := xdgIconTheme.FindThemeWarn(name, path...) xdg, err := xdgIconTheme.FindThemeWarn(name, path...)
if err != nil { return nil, err } if err != nil { return nil, nil, err }
this.xdg = xdg this.xdg = xdg
return this, nil return this, this, nil
} }
func (this *iconTheme) selectSource (size tomo.IconSize) map[tomo.Icon] canvas.Texture { func (this *iconTheme) selectSource (size tomo.IconSize) map[tomo.Icon] canvas.TextureCloser {
switch size { switch size {
case tomo.IconSizeMedium: return this.texturesMedium case tomo.IconSizeMedium: return this.texturesMedium
case tomo.IconSizeLarge: return this.texturesLarge case tomo.IconSizeLarge: return this.texturesLarge
@ -45,7 +46,7 @@ func (this *iconTheme) selectSource (size tomo.IconSize) map[tomo.Icon] canvas.T
} }
} }
func (this *iconTheme) xdgIcon (name string, size tomo.IconSize) (canvas.Texture, bool) { func (this *iconTheme) xdgIcon (name string, size tomo.IconSize) (canvas.TextureCloser, bool) {
// TODO use scaling factor instead of 1 // TODO use scaling factor instead of 1
// find icon file // find icon file
icon, err := this.xdg.FindIcon(name, iconSizePixels(size), 1, xdgIconTheme.PNG) icon, err := this.xdg.FindIcon(name, iconSizePixels(size), 1, xdgIconTheme.PNG)
@ -100,7 +101,20 @@ func (this *iconTheme) MimeIcon (mime data.Mime, size tomo.IconSize) canvas.Text
} }
} }
func (this *iconTheme) icon (icon tomo.Icon, size tomo.IconSize) canvas.Texture { func (this *iconTheme) Close () {
closeAllIn := func (mp map[tomo.Icon] canvas.TextureCloser) {
for _, texture := range mp {
if texture != nil {
texture.Close()
}
}
}
closeAllIn(this.texturesSmall)
closeAllIn(this.texturesMedium)
closeAllIn(this.texturesLarge)
}
func (this *iconTheme) icon (icon tomo.Icon, size tomo.IconSize) canvas.TextureCloser {
if texture, ok := this.xdgIcon(XdgIconName(icon), size); ok { if texture, ok := this.xdgIcon(XdgIconName(icon), size); ok {
return texture return texture
} }
@ -110,7 +124,7 @@ func (this *iconTheme) icon (icon tomo.Icon, size tomo.IconSize) canvas.Texture
return nil return nil
} }
func (this *iconTheme) mimeIcon (mime data.Mime, size tomo.IconSize) canvas.Texture { func (this *iconTheme) mimeIcon (mime data.Mime, size tomo.IconSize) canvas.TextureCloser {
if texture, ok := this.xdgIcon(xdgFormatMime(mime), size); ok { if texture, ok := this.xdgIcon(xdgFormatMime(mime), size); ok {
return texture return texture
} }

View File

@ -1,10 +1,10 @@
//go:build unix && (!darwin) //go:build unix && (!darwin)
package registrar package registrar
import "os"
import "log" import "log"
import "git.tebibyte.media/tomo/tomo" import "git.tebibyte.media/tomo/tomo"
import "git.tebibyte.media/tomo/backend/x" import "git.tebibyte.media/tomo/backend/x"
import "git.tebibyte.media/tomo/tomo/event"
import "git.tebibyte.media/sashakoshka/goparse" import "git.tebibyte.media/sashakoshka/goparse"
import "git.tebibyte.media/tomo/nasin/internal/icons/xdg" import "git.tebibyte.media/tomo/nasin/internal/icons/xdg"
import "git.tebibyte.media/tomo/nasin/internal/styles/tss" import "git.tebibyte.media/tomo/nasin/internal/styles/tss"
@ -14,6 +14,8 @@ import "git.tebibyte.media/tomo/nasin/internal/faces/fallback"
type Registrar struct { type Registrar struct {
backend *x.Backend backend *x.Backend
iconSetCookie event.Cookie
styleCookie event.Cookie
} }
func (this *Registrar) SetBackend () (tomo.Backend, error) { func (this *Registrar) SetBackend () (tomo.Backend, error) {
@ -24,38 +26,50 @@ func (this *Registrar) SetBackend () (tomo.Backend, error) {
return backend, nil return backend, nil
} }
func (this *Registrar) SetTheme () error { func (this *Registrar) SetStyle (name string) error {
styleSheetName := os.Getenv("TOMO_STYLE_SHEET") if this.styleCookie != nil {
if styleSheetName != "" { this.styleCookie.Close()
styl, _, err := tss.LoadFile(styleSheetName) this.styleCookie = nil
}
if name != "" {
styl, cookie, err := tss.LoadFile(name)
if err == nil { if err == nil {
this.backend.SetStyle(styl) this.backend.SetStyle(styl)
this.styleCookie = cookie
return nil return nil
} else { } else {
log.Printf ( log.Printf (
"nasin: could not load style sheet '%s'\n%v", "nasin: could not load style sheet '%s'\n%v",
styleSheetName, parse.Format(err)) name, parse.Format(err))
} }
} }
styl, _ := fallbackStyle.New() styl, cookie := fallbackStyle.New()
this.styleCookie = cookie
this.backend.SetStyle(styl) this.backend.SetStyle(styl)
return nil return nil
} }
func (this *Registrar) SetIconSet () error { func (this *Registrar) SetIconSet (name string) error {
iconSet := fallbackIcons.New() if this.iconSetCookie != nil {
iconSetName := os.Getenv("TOMO_XDG_ICON_THEME") this.iconSetCookie.Close()
if iconSetName != "" { this.iconSetCookie = nil
xdgIconSet, err := xdgIcons.FindThemeWarn(iconSetName, iconSet) }
iconSet, cookie := fallbackIcons.New()
if name != "" {
xdgIconSet, xdgCookie, err := xdgIcons.FindThemeWarn(name, iconSet)
cookie = event.MultiCookie(cookie, xdgCookie)
if err == nil { if err == nil {
iconSet = xdgIconSet iconSet = xdgIconSet
} else { } else {
log.Printf("nasin: could not load icon theme '%s': %v", iconSetName, err) log.Printf("nasin: could not load icon theme '%s': %v", name, err)
} }
} }
this.backend.SetIconSet(iconSet) this.backend.SetIconSet(iconSet)
this.iconSetCookie = cookie
return nil return nil
} }