]> source.dussan.org Git - tigervnc.git/commitdiff
Move client to server clipboard out of vncconfig
authorPierre Ossman <ossman@cendio.se>
Tue, 12 Jan 2016 16:33:32 +0000 (17:33 +0100)
committerPierre Ossman <ossman@cendio.se>
Tue, 12 Jan 2016 17:39:09 +0000 (18:39 +0100)
Handle the clipboard directly in the server, avoiding the
dependency on vncconfig. This commit adds support for clipboard
from the client to the server. Handling of the other direction
will follow.

unix/xserver/hw/vnc/Makefile.am
unix/xserver/hw/vnc/RFBGlue.cc
unix/xserver/hw/vnc/XserverDesktop.cc
unix/xserver/hw/vnc/vncExt.c
unix/xserver/hw/vnc/vncExtInit.cc
unix/xserver/hw/vnc/vncExtInit.h
unix/xserver/hw/vnc/vncSelection.c [new file with mode: 0644]
unix/xserver/hw/vnc/vncSelection.h [new file with mode: 0644]

index d7ab2595f88ce11a89ea78c4578e93cce3ab17d7..95b03d2dc0ad92ab376ef377daa2a3763c0c05c3 100644 (file)
@@ -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
 
index 9a014f176baddc3114124ab8d3ddfc6d4043ef09..dd073e460606e97b48982ba93c1de99dc68b2332 100644 (file)
@@ -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)
 {
index 9b91d9a440ed1eeac773d90dc099893975a326c5..09ba6d7532d50af208d0a483b7345f0ad0a5ac93 100644 (file)
@@ -43,6 +43,7 @@
 #include "XserverDesktop.h"
 #include "vncExtInit.h"
 #include "vncHooks.h"
+#include "vncSelection.h"
 #include "XorgGlue.h"
 #include "Input.h"
 
index 43794dad37445bfe5f9da546ace8914ba731a897..e07ed8656d5d356b1ae9a2008d9ae5afd2b83f00 100644 (file)
@@ -52,9 +52,6 @@ static int vncEventBase = 0;
 
 int vncNoClipboard = 0;
 
-static char* clientCutText = NULL;
-static int clientCutTextLen = 0;
-
 static struct VncInputSelect* vncInputSelectHead = NULL;
 
 struct VncInputSelect {
@@ -121,47 +118,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;
@@ -424,47 +380,6 @@ static int SProcVncExtSetServerCutText(ClientPtr client)
   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;
@@ -670,8 +585,6 @@ static int ProcVncExtDispatch(ClientPtr client)
     return ProcVncExtListParams(client);
   case X_VncExtSetServerCutText:
     return ProcVncExtSetServerCutText(client);
-  case X_VncExtGetClientCutText:
-    return ProcVncExtGetClientCutText(client);
   case X_VncExtSelectInput:
     return ProcVncExtSelectInput(client);
   case X_VncExtConnect:
@@ -699,8 +612,6 @@ static int SProcVncExtDispatch(ClientPtr client)
     return SProcVncExtListParams(client);
   case X_VncExtSetServerCutText:
     return SProcVncExtSetServerCutText(client);
-  case X_VncExtGetClientCutText:
-    return SProcVncExtGetClientCutText(client);
   case X_VncExtSelectInput:
     return SProcVncExtSelectInput(client);
   case X_VncExtConnect:
index 863cd36bd993a2999aefcb8445d903fec7a500ea..32a93f0308445cc8d8ee2c04f18b8aa2cc1d7791 100644 (file)
@@ -35,6 +35,7 @@
 #include "vncExtInit.h"
 #include "vncHooks.h"
 #include "vncBlockHandler.h"
+#include "vncSelection.h"
 #include "XorgGlue.h"
 
 using namespace rfb;
@@ -123,6 +124,8 @@ void vncExtensionInit(void)
   if (ret == -1)
     return;
 
+  vncSelectionInit();
+
   vlog.info("VNC extension running!");
 
   try {
index 6430ac056e3d39a88c91c6d6f568684ca50a109f..1057118a9047a8d95c2b906be85292c1f5003ecc 100644 (file)
@@ -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[];
diff --git a/unix/xserver/hw/vnc/vncSelection.c b/unix/xserver/hw/vnc/vncSelection.c
new file mode 100644 (file)
index 0000000..2369c5d
--- /dev/null
@@ -0,0 +1,291 @@
+/* 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 "scrnintstr.h"
+#include "selection.h"
+#include "windowstr.h"
+#include "xace.h"
+
+#include "xorg-version.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 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 (*origProcConvertSelection)(ClientPtr);
+
+void vncSelectionInit(void)
+{
+  origProcConvertSelection = ProcVector[X_ConvertSelection];
+  ProcVector[X_ConvertSelection] = vncProcConvertSelection;
+}
+
+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;
+
+  rc = vncOwnSelection(MakeAtom("PRIMARY", 7, TRUE));
+  if (rc != Success)
+    LOG_ERROR("Could not set PRIMARY selection");
+  vncOwnSelection(MakeAtom("CLIPBOARD", 9, TRUE));
+  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 xaTARGETS, xaTIMESTAMP, xaSTRING, xaTEXT;
+  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 */
+
+  xaTARGETS = MakeAtom("TARGETS", 7, TRUE);
+  xaTIMESTAMP = MakeAtom("TIMESTAMP", 9, TRUE);
+  xaSTRING = MakeAtom("STRING", 6, TRUE);
+  xaTEXT = MakeAtom("TEXT", 4, TRUE);
+
+  if (target == xaTARGETS) {
+    Atom targets[] = { xaTARGETS, xaTIMESTAMP, xaSTRING, xaTEXT };
+
+    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 {
+    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;
+}
+
+/* The original code cannot deal with the selection owner being
+ * serverClient, so we have to reimplement this. */
+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);
+}
diff --git a/unix/xserver/hw/vnc/vncSelection.h b/unix/xserver/hw/vnc/vncSelection.h
new file mode 100644 (file)
index 0000000..969f895
--- /dev/null
@@ -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