I hate every single line of xwayland code I wrote, it is ugly, long and hard to maintain. Now I know very well why there is wayland in the first place, sadly a complete wayland compositor has to bring a piece of crap of X with it. I just finished the selection handling in xwayland by mimicing weston code. After finally understand that 1000 lines of confusing code, I just found out I can’t do any better.
Handling X11 selection revolves around 4 events: XSelectionNotify
,
XSelectionRequest
, XPropertyNotify
and XfixesSelectionNotify
. Their
names are just as confusing as how they work. It gets more complicated when
INCR protocol is involved.
Our job in compositor, for xwayland, is a proxy. That means getting
wl_data_source
to X data_offer
, and writing to wl_data_offer
from a X
data_source
when there is no data_offer
and data_source
in X at all. In
wayland, the protocol utilises PIPE for implementing clipboard. In X, it is
implemented by writing to a property of a X window. If you have no idea about
the properties in X. It is like a key value hash map, every window has a such
hash map. Clients communicates by reading/writing properties. Here is catch,
the developers ought to adher the specificiation, ICCCM for correctly
implementing their clients or XWM. If anything goes wrong…
Back to our topic, how do we work with those 4 events? Let’s walk through the
story. When a client press “ctrl-c”, it declares the owner of CLIPBOARD,
which is a special atom in the X. Nothing happens at the moment, until another
client, the requestor press “ctrl-v”, it then search for the owner of the
CLIPBOARD and ask for data, it begins our first event XSelectionRequest
,
basically it says, “hey, the owner, I would like you to convert what you have
in the CLIPBOARD to the target I asked and write to my property that I tell
you”. Then the owner can use a function XConvertSelection
for that
purpose. When it finishes, the owner send XSelectionNotify
event to the
requestor. The requestor indicates the end of the transaction by deletes
the property.
We didn’t mention the other two events. It has to do with our xwayland usage. I tried to summary the transaction as brief as possible, but we also omitted a lot of details. There are other playes, the wm(part of your wayland compositor), the CLIPBOARD_MANAGER and the role of xserver(xwayland in this case) in the story. Let me start by asking a few questions:
- How does the XWM know about the onwer of the CLIPBOARD?
- How does a
wl_data_source
becomes the owner of the CLIPBOARD? - How do we copy the property to
wl_data_offer
or vice versa?
When a owner of the CLIPBOARD annouces itself in Xwayland, the XWM need to
make a wl_data_source
out of it. This is done through the
XfixesSelectionNotify
event. In the event, we, the XWM, would ask for all the
targets (or mimes in wayland terms) that owner has(not the data itself). With
that, we have enough to create a proxy wl_date_source
, if there is no
wl_client
ask for data, we do nothing more, otherwise, the XWM represents the
wl_client
asking data from X.
On the other end, if a wl_data_source
becomes available, the XWM gets
notified and simply declares the owner of CLIPBOARD, if we are to process any
XSelectionRequests
, a PIPE need to create inside the XWM for reading from
wl_data_source
and writes the data to some X properties.
In the end, the selection data flows like this.
The ugly part is when INCR protocol comes in. INCR is for the case when you could not read/write X properties in one shot. Basically the XRequestor need to delete the property selection owner wrote to and wait for it to write again. For us xwayland case, we are in the akward situation for waiting on both X client deleting property and PIPE fd becomes available for IO.