From 2e80d53a307694aa676c0bf33d8216d0bc5ce0da Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 27 Mar 2006 08:49:38 +0000 Subject: [PATCH] Examine timestamps of PRIMARY and CLIPBOARD to determine which is more recent and should therefore be used. git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@1205 423420c4-83ab-492f-b58f-81f9feb106b5 --- xclip.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 108 insertions(+), 12 deletions(-) diff --git a/xclip.c b/xclip.c index e8ff223..222e0c0 100644 --- a/xclip.c +++ b/xclip.c @@ -69,6 +69,12 @@ static Atom timestamp_atom; before requesting clipboard data from a fellow rdesktop using the _RDESKTOP_CLIPBOARD_FORMATS target. */ static Atom rdesktop_clipboard_target_atom; +/* Atoms _RDESKTOP_PRIMARY_TIMESTAMP_TARGET and _RDESKTOP_CLIPBOARD_TIMESTAMP_TARGET + are used to store the timestamps for when a window got ownership of the selections. + We use these to determine which is more recent and should be used. */ +static Atom rdesktop_primary_timestamp_target_atom, rdesktop_clipboard_timestamp_target_atom; +/* Storage for timestamps since we get them in two separate notifications. */ +static Time primary_timestamp, clipboard_timestamp; /* Atom _RDESKTOP_CLIPBOARD_FORMATS which has multiple uses: - The clipboard target (X jargon for "clipboard format") for rdesktop-to-rdesktop interchange of Windows native clipboard data. @@ -372,6 +378,14 @@ xclip_send_data_with_convert(uint8 * source, size_t source_size, Atom target) } } +static void +xclip_clear_target_props() +{ + XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom); + XDeleteProperty(g_display, g_wnd, rdesktop_primary_timestamp_target_atom); + XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_timestamp_target_atom); +} + /* This function is called for SelectionNotify events. The SelectionNotify event is sent from the clipboard owner to the requestor after his request was satisfied. @@ -395,13 +409,78 @@ xclip_handle_SelectionNotify(XSelectionEvent * event) XGetAtomName(g_display, event->target), XGetAtomName(g_display, event->property))); - if (event->property == None) - goto fail; + if (event->target == timestamp_atom) + { + if (event->selection == primary_atom) + { + res = XGetWindowProperty(g_display, g_wnd, + rdesktop_primary_timestamp_target_atom, 0, + XMaxRequestSize(g_display), False, XA_INTEGER, + &type, &format, &nitems, &bytes_left, &data); + } + else + { + res = XGetWindowProperty(g_display, g_wnd, + rdesktop_clipboard_timestamp_target_atom, 0, + XMaxRequestSize(g_display), False, XA_INTEGER, + &type, &format, &nitems, &bytes_left, &data); + } + + + if ((res != Success) || (nitems != 1)) + { + DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n")); + goto fail; + } + + if (event->selection == primary_atom) + { + primary_timestamp = *(Time *) data; + if (primary_timestamp == 0) + primary_timestamp++; + XDeleteProperty(g_display, g_wnd, rdesktop_primary_timestamp_target_atom); + DEBUG_CLIPBOARD(("Got PRIMARY timestamp: %u\n", + (unsigned) primary_timestamp)); + } + else + { + clipboard_timestamp = *(Time *) data; + if (clipboard_timestamp == 0) + clipboard_timestamp++; + XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_timestamp_target_atom); + DEBUG_CLIPBOARD(("Got CLIPBOARD timestamp: %u\n", + (unsigned) clipboard_timestamp)); + } + + XFree(data); + + if (primary_timestamp && clipboard_timestamp) + { + if (primary_timestamp > clipboard_timestamp) + { + DEBUG_CLIPBOARD(("PRIMARY is most recent selection.\n")); + XConvertSelection(g_display, primary_atom, targets_atom, + rdesktop_clipboard_target_atom, g_wnd, + event->time); + } + else + { + DEBUG_CLIPBOARD(("CLIPBOARD is most recent selection.\n")); + XConvertSelection(g_display, clipboard_atom, targets_atom, + rdesktop_clipboard_target_atom, g_wnd, + event->time); + } + } + + return; + } res = XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_target_atom, 0, XMaxRequestSize(g_display), False, AnyPropertyType, &type, &format, &nitems, &bytes_left, &data); + xclip_clear_target_props(); + if (res != Success) { DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n")); @@ -417,15 +496,12 @@ xclip_handle_SelectionNotify(XSelectionEvent * event) { XSelectInput(g_display, g_wnd, (wa.your_event_mask | PropertyChangeMask)); } - XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom); XFree(data); g_incr_target = event->target; g_waiting_for_INCR = 1; return; } - XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom); - /* Negotiate target format */ if (event->target == targets_atom) { @@ -502,7 +578,7 @@ xclip_handle_SelectionNotify(XSelectionEvent * event) return; fail: - XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom); + xclip_clear_target_props(); if (data) XFree(data); helper_cliprdr_send_empty_response(); @@ -809,11 +885,13 @@ ui_clip_handle_data(uint8 * data, uint32 length) void ui_clip_request_data(uint32 format) { - Window selectionowner; + Window primary_owner, clipboard_owner; DEBUG_CLIPBOARD(("Request from server for format %d\n", format)); rdp_clipboard_request_format = format; + xclip_clear_target_props(); + if (rdesktop_is_selection_owner) { XChangeProperty(g_display, g_wnd, rdesktop_clipboard_target_atom, @@ -824,17 +902,31 @@ ui_clip_request_data(uint32 format) return; } - selectionowner = XGetSelectionOwner(g_display, primary_atom); - if (selectionowner != None) + primary_owner = XGetSelectionOwner(g_display, primary_atom); + clipboard_owner = XGetSelectionOwner(g_display, clipboard_atom); + + /* Both available */ + if ((primary_owner != None) && (clipboard_owner != None)) + { + primary_timestamp = 0; + clipboard_timestamp = 0; + XConvertSelection(g_display, primary_atom, timestamp_atom, + rdesktop_primary_timestamp_target_atom, g_wnd, CurrentTime); + XConvertSelection(g_display, clipboard_atom, timestamp_atom, + rdesktop_clipboard_timestamp_target_atom, g_wnd, CurrentTime); + return; + } + + /* Just PRIMARY */ + if (primary_owner != None) { XConvertSelection(g_display, primary_atom, targets_atom, rdesktop_clipboard_target_atom, g_wnd, CurrentTime); return; } - /* No PRIMARY, try CLIPBOARD */ - selectionowner = XGetSelectionOwner(g_display, clipboard_atom); - if (selectionowner != None) + /* Just CLIPBOARD */ + if (clipboard_owner != None) { XConvertSelection(g_display, clipboard_atom, targets_atom, rdesktop_clipboard_target_atom, g_wnd, CurrentTime); @@ -864,6 +956,10 @@ xclip_init(void) timestamp_atom = XInternAtom(g_display, "TIMESTAMP", False); rdesktop_clipboard_target_atom = XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_TARGET", False); + rdesktop_primary_timestamp_target_atom = + XInternAtom(g_display, "_RDESKTOP_PRIMARY_TIMESTAMP_TARGET", False); + rdesktop_clipboard_timestamp_target_atom = + XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_TIMESTAMP_TARGET", False); incr_atom = XInternAtom(g_display, "INCR", False); format_string_atom = XInternAtom(g_display, "STRING", False); format_utf8_string_atom = XInternAtom(g_display, "UTF8_STRING", False);