|
|
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:
|