new-gui/plugin.go

216 lines
5.3 KiB
Go
Raw Normal View History

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 (
"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()
// TODO: make Main() main() and never allow the user to call it
// run plugin.Main() when the plugin is loaded
Main func(func ()) // this never returns. Each plugin must have it's own goroutine
Queue func(func ()) // Should this return right away? Should it wait (can it wait?)
Quit func()
// NewWindow func(*toolkit.Widget)
// simplifies passing to the plugin
Send func(*toolkit.Widget, *toolkit.Widget)
}
var allPlugins []*aplug
// loads and initializes a toolkit (andlabs/ui, gocui, etc)
func LoadToolkit(name string) bool {
var newPlug aplug
log(debugGui, "gui.LoadToolkit() START")
newPlug.LoadOk = false
for _, aplug := range allPlugins {
log(debugGui, "gui.LoadToolkit() already loaded toolkit plugin =", aplug.name)
if (aplug.name == name) {
log(debugGui, "gui.LoadToolkit() SKIPPING")
return true
}
}
// locate the shared library file
filename := name + ".so"
loadPlugin(&newPlug, filename)
if (newPlug.plug == nil) {
log(true, "attempt to find plugin", filename, "failed")
return false
}
// newPlug.Ok = true
newPlug.name = name
// deprecate Init(?)
newPlug.Init = loadFuncE(&newPlug, "Init")
// should make a goroutine that never exits
newPlug.Main = loadFuncF(&newPlug, "Main")
// should send things to the goroutine above
newPlug.Queue = loadFuncF(&newPlug, "Queue")
// unload the plugin and restore state
newPlug.Quit = loadFuncE(&newPlug, "Quit")
// Sends a widget (button, checkbox, etc) and it's parent widget
// This includes instructions like "Add", "Delete", "Disable", etc
newPlug.Send = loadFunc2(&newPlug, "Send")
allPlugins = append(allPlugins, &newPlug)
log(debugPlugin, "gui.LoadToolkit() END", newPlug.name, filename)
newPlug.Init()
newPlug.LoadOk = true
return true
}
// TODO: All these functions need to be done a smarter way
// but I haven't worked out the golang syntax to make it smarter
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(debugGui, "DID NOT FIND: name =", test, "err =", err)
return nil
}
newfunc, ok = test.(func())
if !ok {
log(debugGui, "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(debugGui, "DID NOT FIND: name =", test, "err =", err)
return nil
}
newfunc, ok = test.(func(*toolkit.Widget, *toolkit.Widget))
if !ok {
log(debugGui, "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(debugGui, "DID NOT FIND: name =", test, "err =", err)
return nil
}
newfunc, ok = test.(func(func ()))
if !ok {
log(debugGui, "function name =", funcName, "names didn't map correctly. Fix the plugin name =", p.name)
return nil
}
return newfunc
}
/*
This searches in the following order for the plugin .so files:
./toolkit/
~/go/src/go.wit.org/gui/toolkit/
/usr/lib/go-gui/
*/
func loadPlugin(p *aplug, name string) {
var filename string
homeDir, err := os.UserHomeDir()
if err != nil {
exit(err)
}
// attempt to write out the file from the internal resource
filename = "toolkit/" + name
p.plug = loadfile(filename)
if (p.plug != nil) {
p.filename = filename
return
}
filename = homeDir + "/go/src/git.wit.org/wit/gui/toolkit/" + name
p.plug = loadfile(filename)
if (p.plug != nil) {
p.filename = filename
return
}
filename = "/usr/lib/go-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)
if err != nil {
log(debugGui, "plugin FAILED =", filename, err)
return nil
}
log(debugGui, "plugin WORKED =", filename)
log(true, "loading plugin", filename, "worked")
return plug
}
// Sends a widget and what to do with it to the plugin
// parent = n, child = c
func send(p *Node, c *Node) {
for _, aplug := range allPlugins {
Squashed commit of the following: commit 448abc843e2241bab6c399f7a836dccba1defc18 Author: Jeff Carr <jcarr@wit.com> Date: Sun Mar 12 08:35:28 2023 -0500 this should probably be a new release now Signed-off-by: Jeff Carr <jcarr@wit.com> commit a4064f7a6c5ac67437768aa2bc67c75dafc91c4c Author: Jeff Carr <jcarr@wit.com> Date: Sat Mar 11 03:18:23 2023 -0600 able to work on add 'Box' and play with 'Image' Signed-off-by: Jeff Carr <jcarr@wit.com> commit 6e59573d85e82ecb005805f50711dddc2df50480 Author: Jeff Carr <jcarr@wit.com> Date: Sat Mar 11 03:04:34 2023 -0600 rearrange widget debugging Signed-off-by: Jeff Carr <jcarr@wit.com> commit e0570de75c6eb1b4f49e541d9ef5d83ae4434d3d Author: Jeff Carr <jcarr@wit.com> Date: Sat Mar 11 02:29:20 2023 -0600 debugging is lots smarter Signed-off-by: Jeff Carr <jcarr@wit.com> commit ece32a1e43d91cd197d0a8497ad2f034c46126e1 Author: Jeff Carr <jcarr@wit.com> Date: Fri Mar 10 21:38:23 2023 -0600 first pass on a node delete Signed-off-by: Jeff Carr <jcarr@wit.com> commit c91cb0eddb0f73f8dea9b21a16cd76c7e2c19a33 Author: Jeff Carr <jcarr@wit.com> Date: Fri Mar 10 21:06:29 2023 -0600 can recreate window list Signed-off-by: Jeff Carr <jcarr@wit.com> commit 470f9dc26aefd3626b319264fe151aa48d4d5377 Author: Jeff Carr <jcarr@wit.com> Date: Fri Mar 10 12:07:34 2023 -0600 attempt to ressurect mouse in the console plugin Signed-off-by: Jeff Carr <jcarr@wit.com> commit 747bb53e06dda458cc8cd77b665f4d9d07f5e925 Author: Jeff Carr <jcarr@wit.com> Date: Fri Mar 10 10:47:14 2023 -0600 jesus. gocui actually builds and works again as a plugin it didn't take too much to change it Signed-off-by: Jeff Carr <jcarr@wit.com> commit 9283c65c8e9b8d2630b251ad952b6b52caddb307 Author: Jeff Carr <jcarr@wit.com> Date: Fri Mar 10 07:26:53 2023 -0600 show/hide/etc for window widgets Signed-off-by: Jeff Carr <jcarr@wit.com> commit 5724cd7ffd8595ae049a7c9c21cb2f1a993c4b76 Author: Jeff Carr <jcarr@wit.com> Date: Fri Mar 10 06:40:36 2023 -0600 compiles and runs Signed-off-by: Jeff Carr <jcarr@wit.com> commit 44a5e69ce17cb506adfe24ca72cc86caa9ebcc70 Author: Jeff Carr <jcarr@wit.com> Date: Fri Mar 10 05:57:15 2023 -0600 more debugging improvements Signed-off-by: Jeff Carr <jcarr@wit.com> commit b86f145f0252e7545b2e7fa78e1d5960cacb7bad Author: Jeff Carr <jcarr@wit.com> Date: Fri Mar 10 03:42:32 2023 -0600 set margin on tab's works Signed-off-by: Jeff Carr <jcarr@wit.com> commit d2218c08cf44acd5f017a8faa1439ee6d2fd46d5 Author: Jeff Carr <jcarr@wit.com> Date: Thu Mar 9 16:26:21 2023 -0600 ignore all *.so files Signed-off-by: Jeff Carr <jcarr@wit.com> commit e21934fff3cfea30b04df01bf0714f6927aa78f4 Author: Jeff Carr <jcarr@wit.com> Date: Thu Mar 9 16:25:15 2023 -0600 can't embed the toolkit/*.so files here Signed-off-by: Jeff Carr <jcarr@wit.com> commit f1e6c5fc9c8ca36db3ad6109d64612b6850fa856 Author: Jeff Carr <jcarr@wit.com> Date: Thu Mar 9 16:21:14 2023 -0600 andlabs group widget has Show() and Hide() Signed-off-by: Jeff Carr <jcarr@wit.com> commit e8487504aa76ca99c4891b777585a428fda0ef62 Author: Jeff Carr <jcarr@wit.com> Date: Thu Mar 9 16:07:56 2023 -0600 pass the node id into the plugin to use in channels Signed-off-by: Jeff Carr <jcarr@wit.com> commit 3667940a77af4e3855facb9247771d595477302f Author: Jeff Carr <jcarr@wit.com> Date: Thu Mar 9 14:20:21 2023 -0600 fix SetText() on Label Signed-off-by: Jeff Carr <jcarr@wit.com> commit 311d6be66db84b63fb7124df64e2e9be0f0b76a4 Author: Jeff Carr <jcarr@wit.com> Date: Thu Mar 9 14:06:46 2023 -0600 still compiles and runs Signed-off-by: Jeff Carr <jcarr@wit.com> commit ee4e9b21ef59a97f902c6dae2a57ac7b3063fe3b Author: Jeff Carr <jcarr@wit.com> Date: Thu Mar 9 11:02:34 2023 -0600 compiles Signed-off-by: Jeff Carr <jcarr@wit.com> Signed-off-by: Jeff Carr <jcarr@wit.com>
2023-03-12 08:47:16 -05:00
log(debugPlugin, "Send() aplug =", aplug.name, "type=", c.widget.Type, "action=", c.widget.Action, "name=", c.widget.Name)
if (aplug.Send == nil) {
log(debugPlugin, "\tSend() failed (aplug.Selete = nil) for", aplug.name)
continue
}
aplug.Send(&c.parent.widget, &c.widget)
}
}