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
This commit is contained in:
Pierre Ossman 2006-03-27 08:49:38 +00:00
parent 93cfd505c0
commit 2e80d53a30

118
xclip.c
View File

@ -69,6 +69,12 @@ static Atom timestamp_atom;
before requesting clipboard data from a fellow rdesktop using before requesting clipboard data from a fellow rdesktop using
the _RDESKTOP_CLIPBOARD_FORMATS target. */ the _RDESKTOP_CLIPBOARD_FORMATS target. */
static Atom rdesktop_clipboard_target_atom; 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: /* Atom _RDESKTOP_CLIPBOARD_FORMATS which has multiple uses:
- The clipboard target (X jargon for "clipboard format") for rdesktop-to-rdesktop interchange - The clipboard target (X jargon for "clipboard format") for rdesktop-to-rdesktop interchange
of Windows native clipboard data. 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. /* This function is called for SelectionNotify events.
The SelectionNotify event is sent from the clipboard owner to the requestor The SelectionNotify event is sent from the clipboard owner to the requestor
after his request was satisfied. after his request was satisfied.
@ -395,13 +409,78 @@ xclip_handle_SelectionNotify(XSelectionEvent * event)
XGetAtomName(g_display, event->target), XGetAtomName(g_display, event->target),
XGetAtomName(g_display, event->property))); XGetAtomName(g_display, event->property)));
if (event->property == None) 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; 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, res = XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,
0, XMaxRequestSize(g_display), False, AnyPropertyType, 0, XMaxRequestSize(g_display), False, AnyPropertyType,
&type, &format, &nitems, &bytes_left, &data); &type, &format, &nitems, &bytes_left, &data);
xclip_clear_target_props();
if (res != Success) if (res != Success)
{ {
DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n")); DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));
@ -417,15 +496,12 @@ xclip_handle_SelectionNotify(XSelectionEvent * event)
{ {
XSelectInput(g_display, g_wnd, (wa.your_event_mask | PropertyChangeMask)); XSelectInput(g_display, g_wnd, (wa.your_event_mask | PropertyChangeMask));
} }
XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom);
XFree(data); XFree(data);
g_incr_target = event->target; g_incr_target = event->target;
g_waiting_for_INCR = 1; g_waiting_for_INCR = 1;
return; return;
} }
XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom);
/* Negotiate target format */ /* Negotiate target format */
if (event->target == targets_atom) if (event->target == targets_atom)
{ {
@ -502,7 +578,7 @@ xclip_handle_SelectionNotify(XSelectionEvent * event)
return; return;
fail: fail:
XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom); xclip_clear_target_props();
if (data) if (data)
XFree(data); XFree(data);
helper_cliprdr_send_empty_response(); helper_cliprdr_send_empty_response();
@ -809,11 +885,13 @@ ui_clip_handle_data(uint8 * data, uint32 length)
void void
ui_clip_request_data(uint32 format) ui_clip_request_data(uint32 format)
{ {
Window selectionowner; Window primary_owner, clipboard_owner;
DEBUG_CLIPBOARD(("Request from server for format %d\n", format)); DEBUG_CLIPBOARD(("Request from server for format %d\n", format));
rdp_clipboard_request_format = format; rdp_clipboard_request_format = format;
xclip_clear_target_props();
if (rdesktop_is_selection_owner) if (rdesktop_is_selection_owner)
{ {
XChangeProperty(g_display, g_wnd, rdesktop_clipboard_target_atom, XChangeProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,
@ -824,17 +902,31 @@ ui_clip_request_data(uint32 format)
return; return;
} }
selectionowner = XGetSelectionOwner(g_display, primary_atom); primary_owner = XGetSelectionOwner(g_display, primary_atom);
if (selectionowner != None) 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, XConvertSelection(g_display, primary_atom, targets_atom,
rdesktop_clipboard_target_atom, g_wnd, CurrentTime); rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
return; return;
} }
/* No PRIMARY, try CLIPBOARD */ /* Just CLIPBOARD */
selectionowner = XGetSelectionOwner(g_display, clipboard_atom); if (clipboard_owner != None)
if (selectionowner != None)
{ {
XConvertSelection(g_display, clipboard_atom, targets_atom, XConvertSelection(g_display, clipboard_atom, targets_atom,
rdesktop_clipboard_target_atom, g_wnd, CurrentTime); rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
@ -864,6 +956,10 @@ xclip_init(void)
timestamp_atom = XInternAtom(g_display, "TIMESTAMP", False); timestamp_atom = XInternAtom(g_display, "TIMESTAMP", False);
rdesktop_clipboard_target_atom = rdesktop_clipboard_target_atom =
XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_TARGET", False); 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); incr_atom = XInternAtom(g_display, "INCR", False);
format_string_atom = XInternAtom(g_display, "STRING", False); format_string_atom = XInternAtom(g_display, "STRING", False);
format_utf8_string_atom = XInternAtom(g_display, "UTF8_STRING", False); format_utf8_string_atom = XInternAtom(g_display, "UTF8_STRING", False);