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:
parent
93cfd505c0
commit
2e80d53a30
118
xclip.c
118
xclip.c
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user