A drop-in replacement for xpyb based on cffi
APACHE-2.0 License
xcffib
is intended to be a (mostly) drop-in replacement for xpyb
, the original python binding for xcb
.
For most end users of software that depends on xcffib or developers writing
code against xcffib, you can use the version of xcffib on pypi. To install it,
you'll need libxcb's headers and libxcb-render's headers (these are available
via sudo apt-get install libxcb-render0-dev
on Ubuntu). Once you have the C
headers installed, you can just pip install xcffib
.
If you're interested in doing development, read on...
You should be able to install all the language deps from hackage or pip. .github/workflows/ci.yaml has an example of how to install the dependencies on Ubuntu flavors.
See the Makefile for
examples on how to run the tests. Your contribution should at pass make check
before it can be merged. The newtests
make target can be used to regenerate
expected haskell test data if the tests are failing because you made a change
to the generated python code.
Sometimes (more often recently), xcbproto makes some updates that we need to
do some work for. These often require some updates to xcb-types
as well.
First, hack your changes into xcb-types
and cabal install
them, then git
clone the version of xcbproto you want to somewhere, e.g. ~/packages
:
~/packages $ git clone https://gitlab.freedesktop.org/xorg/proto/xcbproto.git
Finally, you can build/test xcffib against this custom version of
xcb-{proto|types}
with:
make XCBDIR=~/packages/xcbproto/src check
To go along with new xcbproto elements, sometimes you need to hack on newer versions of xcb-types. Newer cabals require you to do something like:
echo packages: ../xcb-types/xcb-types.cabal ./xcffib.cabal > cabal.project
In order to find locally modified versions of xcb-types.
In general, you should s/xcb/xcffib/g
. Explicit differences are listed below,
however I don't think these will prevent any porting, because these were either
not public APIs, or not actually generated (in the case of the exceptions) by
xpyb
. I think most porting should Just Work via the regex above.
xcb.Exception
is spelled xcffib.XcffibException
and is also a parent ofxcb.ConnectException
is gone, it was unusedxcffib.ConnectionException
is raised on connection errorsxcb.Iterator
is gone; similar functionality is implemented byxcffib.pack_list
.xcb.Request
is gone. It was an entirely internal and unnecessary interface.xcffib.Connection.send_request
takes slightly different (but more sensible)xcbproto
says char
, xcffib
uses a char. That means on input<list type="char"/>
, you can use a python string literal. xcffib
int
. Finally, there is a helper method called to_string
onxcffib.List
, to convert these string-like things into native strings. Thisxproto.STR
, you can just dothe_str.name.to_string()
instead of ''.join(map(chr, the_str.name))
.void
is also packed/unpacked as char
s, since the convention isxproto.ChangeProperty
.xcb
is gone. The top module re-exported all these constantsxcb.xcb.CurrentTime
is now justxcffib.CurrentTime
.When sending requests with nested structs you no longer have to pack the
contents yourself. For example, when calling xproto.FillPoly
, you used to
have to convert the POINT
s you were passing in to some sort of buffer which
had them struct.pack
'd. Now, you can just pass an iterable (or
xcffib.List
) of POINT
s and it will be automatically packed for you.
Most of the lower level XCB connection primitives that were previously not
exposed are now available via xcffib.{ffi,C}
, assuming you want to go out
of band of the binding.
Checked vs. Unchecked requests are still supported (via Checked and Unchecked
function calls). However, there is also an additional optional parameter
is_checked
to each request function, to allow you to set the checked status
that way. Additionally, requests that are (un)checked by default, e.g.
QueryTree
(CreateWindow
), have a QueryTreeChecked
(CreateWindowUnchecked
) version which just has the same default behavior.
The FooError
BadFoo
duality is gone; it was difficult to understand what
to actually catch if you wanted to handle an error. Instead, FooError
and
BadFoo
are aliases, and both implement the X error object description and
python Exception (via inheriting from XcffibException
).
You can now create synthetic events. This makes it much easier to work with
ClientMessageEvent
s. For example:
e = xcffib.xproto.ClientMessageEvent.synthetic(format=..., window=..., ...)
conn.core.SendEvent(..., e.pack())
Why is the binding generator written in haskell? Because haskell is awesome.