Improved clipboard API
Change the internal clipboard API to use a request based model in
order to be prepared for more advanced clipboard transfers.
diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx
index 2cc1fe4..6ba3276 100644
--- a/vncviewer/CConn.cxx
+++ b/vncviewer/CConn.cxx
@@ -377,11 +377,6 @@
fl_beep();
}
-void CConn::serverCutText(const char* str)
-{
- desktop->serverCutText(str);
-}
-
void CConn::dataRect(const Rect& r, int encoding)
{
sock->inStream().startTiming();
@@ -422,6 +417,21 @@
desktop->setLEDState(state);
}
+void CConn::handleClipboardRequest()
+{
+ desktop->handleClipboardRequest();
+}
+
+void CConn::handleClipboardAnnounce(bool available)
+{
+ desktop->handleClipboardAnnounce(available);
+}
+
+void CConn::handleClipboardData(const char* data)
+{
+ desktop->handleClipboardData(data);
+}
+
////////////////////// Internal methods //////////////////////
diff --git a/vncviewer/CConn.h b/vncviewer/CConn.h
index 38e09c2..4d935c9 100644
--- a/vncviewer/CConn.h
+++ b/vncviewer/CConn.h
@@ -61,8 +61,6 @@
void bell();
- void serverCutText(const char* str);
-
void framebufferUpdateStart();
void framebufferUpdateEnd();
void dataRect(const rfb::Rect& r, int encoding);
@@ -74,6 +72,10 @@
void setLEDState(unsigned int state);
+ virtual void handleClipboardRequest();
+ virtual void handleClipboardAnnounce(bool available);
+ virtual void handleClipboardData(const char* data);
+
private:
void resizeFramebuffer();
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index 4429e77..4860b92 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -276,12 +276,6 @@
}
-void DesktopWindow::serverCutText(const char* str)
-{
- viewport->serverCutText(str);
-}
-
-
void DesktopWindow::setCursor(int width, int height,
const rfb::Point& hotspot,
const rdr::U8* data)
@@ -420,6 +414,22 @@
}
+void DesktopWindow::handleClipboardRequest()
+{
+ viewport->handleClipboardRequest();
+}
+
+void DesktopWindow::handleClipboardAnnounce(bool available)
+{
+ viewport->handleClipboardAnnounce(available);
+}
+
+void DesktopWindow::handleClipboardData(const char* data)
+{
+ viewport->handleClipboardData(data);
+}
+
+
void DesktopWindow::resize(int x, int y, int w, int h)
{
bool resizing;
diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h
index fe938d9..6b03325 100644
--- a/vncviewer/DesktopWindow.h
+++ b/vncviewer/DesktopWindow.h
@@ -62,9 +62,6 @@
// Resize the current framebuffer, but retain the contents
void resizeFramebuffer(int new_w, int new_h);
- // Incoming clipboard from server
- void serverCutText(const char* str);
-
// New image for the locally rendered cursor
void setCursor(int width, int height, const rfb::Point& hotspot,
const rdr::U8* data);
@@ -72,6 +69,11 @@
// Change client LED state
void setLEDState(unsigned int state);
+ // Clipboard events
+ void handleClipboardRequest();
+ void handleClipboardAnnounce(bool available);
+ void handleClipboardData(const char* data);
+
// Fl_Window callback methods
void draw();
void resize(int x, int y, int w, int h);
diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx
index 151ecb4..713d364 100644
--- a/vncviewer/Viewport.cxx
+++ b/vncviewer/Viewport.cxx
@@ -119,7 +119,7 @@
altGrArmed(false),
#endif
firstLEDState(true),
- pendingServerCutText(NULL), pendingClientCutText(NULL),
+ pendingServerClipboard(false), pendingClientClipboard(false),
menuCtrlKey(false), menuAltKey(false), cursor(NULL)
{
#if !defined(WIN32) && !defined(__APPLE__)
@@ -208,8 +208,6 @@
delete cursor;
}
- clearPendingClipboard();
-
// FLTK automatically deletes all child widgets, so we shouldn't touch
// them ourselves here
}
@@ -232,37 +230,6 @@
damage(FL_DAMAGE_USER1, r.tl.x + x(), r.tl.y + y(), r.width(), r.height());
}
-void Viewport::serverCutText(const char* str)
-{
- char *buffer;
- size_t len;
-
- clearPendingClipboard();
-
- if (!acceptClipboard)
- return;
-
- buffer = latin1ToUTF8(str);
- len = strlen(buffer);
-
- vlog.debug("Got clipboard data (%d bytes)", (int)len);
-
- if (!hasFocus()) {
- pendingServerCutText = buffer;
- return;
- }
-
- // RFB doesn't have separate selection and clipboard concepts, so we
- // dump the data into both variants.
-#if !defined(WIN32) && !defined(__APPLE__)
- if (setPrimary)
- Fl::copy(buffer, len, 0);
-#endif
- Fl::copy(buffer, len, 1);
-
- strFree(buffer);
-}
-
static const char * dotcursor_xpm[] = {
"5 5 2 1",
". c #000000",
@@ -311,6 +278,59 @@
window()->cursor(cursor, cursorHotspot.x, cursorHotspot.y);
}
+void Viewport::handleClipboardRequest()
+{
+ Fl::paste(*this, clipboardSource);
+}
+
+void Viewport::handleClipboardAnnounce(bool available)
+{
+ if (!acceptClipboard)
+ return;
+
+ if (available)
+ vlog.debug("Got notification of new clipboard on server");
+ else
+ vlog.debug("Clipboard is no longer available on server");
+
+ if (!available) {
+ pendingServerClipboard = false;
+ return;
+ }
+
+ pendingClientClipboard = false;
+
+ if (!hasFocus()) {
+ pendingServerClipboard = true;
+ return;
+ }
+
+ cc->requestClipboard();
+}
+
+void Viewport::handleClipboardData(const char* data)
+{
+ char* buffer;
+ size_t len;
+
+ if (!hasFocus())
+ return;
+
+ buffer = latin1ToUTF8(data);
+ len = strlen(buffer);
+
+ vlog.debug("Got clipboard data (%d bytes)", (int)len);
+
+ // RFB doesn't have separate selection and clipboard concepts, so we
+ // dump the data into both variants.
+#if !defined(WIN32) && !defined(__APPLE__)
+ if (setPrimary)
+ Fl::copy(buffer, len, 0);
+#endif
+ Fl::copy(buffer, len, 1);
+
+ strFree(buffer);
+}
void Viewport::setLEDState(unsigned int state)
{
@@ -547,21 +567,14 @@
switch (event) {
case FL_PASTE:
- clearPendingClipboard();
-
buffer = utf8ToLatin1(Fl::event_text(), Fl::event_length());
filtered = convertLF(buffer);
strFree(buffer);
- if (!hasFocus()) {
- pendingClientCutText = filtered;
- return 1;
- }
-
vlog.debug("Sending clipboard data (%d bytes)", (int)strlen(filtered));
try {
- cc->writer()->writeClientCutText(filtered);
+ cc->sendClipboardData(filtered);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
exit_vncviewer(e.str());
@@ -725,41 +738,47 @@
return;
#endif
- Fl::paste(*self, source);
-}
+ self->clipboardSource = source;
+ self->pendingServerClipboard = false;
-void Viewport::clearPendingClipboard()
-{
- strFree(pendingServerCutText);
- pendingServerCutText = NULL;
- strFree(pendingClientCutText);
- pendingClientCutText = NULL;
+ if (!self->hasFocus()) {
+ self->pendingClientClipboard = true;
+ // Clear any older client clipboard from the server
+ self->cc->announceClipboard(false);
+ return;
+ }
+
+ try {
+ self->cc->announceClipboard(true);
+ } catch (rdr::Exception& e) {
+ vlog.error("%s", e.str());
+ exit_vncviewer(e.str());
+ }
}
void Viewport::flushPendingClipboard()
{
- if (pendingServerCutText) {
- size_t len = strlen(pendingServerCutText);
-#if !defined(WIN32) && !defined(__APPLE__)
- if (setPrimary)
- Fl::copy(pendingServerCutText, len, 0);
-#endif
- Fl::copy(pendingServerCutText, len, 1);
- }
- if (pendingClientCutText) {
- size_t len = strlen(pendingClientCutText);
- vlog.debug("Sending pending clipboard data (%d bytes)", (int)len);
+ if (pendingServerClipboard) {
try {
- cc->writer()->writeClientCutText(pendingClientCutText);
+ cc->requestClipboard();
+ } catch (rdr::Exception& e) {
+ vlog.error("%s", e.str());
+ exit_vncviewer(e.str());
+ }
+ }
+ if (pendingClientClipboard) {
+ try {
+ cc->announceClipboard(true);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
exit_vncviewer(e.str());
}
}
- clearPendingClipboard();
+ pendingServerClipboard = false;
+ pendingClientClipboard = false;
}
diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h
index 8b9b469..1fb93c6 100644
--- a/vncviewer/Viewport.h
+++ b/vncviewer/Viewport.h
@@ -45,9 +45,6 @@
// Flush updates to screen
void updateWindow();
- // Incoming clipboard from server
- void serverCutText(const char* str);
-
// New image for the locally rendered cursor
void setCursor(int width, int height, const rfb::Point& hotspot,
const rdr::U8* data);
@@ -57,6 +54,11 @@
void draw(Surface* dst);
+ // Clipboard events
+ void handleClipboardRequest();
+ void handleClipboardAnnounce(bool available);
+ void handleClipboardData(const char* data);
+
// Fl_Widget callback methods
void draw();
@@ -72,7 +74,6 @@
static void handleClipboardChange(int source, void *data);
- void clearPendingClipboard();
void flushPendingClipboard();
void handlePointerEvent(const rfb::Point& pos, int buttonMask);
@@ -114,8 +115,10 @@
bool firstLEDState;
- char* pendingServerCutText;
- char* pendingClientCutText;
+ bool pendingServerClipboard;
+ bool pendingClientClipboard;
+
+ int clipboardSource;
rdr::U32 menuKeySym;
int menuKeyCode, menuKeyFLTK;