📄 xclip.c
字号:
return True; } else { return False; }}static voidxclip_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);}static voidxclip_notify_change(){ XChangeProperty(g_display, DefaultRootWindow(g_display), rdesktop_selection_notify_atom, XA_INTEGER, 32, PropModeReplace, NULL, 0);}static voidxclip_probe_selections(){ Window primary_owner, clipboard_owner; if (probing_selections) { DEBUG_CLIPBOARD(("Already probing selections. Scheduling reprobe.\n")); reprobe_selections = True; return; } DEBUG_CLIPBOARD(("Probing selections.\n")); probing_selections = True; reprobe_selections = False; xclip_clear_target_props(); if (auto_mode) primary_owner = XGetSelectionOwner(g_display, primary_atom); else primary_owner = None; clipboard_owner = XGetSelectionOwner(g_display, clipboard_atom); /* If we own all relevant selections then don't do anything. */ if (((primary_owner == g_wnd) || !auto_mode) && (clipboard_owner == g_wnd)) goto end; /* 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; } DEBUG_CLIPBOARD(("No owner of any selection.\n")); /* FIXME: Without XFIXES, we cannot reliably know the formats offered by an upcoming selection owner, so we just lie about him offering RDP_CF_TEXT. */ cliprdr_send_simple_native_format_announce(RDP_CF_TEXT); end: probing_selections = False;}/* This function is called for SelectionNotify events. The SelectionNotify event is sent from the clipboard owner to the requestor after his request was satisfied. If this function is called, we're the requestor side. */#ifndef MAKE_PROTOvoidxclip_handle_SelectionNotify(XSelectionEvent * event){ unsigned long nitems, bytes_left; XWindowAttributes wa; Atom type; Atom *supported_targets; int res, i, format; uint8 *data = NULL; if (event->property == None) goto fail; DEBUG_CLIPBOARD(("xclip_handle_SelectionNotify: selection=%s, target=%s, property=%s\n", XGetAtomName(g_display, event->selection), XGetAtomName(g_display, event->target), XGetAtomName(g_display, event->property))); 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, AnyPropertyType, &type, &format, &nitems, &bytes_left, &data); } else { res = XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_timestamp_target_atom, 0, XMaxRequestSize(g_display), False, AnyPropertyType, &type, &format, &nitems, &bytes_left, &data); } if ((res != Success) || (nitems != 1) || (format != 32)) { DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n")); 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; } if (probing_selections && reprobe_selections) { probing_selections = False; xclip_probe_selections(); return; } res = XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_target_atom, 0, XMaxRequestSize(g_display), False, AnyPropertyType, &type, &format, &nitems, &bytes_left, &data); xclip_clear_target_props(); if (res != Success) { DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n")); goto fail; } if (type == incr_atom) { DEBUG_CLIPBOARD(("Received INCR.\n")); XGetWindowAttributes(g_display, g_wnd, &wa); if ((wa.your_event_mask | PropertyChangeMask) != wa.your_event_mask) { XSelectInput(g_display, g_wnd, (wa.your_event_mask | PropertyChangeMask)); } XFree(data); g_incr_target = event->target; g_waiting_for_INCR = 1; goto end; } /* Negotiate target format */ if (event->target == targets_atom) { /* Determine the best of text targets that we have available: Prefer UTF8_STRING > text/unicode (unspecified encoding) > STRING (ignore TEXT and COMPOUND_TEXT because we don't have code to handle them) */ int text_target_satisfaction = 0; Atom best_text_target = 0; /* measures how much we're satisfied with what we found */ if (type != None) { supported_targets = (Atom *) data; for (i = 0; i < nitems; i++) { DEBUG_CLIPBOARD(("Target %d: %s\n", i, XGetAtomName(g_display, supported_targets[i]))); if (supported_targets[i] == format_string_atom) { if (text_target_satisfaction < 1) { DEBUG_CLIPBOARD(("Other party supports STRING, choosing that as best_target\n")); best_text_target = supported_targets[i]; text_target_satisfaction = 1; } }#ifdef USE_UNICODE_CLIPBOARD else if (supported_targets[i] == format_unicode_atom) { if (text_target_satisfaction < 2) { DEBUG_CLIPBOARD(("Other party supports text/unicode, choosing that as best_target\n")); best_text_target = supported_targets[i]; text_target_satisfaction = 2; } } else if (supported_targets[i] == format_utf8_string_atom) { if (text_target_satisfaction < 3) { DEBUG_CLIPBOARD(("Other party supports UTF8_STRING, choosing that as best_target\n")); best_text_target = supported_targets[i]; text_target_satisfaction = 3; } }#endif else if (supported_targets[i] == rdesktop_clipboard_formats_atom) { if (probing_selections && (text_target_satisfaction < 4)) { DEBUG_CLIPBOARD(("Other party supports native formats, choosing that as best_target\n")); best_text_target = supported_targets[i]; text_target_satisfaction = 4; } } } } /* Kickstarting the next step in the process of satisfying RDP's clipboard request -- specifically, requesting the actual clipboard data. */ if ((best_text_target != 0) && (!probing_selections || (best_text_target == rdesktop_clipboard_formats_atom))) { XConvertSelection(g_display, event->selection, best_text_target, rdesktop_clipboard_target_atom, g_wnd, event->time); goto end; } else { DEBUG_CLIPBOARD(("Unable to find a textual target to satisfy RDP clipboard text request\n")); goto fail; } } else { if (probing_selections) { Window primary_owner, clipboard_owner; /* FIXME: Without XFIXES, we must make sure that the other rdesktop owns all relevant selections or we might try to get a native format from non-rdesktop window later on. */ clipboard_owner = XGetSelectionOwner(g_display, clipboard_atom); if (auto_mode) primary_owner = XGetSelectionOwner(g_display, primary_atom); else primary_owner = clipboard_owner; if (primary_owner != clipboard_owner) goto fail; DEBUG_CLIPBOARD(("Got fellow rdesktop formats\n")); probing_selections = False; rdesktop_is_selection_owner = True; cliprdr_send_native_format_announce(data, nitems); } else if (!xclip_send_data_with_convert(data, nitems, event->target)) { goto fail; } } end: if (data) XFree(data); return; fail: xclip_clear_target_props(); if (probing_selections) { DEBUG_CLIPBOARD(("Unable to find suitable target. Using default text format.\n")); probing_selections = False; rdesktop_is_selection_owner = False; /* FIXME: Without XFIXES, we cannot reliably know the formats offered by an upcoming selection owner, so we just lie about him offering RDP_CF_TEXT. */ cliprdr_send_simple_native_format_announce(RDP_CF_TEXT); } else { helper_cliprdr_send_empty_response(); } goto end;}/* This function is called for SelectionRequest events. The SelectionRequest event is sent from the requestor to the clipboard owner to request clipboard data. */voidxclip_handle_SelectionRequest(XSelectionRequestEvent * event){ unsigned long nitems, bytes_left; unsigned char *prop_return; int format, res; Atom type; DEBUG_CLIPBOARD(("xclip_handle_SelectionRequest: selection=%s, target=%s, property=%s\n", XGetAtomName(g_display, event->selection), XGetAtomName(g_display, event->target), XGetAtomName(g_display, event->property))); if (event->target == targets_atom) { xclip_provide_selection(event, XA_ATOM, 32, (uint8 *) & targets, num_targets); return; } else if (event->target == timestamp_atom) { xclip_provide_selection(event, XA_INTEGER, 32, (uint8 *) & acquire_time, 1); return; } else if (event->target == rdesktop_clipboard_formats_atom) { xclip_provide_selection(event, XA_STRING, 8, formats_data, formats_data_length); } else { /* All the following targets require an async operation with the RDP server and currently we don't do X clipboard request queueing so we can only handle one such request at a time. */ if (has_selection_request) { DEBUG_CLIPBOARD(("Error: Another clipboard request was already sent to the RDP server and not yet responded. Refusing this request.\n")); xclip_refuse_selection(event); return; } if (event->target == rdesktop_native_atom) { /* Before the requestor makes a request for the _RDESKTOP_NATIVE target, he should declare requestor[property] = CF_SOMETHING. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -