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