diff options
author | Pierre Ossman <ossman@cendio.se> | 2016-07-08 14:11:42 +0200 |
---|---|---|
committer | Pierre Ossman <ossman@cendio.se> | 2016-07-08 14:11:42 +0200 |
commit | 1db99eb9ec1868620d1fb49d51f3a2caa8386f77 (patch) | |
tree | 17bd8ddada4ab126e6a18cac93752f665d28166b /unix | |
parent | 024cee5d203c45ba803c30057ae77b442d23112d (diff) | |
parent | 3f2bb341c9734c41a3f0123e44fd27ae50deb18c (diff) | |
download | tigervnc-1db99eb9ec1868620d1fb49d51f3a2caa8386f77.tar.gz tigervnc-1db99eb9ec1868620d1fb49d51f3a2caa8386f77.zip |
Merge branch 'clipboard'
Diffstat (limited to 'unix')
-rw-r--r-- | unix/vncconfig/vncExt.c | 84 | ||||
-rw-r--r-- | unix/vncconfig/vncExt.h | 85 | ||||
-rw-r--r-- | unix/vncconfig/vncconfig.cxx | 149 | ||||
-rw-r--r-- | unix/vncconfig/vncconfig.man | 13 | ||||
-rwxr-xr-x | unix/vncserver | 2 | ||||
-rw-r--r-- | unix/xserver/hw/vnc/Makefile.am | 7 | ||||
-rw-r--r-- | unix/xserver/hw/vnc/RFBGlue.cc | 1 | ||||
-rw-r--r-- | unix/xserver/hw/vnc/XserverDesktop.cc | 1 | ||||
-rw-r--r-- | unix/xserver/hw/vnc/Xvnc.man | 17 | ||||
-rw-r--r-- | unix/xserver/hw/vnc/vncExt.c | 163 | ||||
-rw-r--r-- | unix/xserver/hw/vnc/vncExtInit.cc | 18 | ||||
-rw-r--r-- | unix/xserver/hw/vnc/vncExtInit.h | 5 | ||||
-rw-r--r-- | unix/xserver/hw/vnc/vncSelection.c | 521 | ||||
-rw-r--r-- | unix/xserver/hw/vnc/vncSelection.h | 33 |
14 files changed, 600 insertions, 499 deletions
diff --git a/unix/vncconfig/vncExt.c b/unix/vncconfig/vncExt.c index e9b948d3..6256d3bf 100644 --- a/unix/vncconfig/vncExt.c +++ b/unix/vncconfig/vncExt.c @@ -24,10 +24,6 @@ #define _VNCEXT_PROTO_ #include "vncExt.h" -static Bool XVncExtClientCutTextNotifyWireToEvent(Display* dpy, XEvent* e, - xEvent* w); -static Bool XVncExtSelectionChangeNotifyWireToEvent(Display* dpy, XEvent* e, - xEvent* w); static Bool XVncExtQueryConnectNotifyWireToEvent(Display* dpy, XEvent* e, xEvent* w); @@ -40,10 +36,6 @@ static Bool checkExtension(Display* dpy) extensionInited = True; codes = XInitExtension(dpy, VNCEXTNAME); if (!codes) return False; - XESetWireToEvent(dpy, codes->first_event + VncExtClientCutTextNotify, - XVncExtClientCutTextNotifyWireToEvent); - XESetWireToEvent(dpy, codes->first_event + VncExtSelectionChangeNotify, - XVncExtSelectionChangeNotifyWireToEvent); XESetWireToEvent(dpy, codes->first_event + VncExtQueryConnectNotify, XVncExtQueryConnectNotifyWireToEvent); } @@ -214,53 +206,6 @@ void XVncExtFreeParamList(char** list) } } -Bool XVncExtSetServerCutText(Display* dpy, const char* str, int len) -{ - xVncExtSetServerCutTextReq* req; - - if (!checkExtension(dpy)) return False; - - LockDisplay(dpy); - GetReq(VncExtSetServerCutText, req); - req->reqType = codes->major_opcode; - req->vncExtReqType = X_VncExtSetServerCutText; - req->length += (len + 3) >> 2; - req->textLen = len; - Data(dpy, str, len); - UnlockDisplay(dpy); - SyncHandle(); - return True; -} - -Bool XVncExtGetClientCutText(Display* dpy, char** str, int* len) -{ - xVncExtGetClientCutTextReq* req; - xVncExtGetClientCutTextReply rep; - - if (!checkExtension(dpy)) return False; - - LockDisplay(dpy); - GetReq(VncExtGetClientCutText, req); - req->reqType = codes->major_opcode; - req->vncExtReqType = X_VncExtGetClientCutText; - if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { - UnlockDisplay(dpy); - SyncHandle(); - return False; - } - UnlockDisplay(dpy); - SyncHandle(); - *len = rep.textLen; - *str = (char*) Xmalloc (*len+1); - if (!*str) { - _XEatData(dpy, (*len+1)&~1); - return False; - } - _XReadPad(dpy, *str, *len); - (*str)[*len] = 0; - return True; -} - Bool XVncExtSelectInput(Display* dpy, Window w, int mask) { xVncExtSelectInputReq* req; @@ -359,35 +304,6 @@ Bool XVncExtApproveConnect(Display* dpy, void* opaqueId, int approve) } -static Bool XVncExtClientCutTextNotifyWireToEvent(Display* dpy, XEvent* e, - xEvent* w) -{ - XVncExtClientCutTextEvent* ev = (XVncExtClientCutTextEvent*)e; - xVncExtClientCutTextNotifyEvent* wire = (xVncExtClientCutTextNotifyEvent*)w; - ev->type = wire->type & 0x7f; - ev->serial = _XSetLastRequestRead(dpy,(xGenericReply*)wire); - ev->send_event = (wire->type & 0x80) != 0; - ev->display = dpy; - ev->window = wire->window; - ev->time = wire->time; - return True; -} - -static Bool XVncExtSelectionChangeNotifyWireToEvent(Display* dpy, XEvent* e, - xEvent* w) -{ - XVncExtSelectionChangeEvent* ev = (XVncExtSelectionChangeEvent*)e; - xVncExtSelectionChangeNotifyEvent* wire - = (xVncExtSelectionChangeNotifyEvent*)w; - ev->type = wire->type & 0x7f; - ev->serial = _XSetLastRequestRead(dpy,(xGenericReply*)wire); - ev->send_event = (wire->type & 0x80) != 0; - ev->display = dpy; - ev->window = wire->window; - ev->selection = wire->selection; - return True; -} - static Bool XVncExtQueryConnectNotifyWireToEvent(Display* dpy, XEvent* e, xEvent* w) { diff --git a/unix/vncconfig/vncExt.h b/unix/vncconfig/vncExt.h index e41e2e5b..2b24469e 100644 --- a/unix/vncconfig/vncExt.h +++ b/unix/vncconfig/vncExt.h @@ -26,18 +26,12 @@ extern "C" { #define X_VncExtGetParam 1 #define X_VncExtGetParamDesc 2 #define X_VncExtListParams 3 -#define X_VncExtSetServerCutText 4 -#define X_VncExtGetClientCutText 5 #define X_VncExtSelectInput 6 #define X_VncExtConnect 7 #define X_VncExtGetQueryConnect 8 #define X_VncExtApproveConnect 9 -#define VncExtClientCutTextNotify 0 -#define VncExtSelectionChangeNotify 1 #define VncExtQueryConnectNotify 2 -#define VncExtClientCutTextMask (1 << VncExtClientCutTextNotify) -#define VncExtSelectionChangeMask (1 << VncExtSelectionChangeNotify) #define VncExtQueryConnectMask (1 << VncExtQueryConnectNotify) #define VncExtNumberEvents 3 @@ -51,8 +45,6 @@ Bool XVncExtGetParam(Display* dpy, const char* param, char** value, int* len); char* XVncExtGetParamDesc(Display* dpy, const char* param); char** XVncExtListParams(Display* dpy, int* nParams); void XVncExtFreeParamList(char** list); -Bool XVncExtSetServerCutText(Display* dpy, const char* str, int len); -Bool XVncExtGetClientCutText(Display* dpy, char** str, int* len); Bool XVncExtSelectInput(Display* dpy, Window w, int mask); Bool XVncExtConnect(Display* dpy, const char* hostAndPort); Bool XVncExtGetQueryConnect(Display* dpy, char** addr, @@ -66,24 +58,6 @@ typedef struct { Bool send_event; Display *display; Window window; - Time time; -} XVncExtClientCutTextEvent; - -typedef struct { - int type; - unsigned long serial; - Bool send_event; - Display *display; - Window window; - Atom selection; -} XVncExtSelectionChangeEvent; - -typedef struct { - int type; - unsigned long serial; - Bool send_event; - Display *display; - Window window; } XVncExtQueryConnectEvent; #endif @@ -194,37 +168,6 @@ typedef struct { typedef struct { CARD8 reqType; /* always VncExtReqCode */ - CARD8 vncExtReqType; /* always VncExtSetServerCutText */ - CARD16 length B16; - CARD32 textLen B32; -} xVncExtSetServerCutTextReq; -#define sz_xVncExtSetServerCutTextReq 8 - - -typedef struct { - CARD8 reqType; /* always VncExtReqCode */ - CARD8 vncExtReqType; /* always VncExtGetClientCutText */ - CARD16 length B16; -} xVncExtGetClientCutTextReq; -#define sz_xVncExtGetClientCutTextReq 4 - -typedef struct { - BYTE type; /* X_Reply */ - BYTE pad0; - CARD16 sequenceNumber B16; - CARD32 length B32; - CARD32 textLen B32; - CARD32 pad1 B32; - CARD32 pad2 B32; - CARD32 pad3 B32; - CARD32 pad4 B32; - CARD32 pad5 B32; -} xVncExtGetClientCutTextReply; -#define sz_xVncExtGetClientCutTextReply 32 - - -typedef struct { - CARD8 reqType; /* always VncExtReqCode */ CARD8 vncExtReqType; /* always VncExtSelectInput */ CARD16 length B16; CARD32 window B32; @@ -293,34 +236,6 @@ typedef struct { typedef struct { - BYTE type; /* always eventBase + VncExtClientCutTextNotify */ - BYTE pad0; - CARD16 sequenceNumber B16; - CARD32 window B32; - CARD32 time B32; - CARD32 pad1 B32; - CARD32 pad2 B32; - CARD32 pad3 B32; - CARD32 pad4 B32; - CARD32 pad5 B32; -} xVncExtClientCutTextNotifyEvent; -#define sz_xVncExtClientCutTextNotifyEvent 32 - -typedef struct { - BYTE type; /* always eventBase + VncExtSelectionChangeNotify */ - BYTE pad0; - CARD16 sequenceNumber B16; - CARD32 window B32; - CARD32 selection B32; - CARD32 pad1 B32; - CARD32 pad2 B32; - CARD32 pad3 B32; - CARD32 pad4 B32; - CARD32 pad5 B32; -} xVncExtSelectionChangeNotifyEvent; -#define sz_xVncExtSelectionChangeNotifyEvent 32 - -typedef struct { BYTE type; /* always eventBase + VncExtQueryConnectNotify */ BYTE pad0; CARD16 sequenceNumber B16; diff --git a/unix/vncconfig/vncconfig.cxx b/unix/vncconfig/vncconfig.cxx index 2d6adf57..188ebfb8 100644 --- a/unix/vncconfig/vncconfig.cxx +++ b/unix/vncconfig/vncconfig.cxx @@ -38,7 +38,6 @@ #include <rfb/Configuration.h> #include <rfb/Logger_stdio.h> #include <rfb/LogWriter.h> -#include <rfb/Timer.h> #include "TXWindow.h" #include "TXCheckbox.h" #include "TXLabel.h" @@ -51,18 +50,6 @@ LogWriter vlog("vncconfig"); StringParameter displayname("display", "The X display", ""); BoolParameter noWindow("nowin", "Don't display a window", 0); BoolParameter iconic("iconic", "Start with window iconified", 0); -BoolParameter setPrimary("SetPrimary", "Set the PRIMARY as well " - "as the CLIPBOARD selection", true); -BoolParameter sendPrimary("SendPrimary", "Send the PRIMARY as well as the " - "CLIPBOARD selection", true); -IntParameter pollTime("poll", - "How often to poll for clipboard changes in ms", 0); - -inline const char* selectionName(Atom sel) { - if (sel == xaCLIPBOARD) return "CLIPBOARD"; - if (sel == XA_PRIMARY) return "PRIMARY"; - return "unknown"; -} #define ACCEPT_CUT_TEXT "AcceptCutText" #define SEND_CUT_TEXT "SendCutText" @@ -83,90 +70,29 @@ static bool getBoolParam(Display* dpy, const char* param) { class VncConfigWindow : public TXWindow, public TXEventHandler, public TXDeleteWindowCallback, public TXCheckboxCallback, - public rfb::Timer::Callback, public QueryResultCallback { public: VncConfigWindow(Display* dpy) - : TXWindow(dpy, 300, 100), cutText(0), cutTextLen(0), + : TXWindow(dpy, 300, 100), acceptClipboard(dpy, "Accept clipboard from viewers", this, false, this), - setPrimaryCB(dpy, "Also set primary selection", - this, false, this), sendClipboard(dpy, "Send clipboard to viewers", this, false, this), - sendPrimaryCB(dpy, "Send primary selection to viewers", this,false,this), - pollTimer(this), queryConnectDialog(0) { - selection[0] = selection[1] = 0; - selectionLen[0] = selectionLen[1] = 0; int y = yPad; acceptClipboard.move(xPad, y); acceptClipboard.checked(getBoolParam(dpy, ACCEPT_CUT_TEXT)); y += acceptClipboard.height(); - setPrimaryCB.move(xPad + 10, y); - setPrimaryCB.checked(setPrimary); - setPrimaryCB.disabled(!acceptClipboard.checked()); - y += setPrimaryCB.height(); sendClipboard.move(xPad, y); sendClipboard.checked(getBoolParam(dpy, SEND_CUT_TEXT)); y += sendClipboard.height(); - sendPrimaryCB.move(xPad, y); - sendPrimaryCB.checked(sendPrimary); - sendPrimaryCB.disabled(!sendClipboard.checked()); - y += sendPrimaryCB.height(); setEventHandler(this); toplevel("VNC config", this, 0, 0, 0, iconic); - XVncExtSelectInput(dpy, win(), - VncExtClientCutTextMask| - VncExtSelectionChangeMask| - VncExtQueryConnectMask); - XConvertSelection(dpy, XA_PRIMARY, XA_STRING, - XA_PRIMARY, win(), CurrentTime); - XConvertSelection(dpy, xaCLIPBOARD, XA_STRING, - xaCLIPBOARD, win(), CurrentTime); - if (pollTime != 0) - pollTimer.start(pollTime); + XVncExtSelectInput(dpy, win(), VncExtQueryConnectMask); } - // handleEvent(). If we get a ClientCutTextNotify event from Xvnc, set the - // primary and clipboard selections to the clientCutText. If we get a - // SelectionChangeNotify event from Xvnc, set the serverCutText to the value - // of the new selection. + // handleEvent() virtual void handleEvent(TXWindow* w, XEvent* ev) { - if (acceptClipboard.checked()) { - if (ev->type == vncExtEventBase + VncExtClientCutTextNotify) { - XVncExtClientCutTextEvent* cutEv = (XVncExtClientCutTextEvent*)ev; - if (cutText) - XFree(cutText); - cutText = 0; - if (XVncExtGetClientCutText(dpy, &cutText, &cutTextLen)) { - vlog.debug("Got client cut text: '%.*s%s'", - cutTextLen<9?cutTextLen:8, cutText, - cutTextLen<9?"":"..."); - XStoreBytes(dpy, cutText, cutTextLen); - if (setPrimaryCB.checked()) { - ownSelection(XA_PRIMARY, cutEv->time); - } - ownSelection(xaCLIPBOARD, cutEv->time); - delete [] selection[0]; - delete [] selection[1]; - selection[0] = selection[1] = 0; - selectionLen[0] = selectionLen[1] = 0; - } - } - } - if (sendClipboard.checked()) { - if (ev->type == vncExtEventBase + VncExtSelectionChangeNotify) { - vlog.debug("selection change event"); - XVncExtSelectionChangeEvent* selEv = (XVncExtSelectionChangeEvent*)ev; - if (selEv->selection == xaCLIPBOARD || - (selEv->selection == XA_PRIMARY && sendPrimaryCB.checked())) { - if (!selectionOwner(selEv->selection)) - XConvertSelection(dpy, selEv->selection, XA_STRING, - selEv->selection, win(), CurrentTime); - } - } - } if (ev->type == vncExtEventBase + VncExtQueryConnectNotify) { vlog.debug("query connection event"); if (queryConnectDialog) @@ -188,55 +114,6 @@ public: } } } - - - // selectionRequest() is called when we are the selection owner and another X - // client has requested the selection. We simply put the server's cut text - // into the requested property. TXWindow will handle the rest. - bool selectionRequest(Window requestor, Atom selection, Atom property) - { - if (cutText) - XChangeProperty(dpy, requestor, property, XA_STRING, 8, - PropModeReplace, (unsigned char*)cutText, - cutTextLen); - return cutText; - } - - // selectionNotify() is called when we have requested the selection from the - // selection owner. - void selectionNotify(XSelectionEvent* ev, Atom type, int format, - int nitems, void* data) - { - if (ev->requestor != win() || ev->target != XA_STRING) - return; - - if (data && format == 8) { - int i = (ev->selection == XA_PRIMARY ? 0 : 1); - if (selectionLen[i] == nitems && memcmp(selection[i], data, nitems) == 0) - return; - delete [] selection[i]; - selection[i] = new char[nitems]; - memcpy(selection[i], data, nitems); - selectionLen[i] = nitems; - if (cutTextLen == nitems && memcmp(cutText, data, nitems) == 0) { - vlog.debug("ignoring duplicate cut text"); - return; - } - if (cutText) - XFree(cutText); - cutText = (char*)malloc(nitems); // assuming XFree() same as free() - if (!cutText) { - vlog.error("unable to allocate selection buffer"); - return; - } - memcpy(cutText, data, nitems); - cutTextLen = nitems; - vlog.debug("sending %s selection as server cut text: '%.*s%s'", - selectionName(ev->selection),cutTextLen<9?cutTextLen:8, - cutText, cutTextLen<9?"":"..."); - XVncExtSetServerCutText(dpy, cutText, cutTextLen); - } - } // TXDeleteWindowCallback method virtual void deleteWindow(TXWindow* w) { @@ -248,25 +125,12 @@ public: if (checkbox == &acceptClipboard) { XVncExtSetParam(dpy, (acceptClipboard.checked() ? ACCEPT_CUT_TEXT "=1" : ACCEPT_CUT_TEXT "=0")); - setPrimaryCB.disabled(!acceptClipboard.checked()); } else if (checkbox == &sendClipboard) { XVncExtSetParam(dpy, (sendClipboard.checked() ? SEND_CUT_TEXT "=1" : SEND_CUT_TEXT "=0")); - sendPrimaryCB.disabled(!sendClipboard.checked()); } } - // rfb::Timer::Callback interface - virtual bool handleTimeout(rfb::Timer* timer) { - if (sendPrimaryCB.checked() && !selectionOwner(XA_PRIMARY)) - XConvertSelection(dpy, XA_PRIMARY, XA_STRING, - XA_PRIMARY, win(), CurrentTime); - if (!selectionOwner(xaCLIPBOARD)) - XConvertSelection(dpy, xaCLIPBOARD, XA_STRING, - xaCLIPBOARD, win(), CurrentTime); - return true; - } - // QueryResultCallback interface virtual void queryApproved() { XVncExtApproveConnect(dpy, queryConnectId, 1); @@ -276,12 +140,7 @@ public: } private: - char* cutText; - int cutTextLen; - char* selection[2]; - int selectionLen[2]; - TXCheckbox acceptClipboard, setPrimaryCB, sendClipboard, sendPrimaryCB; - rfb::Timer pollTimer; + TXCheckbox acceptClipboard, sendClipboard; QueryConnectDialog* queryConnectDialog; void* queryConnectId; diff --git a/unix/vncconfig/vncconfig.man b/unix/vncconfig/vncconfig.man index 6695be3d..06f9ca97 100644 --- a/unix/vncconfig/vncconfig.man +++ b/unix/vncconfig/vncconfig.man @@ -37,14 +37,11 @@ server with the VNC extension. Note that it cannot be used to control VNC servers prior to version 4. When run with no options, it runs as a kind of "helper" application for Xvnc. -Its main purpose when run in this mode is to support clipboard transfer to and -from the VNC viewer(s). Note that without a running instance of -\fBvncconfig\fP there will be no clipboard support. It puts up a window with -some checkboxes which can be used to disable clipboard transfers if required -(in the future there may be more functions available from this window). The -\fB-nowin\fP flag can be used if you always want clipboard support but don't -wish to clutter the desktop with this window - alternatively the \fB-iconic\fP -option can be used to make it iconified by default. +Its main purpose when run in this mode is to query the user how new +connections should be handled (provided this feature is enabled). The +\fB-nowin\fP flag can be used if you always want the query support but don't +wish to clutter the desktop with the settings window - alternatively the +\fB-iconic\fP option can be used to make it iconified by default. When run in any other mode, \fBvncconfig\fP is a one-shot program used to configure or control Xvnc as appropriate. It can be used to tell Xvnc to diff --git a/unix/vncserver b/unix/vncserver index 8f1f4b7c..674eadad 100755 --- a/unix/vncserver +++ b/unix/vncserver @@ -387,8 +387,6 @@ if (-e "/tmp/.X11-unix/X$displayNumber" || } $ENV{VNCDESKTOP}= $desktopName; -system($exedir."vncconfig -nowin >> " . "edString($desktopLog) . " 2>&1 &"); - if ($opt{'-fg'}) { if (! $skipxstartup) { system("$xstartup >> " . "edString($desktopLog) . " 2>&1"); diff --git a/unix/xserver/hw/vnc/Makefile.am b/unix/xserver/hw/vnc/Makefile.am index d7ab2595..95b03d2d 100644 --- a/unix/xserver/hw/vnc/Makefile.am +++ b/unix/xserver/hw/vnc/Makefile.am @@ -10,11 +10,12 @@ COMMON_LIBS=$(NETWORK_LIB) $(RFB_LIB) $(RDR_LIB) $(XREGION_LIB) noinst_LTLIBRARIES = libvnccommon.la HDRS = vncExtInit.h vncHooks.h \ - vncBlockHandler.h XorgGlue.h \ - XserverDesktop.h xorg-version.h \ + vncBlockHandler.h vncSelection.h \ + XorgGlue.h XserverDesktop.h xorg-version.h \ Input.h RFBGlue.h -libvnccommon_la_SOURCES = $(HDRS) vncExt.c vncExtInit.cc vncHooks.c \ +libvnccommon_la_SOURCES = $(HDRS) \ + vncExt.c vncExtInit.cc vncHooks.c vncSelection.c \ vncBlockHandler.c XorgGlue.c RFBGlue.cc XserverDesktop.cc \ Input.c InputXKB.c diff --git a/unix/xserver/hw/vnc/RFBGlue.cc b/unix/xserver/hw/vnc/RFBGlue.cc index d6c3ef6a..c9153364 100644 --- a/unix/xserver/hw/vnc/RFBGlue.cc +++ b/unix/xserver/hw/vnc/RFBGlue.cc @@ -31,6 +31,7 @@ using namespace rfb; // Loggers used by C code must be created here static LogWriter inputLog("Input"); +static LogWriter selectionLog("Selection"); void vncInitRFB(void) { diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc index f1c9b747..4eaa41f3 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.cc +++ b/unix/xserver/hw/vnc/XserverDesktop.cc @@ -43,6 +43,7 @@ #include "XserverDesktop.h" #include "vncExtInit.h" #include "vncHooks.h" +#include "vncSelection.h" #include "XorgGlue.h" #include "Input.h" diff --git a/unix/xserver/hw/vnc/Xvnc.man b/unix/xserver/hw/vnc/Xvnc.man index a4d9f8d3..f0f90f8f 100644 --- a/unix/xserver/hw/vnc/Xvnc.man +++ b/unix/xserver/hw/vnc/Xvnc.man @@ -126,14 +126,8 @@ screen is updated. Otherwise the delay is from the first update. Default is off. . .TP -.B \-SendCutText -Send clipboard changes to clients (default is on). Note that you must also run -\fBvncconfig\fP(1) to get the clipboard to work. -. -.TP .B \-AcceptCutText -Accept clipboard updates from clients (default is on). Note that you must also -run \fBvncconfig\fP(1) to get the clipboard to work. +Accept clipboard updates from clients (default is on). . .TP .B \-MaxCutText \fIbytes\fP @@ -141,6 +135,15 @@ The maximum size of a clipboard update that will be accepted from a client. Default is \fB262144\fP. . .TP +.B \-SendCutText +Send clipboard changes to clients (default is on). +. +.TP +.B \-SendPrimary +Send the primary selection and cut buffer to the server as well as the +clipboard selection. Default is on. +. +.TP .B \-AcceptPointerEvents Accept pointer press and release events from clients (default is on). . diff --git a/unix/xserver/hw/vnc/vncExt.c b/unix/xserver/hw/vnc/vncExt.c index b27115f6..0ee32101 100644 --- a/unix/xserver/hw/vnc/vncExt.c +++ b/unix/xserver/hw/vnc/vncExt.c @@ -27,7 +27,6 @@ #include "dixstruct.h" #include "extnsionst.h" #include "scrnintstr.h" -#include "selection.h" #define _VNCEXT_SERVER_ #define _VNCEXT_PROTO_ @@ -44,17 +43,11 @@ static void vncResetProc(ExtensionEntry* extEntry); static void vncClientStateChange(CallbackListPtr*, void *, void *); -static void vncSelectionCallback(CallbackListPtr *callbacks, - void * data, void * args); - static int vncErrorBase = 0; static int vncEventBase = 0; int vncNoClipboard = 0; -static char* clientCutText = NULL; -static int clientCutTextLen = 0; - static struct VncInputSelect* vncInputSelectHead = NULL; struct VncInputSelect { @@ -83,10 +76,6 @@ int vncAddExtension(void) FatalError("Add ClientStateCallback failed\n"); } - if (!AddCallback(&SelectionCallback, vncSelectionCallback, 0)) { - FatalError("Add SelectionCallback failed\n"); - } - return 0; } @@ -121,47 +110,6 @@ int vncNotifyQueryConnect(void) return count; } -void vncClientCutText(const char* str, int len) -{ - xVncExtClientCutTextNotifyEvent ev; - - if (clientCutText != NULL) - free(clientCutText); - clientCutTextLen = 0; - - clientCutText = malloc(len); - if (clientCutText == NULL) { - ErrorF("Could not allocate clipboard buffer\n"); - return; - } - - memcpy(clientCutText, str, len); - clientCutTextLen = len; - - ev.type = vncEventBase + VncExtClientCutTextNotify; - for (struct VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) { - if (cur->mask & VncExtClientCutTextMask) { - ev.sequenceNumber = cur->client->sequence; - ev.window = cur->window; - ev.time = GetTimeInMillis(); - if (cur->client->swapped) { -#if XORG < 112 - int n; - swaps(&ev.sequenceNumber, n); - swapl(&ev.window, n); - swapl(&ev.time, n); -#else - swaps(&ev.sequenceNumber); - swapl(&ev.window); - swapl(&ev.time); -#endif - } - WriteToClient(cur->client, sizeof(xVncExtClientCutTextNotifyEvent), - (char *)&ev); - } - } -} - static int ProcVncExtSetParam(ClientPtr client) { char *param; @@ -397,73 +345,6 @@ static int SProcVncExtListParams(ClientPtr client) return ProcVncExtListParams(client); } -static int ProcVncExtSetServerCutText(ClientPtr client) -{ - REQUEST(xVncExtSetServerCutTextReq); - REQUEST_FIXED_SIZE(xVncExtSetServerCutTextReq, stuff->textLen); - vncServerCutText((const char*)&stuff[1], stuff->textLen); - return (client->noClientException); -} - -static int SProcVncExtSetServerCutText(ClientPtr client) -{ - REQUEST(xVncExtSetServerCutTextReq); -#if XORG < 112 - register char n; - swaps(&stuff->length, n); -#else - swaps(&stuff->length); -#endif - REQUEST_AT_LEAST_SIZE(xVncExtSetServerCutTextReq); -#if XORG < 112 - swapl(&stuff->textLen, n); -#else - swapl(&stuff->textLen); -#endif - return ProcVncExtSetServerCutText(client); -} - -static int ProcVncExtGetClientCutText(ClientPtr client) -{ - xVncExtGetClientCutTextReply rep; - - REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq); - - rep.type = X_Reply; - rep.length = (clientCutTextLen + 3) >> 2; - rep.sequenceNumber = client->sequence; - rep.textLen = clientCutTextLen; - if (client->swapped) { -#if XORG < 112 - int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.textLen, n); -#else - swaps(&rep.sequenceNumber); - swapl(&rep.length); - swapl(&rep.textLen); -#endif - } - WriteToClient(client, sizeof(xVncExtGetClientCutTextReply), (char *)&rep); - if (clientCutText) - WriteToClient(client, clientCutTextLen, clientCutText); - return (client->noClientException); -} - -static int SProcVncExtGetClientCutText(ClientPtr client) -{ - REQUEST(xVncExtGetClientCutTextReq); -#if XORG < 112 - register char n; - swaps(&stuff->length, n); -#else - swaps(&stuff->length); -#endif - REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq); - return ProcVncExtGetClientCutText(client); -} - static int ProcVncExtSelectInput(ClientPtr client) { struct VncInputSelect** nextPtr; @@ -667,10 +548,6 @@ static int ProcVncExtDispatch(ClientPtr client) return ProcVncExtGetParamDesc(client); case X_VncExtListParams: return ProcVncExtListParams(client); - case X_VncExtSetServerCutText: - return ProcVncExtSetServerCutText(client); - case X_VncExtGetClientCutText: - return ProcVncExtGetClientCutText(client); case X_VncExtSelectInput: return ProcVncExtSelectInput(client); case X_VncExtConnect: @@ -696,10 +573,6 @@ static int SProcVncExtDispatch(ClientPtr client) return SProcVncExtGetParamDesc(client); case X_VncExtListParams: return SProcVncExtListParams(client); - case X_VncExtSetServerCutText: - return SProcVncExtSetServerCutText(client); - case X_VncExtGetClientCutText: - return SProcVncExtGetClientCutText(client); case X_VncExtSelectInput: return SProcVncExtSelectInput(client); case X_VncExtConnect: @@ -732,39 +605,3 @@ static void vncClientStateChange(CallbackListPtr * l, void * d, void * p) } } } - -static void SendSelectionChangeEvent(Atom selection) -{ - xVncExtSelectionChangeNotifyEvent ev; - ev.type = vncEventBase + VncExtSelectionChangeNotify; - for (struct VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) { - if (cur->mask & VncExtSelectionChangeMask) { - ev.sequenceNumber = cur->client->sequence; - ev.window = cur->window; - ev.selection = selection; - if (cur->client->swapped) { -#if XORG < 112 - int n; - swaps(&ev.sequenceNumber, n); - swapl(&ev.window, n); - swapl(&ev.selection, n); -#else - swaps(&ev.sequenceNumber); - swapl(&ev.window); - swapl(&ev.selection); -#endif - } - WriteToClient(cur->client, sizeof(xVncExtSelectionChangeNotifyEvent), - (char *)&ev); - } - } -} - -static void vncSelectionCallback(CallbackListPtr *callbacks, void * data, void * args) -{ - SelectionInfoRec *info = (SelectionInfoRec *) args; - Selection *selection = info->selection; - - SendSelectionChangeEvent(selection->selection); -} - diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc index 1d374938..0ad34a27 100644 --- a/unix/xserver/hw/vnc/vncExtInit.cc +++ b/unix/xserver/hw/vnc/vncExtInit.cc @@ -38,6 +38,7 @@ #include "vncExtInit.h" #include "vncHooks.h" #include "vncBlockHandler.h" +#include "vncSelection.h" #include "XorgGlue.h" using namespace rfb; @@ -84,6 +85,11 @@ rfb::BoolParameter avoidShiftNumLock("AvoidShiftNumLock", rfb::StringParameter allowOverride("AllowOverride", "Comma separated list of parameters that can be modified using VNC extension.", "desktop,AcceptPointerEvents,SendCutText,AcceptCutText"); +rfb::BoolParameter setPrimary("SetPrimary", "Set the PRIMARY as well " + "as the CLIPBOARD selection", true); +rfb::BoolParameter sendPrimary("SendPrimary", + "Send the PRIMARY as well as the CLIPBOARD selection", + true); static PixelFormat vncGetPixelFormat(int scrIdx) { @@ -151,6 +157,8 @@ void vncExtensionInit(void) if (ret == -1) return; + vncSelectionInit(); + vlog.info("VNC extension running!"); try { @@ -274,6 +282,16 @@ int vncGetAvoidShiftNumLock(void) return (bool)avoidShiftNumLock; } +int vncGetSetPrimary(void) +{ + return (bool)setPrimary; +} + +int vncGetSendPrimary(void) +{ + return (bool)sendPrimary; +} + void vncUpdateDesktopName(void) { for (int scr = 0; scr < vncGetScreenCount(); scr++) { diff --git a/unix/xserver/hw/vnc/vncExtInit.h b/unix/xserver/hw/vnc/vncExtInit.h index be6487c8..a0914ad7 100644 --- a/unix/xserver/hw/vnc/vncExtInit.h +++ b/unix/xserver/hw/vnc/vncExtInit.h @@ -41,8 +41,6 @@ int vncAddExtension(void); int vncNotifyQueryConnect(void); -void vncClientCutText(const char* str, int len); - // vncExtInit.cc extern void* vncFbptr[]; extern int vncFbstride[]; @@ -59,6 +57,9 @@ void vncCallWriteWakeupHandlers(fd_set * fds, int nfds); int vncGetAvoidShiftNumLock(void); +int vncGetSetPrimary(void); +int vncGetSendPrimary(void); + void vncUpdateDesktopName(void); void vncServerCutText(const char *text, size_t len); diff --git a/unix/xserver/hw/vnc/vncSelection.c b/unix/xserver/hw/vnc/vncSelection.c new file mode 100644 index 00000000..e50548a4 --- /dev/null +++ b/unix/xserver/hw/vnc/vncSelection.c @@ -0,0 +1,521 @@ +/* Copyright 2016 Pierre Ossman for Cendio AB + * + * This 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. + * + * This software 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 this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/Xatom.h> + +#include "propertyst.h" +#include "scrnintstr.h" +#include "selection.h" +#include "windowstr.h" +#include "xace.h" + +#include "xorg-version.h" + +#include "vncExtInit.h" +#include "vncSelection.h" +#include "RFBGlue.h" + +#define LOG_NAME "Selection" + +#define LOG_ERROR(...) vncLogError(LOG_NAME, __VA_ARGS__) +#define LOG_STATUS(...) vncLogStatus(LOG_NAME, __VA_ARGS__) +#define LOG_INFO(...) vncLogInfo(LOG_NAME, __VA_ARGS__) +#define LOG_DEBUG(...) vncLogDebug(LOG_NAME, __VA_ARGS__) + +static Atom xaPRIMARY, xaCLIPBOARD; +static Atom xaTARGETS, xaTIMESTAMP, xaSTRING, xaTEXT, xaUTF8_STRING; + +static WindowPtr pWindow; +static Window wid; + +static char* clientCutText; +static int clientCutTextLen; + +static int vncCreateSelectionWindow(void); +static int vncOwnSelection(Atom selection); +static int vncProcConvertSelection(ClientPtr client); +static int vncProcSendEvent(ClientPtr client); +static void vncSelectionCallback(CallbackListPtr *callbacks, + void * data, void * args); + +static int (*origProcConvertSelection)(ClientPtr); +static int (*origProcSendEvent)(ClientPtr); + +void vncSelectionInit(void) +{ + xaPRIMARY = MakeAtom("PRIMARY", 7, TRUE); + xaCLIPBOARD = MakeAtom("CLIPBOARD", 9, TRUE); + + xaTARGETS = MakeAtom("TARGETS", 7, TRUE); + xaTIMESTAMP = MakeAtom("TIMESTAMP", 9, TRUE); + xaSTRING = MakeAtom("STRING", 6, TRUE); + xaTEXT = MakeAtom("TEXT", 4, TRUE); + xaUTF8_STRING = MakeAtom("UTF8_STRING", 11, TRUE); + + /* There are no hooks for when these are internal windows, so + * override the relevant handlers. */ + origProcConvertSelection = ProcVector[X_ConvertSelection]; + ProcVector[X_ConvertSelection] = vncProcConvertSelection; + origProcSendEvent = ProcVector[X_SendEvent]; + ProcVector[X_SendEvent] = vncProcSendEvent; + + if (!AddCallback(&SelectionCallback, vncSelectionCallback, 0)) + FatalError("Add VNC SelectionCallback failed\n"); +} + +void vncClientCutText(const char* str, int len) +{ + int rc; + + if (clientCutText != NULL) + free(clientCutText); + + clientCutText = malloc(len); + if (clientCutText == NULL) { + LOG_ERROR("Could not allocate clipboard buffer"); + DeleteWindowFromAnySelections(pWindow); + return; + } + + memcpy(clientCutText, str, len); + clientCutTextLen = len; + + if (vncGetSetPrimary()) { + rc = vncOwnSelection(xaPRIMARY); + if (rc != Success) + LOG_ERROR("Could not set PRIMARY selection"); + } + + vncOwnSelection(xaCLIPBOARD); + if (rc != Success) + LOG_ERROR("Could not set CLIPBOARD selection"); +} + +static int vncCreateSelectionWindow(void) +{ + ScreenPtr pScreen; + int result; + + if (pWindow != NULL) + return Success; + + pScreen = screenInfo.screens[0]; + + wid = FakeClientID(0); + pWindow = CreateWindow(wid, pScreen->root, + 0, 0, 100, 100, 0, InputOnly, + 0, NULL, 0, serverClient, + CopyFromParent, &result); + if (!pWindow) + return result; + + if (!AddResource(pWindow->drawable.id, RT_WINDOW, pWindow)) + return BadAlloc; + + LOG_DEBUG("Created selection window"); + + return Success; +} + +static int vncOwnSelection(Atom selection) +{ + Selection *pSel; + int rc; + + SelectionInfoRec info; + + rc = vncCreateSelectionWindow(); + if (rc != Success) + return rc; + + rc = dixLookupSelection(&pSel, selection, serverClient, DixSetAttrAccess); + if (rc == Success) { + if (pSel->client && (pSel->client != serverClient)) { + xEvent event = { + .u.selectionClear.time = currentTime.milliseconds, + .u.selectionClear.window = pSel->window, + .u.selectionClear.atom = pSel->selection + }; + event.u.u.type = SelectionClear; + WriteEventsToClient(pSel->client, 1, &event); + } + } else if (rc == BadMatch) { + pSel = dixAllocateObjectWithPrivates(Selection, PRIVATE_SELECTION); + if (!pSel) + return BadAlloc; + + pSel->selection = selection; + + rc = XaceHookSelectionAccess(serverClient, &pSel, + DixCreateAccess | DixSetAttrAccess); + if (rc != Success) { + free(pSel); + return rc; + } + + pSel->next = CurrentSelections; + CurrentSelections = pSel; + } + else + return rc; + + pSel->lastTimeChanged = currentTime; + pSel->window = wid; + pSel->pWin = pWindow; + pSel->client = serverClient; + + LOG_DEBUG("Grabbed %s selection", NameForAtom(selection)); + + info.selection = pSel; + info.client = serverClient; + info.kind = SelectionSetOwner; + CallCallbacks(&SelectionCallback, &info); + + return Success; +} + +static int vncConvertSelection(ClientPtr client, Atom selection, + Atom target, Atom property, + Window requestor, TimeStamp time) +{ + Selection *pSel; + WindowPtr pWin; + int rc; + + Atom realProperty; + + xEvent event; + + LOG_DEBUG("Selection request for %s (type %s)", + NameForAtom(selection), NameForAtom(target)); + + rc = dixLookupSelection(&pSel, selection, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + if (CompareTimeStamps(time, pSel->lastTimeChanged) != LATER) + return BadMatch; + + rc = dixLookupWindow(&pWin, requestor, client, DixSetAttrAccess); + if (rc != Success) + return rc; + + if (property != None) + realProperty = property; + else + realProperty = target; + + /* FIXME: MULTIPLE target */ + + if (target == xaTARGETS) { + Atom targets[] = { xaTARGETS, xaTIMESTAMP, + xaSTRING, xaTEXT, xaUTF8_STRING }; + + rc = ChangeWindowProperty(pWin, realProperty, XA_ATOM, 32, + PropModeReplace, + sizeof(targets)/sizeof(targets[0]), + targets, TRUE); + if (rc != Success) + return rc; + } else if (target == xaTIMESTAMP) { + rc = ChangeWindowProperty(pWin, realProperty, XA_INTEGER, 32, + PropModeReplace, 1, + &pSel->lastTimeChanged.milliseconds, + TRUE); + if (rc != Success) + return rc; + } else if ((target == xaSTRING) || (target == xaTEXT)) { + rc = ChangeWindowProperty(pWin, realProperty, XA_STRING, 8, + PropModeReplace, clientCutTextLen, + clientCutText, TRUE); + if (rc != Success) + return rc; + } else if (target == xaUTF8_STRING) { + unsigned char* buffer; + unsigned char* out; + size_t len; + + const unsigned char* in; + size_t in_len; + + buffer = malloc(clientCutTextLen*2); + if (buffer == NULL) + return BadAlloc; + + out = buffer; + len = 0; + in = clientCutText; + in_len = clientCutTextLen; + while (in_len > 0) { + if (*in & 0x80) { + *out++ = 0xc0 | (*in >> 6); + *out++ = 0x80 | (*in & 0x3f); + len += 2; + in++; + in_len--; + } else { + *out++ = *in++; + len++; + in_len--; + } + } + + rc = ChangeWindowProperty(pWin, realProperty, xaUTF8_STRING, 8, + PropModeReplace, len, buffer, TRUE); + free(buffer); + if (rc != Success) + return rc; + } else { + return BadMatch; + } + + event.u.u.type = SelectionNotify; + event.u.selectionNotify.time = time.milliseconds; + event.u.selectionNotify.requestor = requestor; + event.u.selectionNotify.selection = selection; + event.u.selectionNotify.target = target; + event.u.selectionNotify.property = property; + WriteEventsToClient(client, 1, &event); + return Success; +} + +static int vncProcConvertSelection(ClientPtr client) +{ + Bool paramsOkay; + WindowPtr pWin; + Selection *pSel; + int rc; + + REQUEST(xConvertSelectionReq); + REQUEST_SIZE_MATCH(xConvertSelectionReq); + + rc = dixLookupWindow(&pWin, stuff->requestor, client, DixSetAttrAccess); + if (rc != Success) + return rc; + + paramsOkay = ValidAtom(stuff->selection) && ValidAtom(stuff->target); + paramsOkay &= (stuff->property == None) || ValidAtom(stuff->property); + if (!paramsOkay) { + client->errorValue = stuff->property; + return BadAtom; + } + + rc = dixLookupSelection(&pSel, stuff->selection, client, DixReadAccess); + if (rc == Success && pSel->client == serverClient && + pSel->window == wid) { + TimeStamp time; + time = ClientTimeToServerTime(stuff->time); + rc = vncConvertSelection(client, stuff->selection, + stuff->target, stuff->property, + stuff->requestor, time); + if (rc != Success) { + xEvent event; + + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = SelectionNotify; + event.u.selectionNotify.time = stuff->time; + event.u.selectionNotify.requestor = stuff->requestor; + event.u.selectionNotify.selection = stuff->selection; + event.u.selectionNotify.target = stuff->target; + event.u.selectionNotify.property = None; + WriteEventsToClient(client, 1, &event); + } + + return Success; + } + + return origProcConvertSelection(client); +} + +static void vncSelectionRequest(Atom selection, Atom target) +{ + Selection *pSel; + xEvent event; + int rc; + + rc = vncCreateSelectionWindow(); + if (rc != Success) + return; + + LOG_DEBUG("Requesting %s for %s selection", + NameForAtom(target), NameForAtom(selection)); + + rc = dixLookupSelection(&pSel, selection, serverClient, DixGetAttrAccess); + if (rc != Success) + return; + + event.u.u.type = SelectionRequest; + event.u.selectionRequest.owner = pSel->window; + event.u.selectionRequest.time = currentTime.milliseconds; + event.u.selectionRequest.requestor = wid; + event.u.selectionRequest.selection = selection; + event.u.selectionRequest.target = target; + event.u.selectionRequest.property = target; + WriteEventsToClient(pSel->client, 1, &event); +} + +static Bool vncHasAtom(Atom atom, const Atom list[], size_t size) +{ + size_t i; + + for (i = 0;i < size;i++) { + if (list[i] == atom) + return TRUE; + } + + return FALSE; +} + +static void vncHandleSelection(Atom selection, Atom target, + Atom property, Atom requestor, + TimeStamp time) +{ + PropertyPtr prop; + int rc; + + rc = dixLookupProperty(&prop, pWindow, property, + serverClient, DixReadAccess); + if (rc != Success) + return; + + LOG_DEBUG("Selection notification for %s (target %s, property %s, type %s)", + NameForAtom(selection), NameForAtom(target), + NameForAtom(property), NameForAtom(prop->type)); + + if (target != property) + return; + + if (target == xaTARGETS) { + if (prop->format != 32) + return; + if (prop->type != XA_ATOM) + return; + + if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size)) + vncSelectionRequest(selection, xaSTRING); + else if (vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size)) + vncSelectionRequest(selection, xaUTF8_STRING); + } else if (target == xaSTRING) { + if (prop->format != 8) + return; + if (prop->type != xaSTRING) + return; + + vncServerCutText(prop->data, prop->size); + } else if (target == xaUTF8_STRING) { + unsigned char* buffer; + unsigned char* out; + size_t len; + + const unsigned char* in; + size_t in_len; + + if (prop->format != 8) + return; + if (prop->type != xaUTF8_STRING) + return; + + buffer = malloc(prop->size); + if (buffer == NULL) + return; + + out = buffer; + len = 0; + in = prop->data; + in_len = prop->size; + while (in_len > 0) { + if ((*in & 0x80) == 0x00) { + *out++ = *in++; + len++; + in_len--; + } else if ((*in & 0xe0) == 0xc0) { + unsigned ucs; + ucs = (*in++ & 0x1f) << 6; + in_len--; + if (in_len > 0) { + ucs |= (*in++ & 0x3f); + in_len--; + } + if (ucs <= 0xff) + *out++ = ucs; + else + *out++ = '?'; + len++; + } else { + *out++ = '?'; + len++; + do { + in++; + in_len--; + } while ((in_len > 0) && ((*in & 0xc0) == 0x80)); + } + } + + vncServerCutText((const char*)buffer, len); + + free(buffer); + } +} + +#define SEND_EVENT_BIT 0x80 + +static int vncProcSendEvent(ClientPtr client) +{ + REQUEST(xSendEventReq); + REQUEST_SIZE_MATCH(xSendEventReq); + + stuff->event.u.u.type &= ~(SEND_EVENT_BIT); + + if (stuff->event.u.u.type == SelectionNotify && + stuff->event.u.selectionNotify.requestor == wid) { + TimeStamp time; + time = ClientTimeToServerTime(stuff->event.u.selectionNotify.time); + vncHandleSelection(stuff->event.u.selectionNotify.selection, + stuff->event.u.selectionNotify.target, + stuff->event.u.selectionNotify.property, + stuff->event.u.selectionNotify.requestor, + time); + } + + return origProcSendEvent(client); +} + +static void vncSelectionCallback(CallbackListPtr *callbacks, + void * data, void * args) +{ + SelectionInfoRec *info = (SelectionInfoRec *) args; + + if (info->kind != SelectionSetOwner) + return; + if (info->client == serverClient) + return; + + if ((info->selection->selection != xaPRIMARY) && + (info->selection->selection != xaCLIPBOARD)) + return; + + if ((info->selection->selection == xaPRIMARY) && + !vncGetSendPrimary()) + return; + + vncSelectionRequest(info->selection->selection, xaTARGETS); +} diff --git a/unix/xserver/hw/vnc/vncSelection.h b/unix/xserver/hw/vnc/vncSelection.h new file mode 100644 index 00000000..969f8958 --- /dev/null +++ b/unix/xserver/hw/vnc/vncSelection.h @@ -0,0 +1,33 @@ +/* Copyright 2016 Pierre Ossman for Cendio AB + * + * This 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. + * + * This software 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 this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +#ifndef __SELECTION_H__ +#define __SELECTION_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +void vncSelectionInit(void); + +void vncClientCutText(const char* str, int len); + +#ifdef __cplusplus +} +#endif + +#endif |