lots of docs and examples

This commit is contained in:
Andrew Gallant (Ocelot)
2012-05-07 04:09:19 -04:00
parent 3bf376bd66
commit dc48249e1a
27 changed files with 495 additions and 305 deletions

View File

@@ -1,27 +0,0 @@
package main
import (
// "fmt"
"log"
"github.com/BurntSushi/xgb"
)
func init() {
log.SetFlags(0)
}
func main() {
X, err := xgb.NewConn()
if err != nil {
log.Fatal(err)
}
aname := "_NET_ACTIVE_WINDOW"
atom, err := X.InternAtom(true, uint16(len(aname)), aname).Reply()
if err != nil {
log.Fatal(err)
}
log.Printf("%d", atom.Atom)
}

View File

@@ -0,0 +1,98 @@
// 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"
)
func main() {
X, err := xgb.NewConn()
if err != nil {
fmt.Println(err)
return
}
// Any time a new resource (i.e., a window, pixmap, graphics context, etc.)
// is created, we need to generate a resource identifier with NewId.
wid, _ := X.NewId()
// CreateWindow takes a boatload of parameters.
X.CreateWindow(X.DefaultScreen().RootDepth, wid, X.DefaultScreen().Root,
0, 0, 500, 500, 0,
xgb.WindowClassInputOutput, X.DefaultScreen().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.
X.ChangeWindowAttributes(wid,
xgb.CwBackPixel|xgb.CwEventMask,
[]uint32{ // values must be in the order defined by the protocol
0xffffffff,
xgb.EventMaskStructureNotify |
xgb.EventMaskKeyPress |
xgb.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 = X.MapWindowChecked(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 = X.MapWindowChecked(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)
}
}
}

21
nexgb/examples/doc.go Normal file
View File

@@ -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

View File

@@ -0,0 +1,57 @@
// 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"
)
func main() {
X, err := xgb.NewConn()
if err != nil {
log.Fatal(err)
}
// Get the window id of the root window.
root := X.DefaultScreen().Root
// Get the atom id (i.e., intern an atom) of "_NET_ACTIVE_WINDOW".
aname := "_NET_ACTIVE_WINDOW"
activeAtom, err := X.InternAtom(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 := X.InternAtom(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 := X.GetProperty(false, root, activeAtom.Atom,
xgb.GetPropertyTypeAny, 0, (1<<32)-1).Reply()
if err != nil {
log.Fatal(err)
}
windowId := xgb.Id(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 = X.GetProperty(false, windowId, nameAtom.Atom,
xgb.GetPropertyTypeAny, 0, (1<<32)-1).Reply()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Active window name: %s\n", string(reply.Value))
}

View File

@@ -1,41 +0,0 @@
package main
import (
"log"
"github.com/BurntSushi/xgb"
)
func init() {
log.SetFlags(0)
}
func get32(buf []byte) uint32 {
v := uint32(buf[0])
v |= uint32(buf[1]) << 8
v |= uint32(buf[2]) << 16
v |= uint32(buf[3]) << 24
return v
}
func main() {
X, err := xgb.NewConn()
if err != nil {
log.Fatal(err)
}
root := X.DefaultScreen().Root
aname := "_NET_ACTIVE_WINDOW"
atom, err := X.InternAtom(true, uint16(len(aname)), aname).Reply()
if err != nil {
log.Fatal(err)
}
reply, err := X.GetProperty(false, root, atom.Atom,
xgb.GetPropertyTypeAny, 0, (1<<32)-1).Reply()
if err != nil {
log.Fatal(err)
}
log.Printf("%X", get32(reply.Value))
}

View File

@@ -1,48 +0,0 @@
package main
import (
"fmt"
"log"
"github.com/BurntSushi/xgb"
)
func main() {
X, _ := xgb.NewConn()
err := X.RegisterExtension("randr")
if err != nil {
log.Fatal(err)
}
resources, err := X.RandrGetScreenResources(X.DefaultScreen().Root).Reply()
if err != nil {
log.Fatal(err)
}
for _, output := range resources.Outputs {
info, err := X.RandrGetOutputInfo(output, 0).Reply()
if err != nil {
log.Fatal(err)
}
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")
for _, crtc := range resources.Crtcs {
info, err := X.RandrGetCrtcInfo(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)
}
}

View File

@@ -0,0 +1,84 @@
// 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"
)
func main() {
X, _ := xgb.NewConn()
// Every extension must be initialized before it can be used.
err := X.RandrInit()
if err != nil {
log.Fatal(err)
}
// Gets the current screen resources. Screen resources contains a list
// of names, crtcs, outputs and modes, among other things.
resources, err := X.RandrGetScreenResources(X.DefaultScreen().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 := X.RandrGetOutputInfo(output, 0).Reply()
if err != nil {
log.Fatal(err)
}
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 := X.RandrGetCrtcInfo(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 = X.RandrSelectInputChecked(X.DefaultScreen().Root,
xgb.RandrNotifyMaskScreenChange|
xgb.RandrNotifyMaskCrtcChange|
xgb.RandrNotifyMaskOutputChange|
xgb.RandrNotifyMaskOutputProperty).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)
}
}

View File

@@ -1,29 +0,0 @@
package main
import (
"fmt"
"github.com/BurntSushi/xgb"
)
func main() {
X, _ := xgb.NewConn()
for i := 1; i <= 1<<16 + 10; i++ {
X.NoOperation()
// fmt.Printf("%d. No-Op\n", i)
}
aname := "_NET_ACTIVE_WINDOW"
for i := 1; i <= 10; i++ {
atom, err := X.InternAtom(true, uint16(len(aname)), aname).Reply()
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("%d. Sequence: %d, Atom: %d\n",
i, atom.Sequence, atom.Atom)
}
}
}

View File

@@ -1,24 +0,0 @@
package main
import (
"fmt"
"github.com/BurntSushi/xgb"
)
func main() {
X, _ := xgb.NewConn()
aname := "_NET_ACTIVE_WINDOW"
for i := 1; i <= 1<<16 + 10; i++ {
atom, err := X.InternAtom(true, uint16(len(aname)), aname).Reply()
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("%d. Sequence: %d, Atom: %d\n",
i, atom.Sequence, atom.Atom)
}
}
}

View File

@@ -1,61 +0,0 @@
package main
import (
"fmt"
"log"
"github.com/BurntSushi/xgb"
)
func main() {
X, err := xgb.NewConn()
if err != nil {
log.Fatal(err)
}
wid, _ := X.NewId()
X.CreateWindow(X.DefaultScreen().RootDepth, wid, X.DefaultScreen().Root,
0, 0, 500, 500, 0,
xgb.WindowClassInputOutput, X.DefaultScreen().RootVisual,
0, []uint32{})
X.ChangeWindowAttributes(wid, xgb.CwEventMask | xgb.CwBackPixel,
[]uint32{0xffffffff, xgb.EventMaskKeyPress | xgb.EventMaskKeyRelease})
err = X.MapWindowChecked(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)
}
err = X.MapWindowChecked(0x1).Check()
if err != nil {
fmt.Printf("Checked Error for mapping window 0x1: %s\n", err)
} else {
fmt.Printf("Map window 0x1 successful!\n")
}
for {
ev, xerr := X.WaitForEvent()
if ev == nil && xerr == nil {
log.Fatal("Both event and error are nil. Exiting...")
}
if ev != nil {
fmt.Printf("Event: %s\n", ev)
}
if xerr != nil {
fmt.Printf("Error: %s\n", xerr)
}
if xerr == nil {
geom, err := X.GetGeometry(0x1).Reply()
if err != nil {
fmt.Printf("Geom Error: %#v\n", err)
} else {
fmt.Printf("Geometry: %#v\n", geom)
}
}
}
}

View File

@@ -1,29 +0,0 @@
package main
import (
"fmt"
"log"
"github.com/BurntSushi/xgb"
)
func main() {
X, _ := xgb.NewConn()
err := X.RegisterExtension("xinerama")
if err != nil {
log.Fatal(err)
}
reply, err := X.XineramaQueryScreens().Reply()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Xinerama number: %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)
}
}

View File

@@ -0,0 +1,39 @@
// Example xinerama shows how to query the geometry of all active heads.
package main
import (
"fmt"
"log"
"github.com/BurntSushi/xgb"
)
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 = X.XineramaInit()
if err != nil {
log.Fatal(err)
}
// Issue a request to get the screen information.
reply, err := X.XineramaQueryScreens().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)
}
}