Browse Source

Move client to server clipboard out of vncconfig

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.
tags/v1.7.90
Pierre Ossman 8 years ago
parent
commit
c62e70c5b3

+ 4
- 3
unix/xserver/hw/vnc/Makefile.am View 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


+ 1
- 0
unix/xserver/hw/vnc/RFBGlue.cc View 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)
{

+ 1
- 0
unix/xserver/hw/vnc/XserverDesktop.cc View File

@@ -43,6 +43,7 @@
#include "XserverDesktop.h"
#include "vncExtInit.h"
#include "vncHooks.h"
#include "vncSelection.h"
#include "XorgGlue.h"
#include "Input.h"


+ 0
- 89
unix/xserver/hw/vnc/vncExt.c View 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:

+ 3
- 0
unix/xserver/hw/vnc/vncExtInit.cc View 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 {

+ 0
- 2
unix/xserver/hw/vnc/vncExtInit.h View 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[];

+ 291
- 0
unix/xserver/hw/vnc/vncSelection.c View File

@@ -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);
}

+ 33
- 0
unix/xserver/hw/vnc/vncSelection.h View File

@@ -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

Loading…
Cancel
Save