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/win/rfb_win32/Clipboard.cxx b/win/rfb_win32/Clipboard.cxx
index 4952695..306cfba 100644
--- a/win/rfb_win32/Clipboard.cxx
+++ b/win/rfb_win32/Clipboard.cxx
@@ -103,32 +103,10 @@
       } else {
         vlog.debug("local clipboard changed by %p", owner);
 
-			  // Open the clipboard
-			  if (OpenClipboard(getHandle())) {
-				  // Get the clipboard data
-				  HGLOBAL cliphandle = GetClipboardData(CF_TEXT);
-				  if (cliphandle) {
-					  char* clipdata = (char*) GlobalLock(cliphandle);
-
-            // Notify clients
-            if (notifier) {
-              if (!clipdata) {
-                notifier->notifyClipboardChanged(0);
-              } else {
-                CharArray unix_text(convertLF(clipdata, strlen(clipdata)));
-                removeNonISOLatin1Chars(unix_text.buf);
-                notifier->notifyClipboardChanged(unix_text.buf);
-              }
-            } else {
-              vlog.debug("no clipboard notifier registered");
-            }
-
-					  // Release the buffer and close the clipboard
-					  GlobalUnlock(cliphandle);
-				  }
-
-				  CloseClipboard();
-        }
+        if (notifier == NULL)
+          vlog.debug("no clipboard notifier registered");
+        else
+          notifier->notifyClipboardChanged(IsClipboardFormatAvailable(CF_TEXT));
 			}
     }
     if (next_window)
@@ -139,6 +117,40 @@
   return MsgWindow::processMessage(msg, wParam, lParam);
 };
 
+char*
+Clipboard::getClipText() {
+  HGLOBAL cliphandle;
+  char* clipdata;
+  char* filtered;
+
+  // Open the clipboard
+  if (!OpenClipboard(getHandle()))
+    return NULL;
+
+  // Get the clipboard data
+  cliphandle = GetClipboardData(CF_TEXT);
+  if (!cliphandle) {
+    CloseClipboard();
+    return NULL;
+  }
+
+  clipdata = (char*) GlobalLock(cliphandle);
+  if (!clipdata) {
+    CloseClipboard();
+    return NULL;
+  }
+
+  // Filter out anything unwanted
+  filtered = convertLF(clipdata, strlen(clipdata));
+  removeNonISOLatin1Chars(filtered);
+
+  // Release the buffer and close the clipboard
+  GlobalUnlock(cliphandle);
+  CloseClipboard();
+
+  return filtered;
+}
+
 void
 Clipboard::setClipText(const char* text) {
   HANDLE clip_handle = 0;
diff --git a/win/rfb_win32/Clipboard.h b/win/rfb_win32/Clipboard.h
index c69e981..1dead82 100644
--- a/win/rfb_win32/Clipboard.h
+++ b/win/rfb_win32/Clipboard.h
@@ -39,7 +39,7 @@
       // -=- Abstract base class for callback recipients
       class Notifier {
       public:
-        virtual void notifyClipboardChanged(const char* text) = 0;
+        virtual void notifyClipboardChanged(bool available) = 0;
         virtual ~Notifier() {};
       };
 
@@ -49,6 +49,9 @@
       // - Set the notifier to use
       void setNotifier(Notifier* cbn) {notifier = cbn;}
 
+      // - Get the clipboard contents
+      char* getClipText();
+
       // - Set the clipboard contents
       void setClipText(const char* text);
 
diff --git a/win/rfb_win32/SDisplay.cxx b/win/rfb_win32/SDisplay.cxx
index 2c91e3f..be33ff1 100644
--- a/win/rfb_win32/SDisplay.cxx
+++ b/win/rfb_win32/SDisplay.cxx
@@ -292,6 +292,22 @@
 }
 
 
+void SDisplay::handleClipboardRequest() {
+  CharArray data(clipboard->getClipText());
+  server->sendClipboardData(data.buf);
+}
+
+void SDisplay::handleClipboardAnnounce(bool available) {
+  // FIXME: Wait for an application to actually request it
+  if (available)
+    server->requestClipboard();
+}
+
+void SDisplay::handleClipboardData(const char* data) {
+  clipboard->setClipText(data);
+}
+
+
 void SDisplay::pointerEvent(const Point& pos, int buttonmask) {
   if (pb->getRect().contains(pos)) {
     Point screenPos = pos.translate(screenRect.tl);
@@ -329,16 +345,12 @@
   return false;
 }
 
-void SDisplay::clientCutText(const char* text) {
-  clipboard->setClipText(text);
-}
-
 
 void
-SDisplay::notifyClipboardChanged(const char* text) {
+SDisplay::notifyClipboardChanged(bool available) {
   vlog.debug("clipboard text changed");
   if (server)
-    server->serverCutText(text);
+    server->announceClipboard(available);
 }
 
 
diff --git a/win/rfb_win32/SDisplay.h b/win/rfb_win32/SDisplay.h
index 1773b78..8e38edb 100644
--- a/win/rfb_win32/SDisplay.h
+++ b/win/rfb_win32/SDisplay.h
@@ -76,13 +76,15 @@
       virtual void terminate();
       virtual void queryConnection(network::Socket* sock,
                                    const char* userName);
+      virtual void handleClipboardRequest();
+      virtual void handleClipboardAnnounce(bool available);
+      virtual void handleClipboardData(const char* data);
       virtual void pointerEvent(const Point& pos, int buttonmask);
       virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
-      virtual void clientCutText(const char* str);
 
-      // -=- Clipboard
+      // -=- Clipboard events
       
-      virtual void notifyClipboardChanged(const char* text);
+      virtual void notifyClipboardChanged(bool available);
 
       // -=- Display events