[ANN] X Go Binding and xgbutil

1,039 views
Skip to first unread message

Andrew Gallant

unread,
May 26, 2012, 7:06:28 PM5/26/12
to golan...@googlegroups.com
Hello fellow gophers!

For the past couple of months, I've been working on the X Go Binding
(XGB) [1] and a purported nice-to-use abstraction library called
xgbutil [2]. There was a
previous XGB library [3], but I've forked it and rewritten most of the
code. I've also replaced the Python code generator with xgbgen [4],
which is written in Go.

If you've worked with XCB before, you should feel right at home with
XGB. Its API is extremely similar.

XGB is thread safe and can benefit from parallelism automatically.
Goroutines were awesome for this!

XGB also has compilable Go source code for many X extensions
except for XKB. I am unsure of whether or not they all work, but so
far, RandR and Xinerama are certainly working.

Both XGB and xgbutil are heavily documented [5,6] and contain several examples.

The more important bit of this announcement, I think, is xgbutil. It
is designed to make your life working with X a *little* bit easier,
although it will not completely remove the need to interact with XGB
directly. xgbutil will allow you to create windows easily, resize them
and query the currently running window manager for information (number
of desktops, top-level clients, workarea, and so on) using the EWMH
and ICCCM standards. xgbutil also provides an implementation of a main
X event loop that acts as a dispatcher to callback functions attached
to events (i.e., key and mouse bindings, ConfigureNotify events, and
so on). The other big piece of xgbutil is the xgraphics package, which
allows one to paint any image.Image to an X window.

There are several heavily documented examples for xgbutil that I think
anyone can get started with. [7] Chief among them: changing the mouse
cursor, drawing text, compressing events, key/mouse bindings, getting
client names/geometry, taking a screenshot and various examples
showing how to paint images to windows.

If you'd like to try any of the examples, they are all go gettable.
One that might be fun to try:

go get github.com/BurntSushi/xgbutil/examples/pointer-painting
go/path/bin/pointer-painting

And use your mouse's left button to paint squares. Use the mouse's
right button for an easter egg :-)

Finally, I've written a very simple image viewer [8] as a small
demonstration of what xgbutil can do. To install:

go get github.com/BurntSushi/imgv
go/path/bin/imgv some-image.png

Another example usage: xgbutil is used in John Asmuth's go.uik for the
XGB backend.

Many thanks go out to the original developers of XGB and the
developers of freetype-go and graphics-go. Their work made my job much
easier. :-)

I welcome any comments or criticisms!

- Andrew

P.S. A window manager [9] is also in the pipeline :-)

[1] - https://github.com/BurntSushi/xgb
[2] - https://github.com/BurntSushi/xgbutil
[3] - http://code.google.com/p/x-go-binding/
[4] - http://godoc.burntsushi.net/pkg/github.com/BurntSushi/xgb/xgbgen/
[5] - http://godoc.burntsushi.net/pkg/github.com/BurntSushi/xgb/
[6] - http://godoc.burntsushi.net/pkg/github.com/BurntSushi/xgbutil/
[7] - http://godoc.burntsushi.net/pkg/github.com/BurntSushi/xgbutil/examples/
[8] - https://github.com/BurntSushi/imgv
[9] - https://github.com/BurntSushi/wingo

Daniel Jo

unread,
May 26, 2012, 8:05:39 PM5/26/12
to Andrew Gallant, golan...@googlegroups.com

A very welcome effort! My weekend is now booked! :)

-Daniel

Anthony Martin

unread,
May 26, 2012, 9:09:37 PM5/26/12
to Andrew Gallant, golan...@googlegroups.com
What made you decide to fork and rewrite?

Anthony

Nigel Tao

unread,
May 27, 2012, 12:20:33 AM5/27/12
to Andrew Gallant, golan...@googlegroups.com
On 27 May 2012 09:06, Andrew Gallant <jam...@gmail.com> wrote:
> For the past couple of months, I've been working on the X Go Binding
> (XGB) [1] and a purported nice-to-use abstraction library called
> xgbutil [2]. There was a
> previous XGB library [3], but I've forked it and rewritten most of the
> code. I've also replaced the Python code generator with xgbgen [4],
> which is written in Go.

Nice!

I 'maintain' the previous xgb library, but I haven't had the time to
do anything with it, and I haven't seen the original xgb author on
golang-nuts or golang-dev in over two years. I've only skimmed your
xgb for now, but it seems much more comprehensive. I'm tempted to take
down code.google.com/p/x-go-binding and point its users to your
project instead.

One thing is that "go build github.com/BurntSushi/wingo" currently
doesn't work; I get compiler errors (copied below). Do you have
uncommited changes?

./client.go:93: cannot use c.window.id (type
"code.google.com/p/jamslam-x-go-binding/xgb".Id) as type xproto.Window
in function argument
./client.go:170: cannot use c.window.id (type
"code.google.com/p/jamslam-x-go-binding/xgb".Id) as type xproto.Window
in function argument
./client.go:202: cannot use c.window.id (type
"code.google.com/p/jamslam-x-go-binding/xgb".Id) as type xproto.Window
in function argument
./client.go:209: X.Conn().SendEvent undefined (type
*"github.com/BurntSushi/xgb".Conn has no field or method SendEvent)
./client.go:222: X.Flush undefined (type *xgbutil.XUtil has no field
or method Flush)
etc.

Andrew Gallant

unread,
May 27, 2012, 1:13:58 AM5/27/12
to Anthony Martin, golan...@googlegroups.com
> What made you decide to fork and rewrite?

There are three primary reasons: thread safety, synchronous error
handling for requests without replies (and less commonly, asynchronous
error handling for requests with replies) and support for more
extensions.

The original XGB wasn't thread safe (and it didn't try to be). This in
and of itself was a fairly substantive change. It also had the
fantastic side effect of reaping performance benefits when parallelism
is available. (Evidence of this claim can be found by running 'make
bench' in the XGB project directory.)

As for synchronous error handling, I'll first explain how errors are
typically handled in other X libraries. One approach, synchronous
error handling, will wait for an error or some indication of success
for every request made. This *requires* a round trip to the X server
for every request, and therefore can be quite costly in performance
critical sections of code. However, it can be very useful for error
handling: errors are reported to the caller directly, and its much
easier to reason about.

The other approach, asynchronous error handling, causes errors to be
reported when reading events from the X connection. (The abstraction
is that one either receives an event or an error.) This is useful when
one doesn't care (or can't do anything about) requests that might
cause errors, or when one doesn't want to wait for a round trip to
know whether a request succeeded or not. The disadvantage is that
error handling is separated from the request that made it, and
therefore can be more difficult to reason about.

The original XGB forced asynchronous error handling for requests
without replies (always the fastest but not always the most readable)
and forced synchronous error handling for requests with replies
(almost always desirable since you'll have to typically wait for a
reply anyway). The rewrite allows synchronous or asynchronous error
handling for requests with and without replies. (This is tricky
because X is silent when a request without a reply is sent to X. Thus,
success must be inferred when the next reply is received.)

Finally, the last reason was adding support for more X extensions. In
typical XCB (and xpyb) fashion, the code that implements the X
protocol is automatically generated. (This is the code that constructs
byte slices to send to X.) This was originally done with XSLT for XCB,
but XCB (and xpyb) now uses a Python module to facilitate code
generation. The original XGB followed this same path, and I found the
Python code generator to be extremely difficult to reason with. So I
rewrote it from scratch using Go. Static types *really* helped here;
this cannot be overstated. The end result is actually ~65,000 lines of
auto-generated Go. (Adding support for additional X extensions also
required some fundamental changes to how XGB keeps track of which
event types are available and some slight modifications to the request
sending for extension requests.)

In the end, nearly all of XGB got a face-lift. The only portion of
code that is leftover or has only been slightly modified is the
connection handshake and parsing the Xauthority file.

I now realized that I've probably rambled a bit too much. However, I
almost always find myself wishing people wrote more about X. It's
almost always so tantalizingly brief. :-/

- Andrew

Andrew Gallant

unread,
May 27, 2012, 1:28:14 AM5/27/12
to Nigel Tao, golan...@googlegroups.com
> Nice!

Thanks :-)

> I 'maintain' the previous xgb library, but I haven't had the time to
> do anything with it, and I haven't seen the original xgb author on
> golang-nuts or golang-dev in over two years. I've only skimmed your
> xgb for now, but it seems much more comprehensive. I'm tempted to take
> down code.google.com/p/x-go-binding and point its users to your
> project instead.

I am obviously biased, but I think this is probably a good idea. :-)
If you like, I'd also recommend linking to xgbutil, as it's quite
likely that anyone doing low-level X stuff in Go is going to find
xgbutil useful. There is a ton of stuff packed in there to be useful
to a large number of use cases.

Thank you for maintaining the previous XGB library. I got a lot of
ideas from the old one. Thanks to the original author too!

> One thing is that "go build github.com/BurntSushi/wingo" currently
> doesn't work; I get compiler errors (copied below). Do you have
> uncommited changes?

Much to my chagrin, my window manager has not received attention for a
couple months. It is still using the old XGB, and by extension, a very
old version of xgbutil. I plan to whip it back into shape soon, but
have focused most of my attention recently on rounding out XGB and
xgbutil, and writing documentation and examples.

Even after that, Wingo will still need a bit more work before I'm
comfortable enough to show it off. However, I'm extremely pleased with
the progress so far. Using Go has been a pure joy! (I have pursued
writing a good window manager for a couple years now, and have failed
twice before in Python. I'm determined to succeed with Go!)

- Andrew

nove...@gmail.com

unread,
May 28, 2012, 7:02:48 PM5/28/12
to golan...@googlegroups.com
why X, why not wayland?

воскресенье, 27 мая 2012 г., 2:06:28 UTC+3 пользователь Andrew Gallant написал:

Andrew Gallant

unread,
May 28, 2012, 8:19:58 PM5/28/12
to golang-nuts
> why X, why not wayland?

I don't use Wayland (yet). I actually don't think it is in a state to
be used full-time yet at all, and my endgame has been to develop a
window manager now. X is going to still be used for a long time to
come, and for the moment, any GUI application on Linux needs to use X.

I don't know much about Wayland (so take what I say with a grain of
salt), but as it stands now, I'm under the impression that existing X
window managers (like awesome, Openbox, fvwm, etc.) will be able to
hook into the Weston compositor (the reference implementation of a
Wayland compositor) with little effort. Whether one can accomplish
this task with a Go window manager is something that I do not know
yet. (Due to ignorance on my part.) I imagine that the heavier weight
window managers (like KWin) will skip Weston and develop their own
compositors.

Also, at the moment, Wayland still depends on X. So even if I wanted
to go the Wayland route, XGB would still be necessary. *Moreover*,
Weston uses XKB (the only major X extension that eludes XGB at the
moment) which as it stands now, is only completely working in Xlib.
(It is only partially working in XCB I think, but not completely. It
is incredibly complex.)

Basically, I suspect that the first step for Wayland using Go is to
develop a compositor written in Go that works with the Wayland
protocol. If the need for XKB in a Wayland compositor can be worked-
around, then I suspect that whatever X requirements a port of Weston
to Go needs will be satisfied by XGB.

If anyone would like to chat more about this, feel free to ping me.

- Andrew
Reply all
Reply to author
Forward
0 new messages