...

Source file src/github.com/jezek/xgb/examples/create-window/main.go

Documentation: github.com/jezek/xgb/examples/create-window

     1  // Example create-window shows how to create a window, map it, resize it,
     2  // and listen to structure and key events (i.e., when the window is resized
     3  // by the window manager, or when key presses/releases are made when the
     4  // window has focus). The events are printed to stdout.
     5  package main
     6  
     7  import (
     8  	"fmt"
     9  
    10  	"github.com/jezek/xgb"
    11  	"github.com/jezek/xgb/xproto"
    12  )
    13  
    14  func main() {
    15  	X, err := xgb.NewConn()
    16  	if err != nil {
    17  		fmt.Println(err)
    18  		return
    19  	}
    20  	defer X.Close()
    21  
    22  	// xproto.Setup retrieves the Setup information from the setup bytes
    23  	// gathered during connection.
    24  	setup := xproto.Setup(X)
    25  
    26  	// This is the default screen with all its associated info.
    27  	screen := setup.DefaultScreen(X)
    28  
    29  	// Any time a new resource (i.e., a window, pixmap, graphics context, etc.)
    30  	// is created, we need to generate a resource identifier.
    31  	// If the resource is a window, then use xproto.NewWindowId. If it's for
    32  	// a pixmap, then use xproto.NewPixmapId. And so on...
    33  	wid, _ := xproto.NewWindowId(X)
    34  
    35  	// CreateWindow takes a boatload of parameters.
    36  	xproto.CreateWindow(X, screen.RootDepth, wid, screen.Root,
    37  		0, 0, 500, 500, 0,
    38  		xproto.WindowClassInputOutput, screen.RootVisual, 0, []uint32{})
    39  
    40  	// This call to ChangeWindowAttributes could be factored out and
    41  	// included with the above CreateWindow call, but it is left here for
    42  	// instructive purposes. It tells X to send us events when the 'structure'
    43  	// of the window is changed (i.e., when it is resized, mapped, unmapped,
    44  	// etc.) and when a key press or a key release has been made when the
    45  	// window has focus.
    46  	// We also set the 'BackPixel' to white so that the window isn't butt ugly.
    47  	xproto.ChangeWindowAttributes(X, wid,
    48  		xproto.CwBackPixel|xproto.CwEventMask,
    49  		[]uint32{ // values must be in the order defined by the protocol
    50  			0xffffffff,
    51  			xproto.EventMaskStructureNotify |
    52  				xproto.EventMaskKeyPress |
    53  				xproto.EventMaskKeyRelease,
    54  		})
    55  
    56  	// MapWindow makes the window we've created appear on the screen.
    57  	// We demonstrated the use of a 'checked' request here.
    58  	// A checked request is a fancy way of saying, "do error handling
    59  	// synchronously." Namely, if there is a problem with the MapWindow request,
    60  	// we'll get the error *here*. If we were to do a normal unchecked
    61  	// request (like the above CreateWindow and ChangeWindowAttributes
    62  	// requests), then we would only see the error arrive in the main event
    63  	// loop.
    64  	//
    65  	// Typically, checked requests are useful when you need to make sure they
    66  	// succeed. Since they are synchronous, they incur a round trip cost before
    67  	// the program can continue, but this is only going to be noticeable if
    68  	// you're issuing tons of requests in succession.
    69  	//
    70  	// Note that requests without replies are by default unchecked while
    71  	// requests *with* replies are checked by default.
    72  	err = xproto.MapWindowChecked(X, wid).Check()
    73  	if err != nil {
    74  		fmt.Printf("Checked Error for mapping window %d: %s\n", wid, err)
    75  	} else {
    76  		fmt.Printf("Map window %d successful!\n", wid)
    77  	}
    78  
    79  	// This is an example of an invalid MapWindow request and what an error
    80  	// looks like.
    81  	err = xproto.MapWindowChecked(X, 0).Check()
    82  	if err != nil {
    83  		fmt.Printf("Checked Error for mapping window 0x1: %s\n", err)
    84  	} else { // neva
    85  		fmt.Printf("Map window 0x1 successful!\n")
    86  	}
    87  
    88  	// Start the main event loop.
    89  	for {
    90  		// WaitForEvent either returns an event or an error and never both.
    91  		// If both are nil, then something went wrong and the loop should be
    92  		// halted.
    93  		//
    94  		// An error can only be seen here as a response to an unchecked
    95  		// request.
    96  		ev, xerr := X.WaitForEvent()
    97  		if ev == nil && xerr == nil {
    98  			fmt.Println("Both event and error are nil. Exiting...")
    99  			return
   100  		}
   101  
   102  		if ev != nil {
   103  			fmt.Printf("Event: %s\n", ev)
   104  		}
   105  		if xerr != nil {
   106  			fmt.Printf("Error: %s\n", xerr)
   107  		}
   108  
   109  		// This is how accepting events work:
   110  		// The application checks what event we got and reacts to it
   111  		// accordingly. All events are defined in the xproto subpackage.
   112  		// To receive events, we have to first register it using
   113  		// either xproto.CreateWindow or xproto.ChangeWindowAttributes.
   114  		switch ev.(type) {
   115  		case xproto.KeyPressEvent:
   116  			// See https://pkg.go.dev/github.com/jezek/xgb/xproto#KeyPressEvent
   117  			// for documentation about a key press event.
   118  			kpe := ev.(xproto.KeyPressEvent)
   119  			fmt.Printf("Key pressed: %d\n", kpe.Detail)
   120  			// The Detail value depends on the keyboard layout,
   121  			// for QWERTY, q is #24.
   122  			if kpe.Detail == 24 {
   123  				return // exit on q
   124  			}
   125  		case xproto.DestroyNotifyEvent:
   126  			// Depending on the user's desktop environment (especially
   127  			// window manager), killing a window might close the
   128  			// client's X connection (e. g. the default Ubuntu
   129  			// desktop environment).
   130  			//
   131  			// If that's the case for your environment, closing this example's window
   132  			// will also close the underlying Go program (because closing the X
   133  			// connection gives a nil event and EOF error).
   134  			//
   135  			// Consider how a single application might have multiple windows
   136  			// (e.g. an open popup or dialog, ...)
   137  			//
   138  			// With other DEs, the X connection will still stay open even after the
   139  			// X window is closed. For these DEs (e.g. i3) we have to check whether
   140  			// the WM sent us a DestroyNotifyEvent and close our program.
   141  			//
   142  			// For more information about closing windows while maintaining
   143  			// the X connection see
   144  			// https://github.com/jezek/xgbutil/blob/master/_examples/graceful-window-close/main.go
   145  			return
   146  		}
   147  	}
   148  }
   149  

View as plain text