a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* -*- c-basic-offset: 8 -*-
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop: A Remote Desktop Protocol client.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Protocol services - Clipboard functions
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Copyright 2003-2008 Erik Forsberg <forsberg@cendio.se> for Cendio AB
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 2003-2008
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Copyright 2006-2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync This program is free software: you can redistribute it and/or modify
a180a41bba1d50822df23fff0099e90b86638b89vboxsync it under the terms of the GNU General Public License as published by
a180a41bba1d50822df23fff0099e90b86638b89vboxsync the Free Software Foundation, either version 3 of the License, or
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (at your option) any later version.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync This program is distributed in the hope that it will be useful,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync but WITHOUT ANY WARRANTY; without even the implied warranty of
a180a41bba1d50822df23fff0099e90b86638b89vboxsync MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
a180a41bba1d50822df23fff0099e90b86638b89vboxsync GNU General Public License for more details.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync You should have received a copy of the GNU General Public License
a180a41bba1d50822df23fff0099e90b86638b89vboxsync along with this program. If not, see <http://www.gnu.org/licenses/>.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync*/
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync/*
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * Oracle GPL Disclaimer: For the avoidance of doubt, except that if any license choice
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * the General Public License version 2 (GPLv2) at this time for any software where
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * a choice of GPL license versions is made available with the language indicating
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * that GPLv2 or any later version may be used, or where a choice of which version
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * of the GPL is applied is otherwise unspecified.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include <X11/Xlib.h>
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include <X11/Xatom.h>
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include "rdesktop.h"
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/*
a180a41bba1d50822df23fff0099e90b86638b89vboxsync To gain better understanding of this code, one could be assisted by the following documents:
a180a41bba1d50822df23fff0099e90b86638b89vboxsync - Inter-Client Communication Conventions Manual (ICCCM)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync HTML: http://tronche.com/gui/x/icccm/
a180a41bba1d50822df23fff0099e90b86638b89vboxsync PDF: http://ftp.xfree86.org/pub/XFree86/4.5.0/doc/PDF/icccm.pdf
a180a41bba1d50822df23fff0099e90b86638b89vboxsync - MSDN: Clipboard Formats
a180a41bba1d50822df23fff0099e90b86638b89vboxsync http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/dataexchange/clipboard/clipboardformats.asp
a180a41bba1d50822df23fff0099e90b86638b89vboxsync*/
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#ifdef HAVE_ICONV
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#ifdef HAVE_LANGINFO_H
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#ifdef HAVE_ICONV_H
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include <langinfo.h>
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync#if defined(RT_OS_SOLARIS) && !defined(_XPG6)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync# define VBOX_XPG6_TMP_DEF
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync# define _XPG6
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync#endif
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync#if defined(RT_OS_SOLARIS) && defined(__USE_LEGACY_PROTOTYPES__)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync# define VBOX_LEGACY_PROTO_TMP_DEF
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync# undef __USE_LEGACY_PROTOTYPES__
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync# endif
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#include <iconv.h>
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync#if defined(VBOX_XPG6_TMP_DEF)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync# undef _XPG6
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync# undef VBOX_XPG6_TMP_DEF
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync#endif
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync#if defined(VBOX_LEGACY_PROTO_TMP_DEF)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync# define __USE_LEGACY_PROTOTYPES__
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync# undef VBOX_LEGACY_PROTO_TMP_DEF
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync#endif
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#define USE_UNICODE_CLIPBOARD
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#endif
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#endif
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#endif
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#ifdef USE_UNICODE_CLIPBOARD
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#define RDP_CF_TEXT CF_UNICODETEXT
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#define RDP_CF_TEXT CF_TEXT
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#endif
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#define MAX_TARGETS 8
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncextern Display *g_display;
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncextern Window g_wnd;
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncextern Time g_last_gesturetime;
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncextern RD_BOOL g_rdpclip;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Mode of operation.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync - Auto: Look at both PRIMARY and CLIPBOARD and use the most recent.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync - Non-auto: Look at just CLIPBOARD. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic RD_BOOL auto_mode = True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Atoms of the two X selections we're dealing with: CLIPBOARD (explicit-copy) and PRIMARY (selection-copy) */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic Atom clipboard_atom, primary_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Atom of the TARGETS clipboard target */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic Atom targets_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Atom of the TIMESTAMP clipboard target */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic Atom timestamp_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Atom _RDESKTOP_CLIPBOARD_TARGET which is used as the 'property' argument in
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XConvertSelection calls: This is the property of our window into which
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XConvertSelection will store the received clipboard data. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic Atom rdesktop_clipboard_target_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Atoms _RDESKTOP_PRIMARY_TIMESTAMP_TARGET and _RDESKTOP_CLIPBOARD_TIMESTAMP_TARGET
a180a41bba1d50822df23fff0099e90b86638b89vboxsync are used to store the timestamps for when a window got ownership of the selections.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync We use these to determine which is more recent and should be used. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic Atom rdesktop_primary_timestamp_target_atom, rdesktop_clipboard_timestamp_target_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Storage for timestamps since we get them in two separate notifications. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic Time primary_timestamp, clipboard_timestamp;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Clipboard target for getting a list of native Windows clipboard formats. The
a180a41bba1d50822df23fff0099e90b86638b89vboxsync presence of this target indicates that the selection owner is another rdesktop. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic Atom rdesktop_clipboard_formats_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* The clipboard target (X jargon for "clipboard format") for rdesktop-to-rdesktop
a180a41bba1d50822df23fff0099e90b86638b89vboxsync interchange of Windows native clipboard data. The requestor must supply the
a180a41bba1d50822df23fff0099e90b86638b89vboxsync desired native Windows clipboard format in the associated property. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic Atom rdesktop_native_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Local copy of the list of native Windows clipboard formats. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic uint8 *formats_data = NULL;
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic uint32 formats_data_length = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* We need to know when another rdesktop process gets or loses ownership of a
a180a41bba1d50822df23fff0099e90b86638b89vboxsync selection. Without XFixes we do this by touching a property on the root window
a180a41bba1d50822df23fff0099e90b86638b89vboxsync which will generate PropertyNotify notifications. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic Atom rdesktop_selection_notify_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* State variables that indicate if we're currently probing the targets of the
a180a41bba1d50822df23fff0099e90b86638b89vboxsync selection owner. reprobe_selections indicate that the ownership changed in
a180a41bba1d50822df23fff0099e90b86638b89vboxsync the middle of the current probe so it should be restarted. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic RD_BOOL probing_selections, reprobe_selections;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Atoms _RDESKTOP_PRIMARY_OWNER and _RDESKTOP_CLIPBOARD_OWNER. Used as properties
a180a41bba1d50822df23fff0099e90b86638b89vboxsync on the root window to indicate which selections that are owned by rdesktop. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic Atom rdesktop_primary_owner_atom, rdesktop_clipboard_owner_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic Atom format_string_atom, format_utf8_string_atom, format_unicode_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Atom of the INCR clipboard type (see ICCCM on "INCR Properties") */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic Atom incr_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Stores the last "selection request" (= another X client requesting clipboard data from us).
a180a41bba1d50822df23fff0099e90b86638b89vboxsync To satisfy such a request, we request the clipboard data from the RDP server.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync When we receive the response from the RDP server (asynchronously), this variable gives us
a180a41bba1d50822df23fff0099e90b86638b89vboxsync the context to proceed. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic XSelectionRequestEvent selection_request;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Denotes we have a pending selection request. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic RD_BOOL has_selection_request;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Stores the clipboard format (CF_TEXT, CF_UNICODETEXT etc.) requested in the last
a180a41bba1d50822df23fff0099e90b86638b89vboxsync CLIPDR_DATA_REQUEST (= the RDP server requesting clipboard data from us).
a180a41bba1d50822df23fff0099e90b86638b89vboxsync When we receive this data from whatever X client offering it, this variable gives us
a180a41bba1d50822df23fff0099e90b86638b89vboxsync the context to proceed.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic int rdp_clipboard_request_format;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Array of offered clipboard targets that will be sent to fellow X clients upon a TARGETS request. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic Atom targets[MAX_TARGETS];
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic int num_targets;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Denotes that an rdesktop (not this rdesktop) is owning the selection,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync allowing us to interchange Windows native clipboard data directly. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic RD_BOOL rdesktop_is_selection_owner = False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Time when we acquired the selection. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic Time acquire_time = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Denotes that an INCR ("chunked") transfer is in progress. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic int g_waiting_for_INCR = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Denotes the target format of the ongoing INCR ("chunked") transfer. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic Atom g_incr_target = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Buffers an INCR transfer. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic uint8 *g_clip_buffer = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Denotes the size of g_clip_buffer. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic uint32 g_clip_buflen = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Translates CR-LF to LF.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Changes the string in-place.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Does not stop on embedded nulls.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync The length is updated. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void
a180a41bba1d50822df23fff0099e90b86638b89vboxsynccrlf2lf(uint8 * data, uint32 * length)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint8 *dst, *src;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync src = dst = data;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync while (src < data + *length)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (*src != '\x0d')
a180a41bba1d50822df23fff0099e90b86638b89vboxsync *dst++ = *src;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync src++;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync *length = dst - data;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#ifdef USE_UNICODE_CLIPBOARD
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Translate LF to CR-LF. To do this, we must allocate more memory.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync The returned string is null-terminated, as required by CF_UNICODETEXT.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync The size is updated. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic uint8 *
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncutf16_lf2crlf(uint8 * data, uint32 * size)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint8 *result;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint16 *inptr, *outptr;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync RD_BOOL swap_endianess;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Worst case: Every char is LF */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync result = xmalloc((*size * 2) + 2);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (result == NULL)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return NULL;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync inptr = (uint16 *) data;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync outptr = (uint16 *) result;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Check for a reversed BOM */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync swap_endianess = (*inptr == 0xfffe);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint16 uvalue_previous = 0; /* Kept so we'll avoid translating CR-LF to CR-CR-LF */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync while ((uint8 *) inptr < data + *size)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint16 uvalue = *inptr;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (swap_endianess)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uvalue = ((uvalue << 8) & 0xff00) + (uvalue >> 8);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((uvalue == 0x0a) && (uvalue_previous != 0x0d))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync *outptr++ = swap_endianess ? 0x0d00 : 0x0d;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uvalue_previous = uvalue;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync *outptr++ = *inptr++;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync *outptr++ = 0; /* null termination */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync *size = (uint8 *) outptr - result;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return result;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Translate LF to CR-LF. To do this, we must allocate more memory.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync The length is updated. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic uint8 *
a180a41bba1d50822df23fff0099e90b86638b89vboxsynclf2crlf(uint8 * data, uint32 * length)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint8 *result, *p, *o;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Worst case: Every char is LF */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync result = xmalloc(*length * 2);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync p = data;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync o = result;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint8 previous = '\0'; /* Kept to avoid translating CR-LF to CR-CR-LF */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync while (p < data + *length)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((*p == '\x0a') && (previous != '\x0d'))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync *o++ = '\x0d';
a180a41bba1d50822df23fff0099e90b86638b89vboxsync previous = *p;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync *o++ = *p++;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync *length = o - result;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Convenience */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync *o++ = '\0';
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return result;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#endif
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncxclip_provide_selection(XSelectionRequestEvent * req, Atom type, unsigned int format, uint8 * data,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint32 length)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XEvent xev;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("xclip_provide_selection: requestor=0x%08x, target=%s, property=%s, length=%u\n", (unsigned) req->requestor, XGetAtomName(g_display, req->target), XGetAtomName(g_display, req->property), (unsigned) length));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XChangeProperty(g_display, req->requestor, req->property,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync type, format, PropModeReplace, data, length);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.type = SelectionNotify;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.serial = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.send_event = True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.requestor = req->requestor;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.selection = req->selection;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.target = req->target;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.property = req->property;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.time = req->time;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XSendEvent(g_display, req->requestor, False, NoEventMask, &xev);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Replies a clipboard requestor, telling that we're unable to satisfy his request for whatever reason.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync This has the benefit of finalizing the clipboard negotiation and thus not leaving our requestor
a180a41bba1d50822df23fff0099e90b86638b89vboxsync lingering (and, potentially, stuck). */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncxclip_refuse_selection(XSelectionRequestEvent * req)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XEvent xev;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("xclip_refuse_selection: requestor=0x%08x, target=%s, property=%s\n",
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (unsigned) req->requestor, XGetAtomName(g_display, req->target),
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XGetAtomName(g_display, req->property)));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.type = SelectionNotify;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.serial = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.send_event = True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.requestor = req->requestor;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.selection = req->selection;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.target = req->target;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.property = None;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xev.xselection.time = req->time;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XSendEvent(g_display, req->requestor, False, NoEventMask, &xev);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Wrapper for cliprdr_send_data which also cleans the request state. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void
a180a41bba1d50822df23fff0099e90b86638b89vboxsynchelper_cliprdr_send_response(uint8 * data, uint32 length)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (rdp_clipboard_request_format != 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync cliprdr_send_data(data, length);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdp_clipboard_request_format = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (!rdesktop_is_selection_owner)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync cliprdr_send_simple_native_format_announce(RDP_CF_TEXT);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Last resort, when we have to provide clipboard data but for whatever
a180a41bba1d50822df23fff0099e90b86638b89vboxsync reason couldn't get any.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void
a180a41bba1d50822df23fff0099e90b86638b89vboxsynchelper_cliprdr_send_empty_response()
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync helper_cliprdr_send_response(NULL, 0);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Replies with clipboard data to RDP, converting it from the target format
a180a41bba1d50822df23fff0099e90b86638b89vboxsync to the expected RDP format as necessary. Returns true if data was sent.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic RD_BOOL
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncxclip_send_data_with_convert(uint8 * source, size_t source_size, Atom target)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("xclip_send_data_with_convert: target=%s, size=%u\n",
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XGetAtomName(g_display, target), (unsigned) source_size));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#ifdef USE_UNICODE_CLIPBOARD
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (target == format_string_atom ||
a180a41bba1d50822df23fff0099e90b86638b89vboxsync target == format_unicode_atom || target == format_utf8_string_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync size_t unicode_buffer_size;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char *unicode_buffer;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync iconv_t cd;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync size_t unicode_buffer_size_remaining;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char *unicode_buffer_remaining;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char *data_remaining;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync size_t data_size_remaining;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint32 translated_data_size;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint8 *translated_data;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (rdp_clipboard_request_format != RDP_CF_TEXT)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Make an attempt to convert any string we send to Unicode.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync We don't know what the RDP server's ANSI Codepage is, or how to convert
a180a41bba1d50822df23fff0099e90b86638b89vboxsync to it, so using CF_TEXT is not safe (and is unnecessary, since all
a180a41bba1d50822df23fff0099e90b86638b89vboxsync WinNT versions are Unicode-minded).
a180a41bba1d50822df23fff0099e90b86638b89vboxsync */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (target == format_string_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char *locale_charset = nl_langinfo(CODESET);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync cd = iconv_open(WINDOWS_CODEPAGE, locale_charset);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (cd == (iconv_t) - 1)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Locale charset %s not found in iconv. Unable to convert clipboard text.\n", locale_charset));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unicode_buffer_size = source_size * 4;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (target == format_unicode_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync cd = iconv_open(WINDOWS_CODEPAGE, "UCS-2");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (cd == (iconv_t) - 1)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unicode_buffer_size = source_size;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (target == format_utf8_string_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync cd = iconv_open(WINDOWS_CODEPAGE, "UTF-8");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (cd == (iconv_t) - 1)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* UTF-8 is guaranteed to be less or equally compact
a180a41bba1d50822df23fff0099e90b86638b89vboxsync as UTF-16 for all Unicode chars >=2 bytes.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unicode_buffer_size = source_size * 2;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unicode_buffer = xmalloc(unicode_buffer_size);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unicode_buffer_size_remaining = unicode_buffer_size;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unicode_buffer_remaining = unicode_buffer;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync data_remaining = (char *) source;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync data_size_remaining = source_size;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync iconv(cd, (ICONV_CONST char **) &data_remaining, &data_size_remaining,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync &unicode_buffer_remaining, &unicode_buffer_size_remaining);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync iconv_close(cd);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* translate linebreaks */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync translated_data_size = unicode_buffer_size - unicode_buffer_size_remaining;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync translated_data = utf16_lf2crlf((uint8 *) unicode_buffer, &translated_data_size);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (translated_data != NULL)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Sending Unicode string of %d bytes\n",
a180a41bba1d50822df23fff0099e90b86638b89vboxsync translated_data_size));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync helper_cliprdr_send_response(translated_data, translated_data_size);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xfree(translated_data); /* Not the same thing as XFree! */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xfree(unicode_buffer);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (target == format_string_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint8 *translated_data;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint32 length = source_size;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (rdp_clipboard_request_format != RDP_CF_TEXT)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Translating linebreaks before sending data\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync translated_data = lf2crlf(source, &length);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (translated_data != NULL)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync helper_cliprdr_send_response(translated_data, length + 1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xfree(translated_data); /* Not the same thing as XFree! */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#endif
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (target == rdesktop_native_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync helper_cliprdr_send_response(source, source_size + 1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncxclip_clear_target_props()
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XDeleteProperty(g_display, g_wnd, rdesktop_primary_timestamp_target_atom);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_timestamp_target_atom);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncxclip_notify_change()
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XChangeProperty(g_display, DefaultRootWindow(g_display),
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_selection_notify_atom, XA_INTEGER, 32, PropModeReplace, NULL, 0);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncstatic void
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncxclip_probe_selections()
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Window primary_owner, clipboard_owner;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (probing_selections)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Already probing selections. Scheduling reprobe.\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync reprobe_selections = True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Probing selections.\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync probing_selections = True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync reprobe_selections = False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_clear_target_props();
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (auto_mode)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync primary_owner = XGetSelectionOwner(g_display, primary_atom);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync primary_owner = None;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync clipboard_owner = XGetSelectionOwner(g_display, clipboard_atom);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* If we own all relevant selections then don't do anything. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (((primary_owner == g_wnd) || !auto_mode) && (clipboard_owner == g_wnd))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync goto end;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Both available */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((primary_owner != None) && (clipboard_owner != None))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync primary_timestamp = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync clipboard_timestamp = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XConvertSelection(g_display, primary_atom, timestamp_atom,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_primary_timestamp_target_atom, g_wnd, CurrentTime);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XConvertSelection(g_display, clipboard_atom, timestamp_atom,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_clipboard_timestamp_target_atom, g_wnd, CurrentTime);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Just PRIMARY */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (primary_owner != None)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XConvertSelection(g_display, primary_atom, targets_atom,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Just CLIPBOARD */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (clipboard_owner != None)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XConvertSelection(g_display, clipboard_atom, targets_atom,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("No owner of any selection.\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* FIXME:
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Without XFIXES, we cannot reliably know the formats offered by an
a180a41bba1d50822df23fff0099e90b86638b89vboxsync upcoming selection owner, so we just lie about him offering
a180a41bba1d50822df23fff0099e90b86638b89vboxsync RDP_CF_TEXT. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync cliprdr_send_simple_native_format_announce(RDP_CF_TEXT);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync end:
a180a41bba1d50822df23fff0099e90b86638b89vboxsync probing_selections = False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* This function is called for SelectionNotify events.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync The SelectionNotify event is sent from the clipboard owner to the requestor
a180a41bba1d50822df23fff0099e90b86638b89vboxsync after his request was satisfied.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync If this function is called, we're the requestor side. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#ifndef MAKE_PROTO
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncvoid
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncxclip_handle_SelectionNotify(XSelectionEvent * event)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unsigned long nitems, bytes_left;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XWindowAttributes wa;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Atom type;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Atom *supported_targets;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync int res, i, format;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint8 *data = NULL;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (event->property == None)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync goto fail;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("xclip_handle_SelectionNotify: selection=%s, target=%s, property=%s\n",
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XGetAtomName(g_display, event->selection),
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XGetAtomName(g_display, event->target),
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XGetAtomName(g_display, event->property)));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (event->target == timestamp_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (event->selection == primary_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync res = XGetWindowProperty(g_display, g_wnd,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_primary_timestamp_target_atom, 0,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XMaxRequestSize(g_display), False, AnyPropertyType,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync &type, &format, &nitems, &bytes_left, &data);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync res = XGetWindowProperty(g_display, g_wnd,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_clipboard_timestamp_target_atom, 0,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XMaxRequestSize(g_display), False, AnyPropertyType,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync &type, &format, &nitems, &bytes_left, &data);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((res != Success) || (nitems != 1) || (format != 32))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync goto fail;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (event->selection == primary_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync primary_timestamp = *(Time *) data;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (primary_timestamp == 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync primary_timestamp++;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XDeleteProperty(g_display, g_wnd, rdesktop_primary_timestamp_target_atom);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Got PRIMARY timestamp: %u\n",
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (unsigned) primary_timestamp));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync clipboard_timestamp = *(Time *) data;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (clipboard_timestamp == 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync clipboard_timestamp++;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_timestamp_target_atom);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Got CLIPBOARD timestamp: %u\n",
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (unsigned) clipboard_timestamp));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XFree(data);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (primary_timestamp && clipboard_timestamp)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (primary_timestamp > clipboard_timestamp)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("PRIMARY is most recent selection.\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XConvertSelection(g_display, primary_atom, targets_atom,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_clipboard_target_atom, g_wnd,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync event->time);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("CLIPBOARD is most recent selection.\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XConvertSelection(g_display, clipboard_atom, targets_atom,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_clipboard_target_atom, g_wnd,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync event->time);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (probing_selections && reprobe_selections)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync probing_selections = False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_probe_selections();
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync res = XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync 0, XMaxRequestSize(g_display), False, AnyPropertyType,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync &type, &format, &nitems, &bytes_left, &data);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_clear_target_props();
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (res != Success)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync goto fail;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (type == incr_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Received INCR.\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XGetWindowAttributes(g_display, g_wnd, &wa);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((wa.your_event_mask | PropertyChangeMask) != wa.your_event_mask)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XSelectInput(g_display, g_wnd, (wa.your_event_mask | PropertyChangeMask));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XFree(data);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync g_incr_target = event->target;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync g_waiting_for_INCR = 1;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync goto end;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Negotiate target format */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (event->target == targets_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Determine the best of text targets that we have available:
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Prefer UTF8_STRING > text/unicode (unspecified encoding) > STRING
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (ignore TEXT and COMPOUND_TEXT because we don't have code to handle them)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync int text_target_satisfaction = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Atom best_text_target = 0; /* measures how much we're satisfied with what we found */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (type != None)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync supported_targets = (Atom *) data;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync for (i = 0; i < nitems; i++)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Target %d: %s\n", i,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XGetAtomName(g_display, supported_targets[i])));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (supported_targets[i] == format_string_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (text_target_satisfaction < 1)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Other party supports STRING, choosing that as best_target\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync best_text_target = supported_targets[i];
a180a41bba1d50822df23fff0099e90b86638b89vboxsync text_target_satisfaction = 1;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#ifdef USE_UNICODE_CLIPBOARD
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (supported_targets[i] == format_unicode_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (text_target_satisfaction < 2)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Other party supports text/unicode, choosing that as best_target\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync best_text_target = supported_targets[i];
a180a41bba1d50822df23fff0099e90b86638b89vboxsync text_target_satisfaction = 2;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (supported_targets[i] == format_utf8_string_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (text_target_satisfaction < 3)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Other party supports UTF8_STRING, choosing that as best_target\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync best_text_target = supported_targets[i];
a180a41bba1d50822df23fff0099e90b86638b89vboxsync text_target_satisfaction = 3;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#endif
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (supported_targets[i] == rdesktop_clipboard_formats_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (probing_selections && (text_target_satisfaction < 4))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Other party supports native formats, choosing that as best_target\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync best_text_target = supported_targets[i];
a180a41bba1d50822df23fff0099e90b86638b89vboxsync text_target_satisfaction = 4;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Kickstarting the next step in the process of satisfying RDP's
a180a41bba1d50822df23fff0099e90b86638b89vboxsync clipboard request -- specifically, requesting the actual clipboard data.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((best_text_target != 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync && (!probing_selections
a180a41bba1d50822df23fff0099e90b86638b89vboxsync || (best_text_target == rdesktop_clipboard_formats_atom)))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XConvertSelection(g_display, event->selection, best_text_target,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_clipboard_target_atom, g_wnd, event->time);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync goto end;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Unable to find a textual target to satisfy RDP clipboard text request\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync goto fail;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (probing_selections)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Window primary_owner, clipboard_owner;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* FIXME:
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Without XFIXES, we must make sure that the other
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop owns all relevant selections or we might try
a180a41bba1d50822df23fff0099e90b86638b89vboxsync to get a native format from non-rdesktop window later
a180a41bba1d50822df23fff0099e90b86638b89vboxsync on. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync clipboard_owner = XGetSelectionOwner(g_display, clipboard_atom);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (auto_mode)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync primary_owner = XGetSelectionOwner(g_display, primary_atom);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync primary_owner = clipboard_owner;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (primary_owner != clipboard_owner)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync goto fail;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Got fellow rdesktop formats\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync probing_selections = False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_is_selection_owner = True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync cliprdr_send_native_format_announce(data, nitems);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if ((!nitems) || (!xclip_send_data_with_convert(data, nitems, event->target)))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync goto fail;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync end:
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (data)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XFree(data);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync fail:
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_clear_target_props();
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (probing_selections)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Unable to find suitable target. Using default text format.\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync probing_selections = False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_is_selection_owner = False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* FIXME:
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Without XFIXES, we cannot reliably know the formats offered by an
a180a41bba1d50822df23fff0099e90b86638b89vboxsync upcoming selection owner, so we just lie about him offering
a180a41bba1d50822df23fff0099e90b86638b89vboxsync RDP_CF_TEXT. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync cliprdr_send_simple_native_format_announce(RDP_CF_TEXT);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync helper_cliprdr_send_empty_response();
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync goto end;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* This function is called for SelectionRequest events.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync The SelectionRequest event is sent from the requestor to the clipboard owner
a180a41bba1d50822df23fff0099e90b86638b89vboxsync to request clipboard data.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncvoid
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncxclip_handle_SelectionRequest(XSelectionRequestEvent * event)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unsigned long nitems, bytes_left;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unsigned char *prop_return = NULL;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync int format, res;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Atom type;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("xclip_handle_SelectionRequest: selection=%s, target=%s, property=%s\n",
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XGetAtomName(g_display, event->selection),
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XGetAtomName(g_display, event->target),
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XGetAtomName(g_display, event->property)));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (event->target == targets_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_provide_selection(event, XA_ATOM, 32, (uint8 *) & targets, num_targets);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (event->target == timestamp_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_provide_selection(event, XA_INTEGER, 32, (uint8 *) & acquire_time, 1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (event->target == rdesktop_clipboard_formats_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_provide_selection(event, XA_STRING, 8, formats_data, formats_data_length);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* All the following targets require an async operation with the RDP server
a180a41bba1d50822df23fff0099e90b86638b89vboxsync and currently we don't do X clipboard request queueing so we can only
a180a41bba1d50822df23fff0099e90b86638b89vboxsync handle one such request at a time. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (has_selection_request)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Error: Another clipboard request was already sent to the RDP server and not yet responded. Refusing this request.\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_refuse_selection(event);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (event->target == rdesktop_native_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Before the requestor makes a request for the _RDESKTOP_NATIVE target,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync he should declare requestor[property] = CF_SOMETHING. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync res = XGetWindowProperty(g_display, event->requestor,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync event->property, 0, 1, True,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XA_INTEGER, &type, &format, &nitems, &bytes_left,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync &prop_return);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (res != Success || (!prop_return))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Requested native format but didn't specifiy which.\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_refuse_selection(event);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync format = *(uint32 *) prop_return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XFree(prop_return);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (event->target == format_string_atom || event->target == XA_STRING)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* STRING and XA_STRING are defined to be ISO8859-1 */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync format = CF_TEXT;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (event->target == format_utf8_string_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#ifdef USE_UNICODE_CLIPBOARD
a180a41bba1d50822df23fff0099e90b86638b89vboxsync format = CF_UNICODETEXT;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Requested target unavailable due to lack of Unicode support. (It was not in TARGETS, so why did you ask for it?!)\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_refuse_selection(event);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#endif
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (event->target == format_unicode_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Assuming text/unicode to be UTF-16 */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync format = CF_UNICODETEXT;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Requested target unavailable. (It was not in TARGETS, so why did you ask for it?!)\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_refuse_selection(event);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync cliprdr_send_data_request(format);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync selection_request = *event;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync has_selection_request = True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return; /* wait for data */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* While this rdesktop holds ownership over the clipboard, it means the clipboard data
a180a41bba1d50822df23fff0099e90b86638b89vboxsync is offered by the RDP server (and when it is pasted inside RDP, there's no network
a180a41bba1d50822df23fff0099e90b86638b89vboxsync roundtrip).
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync This event (SelectionClear) symbolizes this rdesktop lost onwership of the clipboard
a180a41bba1d50822df23fff0099e90b86638b89vboxsync to some other X client. We should find out what clipboard formats this other
a180a41bba1d50822df23fff0099e90b86638b89vboxsync client offers and announce that to RDP. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncvoid
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncxclip_handle_SelectionClear(void)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_notify_change();
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_probe_selections();
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Called when any property changes in our window or the root window. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncvoid
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncxclip_handle_PropertyNotify(XPropertyEvent * event)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unsigned long nitems;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unsigned long offset = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync unsigned long bytes_left = 1;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync int format;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XWindowAttributes wa;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint8 *data;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Atom type;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (event->state == PropertyNewValue && g_waiting_for_INCR)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("x_clip_handle_PropertyNotify: g_waiting_for_INCR != 0\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync while (bytes_left > 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Unlike the specification, we don't set the 'delete' arugment to True
a180a41bba1d50822df23fff0099e90b86638b89vboxsync since we slurp the INCR's chunks in even-smaller chunks of 4096 bytes. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((XGetWindowProperty
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (g_display, g_wnd, rdesktop_clipboard_target_atom, offset, 4096L,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync False, AnyPropertyType, &type, &format, &nitems, &bytes_left,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync &data) != Success))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XFree(data);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (nitems == 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* INCR transfer finished */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XGetWindowAttributes(g_display, g_wnd, &wa);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XSelectInput(g_display, g_wnd,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (wa.your_event_mask ^ PropertyChangeMask));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XFree(data);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync g_waiting_for_INCR = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (g_clip_buflen > 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (!xclip_send_data_with_convert
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (g_clip_buffer, g_clip_buflen, g_incr_target))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync helper_cliprdr_send_empty_response();
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xfree(g_clip_buffer);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync g_clip_buffer = NULL;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync g_clip_buflen = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Another chunk in the INCR transfer */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync offset += (nitems / 4); /* offset at which to begin the next slurp */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync g_clip_buffer = xrealloc(g_clip_buffer, g_clip_buflen + nitems);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync memcpy(g_clip_buffer + g_clip_buflen, data, nitems);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync g_clip_buflen += nitems;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XFree(data);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((event->atom == rdesktop_selection_notify_atom) &&
a180a41bba1d50822df23fff0099e90b86638b89vboxsync (event->window == DefaultRootWindow(g_display)))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_probe_selections();
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#endif
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Called when the RDP server announces new clipboard data formats.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync In response, we:
a180a41bba1d50822df23fff0099e90b86638b89vboxsync - take ownership over the clipboard
a180a41bba1d50822df23fff0099e90b86638b89vboxsync - declare those formats in their Windows native form
a180a41bba1d50822df23fff0099e90b86638b89vboxsync to other rdesktop instances on this X server */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncvoid
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncui_clip_format_announce(uint8 * data, uint32 length)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync acquire_time = g_last_gesturetime;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XSetSelectionOwner(g_display, primary_atom, g_wnd, acquire_time);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (XGetSelectionOwner(g_display, primary_atom) != g_wnd)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync warning("Failed to aquire ownership of PRIMARY clipboard\n");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XSetSelectionOwner(g_display, clipboard_atom, g_wnd, acquire_time);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (XGetSelectionOwner(g_display, clipboard_atom) != g_wnd)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync warning("Failed to aquire ownership of CLIPBOARD clipboard\n");
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (formats_data)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xfree(formats_data);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync formats_data = xmalloc(length);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync memcpy(formats_data, data, length);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync formats_data_length = length;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_notify_change();
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync/* Called when the RDP server responds with clipboard data (after we've requested it). */
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncvoid
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncui_clip_handle_data(uint8 * data, uint32 length)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync RD_BOOL free_data = False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (length == 0)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_refuse_selection(&selection_request);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync has_selection_request = False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (selection_request.target == format_string_atom || selection_request.target == XA_STRING)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* We're expecting a CF_TEXT response */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync uint8 *firstnull;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* translate linebreaks */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync crlf2lf(data, &length);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Only send data up to null byte, if any */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync firstnull = (uint8 *) strchr((char *) data, '\0');
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (firstnull)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync length = firstnull - data + 1;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#ifdef USE_UNICODE_CLIPBOARD
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (selection_request.target == format_utf8_string_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* We're expecting a CF_UNICODETEXT response */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync iconv_t cd = iconv_open("UTF-8", WINDOWS_CODEPAGE);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (cd != (iconv_t) - 1)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync size_t utf8_length = length * 2;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char *utf8_data = malloc(utf8_length);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync size_t utf8_length_remaining = utf8_length;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char *utf8_data_remaining = utf8_data;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync char *data_remaining = (char *) data;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync size_t length_remaining = (size_t) length;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (utf8_data == NULL)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync iconv_close(cd);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync iconv(cd, (ICONV_CONST char **) &data_remaining, &length_remaining,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync &utf8_data_remaining, &utf8_length_remaining);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync iconv_close(cd);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync free_data = True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync data = (uint8 *) utf8_data;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync length = utf8_length - utf8_length_remaining;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* translate linebreaks (works just as well on UTF-8) */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync crlf2lf(data, &length);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (selection_request.target == format_unicode_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* We're expecting a CF_UNICODETEXT response, so what we're
a180a41bba1d50822df23fff0099e90b86638b89vboxsync receiving matches our requirements and there's no need
a180a41bba1d50822df23fff0099e90b86638b89vboxsync for further conversions. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#endif
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (selection_request.target == rdesktop_native_atom)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Pass as-is */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("ui_clip_handle_data: BUG! I don't know how to convert selection target %s!\n", XGetAtomName(g_display, selection_request.target)));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_refuse_selection(&selection_request);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync has_selection_request = False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_provide_selection(&selection_request, selection_request.target, 8, data, length - 1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync has_selection_request = False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (free_data)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync free(data);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncvoid
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncui_clip_request_failed()
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_refuse_selection(&selection_request);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync has_selection_request = False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncvoid
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncui_clip_request_data(uint32 format)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Window primary_owner, clipboard_owner;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("Request from server for format %d\n", format));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdp_clipboard_request_format = format;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (probing_selections)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync DEBUG_CLIPBOARD(("ui_clip_request_data: Selection probe in progress. Cannot handle request.\n"));
a180a41bba1d50822df23fff0099e90b86638b89vboxsync helper_cliprdr_send_empty_response();
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_clear_target_props();
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (rdesktop_is_selection_owner)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XChangeProperty(g_display, g_wnd, rdesktop_clipboard_target_atom,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XA_INTEGER, 32, PropModeReplace, (unsigned char *) &format, 1);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XConvertSelection(g_display, primary_atom, rdesktop_native_atom,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (auto_mode)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync primary_owner = XGetSelectionOwner(g_display, primary_atom);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync primary_owner = None;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync clipboard_owner = XGetSelectionOwner(g_display, clipboard_atom);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Both available */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if ((primary_owner != None) && (clipboard_owner != None))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync primary_timestamp = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync clipboard_timestamp = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XConvertSelection(g_display, primary_atom, timestamp_atom,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_primary_timestamp_target_atom, g_wnd, CurrentTime);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XConvertSelection(g_display, clipboard_atom, timestamp_atom,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_clipboard_timestamp_target_atom, g_wnd, CurrentTime);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Just PRIMARY */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (primary_owner != None)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XConvertSelection(g_display, primary_atom, targets_atom,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* Just CLIPBOARD */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (clipboard_owner != None)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XConvertSelection(g_display, clipboard_atom, targets_atom,
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_clipboard_target_atom, g_wnd, CurrentTime);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* No data available */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync helper_cliprdr_send_empty_response();
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncvoid
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncui_clip_sync(void)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_probe_selections();
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncvoid
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncui_clip_set_mode(const char *optarg)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync g_rdpclip = True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (str_startswith(optarg, "PRIMARYCLIPBOARD"))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync auto_mode = True;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else if (str_startswith(optarg, "CLIPBOARD"))
a180a41bba1d50822df23fff0099e90b86638b89vboxsync auto_mode = False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync else
a180a41bba1d50822df23fff0099e90b86638b89vboxsync {
a180a41bba1d50822df23fff0099e90b86638b89vboxsync warning("Invalid clipboard mode '%s'.\n", optarg);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync g_rdpclip = False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync }
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncvoid
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncxclip_init(void)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (!g_rdpclip)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (!cliprdr_init())
a180a41bba1d50822df23fff0099e90b86638b89vboxsync return;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync primary_atom = XInternAtom(g_display, "PRIMARY", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync clipboard_atom = XInternAtom(g_display, "CLIPBOARD", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync targets_atom = XInternAtom(g_display, "TARGETS", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync timestamp_atom = XInternAtom(g_display, "TIMESTAMP", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_clipboard_target_atom =
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_TARGET", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_primary_timestamp_target_atom =
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XInternAtom(g_display, "_RDESKTOP_PRIMARY_TIMESTAMP_TARGET", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_clipboard_timestamp_target_atom =
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_TIMESTAMP_TARGET", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync incr_atom = XInternAtom(g_display, "INCR", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync format_string_atom = XInternAtom(g_display, "STRING", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync format_utf8_string_atom = XInternAtom(g_display, "UTF8_STRING", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync format_unicode_atom = XInternAtom(g_display, "text/unicode", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync /* rdesktop sets _RDESKTOP_SELECTION_NOTIFY on the root window when acquiring the clipboard.
a180a41bba1d50822df23fff0099e90b86638b89vboxsync Other interested rdesktops can use this to notify their server of the available formats. */
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_selection_notify_atom =
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XInternAtom(g_display, "_RDESKTOP_SELECTION_NOTIFY", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XSelectInput(g_display, DefaultRootWindow(g_display), PropertyChangeMask);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync probing_selections = False;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_native_atom = XInternAtom(g_display, "_RDESKTOP_NATIVE", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_clipboard_formats_atom =
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_FORMATS", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_primary_owner_atom = XInternAtom(g_display, "_RDESKTOP_PRIMARY_OWNER", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync rdesktop_clipboard_owner_atom = XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_OWNER", False);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsync num_targets = 0;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync targets[num_targets++] = targets_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync targets[num_targets++] = timestamp_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync targets[num_targets++] = rdesktop_native_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync targets[num_targets++] = rdesktop_clipboard_formats_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#ifdef USE_UNICODE_CLIPBOARD
a180a41bba1d50822df23fff0099e90b86638b89vboxsync targets[num_targets++] = format_utf8_string_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync#endif
a180a41bba1d50822df23fff0099e90b86638b89vboxsync targets[num_targets++] = format_unicode_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync targets[num_targets++] = format_string_atom;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync targets[num_targets++] = XA_STRING;
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}
a180a41bba1d50822df23fff0099e90b86638b89vboxsync
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncvoid
a180a41bba1d50822df23fff0099e90b86638b89vboxsyncxclip_deinit(void)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync{
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (XGetSelectionOwner(g_display, primary_atom) == g_wnd)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XSetSelectionOwner(g_display, primary_atom, None, acquire_time);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync if (XGetSelectionOwner(g_display, clipboard_atom) == g_wnd)
a180a41bba1d50822df23fff0099e90b86638b89vboxsync XSetSelectionOwner(g_display, clipboard_atom, None, acquire_time);
a180a41bba1d50822df23fff0099e90b86638b89vboxsync xclip_notify_change();
a180a41bba1d50822df23fff0099e90b86638b89vboxsync}