This repository has been archived on 2023-08-08. You can view files and clone it, but cannot push or open issues or pull requests.
tomo-old/tomo.go
Sasha Koshka 02a27447b9 Changed the clipboard API so that it will work with X
In X, clipboard/selection data is specific to each window, and it
may take some time before the clipboard data is fully transferred.
This actually makes sense because there can be entire images in
the clipboard and it is important the clipboard API supports large
file transfer. Because of this, the Copy and Paste methods have
been moved into Window, and Paste now returns a channel.
2023-03-25 13:32:48 -04:00

116 lines
2.9 KiB
Go

package tomo
import "os"
import "io"
import "path/filepath"
import "git.tebibyte.media/sashakoshka/tomo/dirs"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/config"
import "git.tebibyte.media/sashakoshka/tomo/elements"
var backend Backend
// Run initializes a backend, calls the callback function, and begins the event
// loop in that order. This function does not return until Stop() is called, or
// the backend experiences a fatal error.
func Run (callback func ()) (err error) {
backend, err = instantiateBackend()
if err != nil { return }
config := parseConfig()
backend.SetConfig(config)
backend.SetTheme(parseTheme(config.ThemePath()))
if callback != nil { callback() }
err = backend.Run()
backend = nil
return
}
// Stop gracefully stops the event loop and shuts the backend down. Call this
// before closing your application.
func Stop () {
if backend != nil { backend.Stop() }
}
// Do executes the specified callback within the main thread as soon as
// possible. This function can be safely called from other threads.
func Do (callback func ()) {
assertBackend()
backend.Do(callback)
}
// NewWindow creates a new window using the current backend, and returns it as a
// MainWindow. If the window could not be created, an error is returned
// explaining why.
func NewWindow (width, height int) (window elements.MainWindow, err error) {
assertBackend()
return backend.NewWindow(width, height)
}
// SetTheme sets the theme of all open windows.
func SetTheme (theme theme.Theme) {
backend.SetTheme(theme)
}
// SetConfig sets the configuration of all open windows.
func SetConfig (config config.Config) {
backend.SetConfig(config)
}
func parseConfig () (config.Config) {
return parseMany [config.Config] (
dirs.ConfigDirs("tomo/tomo.conf"),
config.Parse,
config.Default { })
}
func parseTheme (path string) (theme.Theme) {
if path == "" { return theme.Default { } }
path = filepath.Join(path, "tomo")
// find all tomo pattern graph files in the directory
directory, err := os.Open(path)
if err != nil { return theme.Default { } }
names, _ := directory.Readdirnames(0)
paths := []string { }
for _, name := range names {
if filepath.Ext(name) == ".tpg" {
paths = append(paths, filepath.Join(path, name))
}
}
// parse them
return parseMany [theme.Theme] (
paths,
theme.Parse,
theme.Default { })
}
func parseMany [OBJECT any] (
paths []string,
parser func (...io.Reader) OBJECT,
fallback OBJECT,
) (
object OBJECT,
) {
// convert all paths into readers
sources := []io.Reader { }
for _, path := range paths {
file, err := os.Open(path)
if err != nil { continue }
sources = append(sources, file)
defer file.Close()
}
if sources == nil {
// if there are no readers, return the fallback object
return fallback
} else {
// if there are readers, parse them
return parser(sources...)
}
}
func assertBackend () {
if backend == nil { panic("no backend is running") }
}