--- sourceforge.net/trunk/rdesktop/cliprdr.c 2003/06/06 09:23:28 385 +++ sourceforge.net/trunk/rdesktop/cliprdr.c 2003/06/06 09:26:11 388 @@ -25,9 +25,11 @@ extern BOOL encryption; extern Display *display; extern Window wnd; -extern Time last_keyrelease; +extern Time last_gesturetime; +// static Time selection_timestamp; static Atom clipboard_atom, primary_atom, targets_atom, timestamp_atom; +static Atom rdesktop_clipboard_target_atom; static cliprdr_dataformat *server_formats = NULL; static uint16 num_server_formats = 0; static XSelectionEvent selection_event; @@ -49,54 +51,180 @@ DEBUG_CLIPBOARD(("There were %d server formats.\n", i)); #endif } +/* +static void +cliprdr_set_selection_timestamp(void) +{ + XEvent xev; + DEBUG_CLIPBOARD(("Changing a property in order to get a timestamp\n")); + fflush(stdout); + XChangeProperty(display, wnd, rdesktop_clipboard_target_atom, + XA_ATOM, 32, PropModeAppend, 0, 0); + DEBUG_CLIPBOARD(("Waiting for PropertyChange on wnd\n")); + fflush(stdout); + XWindowEvent(display, wnd, + PropertyChangeMask, &xev); + DEBUG_CLIPBOARD(("Setting selection_timestamp\n")); + fflush(stdout); + selection_timestamp = xev.xproperty.time; +} +*/ + +static void +cliprdr_send_format_announce(void) +{ + DEBUG_CLIPBOARD(("Sending format announce\n")); + + STREAM s; + int number_of_formats = 1; + s = sec_init(encryption ? SEC_ENCRYPT : 0, number_of_formats*36+12+4+4); + out_uint32_le(s, number_of_formats*36+12); + out_uint32_le(s, 0x13); + out_uint16_le(s, 2); + out_uint16_le(s, 0); + out_uint32_le(s, number_of_formats*36); + + // out_uint32_le(s, 0xd); // FIXME: This is a rather bogus unicode text description.. + // rdp_out_unistr(s, "", 16); + // out_uint8s(s, 32); + + + out_uint32_le(s, 1); // FIXME: This is a rather bogus text description.. + out_uint8s(s, 32); + + out_uint32_le(s, 0); + + s_mark_end(s); + sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, 1005); // FIXME: Don't hardcode channel! +} + + +static void +cliprdr_send_empty_datapacket(void) +{ + STREAM out; + out = sec_init(encryption ? SEC_ENCRYPT : 0, + 20); + out_uint32_le(out, 12); + out_uint32_le(out, 0x13); + out_uint16_le(out, 5); + out_uint16_le(out, 1); + out_uint32_le(out, 0); + /* Insert null string here? */ + out_uint32_le(out, 0); + s_mark_end(out); + + sec_send_to_channel(out, encryption ? SEC_ENCRYPT : 0, 1005); // FIXME: Don't hardcode channel! +} + void -cliprdr_handle_SelectionNotify(void) +cliprdr_handle_SelectionNotify(XSelectionEvent *event) { + + unsigned char *data; + unsigned long nitems, bytes_left; + int res; + + int format; + Atom type_return; + Atom best_target; + + STREAM out; + DEBUG_CLIPBOARD(("cliprdr_handle_SelectionNotify\n")); + + if (None == event->property) { + cliprdr_send_empty_datapacket(); + return; /* Selection failed */ + } + + DEBUG_CLIPBOARD(("selection: %s, target: %s, property: %s\n", + XGetAtomName(display, event->selection), + XGetAtomName(display, event->target), + XGetAtomName(display, event->property))); + + if (targets_atom == event->target) { + /* Response to TARGETS request. Let's find the target + we want and request that */ + res = XGetWindowProperty(display, wnd, + rdesktop_clipboard_target_atom, + 0L, 4096L, False, AnyPropertyType, + &type_return, + &format, &nitems, &bytes_left, &data); + + if (Success != res) + { + DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n")); + cliprdr_send_empty_datapacket(); + return; + } + + if (None == type_return) + /* The owner might no support TARGETS. Just try + STRING */ + best_target = XA_STRING; + else + { + /* FIXME: We should choose format here based + on what the server wanted */ + best_target = XInternAtom(display, "TEXT", False); + + + } + + XConvertSelection(display, primary_atom, + best_target, + rdesktop_clipboard_target_atom, + wnd, event->time); + + } + else /* Other clipboard data */ + { + + res = XGetWindowProperty(display, wnd, + rdesktop_clipboard_target_atom, + 0L, 4096L, False, AnyPropertyType, + &type_return, + &format, &nitems, &bytes_left, &data); + + if (Success != res) + { + DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n")); + cliprdr_send_empty_datapacket(); + return; + } + + /* We need to handle INCR as well */ + + out = sec_init(encryption ? SEC_ENCRYPT : 0, + 20+nitems); + out_uint32_le(out, 12+nitems); + out_uint32_le(out, 0x13); + out_uint16_le(out, 5); + out_uint16_le(out, 1); + out_uint32_le(out, nitems); + out_uint8p(out, data, nitems); + /* Insert null string here? */ + out_uint32_le(out, 0); + s_mark_end(out); + + sec_send_to_channel(out, encryption ? SEC_ENCRYPT : 0, 1005); // FIXME: Don't hardcode channel! + + cliprdr_send_format_announce(); + + } + + } void cliprdr_handle_SelectionClear(void) { DEBUG_CLIPBOARD(("cliprdr_handle_SelectionClear\n")); + cliprdr_send_format_announce(); } -void print_X_error(int res) -{ - switch(res) { - case Success: - DEBUG_CLIPBOARD(("Success\n")); - break; - - case BadAtom: - DEBUG_CLIPBOARD(("BadAtom\n")); - break; - - case BadRequest: - DEBUG_CLIPBOARD(("BadRequest\n")); - break; - - case BadAlloc: - DEBUG_CLIPBOARD(("BadAlloc\n")); - break; - - case BadMatch: - DEBUG_CLIPBOARD(("BadMatch\n")); - break; - - case BadValue: - DEBUG_CLIPBOARD(("BadValue\n")); - break; - - case BadWindow: - DEBUG_CLIPBOARD(("BadWindow\n")); - break; - - default: - DEBUG_CLIPBOARD(("Unknown X error code %d\n", res)); - } -} static void cliprdr_request_clipboard_data(uint32 formatcode) @@ -165,8 +293,6 @@ PropModeAppend, (unsigned char *)targets, 3); - DEBUG_CLIPBOARD(("res after XChangeProperty is ")); - print_X_error(res); res = XSendEvent(display, xevent->requestor, @@ -177,14 +303,14 @@ } else if (timestamp_atom == xevent->target) { DEBUG_CLIPBOARD(("TIMESTAMP requested... sending 0x%x\n", - (unsigned)last_keyrelease)); + (unsigned)last_gesturetime)); res = XChangeProperty(display, xevent->requestor, xevent->property, XA_INTEGER, 32, PropModeAppend, - (unsigned char *)&last_keyrelease, + (unsigned char *)&last_gesturetime, 1); res = XSendEvent(display, xevent->requestor, @@ -267,12 +393,12 @@ static void cliprdr_select_X_clipboards(void) { - XSetSelectionOwner(display, primary_atom, wnd, last_keyrelease); + XSetSelectionOwner(display, primary_atom, wnd, last_gesturetime); if (wnd != XGetSelectionOwner(display, primary_atom)) { warning("Failed to aquire ownership of PRIMARY clipboard\n"); } - XSetSelectionOwner(display, clipboard_atom, wnd, CurrentTime); + XSetSelectionOwner(display, clipboard_atom, wnd, last_gesturetime); if (wnd != XGetSelectionOwner(display, clipboard_atom)) { warning("Failed to aquire ownership of CLIPBOARD clipboard\n"); @@ -282,31 +408,6 @@ -static void -cliprdr_send_format_announce(void) -{ - STREAM s; - int number_of_formats = 1; - s = sec_init(encryption ? SEC_ENCRYPT : 0, number_of_formats*36+12+4+4); - out_uint32_le(s, number_of_formats*36+12); - out_uint32_le(s, 0x13); - out_uint16_le(s, 2); - out_uint16_le(s, 0); - out_uint32_le(s, number_of_formats*36); - - // out_uint32_le(s, 0xd); // FIXME: This is a rather bogus unicode text description.. - // rdp_out_unistr(s, "", 16); - // out_uint8s(s, 32); - - - out_uint32_le(s, 1); // FIXME: This is a rather bogus text description.. - out_uint8s(s, 32); - - out_uint32_le(s, 0); - - s_mark_end(s); - sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, 1005); // FIXME: Don't hardcode channel! -} static void @@ -324,38 +425,31 @@ { uint32 remaining_length; char *data; - int res; in_uint32_le(s, remaining_length); data = s->p; - res = XChangeProperty(display, - selection_event.requestor, - selection_event.property, - XInternAtom(display, "STRING", False), - 8, - PropModeAppend, - data, - remaining_length); - - DEBUG_CLIPBOARD(("res after XChangeProperty is ")); - print_X_error(res); - - res = XSendEvent(display, - selection_event.requestor, - False, - NoEventMask, - (XEvent *)&selection_event); + XChangeProperty(display, + selection_event.requestor, + selection_event.property, + XInternAtom(display, "STRING", False), + 8, + PropModeAppend, + data, + remaining_length); + + XSendEvent(display, + selection_event.requestor, + False, + NoEventMask, + (XEvent *)&selection_event); - DEBUG_CLIPBOARD(("res after XSendEvent is ")); - print_X_error(res); } void cliprdr_handle_server_data_request(STREAM s) { + Window selectionowner; uint32 remaining_length; uint32 wanted_formatcode, pad; - int ret; - STREAM out; in_uint32_le(s, remaining_length); in_uint32_le(s, wanted_formatcode); @@ -366,35 +460,29 @@ DEBUG_CLIPBOARD(("Request from server for format %d\n", wanted_formatcode)); - out = sec_init(encryption ? SEC_ENCRYPT : 0, - 26); - out_uint32_le(out, 18); - out_uint32_le(out, 0x13); - out_uint16_le(out, 5); - out_uint16_le(out, 1); - out_uint32_le(out, 6); - out_uint8p(out, "fnorp", 6); - out_uint32_le(out, 0); + selectionowner = XGetSelectionOwner(display, primary_atom); - s_mark_end(out); + if (None != selectionowner) + { - sec_send_to_channel(out, encryption ? SEC_ENCRYPT : 0, 1005); // FIXME: Don't hardcode channel! + /* FIXME: Perhaps we should check if we are the owner? */ + + XConvertSelection(display, primary_atom, + targets_atom, + rdesktop_clipboard_target_atom, + wnd, CurrentTime); - /* - if (1 != wanted_formatcode) + /* The rest of the transfer is handled in + cliprdr_handle_SelectionNotify */ + + } else { - out = sec_init(encryption ? SEC_ENCRYPT : 0, - 20); - out_uint32_le(s, 12); - out_uint32_le(s, 0x13); - out_uint16_le(s, 5); - out_uint16_le(s, 2); - out_uint32_le(s, 0); - out_uint32_le(s, 0); - s_mark_end(s); - sec_send_to_channel(s, encryption ? SEC_ENCRYPT : 0, 1005); // FIXME: Don't hardcode channel! + DEBUG_CLIPBOARD(("There were no owner for PRIMARY, sending empty string\n")); // FIXME: Should we always send an empty string? + + cliprdr_send_empty_datapacket(); } - */ + + } @@ -450,6 +538,7 @@ { primary_atom = XInternAtom(display, "PRIMARY", False); clipboard_atom = XInternAtom(display, "CLIPBOARD", False); - targets_atom = XInternAtom(display, "TARGETS", True); - timestamp_atom = XInternAtom(display, "TIMESTAMP", True); + targets_atom = XInternAtom(display, "TARGETS", False); + timestamp_atom = XInternAtom(display, "TIMESTAMP", False); + rdesktop_clipboard_target_atom = XInternAtom(display, "_RDESKTOP_CLIPBOARD_TARGET", False); }