--- sourceforge.net/trunk/rdesktop/xclip.c 2003/07/09 09:18:20 435 +++ sourceforge.net/trunk/rdesktop/xclip.c 2004/02/07 17:32:21 602 @@ -25,9 +25,9 @@ #define NUM_TARGETS 6 -extern Display *display; -extern Window wnd; -extern Time last_gesturetime; +extern Display *g_display; +extern Window g_wnd; +extern Time g_last_gesturetime; static Atom clipboard_atom, primary_atom, targets_atom, timestamp_atom; static Atom rdesktop_clipboard_target_atom, rdesktop_clipboard_formats_atom, incr_atom; @@ -36,13 +36,58 @@ static int have_primary = 0; static int rdesktop_is_selection_owner = 0; + +/* Replace CR-LF to LF (well, rather removing all CR:s) This is done + in-place. The length is updated. Handles embedded nulls */ +static void +crlf2lf(uint8 * data, uint32 * length) +{ + uint8 *dst, *src; + src = dst = data; + while (src < data + *length) + { + if (*src != '\x0d') + *dst++ = *src; + src++; + } + *length = dst - data; +} + +/* Translate LF to CR-LF. To do this, we must allocate more memory. + The length is updated. */ +static uint8 * +lf2crlf(uint8 * data, uint32 * length) +{ + uint8 *result, *p, *o; + + /* Worst case: Every char is LF */ + result = xmalloc(*length * 2); + + p = data; + o = result; + + while (p < data + *length) + { + if (*p == '\x0a') + *o++ = '\x0d'; + *o++ = *p++; + } + *length = o - result; + + /* Convenience */ + *o++ = '\0'; + + return result; +} + + static void xclip_provide_selection(XSelectionRequestEvent * req, Atom type, unsigned int format, uint8 * data, uint32 length) { XEvent xev; - XChangeProperty(display, req->requestor, req->property, + XChangeProperty(g_display, req->requestor, req->property, type, format, PropModeReplace, data, length); xev.xselection.type = SelectionNotify; @@ -53,7 +98,7 @@ xev.xselection.target = req->target; xev.xselection.property = req->property; xev.xselection.time = req->time; - XSendEvent(display, req->requestor, False, NoEventMask, &xev); + XSendEvent(g_display, req->requestor, False, NoEventMask, &xev); } void @@ -69,15 +114,15 @@ goto fail; DEBUG_CLIPBOARD(("xclip_handle_SelectionNotify: selection=%s, target=%s, property=%s\n", - XGetAtomName(display, event->selection), - XGetAtomName(display, event->target), - XGetAtomName(display, event->property))); + XGetAtomName(g_display, event->selection), + XGetAtomName(g_display, event->target), + XGetAtomName(g_display, event->property))); if (event->property == None) goto fail; - res = XGetWindowProperty(display, wnd, rdesktop_clipboard_target_atom, - 0, XMaxRequestSize(display), True, AnyPropertyType, + res = XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_target_atom, + 0, XMaxRequestSize(g_display), True, AnyPropertyType, &type, &format, &nitems, &bytes_left, &data); if (res != Success) @@ -86,6 +131,7 @@ goto fail; } + /* Negotiate target format */ if (event->target == targets_atom) { /* FIXME: We should choose format here based on what the server wanted */ @@ -93,22 +139,23 @@ if (type != None) { supported_targets = (Atom *) data; - text_target = XInternAtom(display, "TEXT", False); + text_target = XInternAtom(g_display, "TEXT", False); for (i = 0; i < nitems; i++) { DEBUG_CLIPBOARD(("Target %d: %s\n", i, - XGetAtomName(display, supported_targets[i]))); + XGetAtomName(g_display, supported_targets[i]))); if (supported_targets[i] == text_target) { DEBUG_CLIPBOARD(("Other party supports TEXT, choosing that as best_target\n")); best_target = text_target; + break; } } XFree(data); } - XConvertSelection(display, primary_atom, best_target, - rdesktop_clipboard_target_atom, wnd, event->time); + XConvertSelection(g_display, primary_atom, best_target, + rdesktop_clipboard_target_atom, g_wnd, event->time); return; } @@ -118,7 +165,22 @@ goto fail; } - cliprdr_send_data(data, nitems + 1); + /* Translate linebreaks, but only if not getting data from + other rdesktop instance */ + if (event->target != rdesktop_clipboard_formats_atom) + { + uint8 *translated_data; + uint32 length = nitems; + + DEBUG_CLIPBOARD(("Translating linebreaks before sending data\n")); + translated_data = lf2crlf(data, &length); + cliprdr_send_data(translated_data, length + 1); + xfree(translated_data); /* Not the same thing as XFree! */ + } + else + { + cliprdr_send_data(data, nitems + 1); + } XFree(data); if (!rdesktop_is_selection_owner) @@ -133,14 +195,15 @@ xclip_handle_SelectionRequest(XSelectionRequestEvent * event) { unsigned long nitems, bytes_left; + unsigned char *prop_return; uint32 *wanted_format; int format, res; Atom type; DEBUG_CLIPBOARD(("xclip_handle_SelectionRequest: selection=%s, target=%s, property=%s\n", - XGetAtomName(display, event->selection), - XGetAtomName(display, event->target), - XGetAtomName(display, event->property))); + XGetAtomName(g_display, event->selection), + XGetAtomName(g_display, event->target), + XGetAtomName(g_display, event->property))); if (event->target == targets_atom) { @@ -149,16 +212,17 @@ } else if (event->target == timestamp_atom) { - xclip_provide_selection(event, XA_INTEGER, 32, (uint8 *) & last_gesturetime, 1); + xclip_provide_selection(event, XA_INTEGER, 32, (uint8 *) & g_last_gesturetime, 1); return; } else if (event->target == rdesktop_clipboard_formats_atom) { - res = XGetWindowProperty(display, event->requestor, + res = XGetWindowProperty(g_display, event->requestor, rdesktop_clipboard_target_atom, 0, 1, True, XA_INTEGER, - &type, &format, &nitems, &bytes_left, - (unsigned char **) &wanted_format); + &type, &format, &nitems, &bytes_left, &prop_return); + wanted_format = (uint32 *) prop_return; format = (res == Success) ? *wanted_format : CF_TEXT; + /* FIXME: Need to free returned data? */ } else { @@ -175,7 +239,7 @@ { DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n")); have_primary = 0; - XDeleteProperty(display, DefaultRootWindow(display), rdesktop_clipboard_formats_atom); + XDeleteProperty(g_display, DefaultRootWindow(g_display), rdesktop_clipboard_formats_atom); cliprdr_send_text_format_announce(); } @@ -195,10 +259,10 @@ if (event->state == PropertyNewValue) { - res = XGetWindowProperty(display, DefaultRootWindow(display), + res = XGetWindowProperty(g_display, DefaultRootWindow(g_display), rdesktop_clipboard_formats_atom, 0, - XMaxRequestSize(display), False, XA_STRING, &type, &format, - &nitems, &bytes_left, &data); + XMaxRequestSize(g_display), False, XA_STRING, &type, + &format, &nitems, &bytes_left, &data); if ((res == Success) && (nitems > 0)) { @@ -215,29 +279,44 @@ void -ui_clip_format_announce(char *data, uint32 length) +ui_clip_format_announce(uint8 * data, uint32 length) { - XSetSelectionOwner(display, primary_atom, wnd, last_gesturetime); - if (XGetSelectionOwner(display, primary_atom) != wnd) + XSetSelectionOwner(g_display, primary_atom, g_wnd, g_last_gesturetime); + if (XGetSelectionOwner(g_display, primary_atom) != g_wnd) { warning("Failed to aquire ownership of PRIMARY clipboard\n"); return; } have_primary = 1; - XChangeProperty(display, DefaultRootWindow(display), + XChangeProperty(g_display, DefaultRootWindow(g_display), rdesktop_clipboard_formats_atom, XA_STRING, 8, PropModeReplace, data, length); - XSetSelectionOwner(display, clipboard_atom, wnd, last_gesturetime); - if (XGetSelectionOwner(display, clipboard_atom) != wnd) + XSetSelectionOwner(g_display, clipboard_atom, g_wnd, g_last_gesturetime); + if (XGetSelectionOwner(g_display, clipboard_atom) != g_wnd) warning("Failed to aquire ownership of CLIPBOARD clipboard\n"); } void -ui_clip_handle_data(char *data, uint32 length) +ui_clip_handle_data(uint8 * data, uint32 length) { + if (selection_request.target != rdesktop_clipboard_formats_atom) + { + uint8 *firstnull; + + /* translate linebreaks */ + crlf2lf(data, &length); + + /* Only send data up to null byte, if any */ + firstnull = (uint8 *)strchr((char*)data, '\0'); + if (firstnull) + { + length = firstnull - data + 1; + } + } + xclip_provide_selection(&selection_request, XA_STRING, 8, data, length - 1); } @@ -250,28 +329,28 @@ if (rdesktop_is_selection_owner) { - XChangeProperty(display, wnd, rdesktop_clipboard_target_atom, + XChangeProperty(g_display, g_wnd, rdesktop_clipboard_target_atom, XA_INTEGER, 32, PropModeReplace, (unsigned char *) &format, 1); - XConvertSelection(display, primary_atom, rdesktop_clipboard_formats_atom, - rdesktop_clipboard_target_atom, wnd, CurrentTime); + XConvertSelection(g_display, primary_atom, rdesktop_clipboard_formats_atom, + rdesktop_clipboard_target_atom, g_wnd, CurrentTime); return; } - selectionowner = XGetSelectionOwner(display, primary_atom); + selectionowner = XGetSelectionOwner(g_display, primary_atom); if (selectionowner != None) { - XConvertSelection(display, primary_atom, targets_atom, - rdesktop_clipboard_target_atom, wnd, CurrentTime); + XConvertSelection(g_display, primary_atom, targets_atom, + rdesktop_clipboard_target_atom, g_wnd, CurrentTime); return; } /* No PRIMARY, try CLIPBOARD */ - selectionowner = XGetSelectionOwner(display, clipboard_atom); + selectionowner = XGetSelectionOwner(g_display, clipboard_atom); if (selectionowner != None) { - XConvertSelection(display, clipboard_atom, targets_atom, - rdesktop_clipboard_target_atom, wnd, CurrentTime); + XConvertSelection(g_display, clipboard_atom, targets_atom, + rdesktop_clipboard_target_atom, g_wnd, CurrentTime); return; } @@ -292,22 +371,23 @@ if (!cliprdr_init()) return; - primary_atom = XInternAtom(display, "PRIMARY", False); - clipboard_atom = XInternAtom(display, "CLIPBOARD", False); - targets_atom = XInternAtom(display, "TARGETS", False); - timestamp_atom = XInternAtom(display, "TIMESTAMP", False); - rdesktop_clipboard_target_atom = XInternAtom(display, "_RDESKTOP_CLIPBOARD_TARGET", False); - incr_atom = XInternAtom(display, "INCR", False); + primary_atom = XInternAtom(g_display, "PRIMARY", False); + clipboard_atom = XInternAtom(g_display, "CLIPBOARD", False); + targets_atom = XInternAtom(g_display, "TARGETS", False); + timestamp_atom = XInternAtom(g_display, "TIMESTAMP", False); + rdesktop_clipboard_target_atom = + XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_TARGET", False); + incr_atom = XInternAtom(g_display, "INCR", False); targets[0] = targets_atom; - targets[1] = XInternAtom(display, "TEXT", False); - targets[2] = XInternAtom(display, "UTF8_STRING", False); - targets[3] = XInternAtom(display, "text/unicode", False); - targets[4] = XInternAtom(display, "TIMESTAMP", False); + targets[1] = XInternAtom(g_display, "TEXT", False); + targets[2] = XInternAtom(g_display, "UTF8_STRING", False); + targets[3] = XInternAtom(g_display, "text/unicode", False); + targets[4] = XInternAtom(g_display, "TIMESTAMP", False); targets[5] = XA_STRING; /* rdesktop sets _RDESKTOP_CLIPBOARD_FORMATS on the root window when acquiring the clipboard. Other interested rdesktops can use this to notify their server of the available formats. */ rdesktop_clipboard_formats_atom = - XInternAtom(display, "_RDESKTOP_CLIPBOARD_FORMATS", False); - XSelectInput(display, DefaultRootWindow(display), PropertyChangeMask); + XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_FORMATS", False); + XSelectInput(g_display, DefaultRootWindow(g_display), PropertyChangeMask); }