In a C program, I would like to write a string to the clipboard (and also read back a string from the clipboard) while running X11 in Linux.
This can be easily done in Python with pyperclip
, for example; as regards C, however, despite many searches I did not find any example.
xsel
sourcecode. I tried, but the code is somewhat huge.The selection I must refer to is probably CLIPBOARD
(neither PRIMARY
, nor SECONDARY
). In the linked xsel
source, some relevant parts are
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
and then
/* Find the "CLIPBOARD" selection if required */
if (want_clipboard) {
selection = XInternAtom (display, "CLIPBOARD", False);
}
but I didn't find a direct relation between XInternAtom
and read/write the clipboard.
If XInternAtom
is the correct function, how to proceed? Or is there another API that I can use?
XInternAtom() only converts the string name to an integer ID (the 'atom').
An "atom" in X11 (similar to what other programming languages call a symbol) is just a unique integer ID used to identify certain kinds of "named" objects. Instead of the X server having to process a string name every time some operation is done, you use XInternAtom() to do it just once and use the ID thereafter. (This e.g. allows X11 packets to be fixed-size structs instead of variable-length, which makes them faster to parse, not to mention much smaller.)
The X server keeps track of all strings ever given to XInternAtom() so that every call for the same name returns the same ID throughout the lifetime of the X display; see the output of xlsatoms
.
The clipboard in X11 is a type of selection. There can be many "selections" (some of them for internal purposes), but the one that deals with Windows/MacOS-style Ctrl-C/Ctrl-V is called "CLIPBOARD" – together with the SunView-style "PRIMARY" and "SECONDARY". The latter two have predefined atoms such as XA_PRIMARY
, but the clipboard does not, so you have to use XInternAtom("CLIPBOARD")
to retrieve its ID dynamically.
Contents of a selection are not stored centrally by X; they're kept by the original program where something was copied (which becomes the "selection owner"). Once you have the atom for a selection, you then request its contents from its owner using XConvertSelection() and the process owning that selection stores it in your window and responds with a SelectionNotify event. "Hey, I broke into your house and left the package in your living room."
Since the results get stored as a property of your window, you will need to create an invisible window first.
Just like in Windows API, you will need to request a specific data type such as "UTF8_STRING"
or "image/png"
. Asking for the special type "TARGETS"
usually returns a text list of types that the selection owner can offer.
(Data types are also handled as atoms – there is a constant XA_STRING
for the legacy format but you must XInternAtom("UTF8_STRING")
for the Unicode-compatible one.)
More documentation and code examples at:
Watching a selection for changes can be done using the XFIXES extension (which is universally supported), for example.