Blame SOURCES/fltk-1_v2.3.x-clipboard-x11.patch

ceac5b
diff -up fltk-1.3.x-r8659/src/Fl_x.cxx.orig fltk-1.3.x-r8659/src/Fl_x.cxx
ceac5b
--- fltk-1.3.x-r8659/src/Fl_x.cxx.orig	2011-05-17 16:37:11.092011814 +0200
ceac5b
+++ fltk-1.3.x-r8659/src/Fl_x.cxx	2011-05-18 13:51:06.135475325 +0200
ceac5b
@@ -309,6 +309,9 @@ static Atom WM_PROTOCOLS;
ceac5b
 static Atom fl_MOTIF_WM_HINTS;
ceac5b
 static Atom TARGETS;
ceac5b
 static Atom CLIPBOARD;
ceac5b
+static Atom TIMESTAMP;
ceac5b
+static Atom PRIMARY_TIMESTAMP;
ceac5b
+static Atom CLIPBOARD_TIMESTAMP;
ceac5b
 Atom fl_XdndAware;
ceac5b
 Atom fl_XdndSelection;
ceac5b
 Atom fl_XdndEnter;
ceac5b
@@ -678,6 +681,9 @@ void fl_open_display(Display* d) {
ceac5b
   fl_MOTIF_WM_HINTS     = XInternAtom(d, "_MOTIF_WM_HINTS",     0);
ceac5b
   TARGETS               = XInternAtom(d, "TARGETS",             0);
ceac5b
   CLIPBOARD             = XInternAtom(d, "CLIPBOARD",           0);
ceac5b
+  TIMESTAMP             = XInternAtom(d, "TIMESTAMP",           0);
ceac5b
+  PRIMARY_TIMESTAMP     = XInternAtom(d, "PRIMARY_TIMESTAMP",   0);
ceac5b
+  CLIPBOARD_TIMESTAMP   = XInternAtom(d, "CLIPBOARD_TIMESTAMP", 0);
ceac5b
   fl_XdndAware          = XInternAtom(d, "XdndAware",           0);
ceac5b
   fl_XdndSelection      = XInternAtom(d, "XdndSelection",       0);
ceac5b
   fl_XdndEnter          = XInternAtom(d, "XdndEnter",           0);
ceac5b
@@ -861,6 +881,86 @@ void Fl::copy(const char *stuff, int len
ceac5b
 }
ceac5b
 
ceac5b
 ////////////////////////////////////////////////////////////////
ceac5b
+// Code for tracking clipboard changes:
ceac5b
+
ceac5b
+static Time primary_timestamp = -1;
ceac5b
+static Time clipboard_timestamp = -1;
ceac5b
+
ceac5b
+extern bool fl_clipboard_notify_empty(void);
ceac5b
+extern void fl_trigger_clipboard_notify(int source);
ceac5b
+
ceac5b
+static void poll_clipboard_owner(void) {
ceac5b
+  Window xid;
ceac5b
+
ceac5b
+  // No one is interested, so no point polling
ceac5b
+  if (fl_clipboard_notify_empty())
ceac5b
+    return;
ceac5b
+
ceac5b
+  // We need a window for this to work
ceac5b
+  if (!Fl::first_window())
ceac5b
+    return;
ceac5b
+  xid = fl_xid(Fl::first_window());
ceac5b
+  if (!xid)
ceac5b
+    return;
ceac5b
+
ceac5b
+  // Request an update of the selection time for both the primary and
ceac5b
+  // clipboard selections. Magic continues when we get a SelectionNotify.
ceac5b
+  if (!fl_i_own_selection[0])
ceac5b
+    XConvertSelection(fl_display, XA_PRIMARY, TIMESTAMP, PRIMARY_TIMESTAMP,
ceac5b
+                      xid, fl_event_time);
ceac5b
+  if (!fl_i_own_selection[1])
ceac5b
+    XConvertSelection(fl_display, CLIPBOARD, TIMESTAMP, CLIPBOARD_TIMESTAMP,
ceac5b
+                      xid, fl_event_time);
ceac5b
+}
ceac5b
+
ceac5b
+static void clipboard_timeout(void *data)
ceac5b
+{
ceac5b
+  // No one is interested, so stop polling
ceac5b
+  if (fl_clipboard_notify_empty())
ceac5b
+    return;
ceac5b
+
ceac5b
+  poll_clipboard_owner();
ceac5b
+
ceac5b
+  Fl::repeat_timeout(0.5, clipboard_timeout);
ceac5b
+}
ceac5b
+
ceac5b
+static void handle_clipboard_timestamp(int clipboard, Time time)
ceac5b
+{
ceac5b
+  Time *timestamp;
ceac5b
+
ceac5b
+  timestamp = clipboard ? &clipboard_timestamp : &primary_timestamp;
ceac5b
+
ceac5b
+  // Initial scan, just store the value
ceac5b
+  if (*timestamp == (Time)-1) {
ceac5b
+    *timestamp = time;
ceac5b
+    return;
ceac5b
+  }
ceac5b
+
ceac5b
+  // Same selection
ceac5b
+  if (time == *timestamp)
ceac5b
+    return;
ceac5b
+
ceac5b
+  *timestamp = time;
ceac5b
+
ceac5b
+  // Something happened! Let's tell someone!
ceac5b
+  fl_trigger_clipboard_notify(clipboard);
ceac5b
+}
ceac5b
+
ceac5b
+void fl_clipboard_notify_change() {
ceac5b
+  // Reset the timestamps if we've going idle so that you don't
ceac5b
+  // get a bogus immediate trigger next time they're activated.
ceac5b
+  if (fl_clipboard_notify_empty()) {
ceac5b
+    primary_timestamp = -1;
ceac5b
+    clipboard_timestamp = -1;
ceac5b
+  } else {
ceac5b
+    poll_clipboard_owner();
ceac5b
+
ceac5b
+    if (!Fl::has_timeout(clipboard_timeout))
ceac5b
+      Fl::add_timeout(0.5, clipboard_timeout);
ceac5b
+  }
ceac5b
+}
ceac5b
+
ceac5b
+////////////////////////////////////////////////////////////////
ceac5b
 
ceac5b
 const XEvent* fl_xevent; // the current x event
ceac5b
 ulong fl_event_time; // the last timestamp from an x event
ceac5b
@@ -976,7 +1102,6 @@ int fl_handle(const XEvent& thisevent)
ceac5b
     return 0;
ceac5b
 
ceac5b
   case SelectionNotify: {
ceac5b
-    if (!fl_selection_requestor) return 0;
ceac5b
     static unsigned char* buffer = 0;
ceac5b
     if (buffer) {XFree(buffer); buffer = 0;}
ceac5b
     long bytesread = 0;
ceac5b
@@ -992,6 +1117,19 @@ int fl_handle(const XEvent& thisevent)
ceac5b
                              bytesread/4, 65536, 1, 0,
ceac5b
                              &actual, &format, &count, &remaining,
ceac5b
                              &portion)) break; // quit on error
ceac5b
+
ceac5b
+      if ((fl_xevent->xselection.property == PRIMARY_TIMESTAMP) ||
ceac5b
+          (fl_xevent->xselection.property == CLIPBOARD_TIMESTAMP)) {
ceac5b
+        if (portion && format == 32 && count == 1) {
ceac5b
+          Time t = *(unsigned int*)portion;
ceac5b
+          if (fl_xevent->xselection.property == CLIPBOARD_TIMESTAMP)
ceac5b
+            handle_clipboard_timestamp(1, t);
ceac5b
+          else
ceac5b
+            handle_clipboard_timestamp(0, t);
ceac5b
+        }
ceac5b
+        return true;
ceac5b
+      }
ceac5b
+
ceac5b
       if (actual == TARGETS || actual == XA_ATOM) {
ceac5b
 	Atom type = XA_STRING;
ceac5b
 	for (unsigned i = 0; i
ceac5b
@@ -1029,6 +1167,9 @@ int fl_handle(const XEvent& thisevent)
ceac5b
       buffer[bytesread] = 0;
ceac5b
       convert_crlf(buffer, bytesread);
ceac5b
     }
ceac5b
+
ceac5b
+    if (!fl_selection_requestor) return 0;
ceac5b
+
ceac5b
     Fl::e_text = buffer ? (char*)buffer : (char *)"";
ceac5b
     Fl::e_length = bytesread;
ceac5b
     int old_event = Fl::e_number;
ceac5b
@@ -1049,6 +1190,7 @@ int fl_handle(const XEvent& thisevent)
ceac5b
   case SelectionClear: {
ceac5b
     int clipboard = fl_xevent->xselectionclear.selection == CLIPBOARD;
ceac5b
     fl_i_own_selection[clipboard] = 0;
ceac5b
+    poll_clipboard_owner();
ceac5b
     return 1;}
ceac5b
 
ceac5b
   case SelectionRequest: {
ceac5b
@@ -1248,6 +1390,9 @@ int fl_handle(const XEvent& thisevent)
ceac5b
   case FocusIn:
ceac5b
     if (fl_xim_ic) XSetICFocus(fl_xim_ic);
ceac5b
     event = FL_FOCUS;
ceac5b
+    // If the user has toggled from another application to this one,
ceac5b
+    // then it's a good time to check for clipboard changes.
ceac5b
+    poll_clipboard_owner();
ceac5b
     break;
ceac5b
 
ceac5b
   case FocusOut: