We now filter incoming data, which means we can start assuming the clipboard data is always null terminated. This allows us to clean up a lot of the internal handling.tags/v1.9.90
virtual void setColourMapEntries(int firstColour, int nColours, | virtual void setColourMapEntries(int firstColour, int nColours, | ||||
rdr::U16* rgbs) = 0; | rdr::U16* rgbs) = 0; | ||||
virtual void bell() = 0; | virtual void bell() = 0; | ||||
virtual void serverCutText(const char* str, rdr::U32 len) = 0; | |||||
virtual void serverCutText(const char* str) = 0; | |||||
virtual void setLEDState(unsigned int state); | virtual void setLEDState(unsigned int state); | ||||
CharArray ca(len); | CharArray ca(len); | ||||
is->readBytes(ca.buf, len); | is->readBytes(ca.buf, len); | ||||
CharArray filtered(convertLF(ca.buf, len)); | CharArray filtered(convertLF(ca.buf, len)); | ||||
handler->serverCutText(filtered.buf, strlen(filtered.buf)); | |||||
handler->serverCutText(filtered.buf); | |||||
} | } | ||||
void CMsgReader::readFence() | void CMsgReader::readFence() |
} | } | ||||
void CMsgWriter::writeClientCutText(const char* str, rdr::U32 len) | |||||
void CMsgWriter::writeClientCutText(const char* str) | |||||
{ | { | ||||
if (memchr(str, '\r', len) != NULL) | |||||
size_t len; | |||||
if (strchr(str, '\r') != NULL) | |||||
throw Exception("Invalid carriage return in clipboard data"); | throw Exception("Invalid carriage return in clipboard data"); | ||||
len = strlen(str); | |||||
startMsg(msgTypeClientCutText); | startMsg(msgTypeClientCutText); | ||||
os->pad(3); | os->pad(3); | ||||
os->writeU32(len); | os->writeU32(len); |
void writeKeyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); | void writeKeyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); | ||||
void writePointerEvent(const Point& pos, int buttonMask); | void writePointerEvent(const Point& pos, int buttonMask); | ||||
void writeClientCutText(const char* str, rdr::U32 len); | |||||
void writeClientCutText(const char* str); | |||||
protected: | protected: | ||||
void startMsg(int type); | void startMsg(int type); |
bool __unused_attr down) { } | bool __unused_attr down) { } | ||||
virtual void pointerEvent(const Point& __unused_attr pos, | virtual void pointerEvent(const Point& __unused_attr pos, | ||||
int __unused_attr buttonMask) { } | int __unused_attr buttonMask) { } | ||||
virtual void clientCutText(const char* __unused_attr str, | |||||
int __unused_attr len) { } | |||||
virtual void clientCutText(const char* __unused_attr str) { } | |||||
}; | }; | ||||
} | } |
CharArray ca(len); | CharArray ca(len); | ||||
is->readBytes(ca.buf, len); | is->readBytes(ca.buf, len); | ||||
CharArray filtered(convertLF(ca.buf, len)); | CharArray filtered(convertLF(ca.buf, len)); | ||||
handler->clientCutText(filtered.buf, strlen(filtered.buf)); | |||||
handler->clientCutText(filtered.buf); | |||||
} | } | ||||
void SMsgReader::readQEMUMessage() | void SMsgReader::readQEMUMessage() |
endMsg(); | endMsg(); | ||||
} | } | ||||
void SMsgWriter::writeServerCutText(const char* str, int len) | |||||
void SMsgWriter::writeServerCutText(const char* str) | |||||
{ | { | ||||
if (memchr(str, '\r', len) != NULL) | |||||
size_t len; | |||||
if (strchr(str, '\r') != NULL) | |||||
throw Exception("Invalid carriage return in clipboard data"); | throw Exception("Invalid carriage return in clipboard data"); | ||||
len = strlen(str); | |||||
startMsg(msgTypeServerCutText); | startMsg(msgTypeServerCutText); | ||||
os->pad(3); | os->pad(3); | ||||
os->writeU32(len); | os->writeU32(len); |
// writeBell() and writeServerCutText() do the obvious thing. | // writeBell() and writeServerCutText() do the obvious thing. | ||||
void writeBell(); | void writeBell(); | ||||
void writeServerCutText(const char* str, int len); | |||||
void writeServerCutText(const char* str); | |||||
// writeFence() sends a new fence request or response to the client. | // writeFence() sends a new fence request or response to the client. | ||||
void writeFence(rdr::U32 flags, unsigned len, const char data[]); | void writeFence(rdr::U32 flags, unsigned len, const char data[]); |
} | } | ||||
} | } | ||||
void VNCSConnectionST::serverCutTextOrClose(const char *str, int len) | |||||
void VNCSConnectionST::serverCutTextOrClose(const char *str) | |||||
{ | { | ||||
try { | try { | ||||
if (!accessCheck(AccessCutText)) return; | if (!accessCheck(AccessCutText)) return; | ||||
if (!rfb::Server::sendCutText) return; | if (!rfb::Server::sendCutText) return; | ||||
if (state() == RFBSTATE_NORMAL) | if (state() == RFBSTATE_NORMAL) | ||||
writer()->writeServerCutText(str, len); | |||||
writer()->writeServerCutText(str); | |||||
} catch(rdr::Exception& e) { | } catch(rdr::Exception& e) { | ||||
close(e.str()); | close(e.str()); | ||||
} | } | ||||
server->keyEvent(keysym, keycode, down); | server->keyEvent(keysym, keycode, down); | ||||
} | } | ||||
void VNCSConnectionST::clientCutText(const char* str, int len) | |||||
void VNCSConnectionST::clientCutText(const char* str) | |||||
{ | { | ||||
if (!accessCheck(AccessCutText)) return; | if (!accessCheck(AccessCutText)) return; | ||||
if (!rfb::Server::acceptCutText) return; | if (!rfb::Server::acceptCutText) return; | ||||
server->clientCutText(str, len); | |||||
server->clientCutText(str); | |||||
} | } | ||||
void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental) | void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental) |
void screenLayoutChangeOrClose(rdr::U16 reason); | void screenLayoutChangeOrClose(rdr::U16 reason); | ||||
void setCursorOrClose(); | void setCursorOrClose(); | ||||
void bellOrClose(); | void bellOrClose(); | ||||
void serverCutTextOrClose(const char *str, int len); | |||||
void serverCutTextOrClose(const char *str); | |||||
void setDesktopNameOrClose(const char *name); | void setDesktopNameOrClose(const char *name); | ||||
void setLEDStateOrClose(unsigned int state); | void setLEDStateOrClose(unsigned int state); | ||||
void approveConnectionOrClose(bool accept, const char* reason); | void approveConnectionOrClose(bool accept, const char* reason); | ||||
virtual void setPixelFormat(const PixelFormat& pf); | virtual void setPixelFormat(const PixelFormat& pf); | ||||
virtual void pointerEvent(const Point& pos, int buttonMask); | virtual void pointerEvent(const Point& pos, int buttonMask); | ||||
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); | virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); | ||||
virtual void clientCutText(const char* str, int len); | |||||
virtual void clientCutText(const char* str); | |||||
virtual void framebufferUpdateRequest(const Rect& r, bool incremental); | virtual void framebufferUpdateRequest(const Rect& r, bool incremental); | ||||
virtual void setDesktopSize(int fb_width, int fb_height, | virtual void setDesktopSize(int fb_width, int fb_height, | ||||
const ScreenSet& layout); | const ScreenSet& layout); |
// serverCutText() tells the server that the cut text has changed. This | // serverCutText() tells the server that the cut text has changed. This | ||||
// will normally be sent to all clients. | // will normally be sent to all clients. | ||||
virtual void serverCutText(const char* str, int len) = 0; | |||||
virtual void serverCutText(const char* str) = 0; | |||||
// bell() tells the server that it should make all clients make a bell sound. | // bell() tells the server that it should make all clients make a bell sound. | ||||
virtual void bell() = 0; | virtual void bell() = 0; |
} | } | ||||
} | } | ||||
void VNCServerST::serverCutText(const char* str, int len) | |||||
void VNCServerST::serverCutText(const char* str) | |||||
{ | { | ||||
if (memchr(str, '\r', len) != NULL) | |||||
if (strchr(str, '\r') != NULL) | |||||
throw Exception("Invalid carriage return in clipboard data"); | throw Exception("Invalid carriage return in clipboard data"); | ||||
std::list<VNCSConnectionST*>::iterator ci, ci_next; | std::list<VNCSConnectionST*>::iterator ci, ci_next; | ||||
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) { | for (ci = clients.begin(); ci != clients.end(); ci = ci_next) { | ||||
ci_next = ci; ci_next++; | ci_next = ci; ci_next++; | ||||
(*ci)->serverCutTextOrClose(str, len); | |||||
(*ci)->serverCutTextOrClose(str); | |||||
} | } | ||||
} | } | ||||
desktop->pointerEvent(pos, buttonMask); | desktop->pointerEvent(pos, buttonMask); | ||||
} | } | ||||
void VNCServerST::clientCutText(const char* str, int len) | |||||
void VNCServerST::clientCutText(const char* str) | |||||
{ | { | ||||
desktop->clientCutText(str, len); | |||||
desktop->clientCutText(str); | |||||
} | } | ||||
unsigned int VNCServerST::setDesktopSize(VNCSConnectionST* requester, | unsigned int VNCServerST::setDesktopSize(VNCSConnectionST* requester, |
virtual void setPixelBuffer(PixelBuffer* pb); | virtual void setPixelBuffer(PixelBuffer* pb); | ||||
virtual void setScreenLayout(const ScreenSet& layout); | virtual void setScreenLayout(const ScreenSet& layout); | ||||
virtual const PixelBuffer* getPixelBuffer() const { return pb; } | virtual const PixelBuffer* getPixelBuffer() const { return pb; } | ||||
virtual void serverCutText(const char* str, int len); | |||||
virtual void serverCutText(const char* str); | |||||
virtual void approveConnection(network::Socket* sock, bool accept, | virtual void approveConnection(network::Socket* sock, bool accept, | ||||
const char* reason); | const char* reason); | ||||
// Event handlers | // Event handlers | ||||
void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); | void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); | ||||
void pointerEvent(VNCSConnectionST* client, const Point& pos, int buttonMask); | void pointerEvent(VNCSConnectionST* client, const Point& pos, int buttonMask); | ||||
void clientCutText(const char* str, int len); | |||||
void clientCutText(const char* str); | |||||
unsigned int setDesktopSize(VNCSConnectionST* requester, | unsigned int setDesktopSize(VNCSConnectionST* requester, | ||||
int fb_width, int fb_height, | int fb_width, int fb_height, |
virtual void framebufferUpdateEnd(); | virtual void framebufferUpdateEnd(); | ||||
virtual void setColourMapEntries(int, int, rdr::U16*); | virtual void setColourMapEntries(int, int, rdr::U16*); | ||||
virtual void bell(); | virtual void bell(); | ||||
virtual void serverCutText(const char*, rdr::U32); | |||||
virtual void serverCutText(const char*); | |||||
public: | public: | ||||
double cpuTime; | double cpuTime; | ||||
{ | { | ||||
} | } | ||||
void CConn::serverCutText(const char*, rdr::U32) | |||||
void CConn::serverCutText(const char*) | |||||
{ | { | ||||
} | } | ||||
virtual void dataRect(const rfb::Rect&, int); | virtual void dataRect(const rfb::Rect&, int); | ||||
virtual void setColourMapEntries(int, int, rdr::U16*); | virtual void setColourMapEntries(int, int, rdr::U16*); | ||||
virtual void bell(); | virtual void bell(); | ||||
virtual void serverCutText(const char*, rdr::U32); | |||||
virtual void serverCutText(const char*); | |||||
public: | public: | ||||
double decodeTime; | double decodeTime; | ||||
{ | { | ||||
} | } | ||||
void CConn::serverCutText(const char*, rdr::U32) | |||||
void CConn::serverCutText(const char*) | |||||
{ | { | ||||
} | } | ||||
#endif | #endif | ||||
} | } | ||||
void XDesktop::clientCutText(const char* str, int len) { | |||||
void XDesktop::clientCutText(const char* str) { | |||||
} | } | ||||
ScreenSet XDesktop::computeScreenLayout() | ScreenSet XDesktop::computeScreenLayout() |
virtual void pointerEvent(const rfb::Point& pos, int buttonMask); | virtual void pointerEvent(const rfb::Point& pos, int buttonMask); | ||||
KeyCode XkbKeysymToKeycode(Display* dpy, KeySym keysym); | KeyCode XkbKeysymToKeycode(Display* dpy, KeySym keysym); | ||||
virtual void keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down); | virtual void keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down); | ||||
virtual void clientCutText(const char* str, int len); | |||||
virtual void clientCutText(const char* str); | |||||
virtual unsigned int setScreenLayout(int fb_width, int fb_height, | virtual unsigned int setScreenLayout(int fb_width, int fb_height, | ||||
const rfb::ScreenSet& layout); | const rfb::ScreenSet& layout); | ||||
server->setLEDState(state); | server->setLEDState(state); | ||||
} | } | ||||
void XserverDesktop::serverCutText(const char* str, int len) | |||||
void XserverDesktop::serverCutText(const char* str) | |||||
{ | { | ||||
try { | try { | ||||
server->serverCutText(str, len); | |||||
server->serverCutText(str); | |||||
} catch (rdr::Exception& e) { | } catch (rdr::Exception& e) { | ||||
vlog.error("XserverDesktop::serverCutText: %s",e.str()); | vlog.error("XserverDesktop::serverCutText: %s",e.str()); | ||||
} | } | ||||
vncPointerButtonAction(buttonMask); | vncPointerButtonAction(buttonMask); | ||||
} | } | ||||
void XserverDesktop::clientCutText(const char* str, int len) | |||||
void XserverDesktop::clientCutText(const char* str) | |||||
{ | { | ||||
vncClientCutText(str, len); | |||||
vncClientCutText(str); | |||||
} | } | ||||
unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height, | unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height, |
void refreshScreenLayout(); | void refreshScreenLayout(); | ||||
void bell(); | void bell(); | ||||
void setLEDState(unsigned int state); | void setLEDState(unsigned int state); | ||||
void serverCutText(const char* str, int len); | |||||
void serverCutText(const char* str); | |||||
void setDesktopName(const char* name); | void setDesktopName(const char* name); | ||||
void setCursor(int width, int height, int hotX, int hotY, | void setCursor(int width, int height, int hotX, int hotY, | ||||
const unsigned char *rgbaData); | const unsigned char *rgbaData); | ||||
const char* userName); | const char* userName); | ||||
virtual void pointerEvent(const rfb::Point& pos, int buttonMask); | virtual void pointerEvent(const rfb::Point& pos, int buttonMask); | ||||
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); | virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); | ||||
virtual void clientCutText(const char* str, int len); | |||||
virtual void clientCutText(const char* str); | |||||
virtual unsigned int setScreenLayout(int fb_width, int fb_height, | virtual unsigned int setScreenLayout(int fb_width, int fb_height, | ||||
const rfb::ScreenSet& layout); | const rfb::ScreenSet& layout); | ||||
desktop[scr]->setDesktopName(desktopName); | desktop[scr]->setDesktopName(desktopName); | ||||
} | } | ||||
void vncServerCutText(const char *text, size_t len) | |||||
void vncServerCutText(const char *text) | |||||
{ | { | ||||
for (int scr = 0; scr < vncGetScreenCount(); scr++) | for (int scr = 0; scr < vncGetScreenCount(); scr++) | ||||
desktop[scr]->serverCutText(text, len); | |||||
desktop[scr]->serverCutText(text); | |||||
} | } | ||||
int vncConnectClient(const char *addr) | int vncConnectClient(const char *addr) |
void vncUpdateDesktopName(void); | void vncUpdateDesktopName(void); | ||||
void vncServerCutText(const char *text, size_t len); | |||||
void vncServerCutText(const char *text); | |||||
int vncConnectClient(const char *addr); | int vncConnectClient(const char *addr); | ||||
static Window wid; | static Window wid; | ||||
static char* clientCutText; | static char* clientCutText; | ||||
static int clientCutTextLen; | |||||
static int vncCreateSelectionWindow(void); | static int vncCreateSelectionWindow(void); | ||||
static int vncOwnSelection(Atom selection); | static int vncOwnSelection(Atom selection); | ||||
FatalError("Add VNC SelectionCallback failed\n"); | FatalError("Add VNC SelectionCallback failed\n"); | ||||
} | } | ||||
void vncClientCutText(const char* str, int len) | |||||
void vncClientCutText(const char* str) | |||||
{ | { | ||||
int rc; | int rc; | ||||
if (clientCutText != NULL) | if (clientCutText != NULL) | ||||
free(clientCutText); | free(clientCutText); | ||||
clientCutText = malloc(len); | |||||
clientCutText = strdup(str); | |||||
if (clientCutText == NULL) { | if (clientCutText == NULL) { | ||||
LOG_ERROR("Could not allocate clipboard buffer"); | LOG_ERROR("Could not allocate clipboard buffer"); | ||||
DeleteWindowFromAnySelections(pWindow); | DeleteWindowFromAnySelections(pWindow); | ||||
return; | return; | ||||
} | } | ||||
memcpy(clientCutText, str, len); | |||||
clientCutTextLen = len; | |||||
if (vncGetSetPrimary()) { | if (vncGetSetPrimary()) { | ||||
rc = vncOwnSelection(xaPRIMARY); | rc = vncOwnSelection(xaPRIMARY); | ||||
if (rc != Success) | if (rc != Success) | ||||
} else if ((target == xaSTRING) || (target == xaTEXT)) { | } else if ((target == xaSTRING) || (target == xaTEXT)) { | ||||
rc = dixChangeWindowProperty(serverClient, pWin, realProperty, | rc = dixChangeWindowProperty(serverClient, pWin, realProperty, | ||||
XA_STRING, 8, PropModeReplace, | XA_STRING, 8, PropModeReplace, | ||||
clientCutTextLen, clientCutText, | |||||
strlen(clientCutText), clientCutText, | |||||
TRUE); | TRUE); | ||||
if (rc != Success) | if (rc != Success) | ||||
return rc; | return rc; | ||||
const unsigned char* in; | const unsigned char* in; | ||||
size_t in_len; | size_t in_len; | ||||
buffer = malloc(clientCutTextLen*2); | |||||
buffer = malloc(strlen(clientCutText)*2); | |||||
if (buffer == NULL) | if (buffer == NULL) | ||||
return BadAlloc; | return BadAlloc; | ||||
out = buffer; | out = buffer; | ||||
len = 0; | len = 0; | ||||
in = clientCutText; | in = clientCutText; | ||||
in_len = clientCutTextLen; | |||||
while (in_len > 0) { | |||||
while (*in != '\0') { | |||||
if (*in & 0x80) { | if (*in & 0x80) { | ||||
*out++ = 0xc0 | (*in >> 6); | *out++ = 0xc0 | (*in >> 6); | ||||
*out++ = 0x80 | (*in & 0x3f); | *out++ = 0x80 | (*in & 0x3f); | ||||
len += 2; | len += 2; | ||||
in++; | in++; | ||||
in_len--; | |||||
} else { | } else { | ||||
*out++ = *in++; | *out++ = *in++; | ||||
len++; | len++; | ||||
in_len--; | |||||
} | } | ||||
} | } | ||||
if (filtered == NULL) | if (filtered == NULL) | ||||
return; | return; | ||||
vncServerCutText(filtered, strlen(filtered)); | |||||
vncServerCutText(filtered); | |||||
vncStrFree(filtered); | vncStrFree(filtered); | ||||
} else if (target == xaUTF8_STRING) { | } else if (target == xaUTF8_STRING) { | ||||
if (filtered == NULL) | if (filtered == NULL) | ||||
return; | return; | ||||
vncServerCutText(filtered, strlen(filtered)); | |||||
vncServerCutText(filtered); | |||||
vncStrFree(filtered); | vncStrFree(filtered); | ||||
} | } |
/* Copyright 2016 Pierre Ossman for Cendio AB | |||||
/* Copyright 2016-2019 Pierre Ossman for Cendio AB | |||||
* | * | ||||
* This is free software; you can redistribute it and/or modify | * This is free software; you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
void vncSelectionInit(void); | void vncSelectionInit(void); | ||||
void vncClientCutText(const char* str, int len); | |||||
void vncClientCutText(const char* str); | |||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
} | } |
fl_beep(); | fl_beep(); | ||||
} | } | ||||
void CConn::serverCutText(const char* str, rdr::U32 len) | |||||
void CConn::serverCutText(const char* str) | |||||
{ | { | ||||
desktop->serverCutText(str, len); | |||||
desktop->serverCutText(str); | |||||
} | } | ||||
void CConn::dataRect(const Rect& r, int encoding) | void CConn::dataRect(const Rect& r, int encoding) |
void bell(); | void bell(); | ||||
void serverCutText(const char* str, rdr::U32 len); | |||||
void serverCutText(const char* str); | |||||
void framebufferUpdateStart(); | void framebufferUpdateStart(); | ||||
void framebufferUpdateEnd(); | void framebufferUpdateEnd(); |
} | } | ||||
void DesktopWindow::serverCutText(const char* str, rdr::U32 len) | |||||
void DesktopWindow::serverCutText(const char* str) | |||||
{ | { | ||||
viewport->serverCutText(str, len); | |||||
viewport->serverCutText(str); | |||||
} | } | ||||
void resizeFramebuffer(int new_w, int new_h); | void resizeFramebuffer(int new_w, int new_h); | ||||
// Incoming clipboard from server | // Incoming clipboard from server | ||||
void serverCutText(const char* str, rdr::U32 len); | |||||
void serverCutText(const char* str); | |||||
// New image for the locally rendered cursor | // New image for the locally rendered cursor | ||||
void setCursor(int width, int height, const rfb::Point& hotspot, | void setCursor(int width, int height, const rfb::Point& hotspot, |
damage(FL_DAMAGE_USER1, r.tl.x + x(), r.tl.y + y(), r.width(), r.height()); | damage(FL_DAMAGE_USER1, r.tl.x + x(), r.tl.y + y(), r.width(), r.height()); | ||||
} | } | ||||
void Viewport::serverCutText(const char* str, rdr::U32 len) | |||||
void Viewport::serverCutText(const char* str) | |||||
{ | { | ||||
char *buffer; | char *buffer; | ||||
int size, ret; | int size, ret; | ||||
if (!acceptClipboard) | if (!acceptClipboard) | ||||
return; | return; | ||||
size = fl_utf8froma(NULL, 0, str, len); | |||||
size = fl_utf8froma(NULL, 0, str, strlen(str)); | |||||
if (size <= 0) | if (size <= 0) | ||||
return; | return; | ||||
buffer = new char[size]; | buffer = new char[size]; | ||||
ret = fl_utf8froma(buffer, size, str, len); | |||||
ret = fl_utf8froma(buffer, size, str, strlen(str)); | |||||
assert(ret < size); | assert(ret < size); | ||||
vlog.debug("Got clipboard data (%d bytes)", (int)strlen(buffer)); | vlog.debug("Got clipboard data (%d bytes)", (int)strlen(buffer)); | ||||
vlog.debug("Sending clipboard data (%d bytes)", (int)strlen(filtered)); | vlog.debug("Sending clipboard data (%d bytes)", (int)strlen(filtered)); | ||||
try { | try { | ||||
cc->writer()->writeClientCutText(filtered, strlen(filtered)); | |||||
cc->writer()->writeClientCutText(filtered); | |||||
} catch (rdr::Exception& e) { | } catch (rdr::Exception& e) { | ||||
vlog.error("%s", e.str()); | vlog.error("%s", e.str()); | ||||
exit_vncviewer(e.str()); | exit_vncviewer(e.str()); | ||||
size_t len = strlen(pendingClientCutText); | size_t len = strlen(pendingClientCutText); | ||||
vlog.debug("Sending pending clipboard data (%d bytes)", (int)len); | vlog.debug("Sending pending clipboard data (%d bytes)", (int)len); | ||||
try { | try { | ||||
cc->writer()->writeClientCutText(pendingClientCutText, len); | |||||
cc->writer()->writeClientCutText(pendingClientCutText); | |||||
} catch (rdr::Exception& e) { | } catch (rdr::Exception& e) { | ||||
vlog.error("%s", e.str()); | vlog.error("%s", e.str()); | ||||
exit_vncviewer(e.str()); | exit_vncviewer(e.str()); |
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. | /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. | ||||
* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB | |||||
* Copyright 2011-2019 Pierre Ossman <ossman@cendio.se> for Cendio AB | |||||
* | * | ||||
* This is free software; you can redistribute it and/or modify | * This is free software; you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
void updateWindow(); | void updateWindow(); | ||||
// Incoming clipboard from server | // Incoming clipboard from server | ||||
void serverCutText(const char* str, rdr::U32 len); | |||||
void serverCutText(const char* str); | |||||
// New image for the locally rendered cursor | // New image for the locally rendered cursor | ||||
void setCursor(int width, int height, const rfb::Point& hotspot, | void setCursor(int width, int height, const rfb::Point& hotspot, |
// Notify clients | // Notify clients | ||||
if (notifier) { | if (notifier) { | ||||
if (!clipdata) { | if (!clipdata) { | ||||
notifier->notifyClipboardChanged(0, 0); | |||||
notifier->notifyClipboardChanged(0); | |||||
} else { | } else { | ||||
CharArray unix_text(convertLF(clipdata, strlen(clipdata))); | CharArray unix_text(convertLF(clipdata, strlen(clipdata))); | ||||
removeNonISOLatin1Chars(unix_text.buf); | removeNonISOLatin1Chars(unix_text.buf); | ||||
notifier->notifyClipboardChanged(unix_text.buf, strlen(unix_text.buf)); | |||||
notifier->notifyClipboardChanged(unix_text.buf); | |||||
} | } | ||||
} else { | } else { | ||||
vlog.debug("no clipboard notifier registered"); | vlog.debug("no clipboard notifier registered"); |
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. | /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. | ||||
* Copyright 2016-2019 Pierre Ossman for Cendio AB | |||||
* | * | ||||
* This is free software; you can redistribute it and/or modify | * This is free software; you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
// -=- Abstract base class for callback recipients | // -=- Abstract base class for callback recipients | ||||
class Notifier { | class Notifier { | ||||
public: | public: | ||||
virtual void notifyClipboardChanged(const char* text, int len) = 0; | |||||
virtual void notifyClipboardChanged(const char* text) = 0; | |||||
virtual ~Notifier() {}; | virtual ~Notifier() {}; | ||||
}; | }; | ||||
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. | /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. | ||||
* Copyright 2011-2019 Pierre Ossman for Cendio AB | |||||
* | * | ||||
* This is free software; you can redistribute it and/or modify | * This is free software; you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
return false; | return false; | ||||
} | } | ||||
void SDisplay::clientCutText(const char* text, int len) { | |||||
CharArray clip_sz(len+1); | |||||
memcpy(clip_sz.buf, text, len); | |||||
clip_sz.buf[len] = 0; | |||||
clipboard->setClipText(clip_sz.buf); | |||||
void SDisplay::clientCutText(const char* text) { | |||||
clipboard->setClipText(text); | |||||
} | } | ||||
void | void | ||||
SDisplay::notifyClipboardChanged(const char* text, int len) { | |||||
SDisplay::notifyClipboardChanged(const char* text) { | |||||
vlog.debug("clipboard text changed"); | vlog.debug("clipboard text changed"); | ||||
if (server) | if (server) | ||||
server->serverCutText(text, len); | |||||
server->serverCutText(text); | |||||
} | } | ||||
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. | /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. | ||||
* Copyright 2011-2019 Pierre Ossman for Cendio AB | |||||
* | * | ||||
* This is free software; you can redistribute it and/or modify | * This is free software; you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
const char* userName); | const char* userName); | ||||
virtual void pointerEvent(const Point& pos, int buttonmask); | virtual void pointerEvent(const Point& pos, int buttonmask); | ||||
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); | virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); | ||||
virtual void clientCutText(const char* str, int len); | |||||
virtual void clientCutText(const char* str); | |||||
// -=- Clipboard | // -=- Clipboard | ||||
virtual void notifyClipboardChanged(const char* text, int len); | |||||
virtual void notifyClipboardChanged(const char* text); | |||||
// -=- Display events | // -=- Display events | ||||