Last active
June 13, 2023 21:28
-
-
Save vurtun/1c57d1e9e2ee169b90209325e38f0cb7 to your computer and use it in GitHub Desktop.
X11 clipboard
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, ¬ify)) { | |
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); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.