If xclip / xsel was a C library.
You're writing some X11 application in C/C++ and want "CTRL-C, CTRL-V functionality". It should be pretty simple, right? I imagine it should go something like this:
*user presses CTRL-C*
myawesomeprogram: "Hey XServer, can you put this <data> on the clipboard?"
XServer: "Totally, thnx!"
*time passes*
*user presses CTRL-V*
firefox. "Hey XServer, can you let me see what's on the clipboard?"
XServer: "Of course, here's some <data>."
WRONG! It is much more complicated than that, I'm sorry </3. This library tries to hide that complexity behind a single libxclip_put function, that's all this does.
Put something on the clipboard
#include <X11/Xlib.h>
#indluce "libxclip.h"
void main() {
display *display = XOpenDisplay(NULL);
char *data = "Hello, World!";
libxclip_put(display, data, len(data), NULL);
// if the use does ctrl-p in some other application it will paste "Hello, World!"
}This even works after the C program terminates, because (now comes some technical X11 language) a child process remains and responds to SelectionRequest's until it loses ownership of the selection.
The functions signature is as follows:
int libxclip_put(Display *display, char *data, size_t len, libxclip_putopts *options);where
displayThe connection to the XServer.dataPoints to the data that you want to "put on the clipboard".lenThe size ofdatain number of bytes.libxclip_putoptsCan be used in future versions to pass options tolibxclip_put. Right now it does nothing and you can just pass inNULL.
You as the caller is responsible for freeing data when you no longer need it. libxclip_put copies data to memory it owns (on modern Linux: does a copy-on-write of data. See this post) and so you need not worry about freeing data before libxclip_put is done with it.
Similarly XClose(display) won't cause problems.
Retrieve something from the clipboard
#include <X11/Xlib.h>
#include <stdio.h>
#indluce "libxclip.h"
void main() {
display *display = XOpenDisplay(NULL);
char *data;
size_t size;
libxclip_get(display, &data, &size, NULL);
printf("Got \"");
fwrite(data, 1, size, stdout);
printf("\" from the clipboard");
}The functions signature is as follows:
int libxclip_get(Display *display, char **data_ret, size_t *size_ret, struct libxclip_getopts *options);where
displayThe connection to the XServer.data_retA pointer to the clipboard contents will be written to this argument.size_retThe size of the buffer pointed to bydata_retwill be written to this argument.libxclip_getopsCan be used to pass options tolibxclip_get. See bellow for information.NULLin interpreted as the default options.
libxclip_getopts has the following field
Atom selectionThe selection you want to retrieve. Defaults toNonewhich is interpreted as the clipboard selection (XInternAtom(display, "CLIPBOARD", False);).Atom targetThe target format you want to retrieve the contents in. Defaults toNonewhich is interpreted asXInernAtom(display, "UTF8_STRING", False);.int timeoutAftertimeoutamount of milliseconds has elapsedlibxclip_getwill return with-1. To avoid indefinite blocking if the selection owner is ill-behaved. Defaults to-1which means no timeout.
You can initialize a struct libxclip_getopts to these values with libxclip_getopts_initialize(struct libxclip_getopts *options).
You as the caller is responsible for freeing data_ret when you no longer need it.
0 If the call was a success, and -1 otherwise, for instance if there was no selection owner or you supplied some invalid options.
Listing the available targets
In X11 it's possible for a user to copy many different types of data, for instance you can copy text but you can also copy an image. Your program may want to behave differently depending on what type of contents is on the clipboard, and for that you can request the available "targets" with libxclip_targets which has the following signature
int libxclip_targets(Display *display, Atom **targets_ret, unsigned long *nitems_ret, struct libxclip_getopts *options);
This is similar to libxclip_get but you instead get back a list of Atoms which tell you the format of the data. So you could call libxclip_targets and then see what atoms are returned to determine your programs behaviour. For instance, if one of the targets is the same as XInternAtom(display, "image/png", False); then you might assume that the user copied an image and not text.
Right now there is no packaging for any linux distro (maybe you can help me with that?), but this utility is very small. I suggest you do the following
- Copy
libxclip.candlibxclip.hinto you project. - Add
#include "libxclip.h"wherever you use it. - Make sure you have required dependencies installed (
libX11) - Whatever command you use to compile you project, add
libclip.cas an input file, and add a-lX11flag.
For instance, I'm compiling this repository's test-suite with
gcc -Og -Wall -Wno-unused-result -lX11 libxclip.c test.c -o testThese "installation" instruction are not very clear, I'm sorry.. Just ask me if you'd like help.
The main goal is to provide a nice-to-use utility function so that the author of an X11 application can focus on other things than implementing an X11 protocol.
Of course this utility should also be bug-free and introduce no vulnerabilities.
Full control over what's happening, optimal performance and support for niche use-cases is not a goal. If you want any of these it might be best to just use X11 functions directly, optionally looking at the source-code of this repository for guidance.
That said, if you find something to be missing I'd actually be happy if you opened an issue for it :-)
As far as I'm aware there are two classes of alternatives:
- Use some UI framework like Qt which provides similar utility functions for you.
- Use
system()to call a CLI-tool like xclip or xsel that can do this for you.
Yes please :-) If you want to implement some feature and so on, please don't hesitate to reach out to me.
The source code is based off of xclip which is licensed under GNU GPLv2 or later. The code in this repository is (re)licensed under GNU GPLv3 or later.
- Better "installation" instructions
- Package for common Linux distros
- Implement a
libxclip_get? - Proper documentation (like a man-page?)
- Do the licensing properly (add LICENSE file and license comments on top of files)