summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2023-04-23 09:47:54 -0500
committerJeff Carr <[email protected]>2023-04-23 09:47:54 -0500
commit1322a011e7f5b8665b671d4c5ee4e65804ca75be (patch)
tree24ed995ace7694128d5ecdb4ebafc5da7cd868e3
parent2d4d2b6b3e115a86a10f98c20de0e4e82be519c2 (diff)
andlabs: ran without crashing
Signed-off-by: Jeff Carr <[email protected]>
-rw-r--r--README-goreadme.md17
-rw-r--r--cmds/buttonplugin/main.go2
-rw-r--r--debug.go6
-rw-r--r--main.go31
-rw-r--r--plugin.go141
-rw-r--r--toolkit/andlabs/main.go15
-rw-r--r--toolkit/andlabs/plugin.go16
-rw-r--r--toolkit/widget.go46
-rw-r--r--watchdog.go6
9 files changed, 77 insertions, 203 deletions
diff --git a/README-goreadme.md b/README-goreadme.md
index 160264f..0b9a917 100644
--- a/README-goreadme.md
+++ b/README-goreadme.md
@@ -123,14 +123,7 @@ Creates a window helpful for debugging this package
`func ExampleCatcher(f func())`
-### func [FindPlugin](/plugin.go#L64)
-
-`func FindPlugin(name string) *aplug`
-
-loads and initializes a toolkit (andlabs/ui, gocui, etc)
-attempts to locate the .so file
-
-### func [Indent](/debug.go#L120)
+### func [Indent](/debug.go#L126)
`func Indent(b bool, a ...interface{})`
@@ -138,15 +131,15 @@ attempts to locate the .so file
`func SetDebug(s bool)`
-### func [SetFlag](/debug.go#L44)
+### func [SetFlag](/debug.go#L50)
`func SetFlag(s string, b bool)`
-### func [ShowDebugValues](/debug.go#L79)
+### func [ShowDebugValues](/debug.go#L85)
`func ShowDebugValues()`
-### func [StandardExit](/main.go#L169)
+### func [StandardExit](/main.go#L180)
`func StandardExit()`
@@ -187,7 +180,7 @@ var Config GuiConfig
The Node is a binary tree. This is how all GUI elements are stored
simply the name and the size of whatever GUI element exists
-#### func [New](/main.go#L142)
+#### func [New](/main.go#L153)
`func New() *Node`
diff --git a/cmds/buttonplugin/main.go b/cmds/buttonplugin/main.go
index 7c62b21..6d556b3 100644
--- a/cmds/buttonplugin/main.go
+++ b/cmds/buttonplugin/main.go
@@ -16,7 +16,7 @@ var buttonCounter int = 5
func main() {
// This will turn on all debugging
- // gui.SetDebug(true)
+ gui.SetDebug(true)
// myGui = gui.New().LoadToolkit("gocui")
myGui = gui.New().LoadToolkit("andlabs")
diff --git a/debug.go b/debug.go
index 4f5340d..d25a656 100644
--- a/debug.go
+++ b/debug.go
@@ -29,6 +29,12 @@ func SetDebug (s bool) {
debugGui = s
debugTabs = s
+ logNow = s
+ logInfo = s
+ logWarn = s
+ logError = s
+ logVerbose = s
+
SetFlag("Node", s)
SetFlag("Tabs", s)
SetFlag("Dump", s)
diff --git a/main.go b/main.go
index deb53b5..9e37080 100644
--- a/main.go
+++ b/main.go
@@ -112,22 +112,33 @@ func (n *Node) doUserEvent(a toolkit.Action) {
}
func (n *Node) LoadToolkit(name string) *Node {
- log(logInfo, "LoadToolkit() for name =", name)
- if (FindPlugin(name) == nil) {
+ log(logInfo, "LoadToolkit() START for name =", name)
+ plug := initPlugin(name)
+ if (plug == nil) {
return n
}
+
+ log(logInfo, "LoadToolkit() sending InitToolkit action to the plugin channel")
+ var a toolkit.Action
+ a.ActionType = toolkit.InitToolkit
+ plug.pluginChan <- a
+ sleep(.5) // temp hack until chan communication is setup
+
+ // TODO: find a new way to do this that is locking, safe and accurate
+ Config.rootNode.redraw(plug)
+ log(logInfo, "LoadToolkit() END for name =", name)
return n
}
func (n *Node) CloseToolkit(name string) bool {
log(logInfo, "CloseToolkit() for name =", name)
- for _, aplug := range allPlugins {
- log(debugGui, "CloseToolkit() found", aplug.name)
- if (aplug.name == name) {
+ for _, plug := range allPlugins {
+ log(debugGui, "CloseToolkit() found", plug.name)
+ if (plug.name == name) {
log(debugNow, "CloseToolkit() sending close", name)
var a toolkit.Action
a.ActionType = toolkit.CloseToolkit
- aplug.pluginChan <- a
+ plug.pluginChan <- a
sleep(.5)
return true
}
@@ -144,7 +155,7 @@ func New() *Node {
}
func (n *Node) Default() *Node {
- if (FindPlugin("gocui") == nil) {
+ if (n.LoadToolkit("gocui") == nil) {
log(logError, "New() failed to load gocui")
}
// if DISPLAY isn't set, return since gtk can't load
@@ -152,7 +163,7 @@ func (n *Node) Default() *Node {
if (os.Getenv("DISPLAY") == "") {
return n
}
- if (FindPlugin("andlabs") == nil) {
+ if (n.LoadToolkit("andlabs") == nil) {
log(logError, "New() failed to load andlabs")
}
return n
@@ -169,8 +180,8 @@ func (n *Node) StandardClose() {
func StandardExit() {
log("wit/gui Standard Window Exit. running os.Exit()")
log("StandardExit() attempt to exit each toolkit plugin")
- for i, aplug := range allPlugins {
- log("NewButton()", i, aplug)
+ for i, plug := range allPlugins {
+ log("NewButton()", i, plug)
}
exit(0)
}
diff --git a/plugin.go b/plugin.go
index 7dedd22..addab32 100644
--- a/plugin.go
+++ b/plugin.go
@@ -16,17 +16,14 @@ var err error
type Symbol any
type aplug struct {
- // Ok bool
name string
filename string
plug *plugin.Plugin
- sym *plugin.Symbol
- // LoadOk bool
+ // sym *plugin.Symbol
InitOk bool
- // MainOk bool
// startup whatever might need to be setup in the plugin
- Init func()
+// Init func()
// This passes the go channel to the plugin
// the plugin then passes actions back to
@@ -49,33 +46,27 @@ type aplug struct {
// add button request
pluginChan chan toolkit.Action
PluginChannel func() chan toolkit.Action
-
- // deprecate all this
- // 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
- // Quit func()
}
var allPlugins []*aplug
// loads and initializes a toolkit (andlabs/ui, gocui, etc)
// attempts to locate the .so file
-func FindPlugin(name string) *aplug {
- var newPlug *aplug
- newPlug = new(aplug)
-
- log(logInfo, "FindPlugin() START")
- newPlug.InitOk = false
+func initPlugin(name string) *aplug {
+ log(logInfo, "initPlugin() START")
for _, aplug := range allPlugins {
- log(debugGui, "FindPlugin() already loaded toolkit plugin =", aplug.name)
+ log(debugGui, "initPlugin() already loaded toolkit plugin =", aplug.name)
if (aplug.name == name) {
- log(debugError, "FindPlugin() SKIPPING", name, "as you can't load it twice")
- return aplug
+ log(debugError, "initPlugin() SKIPPING", name, "as you can't load it twice")
+ return nil
}
}
+ var newPlug *aplug
+ newPlug = new(aplug)
+ newPlug.InitOk = false
+
// locate the shared library file
filename := name + ".so"
loadPlugin(newPlug, filename)
@@ -86,22 +77,6 @@ func FindPlugin(name string) *aplug {
// 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 instructions like "Add", "Delete", "Disable", etc
- // Sends a widget (button, checkbox, etc) and it's parent widget
- // newPlug.Action = loadFuncA(newPlug, "Action")
-
// this tells the toolkit plugin how to send user events back to us
// for things like: the user clicked on the 'Check IPv6'
newPlug.Callback = sendCallback(newPlug, "Callback")
@@ -112,8 +87,8 @@ func FindPlugin(name string) *aplug {
allPlugins = append(allPlugins, newPlug)
- log(debugPlugin, "FindPlugin() END", newPlug.name, filename)
- newPlug.Init()
+ log(debugPlugin, "initPlugin() END", newPlug.name, filename)
+ // newPlug.Init()
// set the communication to the plugins
newPlug.pluginChan = newPlug.PluginChannel()
@@ -121,35 +96,9 @@ func FindPlugin(name string) *aplug {
newPlug.InitOk = true
- sleep(1) // temp hack until chan communication is setup
-
- // TODO: find a new way to do this that is locking, safe and accurate
- Config.rootNode.redraw(newPlug)
-
return newPlug
}
-// 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
-}
-
// newPlug.PluginChannel = getPluginChannel(newPlug, "PluginChannel")
func getPluginChannel(p *aplug, funcName string) func() chan toolkit.Action {
var newfunc func() chan toolkit.Action
@@ -190,70 +139,6 @@ func sendCallback(p *aplug, funcName string) func(chan toolkit.Action) {
}
/*
-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
-}
-*/
-
-// does this fix loadFuncE problems?
-// TODO: still need to move to channels here
-func loadFuncA(p *aplug, funcName string) func(*toolkit.Action) {
- var newfunc func(*toolkit.Action)
- 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.Action))
- 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/
diff --git a/toolkit/andlabs/main.go b/toolkit/andlabs/main.go
index 5a99421..e9ac6b1 100644
--- a/toolkit/andlabs/main.go
+++ b/toolkit/andlabs/main.go
@@ -24,9 +24,6 @@ func catchActionChannel() {
log(logNow, "catchActionChannel() START")
for {
log(logNow, "catchActionChannel() for loop")
- uiMain.Do(func() {
- go ui.Main(demoUI)
- })
select {
case a := <-pluginChan:
log(logNow, "catchActionChannel() SELECT widget id =", a.WidgetId, a.Name)
@@ -95,7 +92,7 @@ func queue(f func()) {
}
// This is important. This sets the defaults for the gui. Without this, there isn't correct padding, etc
-func Init() {
+func init() {
log(logNow, "Init() START")
log(debugToolkit, "Init()")
// Can you pass values to a plugin init() ? Otherwise, there is no way to safely print
@@ -106,7 +103,17 @@ func Init() {
pluginChan = make(chan toolkit.Action, 1)
log(logNow, "Init() start channel reciever")
+ go ui.Main(func() {
+ demoUI()
+ })
go catchActionChannel()
+ /*
+ // go catchActionChannel()
+ go uiMain.Do(func() {
+ ui.Main(demoUI)
+ // go catchActionChannel()
+ })
+ */
log(logNow, "Init() END")
}
diff --git a/toolkit/andlabs/plugin.go b/toolkit/andlabs/plugin.go
index f9befd5..a7205fb 100644
--- a/toolkit/andlabs/plugin.go
+++ b/toolkit/andlabs/plugin.go
@@ -24,6 +24,7 @@ func Send(p *toolkit.Widget, c *toolkit.Widget) {
}
*/
+/*
func oldAction2(a *toolkit.Action) {
log(logNow, "Action() START")
if (a == nil) {
@@ -31,22 +32,31 @@ func oldAction2(a *toolkit.Action) {
return
}
pluginChan <- *a
- /*
+
f := func() {
rawAction(a)
}
// f()
Queue(f)
- */
log(logNow, "Action() END")
}
-
+*/
func rawAction(a toolkit.Action) {
log(debugAction, "rawAction() START a.ActionType =", a.ActionType)
log(debugAction, "rawAction() START a.S =", a.S)
+ if (a.ActionType == toolkit.InitToolkit) {
+ // TODO: make sure to only do this once
+ // go uiMain.Do(func() {
+ // ui.Main(demoUI)
+ // go catchActionChannel()
+ // })
+ // try doing this on toolkit load in init()
+ return
+ }
+
log(logNow, "rawAction() START a.WidgetId =", a.WidgetId, "a.ParentId =", a.ParentId)
switch a.WidgetType {
case toolkit.Flag:
diff --git a/toolkit/widget.go b/toolkit/widget.go
index 658475e..1a5a45f 100644
--- a/toolkit/widget.go
+++ b/toolkit/widget.go
@@ -1,15 +1,7 @@
package toolkit
-type WidgetType int
-type ActionType int
-
// passes information between the toolkit library (plugin)
//
-// All Toolkit interactions should be done via a channel or Queue()
-// TODO: FIGURE OUT HOW TO IMPLEMENT THIS
-// https://ieftimov.com/post/golang-datastructures-trees/
-// TODO: protobuf ?
-//
// This is the only thing that is passed between the toolkit plugin
//
// what names should be used? This is not part of [[Graphical Widget]]
@@ -17,29 +9,12 @@ type ActionType int
// Event is used too much: web dev, cloud, etc
// I'm using "Action". Maybe it should really be
// "Interaction" as per wikipedia [[User interface]]
-// Could a protobuf be used here? (Can functions be passed?)
-type Widget2 struct {
- // Name string
- Type WidgetType
-
- // This function is how you interact with the toolkit
- // latest attempt. seems to work so far (2023/02/28)
- // Hopefully this will be the barrier between the goroutines
- // TODO: move this interaction to channels
- Custom func()
-
- // re-adding an id to test channels
- Id int
+//
+// TODO: convert this to a protobuf (?)
+//
- // This is how the values are passed back and forth
- // values from things like checkboxes & dropdown's
- // The string is also used to set the button name
- B bool
- I int
- // maybe safe if there is correctly working Custom() between goroutines?
- // (still probably not, almost certainly not. not possible. layer violation?)
- S string // not safe to have 'S'
-}
+type WidgetType int // Button, Menu, Checkbox, etc.
+type ActionType int // Add, SetText, Click, Hide, Append, Delete, etc
type Action struct {
ActionType ActionType
@@ -51,20 +26,13 @@ type Action struct {
Text string // what is visable to the user
Name string // a name useful for programming
- // this should be the widget
- // if the action is New, Hide, Enable, etc
- // Widget *Widget
-
// This is how the values are passed back and forth
// values from things like checkboxes & dropdown's
- // The string is also used to set the button name
B bool
I int
- // maybe safe if there is correctly working Custom() between goroutines?
- // (still probably not, almost certainly not. not possible. layer violation?)
- S string // not safe to have 'S'
+ S string
- A any
+ A any // switch to this or deprecate this? pros/cons?
// This GUI is intended for simple things
// We are not laying out PDF's here
diff --git a/watchdog.go b/watchdog.go
index d992bd4..690ca44 100644
--- a/watchdog.go
+++ b/watchdog.go
@@ -23,12 +23,6 @@ func Watchdog() {
Config.rootNode.ListChildren(true)
}
}
- if (i == 2) {
- Config.rootNode.LoadToolkit("gocui")
- }
-// if (i == 3) {
-// Config.rootNode.LoadToolkit("andlabs")
-// }
i += 1
time.Sleep(watchtime * time.Second / 10)
}