diff options
Diffstat (limited to 'nexgb/examples')
-rw-r--r-- | nexgb/examples/atoms/.gitignore | 3 | ||||
-rw-r--r-- | nexgb/examples/atoms/Makefile | 12 | ||||
-rw-r--r-- | nexgb/examples/atoms/main.go | 91 | ||||
-rw-r--r-- | nexgb/examples/create-window/main.go | 107 | ||||
-rw-r--r-- | nexgb/examples/doc.go | 21 | ||||
-rw-r--r-- | nexgb/examples/get-active-window/main.go | 61 | ||||
-rw-r--r-- | nexgb/examples/randr/main.go | 92 | ||||
-rw-r--r-- | nexgb/examples/xinerama/main.go | 40 |
8 files changed, 427 insertions, 0 deletions
diff --git a/nexgb/examples/atoms/.gitignore b/nexgb/examples/atoms/.gitignore new file mode 100644 index 0000000..01e08a1 --- /dev/null +++ b/nexgb/examples/atoms/.gitignore @@ -0,0 +1,3 @@ +atoms +*.info +*.prof diff --git a/nexgb/examples/atoms/Makefile b/nexgb/examples/atoms/Makefile new file mode 100644 index 0000000..c192a37 --- /dev/null +++ b/nexgb/examples/atoms/Makefile @@ -0,0 +1,12 @@ +atoms: + go build + +test: atoms + ./atoms --requests 500000 --cpu 1 \ + --cpuprof cpu1.prof --memprof mem1.prof > atoms1.info 2>&1 + ./atoms --requests 500000 --cpu 2 \ + --cpuprof cpu2.prof --memprof mem2.prof > atoms2.info 2>&1 + ./atoms --requests 500000 --cpu 3 \ + --cpuprof cpu3.prof --memprof mem3.prof > atoms3.info 2>&1 + ./atoms --requests 500000 --cpu 6 \ + --cpuprof cpu6.prof --memprof mem6.prof > atoms6.info 2>&1 diff --git a/nexgb/examples/atoms/main.go b/nexgb/examples/atoms/main.go new file mode 100644 index 0000000..8985768 --- /dev/null +++ b/nexgb/examples/atoms/main.go @@ -0,0 +1,91 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + "runtime" + "runtime/pprof" + "time" + + "github.com/BurntSushi/xgb" + "github.com/BurntSushi/xgb/xproto" +) + +var ( + flagRequests int + flagGOMAXPROCS int + flagCpuProfName string + flagMemProfName string +) + +func init() { + flag.IntVar(&flagRequests, "requests", 100000, "Number of atoms to intern.") + flag.IntVar(&flagGOMAXPROCS, "cpu", 1, "Value of GOMAXPROCS.") + flag.StringVar(&flagCpuProfName, "cpuprof", "cpu.prof", + "Name of CPU profile file.") + flag.StringVar(&flagMemProfName, "memprof", "mem.prof", + "Name of memory profile file.") + + flag.Parse() + + runtime.GOMAXPROCS(flagGOMAXPROCS) +} + +func seqNames(n int) []string { + names := make([]string, n) + for i := range names { + names[i] = fmt.Sprintf("NAME%d", i) + } + return names +} + +func main() { + X, err := xgb.NewConn() + if err != nil { + log.Fatal(err) + } + + names := seqNames(flagRequests) + + fcpu, err := os.Create(flagCpuProfName) + if err != nil { + log.Fatal(err) + } + defer fcpu.Close() + pprof.StartCPUProfile(fcpu) + defer pprof.StopCPUProfile() + + start := time.Now() + cookies := make([]xproto.InternAtomCookie, flagRequests) + for i := 0; i < flagRequests; i++ { + cookies[i] = xproto.InternAtom(X, + false, uint16(len(names[i])), names[i]) + } + for _, cookie := range cookies { + cookie.Reply() + } + fmt.Printf("Exec time: %s\n\n", time.Since(start)) + + fmem, err := os.Create(flagMemProfName) + if err != nil { + log.Fatal(err) + } + defer fmem.Close() + pprof.WriteHeapProfile(fmem) + + memStats := &runtime.MemStats{} + runtime.ReadMemStats(memStats) + + // This isn't right. I'm not sure what's wrong. + lastGcTime := time.Unix(int64(memStats.LastGC/1000000000), + int64(memStats.LastGC-memStats.LastGC/1000000000)) + + fmt.Printf("Alloc: %d\n", memStats.Alloc) + fmt.Printf("TotalAlloc: %d\n", memStats.TotalAlloc) + fmt.Printf("LastGC: %s\n", lastGcTime) + fmt.Printf("PauseTotalNs: %d\n", memStats.PauseTotalNs) + fmt.Printf("PauseNs: %d\n", memStats.PauseNs) + fmt.Printf("NumGC: %d\n", memStats.NumGC) +} diff --git a/nexgb/examples/create-window/main.go b/nexgb/examples/create-window/main.go new file mode 100644 index 0000000..73a0099 --- /dev/null +++ b/nexgb/examples/create-window/main.go @@ -0,0 +1,107 @@ +// Example create-window shows how to create a window, map it, resize it, +// and listen to structure and key events (i.e., when the window is resized +// by the window manager, or when key presses/releases are made when the +// window has focus). The events are printed to stdout. +package main + +import ( + "fmt" + + "github.com/BurntSushi/xgb" + "github.com/BurntSushi/xgb/xproto" +) + +func main() { + X, err := xgb.NewConn() + if err != nil { + fmt.Println(err) + return + } + + // xproto.Setup retrieves the Setup information from the setup bytes + // gathered during connection. + setup := xproto.Setup(X) + + // This is the default screen with all its associated info. + screen := setup.DefaultScreen(X) + + // Any time a new resource (i.e., a window, pixmap, graphics context, etc.) + // is created, we need to generate a resource identifier. + // If the resource is a window, then use xproto.NewWindowId. If it's for + // a pixmap, then use xproto.NewPixmapId. And so on... + wid, _ := xproto.NewWindowId(X) + + // CreateWindow takes a boatload of parameters. + xproto.CreateWindow(X, screen.RootDepth, wid, screen.Root, + 0, 0, 500, 500, 0, + xproto.WindowClassInputOutput, screen.RootVisual, 0, []uint32{}) + + // This call to ChangeWindowAttributes could be factored out and + // included with the above CreateWindow call, but it is left here for + // instructive purposes. It tells X to send us events when the 'structure' + // of the window is changed (i.e., when it is resized, mapped, unmapped, + // etc.) and when a key press or a key release has been made when the + // window has focus. + // We also set the 'BackPixel' to white so that the window isn't butt ugly. + xproto.ChangeWindowAttributes(X, wid, + xproto.CwBackPixel|xproto.CwEventMask, + []uint32{ // values must be in the order defined by the protocol + 0xffffffff, + xproto.EventMaskStructureNotify | + xproto.EventMaskKeyPress | + xproto.EventMaskKeyRelease}) + + // MapWindow makes the window we've created appear on the screen. + // We demonstrated the use of a 'checked' request here. + // A checked request is a fancy way of saying, "do error handling + // synchronously." Namely, if there is a problem with the MapWindow request, + // we'll get the error *here*. If we were to do a normal unchecked + // request (like the above CreateWindow and ChangeWindowAttributes + // requests), then we would only see the error arrive in the main event + // loop. + // + // Typically, checked requests are useful when you need to make sure they + // succeed. Since they are synchronous, they incur a round trip cost before + // the program can continue, but this is only going to be noticeable if + // you're issuing tons of requests in succession. + // + // Note that requests without replies are by default unchecked while + // requests *with* replies are checked by default. + err = xproto.MapWindowChecked(X, wid).Check() + if err != nil { + fmt.Printf("Checked Error for mapping window %d: %s\n", wid, err) + } else { + fmt.Printf("Map window %d successful!\n", wid) + } + + // This is an example of an invalid MapWindow request and what an error + // looks like. + err = xproto.MapWindowChecked(X, 0).Check() + if err != nil { + fmt.Printf("Checked Error for mapping window 0x1: %s\n", err) + } else { // neva + fmt.Printf("Map window 0x1 successful!\n") + } + + // Start the main event loop. + for { + // WaitForEvent either returns an event or an error and never both. + // If both are nil, then something went wrong and the loop should be + // halted. + // + // An error can only be seen here as a response to an unchecked + // request. + ev, xerr := X.WaitForEvent() + if ev == nil && xerr == nil { + fmt.Println("Both event and error are nil. Exiting...") + return + } + + if ev != nil { + fmt.Printf("Event: %s\n", ev) + } + if xerr != nil { + fmt.Printf("Error: %s\n", xerr) + } + } +} diff --git a/nexgb/examples/doc.go b/nexgb/examples/doc.go new file mode 100644 index 0000000..80ea5b7 --- /dev/null +++ b/nexgb/examples/doc.go @@ -0,0 +1,21 @@ +/* +Package examples contains a few different use cases of XGB, like creating +a window, reading properties, and querying for information about multiple +heads using the Xinerama or RandR extensions. + +If you're looking to get started quickly, I recommend checking out the +create-window example first. It is the most documented and probably covers +some of the more common bare bones cases of creating windows and responding +to events. + +If you're looking to query information about your window manager, +get-active-window is a start. However, to do anything extensive requires +a lot of boiler plate. To that end, I'd recommend use of my higher level +library, xgbutil: https://github.com/BurntSushi/xgbutil + +There are also examples of using the Xinerama and RandR extensions, if you're +interested in querying information about your active heads. In RandR's case, +you can also reconfigure your heads, but the example doesn't cover that. + +*/ +package documentation diff --git a/nexgb/examples/get-active-window/main.go b/nexgb/examples/get-active-window/main.go new file mode 100644 index 0000000..48e020c --- /dev/null +++ b/nexgb/examples/get-active-window/main.go @@ -0,0 +1,61 @@ +// Example get-active-window reads the _NET_ACTIVE_WINDOW property of the root +// window and uses the result (a window id) to get the name of the window. +package main + +import ( + "fmt" + "log" + + "github.com/BurntSushi/xgb" + "github.com/BurntSushi/xgb/xproto" +) + +func main() { + X, err := xgb.NewConn() + if err != nil { + log.Fatal(err) + } + + // Get the window id of the root window. + setup := xproto.Setup(X) + root := setup.DefaultScreen(X).Root + + // Get the atom id (i.e., intern an atom) of "_NET_ACTIVE_WINDOW". + aname := "_NET_ACTIVE_WINDOW" + activeAtom, err := xproto.InternAtom(X, true, uint16(len(aname)), + aname).Reply() + if err != nil { + log.Fatal(err) + } + + // Get the atom id (i.e., intern an atom) of "_NET_WM_NAME". + aname = "_NET_WM_NAME" + nameAtom, err := xproto.InternAtom(X, true, uint16(len(aname)), + aname).Reply() + if err != nil { + log.Fatal(err) + } + + // Get the actual value of _NET_ACTIVE_WINDOW. + // Note that 'reply.Value' is just a slice of bytes, so we use an + // XGB helper function, 'Get32', to pull an unsigned 32-bit integer out + // of the byte slice. We then convert it to an X resource id so it can + // be used to get the name of the window in the next GetProperty request. + reply, err := xproto.GetProperty(X, false, root, activeAtom.Atom, + xproto.GetPropertyTypeAny, 0, (1<<32)-1).Reply() + if err != nil { + log.Fatal(err) + } + windowId := xproto.Window(xgb.Get32(reply.Value)) + fmt.Printf("Active window id: %X\n", windowId) + + // Now get the value of _NET_WM_NAME for the active window. + // Note that this time, we simply convert the resulting byte slice, + // reply.Value, to a string. + reply, err = xproto.GetProperty(X, false, windowId, nameAtom.Atom, + xproto.GetPropertyTypeAny, 0, (1<<32)-1).Reply() + if err != nil { + log.Fatal(err) + } + fmt.Printf("Active window name: %s\n", string(reply.Value)) +} diff --git a/nexgb/examples/randr/main.go b/nexgb/examples/randr/main.go new file mode 100644 index 0000000..e349144 --- /dev/null +++ b/nexgb/examples/randr/main.go @@ -0,0 +1,92 @@ +// Example randr uses the randr protocol to get information about the active +// heads. It also listens for events that are sent when the head configuration +// changes. Since it listens to events, you'll have to manually kill this +// process when you're done (i.e., ctrl+c.) +// +// While this program is running, if you use 'xrandr' to reconfigure your +// heads, you should see event information dumped to standard out. +// +// For more information, please see the RandR protocol spec: +// http://www.x.org/releases/X11R7.6/doc/randrproto/randrproto.txt +package main + +import ( + "fmt" + "log" + + "github.com/BurntSushi/xgb" + "github.com/BurntSushi/xgb/randr" + "github.com/BurntSushi/xgb/xproto" +) + +func main() { + X, _ := xgb.NewConn() + + // Every extension must be initialized before it can be used. + err := randr.Init(X) + if err != nil { + log.Fatal(err) + } + + // Get the root window on the default screen. + root := xproto.Setup(X).DefaultScreen(X).Root + + // Gets the current screen resources. Screen resources contains a list + // of names, crtcs, outputs and modes, among other things. + resources, err := randr.GetScreenResources(X, root).Reply() + if err != nil { + log.Fatal(err) + } + + // Iterate through all of the outputs and show some of their info. + for _, output := range resources.Outputs { + info, err := randr.GetOutputInfo(X, output, 0).Reply() + if err != nil { + log.Fatal(err) + } + + if info.Connection == randr.ConnectionConnected { + bestMode := info.Modes[0] + for _, mode := range resources.Modes { + if mode.Id == uint32(bestMode) { + fmt.Printf("Width: %d, Height: %d\n", + mode.Width, mode.Height) + } + } + } + } + + fmt.Println("\n") + + // Iterate through all of the crtcs and show some of their info. + for _, crtc := range resources.Crtcs { + info, err := randr.GetCrtcInfo(X, crtc, 0).Reply() + if err != nil { + log.Fatal(err) + } + fmt.Printf("X: %d, Y: %d, Width: %d, Height: %d\n", + info.X, info.Y, info.Width, info.Height) + } + + // Tell RandR to send us events. (I think these are all of them, as of 1.3.) + err = randr.SelectInputChecked(X, root, + randr.NotifyMaskScreenChange| + randr.NotifyMaskCrtcChange| + randr.NotifyMaskOutputChange| + randr.NotifyMaskOutputProperty).Check() + if err != nil { + log.Fatal(err) + } + + // Listen to events and just dump them to standard out. + // A more involved approach will have to read the 'U' field of + // RandrNotifyEvent, which is a union (really a struct) of type + // RanrNotifyDataUnion. + for { + ev, err := X.WaitForEvent() + if err != nil { + log.Fatal(err) + } + fmt.Println(ev) + } +} diff --git a/nexgb/examples/xinerama/main.go b/nexgb/examples/xinerama/main.go new file mode 100644 index 0000000..896bb63 --- /dev/null +++ b/nexgb/examples/xinerama/main.go @@ -0,0 +1,40 @@ +// Example xinerama shows how to query the geometry of all active heads. +package main + +import ( + "fmt" + "log" + + "github.com/BurntSushi/xgb" + "github.com/BurntSushi/xgb/xinerama" +) + +func main() { + X, err := xgb.NewConn() + if err != nil { + log.Fatal(err) + } + + // Initialize the Xinerama extension. + // The appropriate 'Init' function must be run for *every* + // extension before any of its requests can be used. + err = xinerama.Init(X) + if err != nil { + log.Fatal(err) + } + + // Issue a request to get the screen information. + reply, err := xinerama.QueryScreens(X).Reply() + if err != nil { + log.Fatal(err) + } + + // reply.Number is the number of active heads, while reply.ScreenInfo + // is a slice of XineramaScreenInfo containing the rectangle geometry + // of each head. + fmt.Printf("Number of heads: %d\n", reply.Number) + for i, screen := range reply.ScreenInfo { + fmt.Printf("%d :: X: %d, Y: %d, Width: %d, Height: %d\n", + i, screen.XOrg, screen.YOrg, screen.Width, screen.Height) + } +} |