Skip to content

Instantly share code, notes, and snippets.

@vurtun
Last active June 13, 2023 21:28
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vurtun/1c57d1e9e2ee169b90209325e38f0cb7 to your computer and use it in GitHub Desktop.
Save vurtun/1c57d1e9e2ee169b90209325e38f0cb7 to your computer and use it in GitHub Desktop.
X11 clipboard
static char*
sys_clip_get(struct sys *s, Atom selection, Atom target)
{
assert(s);
struct sys_x11 *x11 = s->platform;
/* blocking wait for clipboard data */
XEvent notify;
XConvertSelection(x11->dpy, selection, target, selection, x11->helper, CurrentTime);
while (!XCheckTypedWindowEvent(x11->dpy, x11->helper, SelectionNotify, &notify)) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(s->fd, &fds); // fd is the file handle returned by ConnectionNumber(x11->dpy);
if (select(s->fd + 1, &fds, 0,0,0) == -1 || errno == EINTR)
return 0;
}
if (notify.xselection.property == None)
return 0;
char *data = 0;
int actual_fmt;
Atom actual_type;
unsigned long item_cnt;
unsigned long bytes_after;
/* get clipboard data out of window property */
XGetWindowProperty(x11->dpy, notify.xselection.requestor,
notify.xselection.property, 0, LONG_MAX, True, AnyPropertyType,
&actual_type, &actual_fmt, &item_cnt, &bytes_after, (unsigned char**)&data);
if (actual_type != target) {
XFree(data);
return 0;
} return data;
}
static char*
sys_clip_get_str(struct sys *s)
{
assert(s);
struct sys_x11 *x11 = s->platform;
if (XGetSelectionOwner(x11->dpy, x11->xa_clipboard) == x11->helper) { // xa_clipbard is just an atom
/* Don't do any round trips. Instead just provide data */
if (!s->clip.data) return 0;
char *str = xmalloc(s->clip.len + 1);
strcpy(str, s->clip.data);
return str;
}
const Atom targets[] = {x11->xa_utf8_string, XA_STRING};
for (int i = 0; i < cntof(targets); ++i) {
char *data = sys_clip_get(s, x11->xa_clipboard, targets[i]);
if (!data) continue;
char *str = xmalloc(cast(int, strlen(data) + 1));
strcpy(str, data);
XFree(data);
return str;
} return 0;
}
static void
sys_clip_set_str(struct sys *s, const char *str, int len)
{
assert(s);
assert(str);
struct sys_x11 *x11 = s->platform;
free(s->clip.data);
s->clip.len = len;
s->clip.data = xmalloc(len+1);
strcpy(s->clip.data, str);
// helper here is just a default window with zero size which is never mapped
XSetSelectionOwner(x11->dpy, XA_PRIMARY, x11->helper, CurrentTime);
XSetSelectionOwner(x11->dpy, x11->xa_clipboard, x11->helper, CurrentTime);
}
static int
sys_clip_supports_type(const struct sys *s, Atom type)
{
assert(s);
const struct sys_x11 *x11 = s->platform;
if (type == x11->xa_text)
return True;
if (type == x11->xa_utf8_string)
return True;
if (type == XA_STRING)
return True;
return False;
}
int main(void)
{
/** ... */
x11->xa_clipboard = XInternAtom(x11->dpy, "CLIPBOARD", False);
x11->xa_utf8_string = XInternAtom(x11->dpy, "UTF8_STRING", False);
x11->xa_text = XInternAtom(x11->dpy, "TEXT", False);
/* create helper window */
x11->helper = XCreateSimpleWindow(x11->dpy, x11->root, -10, -10, 1,1,0,0,0);
XSelectInput(x11->dpy, x11->helper, SelectionNotify);
/* event handling */
while (XPending(x11->dpy)) {
XNextEvent(x11->dpy, &e);
switch(e.type) {
case SelectionRequest: {
XEvent reply = {0};
reply.xselection.type = SelectionNotify;
reply.xselection.requestor = e.xselectionrequest.requestor;
reply.xselection.selection = e.xselectionrequest.selection;
reply.xselection.target = e.xselectionrequest.target;
reply.xselection.time = e.xselectionrequest.time;
reply.xselection.property = None;
if (s->clip.data) {
if (reply.xselection.target == x11->xa_targets) {
/* handle request for supported types */
int tar_cnt = 0;
Atom tar_list[4];
tar_list[0] = x11->xa_targets;
tar_list[1] = x11->xa_utf8_string;
tar_list[2] = XA_STRING;
tar_cnt = 3;
reply.xselection.property = e.xselectionrequest.property;
XChangeProperty(e.xselection.display, e.xselectionrequest.requestor,
reply.xselection.property, XA_ATOM, 32, PropModeReplace,
(unsigned char*)&tar_list, tar_cnt);
} else if (sys_clip_supports_type(s, reply.xselection.target)) {
/* provide access to this apps clipboard data */
reply.xselection.property = e.xselectionrequest.property;
XChangeProperty(e.xselection.display, e.xselectionrequest.requestor,
reply.xselection.property, reply.xselection.target, 8,
PropModeReplace, (unsigned char*)s->clip.data, s->clip.len);
}
}
XSendEvent(e.xselection.display, e.xselectionrequest.requestor, True, 0, &reply);
XFlush(e.xselection.display);
}
}
Copy link

ghost commented Jan 23, 2022

This code won't compile without knowing the includes (which may be the easy part to figure out).

There are several parts that aren't defined such as clip, data, len, platform, and most especially, cntof and cast.

The most egregious part would be the error: invalid use of undefined type ‘struct sys’.
struct sys_x11 *x11 = s->platform;

There are way too many pointers that are throwing invalid use of undefined type errors. Also, wouldn't it have been a better idea to just define a struct that avoids the warning: ‘struct sys’ declared inside parameter list will not be visible outside of this definition or declaration seeing as there are 4 functions that basically use the same thing?

No one that's not a professional programmer would be able to complete this IMHO. I've tried to figure out how this works but the amount of errors are such that I'm at a loss on integrating this with the Nuklear X11 demo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment