> 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