diff options
author | Přemysl Janouch <p@janouch.name> | 2018-09-08 16:54:17 +0200 |
---|---|---|
committer | Přemysl Janouch <p@janouch.name> | 2018-09-08 16:54:17 +0200 |
commit | 3173202cc1e08762c6e156a8fffd23269a5ddb2b (patch) | |
tree | 95c4a06f8384d41b15e9c22afac0a387de79dc51 /nexgb/examples | |
parent | 632b3ae494d45755525644fe5d04475c95aae364 (diff) | |
parent | 3906399e7c2a40fbaf355de572cf50a314083f64 (diff) | |
download | haven-3173202cc1e08762c6e156a8fffd23269a5ddb2b.tar.gz haven-3173202cc1e08762c6e156a8fffd23269a5ddb2b.tar.xz haven-3173202cc1e08762c6e156a8fffd23269a5ddb2b.zip |
Merge aarzilli/xgb, branch xcb1.12 as nexgb
History has been linearized and rewritten to stay under the new
subdirectory. I want to make changes incompatible to BurntSushi/xgb.
The history begs for being thrown away entirely because of its quality
and because it doesn't cover the Google period but it is still useful
for copyright tracking.
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) + } +} |