clipboard.c 95.9 KB
Newer Older
1
/*
2
 * X11 clipboard windows driver
3 4 5
 *
 * Copyright 1994 Martin Ayotte
 *	     1996 Alex Korobka
6
 *	     1999 Noel Borthwick
7
 *           2003 Ulrich Czekalla for CodeWeavers
8
 *
9 10 11 12 13 14 15 16 17 18 19 20
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22
 *
23 24 25 26 27 28 29 30 31 32
 * NOTES:
 *    This file contains the X specific implementation for the windows
 *    Clipboard API.
 *
 *    Wine's internal clipboard is exposed to external apps via the X
 *    selection mechanism.
 *    Currently the driver asserts ownership via two selection atoms:
 *    1. PRIMARY(XA_PRIMARY)
 *    2. CLIPBOARD
 *
Francois Gouget's avatar
Francois Gouget committed
33
 *    In our implementation, the CLIPBOARD selection takes precedence over PRIMARY,
34
 *    i.e. if a CLIPBOARD selection is available, it is used instead of PRIMARY.
Francois Gouget's avatar
Francois Gouget committed
35
 *    When Wine takes ownership of the clipboard, it takes ownership of BOTH selections.
36 37 38 39 40 41 42 43
 *    While giving up selection ownership, if the CLIPBOARD selection is lost,
 *    it will lose both PRIMARY and CLIPBOARD and empty the clipboard.
 *    However if only PRIMARY is lost, it will continue to hold the CLIPBOARD selection
 *    (leaving the clipboard cache content unaffected).
 *
 *      Every format exposed via a windows clipboard format is also exposed through
 *    a corresponding X selection target. A selection target atom is synthesized
 *    whenever a new Windows clipboard format is registered via RegisterClipboardFormat,
Francois Gouget's avatar
Francois Gouget committed
44
 *    or when a built-in format is used for the first time.
45 46 47 48 49 50 51
 *    Windows native format are exposed by prefixing the format name with "<WCF>"
 *    This allows us to uniquely identify windows native formats exposed by other
 *    running WINE apps.
 *
 *      In order to allow external applications to query WINE for supported formats,
 *    we respond to the "TARGETS" selection target. (See EVENT_SelectionRequest
 *    for implementation) We use the same mechanism to query external clients for
Francois Gouget's avatar
Francois Gouget committed
52
 *    availability of a particular format, by caching the list of available targets
53 54 55 56 57 58 59 60
 *    by using the clipboard cache's "delayed render" mechanism. If a selection client
 *    does not support the "TARGETS" selection target, we actually attempt to retrieve
 *    the format requested as a fallback mechanism.
 *
 *      Certain Windows native formats are automatically converted to X native formats
 *    and vice versa. If a native format is available in the selection, it takes
 *    precedence, in order to avoid unnecessary conversions.
 *
61
 * FIXME: global format list needs a critical section
62 63
 */

64
#include "config.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
65
#include "wine/port.h"
66

67
#include <string.h>
68
#include <stdarg.h>
69
#include <stdio.h>
70
#include <stdlib.h>
71 72 73
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
74
#include <fcntl.h>
75
#include <limits.h>
76
#include <time.h>
77
#include <assert.h>
78

79 80
#include "windef.h"
#include "winbase.h"
81
#include "wine/wingdi16.h"
82
#include "x11drv.h"
83
#include "wine/debug.h"
84 85
#include "wine/unicode.h"
#include "wine/server.h"
86

87
WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
88

89 90
#define HGDIOBJ_32(handle16)  ((HGDIOBJ)(ULONG_PTR)(handle16))

91
/* Maximum wait time for selection notify */
92 93
#define SELECTION_RETRIES 500  /* wait for .1 seconds */
#define SELECTION_WAIT    1000 /* us */
94
/* Minimum seconds that must lapse between owner queries */
95
#define OWNERQUERYLAPSETIME 1
96

97 98 99 100 101
/* Selection masks */
#define S_NOSELECTION    0
#define S_PRIMARY        1
#define S_CLIPBOARD      2

102 103 104 105 106 107 108 109 110
typedef struct
{
    HWND hWndOpen;
    HWND hWndOwner;
    HWND hWndViewer;
    UINT seqno;
    UINT flags;
} CLIPBOARDINFO, *LPCLIPBOARDINFO;

111
struct tagWINE_CLIPDATA; /* Forward */
112

113
typedef HANDLE (*DRVEXPORTFUNC)(Display *display, Window requestor, Atom aTarget, Atom rprop,
114
    struct tagWINE_CLIPDATA* lpData, LPDWORD lpBytes);
115
typedef HANDLE (*DRVIMPORTFUNC)(Display *d, Window w, Atom prop);
116 117 118 119 120 121 122 123 124 125 126 127

typedef struct tagWINE_CLIPFORMAT {
    UINT        wFormatID;
    LPCWSTR     Name;
    UINT        drvData;
    UINT        wFlags;
    DRVIMPORTFUNC  lpDrvImportFunc;
    DRVEXPORTFUNC  lpDrvExportFunc;
    struct tagWINE_CLIPFORMAT *PrevFormat;
    struct tagWINE_CLIPFORMAT *NextFormat;
} WINE_CLIPFORMAT, *LPWINE_CLIPFORMAT;

128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
typedef struct tagWINE_CLIPDATA {
    UINT        wFormatID;
    HANDLE16    hData16;
    HANDLE      hData32;
    UINT        wFlags;
    UINT        drvData;
    LPWINE_CLIPFORMAT lpFormat;
    struct tagWINE_CLIPDATA *PrevData;
    struct tagWINE_CLIPDATA *NextData;
} WINE_CLIPDATA, *LPWINE_CLIPDATA;

#define CF_FLAG_BUILTINFMT   0x0001 /* Built-in windows format */
#define CF_FLAG_UNOWNED      0x0002 /* cached data is not owned */
#define CF_FLAG_SYNTHESIZED  0x0004 /* Implicitly converted data */
#define CF_FLAG_UNICODE      0x0008 /* Data is in unicode */
143

144
static int selectionAcquired = 0;              /* Contains the current selection masks */
145
static Window selectionWindow = None;          /* The top level X window which owns the selection */
146
static Atom selectionCacheSrc = XA_PRIMARY;    /* The selection source from which the clipboard cache was filled */
147

148
void X11DRV_EmptyClipboard(BOOL keepunowned);
149
void X11DRV_EndClipboardUpdate(void);
150 151 152 153 154 155 156 157
static HANDLE X11DRV_CLIPBOARD_ImportClipboardData(Display *d, Window w, Atom prop);
static HANDLE X11DRV_CLIPBOARD_ImportEnhMetaFile(Display *d, Window w, Atom prop);
static HANDLE X11DRV_CLIPBOARD_ImportMetaFilePict(Display *d, Window w, Atom prop);
static HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(Display *d, Window w, Atom prop);
static HANDLE X11DRV_CLIPBOARD_ImportXAString(Display *d, Window w, Atom prop);
static HANDLE X11DRV_CLIPBOARD_ImportUTF8(Display *d, Window w, Atom prop);
static HANDLE X11DRV_CLIPBOARD_ImportCompoundText(Display *d, Window w, Atom prop);
static HANDLE X11DRV_CLIPBOARD_ExportClipboardData(Display *display, Window requestor, Atom aTarget,
158
    Atom rprop, LPWINE_CLIPDATA lpData, LPDWORD lpBytes);
159
static HANDLE X11DRV_CLIPBOARD_ExportString(Display *display, Window requestor, Atom aTarget,
160
    Atom rprop, LPWINE_CLIPDATA lpData, LPDWORD lpBytes);
161
static HANDLE X11DRV_CLIPBOARD_ExportXAPIXMAP(Display *display, Window requestor, Atom aTarget,
162
    Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
163
static HANDLE X11DRV_CLIPBOARD_ExportMetaFilePict(Display *display, Window requestor, Atom aTarget,
164
    Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
165
static HANDLE X11DRV_CLIPBOARD_ExportEnhMetaFile(Display *display, Window requestor, Atom aTarget,
166
    Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
Jacek Caban's avatar
Jacek Caban committed
167
static WINE_CLIPFORMAT *X11DRV_CLIPBOARD_InsertClipboardFormat(LPCWSTR FormatName, Atom prop);
168
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedText(Display *display, UINT wFormatID);
169 170
static void X11DRV_CLIPBOARD_FreeData(LPWINE_CLIPDATA lpData);
static BOOL X11DRV_CLIPBOARD_IsSelectionOwner(void);
171 172 173
static int X11DRV_CLIPBOARD_QueryAvailableData(Display *display, LPCLIPBOARDINFO lpcbinfo);
static BOOL X11DRV_CLIPBOARD_ReadSelectionData(Display *display, LPWINE_CLIPDATA lpData);
static BOOL X11DRV_CLIPBOARD_ReadProperty(Display *display, Window w, Atom prop,
174
    unsigned char** data, unsigned long* datasize);
175
static BOOL X11DRV_CLIPBOARD_RenderFormat(Display *display, LPWINE_CLIPDATA lpData);
176 177
static HANDLE X11DRV_CLIPBOARD_SerializeMetafile(INT wformat, HANDLE hdata, LPDWORD lpcbytes, BOOL out);
static BOOL X11DRV_CLIPBOARD_SynthesizeData(UINT wFormatID);
178 179 180
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedFormat(Display *display, LPWINE_CLIPDATA lpData);
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedDIB(Display *display);
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedBitmap(Display *display);
181
static void X11DRV_HandleSelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
182 183 184 185 186

/* Clipboard formats
 * WARNING: This data ordering is dependent on the WINE_CLIPFORMAT structure
 * declared in clipboard.h
 */
Jacek Caban's avatar
Jacek Caban committed
187 188 189 190 191 192 193 194 195 196 197 198
static const WCHAR wszCF_TEXT[] = {'W','C','F','_','T','E','X','T',0};
static const WCHAR wszCF_BITMAP[] = {'W','C','F','_','B','I','T','M','A','P',0};
static const WCHAR wszCF_METAFILEPICT[] = {'W','C','F','_','M','E','T','A','F','I','L','E','P','I','C','T',0};
static const WCHAR wszCF_SYLK[] = {'W','C','F','_','S','Y','L','K',0};
static const WCHAR wszCF_DIF[] = {'W','C','F','_','D','I','F',0};
static const WCHAR wszCF_TIFF[] = {'W','C','F','_','T','I','F','F',0};
static const WCHAR wszCF_OEMTEXT[] = {'W','C','F','_','O','E','M','T','E','X','T',0};
static const WCHAR wszCF_DIB[] = {'W','C','F','_','D','I','B',0};
static const WCHAR wszCF_PALETTE[] = {'W','C','F','_','P','A','L','E','T','T','E',0};
static const WCHAR wszCF_PENDATA[] = {'W','C','F','_','P','E','N','D','A','T','A',0};
static const WCHAR wszCF_RIFF[] = {'W','C','F','_','R','I','F','F',0};
static const WCHAR wszCF_WAVE[] = {'W','C','F','_','W','A','V','E',0};
199 200
static const WCHAR wszCOMPOUNDTEXT[] = {'C','O','M','P','O','U','N','D','_','T','E','X','T',0};
static const WCHAR wszUTF8STRING[] = {'U','T','F','8','_','S','T','R','I','N','G',0};
Jacek Caban's avatar
Jacek Caban committed
201 202 203 204 205 206 207 208 209 210
static const WCHAR wszCF_ENHMETAFILE[] = {'W','C','F','_','E','N','H','M','E','T','A','F','I','L','E',0};
static const WCHAR wszCF_HDROP[] = {'W','C','F','_','H','D','R','O','P',0};
static const WCHAR wszCF_LOCALE[] = {'W','C','F','_','L','O','C','A','L','E',0};
static const WCHAR wszCF_DIBV5[] = {'W','C','F','_','D','I','B','V','5',0};
static const WCHAR wszCF_OWNERDISPLAY[] = {'W','C','F','_','O','W','N','E','R','D','I','S','P','L','A','Y',0};
static const WCHAR wszCF_DSPTEXT[] = {'W','C','F','_','D','S','P','T','E','X','T',0};
static const WCHAR wszCF_DSPBITMAP[] = {'W','C','F','_','D','S','P','B','I','T','M','A','P',0};
static const WCHAR wszCF_DSPMETAFILEPICT[] = {'W','C','F','_','D','S','P','M','E','T','A','F','I','L','E','P','I','C','T',0};
static const WCHAR wszCF_DSPENHMETAFILE[] = {'W','C','F','_','D','S','P','E','N','H','M','E','T','A','F','I','L','E',0};

211
static WINE_CLIPFORMAT ClipFormats[]  =
212
{
213 214
    { CF_TEXT, wszCF_TEXT, XA_STRING, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportXAString,
        X11DRV_CLIPBOARD_ExportString, NULL, &ClipFormats[1]},
215

Jacek Caban's avatar
Jacek Caban committed
216
    { CF_BITMAP, wszCF_BITMAP, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
217
        NULL, &ClipFormats[0], &ClipFormats[2]},
218

Jacek Caban's avatar
Jacek Caban committed
219
    { CF_METAFILEPICT, wszCF_METAFILEPICT, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportMetaFilePict,
220 221
        X11DRV_CLIPBOARD_ExportMetaFilePict, &ClipFormats[1], &ClipFormats[3]},

Jacek Caban's avatar
Jacek Caban committed
222
    { CF_SYLK, wszCF_SYLK, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
223 224
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[2], &ClipFormats[4]},

Jacek Caban's avatar
Jacek Caban committed
225
    { CF_DIF, wszCF_DIF, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
226 227
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[3], &ClipFormats[5]},

Jacek Caban's avatar
Jacek Caban committed
228
    { CF_TIFF, wszCF_TIFF, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
229 230
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[4], &ClipFormats[6]},

Jacek Caban's avatar
Jacek Caban committed
231
    { CF_OEMTEXT, wszCF_OEMTEXT, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
232 233
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[5], &ClipFormats[7]},

234
    { CF_DIB, wszCF_DIB, XA_PIXMAP, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportXAPIXMAP,
Jacek Caban's avatar
Jacek Caban committed
235
        X11DRV_CLIPBOARD_ExportXAPIXMAP, &ClipFormats[6], &ClipFormats[8]},
236

Jacek Caban's avatar
Jacek Caban committed
237
    { CF_PALETTE, wszCF_PALETTE, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
238 239
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[7], &ClipFormats[9]},

Jacek Caban's avatar
Jacek Caban committed
240
    { CF_PENDATA, wszCF_PENDATA, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
241 242
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[8], &ClipFormats[10]},

Jacek Caban's avatar
Jacek Caban committed
243
    { CF_RIFF, wszCF_RIFF, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
244
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[9], &ClipFormats[11]},
245

Jacek Caban's avatar
Jacek Caban committed
246
    { CF_WAVE, wszCF_WAVE, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
247
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[10], &ClipFormats[12]},
248

249
    { CF_UNICODETEXT, wszUTF8STRING, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportUTF8,
Jacek Caban's avatar
Jacek Caban committed
250
        X11DRV_CLIPBOARD_ExportString, &ClipFormats[11], &ClipFormats[13]},
251

252 253 254 255
    /* If UTF8_STRING is not available, attempt COMPUND_TEXT */
    { CF_UNICODETEXT, wszCOMPOUNDTEXT, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportCompoundText,
        X11DRV_CLIPBOARD_ExportString, &ClipFormats[12], &ClipFormats[14]},

Jacek Caban's avatar
Jacek Caban committed
256
    { CF_ENHMETAFILE, wszCF_ENHMETAFILE, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportEnhMetaFile,
257
        X11DRV_CLIPBOARD_ExportEnhMetaFile, &ClipFormats[13], &ClipFormats[15]},
258

Jacek Caban's avatar
Jacek Caban committed
259
    { CF_HDROP, wszCF_HDROP, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
260
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[14], &ClipFormats[16]},
261

Jacek Caban's avatar
Jacek Caban committed
262
    { CF_LOCALE, wszCF_LOCALE, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
263
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[15], &ClipFormats[17]},
264

Jacek Caban's avatar
Jacek Caban committed
265
    { CF_DIBV5, wszCF_DIBV5, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
266
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[16], &ClipFormats[18]},
267

Jacek Caban's avatar
Jacek Caban committed
268
    { CF_OWNERDISPLAY, wszCF_OWNERDISPLAY, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
269
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[17], &ClipFormats[19]},
270

Jacek Caban's avatar
Jacek Caban committed
271
    { CF_DSPTEXT, wszCF_DSPTEXT, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
272
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[18], &ClipFormats[20]},
273

Jacek Caban's avatar
Jacek Caban committed
274
    { CF_DSPBITMAP, wszCF_DSPBITMAP, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
275
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[19], &ClipFormats[21]},
276

Jacek Caban's avatar
Jacek Caban committed
277
    { CF_DSPMETAFILEPICT, wszCF_DSPMETAFILEPICT, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
278
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[20], &ClipFormats[22]},
279

Jacek Caban's avatar
Jacek Caban committed
280
    { CF_DSPENHMETAFILE, wszCF_DSPENHMETAFILE, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
281
        X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[21], NULL}
282 283
};

284
#define GET_ATOM(prop)  (((prop) < FIRST_XATOM) ? (Atom)(prop) : X11DRV_Atoms[(prop) - FIRST_XATOM])
285 286

/* Maps X properties to Windows formats */
Jacek Caban's avatar
Jacek Caban committed
287 288
static const WCHAR wszRichTextFormat[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
static const WCHAR wszGIF[] = {'G','I','F',0};
289
static const WCHAR wszHTMLFormat[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
290 291
static const struct
{
Jacek Caban's avatar
Jacek Caban committed
292
    LPCWSTR lpszFormat;
293 294 295
    UINT   prop;
} PropertyFormatMap[] =
{
Jacek Caban's avatar
Jacek Caban committed
296
    { wszRichTextFormat, XATOM_text_rtf },
297 298 299
    { wszRichTextFormat, XATOM_text_richtext },
    { wszGIF, XATOM_image_gif },
    { wszHTMLFormat, XATOM_text_html },
300 301 302 303 304 305 306 307 308 309 310 311
};


/*
 * Cached clipboard data.
 */
static LPWINE_CLIPDATA ClipData = NULL;
static UINT ClipDataCount = 0;

/*
 * Clipboard sequence number
 */
312
static UINT wSeqNo = 0;
313 314

/**************************************************************************
315 316 317
 *                Internal Clipboard implementation methods
 **************************************************************************/

318 319
static Window thread_selection_wnd(void)
{
320 321
    struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
    Window w = thread_data->selection_wnd;
322 323 324

    if (!w)
    {
325 326 327
        XSetWindowAttributes attr;

        attr.event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
328
                       ButtonPressMask | ButtonReleaseMask | EnterWindowMask | PropertyChangeMask);
329

330
        wine_tsx11_lock();
331
        w = XCreateWindow(thread_data->display, root_window, 0, 0, 1, 1, 0, screen_depth,
332
                          InputOutput, CopyFromParent, CWEventMask, &attr);
333 334 335
        wine_tsx11_unlock();

        if (w)
336
            thread_data->selection_wnd = w;
337 338 339 340 341 342 343
        else
            FIXME("Failed to create window. Fetching selection data will fail.\n");
    }

    return w;
}

344 345
/**************************************************************************
 *		X11DRV_InitClipboard
346
 */
347
void X11DRV_InitClipboard(void)
348
{
349
    UINT i;
350

351 352
    /* Register known mapping between window formats and X properties */
    for (i = 0; i < sizeof(PropertyFormatMap)/sizeof(PropertyFormatMap[0]); i++)
353
        X11DRV_CLIPBOARD_InsertClipboardFormat(PropertyFormatMap[i].lpszFormat, GET_ATOM(PropertyFormatMap[i].prop));
354 355 356 357 358 359 360 361 362 363 364
}


/**************************************************************************
 *                intern_atoms
 *
 * Intern atoms for formats that don't have one yet.
 */
static void intern_atoms(void)
{
    LPWINE_CLIPFORMAT format;
Jacek Caban's avatar
Jacek Caban committed
365
    int i, count, len;
366 367
    char **names;
    Atom *atoms;
368
    Display *display;
369 370 371 372 373

    for (format = ClipFormats, count = 0; format; format = format->NextFormat)
        if (!format->drvData) count++;
    if (!count) return;

374 375
    display = thread_init_display();

376 377 378
    names = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*names) );
    atoms = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*atoms) );

Jacek Caban's avatar
Jacek Caban committed
379 380
    for (format = ClipFormats, i = 0; format; format = format->NextFormat) {
        if (!format->drvData) {
381 382 383
            len = WideCharToMultiByte(CP_UNIXCP, 0, format->Name, -1, NULL, 0, NULL, NULL);
            names[i] = HeapAlloc(GetProcessHeap(), 0, len);
            WideCharToMultiByte(CP_UNIXCP, 0, format->Name, -1, names[i++], len, NULL, NULL);
Jacek Caban's avatar
Jacek Caban committed
384 385
        }
    }
386 387

    wine_tsx11_lock();
388
    XInternAtoms( display, names, count, False, atoms );
389
    wine_tsx11_unlock();
390

Jacek Caban's avatar
Jacek Caban committed
391 392 393 394 395 396
    for (format = ClipFormats, i = 0; format; format = format->NextFormat) {
        if (!format->drvData) {
            HeapFree(GetProcessHeap(), 0, names[i]);
            format->drvData = atoms[i++];
        }
    }
397

398 399 400 401 402 403 404 405 406 407
    HeapFree( GetProcessHeap(), 0, names );
    HeapFree( GetProcessHeap(), 0, atoms );
}


/**************************************************************************
 *		register_format
 *
 * Register a custom X clipboard format.
 */
Jacek Caban's avatar
Jacek Caban committed
408
static WINE_CLIPFORMAT *register_format( LPCWSTR FormatName, Atom prop )
409 410 411
{
    LPWINE_CLIPFORMAT lpFormat = ClipFormats;

Jacek Caban's avatar
Jacek Caban committed
412
    TRACE("%s\n", debugstr_w(FormatName));
413 414 415 416

    /* walk format chain to see if it's already registered */
    while (lpFormat)
    {
Jacek Caban's avatar
Jacek Caban committed
417 418
	if (CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lpFormat->Name, -1, FormatName, -1) == CSTR_EQUAL
	    && (lpFormat->wFlags & CF_FLAG_BUILTINFMT) == 0)
419
	     return lpFormat;
420 421 422
	lpFormat = lpFormat->NextFormat;
    }

423
    return X11DRV_CLIPBOARD_InsertClipboardFormat(FormatName, prop);
424 425 426 427 428 429
}


/**************************************************************************
 *                X11DRV_CLIPBOARD_LookupFormat
 */
430
static LPWINE_CLIPFORMAT X11DRV_CLIPBOARD_LookupFormat(WORD wID)
431 432 433 434 435 436 437 438 439 440
{
    LPWINE_CLIPFORMAT lpFormat = ClipFormats;

    while(lpFormat)
    {
        if (lpFormat->wFormatID == wID) 
            break;

	lpFormat = lpFormat->NextFormat;
    }
441
    if (lpFormat && !lpFormat->drvData) intern_atoms();
442 443 444 445 446 447 448
    return lpFormat;
}


/**************************************************************************
 *                X11DRV_CLIPBOARD_LookupProperty
 */
449
static LPWINE_CLIPFORMAT X11DRV_CLIPBOARD_LookupProperty(LPWINE_CLIPFORMAT current, UINT drvData)
450
{
451
    for (;;)
452
    {
453 454
        LPWINE_CLIPFORMAT lpFormat = ClipFormats;
        BOOL need_intern = FALSE;
455

456 457 458
        if (current)
            lpFormat = current->NextFormat;

459 460 461 462 463 464 465 466 467
        while(lpFormat)
        {
            if (lpFormat->drvData == drvData) return lpFormat;
            if (!lpFormat->drvData) need_intern = TRUE;
            lpFormat = lpFormat->NextFormat;
        }
        if (!need_intern) return NULL;
        intern_atoms();
        /* restart the search for the new atoms */
468 469 470 471 472 473 474
    }
}


/**************************************************************************
 *               X11DRV_CLIPBOARD_LookupData
 */
475
static LPWINE_CLIPDATA X11DRV_CLIPBOARD_LookupData(DWORD wID)
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
{
    LPWINE_CLIPDATA lpData = ClipData;

    if (lpData)
    {
        do
        {
            if (lpData->wFormatID == wID) 
                break;

	    lpData = lpData->NextData;
        }
        while(lpData != ClipData);

        if (lpData->wFormatID != wID)
            lpData = NULL;
    }

    return lpData;
}


/**************************************************************************
 *		InsertClipboardFormat
 */
Jacek Caban's avatar
Jacek Caban committed
501
static WINE_CLIPFORMAT *X11DRV_CLIPBOARD_InsertClipboardFormat(LPCWSTR FormatName, Atom prop)
502 503 504
{
    LPWINE_CLIPFORMAT lpFormat;
    LPWINE_CLIPFORMAT lpNewFormat;
505 506
    LPWSTR new_name;

507
    /* allocate storage for new format entry */
508
    lpNewFormat = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPFORMAT));
509 510 511 512

    if(lpNewFormat == NULL) 
    {
        WARN("No more memory for a new format!\n");
513
        return NULL;
514 515
    }

516
    if (!(new_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(FormatName)+1)*sizeof(WCHAR))))
517 518 519
    {
        WARN("No more memory for the new format name!\n");
        HeapFree(GetProcessHeap(), 0, lpNewFormat);
520
        return NULL;
521 522
    }

523
    lpNewFormat->Name = strcpyW(new_name, FormatName);
524
    lpNewFormat->wFlags = 0;
Jacek Caban's avatar
Jacek Caban committed
525
    lpNewFormat->wFormatID = GlobalAddAtomW(lpNewFormat->Name);
526
    lpNewFormat->drvData = prop;
527 528 529 530 531 532 533 534 535 536 537 538 539
    lpNewFormat->lpDrvImportFunc = X11DRV_CLIPBOARD_ImportClipboardData;
    lpNewFormat->lpDrvExportFunc = X11DRV_CLIPBOARD_ExportClipboardData;

    /* Link Format */
    lpFormat = ClipFormats;

    while(lpFormat->NextFormat) /* Move to last entry */
	lpFormat = lpFormat->NextFormat;

    lpNewFormat->NextFormat = NULL;
    lpFormat->NextFormat = lpNewFormat;
    lpNewFormat->PrevFormat = lpFormat;

540
    TRACE("Registering format(%d): %s drvData %d\n",
Jacek Caban's avatar
Jacek Caban committed
541
        lpNewFormat->wFormatID, debugstr_w(FormatName), lpNewFormat->drvData);
542

543
    return lpNewFormat;
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
}




/**************************************************************************
 *                      X11DRV_CLIPBOARD_GetClipboardInfo
 */
static BOOL X11DRV_CLIPBOARD_GetClipboardInfo(LPCLIPBOARDINFO cbInfo)
{
    BOOL bRet = FALSE;

    SERVER_START_REQ( set_clipboard_info )
    {
        req->flags = 0;

        if (wine_server_call_err( req ))
        {
            ERR("Failed to get clipboard owner.\n");
        }
564
        else
565 566 567 568 569 570 571 572 573
        {
            cbInfo->hWndOpen = reply->old_clipboard;
            cbInfo->hWndOwner = reply->old_owner;
            cbInfo->hWndViewer = reply->old_viewer;
            cbInfo->seqno = reply->seqno;
            cbInfo->flags = reply->flags;

            bRet = TRUE;
        }
574
    }
575
    SERVER_END_REQ;
576

577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
    return bRet;
}


/**************************************************************************
 *	X11DRV_CLIPBOARD_ReleaseOwnership
 */
static BOOL X11DRV_CLIPBOARD_ReleaseOwnership(void)
{
    BOOL bRet = FALSE;

    SERVER_START_REQ( set_clipboard_info )
    {
        req->flags = SET_CB_RELOWNER | SET_CB_SEQNO;

        if (wine_server_call_err( req ))
        {
            ERR("Failed to set clipboard.\n");
        }
        else
        {
            bRet = TRUE;
        }
    }
    SERVER_END_REQ;

    return bRet;
604
}
605

606 607


608
/**************************************************************************
609
 *                      X11DRV_CLIPBOARD_InsertClipboardData
610
 *
611
 * Caller *must* have the clipboard open and be the owner.
612
 */
613 614
static BOOL X11DRV_CLIPBOARD_InsertClipboardData(UINT wFormatID, HANDLE16 hData16,
    HANDLE hData32, DWORD flags, LPWINE_CLIPFORMAT lpFormat, BOOL override)
615
{
616
    LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(wFormatID);
617

618
    TRACE("format=%d lpData=%p hData16=%08x hData32=%p flags=0x%08x lpFormat=%p override=%d\n",
619 620 621 622
        wFormatID, lpData, hData16, hData32, flags, lpFormat, override);

    if (lpData && !override)
        return TRUE;
623 624

    if (lpData)
625
    {
626
        X11DRV_CLIPBOARD_FreeData(lpData);
627

628 629 630 631 632
        lpData->hData16 = hData16;  /* 0 is legal, see WM_RENDERFORMAT */
        lpData->hData32 = hData32;
    }
    else
    {
633
        lpData = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPDATA));
634

635
        lpData->wFormatID = wFormatID;
636 637
        lpData->hData16 = hData16;  /* 0 is legal, see WM_RENDERFORMAT */
        lpData->hData32 = hData32;
638
        lpData->lpFormat = lpFormat;
639
        lpData->drvData = 0;
640

641
        if (ClipData)
642
        {
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
            LPWINE_CLIPDATA lpPrevData = ClipData->PrevData;

            lpData->PrevData = lpPrevData;
            lpData->NextData = ClipData;

            lpPrevData->NextData = lpData;
            ClipData->PrevData = lpData;
        }
        else
        {
            lpData->NextData = lpData;
            lpData->PrevData = lpData;
            ClipData = lpData;
        }

658
        ClipDataCount++;
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
    }

    lpData->wFlags = flags;

    return TRUE;
}


/**************************************************************************
 *			X11DRV_CLIPBOARD_FreeData
 *
 * Free clipboard data handle.
 */
static void X11DRV_CLIPBOARD_FreeData(LPWINE_CLIPDATA lpData)
{
    TRACE("%d\n", lpData->wFormatID);

    if ((lpData->wFormatID >= CF_GDIOBJFIRST &&
        lpData->wFormatID <= CF_GDIOBJLAST) || 
        lpData->wFormatID == CF_BITMAP || 
        lpData->wFormatID == CF_DIB || 
        lpData->wFormatID == CF_PALETTE)
    {
      if (lpData->hData32)
	DeleteObject(lpData->hData32);

      if (lpData->hData16)
	DeleteObject(HGDIOBJ_32(lpData->hData16));
687 688 689

      if ((lpData->wFormatID == CF_DIB) && lpData->drvData)
          XFreePixmap(gdi_display, lpData->drvData);
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
    }
    else if (lpData->wFormatID == CF_METAFILEPICT)
    {
      if (lpData->hData32)
      {
        DeleteMetaFile(((METAFILEPICT *)GlobalLock( lpData->hData32 ))->hMF );
        GlobalFree(lpData->hData32);

	if (lpData->hData16)
	  /* HMETAFILE16 and HMETAFILE32 are apparently the same thing,
	     and a shallow copy is enough to share a METAFILEPICT
	     structure between 16bit and 32bit clipboards.  The MetaFile
	     should of course only be deleted once. */
	  GlobalFree16(lpData->hData16);
      }

      if (lpData->hData16)
      {
708
        METAFILEPICT16* lpMetaPict = GlobalLock16(lpData->hData16);
709 710 711

        if (lpMetaPict)
        {
712 713 714
            /* To delete 16-bit meta file, we just need to free the associated
               handle. See DeleteMetaFile16() in dlls/gdi/metafile.c. */
            GlobalFree16(lpMetaPict->hMF);
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737
            lpMetaPict->hMF = 0;
        }

	GlobalFree16(lpData->hData16);
      }
    }
    else if (lpData->wFormatID == CF_ENHMETAFILE)
    {
        if (lpData->hData32)
            DeleteEnhMetaFile(lpData->hData32);
    }
    else if (lpData->wFormatID < CF_PRIVATEFIRST ||
             lpData->wFormatID > CF_PRIVATELAST)
    {
      if (lpData->hData32)
        GlobalFree(lpData->hData32);

      if (lpData->hData16)
	GlobalFree16(lpData->hData16);
    }

    lpData->hData16 = 0;
    lpData->hData32 = 0;
738
    lpData->drvData = 0;
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
}


/**************************************************************************
 *			X11DRV_CLIPBOARD_UpdateCache
 */
static BOOL X11DRV_CLIPBOARD_UpdateCache(LPCLIPBOARDINFO lpcbinfo)
{
    BOOL bret = TRUE;

    if (!X11DRV_CLIPBOARD_IsSelectionOwner())
    {
        if (!X11DRV_CLIPBOARD_GetClipboardInfo(lpcbinfo))
        {
            ERR("Failed to retrieve clipboard information.\n");
            bret = FALSE;
        }
        else if (wSeqNo < lpcbinfo->seqno)
        {
758
            X11DRV_EmptyClipboard(TRUE);
759

760
            if (X11DRV_CLIPBOARD_QueryAvailableData(thread_init_display(), lpcbinfo) < 0)
761 762 763 764 765
            {
                ERR("Failed to cache clipboard data owned by another process.\n");
                bret = FALSE;
            }
            else
766
            {
767
                X11DRV_EndClipboardUpdate();
768
            }
769 770

            wSeqNo = lpcbinfo->seqno;
771
        }
772 773 774 775
    }

    return bret;
}
776

777 778 779 780

/**************************************************************************
 *			X11DRV_CLIPBOARD_RenderFormat
 */
781
static BOOL X11DRV_CLIPBOARD_RenderFormat(Display *display, LPWINE_CLIPDATA lpData)
782 783 784
{
    BOOL bret = TRUE;

785 786
    TRACE(" 0x%04x hData32(%p) hData16(0x%08x)\n",
        lpData->wFormatID, lpData->hData32, lpData->hData16);
787 788 789 790

    if (lpData->hData32 || lpData->hData16)
        return bret; /* Already rendered */

791
    if (lpData->wFlags & CF_FLAG_SYNTHESIZED)
792
        bret = X11DRV_CLIPBOARD_RenderSynthesizedFormat(display, lpData);
793
    else if (!X11DRV_CLIPBOARD_IsSelectionOwner())
794
    {
795
        if (!X11DRV_CLIPBOARD_ReadSelectionData(display, lpData))
796
        {
797 798 799 800 801 802 803
            ERR("Failed to cache clipboard data owned by another process. Format=%d\n", 
                lpData->wFormatID);
            bret = FALSE;
        }
    }
    else
    {
804
        CLIPBOARDINFO cbInfo;
805

806
        if (X11DRV_CLIPBOARD_GetClipboardInfo(&cbInfo) && cbInfo.hWndOwner)
807 808 809 810 811 812 813 814
        {
            /* Send a WM_RENDERFORMAT message to notify the owner to render the
             * data requested into the clipboard.
             */
            TRACE("Sending WM_RENDERFORMAT message to hwnd(%p)\n", cbInfo.hWndOwner);
            SendMessageW(cbInfo.hWndOwner, WM_RENDERFORMAT, (WPARAM)lpData->wFormatID, 0);

            if (!lpData->hData32 && !lpData->hData16)
815 816
                bret = FALSE;
        }
817 818 819 820 821 822
        else
        {
            ERR("hWndClipOwner is lost!\n");
            bret = FALSE;
        }
    }
823

824 825
    return bret;
}
826

827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884

/**************************************************************************
 *                      CLIPBOARD_ConvertText
 * Returns number of required/converted characters - not bytes!
 */
static INT CLIPBOARD_ConvertText(WORD src_fmt, void const *src, INT src_size,
				 WORD dst_fmt, void *dst, INT dst_size)
{
    UINT cp;

    if(src_fmt == CF_UNICODETEXT)
    {
	switch(dst_fmt)
	{
	case CF_TEXT:
	    cp = CP_ACP;
	    break;
	case CF_OEMTEXT:
	    cp = CP_OEMCP;
	    break;
	default:
	    return 0;
	}
	return WideCharToMultiByte(cp, 0, src, src_size, dst, dst_size, NULL, NULL);
    }

    if(dst_fmt == CF_UNICODETEXT)
    {
	switch(src_fmt)
	{
	case CF_TEXT:
	    cp = CP_ACP;
	    break;
	case CF_OEMTEXT:
	    cp = CP_OEMCP;
	    break;
	default:
	    return 0;
	}
	return MultiByteToWideChar(cp, 0, src, src_size, dst, dst_size);
    }

    if(!dst_size) return src_size;

    if(dst_size > src_size) dst_size = src_size;

    if(src_fmt == CF_TEXT )
	CharToOemBuffA(src, dst, dst_size);
    else
	OemToCharBuffA(src, dst, dst_size);

    return dst_size;
}


/**************************************************************************
 *                      X11DRV_CLIPBOARD_RenderSynthesizedFormat
 */
885
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedFormat(Display *display, LPWINE_CLIPDATA lpData)
886 887 888
{
    BOOL bret = FALSE;

889 890
    TRACE("\n");

891 892 893 894 895
    if (lpData->wFlags & CF_FLAG_SYNTHESIZED)
    {
        UINT wFormatID = lpData->wFormatID;

        if (wFormatID == CF_UNICODETEXT || wFormatID == CF_TEXT || wFormatID == CF_OEMTEXT)
896
            bret = X11DRV_CLIPBOARD_RenderSynthesizedText(display, wFormatID);
897 898 899 900 901
        else 
        {
            switch (wFormatID)
	    {
                case CF_DIB:
902
                    bret = X11DRV_CLIPBOARD_RenderSynthesizedDIB( display );
903 904
                    break;

905
                case CF_BITMAP:
906
                    bret = X11DRV_CLIPBOARD_RenderSynthesizedBitmap( display );
907 908 909 910
                    break;

                case CF_ENHMETAFILE:
                case CF_METAFILEPICT:
911 912 913 914 915 916 917
		    FIXME("Synthesizing wFormatID(0x%08x) not implemented\n", wFormatID);
                    break;

                default:
		    FIXME("Called to synthesize unknown format\n");
                    break;
            }
918
        }
919 920 921 922 923 924 925 926 927

        lpData->wFlags &= ~CF_FLAG_SYNTHESIZED;
    }

    return bret;
}


/**************************************************************************
928
 *                      X11DRV_CLIPBOARD_RenderSynthesizedText
929
 *
930
 * Renders synthesized text
931
 */
932
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedText(Display *display, UINT wFormatID)
933 934 935 936 937 938 939 940 941
{
    LPCSTR lpstrS;
    LPSTR  lpstrT;
    HANDLE hData32;
    INT src_chars, dst_chars, alloc_size;
    LPWINE_CLIPDATA lpSource = NULL;

    TRACE(" %d\n", wFormatID);

942 943
    if ((lpSource = X11DRV_CLIPBOARD_LookupData(wFormatID)) &&
        lpSource->hData32)
944 945
        return TRUE;

946 947 948
    /* Look for rendered source or non-synthesized source */
    if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_UNICODETEXT)) &&
        (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData32))
949 950 951
    {
        TRACE("UNICODETEXT -> %d\n", wFormatID);
    }
952 953
    else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_TEXT)) &&
        (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData32))
954 955 956
    {
        TRACE("TEXT -> %d\n", wFormatID);
    }
957 958
    else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_OEMTEXT)) &&
        (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData32))
959 960 961 962
    {
        TRACE("OEMTEXT -> %d\n", wFormatID);
    }

963 964
    if (!lpSource || (lpSource->wFlags & CF_FLAG_SYNTHESIZED &&
        !lpSource->hData32))
965 966
        return FALSE;

967
    /* Ask the clipboard owner to render the source text if necessary */
968
    if (!lpSource->hData32 && !X11DRV_CLIPBOARD_RenderFormat(display, lpSource))
969 970 971 972
        return FALSE;

    if (lpSource->hData32)
    {
973
        lpstrS = GlobalLock(lpSource->hData32);
974 975 976
    }
    else
    {
977
        lpstrS = GlobalLock16(lpSource->hData16);
978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
    }

    if (!lpstrS)
        return FALSE;

    /* Text always NULL terminated */
    if(lpSource->wFormatID == CF_UNICODETEXT)
        src_chars = strlenW((LPCWSTR)lpstrS) + 1;
    else
        src_chars = strlen(lpstrS) + 1;

    /* Calculate number of characters in the destination buffer */
    dst_chars = CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, 
        src_chars, wFormatID, NULL, 0);

    if (!dst_chars)
        return FALSE;

    TRACE("Converting from '%d' to '%d', %i chars\n",
    	lpSource->wFormatID, wFormatID, src_chars);

    /* Convert characters to bytes */
    if(wFormatID == CF_UNICODETEXT)
        alloc_size = dst_chars * sizeof(WCHAR);
    else
        alloc_size = dst_chars;

    hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | 
        GMEM_DDESHARE, alloc_size);

1008
    lpstrT = GlobalLock(hData32);
1009 1010 1011 1012 1013 1014

    if (lpstrT)
    {
        CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, src_chars,
            wFormatID, lpstrT, dst_chars);
        GlobalUnlock(hData32);
1015
    }
1016

1017 1018 1019 1020 1021
    /* Unlock source */
    if (lpSource->hData32)
        GlobalUnlock(lpSource->hData32);
    else
        GlobalUnlock16(lpSource->hData16);
1022

1023
    return X11DRV_CLIPBOARD_InsertClipboardData(wFormatID, 0, hData32, 0, NULL, TRUE);
1024
}
1025

1026

1027 1028 1029 1030 1031
/**************************************************************************
 *                      X11DRV_CLIPBOARD_RenderSynthesizedDIB
 *
 * Renders synthesized DIB
 */
1032
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedDIB(Display *display)
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
{
    BOOL bret = FALSE;
    LPWINE_CLIPDATA lpSource = NULL;

    TRACE("\n");

    if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIB)) && lpSource->hData32)
    {
        bret = TRUE;
    }
    /* If we have a bitmap and it's not synthesized or it has been rendered */
    else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_BITMAP)) &&
        (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData32))
    {
        /* Render source if required */
1048
        if (lpSource->hData32 || X11DRV_CLIPBOARD_RenderFormat(display, lpSource))
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
        {
            HDC hdc;
            HGLOBAL hData32;

            hdc = GetDC(NULL);
            hData32 = X11DRV_DIB_CreateDIBFromBitmap(hdc, lpSource->hData32);
            ReleaseDC(NULL, hdc);

            if (hData32)
            {
1059
                X11DRV_CLIPBOARD_InsertClipboardData(CF_DIB, 0, hData32, 0, NULL, TRUE);
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
                bret = TRUE;
            }
        }
    }

    return bret;
}


/**************************************************************************
 *                      X11DRV_CLIPBOARD_RenderSynthesizedBitmap
 *
 * Renders synthesized bitmap
 */
1074
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedBitmap(Display *display)
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089
{
    BOOL bret = FALSE;
    LPWINE_CLIPDATA lpSource = NULL;

    TRACE("\n");

    if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_BITMAP)) && lpSource->hData32)
    {
        bret = TRUE;
    }
    /* If we have a dib and it's not synthesized or it has been rendered */
    else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIB)) &&
        (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData32))
    {
        /* Render source if required */
1090
        if (lpSource->hData32 || X11DRV_CLIPBOARD_RenderFormat(display, lpSource))
1091 1092 1093 1094 1095 1096 1097
        {
            HDC hdc;
            HBITMAP hData32;
            unsigned int offset;
            LPBITMAPINFOHEADER lpbmih;

            hdc = GetDC(NULL);
1098
            lpbmih = GlobalLock(lpSource->hData32);
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111

            offset = sizeof(BITMAPINFOHEADER)
                  + ((lpbmih->biBitCount <= 8) ? (sizeof(RGBQUAD) *
                    (1 << lpbmih->biBitCount)) : 0);

            hData32 = CreateDIBitmap(hdc, lpbmih, CBM_INIT, (LPBYTE)lpbmih +
                offset, (LPBITMAPINFO) lpbmih, DIB_RGB_COLORS);

            GlobalUnlock(lpSource->hData32);
            ReleaseDC(NULL, hdc);

            if (hData32)
            {
1112
                X11DRV_CLIPBOARD_InsertClipboardData(CF_BITMAP, 0, hData32, 0, NULL, TRUE);
1113 1114 1115 1116 1117 1118 1119 1120 1121
                bret = TRUE;
            }
        }
    }

    return bret;
}


1122
/**************************************************************************
1123
 *		X11DRV_CLIPBOARD_ImportXAString
1124
 *
1125 1126
 *  Import XA_STRING, converting the string to CF_TEXT.
 */
1127
HANDLE X11DRV_CLIPBOARD_ImportXAString(Display *display, Window w, Atom prop)
1128 1129
{
    LPBYTE lpdata;
1130
    unsigned long cbytes;
1131
    LPSTR lpstr;
1132
    unsigned long i, inlcount = 0;
1133 1134
    HANDLE hText = 0;

1135
    if (!X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168
        return 0;

    for (i = 0; i <= cbytes; i++)
    {
        if (lpdata[i] == '\n')
            inlcount++;
    }

    if ((hText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cbytes + inlcount + 1)))
    {
        lpstr = GlobalLock(hText);

        for (i = 0, inlcount = 0; i <= cbytes; i++)
        {
            if (lpdata[i] == '\n')
                lpstr[inlcount++] = '\r';

            lpstr[inlcount++] = lpdata[i];
        }

        GlobalUnlock(hText);
    }

    /* Free the retrieved property data */
    HeapFree(GetProcessHeap(), 0, lpdata);

    return hText;
}


/**************************************************************************
 *		X11DRV_CLIPBOARD_ImportUTF8
 *
1169
 *  Import XA_STRING, converting the string to CF_UNICODE.
1170
 */
1171
HANDLE X11DRV_CLIPBOARD_ImportUTF8(Display *display, Window w, Atom prop)
1172
{
1173
    LPBYTE lpdata;
1174
    unsigned long cbytes;
1175
    LPSTR lpstr;
1176
    unsigned long i, inlcount = 0;
1177
    HANDLE hUnicodeText = 0;
1178

1179
    if (!X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1180 1181 1182
        return 0;

    for (i = 0; i <= cbytes; i++)
1183 1184 1185 1186
    {
        if (lpdata[i] == '\n')
            inlcount++;
    }
1187

1188
    if ((lpstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbytes + inlcount + 1)))
1189 1190 1191
    {
        UINT count;

1192
        for (i = 0, inlcount = 0; i <= cbytes; i++)
1193 1194 1195 1196 1197 1198 1199
        {
            if (lpdata[i] == '\n')
                lpstr[inlcount++] = '\r';

            lpstr[inlcount++] = lpdata[i];
        }

1200 1201
        count = MultiByteToWideChar(CP_UTF8, 0, lpstr, -1, NULL, 0);
        hUnicodeText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, count * sizeof(WCHAR));
1202

1203 1204
        if (hUnicodeText)
        {
1205
            WCHAR *textW = GlobalLock(hUnicodeText);
1206
            MultiByteToWideChar(CP_UTF8, 0, lpstr, -1, textW, count);
1207 1208 1209 1210 1211 1212
            GlobalUnlock(hUnicodeText);
        }

        HeapFree(GetProcessHeap(), 0, lpstr);
    }

1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
    /* Free the retrieved property data */
    HeapFree(GetProcessHeap(), 0, lpdata);

    return hUnicodeText;
}


/**************************************************************************
 *		X11DRV_CLIPBOARD_ImportCompoundText
 *
 *  Import COMPOUND_TEXT to CF_UNICODE
 */
1225
static HANDLE X11DRV_CLIPBOARD_ImportCompoundText(Display *display, Window w, Atom prop)
1226
{
1227
    int i, j, ret;
1228 1229 1230 1231 1232 1233
    char** srcstr;
    int count, lcount;
    int srclen, destlen;
    HANDLE hUnicodeText;
    XTextProperty txtprop;

1234
    if (!X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &txtprop.value, &txtprop.nitems))
1235 1236 1237 1238
    {
        return 0;
    }

1239 1240 1241
    txtprop.encoding = x11drv_atom(COMPOUND_TEXT);
    txtprop.format = 8;
    wine_tsx11_lock();
1242
    ret = XmbTextPropertyToTextList(display, &txtprop, &srcstr, &count);
1243
    wine_tsx11_unlock();
1244
    HeapFree(GetProcessHeap(), 0, txtprop.value);
1245
    if (ret != Success || !count) return 0;
1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283

    TRACE("Importing %d line(s)\n", count);

    /* Compute number of lines */
    srclen = strlen(srcstr[0]);
    for (i = 0, lcount = 0; i <= srclen; i++)
    {
        if (srcstr[0][i] == '\n')
            lcount++;
    }

    destlen = MultiByteToWideChar(CP_UNIXCP, 0, srcstr[0], -1, NULL, 0);

    TRACE("lcount = %d, destlen=%d, srcstr %s\n", lcount, destlen, srcstr[0]);

    if ((hUnicodeText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (destlen + lcount + 1) * sizeof(WCHAR))))
    {
        WCHAR *deststr = GlobalLock(hUnicodeText);
        MultiByteToWideChar(CP_UNIXCP, 0, srcstr[0], -1, deststr, destlen);

        if (lcount)
        {
            for (i = destlen - 1, j = destlen + lcount - 1; i >= 0; i--, j--)
            {
                deststr[j] = deststr[i];

                if (deststr[i] == '\n')
                    deststr[--j] = '\r';
            }
        }

        GlobalUnlock(hUnicodeText);
    }

    wine_tsx11_lock();
    XFreeStringList(srcstr);
    wine_tsx11_unlock();

1284
    return hUnicodeText;
1285
}
1286

1287

1288
/**************************************************************************
1289 1290 1291
 *		X11DRV_CLIPBOARD_ImportXAPIXMAP
 *
 *  Import XA_PIXMAP, converting the image to CF_DIB.
1292
 */
1293
HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(Display *display, Window w, Atom prop)
1294
{
1295 1296 1297
    HWND hwnd;
    HDC hdc;
    LPBYTE lpdata;
1298
    unsigned long cbytes;
1299 1300 1301
    Pixmap *pPixmap;
    HANDLE hClipData = 0;

1302
    if (X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1303 1304
    {
        pPixmap = (Pixmap *) lpdata;
1305

1306 1307
        hwnd = GetOpenClipboardWindow();
        hdc = GetDC(hwnd);
1308

1309 1310 1311 1312 1313 1314
        hClipData = X11DRV_DIB_CreateDIBFromPixmap(*pPixmap, hdc);
        ReleaseDC(hwnd, hdc);

        /* Free the retrieved property data */
        HeapFree(GetProcessHeap(), 0, lpdata);
    }
1315

1316
    return hClipData;
1317 1318 1319 1320 1321 1322 1323 1324
}


/**************************************************************************
 *		X11DRV_CLIPBOARD_ImportMetaFilePict
 *
 *  Import MetaFilePict.
 */
1325
HANDLE X11DRV_CLIPBOARD_ImportMetaFilePict(Display *display, Window w, Atom prop)
1326
{
1327
    LPBYTE lpdata;
1328
    unsigned long cbytes;
1329 1330
    HANDLE hClipData = 0;

1331
    if (X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1332 1333
    {
        if (cbytes)
1334
            hClipData = X11DRV_CLIPBOARD_SerializeMetafile(CF_METAFILEPICT, lpdata, (LPDWORD)&cbytes, FALSE);
1335 1336 1337 1338 1339 1340

        /* Free the retrieved property data */
        HeapFree(GetProcessHeap(), 0, lpdata);
    }

    return hClipData;
1341 1342 1343 1344 1345 1346 1347 1348
}


/**************************************************************************
 *		X11DRV_ImportEnhMetaFile
 *
 *  Import EnhMetaFile.
 */
1349
HANDLE X11DRV_CLIPBOARD_ImportEnhMetaFile(Display *display, Window w, Atom prop)
1350
{
1351
    LPBYTE lpdata;
1352
    unsigned long cbytes;
1353 1354
    HANDLE hClipData = 0;

1355
    if (X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1356 1357
    {
        if (cbytes)
1358
            hClipData = X11DRV_CLIPBOARD_SerializeMetafile(CF_ENHMETAFILE, lpdata, (LPDWORD)&cbytes, FALSE);
1359 1360 1361 1362 1363 1364

        /* Free the retrieved property data */
        HeapFree(GetProcessHeap(), 0, lpdata);
    }

    return hClipData;
1365 1366 1367 1368 1369 1370 1371 1372
}


/**************************************************************************
 *		X11DRV_ImportClipbordaData
 *
 *  Generic import clipboard data routine.
 */
1373
HANDLE X11DRV_CLIPBOARD_ImportClipboardData(Display *display, Window w, Atom prop)
1374 1375
{
    LPVOID lpClipData;
1376
    LPBYTE lpdata;
1377
    unsigned long cbytes;
1378 1379
    HANDLE hClipData = 0;

1380
    if (X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1381
    {
1382
        if (cbytes)
1383
        {
1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398
            /* Turn on the DDESHARE flag to enable shared 32 bit memory */
            hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cbytes);
            if (hClipData == 0)
                return NULL;

            if ((lpClipData = GlobalLock(hClipData)))
            {
                memcpy(lpClipData, lpdata, cbytes);
                GlobalUnlock(hClipData);
            }
            else
            {
                GlobalFree(hClipData);
                hClipData = 0;
            }
1399
        }
1400 1401 1402

        /* Free the retrieved property data */
        HeapFree(GetProcessHeap(), 0, lpdata);
1403 1404 1405 1406 1407 1408 1409
    }

    return hClipData;
}


/**************************************************************************
1410
 		X11DRV_CLIPBOARD_ExportClipboardData
1411 1412 1413
 *
 *  Generic export clipboard data routine.
 */
1414 1415
HANDLE X11DRV_CLIPBOARD_ExportClipboardData(Display *display, Window requestor, Atom aTarget,
                                            Atom rprop, LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
1416 1417
{
    LPVOID lpClipData;
1418
    UINT datasize = 0;
1419 1420 1421 1422
    HANDLE hClipData = 0;

    *lpBytes = 0; /* Assume failure */

1423
    if (!X11DRV_CLIPBOARD_RenderFormat(display, lpData))
1424 1425 1426
        ERR("Failed to export %d format\n", lpData->wFormatID);
    else
    {
1427
        datasize = GlobalSize(lpData->hData32);
1428

1429
        hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, datasize);
1430
        if (hClipData == 0) return NULL;
1431 1432 1433 1434 1435

        if ((lpClipData = GlobalLock(hClipData)))
        {
            LPVOID lpdata = GlobalLock(lpData->hData32);

1436 1437
            memcpy(lpClipData, lpdata, datasize);
            *lpBytes = datasize;
1438

1439 1440
            GlobalUnlock(lpData->hData32);
            GlobalUnlock(hClipData);
1441 1442 1443
        } else {
            GlobalFree(hClipData);
            hClipData = 0;
1444
        }
1445
    }
1446

1447 1448
    return hClipData;
}
1449 1450


1451 1452 1453
/**************************************************************************
 *		X11DRV_CLIPBOARD_ExportXAString
 *
1454
 *  Export CF_TEXT converting the string to XA_STRING.
1455
 *  Helper function for X11DRV_CLIPBOARD_ExportString.
1456
 */
1457
static HANDLE X11DRV_CLIPBOARD_ExportXAString(LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497
{
    UINT i, j;
    UINT size;
    LPSTR text, lpstr = NULL;

    *lpBytes = 0; /* Assume return has zero bytes */

    text = GlobalLock(lpData->hData32);
    size = strlen(text);

    /* remove carriage returns */
    lpstr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + 1);
    if (lpstr == NULL)
        goto done;

    for (i = 0,j = 0; i < size && text[i]; i++)
    {
        if (text[i] == '\r' && (text[i+1] == '\n' || text[i+1] == '\0'))
            continue;
        lpstr[j++] = text[i];
    }

    lpstr[j]='\0';
    *lpBytes = j; /* Number of bytes in string */

done:
    HeapFree(GetProcessHeap(), 0, text);
    GlobalUnlock(lpData->hData32);

    return lpstr;
}


/**************************************************************************
 *		X11DRV_CLIPBOARD_ExportUTF8String
 *
 *  Export CF_UNICODE converting the string to UTF8.
 *  Helper function for X11DRV_CLIPBOARD_ExportString.
 */
static HANDLE X11DRV_CLIPBOARD_ExportUTF8String(LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
1498
{
1499
    UINT i, j;
1500 1501
    UINT size;
    LPWSTR uni_text;
1502
    LPSTR text, lpstr = NULL;
1503 1504 1505 1506 1507

    *lpBytes = 0; /* Assume return has zero bytes */

    uni_text = GlobalLock(lpData->hData32);

1508
    size = WideCharToMultiByte(CP_UTF8, 0, uni_text, -1, NULL, 0, NULL, NULL);
1509 1510

    text = HeapAlloc(GetProcessHeap(), 0, size);
1511 1512 1513
    if (!text)
        goto done;
    WideCharToMultiByte(CP_UTF8, 0, uni_text, -1, text, size, NULL, NULL);
1514 1515

    /* remove carriage returns */
1516 1517 1518
    lpstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size--);
    if (lpstr == NULL)
        goto done;
1519

1520
    for (i = 0,j = 0; i < size && text[i]; i++)
1521
    {
1522 1523
        if (text[i] == '\r' && (text[i+1] == '\n' || text[i+1] == '\0'))
            continue;
1524 1525 1526 1527 1528 1529
        lpstr[j++] = text[i];
    }
    lpstr[j]='\0';

    *lpBytes = j; /* Number of bytes in string */

1530
done:
1531 1532 1533 1534 1535 1536 1537
    HeapFree(GetProcessHeap(), 0, text);
    GlobalUnlock(lpData->hData32);

    return lpstr;
}


1538

1539 1540 1541
/**************************************************************************
 *		X11DRV_CLIPBOARD_ExportCompoundText
 *
1542
 *  Export CF_UNICODE to COMPOUND_TEXT
1543 1544
 *  Helper function for X11DRV_CLIPBOARD_ExportString.
 */
1545
static HANDLE X11DRV_CLIPBOARD_ExportCompoundText(Display *display, Window requestor, Atom aTarget, Atom rprop,
1546 1547 1548 1549 1550
    LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
{
    char* lpstr = 0;
    XTextProperty prop;
    XICCEncodingStyle style;
1551 1552 1553 1554 1555 1556 1557 1558 1559 1560
    UINT i, j;
    UINT size;
    LPWSTR uni_text;

    uni_text = GlobalLock(lpData->hData32);

    size = WideCharToMultiByte(CP_UNIXCP, 0, uni_text, -1, NULL, 0, NULL, NULL);
    lpstr = HeapAlloc(GetProcessHeap(), 0, size);
    if (!lpstr)
        return 0;
1561

1562
    WideCharToMultiByte(CP_UNIXCP, 0, uni_text, -1, lpstr, size, NULL, NULL);
1563

1564 1565
    /* remove carriage returns */
    for (i = 0, j = 0; i < size && lpstr[i]; i++)
1566
    {
1567 1568 1569 1570 1571
        if (lpstr[i] == '\r' && (lpstr[i+1] == '\n' || lpstr[i+1] == '\0'))
            continue;
        lpstr[j++] = lpstr[i];
    }
    lpstr[j]='\0';
1572

1573
    GlobalUnlock(lpData->hData32);
1574

1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585
    if (aTarget == x11drv_atom(COMPOUND_TEXT))
        style = XCompoundTextStyle;
    else
        style = XStdICCTextStyle;

    /* Update the X property */
    wine_tsx11_lock();
    if (XmbTextListToTextProperty(display, &lpstr, 1, style, &prop) == Success)
    {
        XSetTextProperty(display, requestor, &prop, rprop);
        XFree(prop.value);
1586
    }
1587 1588 1589
    wine_tsx11_unlock();

    HeapFree(GetProcessHeap(), 0, lpstr);
1590 1591 1592 1593 1594 1595 1596

    return 0;
}

/**************************************************************************
 *		X11DRV_CLIPBOARD_ExportString
 *
1597
 *  Export string
1598
 */
1599 1600
HANDLE X11DRV_CLIPBOARD_ExportString(Display *display, Window requestor, Atom aTarget, Atom rprop,
                                     LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
1601
{
1602
    if (X11DRV_CLIPBOARD_RenderFormat(display, lpData))
1603 1604 1605
    {
        if (aTarget == XA_STRING)
            return X11DRV_CLIPBOARD_ExportXAString(lpData, lpBytes);
1606
        else if (aTarget == x11drv_atom(COMPOUND_TEXT) || aTarget == x11drv_atom(TEXT))
1607
            return X11DRV_CLIPBOARD_ExportCompoundText(display, requestor, aTarget,
1608 1609
                rprop, lpData, lpBytes);
        else
1610 1611 1612 1613
        {
            TRACE("Exporting target %ld to default UTF8_STRING\n", aTarget);
            return X11DRV_CLIPBOARD_ExportUTF8String(lpData, lpBytes);
        }
1614 1615 1616 1617 1618 1619 1620 1621
    }
    else
        ERR("Failed to render %d format\n", lpData->wFormatID);

    return 0;
}


1622 1623 1624 1625 1626
/**************************************************************************
 *		X11DRV_CLIPBOARD_ExportXAPIXMAP
 *
 *  Export CF_DIB to XA_PIXMAP.
 */
1627
HANDLE X11DRV_CLIPBOARD_ExportXAPIXMAP(Display *display, Window requestor, Atom aTarget, Atom rprop,
1628
    LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
1629 1630
{
    HDC hdc;
1631 1632
    HANDLE hData;
    unsigned char* lpData;
1633

1634
    if (!X11DRV_CLIPBOARD_RenderFormat(display, lpdata))
1635 1636 1637 1638 1639
    {
        ERR("Failed to export %d format\n", lpdata->wFormatID);
        return 0;
    }

1640 1641 1642 1643 1644 1645 1646
    if (!lpdata->drvData) /* If not already rendered */
    {
        /* For convert from packed DIB to Pixmap */
        hdc = GetDC(0);
        lpdata->drvData = (UINT) X11DRV_DIB_CreatePixmapFromDIB(lpdata->hData32, hdc);
        ReleaseDC(0, hdc);
    }
1647

1648
    *lpBytes = sizeof(Pixmap); /* pixmap is a 32bit value */
1649

1650 1651 1652 1653 1654
    /* Wrap pixmap so we can return a handle */
    hData = GlobalAlloc(0, *lpBytes);
    lpData = GlobalLock(hData);
    memcpy(lpData, &lpdata->drvData, *lpBytes);
    GlobalUnlock(hData);
1655

1656
    return hData;
1657 1658 1659 1660 1661 1662 1663 1664
}


/**************************************************************************
 *		X11DRV_CLIPBOARD_ExportMetaFilePict
 *
 *  Export MetaFilePict.
 */
1665 1666
HANDLE X11DRV_CLIPBOARD_ExportMetaFilePict(Display *display, Window requestor, Atom aTarget, Atom rprop,
                                           LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
1667
{
1668
    if (!X11DRV_CLIPBOARD_RenderFormat(display, lpdata))
1669 1670 1671 1672 1673
    {
        ERR("Failed to export %d format\n", lpdata->wFormatID);
        return 0;
    }

1674
    return X11DRV_CLIPBOARD_SerializeMetafile(CF_METAFILEPICT, lpdata->hData32, lpBytes, TRUE);
1675 1676 1677 1678 1679 1680 1681 1682
}


/**************************************************************************
 *		X11DRV_CLIPBOARD_ExportEnhMetaFile
 *
 *  Export EnhMetaFile.
 */
1683 1684
HANDLE X11DRV_CLIPBOARD_ExportEnhMetaFile(Display *display, Window requestor, Atom aTarget, Atom rprop,
                                          LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
1685
{
1686
    if (!X11DRV_CLIPBOARD_RenderFormat(display, lpdata))
1687 1688 1689 1690
    {
        ERR("Failed to export %d format\n", lpdata->wFormatID);
        return 0;
    }
1691

1692
    return X11DRV_CLIPBOARD_SerializeMetafile(CF_ENHMETAFILE, lpdata->hData32, lpBytes, TRUE);
1693
}
1694 1695


1696 1697 1698
/**************************************************************************
 *		X11DRV_CLIPBOARD_QueryTargets
 */
1699 1700
static BOOL X11DRV_CLIPBOARD_QueryTargets(Display *display, Window w, Atom selection,
    Atom target, XEvent *xe)
1701 1702 1703
{
    INT i;
    Bool res;
1704

1705
    wine_tsx11_lock();
1706 1707
    XConvertSelection(display, selection, target,
        x11drv_atom(SELECTION_DATA), w, CurrentTime);
1708
    wine_tsx11_unlock();
1709

1710 1711
    /*
     * Wait until SelectionNotify is received
1712
     */
1713
    for (i = 0; i < SELECTION_RETRIES; i++)
1714
    {
1715 1716 1717 1718
        wine_tsx11_lock();
        res = XCheckTypedWindowEvent(display, w, SelectionNotify, xe);
        wine_tsx11_unlock();
        if (res && xe->xselection.selection == selection) break;
1719

1720
        usleep(SELECTION_WAIT);
1721 1722
    }

1723
    /* Verify that the selection returned a valid TARGETS property */
1724
    if ((xe->xselection.target != target) || (xe->xselection.property == None))
1725 1726 1727 1728 1729
    {
        /* Selection owner failed to respond or we missed the SelectionNotify */
        WARN("Failed to retrieve TARGETS for selection %ld.\n", selection);
        return FALSE;
    }
1730

1731 1732 1733 1734
    return TRUE;
}


1735 1736 1737 1738 1739
static int is_atom_error( Display *display, XErrorEvent *event, void *arg )
{
    return (event->error_code == BadAtom);
}

1740 1741 1742
/**************************************************************************
 *		X11DRV_CLIPBOARD_InsertSelectionProperties
 *
1743
 * Mark properties available for future retrieval.
1744 1745 1746
 */
static VOID X11DRV_CLIPBOARD_InsertSelectionProperties(Display *display, Atom* properties, UINT count)
{
1747
     UINT i, nb_atoms = 0;
1748 1749 1750 1751 1752
     Atom *atoms = NULL;

     /* Cache these formats in the clipboard cache */
     for (i = 0; i < count; i++)
     {
1753
         LPWINE_CLIPFORMAT lpFormat = X11DRV_CLIPBOARD_LookupProperty(NULL, properties[i]);
1754

1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770
         if (lpFormat)
         {
             /* We found at least one Window's format that mapps to the property.
              * Continue looking for more.
              *
              * If more than one property map to a Window's format then we use the first 
              * one and ignore the rest.
              */
             while (lpFormat)
             {
                 TRACE("Atom#%d Property(%d): --> FormatID(%d) %s\n",
                       i, lpFormat->drvData, lpFormat->wFormatID, debugstr_w(lpFormat->Name));
                 X11DRV_CLIPBOARD_InsertClipboardData(lpFormat->wFormatID, 0, 0, 0, lpFormat, FALSE);
                 lpFormat = X11DRV_CLIPBOARD_LookupProperty(lpFormat, properties[i]);
             }
         }
1771
         else if (properties[i])
1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785
         {
             /* add it to the list of atoms that we don't know about yet */
             if (!atoms) atoms = HeapAlloc( GetProcessHeap(), 0,
                                            (count - i) * sizeof(*atoms) );
             if (atoms) atoms[nb_atoms++] = properties[i];
         }
     }

     /* query all unknown atoms in one go */
     if (atoms)
     {
         char **names = HeapAlloc( GetProcessHeap(), 0, nb_atoms * sizeof(*names) );
         if (names)
         {
1786 1787 1788 1789 1790 1791 1792
             X11DRV_expect_error( display, is_atom_error, NULL );
             if (!XGetAtomNames( display, atoms, nb_atoms, names )) nb_atoms = 0;
             if (X11DRV_check_error())
             {
                 WARN( "got some bad atoms, ignoring\n" );
                 nb_atoms = 0;
             }
1793 1794
             for (i = 0; i < nb_atoms; i++)
             {
Jacek Caban's avatar
Jacek Caban committed
1795 1796 1797 1798 1799 1800 1801 1802
                 WINE_CLIPFORMAT *lpFormat;
                 LPWSTR wname;
                 int len = MultiByteToWideChar(CP_UNIXCP, 0, names[i], -1, NULL, 0);
                 wname = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
                 MultiByteToWideChar(CP_UNIXCP, 0, names[i], -1, wname, len);

                 lpFormat = register_format( wname, atoms[i] );
                 HeapFree(GetProcessHeap(), 0, wname);
1803 1804 1805 1806 1807 1808
                 if (!lpFormat)
                 {
                     ERR("Failed to register %s property. Type will not be cached.\n", names[i]);
                     continue;
                 }
                 TRACE("Atom#%d Property(%d): --> FormatID(%d) %s\n",
Jacek Caban's avatar
Jacek Caban committed
1809
                       i, lpFormat->drvData, lpFormat->wFormatID, debugstr_w(lpFormat->Name));
1810
                 X11DRV_CLIPBOARD_InsertClipboardData(lpFormat->wFormatID, 0, 0, 0, lpFormat, FALSE);
1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821
             }
             wine_tsx11_lock();
             for (i = 0; i < nb_atoms; i++) XFree( names[i] );
             wine_tsx11_unlock();
             HeapFree( GetProcessHeap(), 0, names );
         }
         HeapFree( GetProcessHeap(), 0, atoms );
     }
}


1822
/**************************************************************************
1823
 *		X11DRV_CLIPBOARD_QueryAvailableData
1824 1825 1826 1827 1828
 *
 * Caches the list of data formats available from the current selection.
 * This queries the selection owner for the TARGETS property and saves all
 * reported property types.
 */
1829
static int X11DRV_CLIPBOARD_QueryAvailableData(Display *display, LPCLIPBOARDINFO lpcbinfo)
1830 1831 1832 1833 1834 1835 1836
{
    XEvent         xe;
    Atom           atype=AnyPropertyType;
    int		   aformat;
    unsigned long  remain;
    Atom*	   targetList=NULL;
    Window         w;
1837
    unsigned long  cSelectionTargets = 0;
1838

1839 1840 1841 1842
    if (selectionAcquired & (S_PRIMARY | S_CLIPBOARD))
    {
        ERR("Received request to cache selection but process is owner=(%08x)\n", 
            (unsigned) selectionWindow);
1843
        return -1; /* Prevent self request */
1844
    }
1845

1846 1847
    w = thread_selection_wnd();
    if (!w)
1848
    {
1849
        ERR("No window available to retrieve selection!\n");
1850
        return -1;
1851 1852
    }

1853 1854 1855
    /*
     * Query the selection owner for the TARGETS property
     */
1856
    wine_tsx11_lock();
1857
    if ((use_primary_selection && XGetSelectionOwner(display,XA_PRIMARY)) ||
1858
        XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)))
1859
    {
1860
        wine_tsx11_unlock();
1861
        if (use_primary_selection && (X11DRV_CLIPBOARD_QueryTargets(display, w, XA_PRIMARY, x11drv_atom(TARGETS), &xe)))
1862
            selectionCacheSrc = XA_PRIMARY;
1863
        else if (X11DRV_CLIPBOARD_QueryTargets(display, w, x11drv_atom(CLIPBOARD), x11drv_atom(TARGETS), &xe))
1864 1865
            selectionCacheSrc = x11drv_atom(CLIPBOARD);
        else
1866
        {
1867
            Atom xstr = XA_STRING;
1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887

            /* Selection Owner doesn't understand TARGETS, try retrieving XA_STRING */
            if (X11DRV_CLIPBOARD_QueryTargets(display, w, XA_PRIMARY, XA_STRING, &xe))
            {
                X11DRV_CLIPBOARD_InsertSelectionProperties(display, &xstr, 1);
                selectionCacheSrc = XA_PRIMARY;
                return 1;
            }
            else if (X11DRV_CLIPBOARD_QueryTargets(display, w, x11drv_atom(CLIPBOARD), XA_STRING, &xe))
            {
                X11DRV_CLIPBOARD_InsertSelectionProperties(display, &xstr, 1);
                selectionCacheSrc = x11drv_atom(CLIPBOARD);
                return 1;
            }
            else
            {
                WARN("Failed to query selection owner for available data.\n");
                return -1;
            }
        }
1888 1889
    }
    else /* No selection owner so report 0 targets available */
1890 1891
    {
        wine_tsx11_unlock();
1892
        return 0;
1893
    }
1894 1895

    /* Read the TARGETS property contents */
1896 1897
    wine_tsx11_lock();
    if(XGetWindowProperty(display, xe.xselection.requestor, xe.xselection.property,
1898 1899 1900
        0, 0x3FFF, True, AnyPropertyType/*XA_ATOM*/, &atype, &aformat, &cSelectionTargets, 
        &remain, (unsigned char**)&targetList) != Success)
    {
1901
        wine_tsx11_unlock();
1902 1903
        WARN("Failed to read TARGETS property\n");
    }
1904 1905
    else
    {
1906
        wine_tsx11_unlock();
1907 1908
       TRACE("Type %lx,Format %d,nItems %ld, Remain %ld\n",
             atype, aformat, cSelectionTargets, remain);
1909 1910 1911 1912
       /*
        * The TARGETS property should have returned us a list of atoms
        * corresponding to each selection target format supported.
        */
1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928
       if (atype == XA_ATOM || atype == x11drv_atom(TARGETS))
       {
           if (aformat == 32)
           {
               X11DRV_CLIPBOARD_InsertSelectionProperties(display, targetList, cSelectionTargets);
           }
           else if (aformat == 8)  /* work around quartz-wm brain damage */
           {
               unsigned long i, count = cSelectionTargets / sizeof(CARD32);
               Atom *atoms = HeapAlloc( GetProcessHeap(), 0, count * sizeof(Atom) );
               for (i = 0; i < count; i++)
                   atoms[i] = ((CARD32 *)targetList)[i];  /* FIXME: byte swapping */
               X11DRV_CLIPBOARD_InsertSelectionProperties( display, atoms, count );
               HeapFree( GetProcessHeap(), 0, atoms );
           }
       }
1929 1930

       /* Free the list of targets */
1931 1932 1933
       wine_tsx11_lock();
       XFree(targetList);
       wine_tsx11_unlock();
1934
    }
1935

1936
    return cSelectionTargets;
1937 1938
}

1939 1940

/**************************************************************************
1941
 *	X11DRV_CLIPBOARD_ReadSelectionData
1942 1943 1944 1945 1946 1947
 *
 * This method is invoked only when we DO NOT own the X selection
 *
 * We always get the data from the selection client each time,
 * since we have no way of determining if the data in our cache is stale.
 */
1948
static BOOL X11DRV_CLIPBOARD_ReadSelectionData(Display *display, LPWINE_CLIPDATA lpData)
1949 1950
{
    Bool res;
1951 1952 1953 1954 1955
    DWORD i;
    XEvent xe;
    BOOL bRet = FALSE;

    TRACE("%d\n", lpData->wFormatID);
1956

1957 1958 1959 1960 1961 1962
    if (!lpData->lpFormat)
    {
        ERR("Requesting format %d but no source format linked to data.\n",
            lpData->wFormatID);
        return FALSE;
    }
1963 1964 1965

    if (!selectionAcquired)
    {
1966
        Window w = thread_selection_wnd();
1967 1968
        if(!w)
        {
1969
            ERR("No window available to read selection data!\n");
1970 1971 1972
            return FALSE;
        }

1973 1974
        TRACE("Requesting conversion of %s property (%d) from selection type %08x\n",
            debugstr_w(lpData->lpFormat->Name), lpData->lpFormat->drvData, (UINT)selectionCacheSrc);
1975

1976 1977 1978 1979
        wine_tsx11_lock();
        XConvertSelection(display, selectionCacheSrc, lpData->lpFormat->drvData,
            x11drv_atom(SELECTION_DATA), w, CurrentTime);
        wine_tsx11_unlock();
1980

1981 1982 1983
        /* wait until SelectionNotify is received */
        for (i = 0; i < SELECTION_RETRIES; i++)
        {
1984
            wine_tsx11_lock();
1985
            res = XCheckTypedWindowEvent(display, w, SelectionNotify, &xe);
1986
            wine_tsx11_unlock();
1987
            if (res && xe.xselection.selection == selectionCacheSrc) break;
1988

1989 1990
            usleep(SELECTION_WAIT);
        }
1991

1992 1993 1994 1995 1996 1997 1998 1999
        /* Verify that the selection returned a valid TARGETS property */
        if (xe.xselection.property != None)
        {
            /*
             *  Read the contents of the X selection property 
             *  into WINE's clipboard cache and converting the 
             *  data format if necessary.
             */
2000
             HANDLE hData = lpData->lpFormat->lpDrvImportFunc(display, xe.xselection.requestor,
2001
                 xe.xselection.property);
2002

2003 2004 2005 2006 2007
             bRet = X11DRV_CLIPBOARD_InsertClipboardData(lpData->wFormatID, 0, hData, 0, lpData->lpFormat, TRUE);
        }
        else
        {
            TRACE("Failed to convert selection\n");
2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020
        }
    }
    else
    {
        ERR("Received request to cache selection data but process is owner\n");
    }

    TRACE("Returning %d\n", bRet);

    return bRet;
}


2021
/**************************************************************************
2022 2023
 *		X11DRV_CLIPBOARD_GetProperty
 *  Gets type, data and size.
2024
 */
2025 2026
static BOOL X11DRV_CLIPBOARD_GetProperty(Display *display, Window w, Atom prop,
    Atom *atype, unsigned char** data, unsigned long* datasize)
2027
{
2028
    int aformat;
2029 2030
    unsigned long pos = 0, nitems, remain, count;
    unsigned char *val = NULL, *buffer;
2031

2032
    TRACE("Reading property %lu from X window %lx\n", prop, w);
2033

2034
    for (;;)
2035
    {
2036 2037
        wine_tsx11_lock();
        if (XGetWindowProperty(display, w, prop, pos, INT_MAX / 4, False,
2038
                               AnyPropertyType, atype, &aformat, &nitems, &remain, &buffer) != Success)
2039 2040 2041 2042 2043 2044
        {
            wine_tsx11_unlock();
            WARN("Failed to read property\n");
            HeapFree( GetProcessHeap(), 0, val );
            return FALSE;
        }
2045

2046
        count = get_property_size( aformat, nitems );
2047 2048
        if (!val) *data = HeapAlloc( GetProcessHeap(), 0, pos * sizeof(int) + count + 1 );
        else *data = HeapReAlloc( GetProcessHeap(), 0, val, pos * sizeof(int) + count + 1 );
2049

2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067
        if (!*data)
        {
            XFree( buffer );
            wine_tsx11_unlock();
            HeapFree( GetProcessHeap(), 0, val );
            return FALSE;
        }
        val = *data;
        memcpy( (int *)val + pos, buffer, count );
        XFree( buffer );
        wine_tsx11_unlock();
        if (!remain)
        {
            *datasize = pos * sizeof(int) + count;
            val[*datasize] = 0;
            break;
        }
        pos += count / sizeof(int);
2068
    }
2069

2070 2071
    /* Delete the property on the window now that we are done
     * This will send a PropertyNotify event to the selection owner. */
2072
    wine_tsx11_lock();
2073
    XDeleteProperty(display, w, prop);
2074
    wine_tsx11_unlock();
2075
    return TRUE;
2076
}
2077 2078


2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158
/**************************************************************************
 *		X11DRV_CLIPBOARD_ReadProperty
 *  Reads the contents of the X selection property.
 */
static BOOL X11DRV_CLIPBOARD_ReadProperty(Display *display, Window w, Atom prop,
    unsigned char** data, unsigned long* datasize)
{
    Atom atype;
    XEvent xe;

    if (prop == None)
        return FALSE;

    if (!X11DRV_CLIPBOARD_GetProperty(display, w, prop, &atype, data, datasize))
        return FALSE;

    wine_tsx11_lock();
    while (XCheckTypedWindowEvent(display, w, PropertyNotify, &xe))
        ;
    wine_tsx11_unlock();

    if (atype == x11drv_atom(INCR))
    {
        unsigned char *buf = *data;
        unsigned long bufsize = 0;

        for (;;)
        {
            int i;
            unsigned char *prop_data, *tmp;
            unsigned long prop_size;

            /* Wait until PropertyNotify is received */
            for (i = 0; i < SELECTION_RETRIES; i++)
            {
                Bool res;

                wine_tsx11_lock();
                res = XCheckTypedWindowEvent(display, w, PropertyNotify, &xe);
                wine_tsx11_unlock();
                if (res && xe.xproperty.atom == prop &&
                    xe.xproperty.state == PropertyNewValue)
                    break;
                usleep(SELECTION_WAIT);
            }

            if (i >= SELECTION_RETRIES ||
                !X11DRV_CLIPBOARD_GetProperty(display, w, prop, &atype, &prop_data, &prop_size))
            {
                HeapFree(GetProcessHeap(), 0, buf);
                return FALSE;
            }

            /* Retrieved entire data. */
            if (prop_size == 0)
            {
                HeapFree(GetProcessHeap(), 0, prop_data);
                *data = buf;
                *datasize = bufsize;
                return TRUE;
            }

            tmp = HeapReAlloc(GetProcessHeap(), 0, buf, bufsize + prop_size + 1);
            if (!tmp)
            {
                HeapFree(GetProcessHeap(), 0, buf);
                return FALSE;
            }

            buf = tmp;
            memcpy(buf + bufsize, prop_data, prop_size + 1);
            bufsize += prop_size;
            HeapFree(GetProcessHeap(), 0, prop_data);
        }
    }

    return TRUE;
}


2159 2160 2161 2162 2163 2164
/**************************************************************************
 *		CLIPBOARD_SerializeMetafile
 */
static HANDLE X11DRV_CLIPBOARD_SerializeMetafile(INT wformat, HANDLE hdata, LPDWORD lpcbytes, BOOL out)
{
    HANDLE h = 0;
2165

2166
    TRACE(" wFormat=%d hdata=%p out=%d\n", wformat, hdata, out);
2167

2168 2169 2170
    if (out) /* Serialize out, caller should free memory */
    {
        *lpcbytes = 0; /* Assume failure */
2171

2172 2173
        if (wformat == CF_METAFILEPICT)
        {
2174
            LPMETAFILEPICT lpmfp = GlobalLock(hdata);
2175
            unsigned int size = GetMetaFileBitsEx(lpmfp->hMF, 0, NULL);
2176

2177 2178 2179 2180
            h = GlobalAlloc(0, size + sizeof(METAFILEPICT));
            if (h)
            {
                char *pdata = GlobalLock(h);
2181

2182 2183
                memcpy(pdata, lpmfp, sizeof(METAFILEPICT));
                GetMetaFileBitsEx(lpmfp->hMF, size, pdata + sizeof(METAFILEPICT));
2184

2185
                *lpcbytes = size + sizeof(METAFILEPICT);
2186

2187 2188
                GlobalUnlock(h);
            }
2189

2190 2191 2192 2193 2194
            GlobalUnlock(hdata);
        }
        else if (wformat == CF_ENHMETAFILE)
        {
            int size = GetEnhMetaFileBits(hdata, 0, NULL);
2195

2196 2197 2198 2199
            h = GlobalAlloc(0, size);
            if (h)
            {
                LPVOID pdata = GlobalLock(h);
2200

2201 2202
                GetEnhMetaFileBits(hdata, size, pdata);
                *lpcbytes = size;
2203

2204 2205 2206
                GlobalUnlock(h);
            }
        }
2207
    }
2208 2209
    else
    {
2210 2211 2212 2213 2214
        if (wformat == CF_METAFILEPICT)
        {
            h = GlobalAlloc(0, sizeof(METAFILEPICT));
            if (h)
            {
2215
                unsigned int wiresize, size;
2216
                LPMETAFILEPICT lpmfp = GlobalLock(h);
2217

2218
                memcpy(lpmfp, hdata, sizeof(METAFILEPICT));
2219 2220
                wiresize = *lpcbytes - sizeof(METAFILEPICT);
                lpmfp->hMF = SetMetaFileBitsEx(wiresize,
2221
                    ((const BYTE *)hdata) + sizeof(METAFILEPICT));
2222
                size = GetMetaFileBitsEx(lpmfp->hMF, 0, NULL);
2223 2224 2225 2226 2227
                GlobalUnlock(h);
            }
        }
        else if (wformat == CF_ENHMETAFILE)
        {
2228
            h = SetEnhMetaFileBits(*lpcbytes, hdata);
2229 2230 2231 2232
        }
    }

    return h;
2233 2234
}

2235

2236 2237 2238
/**************************************************************************
 *		X11DRV_CLIPBOARD_ReleaseSelection
 *
2239
 * Release XA_CLIPBOARD and XA_PRIMARY in response to a SelectionClear event.
2240
 */
2241
static void X11DRV_CLIPBOARD_ReleaseSelection(Display *display, Atom selType, Window w, HWND hwnd, Time time)
2242
{
2243
    /* w is the window that lost the selection
2244
     */
2245 2246
    TRACE("event->window = %08x (selectionWindow = %08x) selectionAcquired=0x%08x\n",
	  (unsigned)w, (unsigned)selectionWindow, (unsigned)selectionAcquired);
2247

2248
    if (selectionAcquired && (w == selectionWindow))
2249
    {
2250 2251 2252 2253 2254 2255 2256
        CLIPBOARDINFO cbinfo;

        /* completely give up the selection */
        TRACE("Lost CLIPBOARD (+PRIMARY) selection\n");

        X11DRV_CLIPBOARD_GetClipboardInfo(&cbinfo);

2257
        if (cbinfo.flags & CB_PROCESS)
2258
        {
2259
            /* Since we're still the owner, this wasn't initiated by
2260 2261
               another Wine process */
            if (OpenClipboard(hwnd))
2262
            {
2263 2264
                /* Destroy private objects */
                SendMessageW(cbinfo.hWndOwner, WM_DESTROYCLIPBOARD, 0, 0);
2265

2266 2267 2268 2269 2270
                /* Give up ownership of the windows clipboard */
                X11DRV_CLIPBOARD_ReleaseOwnership();
                CloseClipboard();
            }
        }
2271

2272 2273 2274
        if ((selType == x11drv_atom(CLIPBOARD)) && (selectionAcquired & S_PRIMARY))
        {
            TRACE("Lost clipboard. Check if we need to release PRIMARY\n");
2275

2276 2277 2278 2279 2280
            wine_tsx11_lock();
            if (selectionWindow == XGetSelectionOwner(display, XA_PRIMARY))
            {
                TRACE("We still own PRIMARY. Releasing PRIMARY.\n");
                XSetSelectionOwner(display, XA_PRIMARY, None, time);
2281
            }
2282 2283 2284 2285 2286 2287 2288 2289 2290 2291
            else
                TRACE("We no longer own PRIMARY\n");
            wine_tsx11_unlock();
        }
        else if ((selType == XA_PRIMARY) && (selectionAcquired & S_CLIPBOARD))
        {
            TRACE("Lost PRIMARY. Check if we need to release CLIPBOARD\n");

            wine_tsx11_lock();
            if (selectionWindow == XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)))
2292
            {
2293 2294
                TRACE("We still own CLIPBOARD. Releasing CLIPBOARD.\n");
                XSetSelectionOwner(display, x11drv_atom(CLIPBOARD), None, time);
2295
            }
2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306
            else
                TRACE("We no longer own CLIPBOARD\n");
            wine_tsx11_unlock();
        }

        selectionWindow = None;

        X11DRV_EmptyClipboard(FALSE);

        /* Reset the selection flags now that we are done */
        selectionAcquired = S_NOSELECTION;
2307
    }
2308
}
2309

2310

2311 2312 2313 2314 2315 2316 2317 2318
/**************************************************************************
 *		IsSelectionOwner (X11DRV.@)
 *
 * Returns: TRUE if the selection is owned by this process, FALSE otherwise
 */
static BOOL X11DRV_CLIPBOARD_IsSelectionOwner(void)
{
    return selectionAcquired;
2319 2320
}

2321 2322 2323 2324 2325 2326

/**************************************************************************
 *                X11DRV Clipboard Exports
 **************************************************************************/


2327
/**************************************************************************
2328 2329 2330 2331
 *		RegisterClipboardFormat (X11DRV.@)
 *
 * Registers a custom X clipboard format
 * Returns: Format id or 0 on failure
2332
 */
2333
UINT X11DRV_RegisterClipboardFormat(LPCWSTR FormatName)
2334
{
2335
    LPWINE_CLIPFORMAT lpFormat;
2336

2337 2338 2339
    if (FormatName == NULL) return 0;
    if (!(lpFormat = register_format( FormatName, 0 ))) return 0;
    return lpFormat->wFormatID;
2340
}
2341

2342

2343 2344 2345
/**************************************************************************
 *		X11DRV_GetClipboardFormatName
 */
Jacek Caban's avatar
Jacek Caban committed
2346
INT X11DRV_GetClipboardFormatName(UINT wFormat, LPWSTR retStr, INT maxlen)
2347
{
2348
    LPWINE_CLIPFORMAT lpFormat;
2349

2350
    TRACE("(%04X, %p, %d) !\n", wFormat, retStr, maxlen);
2351

2352
    if (wFormat < 0xc000)
2353 2354
    {
        SetLastError(ERROR_INVALID_PARAMETER);
2355
        return 0;
2356 2357
    }

2358 2359 2360 2361 2362 2363 2364
    lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);

    if (!lpFormat || (lpFormat->wFlags & CF_FLAG_BUILTINFMT))
    {
        TRACE("Unknown format 0x%08x!\n", wFormat);
        SetLastError(ERROR_INVALID_HANDLE);
        return 0;
2365
    }
2366

Jacek Caban's avatar
Jacek Caban committed
2367
    lstrcpynW(retStr, lpFormat->Name, maxlen);
2368

Jacek Caban's avatar
Jacek Caban committed
2369
    return strlenW(retStr);
2370 2371
}

2372

2373
/**************************************************************************
2374
 *		AcquireClipboard (X11DRV.@)
2375
 */
2376
int X11DRV_AcquireClipboard(HWND hWndClipWindow)
2377
{
2378 2379
    DWORD procid;
    Window owner;
2380
    Display *display;
2381

2382 2383
    TRACE(" %p\n", hWndClipWindow);

2384
    /*
2385 2386 2387 2388
     * It's important that the selection get acquired from the thread
     * that owns the clipboard window. The primary reason is that we know 
     * it is running a message loop and therefore can process the 
     * X selection events.
2389
     */
2390 2391
    if (hWndClipWindow &&
        GetCurrentThreadId() != GetWindowThreadProcessId(hWndClipWindow, &procid))
2392
    {
2393 2394 2395 2396 2397 2398
        if (procid != GetCurrentProcessId())
        {
            WARN("Setting clipboard owner to other process is not supported\n");
            hWndClipWindow = NULL;
        }
        else
2399
        {
2400
            TRACE("Thread %x is acquiring selection with thread %x's window %p\n",
2401
                GetCurrentThreadId(),
2402 2403 2404
                GetWindowThreadProcessId(hWndClipWindow, NULL), hWndClipWindow);

            return SendMessageW(hWndClipWindow, WM_X11DRV_ACQUIRE_SELECTION, 0, 0);
2405
        }
2406
    }
2407

2408
    owner = thread_selection_wnd();
2409
    display = thread_display();
2410

2411
    wine_tsx11_lock();
2412

2413 2414
    selectionAcquired = 0;
    selectionWindow = 0;
2415

2416 2417 2418
    /* Grab PRIMARY selection if not owned */
    if (use_primary_selection)
        XSetSelectionOwner(display, XA_PRIMARY, owner, CurrentTime);
2419

2420 2421
    /* Grab CLIPBOARD selection if not owned */
    XSetSelectionOwner(display, x11drv_atom(CLIPBOARD), owner, CurrentTime);
2422

2423 2424 2425 2426 2427 2428 2429 2430 2431
    if (use_primary_selection && XGetSelectionOwner(display, XA_PRIMARY) == owner)
        selectionAcquired |= S_PRIMARY;

    if (XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)) == owner)
        selectionAcquired |= S_CLIPBOARD;

    wine_tsx11_unlock();

    if (selectionAcquired)
2432
    {
2433 2434
        selectionWindow = owner;
        TRACE("Grabbed X selection, owner=(%08x)\n", (unsigned) owner);
2435
    }
2436 2437

    return 1;
2438
}
2439

2440

2441
/**************************************************************************
2442
 *	X11DRV_EmptyClipboard
2443 2444
 *
 * Empty cached clipboard data. 
2445
 */
2446
void X11DRV_EmptyClipboard(BOOL keepunowned)
2447
{
2448
    if (ClipData)
2449
    {
2450
        LPWINE_CLIPDATA lpData, lpStart;
2451
        LPWINE_CLIPDATA lpNext = ClipData;
2452

2453 2454
        TRACE(" called with %d entries in cache.\n", ClipDataCount);

2455 2456
        do
        {
2457
            lpStart = ClipData;
2458 2459
            lpData = lpNext;
            lpNext = lpData->NextData;
2460 2461 2462

            if (!keepunowned || !(lpData->wFlags & CF_FLAG_UNOWNED))
            {
2463 2464
            lpData->PrevData->NextData = lpData->NextData;
            lpData->NextData->PrevData = lpData->PrevData;
2465 2466 2467 2468

                if (lpData == ClipData)
                    ClipData = lpNext != lpData ? lpNext : NULL;

2469 2470
            X11DRV_CLIPBOARD_FreeData(lpData);
            HeapFree(GetProcessHeap(), 0, lpData);
2471

2472 2473 2474 2475
                ClipDataCount--;
            }
        } while (lpNext != lpStart);
    }
2476

2477
    TRACE(" %d entries remaining in cache.\n", ClipDataCount);
2478
}
2479

2480

2481 2482 2483 2484

/**************************************************************************
 *		X11DRV_SetClipboardData
 */
2485 2486 2487 2488 2489 2490 2491 2492
BOOL X11DRV_SetClipboardData(UINT wFormat, HANDLE16 hData16, HANDLE hData32, BOOL owner)
{
    DWORD flags = 0;
    BOOL bResult = TRUE;

    /* If it's not owned, data can only be set if the format data is not already owned
       and its rendering is not delayed */
    if (!owner)
2493
    {
2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505
        CLIPBOARDINFO cbinfo;
        LPWINE_CLIPDATA lpRender;

        X11DRV_CLIPBOARD_UpdateCache(&cbinfo);

        if ((!hData16 && !hData32) ||
            ((lpRender = X11DRV_CLIPBOARD_LookupData(wFormat)) &&
            !(lpRender->wFlags & CF_FLAG_UNOWNED)))
            bResult = FALSE;
        else
            flags = CF_FLAG_UNOWNED;
    }
2506

2507
    bResult &= X11DRV_CLIPBOARD_InsertClipboardData(wFormat, hData16, hData32, flags, NULL, TRUE);
2508 2509

    return bResult;
2510 2511
}

2512

2513
/**************************************************************************
2514
 *		CountClipboardFormats
2515
 */
2516
INT X11DRV_CountClipboardFormats(void)
2517
{
2518
    CLIPBOARDINFO cbinfo;
2519

2520 2521 2522
    X11DRV_CLIPBOARD_UpdateCache(&cbinfo);

    TRACE(" count=%d\n", ClipDataCount);
2523

2524
    return ClipDataCount;
2525 2526
}

2527

2528
/**************************************************************************
2529
 *		X11DRV_EnumClipboardFormats
2530
 */
2531
UINT X11DRV_EnumClipboardFormats(UINT wFormat)
2532
{
2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548
    CLIPBOARDINFO cbinfo;
    UINT wNextFormat = 0;

    TRACE("(%04X)\n", wFormat);

    X11DRV_CLIPBOARD_UpdateCache(&cbinfo);

    if (!wFormat)
    {
        if (ClipData)
            wNextFormat = ClipData->wFormatID;
    }
    else
    {
        LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(wFormat);

2549
        if (lpData && lpData->NextData != ClipData)
2550 2551 2552 2553
            wNextFormat = lpData->NextData->wFormatID;
    }

    return wNextFormat;
2554 2555
}

2556

2557
/**************************************************************************
2558
 *		X11DRV_IsClipboardFormatAvailable
2559
 */
2560
BOOL X11DRV_IsClipboardFormatAvailable(UINT wFormat)
2561
{
2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574
    BOOL bRet = FALSE;
    CLIPBOARDINFO cbinfo;

    TRACE("(%04X)\n", wFormat);

    X11DRV_CLIPBOARD_UpdateCache(&cbinfo);

    if (wFormat != 0 && X11DRV_CLIPBOARD_LookupData(wFormat))
        bRet = TRUE;

    TRACE("(%04X)- ret(%d)\n", wFormat, bRet);

    return bRet;
2575 2576
}

2577

2578
/**************************************************************************
2579
 *		GetClipboardData (USER.142)
2580
 */
2581
BOOL X11DRV_GetClipboardData(UINT wFormat, HANDLE16* phData16, HANDLE* phData32)
2582
{
2583 2584
    CLIPBOARDINFO cbinfo;
    LPWINE_CLIPDATA lpRender;
2585

2586
    TRACE("(%04X)\n", wFormat);
2587

2588 2589 2590
    X11DRV_CLIPBOARD_UpdateCache(&cbinfo);

    if ((lpRender = X11DRV_CLIPBOARD_LookupData(wFormat)))
2591
    {
2592
        if ( !lpRender->hData32 )
2593
            X11DRV_CLIPBOARD_RenderFormat(thread_init_display(), lpRender);
2594 2595 2596

        /* Convert between 32 -> 16 bit data, if necessary */
        if (lpRender->hData32 && !lpRender->hData16)
2597
        {
2598
            int size;
2599

2600 2601 2602 2603
            if (lpRender->wFormatID == CF_METAFILEPICT)
                size = sizeof(METAFILEPICT16);
            else
                size = GlobalSize(lpRender->hData32);
2604

2605 2606 2607 2608 2609 2610 2611 2612 2613 2614
            lpRender->hData16 = GlobalAlloc16(GMEM_ZEROINIT, size);

            if (!lpRender->hData16)
                ERR("(%04X) -- not enough memory in 16b heap\n", wFormat);
            else
            {
                if (lpRender->wFormatID == CF_METAFILEPICT)
                {
                    FIXME("\timplement function CopyMetaFilePict32to16\n");
                    FIXME("\tin the appropriate file.\n");
2615
#ifdef SOMEONE_IMPLEMENTED_ME
2616 2617
                    CopyMetaFilePict32to16(GlobalLock16(lpRender->hData16),
                        GlobalLock(lpRender->hData32));
2618
#endif
2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629
                }
                else
                {
                    memcpy(GlobalLock16(lpRender->hData16),
                        GlobalLock(lpRender->hData32), size);
                }

                GlobalUnlock16(lpRender->hData16);
                GlobalUnlock(lpRender->hData32);
            }
        }
2630

2631 2632
        /* Convert between 32 -> 16 bit data, if necessary */
        if (lpRender->hData16 && !lpRender->hData32)
2633
        {
2634
            int size;
2635

2636 2637 2638 2639
            if (lpRender->wFormatID == CF_METAFILEPICT)
                size = sizeof(METAFILEPICT16);
            else
                size = GlobalSize(lpRender->hData32);
2640

2641 2642 2643 2644
            lpRender->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | 
                GMEM_DDESHARE, size);

            if (lpRender->wFormatID == CF_METAFILEPICT)
2645
            {
2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656
                FIXME("\timplement function CopyMetaFilePict16to32\n");
                FIXME("\tin the appropriate file.\n");
#ifdef SOMEONE_IMPLEMENTED_ME
                CopyMetaFilePict16to32(GlobalLock16(lpRender->hData32),
                    GlobalLock(lpRender->hData16));
#endif
            }
            else
            {
                memcpy(GlobalLock(lpRender->hData32),
                    GlobalLock16(lpRender->hData16), size);
2657
            }
2658

2659 2660
            GlobalUnlock(lpRender->hData32);
            GlobalUnlock16(lpRender->hData16);
2661 2662
        }

2663 2664
        if (phData16)
            *phData16 = lpRender->hData16;
2665

2666 2667
        if (phData32)
            *phData32 = lpRender->hData32;
2668

2669 2670
        TRACE(" returning hData16(%04x) hData32(%p) (type %d)\n",
            lpRender->hData16, lpRender->hData32, lpRender->wFormatID);
2671 2672 2673 2674 2675

        return lpRender->hData16 || lpRender->hData32;
    }

    return 0;
2676 2677
}

2678

2679
/**************************************************************************
2680
 *		ResetSelectionOwner
2681
 *
2682 2683 2684
 * Called when the thread owning the selection is destroyed and we need to
 * preserve the selection ownership. We look for another top level window
 * in this process and send it a message to acquire the selection.
2685
 */
2686
void X11DRV_ResetSelectionOwner(void)
2687
{
2688 2689
    HWND hwnd;
    DWORD procid;
2690

2691
    TRACE("\n");
2692

2693 2694
    if (!selectionAcquired  || thread_selection_wnd() != selectionWindow)
        return;
2695

2696 2697
    selectionAcquired = S_NOSELECTION;
    selectionWindow = 0;
2698

2699 2700
    hwnd = GetWindow(GetDesktopWindow(), GW_CHILD);
    do
2701
    {
2702
        if (GetCurrentThreadId() != GetWindowThreadProcessId(hwnd, &procid))
2703
        {
2704 2705 2706 2707 2708
            if (GetCurrentProcessId() == procid)
            {
                if (SendMessageW(hwnd, WM_X11DRV_ACQUIRE_SELECTION, 0, 0))
                    return;
            }
2709
        }
2710
    } while ((hwnd = GetWindow(hwnd, GW_HWNDNEXT)) != NULL);
2711

2712
    WARN("Failed to find another thread to take selection ownership. Clipboard data will be lost.\n");
2713

2714 2715
    X11DRV_CLIPBOARD_ReleaseOwnership();
    X11DRV_EmptyClipboard(FALSE);
2716 2717
}

2718 2719

/**************************************************************************
2720
 *                      X11DRV_CLIPBOARD_SynthesizeData
2721
 */
2722
static BOOL X11DRV_CLIPBOARD_SynthesizeData(UINT wFormatID)
2723
{
2724 2725
    BOOL bsyn = TRUE;
    LPWINE_CLIPDATA lpSource = NULL;
2726

2727
    TRACE(" %d\n", wFormatID);
2728

2729 2730 2731
    /* Don't need to synthesize if it already exists */
    if (X11DRV_CLIPBOARD_LookupData(wFormatID))
        return TRUE;
2732

2733
    if (wFormatID == CF_UNICODETEXT || wFormatID == CF_TEXT || wFormatID == CF_OEMTEXT)
2734
    {
2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760
        bsyn = ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_UNICODETEXT)) &&
            ~lpSource->wFlags & CF_FLAG_SYNTHESIZED) ||
            ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_TEXT)) &&
            ~lpSource->wFlags & CF_FLAG_SYNTHESIZED) ||
            ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_OEMTEXT)) &&
            ~lpSource->wFlags & CF_FLAG_SYNTHESIZED);
    }
    else if (wFormatID == CF_ENHMETAFILE)
    {
        bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_METAFILEPICT)) &&
            ~lpSource->wFlags & CF_FLAG_SYNTHESIZED;
    }
    else if (wFormatID == CF_METAFILEPICT)
    {
        bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_METAFILEPICT)) &&
            ~lpSource->wFlags & CF_FLAG_SYNTHESIZED;
    }
    else if (wFormatID == CF_DIB)
    {
        bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_BITMAP)) &&
            ~lpSource->wFlags & CF_FLAG_SYNTHESIZED;
    }
    else if (wFormatID == CF_BITMAP)
    {
        bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIB)) &&
            ~lpSource->wFlags & CF_FLAG_SYNTHESIZED;
2761 2762
    }

2763
    if (bsyn)
2764
        X11DRV_CLIPBOARD_InsertClipboardData(wFormatID, 0, 0, CF_FLAG_SYNTHESIZED, NULL, TRUE);
2765

2766
    return bsyn;
2767 2768 2769
}


2770

2771
/**************************************************************************
2772 2773 2774
 *              X11DRV_EndClipboardUpdate
 * TODO:
 *  Add locale if it hasn't already been added
2775
 */
2776
void X11DRV_EndClipboardUpdate(void)
2777
{
2778
    INT count = ClipDataCount;
2779

2780 2781 2782 2783
    /* Do Unicode <-> Text <-> OEM mapping */
    X11DRV_CLIPBOARD_SynthesizeData(CF_UNICODETEXT);
    X11DRV_CLIPBOARD_SynthesizeData(CF_TEXT);
    X11DRV_CLIPBOARD_SynthesizeData(CF_OEMTEXT);
2784

2785 2786 2787
    /* Enhmetafile <-> MetafilePict mapping */
    X11DRV_CLIPBOARD_SynthesizeData(CF_ENHMETAFILE);
    X11DRV_CLIPBOARD_SynthesizeData(CF_METAFILEPICT);
2788

2789 2790 2791
    /* DIB <-> Bitmap mapping */
    X11DRV_CLIPBOARD_SynthesizeData(CF_DIB);
    X11DRV_CLIPBOARD_SynthesizeData(CF_BITMAP);
2792

2793
    TRACE("%d formats added to cached data\n", ClipDataCount - count);
2794
}
2795 2796 2797 2798 2799 2800 2801 2802 2803


/***********************************************************************
 *           X11DRV_SelectionRequest_TARGETS
 *  Service a TARGETS selection request event
 */
static Atom X11DRV_SelectionRequest_TARGETS( Display *display, Window requestor,
                                             Atom target, Atom rprop )
{
2804
    UINT i;
2805 2806
    Atom* targets;
    ULONG cTargets;
2807 2808
    LPWINE_CLIPFORMAT lpFormats;
    LPWINE_CLIPDATA lpData;
2809

2810 2811 2812 2813 2814 2815 2816
    /* Create X atoms for any clipboard types which don't have atoms yet.
     * This avoids sending bogus zero atoms.
     * Without this, copying might not have access to all clipboard types.
     * FIXME: is it safe to call this here?
     */
    intern_atoms();

2817 2818 2819
    /*
     * Count the number of items we wish to expose as selection targets.
     */
2820
    cTargets = 1; /* Include TARGETS */
2821

2822
    if (!(lpData = ClipData)) return None;
2823 2824

    do
2825
    {
2826
        lpFormats = ClipFormats;
2827

2828
        while (lpFormats)
2829
        {
2830
            if ((lpFormats->wFormatID == lpData->wFormatID) &&
2831
                lpFormats->lpDrvExportFunc && lpFormats->drvData)
2832
                cTargets++;
2833 2834

            lpFormats = lpFormats->NextFormat;
2835
        }
2836 2837

        lpData = lpData->NextData;
2838
    }
2839
    while (lpData != ClipData);
2840

2841
    TRACE(" found %d formats\n", cTargets);
2842 2843

    /* Allocate temp buffer */
2844
    targets = HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
2845 2846 2847
    if(targets == NULL)
        return None;

2848 2849 2850 2851 2852
    i = 0;
    lpData = ClipData;
    targets[i++] = x11drv_atom(TARGETS);

    do
2853
    {
2854
        lpFormats = ClipFormats;
2855

2856
        while (lpFormats)
2857
        {
2858
            if ((lpFormats->wFormatID == lpData->wFormatID) &&
2859
                lpFormats->lpDrvExportFunc && lpFormats->drvData)
2860
                targets[i++] = lpFormats->drvData;
2861

2862
            lpFormats = lpFormats->NextFormat;
2863
        }
2864 2865

        lpData = lpData->NextData;
2866
    }
2867
    while (lpData != ClipData);
2868 2869 2870 2871 2872 2873 2874 2875

    wine_tsx11_lock();

    if (TRACE_ON(clipboard))
    {
        unsigned int i;
        for ( i = 0; i < cTargets; i++)
        {
2876 2877 2878
            char *itemFmtName = XGetAtomName(display, targets[i]);
            TRACE("\tAtom# %d:  Property %ld Type %s\n", i, targets[i], itemFmtName);
            XFree(itemFmtName);
2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982
        }
    }

    /* We may want to consider setting the type to xaTargets instead,
     * in case some apps expect this instead of XA_ATOM */
    XChangeProperty(display, requestor, rprop, XA_ATOM, 32,
                    PropModeReplace, (unsigned char *)targets, cTargets);
    wine_tsx11_unlock();

    HeapFree(GetProcessHeap(), 0, targets);

    return rprop;
}


/***********************************************************************
 *           X11DRV_SelectionRequest_MULTIPLE
 *  Service a MULTIPLE selection request event
 *  rprop contains a list of (target,property) atom pairs.
 *  The first atom names a target and the second names a property.
 *  The effect is as if we have received a sequence of SelectionRequest events
 *  (one for each atom pair) except that:
 *  1. We reply with a SelectionNotify only when all the requested conversions
 *  have been performed.
 *  2. If we fail to convert the target named by an atom in the MULTIPLE property,
 *  we replace the atom in the property by None.
 */
static Atom X11DRV_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
{
    Display *display = pevent->display;
    Atom           rprop;
    Atom           atype=AnyPropertyType;
    int            aformat;
    unsigned long  remain;
    Atom*          targetPropList=NULL;
    unsigned long  cTargetPropList = 0;

    /* If the specified property is None the requestor is an obsolete client.
     * We support these by using the specified target atom as the reply property.
     */
    rprop = pevent->property;
    if( rprop == None )
        rprop = pevent->target;
    if (!rprop)
        return 0;

    /* Read the MULTIPLE property contents. This should contain a list of
     * (target,property) atom pairs.
     */
    wine_tsx11_lock();
    if(XGetWindowProperty(display, pevent->requestor, rprop,
                          0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
                          &cTargetPropList, &remain,
                          (unsigned char**)&targetPropList) != Success)
    {
        wine_tsx11_unlock();
        TRACE("\tCouldn't read MULTIPLE property\n");
    }
    else
    {
        TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
              XGetAtomName(display, atype), aformat, cTargetPropList, remain);
        wine_tsx11_unlock();

        /*
         * Make sure we got what we expect.
         * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
         * in a MULTIPLE selection request should be of type ATOM_PAIR.
         * However some X apps(such as XPaint) are not compliant with this and return
         * a user defined atom in atype when XGetWindowProperty is called.
         * The data *is* an atom pair but is not denoted as such.
         */
        if(aformat == 32 /* atype == xAtomPair */ )
        {
            unsigned int i;

            /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
             * for each (target,property) pair */

            for (i = 0; i < cTargetPropList; i+=2)
            {
                XSelectionRequestEvent event;

                if (TRACE_ON(clipboard))
                {
                    char *targetName, *propName;
                    wine_tsx11_lock();
                    targetName = XGetAtomName(display, targetPropList[i]);
                    propName = XGetAtomName(display, targetPropList[i+1]);
                    TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
                          i/2, targetName, propName);
                    XFree(targetName);
                    XFree(propName);
                    wine_tsx11_unlock();
                }

                /* We must have a non "None" property to service a MULTIPLE target atom */
                if ( !targetPropList[i+1] )
                {
                    TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
                    continue;
                }

                /* Set up an XSelectionRequestEvent for this (target,property) pair */
2983
                event = *pevent;
2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051
                event.target = targetPropList[i];
                event.property = targetPropList[i+1];

                /* Fire a SelectionRequest, informing the handler that we are processing
                 * a MULTIPLE selection request event.
                 */
                X11DRV_HandleSelectionRequest( hWnd, &event, TRUE );
            }
        }

        /* Free the list of targets/properties */
        wine_tsx11_lock();
        XFree(targetPropList);
        wine_tsx11_unlock();
    }

    return rprop;
}


/***********************************************************************
 *           X11DRV_HandleSelectionRequest
 *  Process an event selection request event.
 *  The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
 *  recursively while servicing a "MULTIPLE" selection target.
 *
 *  Note: We only receive this event when WINE owns the X selection
 */
static void X11DRV_HandleSelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
{
    Display *display = event->display;
    XSelectionEvent result;
    Atom rprop = None;
    Window request = event->requestor;

    TRACE("\n");

    /*
     * We can only handle the selection request if :
     * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
     * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
     * since this has been already done.
     */
    if ( !bIsMultiple )
    {
        if (((event->selection != XA_PRIMARY) && (event->selection != x11drv_atom(CLIPBOARD))))
            goto END;
    }

    /* If the specified property is None the requestor is an obsolete client.
     * We support these by using the specified target atom as the reply property.
     */
    rprop = event->property;
    if( rprop == None )
        rprop = event->target;

    if(event->target == x11drv_atom(TARGETS))  /*  Return a list of all supported targets */
    {
        /* TARGETS selection request */
        rprop = X11DRV_SelectionRequest_TARGETS( display, request, event->target, rprop );
    }
    else if(event->target == x11drv_atom(MULTIPLE))  /*  rprop contains a list of (target, property) atom pairs */
    {
        /* MULTIPLE selection request */
        rprop = X11DRV_SelectionRequest_MULTIPLE( hWnd, event );
    }
    else
    {
3052
        LPWINE_CLIPFORMAT lpFormat = X11DRV_CLIPBOARD_LookupProperty(NULL, event->target);
3053 3054 3055 3056 3057 3058 3059 3060 3061

        if (lpFormat && lpFormat->lpDrvExportFunc)
        {
            LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(lpFormat->wFormatID);

            if (lpData)
            {
                unsigned char* lpClipData;
                DWORD cBytes;
3062
                HANDLE hClipData = lpFormat->lpDrvExportFunc(display, request, event->target,
3063 3064 3065 3066
                                                             rprop, lpData, &cBytes);

                if (hClipData && (lpClipData = GlobalLock(hClipData)))
                {
3067
                    TRACE("\tUpdating property %s, %d bytes\n", debugstr_w(lpFormat->Name), cBytes);
3068 3069 3070

                    wine_tsx11_lock();
                    XChangeProperty(display, request, rprop, event->target,
3071
                                    8, PropModeReplace, lpClipData, cBytes);
3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104
                    wine_tsx11_unlock();

                    GlobalUnlock(hClipData);
                    GlobalFree(hClipData);
                }
            }
        }
    }

END:
    /* reply to sender
     * SelectionNotify should be sent only at the end of a MULTIPLE request
     */
    if ( !bIsMultiple )
    {
        result.type = SelectionNotify;
        result.display = display;
        result.requestor = request;
        result.selection = event->selection;
        result.property = rprop;
        result.target = event->target;
        result.time = event->time;
        TRACE("Sending SelectionNotify event...\n");
        wine_tsx11_lock();
        XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
        wine_tsx11_unlock();
    }
}


/***********************************************************************
 *           X11DRV_SelectionRequest
 */
3105
void X11DRV_SelectionRequest( HWND hWnd, XEvent *event )
3106
{
3107
    X11DRV_HandleSelectionRequest( hWnd, &event->xselectionrequest, FALSE );
3108 3109 3110 3111 3112 3113
}


/***********************************************************************
 *           X11DRV_SelectionClear
 */
3114
void X11DRV_SelectionClear( HWND hWnd, XEvent *xev )
3115
{
3116
    XSelectionClearEvent *event = &xev->xselectionclear;
3117
    if (event->selection == XA_PRIMARY || event->selection == x11drv_atom(CLIPBOARD))
3118 3119
        X11DRV_CLIPBOARD_ReleaseSelection( event->display, event->selection,
                                           event->window, hWnd, event->time );
3120
}