loop

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 31, 2021 License: BSD-3-Clause Imports: 7 Imported by: 16

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

View Source
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

func Do(action func() error) error

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

func Run(action func() error) error

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

func TestMain

func TestMain(m *testing.M)

TestMain should be used by any GUI wants to call tests...

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL