In this article I will explain how one can serve data through the copy/paste mechanism from a C program using X11. There are many resources on the Web about the subject (this one and this one put me on tracks) but of those I've found none did actually worked out of the box. I hope this article will bring clarifications for those who wander on these strange roads...
Copy/paste can be handle in C programming through the Selection mechanism of the X Window System (X11). In short, it works as follow. The application serving data registers as the one holding the clipboard data, it listens for SelectionRequest events from other applications, and replies to them, either to let the requestor know what kind of data it serves, either to actually serve the requested data.
Here I will go through a demo which serves a dummy payload (some UTF-8 text) for a few seconds and then stops. It doesn't cover the "paste" operation, only the "copy" one (application uniquely serving data through the clipboard). I haven't pushed further because it's sufficient for my current needs, maybe I'll come back to it later. If you want to look by yourself, checking about the SelectionNotify events should put you on track.
First, to end automatically the app after a few seconds I spawn a thread which will update a flag controlling a loop in the main thread.
C by itself doesn't have copy/paste functionalities, it is a service offered by the window manager. Hence we need to create an X window, even if we won't even display it. It's really just here to be able to communicate with the X11 server.
For various application to be able to communicate they need some kind of common language. In X11 that's the role of an Atom. CLIPBOARD represents the clipboard, and TARGETS will be used to request the type of data. We need also one more for the actual type of data, and that's probably the trickiest part: how do you know in advance what the other application are expecting? I've choosen the one below through trial and error.
Note that you're free to choose whatever label you want for the last Atom, XInternAtom() will create it if it doesn't exist (that's the False flag at the end). So, if you're only interested in communicating with another application you're developping yourself you could very well use Atom atomDataType = XInternAtom(display , "my_own_weird_data_type", False); as long as you use the same label in both applications.
Next we inform the X11 server that we are the one responsible for the clipboard data. It will hold until the application ends, or a "copy" occurs in another application.
Next we start the main loop which processes events until the termination flag is raised or someone else takes the ownership of the clipboard data.
The main loop checks the events and filters requests related to the clipboard.
To reply to those requests, we prepare a SelectionNotify event that will be sent back to the requestor.
The reply event is completed with appropriate data. If we were requested the type of served data, we use the Atom defining that type. Note that here we can serve several types of data (just add them in the targets array).
If we were requested for one of the data type we serve, we set the actual data. Here I'm simply using a hardcoded value for demo. Note that the data can be anything you want, as long as the sender and receiver knows what to do about it. These are really just bytes moving from one process to another.
To help me identify what labels are used by other applications I also print those I don't recognize. A real application would probably ignore or throw an error here.
The reply event is now ready to be sent, and that's all for the main loop.
Finally, free the resources and return the success code.
The full code is as follow:
Compile with gcc -o main main.c -lX11.
Execute the application and try to paste in another one within the time limit, you should get the clipboardData. It works for me, on Linux, for Chrome, the Office suite, Nano, and Geany.