📄 xclip.c
字号:
res = XGetWindowProperty(g_display, event->requestor, event->property, 0, 1, True, XA_INTEGER, &type, &format, &nitems, &bytes_left, &prop_return); if (res != Success || (!prop_return)) { DEBUG_CLIPBOARD(("Requested native format but didn't specifiy which.\n")); xclip_refuse_selection(event); return; } format = *(uint32 *) prop_return; XFree(prop_return); } else if (event->target == format_string_atom || event->target == XA_STRING) { /* STRING and XA_STRING are defined to be ISO8859-1 */ format = CF_TEXT; } else if (event->target == format_utf8_string_atom) {#ifdef USE_UNICODE_CLIPBOARD format = CF_UNICODETEXT;#else DEBUG_CLIPBOARD(("Requested target unavailable due to lack of Unicode support. (It was not in TARGETS, so why did you ask for it?!)\n")); xclip_refuse_selection(event); return;#endif } else if (event->target == format_unicode_atom) { /* Assuming text/unicode to be UTF-16 */ format = CF_UNICODETEXT; } else { DEBUG_CLIPBOARD(("Requested target unavailable. (It was not in TARGETS, so why did you ask for it?!)\n")); xclip_refuse_selection(event); return; } cliprdr_send_data_request(format); selection_request = *event; has_selection_request = True; return; /* wait for data */ }}/* While this rdesktop holds ownership over the clipboard, it means the clipboard data is offered by the RDP server (and when it is pasted inside RDP, there's no network roundtrip). This event (SelectionClear) symbolizes this rdesktop lost onwership of the clipboard to some other X client. We should find out what clipboard formats this other client offers and announce that to RDP. */voidxclip_handle_SelectionClear(void){ DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n")); xclip_notify_change(); xclip_probe_selections();}/* Called when any property changes in our window or the root window. */voidxclip_handle_PropertyNotify(XPropertyEvent * event){ unsigned long nitems; unsigned long offset = 0; unsigned long bytes_left = 1; int format; XWindowAttributes wa; uint8 *data; Atom type; if (event->state == PropertyNewValue && g_waiting_for_INCR) { DEBUG_CLIPBOARD(("x_clip_handle_PropertyNotify: g_waiting_for_INCR != 0\n")); while (bytes_left > 0) { /* Unlike the specification, we don't set the 'delete' arugment to True since we slurp the INCR's chunks in even-smaller chunks of 4096 bytes. */ if ((XGetWindowProperty (g_display, g_wnd, rdesktop_clipboard_target_atom, offset, 4096L, False, AnyPropertyType, &type, &format, &nitems, &bytes_left, &data) != Success)) { XFree(data); return; } if (nitems == 0) { /* INCR transfer finished */ XGetWindowAttributes(g_display, g_wnd, &wa); XSelectInput(g_display, g_wnd, (wa.your_event_mask ^ PropertyChangeMask)); XFree(data); g_waiting_for_INCR = 0; if (g_clip_buflen > 0) { if (!xclip_send_data_with_convert (g_clip_buffer, g_clip_buflen, g_incr_target)) { helper_cliprdr_send_empty_response(); } xfree(g_clip_buffer); g_clip_buffer = NULL; g_clip_buflen = 0; } } else { /* Another chunk in the INCR transfer */ offset += (nitems / 4); /* offset at which to begin the next slurp */ g_clip_buffer = xrealloc(g_clip_buffer, g_clip_buflen + nitems); memcpy(g_clip_buffer + g_clip_buflen, data, nitems); g_clip_buflen += nitems; XFree(data); } } XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom); return; } if ((event->atom == rdesktop_selection_notify_atom) && (event->window == DefaultRootWindow(g_display))) xclip_probe_selections();}#endif/* Called when the RDP server announces new clipboard data formats. In response, we: - take ownership over the clipboard - declare those formats in their Windows native form to other rdesktop instances on this X server */voidui_clip_format_announce(uint8 * data, uint32 length){ acquire_time = g_last_gesturetime; XSetSelectionOwner(g_display, primary_atom, g_wnd, acquire_time); if (XGetSelectionOwner(g_display, primary_atom) != g_wnd) warning("Failed to aquire ownership of PRIMARY clipboard\n"); XSetSelectionOwner(g_display, clipboard_atom, g_wnd, acquire_time); if (XGetSelectionOwner(g_display, clipboard_atom) != g_wnd) warning("Failed to aquire ownership of CLIPBOARD clipboard\n"); if (formats_data) xfree(formats_data); formats_data = xmalloc(length); memcpy(formats_data, data, length); formats_data_length = length; xclip_notify_change();}/* Called when the RDP server responds with clipboard data (after we've requested it). */voidui_clip_handle_data(uint8 * data, uint32 length){ RD_BOOL free_data = False; if (length == 0) { xclip_refuse_selection(&selection_request); has_selection_request = False; return; } if (selection_request.target == format_string_atom || selection_request.target == XA_STRING) { /* We're expecting a CF_TEXT response */ 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; } }#ifdef USE_UNICODE_CLIPBOARD else if (selection_request.target == format_utf8_string_atom) { /* We're expecting a CF_UNICODETEXT response */ iconv_t cd = iconv_open("UTF-8", WINDOWS_CODEPAGE); if (cd != (iconv_t) - 1) { size_t utf8_length = length * 2; char *utf8_data = malloc(utf8_length); size_t utf8_length_remaining = utf8_length; char *utf8_data_remaining = utf8_data; char *data_remaining = (char *) data; size_t length_remaining = (size_t) length; if (utf8_data == NULL) { iconv_close(cd); return; } iconv(cd, (ICONV_CONST char **) &data_remaining, &length_remaining, &utf8_data_remaining, &utf8_length_remaining); iconv_close(cd); free_data = True; data = (uint8 *) utf8_data; length = utf8_length - utf8_length_remaining; /* translate linebreaks (works just as well on UTF-8) */ crlf2lf(data, &length); } } else if (selection_request.target == format_unicode_atom) { /* We're expecting a CF_UNICODETEXT response, so what we're receiving matches our requirements and there's no need for further conversions. */ }#endif else if (selection_request.target == rdesktop_native_atom) { /* Pass as-is */ } else { DEBUG_CLIPBOARD(("ui_clip_handle_data: BUG! I don't know how to convert selection target %s!\n", XGetAtomName(g_display, selection_request.target))); xclip_refuse_selection(&selection_request); has_selection_request = False; return; } xclip_provide_selection(&selection_request, selection_request.target, 8, data, length - 1); has_selection_request = False; if (free_data) free(data);}voidui_clip_request_failed(){ xclip_refuse_selection(&selection_request); has_selection_request = False;}voidui_clip_request_data(uint32 format){ Window primary_owner, clipboard_owner; DEBUG_CLIPBOARD(("Request from server for format %d\n", format)); rdp_clipboard_request_format = format; if (probing_selections) { DEBUG_CLIPBOARD(("ui_clip_request_data: Selection probe in progress. Cannot handle request.\n")); helper_cliprdr_send_empty_response(); return; } xclip_clear_target_props(); if (rdesktop_is_selection_owner) { XChangeProperty(g_display, g_wnd, rdesktop_clipboard_target_atom, XA_INTEGER, 32, PropModeReplace, (unsigned char *) &format, 1); XConvertSelection(g_display, primary_atom, rdesktop_native_atom, rdesktop_clipboard_target_atom, g_wnd, CurrentTime); return; } if (auto_mode) primary_owner = XGetSelectionOwner(g_display, primary_atom); else primary_owner = 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, rdesktop_clipboard_target_atom, g_wnd, CurrentTime); return; } /* Just CLIPBOARD */ if (clipboard_owner != None) { XConvertSelection(g_display, clipboard_atom, targets_atom, rdesktop_clipboard_target_atom, g_wnd, CurrentTime); return; } /* No data available */ helper_cliprdr_send_empty_response();}voidui_clip_sync(void){ xclip_probe_selections();}voidui_clip_set_mode(const char *optarg){ g_rdpclip = True; if (str_startswith(optarg, "PRIMARYCLIPBOARD")) auto_mode = True; else if (str_startswith(optarg, "CLIPBOARD")) auto_mode = False; else { warning("Invalid clipboard mode '%s'.\n", optarg); g_rdpclip = False; }}voidxclip_init(void){ if (!g_rdpclip) return; if (!cliprdr_init()) return; 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); 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); format_unicode_atom = XInternAtom(g_display, "text/unicode", False); /* rdesktop sets _RDESKTOP_SELECTION_NOTIFY on the root window when acquiring the clipboard. Other interested rdesktops can use this to notify their server of the available formats. */ rdesktop_selection_notify_atom = XInternAtom(g_display, "_RDESKTOP_SELECTION_NOTIFY", False); XSelectInput(g_display, DefaultRootWindow(g_display), PropertyChangeMask); probing_selections = False; rdesktop_native_atom = XInternAtom(g_display, "_RDESKTOP_NATIVE", False); rdesktop_clipboard_formats_atom = XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_FORMATS", False); rdesktop_primary_owner_atom = XInternAtom(g_display, "_RDESKTOP_PRIMARY_OWNER", False); rdesktop_clipboard_owner_atom = XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_OWNER", False); num_targets = 0; targets[num_targets++] = targets_atom; targets[num_targets++] = timestamp_atom; targets[num_targets++] = rdesktop_native_atom; targets[num_targets++] = rdesktop_clipboard_formats_atom;#ifdef USE_UNICODE_CLIPBOARD targets[num_targets++] = format_utf8_string_atom;#endif targets[num_targets++] = format_unicode_atom; targets[num_targets++] = format_string_atom; targets[num_targets++] = XA_STRING;}voidxclip_deinit(void){ if (XGetSelectionOwner(g_display, primary_atom) == g_wnd) XSetSelectionOwner(g_display, primary_atom, None, acquire_time); if (XGetSelectionOwner(g_display, clipboard_atom) == g_wnd) XSetSelectionOwner(g_display, clipboard_atom, None, acquire_time); xclip_notify_change();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -