From 6f6a6c0d90c5ad9ceeff8d24299cdfc215955947 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 12 Jan 2016 18:40:23 +0100 Subject: [PATCH] Move server to client clipboard out of vncconfig Also handle clipboard transactions from the server to the client directly in the server without the help of vncconfig. --- unix/xserver/hw/vnc/Xvnc.man | 17 +++-- unix/xserver/hw/vnc/vncExt.c | 74 ------------------- unix/xserver/hw/vnc/vncExtInit.cc | 8 ++ unix/xserver/hw/vnc/vncExtInit.h | 2 + unix/xserver/hw/vnc/vncSelection.c | 114 ++++++++++++++++++++++++++++- 5 files changed, 132 insertions(+), 83 deletions(-) diff --git a/unix/xserver/hw/vnc/Xvnc.man b/unix/xserver/hw/vnc/Xvnc.man index 4a833157..e86bf87f 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 e07ed865..334c8889 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,9 +43,6 @@ 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; @@ -80,10 +76,6 @@ int vncAddExtension(void) FatalError("Add ClientStateCallback failed\n"); } - if (!AddCallback(&SelectionCallback, vncSelectionCallback, 0)) { - FatalError("Add SelectionCallback failed\n"); - } - return 0; } @@ -354,32 +346,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 ProcVncExtSelectInput(ClientPtr client) { struct VncInputSelect** nextPtr; @@ -583,8 +549,6 @@ static int ProcVncExtDispatch(ClientPtr client) return ProcVncExtGetParamDesc(client); case X_VncExtListParams: return ProcVncExtListParams(client); - case X_VncExtSetServerCutText: - return ProcVncExtSetServerCutText(client); case X_VncExtSelectInput: return ProcVncExtSelectInput(client); case X_VncExtConnect: @@ -610,8 +574,6 @@ static int SProcVncExtDispatch(ClientPtr client) return SProcVncExtGetParamDesc(client); case X_VncExtListParams: return SProcVncExtListParams(client); - case X_VncExtSetServerCutText: - return SProcVncExtSetServerCutText(client); case X_VncExtSelectInput: return SProcVncExtSelectInput(client); case X_VncExtConnect: @@ -644,39 +606,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 32a93f03..fda2562e 100644 --- a/unix/xserver/hw/vnc/vncExtInit.cc +++ b/unix/xserver/hw/vnc/vncExtInit.cc @@ -70,6 +70,9 @@ rfb::StringParameter interface("interface", rfb::BoolParameter avoidShiftNumLock("AvoidShiftNumLock", "Avoid fake Shift presses for keys affected by NumLock.", true); +rfb::BoolParameter sendPrimary("SendPrimary", + "Send the PRIMARY as well as the CLIPBOARD selection", + true); static PixelFormat vncGetPixelFormat(int scrIdx) { @@ -245,6 +248,11 @@ int vncGetAvoidShiftNumLock(void) return (bool)avoidShiftNumLock; } +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 1057118a..4b8568e1 100644 --- a/unix/xserver/hw/vnc/vncExtInit.h +++ b/unix/xserver/hw/vnc/vncExtInit.h @@ -57,6 +57,8 @@ void vncCallWriteWakeupHandlers(fd_set * fds, int nfds); int vncGetAvoidShiftNumLock(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 index 2369c5d7..263dbeca 100644 --- a/unix/xserver/hw/vnc/vncSelection.c +++ b/unix/xserver/hw/vnc/vncSelection.c @@ -22,6 +22,7 @@ #include +#include "propertyst.h" #include "scrnintstr.h" #include "selection.h" #include "windowstr.h" @@ -29,6 +30,7 @@ #include "xorg-version.h" +#include "vncExtInit.h" #include "vncSelection.h" #include "RFBGlue.h" @@ -48,13 +50,24 @@ 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) { + /* 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) @@ -240,8 +253,6 @@ static int vncConvertSelection(ClientPtr client, Atom selection, return Success; } -/* The original code cannot deal with the selection owner being - * serverClient, so we have to reimplement this. */ static int vncProcConvertSelection(ClientPtr client) { Bool paramsOkay; @@ -289,3 +300,102 @@ static int vncProcConvertSelection(ClientPtr client) return origProcConvertSelection(client); } + +static void vncHandleSelection(Atom selection, Atom target, + Atom property, Atom requestor, + TimeStamp time) +{ + Atom xaSTRING; + PropertyPtr prop; + int rc; + + LOG_DEBUG("Selection notification for %s (target %s, property %s)", + NameForAtom(selection), NameForAtom(target), + NameForAtom(property)); + + xaSTRING = MakeAtom("STRING", 6, TRUE); + + if (target != xaSTRING) + return; + if (property != xaSTRING) + return; + + rc = dixLookupProperty(&prop, pWindow, xaSTRING, + serverClient, DixReadAccess); + if (rc != Success) + return; + + if (prop->type != xaSTRING) + return; + if (prop->format != 8) + return; + + vncServerCutText(prop->data, prop->size); +} + +#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; + + Atom xaPRIMARY, xaCLIPBOARD, xaSTRING; + xEvent event; + int rc; + + if (info->kind != SelectionSetOwner) + return; + if (info->client == serverClient) + return; + + xaPRIMARY = MakeAtom("PRIMARY", 7, TRUE); + xaCLIPBOARD = MakeAtom("CLIPBOARD", 9, TRUE); + + if ((info->selection->selection != xaPRIMARY) && + (info->selection->selection != xaCLIPBOARD)) + return; + + if ((info->selection->selection == xaPRIMARY) && + !vncGetSendPrimary()) + return; + + rc = vncCreateSelectionWindow(); + if (rc != Success) + return; + + LOG_DEBUG("Requesting %s selection", + NameForAtom(info->selection->selection)); + + xaSTRING = MakeAtom("STRING", 6, TRUE); + + event.u.u.type = SelectionRequest; + event.u.selectionRequest.owner = info->selection->window; + event.u.selectionRequest.time = currentTime.milliseconds; + event.u.selectionRequest.requestor = wid; + event.u.selectionRequest.selection = info->selection->selection; + event.u.selectionRequest.target = xaSTRING; + event.u.selectionRequest.property = xaSTRING; + WriteEventsToClient(info->client, 1, &event); +} -- 2.39.5