Talking with the OS

Since a GUI library needs to talk to some sort of display system to display information:

var window app.Window

var ops op.Ops
for {
	switch e := window.Event().(type) {
	case app.DestroyEvent:
		// The window was closed.
		return e.Err
	case app.FrameEvent:
		// A request to draw the window state.

		// Reset the operations back to zero.
		// Draw the state into ops.
		// Update the display.

app.Window.Run chooses the appropriate “driver” depending on the environment and build context. It might choose Wayland, Win32, or Cocoa among several others.

An app.Window allows accessing events from the display with window.Event(). There are other lifecycle events in the package such as app.DestroyEvent and app.FrameEvent.


All UI libraries need a way for the program to specify what to display and how to handle events. Gio programs use operations, serialized into one or more op.Ops operation lists. Operation lists are in turn passed to the window driver through the FrameEvent.Frame function.

By convention, each operation kind is represented by a Go type with an Add method that records the operation into the Ops argument. Like any Go struct literal, zero-valued fields can be useful to represent optional values.

For example, recording an operation that sets the current color to red:

func addColorOperation(ops *op.Ops) {
	red := color.NRGBA{R: 0xFF, A: 0xFF}
	paint.ColorOp{Color: red}.Add(ops)

You might be thinking that it would be more usual to have an ops.Add(ColorOp{Color: red}) method instead of using op.ColorOp{Color: red}.Add(ops). It’s like this so that the Add method doesn’t have to take an interface-typed argument, which would often require an allocation to call. This is a key aspect of Gio’s “zero allocation” design.