aboutsummaryrefslogtreecommitdiff
path: root/nexgb/examples
diff options
context:
space:
mode:
Diffstat (limited to 'nexgb/examples')
-rw-r--r--nexgb/examples/atoms/.gitignore3
-rw-r--r--nexgb/examples/atoms/Makefile12
-rw-r--r--nexgb/examples/atoms/main.go91
-rw-r--r--nexgb/examples/create-window/main.go107
-rw-r--r--nexgb/examples/doc.go21
-rw-r--r--nexgb/examples/get-active-window/main.go61
-rw-r--r--nexgb/examples/randr/main.go92
-rw-r--r--nexgb/examples/xinerama/main.go40
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)
+ }
+}