Browse Source

SDLvncviewer: use SDL2 for clipboard handling

By using this, we can get rid of our own homebrewn solution scrap.[c|h] and drop X11 from the build system.
pull/3/head
Christian Beier 4 years ago
parent
commit
bfdb850bfb
No known key found for this signature in database
GPG Key ID: 421BB3B45C6067F8
  1. 9
      CMakeLists.txt
  2. 54
      client_examples/SDLvncviewer.c
  3. 559
      client_examples/scrap.c
  4. 18
      client_examples/scrap.h

9
CMakeLists.txt

@ -37,7 +37,6 @@ option(WITH_ZLIB "Search for the zlib compression library to support additional
option(WITH_JPEG "Search for the libjpeg compression library to support additional encodings" ON)
option(WITH_PNG "Search for the PNG compression library to support additional encodings" ON)
option(WITH_SDL "Search for the Simple Direct Media Layer library to build an example SDL vnc client" ON)
option(WITH_X11 "Search for X11 to build the example SDL vnc client with clipboard support" ON)
option(WITH_THREADS "Search for a threading library to build with multithreading support" ON)
option(WITH_GNUTLS "Search for the GnuTLS secure communications library to support encryption" ON)
option(WITH_OPENSSL "Search for the OpenSSL cryptography library to support encryption" ON)
@ -105,11 +104,6 @@ if(WITH_SDL)
endif(WITH_SDL)
if(WITH_X11)
find_package(X11)
endif(WITH_X11)
if(WITH_THREADS)
find_package(Threads)
endif(WITH_THREADS)
@ -506,7 +500,6 @@ if(SDL2_FOUND)
${LIBVNCCLIENT_EXAMPLES}
SDLvncviewer
)
set(SDLvncviewer_EXTRA_SOURCES scrap.c)
endif(SDL2_FOUND)
if(FFMPEG_FOUND)
@ -530,7 +523,7 @@ foreach(e ${LIBVNCCLIENT_EXAMPLES})
add_executable(client_examples_${e} ${LIBVNCCLIEXAMPLE_DIR}/${e}.c ${LIBVNCCLIEXAMPLE_DIR}/${${e}_EXTRA_SOURCES} )
set_target_properties(client_examples_${e} PROPERTIES OUTPUT_NAME ${e})
set_target_properties(client_examples_${e} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/client_examples)
target_link_libraries(client_examples_${e} vncclient ${CMAKE_THREAD_LIBS_INIT} ${SDL2_LIBRARY} ${X11_LIBRARIES} ${FFMPEG_LIBRARIES})
target_link_libraries(client_examples_${e} vncclient ${CMAKE_THREAD_LIBS_INIT} ${SDL2_LIBRARY} ${FFMPEG_LIBRARIES})
endforeach(e ${LIBVNCCLIENT_EXAMPLES})

54
client_examples/SDLvncviewer.c

@ -5,7 +5,6 @@
#include <SDL.h>
#include <signal.h>
#include <rfb/rfbclient.h>
#include "scrap.h"
struct { int sdl; int rfb; } buttonMapping[]={
{1, rfbButton1Mask},
@ -410,6 +409,28 @@ static rfbBool handleSDLEvent(rfbClient *cl, SDL_Event *e)
SendFramebufferUpdateRequest(cl, 0, 0,
cl->width, cl->height, FALSE);
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
if (SDL_HasClipboardText()) {
char *text = SDL_GetClipboardText();
if(text) {
rfbClientLog("sending clipboard text '%s'\n", text);
SendClientCutText(cl, text, strlen(text));
}
}
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
if (rightAltKeyDown) {
SendKeyEvent(cl, XK_Alt_R, FALSE);
rightAltKeyDown = FALSE;
rfbClientLog("released right Alt key\n");
}
if (leftAltKeyDown) {
SendKeyEvent(cl, XK_Alt_L, FALSE);
leftAltKeyDown = FALSE;
rfbClientLog("released left Alt key\n");
}
break;
}
break;
case SDL_MOUSEBUTTONUP:
@ -473,31 +494,6 @@ static rfbBool handleSDLEvent(rfbClient *cl, SDL_Event *e)
exit(0);
}
/*FIXME
case SDL_ACTIVEEVENT:
if (!e->active.gain && rightAltKeyDown) {
SendKeyEvent(cl, XK_Alt_R, FALSE);
rightAltKeyDown = FALSE;
rfbClientLog("released right Alt key\n");
}
if (!e->active.gain && leftAltKeyDown) {
SendKeyEvent(cl, XK_Alt_L, FALSE);
leftAltKeyDown = FALSE;
rfbClientLog("released left Alt key\n");
}
if (e->active.gain && lost_scrap()) {
static char *data = NULL;
static int len = 0;
get_scrap(T('T', 'E', 'X', 'T'), &len, &data);
if (len)
SendClientCutText(cl, data, len);
}
break;
*/
case SDL_SYSWMEVENT:
clipboard_filter(e);
break;
/*FIXME
case SDL_VIDEORESIZE:
setRealDimension(cl, e->resize.w, e->resize.h);
break;
@ -510,7 +506,9 @@ static rfbBool handleSDLEvent(rfbClient *cl, SDL_Event *e)
static void got_selection(rfbClient *cl, const char *text, int len)
{
//FIXMEput_scrap(T('T', 'E', 'X', 'T'), len, text);
rfbClientLog("received clipboard text '%s'\n", text);
if(SDL_SetClipboardText(text) != 0)
rfbClientErr("could not set received clipboard text: %s\n", SDL_GetError());
}
@ -593,8 +591,6 @@ int main(int argc,char** argv) {
break;
}
init_scrap();
while(1) {
if(SDL_PollEvent(&e)) {
/*

559
client_examples/scrap.c

@ -1,559 +0,0 @@
/* Handle clipboard text and data in arbitrary formats */
#include <stdio.h>
#include <limits.h>
#ifdef WIN32
#include <SDL.h>
#include <SDL_syswm.h>
#else
#include <SDL/SDL.h>
#include <SDL/SDL_syswm.h>
#endif
#include "scrap.h"
#include "rfb/rfbconfig.h"
/* Determine what type of clipboard we are using */
#if defined(__unix__) && !defined(__QNXNTO__) && defined(SDL_VIDEO_DRIVER_X11)
#define X11_SCRAP
#elif defined(__WIN32__)
#define WIN_SCRAP
#elif defined(__QNXNTO__)
#define QNX_SCRAP
#else
#warning Unknown window manager for clipboard handling
#endif /* scrap type */
/* System dependent data types */
#if defined(X11_SCRAP)
typedef Atom scrap_type;
static Atom XA_TARGETS, XA_TEXT, XA_COMPOUND_TEXT, XA_UTF8_STRING;
#elif defined(WIN_SCRAP)
typedef UINT scrap_type;
#elif defined(QNX_SCRAP)
typedef uint32_t scrap_type;
#define Ph_CL_TEXT T('T', 'E', 'X', 'T')
#else
typedef int scrap_type;
#endif /* scrap type */
/* System dependent variables */
#if defined(X11_SCRAP)
static Display *SDL_Display;
static Window SDL_Window;
static void (*Lock_Display)(void);
static void (*Unlock_Display)(void);
static Atom XA_UTF8_STRING;
#elif defined(WIN_SCRAP)
static HWND SDL_Window;
#elif defined(QNX_SCRAP)
static unsigned short InputGroup;
#endif /* scrap type */
#define FORMAT_PREFIX "SDL_scrap_0x"
static scrap_type convert_format(int type)
{
switch (type) {
case T('T', 'E', 'X', 'T'):
#if defined(X11_SCRAP)
return XA_UTF8_STRING ? XA_UTF8_STRING : XA_STRING;
#elif defined(WIN_SCRAP)
return CF_TEXT;
#elif defined(QNX_SCRAP)
return Ph_CL_TEXT;
#endif /* scrap type */
default:
{
char format[sizeof(FORMAT_PREFIX)+8+1];
sprintf(format, "%s%08lx", FORMAT_PREFIX,
(unsigned long)type);
#if defined(X11_SCRAP)
return XInternAtom(SDL_Display, format, False);
#elif defined(WIN_SCRAP)
return RegisterClipboardFormat(format);
#endif /* scrap type */
}
}
}
/* Convert internal data to scrap format */
static int convert_data(int type, char *dst, const char *src, int srclen)
{
int dstlen;
dstlen = 0;
switch (type) {
case T('T', 'E', 'X', 'T'):
if (dst) {
while (--srclen >= 0) {
#if defined(__unix__)
if (*src == '\r') {
*dst++ = '\n';
++dstlen;
}
else
#elif defined(__WIN32__)
if (*src == '\r') {
*dst++ = '\r';
++dstlen;
*dst++ = '\n';
++dstlen;
}
else
#endif
{
*dst++ = *src;
++dstlen;
}
++src;
}
*dst = '\0';
++dstlen;
}
else {
while (--srclen >= 0) {
#if defined(__unix__)
if (*src == '\r')
++dstlen;
else
#elif defined(__WIN32__)
if (*src == '\r') {
++dstlen;
++dstlen;
}
else
#endif
{
++dstlen;
}
++src;
}
++dstlen;
}
break;
default:
if (dst) {
*(int *)dst = srclen;
dst += sizeof(int);
memcpy(dst, src, srclen);
}
dstlen = sizeof(int)+srclen;
break;
}
return(dstlen);
}
/* Convert scrap data to internal format */
static int convert_scrap(int type, char *dst, char *src, int srclen)
{
int dstlen;
dstlen = 0;
switch (type) {
case T('T', 'E', 'X', 'T'):
{
if (srclen == 0)
srclen = strlen(src);
if (dst) {
while (--srclen >= 0) {
#if defined(__WIN32__)
if (*src == '\r')
/* drop extraneous '\r' */;
else
#endif
if (*src == '\n') {
*dst++ = '\r';
++dstlen;
}
else {
*dst++ = *src;
++dstlen;
}
++src;
}
*dst = '\0';
++dstlen;
}
else {
while (--srclen >= 0) {
#if defined(__WIN32__)
/* drop extraneous '\r' */;
if (*src != '\r')
#endif
++dstlen;
++src;
}
++dstlen;
}
break;
}
default:
dstlen = *(int *)src;
if (dst)
memcpy(dst, src + sizeof(int),
srclen ? srclen - sizeof(int) : dstlen);
break;
}
return dstlen;
}
int init_scrap(void)
{
SDL_SysWMinfo info;
int retval;
/* Grab the window manager specific information */
retval = -1;
SDL_SetError("SDL is not running on known window manager");
SDL_VERSION(&info.version);
//FIXMEif (SDL_GetWMInfo(&info))
{
/* Save the information for later use */
#if defined(X11_SCRAP)
if (info.subsystem == SDL_SYSWM_X11) {
SDL_Display = info.info.x11.display;
SDL_Window = info.info.x11.window;
Lock_Display = info.info.x11.lock_func;
Unlock_Display = info.info.x11.unlock_func;
/* Enable the special window hook events */
SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
SDL_SetEventFilter(clipboard_filter);
XA_TARGETS = XInternAtom(SDL_Display, "TARGETS", False);
XA_TEXT = XInternAtom(SDL_Display, "TEXT", False);
XA_COMPOUND_TEXT = XInternAtom(SDL_Display,
"COMPOUND_TEXT", False);
XA_UTF8_STRING = XInternAtom(SDL_Display,
"UTF8_STRING", False);
retval = 0;
}
else
SDL_SetError("SDL is not running on X11");
#elif defined(WIN_SCRAP)
SDL_Window = info.window;
retval = 0;
#elif defined(QNX_SCRAP)
InputGroup = PhInputGroup(NULL);
retval = 0;
#endif /* scrap type */
}
return(retval);
}
int lost_scrap(void)
{
int retval;
#if defined(X11_SCRAP)
if (Lock_Display)
Lock_Display();
retval = (XGetSelectionOwner(SDL_Display, XA_PRIMARY) != SDL_Window);
if (Unlock_Display)
Unlock_Display();
#elif defined(WIN_SCRAP)
retval = (GetClipboardOwner() != SDL_Window);
#elif defined(QNX_SCRAP)
retval = (PhInputGroup(NULL) != InputGroup);
#endif /* scrap type */
return(retval);
}
void put_scrap(int type, int srclen, const char *src)
{
scrap_type format;
int dstlen;
char *dst;
format = convert_format(type);
dstlen = convert_data(type, NULL, src, srclen);
#if defined(X11_SCRAP)
dst = (char *)malloc(dstlen);
if (dst != NULL) {
if (Lock_Display)
Lock_Display();
convert_data(type, dst, src, srclen);
XChangeProperty(SDL_Display, DefaultRootWindow(SDL_Display),
XA_CUT_BUFFER0, format, 8, PropModeReplace,
(unsigned char *)dst, dstlen);
free(dst);
if (lost_scrap())
XSetSelectionOwner(SDL_Display, XA_PRIMARY,
SDL_Window, CurrentTime);
if (Unlock_Display)
Unlock_Display();
}
#elif defined(WIN_SCRAP)
if (OpenClipboard(SDL_Window)) {
HANDLE hMem;
hMem = GlobalAlloc((GMEM_MOVEABLE|GMEM_DDESHARE), dstlen);
if (hMem != NULL) {
dst = (char *)GlobalLock(hMem);
convert_data(type, dst, src, srclen);
GlobalUnlock(hMem);
EmptyClipboard();
SetClipboardData(format, hMem);
}
CloseClipboard();
}
#elif defined(QNX_SCRAP)
#if (_NTO_VERSION < 620) /* before 6.2.0 releases */
#define PhClipboardHdr PhClipHeader
#endif
{
PhClipboardHdr clheader = { Ph_CLIPBOARD_TYPE_TEXT, 0, NULL };
int* cldata;
int status;
dst = (char *)malloc(dstlen+4);
if (dst != NULL) {
cldata = (int*)dst;
*cldata = type;
convert_data(type, dst+4, src, srclen);
clheader.data = dst;
#if (_NTO_VERSION < 620) /* before 6.2.0 releases */
if (dstlen > 65535)
/* maximum photon clipboard size :(*/
clheader.length = 65535;
else
#endif
clheader.length = dstlen+4;
status = PhClipboardCopy(InputGroup, 1, &clheader);
if (status == -1)
fprintf(stderr,
"Photon: copy to clipboard failed!\n");
free(dst);
}
}
#endif /* scrap type */
}
void get_scrap(int type, int *dstlen, char **dst)
{
scrap_type format;
*dstlen = 0;
format = convert_format(type);
#if defined(X11_SCRAP)
{
Window owner;
Atom selection;
Atom seln_type;
int seln_format;
unsigned long nbytes;
unsigned long overflow;
char *src;
if (Lock_Display)
Lock_Display();
owner = XGetSelectionOwner(SDL_Display, XA_PRIMARY);
if (Unlock_Display)
Unlock_Display();
if ((owner == None) || (owner == SDL_Window)) {
owner = DefaultRootWindow(SDL_Display);
selection = XA_CUT_BUFFER0;
}
else {
int selection_response = 0;
SDL_Event event;
owner = SDL_Window;
if (Lock_Display)
Lock_Display();
selection = XInternAtom(SDL_Display, "SDL_SELECTION",
False);
XConvertSelection(SDL_Display, XA_PRIMARY, format,
selection, owner, CurrentTime);
if (Unlock_Display)
Unlock_Display();
while (!selection_response) {
SDL_WaitEvent(&event);
if (event.type == SDL_SYSWMEVENT) {
XEvent xevent =
event.syswm.msg->event.xevent;
if ((xevent.type == SelectionNotify) &&
(xevent.xselection.requestor
== owner))
selection_response = 1;
}
}
}
if (Lock_Display)
Lock_Display();
if (XGetWindowProperty(SDL_Display, owner, selection,
0, INT_MAX/4, False, format, &seln_type,
&seln_format, &nbytes, &overflow,
(unsigned char **)&src) == Success) {
if (seln_type == format) {
*dstlen = convert_scrap(type, NULL,
src, nbytes);
*dst = (char *)realloc(*dst, *dstlen);
if (*dst == NULL)
*dstlen = 0;
else
convert_scrap(type, *dst, src, nbytes);
}
XFree(src);
}
}
if (Unlock_Display)
Unlock_Display();
#elif defined(WIN_SCRAP)
if (IsClipboardFormatAvailable(format) && OpenClipboard(SDL_Window)) {
HANDLE hMem;
char *src;
hMem = GetClipboardData(format);
if (hMem != NULL) {
src = (char *)GlobalLock(hMem);
*dstlen = convert_scrap(type, NULL, src, 0);
*dst = (char *)realloc(*dst, *dstlen);
if (*dst == NULL)
*dstlen = 0;
else
convert_scrap(type, *dst, src, 0);
GlobalUnlock(hMem);
}
CloseClipboard();
}
#elif defined(QNX_SCRAP)
#if (_NTO_VERSION < 620) /* before 6.2.0 releases */
{
void* clhandle;
PhClipHeader* clheader;
int* cldata;
clhandle = PhClipboardPasteStart(InputGroup);
if (clhandle != NULL) {
clheader = PhClipboardPasteType(clhandle,
Ph_CLIPBOARD_TYPE_TEXT);
if (clheader != NULL) {
cldata = clheader->data;
if ((clheader->length>4) && (*cldata == type)) {
*dstlen = convert_scrap(type, NULL,
(char*)clheader->data+4,
clheader->length-4);
*dst = (char *)realloc(*dst, *dstlen);
if (*dst == NULL)
*dstlen = 0;
else
convert_scrap(type, *dst,
(char*)clheader->data+4,
clheader->length-4);
}
}
PhClipboardPasteFinish(clhandle);
}
}
#else /* 6.2.0 and 6.2.1 and future releases */
{
void* clhandle;
PhClipboardHdr* clheader;
int* cldata;
clheader=PhClipboardRead(InputGroup, Ph_CLIPBOARD_TYPE_TEXT);
if (clheader!=NULL) {
cldata=clheader->data;
if ((clheader->length>4) && (*cldata==type)) {
*dstlen = convert_scrap(type, NULL,
(char*)clheader->data+4,
clheader->length-4);
*dst = (char *)realloc(*dst, *dstlen);
if (*dst == NULL)
*dstlen = 0;
else
convert_scrap(type, *dst,
(char*)clheader->data+4,
clheader->length-4);
}
}
}
#endif
#endif /* scrap type */
}
int clipboard_filter(const SDL_Event *event)
{
#if defined(X11_SCRAP)
/* Post all non-window manager specific events */
if (event->type != SDL_SYSWMEVENT)
return(1);
/* Handle window-manager specific clipboard events */
switch (event->syswm.msg->event.xevent.type) {
/* Copy the selection from XA_CUT_BUFFER0 to the requested property */
case SelectionRequest: {
XSelectionRequestEvent *req;
XEvent sevent;
int seln_format;
unsigned long nbytes;
unsigned long overflow;
unsigned char *seln_data;
req = &event->syswm.msg->event.xevent.xselectionrequest;
if (req->target == XA_TARGETS) {
Atom supported[] = {
XA_TEXT, XA_COMPOUND_TEXT, XA_UTF8_STRING,
XA_TARGETS, XA_STRING
};
XEvent response;
XChangeProperty(SDL_Display, req->requestor,
req->property, req->target, 32, PropModeReplace,
(unsigned char*)supported,
sizeof(supported) / sizeof(supported[0]));
response.xselection.property=None;
response.xselection.type= SelectionNotify;
response.xselection.display= req->display;
response.xselection.requestor= req->requestor;
response.xselection.selection=req->selection;
response.xselection.target= req->target;
response.xselection.time = req->time;
XSendEvent (SDL_Display, req->requestor,0,0,&response);
XFlush (SDL_Display);
return 1;
}
sevent.xselection.type = SelectionNotify;
sevent.xselection.display = req->display;
sevent.xselection.selection = req->selection;
sevent.xselection.target = None;
sevent.xselection.property = req->property;
sevent.xselection.requestor = req->requestor;
sevent.xselection.time = req->time;
if (XGetWindowProperty(SDL_Display,
DefaultRootWindow(SDL_Display), XA_CUT_BUFFER0,
0, INT_MAX/4, False, req->target,
&sevent.xselection.target, &seln_format,
&nbytes, &overflow, &seln_data) == Success) {
if (sevent.xselection.target == req->target) {
if (sevent.xselection.target == XA_STRING &&
nbytes > 0 &&
seln_data[nbytes-1] == '\0')
--nbytes;
XChangeProperty(SDL_Display, req->requestor,
req->property, sevent.xselection.target,
seln_format, PropModeReplace,
seln_data, nbytes);
sevent.xselection.property = req->property;
}
XFree(seln_data);
}
XSendEvent(SDL_Display,req->requestor,False,0,&sevent);
XSync(SDL_Display, False);
break;
}
}
/* Post the event for X11 clipboard reading above */
#endif /* X11_SCRAP */
return(1);
}

18
client_examples/scrap.h

@ -1,18 +0,0 @@
/* Handle clipboard text and data in arbitrary formats */
/* Miscellaneous defines */
#define T(A, B, C, D) (int)((A<<24)|(B<<16)|(C<<8)|(D<<0))
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
extern int init_scrap(void);
extern int lost_scrap(void);
extern void put_scrap(int type, int srclen, const char *src);
extern void get_scrap(int type, int *dstlen, char **dst);
extern int clipboard_filter(const SDL_Event *event);
#ifdef __cplusplus
}
#endif /* __cplusplus */
Loading…
Cancel
Save