|
|
@ -154,6 +154,11 @@ int main(int argc, char **argv) {
|
|
|
|
XFixesSelectSelectionInput(appdisp, approot, XA_PRIMARY,
|
|
|
|
XFixesSelectSelectionInput(appdisp, approot, XA_PRIMARY,
|
|
|
|
XFixesSetSelectionOwnerNotifyMask);
|
|
|
|
XFixesSetSelectionOwnerNotifyMask);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int xfixesbasevnc, xfixeserrbasevnc;
|
|
|
|
|
|
|
|
XFixesQueryExtension(vncdisp, &xfixesbasevnc, &xfixeserrbasevnc);
|
|
|
|
|
|
|
|
XFixesSelectSelectionInput(vncdisp, vncroot, XA_PRIMARY,
|
|
|
|
|
|
|
|
XFixesSetSelectionOwnerNotifyMask);
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef XA_LENGTH
|
|
|
|
#ifndef XA_LENGTH
|
|
|
|
Atom XA_LENGTH = XInternAtom(vncdisp, "LENGTH", True);
|
|
|
|
Atom XA_LENGTH = XInternAtom(vncdisp, "LENGTH", True);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
@ -161,6 +166,7 @@ int main(int argc, char **argv) {
|
|
|
|
if (xa_targets == None)
|
|
|
|
if (xa_targets == None)
|
|
|
|
xa_targets = XInternAtom(vncdisp, "TARGETS", False);
|
|
|
|
xa_targets = XInternAtom(vncdisp, "TARGETS", False);
|
|
|
|
Window selwin = XCreateSimpleWindow(appdisp, approot, 3, 2, 1, 1, 0, 0, 0);
|
|
|
|
Window selwin = XCreateSimpleWindow(appdisp, approot, 3, 2, 1, 1, 0, 0, 0);
|
|
|
|
|
|
|
|
Window vncselwin = XCreateSimpleWindow(vncdisp, vncroot, 3, 2, 1, 1, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
XFixesCursorImage *cursor = NULL;
|
|
|
|
XFixesCursorImage *cursor = NULL;
|
|
|
|
uint64_t cursorhash = 0;
|
|
|
|
uint64_t cursorhash = 0;
|
|
|
@ -301,7 +307,17 @@ int main(int argc, char **argv) {
|
|
|
|
|
|
|
|
|
|
|
|
XSelectionEvent sev;
|
|
|
|
XSelectionEvent sev;
|
|
|
|
|
|
|
|
|
|
|
|
switch (ev.type) {
|
|
|
|
if (ev.type == xfixesbasevnc + XFixesSelectionNotify) {
|
|
|
|
|
|
|
|
XFixesSelectionNotifyEvent *xfe =
|
|
|
|
|
|
|
|
(XFixesSelectionNotifyEvent *) &ev;
|
|
|
|
|
|
|
|
// printf("vnc disp did a copy, owner %lu, root %lu\n",
|
|
|
|
|
|
|
|
// xfe->owner, vncroot);
|
|
|
|
|
|
|
|
if (xfe->owner == None || xfe->owner == vncroot)
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XConvertSelection(vncdisp, XA_PRIMARY, XA_STRING, XA_STRING,
|
|
|
|
|
|
|
|
vncselwin, CurrentTime);
|
|
|
|
|
|
|
|
} else switch (ev.type) {
|
|
|
|
case KeyPress:
|
|
|
|
case KeyPress:
|
|
|
|
case KeyRelease:
|
|
|
|
case KeyRelease:
|
|
|
|
XTestFakeKeyEvent(appdisp, ev.xkey.keycode,
|
|
|
|
XTestFakeKeyEvent(appdisp, ev.xkey.keycode,
|
|
|
@ -377,6 +393,49 @@ int main(int argc, char **argv) {
|
|
|
|
XSendEvent(vncdisp, sev.requestor, False, 0,
|
|
|
|
XSendEvent(vncdisp, sev.requestor, False, 0,
|
|
|
|
(XEvent *) &sev);
|
|
|
|
(XEvent *) &sev);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SelectionNotify:
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Atom realtype;
|
|
|
|
|
|
|
|
int fmt;
|
|
|
|
|
|
|
|
unsigned long nitems, bytes_rem;
|
|
|
|
|
|
|
|
unsigned char *data;
|
|
|
|
|
|
|
|
if (XGetWindowProperty(vncdisp, vncselwin,
|
|
|
|
|
|
|
|
XA_STRING,
|
|
|
|
|
|
|
|
0, CUT_MAX / 4,
|
|
|
|
|
|
|
|
False, AnyPropertyType,
|
|
|
|
|
|
|
|
&realtype, &fmt,
|
|
|
|
|
|
|
|
&nitems, &bytes_rem,
|
|
|
|
|
|
|
|
&data) == Success) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (bytes_rem) {
|
|
|
|
|
|
|
|
printf("Clipboard too large, ignoring\n");
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
const uint32_t len = nitems * (fmt / 8);
|
|
|
|
|
|
|
|
//printf("realtype %lu, fmt %u, nitems %lu\n",
|
|
|
|
|
|
|
|
// realtype, fmt, nitems);
|
|
|
|
|
|
|
|
memcpy(cutbuf, data, len);
|
|
|
|
|
|
|
|
if (len < CUT_MAX)
|
|
|
|
|
|
|
|
cutbuf[len] = 0;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
cutbuf[CUT_MAX - 1] = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Send it to the app screen
|
|
|
|
|
|
|
|
XSetSelectionOwner(appdisp, XA_PRIMARY,
|
|
|
|
|
|
|
|
approot,
|
|
|
|
|
|
|
|
CurrentTime);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XFree(data);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
printf("Failed to fetch vnc clipboard\n");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SelectionClear:
|
|
|
|
|
|
|
|
cutbuf[0] = '\0';
|
|
|
|
|
|
|
|
XSetSelectionOwner(appdisp, XA_PRIMARY, None,
|
|
|
|
|
|
|
|
CurrentTime);
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
printf("Unexpected event type %u\n", ev.type);
|
|
|
|
printf("Unexpected event type %u\n", ev.type);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
@ -388,11 +447,13 @@ int main(int argc, char **argv) {
|
|
|
|
XEvent ev;
|
|
|
|
XEvent ev;
|
|
|
|
XNextEvent(appdisp, &ev);
|
|
|
|
XNextEvent(appdisp, &ev);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XSelectionEvent sev;
|
|
|
|
|
|
|
|
|
|
|
|
if (ev.type == xfixesbase + XFixesSelectionNotify) {
|
|
|
|
if (ev.type == xfixesbase + XFixesSelectionNotify) {
|
|
|
|
XFixesSelectionNotifyEvent *xfe =
|
|
|
|
XFixesSelectionNotifyEvent *xfe =
|
|
|
|
(XFixesSelectionNotifyEvent *) &ev;
|
|
|
|
(XFixesSelectionNotifyEvent *) &ev;
|
|
|
|
//printf("app disp did a copy, owner %lu\n", xfe->owner);
|
|
|
|
//printf("app disp did a copy, owner %lu\n", xfe->owner);
|
|
|
|
if (xfe->owner == None)
|
|
|
|
if (xfe->owner == None || xfe->owner == approot)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
XConvertSelection(appdisp, XA_PRIMARY, XA_STRING, XA_STRING,
|
|
|
|
XConvertSelection(appdisp, XA_PRIMARY, XA_STRING, XA_STRING,
|
|
|
@ -436,6 +497,67 @@ int main(int argc, char **argv) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SelectionRequest:
|
|
|
|
|
|
|
|
/* printf("app selreq, owner %lu requester %lu, approot %lu selwin %lu\n",
|
|
|
|
|
|
|
|
ev.xselectionrequest.owner,
|
|
|
|
|
|
|
|
ev.xselectionrequest.requestor,
|
|
|
|
|
|
|
|
approot, selwin);*/
|
|
|
|
|
|
|
|
sev.type = SelectionNotify;
|
|
|
|
|
|
|
|
sev.display = appdisp;
|
|
|
|
|
|
|
|
sev.requestor = ev.xselectionrequest.requestor;
|
|
|
|
|
|
|
|
sev.selection = ev.xselectionrequest.selection;
|
|
|
|
|
|
|
|
sev.target = ev.xselectionrequest.target;
|
|
|
|
|
|
|
|
sev.time = ev.xselectionrequest.time;
|
|
|
|
|
|
|
|
/*printf("app wants our clipboard, sel %lu, tgt %lu, prop %lu\n",
|
|
|
|
|
|
|
|
sev.selection, sev.target,
|
|
|
|
|
|
|
|
ev.xselectionrequest.property);*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ev.xselectionrequest.property == None)
|
|
|
|
|
|
|
|
sev.property = sev.target;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
sev.property = ev.xselectionrequest.property;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t len = strlen((char *) cutbuf);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ev.xselectionrequest.target == XA_LENGTH) {
|
|
|
|
|
|
|
|
// They're asking for the length
|
|
|
|
|
|
|
|
long llen = len;
|
|
|
|
|
|
|
|
XChangeProperty(appdisp, sev.requestor,
|
|
|
|
|
|
|
|
ev.xselectionrequest.property,
|
|
|
|
|
|
|
|
sev.target, 32,
|
|
|
|
|
|
|
|
PropModeReplace,
|
|
|
|
|
|
|
|
(unsigned char *) &llen,
|
|
|
|
|
|
|
|
1);
|
|
|
|
|
|
|
|
//puts("sent len");
|
|
|
|
|
|
|
|
} else if (xa_targets != None &&
|
|
|
|
|
|
|
|
sev.target == xa_targets) {
|
|
|
|
|
|
|
|
// Which formats can we do
|
|
|
|
|
|
|
|
Atom tgt[2] = {
|
|
|
|
|
|
|
|
xa_targets,
|
|
|
|
|
|
|
|
XA_STRING
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XChangeProperty(appdisp, sev.requestor,
|
|
|
|
|
|
|
|
ev.xselectionrequest.property,
|
|
|
|
|
|
|
|
XA_ATOM, 32,
|
|
|
|
|
|
|
|
PropModeReplace,
|
|
|
|
|
|
|
|
(unsigned char *) tgt,
|
|
|
|
|
|
|
|
2);
|
|
|
|
|
|
|
|
//puts("sent targets");
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Data
|
|
|
|
|
|
|
|
XChangeProperty(appdisp, sev.requestor,
|
|
|
|
|
|
|
|
ev.xselectionrequest.property,
|
|
|
|
|
|
|
|
sev.target, 8,
|
|
|
|
|
|
|
|
PropModeReplace,
|
|
|
|
|
|
|
|
cutbuf, len);
|
|
|
|
|
|
|
|
//printf("sent data, of len %u\n", len);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Send the notify event
|
|
|
|
|
|
|
|
XSendEvent(appdisp, sev.requestor, False, 0,
|
|
|
|
|
|
|
|
(XEvent *) &sev);
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
printf("Unexpected app event type %u\n", ev.type);
|
|
|
|
printf("Unexpected app event type %u\n", ev.type);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|