diff options
Diffstat (limited to 'x11vnc/selection.c')
-rw-r--r-- | x11vnc/selection.c | 548 |
1 files changed, 0 insertions, 548 deletions
diff --git a/x11vnc/selection.c b/x11vnc/selection.c deleted file mode 100644 index a334586..0000000 --- a/x11vnc/selection.c +++ /dev/null @@ -1,548 +0,0 @@ -/* - Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com> - All rights reserved. - -This file is part of x11vnc. - -x11vnc is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -x11vnc is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with x11vnc; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA -or see <http://www.gnu.org/licenses/>. - -In addition, as a special exception, Karl J. Runge -gives permission to link the code of its release of x11vnc with the -OpenSSL project's "OpenSSL" library (or with modified versions of it -that use the same license as the "OpenSSL" library), and distribute -the linked executables. You must obey the GNU General Public License -in all respects for all of the code used other than "OpenSSL". If you -modify this file, you may extend this exception to your version of the -file, but you are not obligated to do so. If you do not wish to do -so, delete this exception statement from your version. -*/ - -/* -- selection.c -- */ - -#include "x11vnc.h" -#include "cleanup.h" -#include "connections.h" -#include "unixpw.h" -#include "win_utils.h" -#include "xwrappers.h" - -/* - * Selection/Cutbuffer/Clipboard handlers. - */ - -int own_primary = 0; /* whether we currently own PRIMARY or not */ -int set_primary = 1; -int own_clipboard = 0; /* whether we currently own CLIPBOARD or not */ -int set_clipboard = 1; -int set_cutbuffer = 0; /* to avoid bouncing the CutText right back */ -int sel_waittime = 15; /* some seconds to skip before first send */ -Window selwin = None; /* special window for our selection */ -Atom clipboard_atom = None; - -/* - * This is where we keep our selection: the string sent TO us from VNC - * clients, and the string sent BY us to requesting X11 clients. - */ -char *xcut_str_primary = NULL; -char *xcut_str_clipboard = NULL; - - -void selection_request(XEvent *ev, char *type); -int check_sel_direction(char *dir, char *label, char *sel, int len); -void cutbuffer_send(void); -void selection_send(XEvent *ev); -void resend_selection(char *type); - - -/* - * Our callbacks instruct us to check for changes in the cutbuffer - * and PRIMARY and CLIPBOARD selection on the local X11 display. - * - * TODO: check if malloc does not cause performance issues (esp. WRT - * SelectionNotify handling). - */ -static char cutbuffer_str[PROP_MAX+1]; -static char primary_str[PROP_MAX+1]; -static char clipboard_str[PROP_MAX+1]; -static int cutbuffer_len = 0; -static int primary_len = 0; -static int clipboard_len = 0; - -/* - * An X11 (not VNC) client on the local display has requested the selection - * from us (because we are the current owner). - * - * n.b.: our caller already has the X_LOCK. - */ -void selection_request(XEvent *ev, char *type) { -#if NO_X11 - RAWFB_RET_VOID - if (!ev || !type) {} - return; -#else - XSelectionEvent notify_event; - XSelectionRequestEvent *req_event; - XErrorHandler old_handler; - char *str; - unsigned int length; - unsigned char *data; - static Atom xa_targets = None; - static int sync_it = -1; -# ifndef XA_LENGTH - unsigned long XA_LENGTH; -# endif - RAWFB_RET_VOID - -# ifndef XA_LENGTH - XA_LENGTH = XInternAtom(dpy, "LENGTH", True); -# endif - - if (sync_it < 0) { - if (getenv("X11VNC_SENDEVENT_SYNC")) { - sync_it = 1; - } else { - sync_it = 0; - } - } - - req_event = &(ev->xselectionrequest); - notify_event.type = SelectionNotify; - notify_event.display = req_event->display; - notify_event.requestor = req_event->requestor; - notify_event.selection = req_event->selection; - notify_event.target = req_event->target; - notify_event.time = req_event->time; - - if (req_event->property == None) { - notify_event.property = req_event->target; - } else { - notify_event.property = req_event->property; - } - - if (!strcmp(type, "PRIMARY")) { - str = xcut_str_primary; - } else if (!strcmp(type, "CLIPBOARD")) { - str = xcut_str_clipboard; - } else { - return; - } - if (str) { - length = strlen(str); - } else { - length = 0; - } - if (debug_sel) { - rfbLog("%s\trequest event: owner=0x%x requestor=0x%x sel=%03d targ=%d prop=%d\n", - type, req_event->owner, req_event->requestor, req_event->selection, - req_event->target, req_event->property); - } - - if (xa_targets == None) { - xa_targets = XInternAtom(dpy, "TARGETS", False); - } - - /* the window may have gone away, so trap errors */ - trapped_xerror = 0; - old_handler = XSetErrorHandler(trap_xerror); - - if (ev->xselectionrequest.target == XA_LENGTH) { - /* length request */ - int ret; - long llength = (long) length; - - ret = XChangeProperty(ev->xselectionrequest.display, - ev->xselectionrequest.requestor, - ev->xselectionrequest.property, - ev->xselectionrequest.target, 32, PropModeReplace, - (unsigned char *) &llength, 1); /* had sizeof(unsigned int) = 4 before... */ - if (debug_sel) { - rfbLog("LENGTH: XChangeProperty() -> %d\n", ret); - } - - } else if (xa_targets != None && ev->xselectionrequest.target == xa_targets) { - /* targets request */ - int ret; - Atom targets[2]; - targets[0] = (Atom) xa_targets; - targets[1] = (Atom) XA_STRING; - - ret = XChangeProperty(ev->xselectionrequest.display, - ev->xselectionrequest.requestor, - ev->xselectionrequest.property, - ev->xselectionrequest.target, 32, PropModeReplace, - (unsigned char *) targets, 2); - if (debug_sel) { - rfbLog("TARGETS: XChangeProperty() -> %d -- sz1: %d sz2: %d\n", - ret, sizeof(targets[0]), sizeof(targets)/sizeof(targets[0])); - } - - } else { - /* data request */ - int ret; - - data = (unsigned char *)str; - - ret = XChangeProperty(ev->xselectionrequest.display, - ev->xselectionrequest.requestor, - ev->xselectionrequest.property, - ev->xselectionrequest.target, 8, PropModeReplace, - data, length); - if (debug_sel) { - rfbLog("DATA: XChangeProperty() -> %d\n", ret); - } - } - - if (! trapped_xerror) { - int ret = -2, skip_it = 0, ms = 0; - double now = dnow(); - static double last_check = 0.0; - - if (now > last_check + 0.2) { - XFlush_wr(dpy); - if (!valid_window(req_event->requestor , NULL, 1)) { - sync_it = 1; - skip_it = 1; - if (debug_sel) { - rfbLog("selection_request: not a valid window: 0x%x\n", - req_event->requestor); - } - ms = 10; - } - if (trapped_xerror) { - sync_it = 1; - skip_it = 1; - } - last_check = dnow(); - } - - if (!skip_it) { - ret = XSendEvent(req_event->display, req_event->requestor, False, 0, - (XEvent *)¬ify_event); - } - if (debug_sel) { - rfbLog("XSendEvent() -> %d\n", ret); - } - if (ms > 0) { - usleep(ms * 1000); - } - } - if (trapped_xerror) { - rfbLog("selection_request: ignored XError while sending " - "%s selection to 0x%x.\n", type, req_event->requestor); - } - - XFlush_wr(dpy); - if (sync_it) { - usleep(10 * 1000); - XSync(dpy, False); - } - - XSetErrorHandler(old_handler); - trapped_xerror = 0; - -#endif /* NO_X11 */ -} - -int check_sel_direction(char *dir, char *label, char *sel, int len) { - int db = 0, ok = 1; - if (debug_sel) { - db = 1; - } - if (sel_direction) { - if (strstr(sel_direction, "debug")) { - db = 1; - } - if (strcmp(sel_direction, "debug")) { - if (strstr(sel_direction, dir) == NULL) { - ok = 0; - } - } - } - if (db) { - char str[40]; - int n = 40; - strncpy(str, sel, n); - str[n-1] = '\0'; - if (len < n) { - str[len] = '\0'; - } - rfbLog("%s: '%s'\n", label, str); - if (ok) { - rfbLog("%s: %s-ing it.\n", label, dir); - } else { - rfbLog("%s: NOT %s-ing it.\n", label, dir); - } - } - return ok; -} - -/* - * CUT_BUFFER0 property on the local display has changed, we read and - * store it and send it out to any connected VNC clients. - * - * n.b.: our caller already has the X_LOCK. - */ -void cutbuffer_send(void) { -#if NO_X11 - RAWFB_RET_VOID - return; -#else - Atom type; - int format, slen, dlen, len; - unsigned long nitems = 0, bytes_after = 0; - unsigned char* data = NULL; - - cutbuffer_str[0] = '\0'; - slen = 0; - - RAWFB_RET_VOID - - /* read the property value into cutbuffer_str: */ - do { - if (XGetWindowProperty(dpy, DefaultRootWindow(dpy), - XA_CUT_BUFFER0, nitems/4, PROP_MAX/16, False, - AnyPropertyType, &type, &format, &nitems, &bytes_after, - &data) == Success) { - - dlen = nitems * (format/8); - if (slen + dlen > PROP_MAX) { - /* too big */ - rfbLog("warning: truncating large CUT_BUFFER0" - " selection > %d bytes.\n", PROP_MAX); - XFree_wr(data); - break; - } - memcpy(cutbuffer_str+slen, data, dlen); - slen += dlen; - cutbuffer_str[slen] = '\0'; - XFree_wr(data); - } - } while (bytes_after > 0); - - cutbuffer_str[PROP_MAX] = '\0'; - - if (debug_sel) { - rfbLog("cutbuffer_send: '%s'\n", cutbuffer_str); - } - - if (! all_clients_initialized()) { - rfbLog("cutbuffer_send: no send: uninitialized clients\n"); - return; /* some clients initializing, cannot send */ - } - if (unixpw_in_progress) { - return; - } - - /* now send it to any connected VNC clients (rfbServerCutText) */ - if (!screen) { - return; - } - cutbuffer_len = len = strlen(cutbuffer_str); - if (check_sel_direction("send", "cutbuffer_send", cutbuffer_str, len)) { - rfbSendServerCutText(screen, cutbuffer_str, len); - } -#endif /* NO_X11 */ -} - -/* - * "callback" for our SelectionNotify polling. We try to determine if - * the PRIMARY selection has changed (checking length and first CHKSZ bytes) - * and if it has we store it and send it off to any connected VNC clients. - * - * n.b.: our caller already has the X_LOCK. - * - * TODO: if we were willing to use libXt, we could perhaps get selection - * timestamps to speed up the checking... XtGetSelectionValue(). - * - * Also: XFIXES has XFixesSelectSelectionInput(). - */ -#define CHKSZ 32 - -void selection_send(XEvent *ev) { -#if NO_X11 - RAWFB_RET_VOID - if (!ev) {} - return; -#else - Atom type; - int format, slen, dlen, oldlen, newlen, toobig = 0, len; - static int err = 0, sent_one = 0; - char before[CHKSZ], after[CHKSZ]; - unsigned long nitems = 0, bytes_after = 0; - unsigned char* data = NULL; - char *selection_str; - - RAWFB_RET_VOID - /* - * remember info about our last value of PRIMARY (or CUT_BUFFER0) - * so we can check for any changes below. - */ - if (ev->xselection.selection == XA_PRIMARY) { - if (! watch_primary) { - return; - } - selection_str = primary_str; - if (debug_sel) { - rfbLog("selection_send: event PRIMARY prop: %d requestor: 0x%x atom: %d\n", - ev->xselection.property, ev->xselection.requestor, ev->xselection.selection); - } - } else if (clipboard_atom && ev->xselection.selection == clipboard_atom) { - if (! watch_clipboard) { - return; - } - selection_str = clipboard_str; - if (debug_sel) { - rfbLog("selection_send: event CLIPBOARD prop: %d requestor: 0x%x atom: %d\n", - ev->xselection.property, ev->xselection.requestor, ev->xselection.selection); - } - } else { - return; - } - - oldlen = strlen(selection_str); - strncpy(before, selection_str, CHKSZ); - - selection_str[0] = '\0'; - slen = 0; - - /* read in the current value of PRIMARY or CLIPBOARD: */ - do { - if (XGetWindowProperty(dpy, ev->xselection.requestor, - ev->xselection.property, nitems/4, PROP_MAX/16, True, - AnyPropertyType, &type, &format, &nitems, &bytes_after, - &data) == Success) { - - dlen = nitems * (format/8); - if (slen + dlen > PROP_MAX) { - /* too big */ - toobig = 1; - XFree_wr(data); - if (err) { /* cut down on messages */ - break; - } else { - err = 5; - } - rfbLog("warning: truncating large PRIMARY" - "/CLIPBOARD selection > %d bytes.\n", - PROP_MAX); - break; - } -if (debug_sel) fprintf(stderr, "selection_send: data: '%s' dlen: %d nitems: %lu ba: %lu\n", data, dlen, nitems, bytes_after); - memcpy(selection_str+slen, data, dlen); - slen += dlen; - selection_str[slen] = '\0'; - XFree_wr(data); - } - } while (bytes_after > 0); - - if (! toobig) { - err = 0; - } else if (err) { - err--; - } - - if (! sent_one) { - /* try to force a send first time in */ - oldlen = -1; - sent_one = 1; - } - if (debug_sel) { - rfbLog("selection_send: %s '%s'\n", - ev->xselection.selection == XA_PRIMARY ? "PRIMARY " : "CLIPBOARD", - selection_str); - } - - /* look for changes in the new value */ - newlen = strlen(selection_str); - strncpy(after, selection_str, CHKSZ); - - if (oldlen == newlen && strncmp(before, after, CHKSZ) == 0) { - /* evidently no change */ - if (debug_sel) { - rfbLog("selection_send: no change.\n"); - } - return; - } - if (newlen == 0) { - /* do not bother sending a null string out */ - return; - } - - if (! all_clients_initialized()) { - rfbLog("selection_send: no send: uninitialized clients\n"); - return; /* some clients initializing, cannot send */ - } - - if (unixpw_in_progress) { - return; - } - - /* now send it to any connected VNC clients (rfbServerCutText) */ - if (!screen) { - return; - } - - len = newlen; - if (ev->xselection.selection == XA_PRIMARY) { - primary_len = len; - } else if (clipboard_atom && ev->xselection.selection == clipboard_atom) { - clipboard_len = len; - } - if (check_sel_direction("send", "selection_send", selection_str, len)) { - rfbSendServerCutText(screen, selection_str, len); - } -#endif /* NO_X11 */ -} - -void resend_selection(char *type) { -#if NO_X11 - RAWFB_RET_VOID - if (!type) {} - return; -#else - char *selection_str = ""; - int len = 0; - - RAWFB_RET_VOID - - if (! all_clients_initialized()) { - rfbLog("selection_send: no send: uninitialized clients\n"); - return; /* some clients initializing, cannot send */ - } - if (unixpw_in_progress) { - return; - } - if (!screen) { - return; - } - - if (!strcmp(type, "cutbuffer")) { - selection_str = cutbuffer_str; - len = cutbuffer_len; - } else if (!strcmp(type, "clipboard")) { - selection_str = clipboard_str; - len = clipboard_len; - } else if (!strcmp(type, "primary")) { - selection_str = primary_str; - len = primary_len; - } - if (check_sel_direction("send", "selection_send", selection_str, len)) { - rfbSendServerCutText(screen, selection_str, len); - } -#endif /* NO_X11 */ -} - - |