From a5d4ad6c9d763b3d3f797075038023756c38bb28 Mon Sep 17 00:00:00 2001 From: "Andrew Gallant (Ocelot)" Date: Thu, 3 May 2012 22:47:50 -0400 Subject: reworking xgb. cleaned up connection stuff a little. making new xid generation cleaner and use goroutines for it. --- nexgb/examples/atom.go | 27 +++++++++++++++++++++++++++ nexgb/examples/property.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 nexgb/examples/atom.go create mode 100644 nexgb/examples/property.go (limited to 'nexgb/examples') diff --git a/nexgb/examples/atom.go b/nexgb/examples/atom.go new file mode 100644 index 0000000..c64acee --- /dev/null +++ b/nexgb/examples/atom.go @@ -0,0 +1,27 @@ +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) + if err != nil { + log.Fatal(err) + } + log.Printf("%d", atom.Atom) +} + diff --git a/nexgb/examples/property.go b/nexgb/examples/property.go new file mode 100644 index 0000000..2477df4 --- /dev/null +++ b/nexgb/examples/property.go @@ -0,0 +1,39 @@ +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) + if err != nil { + log.Fatal(err) + } + + reply, err := X.GetProperty(false, root, atom.Atom, xgb.GetPropertyTypeAny, + 0, (1<<32)-1) + log.Printf("%X", get32(reply.Value)) +} + -- cgit v1.2.3 From 369ad0d33e51035a3e48436fc85f60130b201437 Mon Sep 17 00:00:00 2001 From: "Andrew Gallant (Ocelot)" Date: Sat, 5 May 2012 18:22:24 -0400 Subject: extensions are working! extensions are working! --- nexgb/examples/atom.go | 2 +- nexgb/examples/property.go | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'nexgb/examples') diff --git a/nexgb/examples/atom.go b/nexgb/examples/atom.go index c64acee..2cb7132 100644 --- a/nexgb/examples/atom.go +++ b/nexgb/examples/atom.go @@ -18,7 +18,7 @@ func main() { } aname := "_NET_ACTIVE_WINDOW" - atom, err := X.InternAtom(true, uint16(len(aname)), aname) + atom, err := X.InternAtom(true, uint16(len(aname)), aname).Reply() if err != nil { log.Fatal(err) } diff --git a/nexgb/examples/property.go b/nexgb/examples/property.go index 2477df4..45144c7 100644 --- a/nexgb/examples/property.go +++ b/nexgb/examples/property.go @@ -27,13 +27,15 @@ func main() { root := X.DefaultScreen().Root aname := "_NET_ACTIVE_WINDOW" - atom, err := X.InternAtom(true, uint16(len(aname)), aname) + 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, 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)) } - -- cgit v1.2.3 From 99bc76de54729df5494faa944d4da96a8885d51e Mon Sep 17 00:00:00 2001 From: "Andrew Gallant (Ocelot)" Date: Sat, 5 May 2012 18:22:40 -0400 Subject: examples. some should be tests --- nexgb/examples/randr.go | 48 ++++++++++++++++++++++++++++++++++ nexgb/examples/seq-nowrap.go | 29 +++++++++++++++++++++ nexgb/examples/seq-wrap.go | 24 +++++++++++++++++ nexgb/examples/window.go | 61 ++++++++++++++++++++++++++++++++++++++++++++ nexgb/examples/xinerama.go | 29 +++++++++++++++++++++ 5 files changed, 191 insertions(+) create mode 100644 nexgb/examples/randr.go create mode 100644 nexgb/examples/seq-nowrap.go create mode 100644 nexgb/examples/seq-wrap.go create mode 100644 nexgb/examples/window.go create mode 100644 nexgb/examples/xinerama.go (limited to 'nexgb/examples') diff --git a/nexgb/examples/randr.go b/nexgb/examples/randr.go new file mode 100644 index 0000000..064856d --- /dev/null +++ b/nexgb/examples/randr.go @@ -0,0 +1,48 @@ +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) + } +} + diff --git a/nexgb/examples/seq-nowrap.go b/nexgb/examples/seq-nowrap.go new file mode 100644 index 0000000..994a07b --- /dev/null +++ b/nexgb/examples/seq-nowrap.go @@ -0,0 +1,29 @@ +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) + } + } +} + diff --git a/nexgb/examples/seq-wrap.go b/nexgb/examples/seq-wrap.go new file mode 100644 index 0000000..b5bc834 --- /dev/null +++ b/nexgb/examples/seq-wrap.go @@ -0,0 +1,24 @@ +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) + } + } +} + diff --git a/nexgb/examples/window.go b/nexgb/examples/window.go new file mode 100644 index 0000000..68fe27b --- /dev/null +++ b/nexgb/examples/window.go @@ -0,0 +1,61 @@ +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) + } + } + } +} + diff --git a/nexgb/examples/xinerama.go b/nexgb/examples/xinerama.go new file mode 100644 index 0000000..7fe9984 --- /dev/null +++ b/nexgb/examples/xinerama.go @@ -0,0 +1,29 @@ +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) + } +} + -- cgit v1.2.3 From dc48249e1acea54b391f53b95f16e515dead7c97 Mon Sep 17 00:00:00 2001 From: "Andrew Gallant (Ocelot)" Date: Mon, 7 May 2012 04:09:19 -0400 Subject: lots of docs and examples --- nexgb/examples/atom.go | 27 --------- nexgb/examples/create-window/main.go | 98 ++++++++++++++++++++++++++++++++ nexgb/examples/doc.go | 21 +++++++ nexgb/examples/get-active-window/main.go | 57 +++++++++++++++++++ nexgb/examples/property.go | 41 ------------- nexgb/examples/randr.go | 48 ---------------- nexgb/examples/randr/main.go | 84 +++++++++++++++++++++++++++ nexgb/examples/seq-nowrap.go | 29 ---------- nexgb/examples/seq-wrap.go | 24 -------- nexgb/examples/window.go | 61 -------------------- nexgb/examples/xinerama.go | 29 ---------- nexgb/examples/xinerama/main.go | 39 +++++++++++++ 12 files changed, 299 insertions(+), 259 deletions(-) delete mode 100644 nexgb/examples/atom.go create mode 100644 nexgb/examples/create-window/main.go create mode 100644 nexgb/examples/doc.go create mode 100644 nexgb/examples/get-active-window/main.go delete mode 100644 nexgb/examples/property.go delete mode 100644 nexgb/examples/randr.go create mode 100644 nexgb/examples/randr/main.go delete mode 100644 nexgb/examples/seq-nowrap.go delete mode 100644 nexgb/examples/seq-wrap.go delete mode 100644 nexgb/examples/window.go delete mode 100644 nexgb/examples/xinerama.go create mode 100644 nexgb/examples/xinerama/main.go (limited to 'nexgb/examples') diff --git a/nexgb/examples/atom.go b/nexgb/examples/atom.go deleted file mode 100644 index 2cb7132..0000000 --- a/nexgb/examples/atom.go +++ /dev/null @@ -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) -} - diff --git a/nexgb/examples/create-window/main.go b/nexgb/examples/create-window/main.go new file mode 100644 index 0000000..6996f37 --- /dev/null +++ b/nexgb/examples/create-window/main.go @@ -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) + } + } +} 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..e90563c --- /dev/null +++ b/nexgb/examples/get-active-window/main.go @@ -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)) +} diff --git a/nexgb/examples/property.go b/nexgb/examples/property.go deleted file mode 100644 index 45144c7..0000000 --- a/nexgb/examples/property.go +++ /dev/null @@ -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)) -} diff --git a/nexgb/examples/randr.go b/nexgb/examples/randr.go deleted file mode 100644 index 064856d..0000000 --- a/nexgb/examples/randr.go +++ /dev/null @@ -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) - } -} - diff --git a/nexgb/examples/randr/main.go b/nexgb/examples/randr/main.go new file mode 100644 index 0000000..5c56609 --- /dev/null +++ b/nexgb/examples/randr/main.go @@ -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) + } +} diff --git a/nexgb/examples/seq-nowrap.go b/nexgb/examples/seq-nowrap.go deleted file mode 100644 index 994a07b..0000000 --- a/nexgb/examples/seq-nowrap.go +++ /dev/null @@ -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) - } - } -} - diff --git a/nexgb/examples/seq-wrap.go b/nexgb/examples/seq-wrap.go deleted file mode 100644 index b5bc834..0000000 --- a/nexgb/examples/seq-wrap.go +++ /dev/null @@ -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) - } - } -} - diff --git a/nexgb/examples/window.go b/nexgb/examples/window.go deleted file mode 100644 index 68fe27b..0000000 --- a/nexgb/examples/window.go +++ /dev/null @@ -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) - } - } - } -} - diff --git a/nexgb/examples/xinerama.go b/nexgb/examples/xinerama.go deleted file mode 100644 index 7fe9984..0000000 --- a/nexgb/examples/xinerama.go +++ /dev/null @@ -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) - } -} - diff --git a/nexgb/examples/xinerama/main.go b/nexgb/examples/xinerama/main.go new file mode 100644 index 0000000..ec7f46a --- /dev/null +++ b/nexgb/examples/xinerama/main.go @@ -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) + } +} -- cgit v1.2.3 From 0c50dc6241fa21712e041cfa2bfb9db4ccaef10a Mon Sep 17 00:00:00 2001 From: "Andrew Gallant (Ocelot)" Date: Thu, 10 May 2012 17:01:42 -0400 Subject: a huge commit. splitting extensions into their own sub-packages. --- nexgb/examples/create-window/main.go | 33 ++++++++++++++++++++------------ nexgb/examples/get-active-window/main.go | 20 +++++++++++-------- nexgb/examples/randr/main.go | 23 +++++++++++++--------- nexgb/examples/xinerama/main.go | 5 +++-- 4 files changed, 50 insertions(+), 31 deletions(-) (limited to 'nexgb/examples') diff --git a/nexgb/examples/create-window/main.go b/nexgb/examples/create-window/main.go index 6996f37..73a0099 100644 --- a/nexgb/examples/create-window/main.go +++ b/nexgb/examples/create-window/main.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/BurntSushi/xgb" + "github.com/BurntSushi/xgb/xproto" ) func main() { @@ -17,15 +18,23 @@ func main() { 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 with NewId. - wid, _ := X.NewId() + // 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. - X.CreateWindow(X.DefaultScreen().RootDepth, wid, X.DefaultScreen().Root, + xproto.CreateWindow(X, screen.RootDepth, wid, screen.Root, 0, 0, 500, 500, 0, - xgb.WindowClassInputOutput, X.DefaultScreen().RootVisual, - 0, []uint32{}) + 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 @@ -34,13 +43,13 @@ func main() { // 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, + xproto.ChangeWindowAttributes(X, wid, + xproto.CwBackPixel|xproto.CwEventMask, []uint32{ // values must be in the order defined by the protocol 0xffffffff, - xgb.EventMaskStructureNotify | - xgb.EventMaskKeyPress | - xgb.EventMaskKeyRelease}) + 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. @@ -58,7 +67,7 @@ func main() { // // Note that requests without replies are by default unchecked while // requests *with* replies are checked by default. - err = X.MapWindowChecked(wid).Check() + err = xproto.MapWindowChecked(X, wid).Check() if err != nil { fmt.Printf("Checked Error for mapping window %d: %s\n", wid, err) } else { @@ -67,7 +76,7 @@ func main() { // This is an example of an invalid MapWindow request and what an error // looks like. - err = X.MapWindowChecked(0).Check() + err = xproto.MapWindowChecked(X, 0).Check() if err != nil { fmt.Printf("Checked Error for mapping window 0x1: %s\n", err) } else { // neva diff --git a/nexgb/examples/get-active-window/main.go b/nexgb/examples/get-active-window/main.go index e90563c..48e020c 100644 --- a/nexgb/examples/get-active-window/main.go +++ b/nexgb/examples/get-active-window/main.go @@ -7,6 +7,7 @@ import ( "log" "github.com/BurntSushi/xgb" + "github.com/BurntSushi/xgb/xproto" ) func main() { @@ -16,18 +17,21 @@ func main() { } // Get the window id of the root window. - root := X.DefaultScreen().Root + 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 := X.InternAtom(true, uint16(len(aname)), aname).Reply() + 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 := X.InternAtom(true, uint16(len(aname)), aname).Reply() + nameAtom, err := xproto.InternAtom(X, true, uint16(len(aname)), + aname).Reply() if err != nil { log.Fatal(err) } @@ -37,19 +41,19 @@ func main() { // 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() + reply, err := xproto.GetProperty(X, false, root, activeAtom.Atom, + xproto.GetPropertyTypeAny, 0, (1<<32)-1).Reply() if err != nil { log.Fatal(err) } - windowId := xgb.Id(xgb.Get32(reply.Value)) + 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 = X.GetProperty(false, windowId, nameAtom.Atom, - xgb.GetPropertyTypeAny, 0, (1<<32)-1).Reply() + reply, err = xproto.GetProperty(X, false, windowId, nameAtom.Atom, + xproto.GetPropertyTypeAny, 0, (1<<32)-1).Reply() if err != nil { log.Fatal(err) } diff --git a/nexgb/examples/randr/main.go b/nexgb/examples/randr/main.go index 5c56609..ad575ee 100644 --- a/nexgb/examples/randr/main.go +++ b/nexgb/examples/randr/main.go @@ -15,27 +15,32 @@ import ( "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 := X.RandrInit() + 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 := X.RandrGetScreenResources(X.DefaultScreen().Root).Reply() + 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 := X.RandrGetOutputInfo(output, 0).Reply() + info, err := randr.GetOutputInfo(X, output, 0).Reply() if err != nil { log.Fatal(err) } @@ -52,7 +57,7 @@ func main() { // Iterate through all of the crtcs and show some of their info. for _, crtc := range resources.Crtcs { - info, err := X.RandrGetCrtcInfo(crtc, 0).Reply() + info, err := randr.GetCrtcInfo(X, crtc, 0).Reply() if err != nil { log.Fatal(err) } @@ -61,11 +66,11 @@ func main() { } // 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() + err = randr.SelectInputChecked(X, root, + randr.NotifyMaskScreenChange| + randr.NotifyMaskCrtcChange| + randr.NotifyMaskOutputChange| + randr.NotifyMaskOutputProperty).Check() if err != nil { log.Fatal(err) } diff --git a/nexgb/examples/xinerama/main.go b/nexgb/examples/xinerama/main.go index ec7f46a..896bb63 100644 --- a/nexgb/examples/xinerama/main.go +++ b/nexgb/examples/xinerama/main.go @@ -6,6 +6,7 @@ import ( "log" "github.com/BurntSushi/xgb" + "github.com/BurntSushi/xgb/xinerama" ) func main() { @@ -17,13 +18,13 @@ func main() { // 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() + err = xinerama.Init(X) if err != nil { log.Fatal(err) } // Issue a request to get the screen information. - reply, err := X.XineramaQueryScreens().Reply() + reply, err := xinerama.QueryScreens(X).Reply() if err != nil { log.Fatal(err) } -- cgit v1.2.3 From 8ee0ea98997eaa967f862da029cc04e5ae18b90e Mon Sep 17 00:00:00 2001 From: "Andrew Gallant (Ocelot)" Date: Sat, 2 Jun 2012 12:59:44 -0400 Subject: A pathological example for profiling purposes. Use 'make test'. --- nexgb/examples/atoms/.gitignore | 3 ++ nexgb/examples/atoms/Makefile | 12 ++++++ nexgb/examples/atoms/main.go | 91 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 nexgb/examples/atoms/.gitignore create mode 100644 nexgb/examples/atoms/Makefile create mode 100644 nexgb/examples/atoms/main.go (limited to 'nexgb/examples') 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) +} -- cgit v1.2.3 From 64c6e6170d86dd4b18d04c49888a6b8ac472c4d6 Mon Sep 17 00:00:00 2001 From: snyh Date: Mon, 30 Dec 2013 16:58:14 +0800 Subject: example/randr: check the GetOutputInfo's mode length (virtual head can have zero mode) --- nexgb/examples/randr/main.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'nexgb/examples') diff --git a/nexgb/examples/randr/main.go b/nexgb/examples/randr/main.go index ad575ee..427aed6 100644 --- a/nexgb/examples/randr/main.go +++ b/nexgb/examples/randr/main.go @@ -45,10 +45,12 @@ func main() { 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) + if len(info.Modes) > 0 { + 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) + } } } } -- cgit v1.2.3 From 1f8bd79abee5d96a41a934d1eb8c74e90ccbcc8f Mon Sep 17 00:00:00 2001 From: snyh Date: Tue, 31 Dec 2013 09:20:13 +0800 Subject: examples:randr use info.Connection to detect whether there has any Randr.Modes --- nexgb/examples/randr/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nexgb/examples') diff --git a/nexgb/examples/randr/main.go b/nexgb/examples/randr/main.go index 427aed6..414ef8d 100644 --- a/nexgb/examples/randr/main.go +++ b/nexgb/examples/randr/main.go @@ -45,7 +45,7 @@ func main() { log.Fatal(err) } - if len(info.Modes) > 0 { + if info.Connection == randr.ConnectionConnected { bestMode := info.Modes[0] for _, mode := range resources.Modes { if mode.Id == uint32(bestMode) { -- cgit v1.2.3 From a548d9d0f7b889627c43b18811357fad88760b2d Mon Sep 17 00:00:00 2001 From: aarzilli Date: Fri, 2 May 2014 15:09:23 +0200 Subject: Fix Issue #21: automatic calculation of alignment padding after lists --- nexgb/examples/randr/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nexgb/examples') diff --git a/nexgb/examples/randr/main.go b/nexgb/examples/randr/main.go index 414ef8d..ac6fb7a 100644 --- a/nexgb/examples/randr/main.go +++ b/nexgb/examples/randr/main.go @@ -63,7 +63,7 @@ func main() { if err != nil { log.Fatal(err) } - fmt.Printf("X: %d, Y: %d, Width: %d, Height: %d\n", + fmt.Printf("%v, X: %d, Y: %d, Width: %d, Height: %d\n", info.X, info.Y, info.Width, info.Height) } -- cgit v1.2.3 From ef8155bf17787473a58f00d54cfc8a7e16ee8708 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Sat, 10 May 2014 11:41:51 -0400 Subject: Formatting and 80 cols. --- nexgb/examples/randr/main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'nexgb/examples') diff --git a/nexgb/examples/randr/main.go b/nexgb/examples/randr/main.go index ac6fb7a..01ad594 100644 --- a/nexgb/examples/randr/main.go +++ b/nexgb/examples/randr/main.go @@ -49,7 +49,8 @@ func main() { 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.Printf("Width: %d, Height: %d\n", + mode.Width, mode.Height) } } } -- cgit v1.2.3 From 1f83ea75a2972ad9749edf188211f31517170854 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sun, 22 May 2016 14:13:31 +0200 Subject: Remove stray format char in randr example --- nexgb/examples/randr/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nexgb/examples') diff --git a/nexgb/examples/randr/main.go b/nexgb/examples/randr/main.go index 01ad594..e349144 100644 --- a/nexgb/examples/randr/main.go +++ b/nexgb/examples/randr/main.go @@ -64,7 +64,7 @@ func main() { if err != nil { log.Fatal(err) } - fmt.Printf("%v, X: %d, Y: %d, Width: %d, Height: %d\n", + fmt.Printf("X: %d, Y: %d, Width: %d, Height: %d\n", info.X, info.Y, info.Width, info.Height) } -- cgit v1.2.3