242 lines
5.9 KiB
Go
242 lines
5.9 KiB
Go
package gui
|
|
|
|
// This is based off of the excellent example and documentation here:
|
|
// https://github.com/vladimirvivien/go-plugin-example
|
|
// There truly are great people in this world.
|
|
// It's a pleasure to be here with all of you
|
|
|
|
import (
|
|
"log"
|
|
"os"
|
|
"plugin"
|
|
|
|
"git.wit.org/wit/gui/toolkit"
|
|
)
|
|
|
|
var err error
|
|
type Symbol any
|
|
|
|
type aplug struct {
|
|
// Ok bool
|
|
name string
|
|
filename string
|
|
plug *plugin.Plugin
|
|
sym *plugin.Symbol
|
|
LoadOk bool
|
|
InitOk bool
|
|
MainOk bool
|
|
|
|
Init func()
|
|
Main func(func ())
|
|
Queue func(func ())
|
|
Quit func()
|
|
NewWindow func(*toolkit.Widget)
|
|
NewButton func(*toolkit.Widget, *toolkit.Widget)
|
|
NewGroup func(*toolkit.Widget, *toolkit.Widget)
|
|
NewCheckbox func(*toolkit.Widget, *toolkit.Widget)
|
|
NewTab func(*toolkit.Widget, *toolkit.Widget)
|
|
NewLabel func(*toolkit.Widget, *toolkit.Widget)
|
|
NewTextbox func(*toolkit.Widget, *toolkit.Widget)
|
|
NewSlider func(*toolkit.Widget, *toolkit.Widget)
|
|
NewSpinner func(*toolkit.Widget, *toolkit.Widget)
|
|
|
|
NewDropdown func(*toolkit.Widget, *toolkit.Widget)
|
|
AddDropdownName func(*toolkit.Widget, string)
|
|
}
|
|
|
|
var allPlugins []*aplug
|
|
|
|
// loads and initializes a toolkit (andlabs/ui, gocui, etc)
|
|
func LoadToolkit(name string) bool {
|
|
var newPlug aplug
|
|
|
|
log.Println("gui.LoadToolkit() START")
|
|
newPlug.LoadOk = false
|
|
|
|
for _, aplug := range allPlugins {
|
|
log.Println("gui.LoadToolkit() already loaded toolkit plugin =", aplug.name)
|
|
if (aplug.name == name) {
|
|
log.Println("gui.LoadToolkit() SKIPPING")
|
|
return true
|
|
}
|
|
}
|
|
|
|
// locate the shared library file
|
|
filename := name + ".so"
|
|
loadPlugin(&newPlug, filename)
|
|
if (newPlug.plug == nil) {
|
|
return false
|
|
}
|
|
// newPlug.Ok = true
|
|
newPlug.name = name
|
|
|
|
// map all the functions
|
|
newPlug.Init = loadFuncE(&newPlug, "Init")
|
|
newPlug.Quit = loadFuncE(&newPlug, "Quit")
|
|
|
|
// this should be laodFuncE()
|
|
newPlug.Main = loadFuncF(&newPlug, "Main")
|
|
newPlug.Queue = loadFuncF(&newPlug, "Queue")
|
|
|
|
newPlug.NewWindow = loadFunc1(&newPlug, "NewWindow")
|
|
|
|
newPlug.NewButton = loadFunc2(&newPlug, "NewButton")
|
|
newPlug.NewGroup = loadFunc2(&newPlug, "NewGroup")
|
|
newPlug.NewCheckbox = loadFunc2(&newPlug, "NewCheckbox")
|
|
newPlug.NewTab = loadFunc2(&newPlug, "NewTab")
|
|
newPlug.NewLabel = loadFunc2(&newPlug, "NewLabel")
|
|
newPlug.NewTextbox = loadFunc2(&newPlug, "NewTextbox")
|
|
newPlug.NewSlider = loadFunc2(&newPlug, "NewSlider")
|
|
newPlug.NewSpinner = loadFunc2(&newPlug, "NewSpinner")
|
|
|
|
newPlug.NewDropdown = loadFunc2(&newPlug, "NewDropdown")
|
|
newPlug.AddDropdownName = loadFuncS(&newPlug, "AddDropdownName")
|
|
|
|
allPlugins = append(allPlugins, &newPlug)
|
|
|
|
log.Println("gui.LoadToolkit() END", newPlug.name, filename)
|
|
newPlug.LoadOk = true
|
|
return true
|
|
}
|
|
|
|
func loadFuncE(p *aplug, funcName string) func() {
|
|
var newfunc func()
|
|
var ok bool
|
|
var test plugin.Symbol
|
|
|
|
test, err = p.plug.Lookup(funcName)
|
|
if err != nil {
|
|
log.Println("DID NOT FIND: name =", test, "err =", err)
|
|
return nil
|
|
}
|
|
|
|
newfunc, ok = test.(func())
|
|
if !ok {
|
|
log.Println("function name =", funcName, "names didn't map correctly. Fix the plugin name =", p.name)
|
|
return nil
|
|
}
|
|
return newfunc
|
|
}
|
|
|
|
func loadFunc1(p *aplug, funcName string) func(*toolkit.Widget) {
|
|
var newfunc func(*toolkit.Widget)
|
|
var ok bool
|
|
var test plugin.Symbol
|
|
|
|
test, err = p.plug.Lookup(funcName)
|
|
if err != nil {
|
|
log.Println("DID NOT FIND: name =", test, "err =", err)
|
|
return nil
|
|
}
|
|
|
|
newfunc, ok = test.(func(*toolkit.Widget))
|
|
if !ok {
|
|
log.Println("function name =", funcName, "names didn't map correctly. Fix the plugin name =", p.name)
|
|
return nil
|
|
}
|
|
return newfunc
|
|
}
|
|
|
|
func loadFuncS(p *aplug, funcName string) func(*toolkit.Widget, string) {
|
|
var newfunc func(*toolkit.Widget, string)
|
|
var ok bool
|
|
var test plugin.Symbol
|
|
|
|
test, err = p.plug.Lookup(funcName)
|
|
if err != nil {
|
|
log.Println("DID NOT FIND: name =", test, "err =", err)
|
|
return nil
|
|
}
|
|
|
|
newfunc, ok = test.(func(*toolkit.Widget, string))
|
|
if !ok {
|
|
log.Println("function name =", funcName, "names didn't map correctly. Fix the plugin name =", p.name)
|
|
return nil
|
|
}
|
|
return newfunc
|
|
}
|
|
|
|
func loadFunc2(p *aplug, funcName string) func(*toolkit.Widget, *toolkit.Widget) {
|
|
var newfunc func(*toolkit.Widget, *toolkit.Widget)
|
|
var ok bool
|
|
var test plugin.Symbol
|
|
|
|
test, err = p.plug.Lookup(funcName)
|
|
if err != nil {
|
|
log.Println("DID NOT FIND: name =", test, "err =", err)
|
|
return nil
|
|
}
|
|
|
|
newfunc, ok = test.(func(*toolkit.Widget, *toolkit.Widget))
|
|
if !ok {
|
|
log.Println("function name =", funcName, "names didn't map correctly. Fix the plugin name =", p.name)
|
|
return nil
|
|
}
|
|
return newfunc
|
|
}
|
|
|
|
// This is probably dangerous and should never be done
|
|
// executing arbitrary functions will cause them to run inside the goroutine that
|
|
// the GUI toolkit itself is running in. TODO: move to channels here
|
|
func loadFuncF(p *aplug, funcName string) func(func ()) {
|
|
var newfunc func(func ())
|
|
var ok bool
|
|
var test plugin.Symbol
|
|
|
|
test, err = p.plug.Lookup(funcName)
|
|
if err != nil {
|
|
log.Println("DID NOT FIND: name =", test, "err =", err)
|
|
return nil
|
|
}
|
|
|
|
newfunc, ok = test.(func(func ()))
|
|
if !ok {
|
|
log.Println("function name =", funcName, "names didn't map correctly. Fix the plugin name =", p.name)
|
|
return nil
|
|
}
|
|
return newfunc
|
|
}
|
|
|
|
func loadPlugin(p *aplug, name string) {
|
|
var filename string
|
|
|
|
// attempt to write out the file from the internal resource
|
|
internalName := "toolkit/" + name
|
|
soFile, err := res.ReadFile(internalName)
|
|
if (err != nil) {
|
|
log.Println(err)
|
|
} else {
|
|
err = os.WriteFile("/tmp/wit/" + name, soFile, 0644)
|
|
if (err != nil) {
|
|
log.Println(err)
|
|
}
|
|
}
|
|
|
|
filename = "/tmp/wit/" + name
|
|
p.plug = loadfile(filename)
|
|
if (p.plug != nil) {
|
|
p.filename = filename
|
|
return
|
|
}
|
|
|
|
filename = "/usr/share/wit/gui/" + name
|
|
p.plug = loadfile(filename)
|
|
if (p.plug != nil) {
|
|
p.filename = filename
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// load module
|
|
// 1. open the shared object file to load the symbols
|
|
func loadfile(filename string) *plugin.Plugin {
|
|
plug, err := plugin.Open(filename)
|
|
log.Println("plug =", plug)
|
|
if err != nil {
|
|
log.Println(err)
|
|
return nil
|
|
}
|
|
return plug
|
|
}
|