Documentation ¶
Overview ¶
Package loop provides a GUI event loop. The event loop will be locked to an OS thread and not return until all GUI elements have been destroyed. However, callbacks can be dispatched to the event loop, and will be executed on the same thread.
Cocoa: Unlike the other platform, the run loop not only needs to be locked to an OS thread, it must be locked to the main thread. This is the first thread in an application. For this reason, the init function for this package will call runtime.LockOSThread() to ensure that the thread is locked as soon as possible. Additionally, Run must be called from same goroutine (i.e., same OS thread) as used to run main.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNotRunning indicates that the main loop is not running. ErrNotRunning = errors.New("main loop is not running") // ErrAlreadyRunning indicates that the main loop is already running. ErrAlreadyRunning = errors.New("main loop is already running") )
Functions ¶
func AddLockCount ¶
func AddLockCount(delta int32)
AddLockCount is used to track the number of top-level GUI elements that are created. When the count falls back to zero, the event loop will terminate.
Users should not typically need to call this function. Top-level GUI elements, such as windows, will increment and decrement the count as they are created and destroyed.
If the GUI event loop is not running, this function will panic.
func Do ¶
Do runs the passed function on the GUI thread. If the GUI event loop is not running, this function will return an error (ErrNotRunning). Any error from the callback will also be returned.
Because this function involves asynchronous communication with the GUI thread, it can deadlock if called from the GUI thread. It is therefore not safe to use in any event callbacks from widgets. However, since those callbacks are already executing on the GUI thread, the use of Do is also unnecessary in that context.
Note, this function contains a race-condition. An action may be scheduled while the event loop is being terminated, in which case the scheduled action may never be run. Presumably, those actions don't need to be run on the GUI thread, so they should be scheduled using a different mechanism.
If the passed function panics, the panic will be recovered, and wrapped into an error. That error will be used to create a new panic within the caller's goroutine. If the program terminates because of that panic, there will be two active goroutines in the stack trace. One active goroutine will be the GUI thread, where the panic originated, and a second active goroutine from caller's goroutine.
Example ¶
package main import ( "fmt" "bitbucket.org/rj/goey/loop" ) func main() { err := loop.Do(func() error { // Inside this closure, we will be executing only on the GUI thread. _, err := fmt.Println("Hello.") // Return the error (if any) back to the caller. return err }) // Report on the success or failure fmt.Println("Previous call to fmt.Println resulted in ", err) }
Output:
func LockCount ¶
func LockCount() int32
LockCount returns the current lock count. This code is not meant to be used in regular code, it exists to support testing.
func Run ¶
Run locks the OS thread to act as a GUI thread, and then starts the GUI event loop until there are no more instances of Window open. If the main loop is already running, this function will return an error (ErrAlreadyRunning).
Modification of the GUI should happen only on the GUI thread. This includes creating any windows, mounting any widgets, or updating the properties of any elements.
The parameter action takes a closure that can be used to initialize the GUI. Any further modifications to the GUI also need to be scheduled on the GUI thread, which can be done using the function Do.
Example ¶
package main import ( "fmt" "bitbucket.org/rj/goey/loop" ) func main() { // This init function will be used to create a window on the GUI thread. init := func() error { // Create an empty window. Note that most user code should instead // create a window, which will handle lock counting. loop.AddLockCount(1) go func() { // Because of goroutine, we are now off the GUI thread. // Schedule an action. err := loop.Do(func() error { loop.AddLockCount(-1) fmt.Println("...like tears in rain") return nil }) if err != nil { fmt.Println("Error:", err) } }() return nil } err := loop.Run(init) if err != nil { fmt.Println("Error:", err) } }
Output: ...like tears in rain
Types ¶
This section is empty.