clipboard.c 96.3 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 "x11drv.h"
82
#include "wine/list.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
/* Maximum wait time for selection notify */
90
#define SELECTION_RETRIES 500  /* wait for .5 seconds */
91
#define SELECTION_WAIT    1000 /* us */
92

93 94 95 96 97
/* Selection masks */
#define S_NOSELECTION    0
#define S_PRIMARY        1
#define S_CLIPBOARD      2

98 99 100 101 102 103 104 105 106
typedef struct
{
    HWND hWndOpen;
    HWND hWndOwner;
    HWND hWndViewer;
    UINT seqno;
    UINT flags;
} CLIPBOARDINFO, *LPCLIPBOARDINFO;

107
struct tagWINE_CLIPDATA; /* Forward */
108

109
typedef HANDLE (*DRVEXPORTFUNC)(Display *display, Window requestor, Atom aTarget, Atom rprop,
110
    struct tagWINE_CLIPDATA* lpData, LPDWORD lpBytes);
111
typedef HANDLE (*DRVIMPORTFUNC)(Display *d, Window w, Atom prop);
112 113

typedef struct tagWINE_CLIPFORMAT {
114
    struct list entry;
115 116 117 118 119 120
    UINT        wFormatID;
    UINT        drvData;
    DRVIMPORTFUNC  lpDrvImportFunc;
    DRVEXPORTFUNC  lpDrvExportFunc;
} WINE_CLIPFORMAT, *LPWINE_CLIPFORMAT;

121
typedef struct tagWINE_CLIPDATA {
122
    struct list entry;
123
    UINT        wFormatID;
124
    HANDLE      hData;
125 126 127 128 129
    UINT        wFlags;
    UINT        drvData;
    LPWINE_CLIPFORMAT lpFormat;
} WINE_CLIPDATA, *LPWINE_CLIPDATA;

130 131
#define CF_FLAG_UNOWNED      0x0001 /* cached data is not owned */
#define CF_FLAG_SYNTHESIZED  0x0002 /* Implicitly converted data */
132

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

137 138
void CDECL X11DRV_EmptyClipboard(BOOL keepunowned);
void CDECL X11DRV_EndClipboardUpdate(void);
139 140 141 142
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);
143
static HANDLE X11DRV_CLIPBOARD_ImportImageBmp(Display *d, Window w, Atom prop);
144 145 146 147
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,
148
    Atom rprop, LPWINE_CLIPDATA lpData, LPDWORD lpBytes);
149
static HANDLE X11DRV_CLIPBOARD_ExportString(Display *display, Window requestor, Atom aTarget,
150
    Atom rprop, LPWINE_CLIPDATA lpData, LPDWORD lpBytes);
151
static HANDLE X11DRV_CLIPBOARD_ExportXAPIXMAP(Display *display, Window requestor, Atom aTarget,
152
    Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
153 154
static HANDLE X11DRV_CLIPBOARD_ExportImageBmp(Display *display, Window requestor, Atom aTarget,
    Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
155
static HANDLE X11DRV_CLIPBOARD_ExportMetaFilePict(Display *display, Window requestor, Atom aTarget,
156
    Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
157
static HANDLE X11DRV_CLIPBOARD_ExportEnhMetaFile(Display *display, Window requestor, Atom aTarget,
158
    Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
159 160
static HANDLE X11DRV_CLIPBOARD_ExportTextHtml(Display *display, Window requestor, Atom aTarget,
    Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
161
static WINE_CLIPFORMAT *X11DRV_CLIPBOARD_InsertClipboardFormat(UINT id, Atom prop);
162
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedText(Display *display, UINT wFormatID);
163 164
static void X11DRV_CLIPBOARD_FreeData(LPWINE_CLIPDATA lpData);
static BOOL X11DRV_CLIPBOARD_IsSelectionOwner(void);
165 166 167
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,
168
    unsigned char** data, unsigned long* datasize);
169
static BOOL X11DRV_CLIPBOARD_RenderFormat(Display *display, LPWINE_CLIPDATA lpData);
170 171
static HANDLE X11DRV_CLIPBOARD_SerializeMetafile(INT wformat, HANDLE hdata, LPDWORD lpcbytes, BOOL out);
static BOOL X11DRV_CLIPBOARD_SynthesizeData(UINT wFormatID);
172 173 174
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedFormat(Display *display, LPWINE_CLIPDATA lpData);
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedDIB(Display *display);
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedBitmap(Display *display);
175
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedEnhMetaFile(Display *display);
176
static void X11DRV_HandleSelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
177

178
/* Clipboard formats */
Jacek Caban's avatar
Jacek Caban committed
179

180
static const struct
181
{
182 183 184 185 186 187
    UINT          id;
    UINT          data;
    DRVIMPORTFUNC import;
    DRVEXPORTFUNC export;
} builtin_formats[] =
{
188 189 190 191 192 193 194 195 196 197 198 199 200
    { CF_TEXT, XA_STRING, X11DRV_CLIPBOARD_ImportXAString, X11DRV_CLIPBOARD_ExportString},
    { CF_BITMAP, XATOM_WCF_BITMAP, X11DRV_CLIPBOARD_ImportClipboardData, NULL},
    { CF_METAFILEPICT, XATOM_WCF_METAFILEPICT, X11DRV_CLIPBOARD_ImportMetaFilePict, X11DRV_CLIPBOARD_ExportMetaFilePict },
    { CF_SYLK, XATOM_WCF_SYLK, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_DIF, XATOM_WCF_DIF, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_TIFF, XATOM_WCF_TIFF, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_OEMTEXT, XATOM_WCF_OEMTEXT, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_DIB, XA_PIXMAP, X11DRV_CLIPBOARD_ImportXAPIXMAP, X11DRV_CLIPBOARD_ExportXAPIXMAP },
    { CF_PALETTE, XATOM_WCF_PALETTE, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_PENDATA, XATOM_WCF_PENDATA, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_RIFF, XATOM_WCF_RIFF, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_WAVE, XATOM_WCF_WAVE, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_UNICODETEXT, XATOM_UTF8_STRING, X11DRV_CLIPBOARD_ImportUTF8, X11DRV_CLIPBOARD_ExportString },
201
    /* If UTF8_STRING is not available, attempt COMPOUND_TEXT */
202 203 204 205 206 207 208 209 210 211 212
    { CF_UNICODETEXT, XATOM_COMPOUND_TEXT, X11DRV_CLIPBOARD_ImportCompoundText, X11DRV_CLIPBOARD_ExportString },
    { CF_ENHMETAFILE, XATOM_WCF_ENHMETAFILE, X11DRV_CLIPBOARD_ImportEnhMetaFile, X11DRV_CLIPBOARD_ExportEnhMetaFile },
    { CF_HDROP, XATOM_WCF_HDROP, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_LOCALE, XATOM_WCF_LOCALE, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_DIBV5, XATOM_WCF_DIBV5, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_OWNERDISPLAY, XATOM_WCF_OWNERDISPLAY, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_DSPTEXT, XATOM_WCF_DSPTEXT, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_DSPBITMAP, XATOM_WCF_DSPBITMAP, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_DSPMETAFILEPICT, XATOM_WCF_DSPMETAFILEPICT, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_DSPENHMETAFILE, XATOM_WCF_DSPENHMETAFILE, X11DRV_CLIPBOARD_ImportClipboardData, X11DRV_CLIPBOARD_ExportClipboardData },
    { CF_DIB, XATOM_image_bmp, X11DRV_CLIPBOARD_ImportImageBmp, X11DRV_CLIPBOARD_ExportImageBmp },
213 214
};

215 216
static struct list format_list = LIST_INIT( format_list );

217
#define GET_ATOM(prop)  (((prop) < FIRST_XATOM) ? (Atom)(prop) : X11DRV_Atoms[(prop) - FIRST_XATOM])
218 219

/* Maps X properties to Windows formats */
Jacek Caban's avatar
Jacek Caban committed
220 221
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};
222
static const WCHAR wszJFIF[] = {'J','F','I','F',0};
223
static const WCHAR wszPNG[] = {'P','N','G',0};
224
static const WCHAR wszHTMLFormat[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
225 226
static const struct
{
Jacek Caban's avatar
Jacek Caban committed
227
    LPCWSTR lpszFormat;
228 229 230
    UINT   prop;
} PropertyFormatMap[] =
{
Jacek Caban's avatar
Jacek Caban committed
231
    { wszRichTextFormat, XATOM_text_rtf },
232 233
    { wszRichTextFormat, XATOM_text_richtext },
    { wszGIF, XATOM_image_gif },
234
    { wszJFIF, XATOM_image_jpeg },
235
    { wszPNG, XATOM_image_png },
236
    { wszHTMLFormat, XATOM_HTML_Format }, /* prefer this to text/html */
237 238 239 240 241 242
};


/*
 * Cached clipboard data.
 */
243
static struct list data_list = LIST_INIT( data_list );
244 245 246 247 248
static UINT ClipDataCount = 0;

/*
 * Clipboard sequence number
 */
249
static UINT wSeqNo = 0;
250 251

/**************************************************************************
252 253 254
 *                Internal Clipboard implementation methods
 **************************************************************************/

255 256
static Window thread_selection_wnd(void)
{
257 258
    struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
    Window w = thread_data->selection_wnd;
259 260 261

    if (!w)
    {
262 263 264
        XSetWindowAttributes attr;

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

267
        wine_tsx11_lock();
268
        w = XCreateWindow(thread_data->display, root_window, 0, 0, 1, 1, 0, screen_depth,
269
                          InputOutput, CopyFromParent, CWEventMask, &attr);
270 271 272
        wine_tsx11_unlock();

        if (w)
273
            thread_data->selection_wnd = w;
274 275 276 277 278 279 280
        else
            FIXME("Failed to create window. Fetching selection data will fail.\n");
    }

    return w;
}

281 282
static const char *debugstr_format( UINT id )
{
283 284 285
    WCHAR buffer[256];

    if (GetClipboardFormatNameW( id, buffer, 256 ))
286
        return wine_dbg_sprintf( "%04x %s", id, debugstr_w(buffer) );
287

288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
    switch (id)
    {
#define BUILTIN(id) case id: return #id;
    BUILTIN(CF_TEXT)
    BUILTIN(CF_BITMAP)
    BUILTIN(CF_METAFILEPICT)
    BUILTIN(CF_SYLK)
    BUILTIN(CF_DIF)
    BUILTIN(CF_TIFF)
    BUILTIN(CF_OEMTEXT)
    BUILTIN(CF_DIB)
    BUILTIN(CF_PALETTE)
    BUILTIN(CF_PENDATA)
    BUILTIN(CF_RIFF)
    BUILTIN(CF_WAVE)
    BUILTIN(CF_UNICODETEXT)
    BUILTIN(CF_ENHMETAFILE)
    BUILTIN(CF_HDROP)
    BUILTIN(CF_LOCALE)
    BUILTIN(CF_DIBV5)
    BUILTIN(CF_OWNERDISPLAY)
    BUILTIN(CF_DSPTEXT)
    BUILTIN(CF_DSPBITMAP)
    BUILTIN(CF_DSPMETAFILEPICT)
    BUILTIN(CF_DSPENHMETAFILE)
#undef BUILTIN
    default: return wine_dbg_sprintf( "%04x", id );
    }
}

318 319
/**************************************************************************
 *		X11DRV_InitClipboard
320
 */
321
void X11DRV_InitClipboard(void)
322
{
323
    UINT i;
324
    WINE_CLIPFORMAT *format;
325

326 327 328 329 330
    /* Register built-in formats */
    for (i = 0; i < sizeof(builtin_formats)/sizeof(builtin_formats[0]); i++)
    {
        if (!(format = HeapAlloc( GetProcessHeap(), 0, sizeof(*format )))) break;
        format->wFormatID       = builtin_formats[i].id;
331
        format->drvData         = GET_ATOM(builtin_formats[i].data);
332 333 334 335 336
        format->lpDrvImportFunc = builtin_formats[i].import;
        format->lpDrvExportFunc = builtin_formats[i].export;
        list_add_tail( &format_list, &format->entry );
    }

337 338
    /* Register known mapping between window formats and X properties */
    for (i = 0; i < sizeof(PropertyFormatMap)/sizeof(PropertyFormatMap[0]); i++)
339
        X11DRV_CLIPBOARD_InsertClipboardFormat( RegisterClipboardFormatW(PropertyFormatMap[i].lpszFormat),
340
                                                GET_ATOM(PropertyFormatMap[i].prop));
341 342

    /* Set up a conversion function from "HTML Format" to "text/html" */
343
    format = X11DRV_CLIPBOARD_InsertClipboardFormat( RegisterClipboardFormatW(wszHTMLFormat),
344
                                                     GET_ATOM(XATOM_text_html));
345
    format->lpDrvExportFunc = X11DRV_CLIPBOARD_ExportTextHtml;
346 347 348 349 350 351 352 353 354 355 356
}


/**************************************************************************
 *                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
357
    int i, count, len;
358 359
    char **names;
    Atom *atoms;
360
    Display *display;
361
    WCHAR buffer[256];
362

363 364
    count = 0;
    LIST_FOR_EACH_ENTRY( format, &format_list, WINE_CLIPFORMAT, entry )
365 366 367
        if (!format->drvData) count++;
    if (!count) return;

368 369
    display = thread_init_display();

370 371 372
    names = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*names) );
    atoms = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*atoms) );

373 374
    i = 0;
    LIST_FOR_EACH_ENTRY( format, &format_list, WINE_CLIPFORMAT, entry )
Jacek Caban's avatar
Jacek Caban committed
375
        if (!format->drvData) {
376
            GetClipboardFormatNameW( format->wFormatID, buffer, 256 );
377
            len = WideCharToMultiByte(CP_UNIXCP, 0, buffer, -1, NULL, 0, NULL, NULL);
378
            names[i] = HeapAlloc(GetProcessHeap(), 0, len);
379
            WideCharToMultiByte(CP_UNIXCP, 0, buffer, -1, names[i++], len, NULL, NULL);
Jacek Caban's avatar
Jacek Caban committed
380
        }
381 382

    wine_tsx11_lock();
383
    XInternAtoms( display, names, count, False, atoms );
384
    wine_tsx11_unlock();
385

386 387
    i = 0;
    LIST_FOR_EACH_ENTRY( format, &format_list, WINE_CLIPFORMAT, entry )
Jacek Caban's avatar
Jacek Caban committed
388 389 390 391
        if (!format->drvData) {
            HeapFree(GetProcessHeap(), 0, names[i]);
            format->drvData = atoms[i++];
        }
392

393 394 395 396 397 398 399 400 401 402
    HeapFree( GetProcessHeap(), 0, names );
    HeapFree( GetProcessHeap(), 0, atoms );
}


/**************************************************************************
 *		register_format
 *
 * Register a custom X clipboard format.
 */
403
static WINE_CLIPFORMAT *register_format( UINT id, Atom prop )
404
{
405
    LPWINE_CLIPFORMAT lpFormat;
406 407

    /* walk format chain to see if it's already registered */
408
    LIST_FOR_EACH_ENTRY( lpFormat, &format_list, WINE_CLIPFORMAT, entry )
409
        if (lpFormat->wFormatID == id) return lpFormat;
410

411
    return X11DRV_CLIPBOARD_InsertClipboardFormat(id, prop);
412 413 414 415 416 417
}


/**************************************************************************
 *                X11DRV_CLIPBOARD_LookupProperty
 */
418
static LPWINE_CLIPFORMAT X11DRV_CLIPBOARD_LookupProperty(LPWINE_CLIPFORMAT current, UINT drvData)
419
{
420
    for (;;)
421
    {
422
        struct list *ptr = current ? &current->entry : &format_list;
423
        BOOL need_intern = FALSE;
424

425
        while ((ptr = list_next( &format_list, ptr )))
426
        {
427
            LPWINE_CLIPFORMAT lpFormat = LIST_ENTRY( ptr, WINE_CLIPFORMAT, entry );
428 429 430 431 432 433
            if (lpFormat->drvData == drvData) return lpFormat;
            if (!lpFormat->drvData) need_intern = TRUE;
        }
        if (!need_intern) return NULL;
        intern_atoms();
        /* restart the search for the new atoms */
434 435 436 437 438 439 440
    }
}


/**************************************************************************
 *               X11DRV_CLIPBOARD_LookupData
 */
441
static LPWINE_CLIPDATA X11DRV_CLIPBOARD_LookupData(DWORD wID)
442
{
443
    WINE_CLIPDATA *data;
444

445 446
    LIST_FOR_EACH_ENTRY( data, &data_list, WINE_CLIPDATA, entry )
        if (data->wFormatID == wID) return data;
447

448
    return NULL;
449 450 451 452 453 454
}


/**************************************************************************
 *		InsertClipboardFormat
 */
455
static WINE_CLIPFORMAT *X11DRV_CLIPBOARD_InsertClipboardFormat( UINT id, Atom prop )
456 457
{
    LPWINE_CLIPFORMAT lpNewFormat;
458

459
    /* allocate storage for new format entry */
460
    lpNewFormat = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPFORMAT));
461 462 463 464

    if(lpNewFormat == NULL) 
    {
        WARN("No more memory for a new format!\n");
465
        return NULL;
466
    }
467
    lpNewFormat->wFormatID = id;
468
    lpNewFormat->drvData = prop;
469 470 471
    lpNewFormat->lpDrvImportFunc = X11DRV_CLIPBOARD_ImportClipboardData;
    lpNewFormat->lpDrvExportFunc = X11DRV_CLIPBOARD_ExportClipboardData;

472
    list_add_tail( &format_list, &lpNewFormat->entry );
473

474 475
    TRACE("Registering format %s drvData %d\n",
          debugstr_format(lpNewFormat->wFormatID), lpNewFormat->drvData);
476

477
    return lpNewFormat;
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
}




/**************************************************************************
 *                      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");
        }
498
        else
499
        {
500 501 502
            cbInfo->hWndOpen = wine_server_ptr_handle( reply->old_clipboard );
            cbInfo->hWndOwner = wine_server_ptr_handle( reply->old_owner );
            cbInfo->hWndViewer = wine_server_ptr_handle( reply->old_viewer );
503 504 505 506 507
            cbInfo->seqno = reply->seqno;
            cbInfo->flags = reply->flags;

            bRet = TRUE;
        }
508
    }
509
    SERVER_END_REQ;
510

511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
    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;
538
}
539

540 541


542
/**************************************************************************
543
 *                      X11DRV_CLIPBOARD_InsertClipboardData
544
 *
545
 * Caller *must* have the clipboard open and be the owner.
546
 */
547 548
static BOOL X11DRV_CLIPBOARD_InsertClipboardData(UINT wFormatID, HANDLE hData, DWORD flags,
                                                 LPWINE_CLIPFORMAT lpFormat, BOOL override)
549
{
550
    LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(wFormatID);
551

552 553
    TRACE("format=%04x lpData=%p hData=%p flags=0x%08x lpFormat=%p override=%d\n",
        wFormatID, lpData, hData, flags, lpFormat, override);
554

555 556 557
    /* make sure the format exists */
    if (!lpFormat) register_format( wFormatID, 0 );

558 559
    if (lpData && !override)
        return TRUE;
560 561

    if (lpData)
562
    {
563
        X11DRV_CLIPBOARD_FreeData(lpData);
564

565
        lpData->hData = hData;
566 567 568
    }
    else
    {
569
        lpData = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPDATA));
570

571
        lpData->wFormatID = wFormatID;
572
        lpData->hData = hData;
573
        lpData->lpFormat = lpFormat;
574
        lpData->drvData = 0;
575

576
        list_add_tail( &data_list, &lpData->entry );
577
        ClipDataCount++;
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
    }

    lpData->wFlags = flags;

    return TRUE;
}


/**************************************************************************
 *			X11DRV_CLIPBOARD_FreeData
 *
 * Free clipboard data handle.
 */
static void X11DRV_CLIPBOARD_FreeData(LPWINE_CLIPDATA lpData)
{
593
    TRACE("%04x\n", lpData->wFormatID);
594 595 596 597 598 599 600

    if ((lpData->wFormatID >= CF_GDIOBJFIRST &&
        lpData->wFormatID <= CF_GDIOBJLAST) || 
        lpData->wFormatID == CF_BITMAP || 
        lpData->wFormatID == CF_DIB || 
        lpData->wFormatID == CF_PALETTE)
    {
601 602
      if (lpData->hData)
	DeleteObject(lpData->hData);
603 604 605

      if ((lpData->wFormatID == CF_DIB) && lpData->drvData)
          XFreePixmap(gdi_display, lpData->drvData);
606 607 608
    }
    else if (lpData->wFormatID == CF_METAFILEPICT)
    {
609
      if (lpData->hData)
610
      {
611 612
        DeleteMetaFile(((METAFILEPICT *)GlobalLock( lpData->hData ))->hMF );
        GlobalFree(lpData->hData);
613 614 615 616
      }
    }
    else if (lpData->wFormatID == CF_ENHMETAFILE)
    {
617 618
        if (lpData->hData)
            DeleteEnhMetaFile(lpData->hData);
619 620 621 622
    }
    else if (lpData->wFormatID < CF_PRIVATEFIRST ||
             lpData->wFormatID > CF_PRIVATELAST)
    {
623 624
      if (lpData->hData)
        GlobalFree(lpData->hData);
625 626
    }

627
    lpData->hData = 0;
628
    lpData->drvData = 0;
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
}


/**************************************************************************
 *			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)
        {
648
            X11DRV_EmptyClipboard(TRUE);
649

650
            if (X11DRV_CLIPBOARD_QueryAvailableData(thread_init_display(), lpcbinfo) < 0)
651 652 653 654 655
            {
                ERR("Failed to cache clipboard data owned by another process.\n");
                bret = FALSE;
            }
            else
656
            {
657
                X11DRV_EndClipboardUpdate();
658
            }
659 660

            wSeqNo = lpcbinfo->seqno;
661
        }
662 663 664 665
    }

    return bret;
}
666

667 668 669 670

/**************************************************************************
 *			X11DRV_CLIPBOARD_RenderFormat
 */
671
static BOOL X11DRV_CLIPBOARD_RenderFormat(Display *display, LPWINE_CLIPDATA lpData)
672 673 674
{
    BOOL bret = TRUE;

675
    TRACE(" 0x%04x hData(%p)\n", lpData->wFormatID, lpData->hData);
676

677
    if (lpData->hData) return bret; /* Already rendered */
678

679
    if (lpData->wFlags & CF_FLAG_SYNTHESIZED)
680
        bret = X11DRV_CLIPBOARD_RenderSynthesizedFormat(display, lpData);
681
    else if (!X11DRV_CLIPBOARD_IsSelectionOwner())
682
    {
683
        if (!X11DRV_CLIPBOARD_ReadSelectionData(display, lpData))
684
        {
685
            ERR("Failed to cache clipboard data owned by another process. Format=%04x\n",
686 687 688 689 690 691
                lpData->wFormatID);
            bret = FALSE;
        }
    }
    else
    {
692
        CLIPBOARDINFO cbInfo;
693

694
        if (X11DRV_CLIPBOARD_GetClipboardInfo(&cbInfo) && cbInfo.hWndOwner)
695 696 697 698 699
        {
            /* 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);
700
            SendMessageW(cbInfo.hWndOwner, WM_RENDERFORMAT, lpData->wFormatID, 0);
701

702
            if (!lpData->hData) bret = FALSE;
703
        }
704 705 706 707 708 709
        else
        {
            ERR("hWndClipOwner is lost!\n");
            bret = FALSE;
        }
    }
710

711 712
    return bret;
}
713

714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771

/**************************************************************************
 *                      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
 */
772
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedFormat(Display *display, LPWINE_CLIPDATA lpData)
773 774 775
{
    BOOL bret = FALSE;

776 777
    TRACE("\n");

778 779 780 781 782
    if (lpData->wFlags & CF_FLAG_SYNTHESIZED)
    {
        UINT wFormatID = lpData->wFormatID;

        if (wFormatID == CF_UNICODETEXT || wFormatID == CF_TEXT || wFormatID == CF_OEMTEXT)
783
            bret = X11DRV_CLIPBOARD_RenderSynthesizedText(display, wFormatID);
784 785 786 787 788
        else 
        {
            switch (wFormatID)
	    {
                case CF_DIB:
789
                    bret = X11DRV_CLIPBOARD_RenderSynthesizedDIB( display );
790 791
                    break;

792
                case CF_BITMAP:
793
                    bret = X11DRV_CLIPBOARD_RenderSynthesizedBitmap( display );
794 795 796
                    break;

                case CF_ENHMETAFILE:
797 798 799
                    bret = X11DRV_CLIPBOARD_RenderSynthesizedEnhMetaFile( display );
                    break;

800
                case CF_METAFILEPICT:
801
                    FIXME("Synthesizing CF_METAFILEPICT not implemented\n");
802 803 804
                    break;

                default:
805
                    FIXME("Called to synthesize unknown format 0x%08x\n", wFormatID);
806 807
                    break;
            }
808
        }
809 810 811 812 813 814 815 816 817

        lpData->wFlags &= ~CF_FLAG_SYNTHESIZED;
    }

    return bret;
}


/**************************************************************************
818
 *                      X11DRV_CLIPBOARD_RenderSynthesizedText
819
 *
820
 * Renders synthesized text
821
 */
822
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedText(Display *display, UINT wFormatID)
823 824 825
{
    LPCSTR lpstrS;
    LPSTR  lpstrT;
826
    HANDLE hData;
827 828 829
    INT src_chars, dst_chars, alloc_size;
    LPWINE_CLIPDATA lpSource = NULL;

830
    TRACE("%04x\n", wFormatID);
831

832
    if ((lpSource = X11DRV_CLIPBOARD_LookupData(wFormatID)) &&
833
        lpSource->hData)
834 835
        return TRUE;

836 837
    /* Look for rendered source or non-synthesized source */
    if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_UNICODETEXT)) &&
838
        (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData))
839
    {
840
        TRACE("UNICODETEXT -> %04x\n", wFormatID);
841
    }
842
    else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_TEXT)) &&
843
        (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData))
844
    {
845
        TRACE("TEXT -> %04x\n", wFormatID);
846
    }
847
    else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_OEMTEXT)) &&
848
        (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData))
849
    {
850
        TRACE("OEMTEXT -> %04x\n", wFormatID);
851 852
    }

853
    if (!lpSource || (lpSource->wFlags & CF_FLAG_SYNTHESIZED &&
854
        !lpSource->hData))
855 856
        return FALSE;

857
    /* Ask the clipboard owner to render the source text if necessary */
858
    if (!lpSource->hData && !X11DRV_CLIPBOARD_RenderFormat(display, lpSource))
859 860
        return FALSE;

861
    lpstrS = GlobalLock(lpSource->hData);
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877
    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;

878
    TRACE("Converting from '%04x' to '%04x', %i chars\n",
879 880 881 882 883 884 885 886
    	lpSource->wFormatID, wFormatID, src_chars);

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

887
    hData = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE |
888 889
        GMEM_DDESHARE, alloc_size);

890
    lpstrT = GlobalLock(hData);
891 892 893 894 895

    if (lpstrT)
    {
        CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, src_chars,
            wFormatID, lpstrT, dst_chars);
896
        GlobalUnlock(hData);
897
    }
898

899
    GlobalUnlock(lpSource->hData);
900

901
    return X11DRV_CLIPBOARD_InsertClipboardData(wFormatID, hData, 0, NULL, TRUE);
902
}
903

904

905 906 907 908 909
/**************************************************************************
 *                      X11DRV_CLIPBOARD_RenderSynthesizedDIB
 *
 * Renders synthesized DIB
 */
910
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedDIB(Display *display)
911 912 913 914 915 916
{
    BOOL bret = FALSE;
    LPWINE_CLIPDATA lpSource = NULL;

    TRACE("\n");

917
    if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIB)) && lpSource->hData)
918 919 920 921 922
    {
        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)) &&
923
        (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData))
924 925
    {
        /* Render source if required */
926
        if (lpSource->hData || X11DRV_CLIPBOARD_RenderFormat(display, lpSource))
927 928
        {
            HDC hdc;
929
            HGLOBAL hData;
930 931

            hdc = GetDC(NULL);
932
            hData = X11DRV_DIB_CreateDIBFromBitmap(hdc, lpSource->hData);
933 934
            ReleaseDC(NULL, hdc);

935
            if (hData)
936
            {
937
                X11DRV_CLIPBOARD_InsertClipboardData(CF_DIB, hData, 0, NULL, TRUE);
938 939 940 941 942 943 944 945 946 947 948 949 950 951
                bret = TRUE;
            }
        }
    }

    return bret;
}


/**************************************************************************
 *                      X11DRV_CLIPBOARD_RenderSynthesizedBitmap
 *
 * Renders synthesized bitmap
 */
952
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedBitmap(Display *display)
953 954 955 956 957 958
{
    BOOL bret = FALSE;
    LPWINE_CLIPDATA lpSource = NULL;

    TRACE("\n");

959
    if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_BITMAP)) && lpSource->hData)
960 961 962 963 964
    {
        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)) &&
965
        (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData))
966 967
    {
        /* Render source if required */
968
        if (lpSource->hData || X11DRV_CLIPBOARD_RenderFormat(display, lpSource))
969 970
        {
            HDC hdc;
971
            HBITMAP hData = NULL;
972 973 974 975
            unsigned int offset;
            LPBITMAPINFOHEADER lpbmih;

            hdc = GetDC(NULL);
976
            lpbmih = GlobalLock(lpSource->hData);
977 978 979 980 981
            if (lpbmih)
            {
                offset = sizeof(BITMAPINFOHEADER)
                      + ((lpbmih->biBitCount <= 8) ? (sizeof(RGBQUAD) *
                        (1 << lpbmih->biBitCount)) : 0);
982

983 984
                hData = CreateDIBitmap(hdc, lpbmih, CBM_INIT, (LPBYTE)lpbmih +
                    offset, (LPBITMAPINFO) lpbmih, DIB_RGB_COLORS);
985

986 987
                GlobalUnlock(lpSource->hData);
            }
988 989
            ReleaseDC(NULL, hdc);

990
            if (hData)
991
            {
992
                X11DRV_CLIPBOARD_InsertClipboardData(CF_BITMAP, hData, 0, NULL, TRUE);
993 994 995 996 997 998 999 1000 1001
                bret = TRUE;
            }
        }
    }

    return bret;
}


1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
/**************************************************************************
 *                      X11DRV_CLIPBOARD_RenderSynthesizedEnhMetaFile
 */
static BOOL X11DRV_CLIPBOARD_RenderSynthesizedEnhMetaFile(Display *display)
{
    LPWINE_CLIPDATA lpSource = NULL;

    TRACE("\n");

    if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_ENHMETAFILE)) && lpSource->hData)
        return TRUE;
    /* If we have a MF pict and it's not synthesized or it has been rendered */
    else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_METAFILEPICT)) &&
        (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData))
    {
        /* Render source if required */
        if (lpSource->hData || X11DRV_CLIPBOARD_RenderFormat(display, lpSource))
        {
            METAFILEPICT *pmfp;
            HENHMETAFILE hData = NULL;

            pmfp = GlobalLock(lpSource->hData);
            if (pmfp)
            {
                UINT size_mf_bits = GetMetaFileBitsEx(pmfp->hMF, 0, NULL);
                void *mf_bits = HeapAlloc(GetProcessHeap(), 0, size_mf_bits);
                if (mf_bits)
                {
                    GetMetaFileBitsEx(pmfp->hMF, size_mf_bits, mf_bits);
                    hData = SetWinMetaFileBits(size_mf_bits, mf_bits, NULL, pmfp);
                    HeapFree(GetProcessHeap(), 0, mf_bits);
                }
                GlobalUnlock(lpSource->hData);
            }

            if (hData)
            {
                X11DRV_CLIPBOARD_InsertClipboardData(CF_ENHMETAFILE, hData, 0, NULL, TRUE);
                return TRUE;
            }
        }
    }

    return FALSE;
}


1049
/**************************************************************************
1050
 *		X11DRV_CLIPBOARD_ImportXAString
1051
 *
1052 1053
 *  Import XA_STRING, converting the string to CF_TEXT.
 */
1054
static HANDLE X11DRV_CLIPBOARD_ImportXAString(Display *display, Window w, Atom prop)
1055 1056
{
    LPBYTE lpdata;
1057
    unsigned long cbytes;
1058
    LPSTR lpstr;
1059
    unsigned long i, inlcount = 0;
1060 1061
    HANDLE hText = 0;

1062
    if (!X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
        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
 *
1096
 *  Import XA_STRING, converting the string to CF_UNICODE.
1097
 */
1098
static HANDLE X11DRV_CLIPBOARD_ImportUTF8(Display *display, Window w, Atom prop)
1099
{
1100
    LPBYTE lpdata;
1101
    unsigned long cbytes;
1102
    LPSTR lpstr;
1103
    unsigned long i, inlcount = 0;
1104
    HANDLE hUnicodeText = 0;
1105

1106
    if (!X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1107 1108 1109
        return 0;

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

1115
    if ((lpstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbytes + inlcount + 1)))
1116 1117 1118
    {
        UINT count;

1119
        for (i = 0, inlcount = 0; i <= cbytes; i++)
1120 1121 1122 1123 1124 1125 1126
        {
            if (lpdata[i] == '\n')
                lpstr[inlcount++] = '\r';

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

1127 1128
        count = MultiByteToWideChar(CP_UTF8, 0, lpstr, -1, NULL, 0);
        hUnicodeText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, count * sizeof(WCHAR));
1129

1130 1131
        if (hUnicodeText)
        {
1132
            WCHAR *textW = GlobalLock(hUnicodeText);
1133
            MultiByteToWideChar(CP_UTF8, 0, lpstr, -1, textW, count);
1134 1135 1136 1137 1138 1139
            GlobalUnlock(hUnicodeText);
        }

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

1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
    /* Free the retrieved property data */
    HeapFree(GetProcessHeap(), 0, lpdata);

    return hUnicodeText;
}


/**************************************************************************
 *		X11DRV_CLIPBOARD_ImportCompoundText
 *
 *  Import COMPOUND_TEXT to CF_UNICODE
 */
1152
static HANDLE X11DRV_CLIPBOARD_ImportCompoundText(Display *display, Window w, Atom prop)
1153
{
1154
    int i, j, ret;
1155 1156 1157 1158 1159 1160
    char** srcstr;
    int count, lcount;
    int srclen, destlen;
    HANDLE hUnicodeText;
    XTextProperty txtprop;

1161
    if (!X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &txtprop.value, &txtprop.nitems))
1162 1163 1164 1165
    {
        return 0;
    }

1166 1167 1168
    txtprop.encoding = x11drv_atom(COMPOUND_TEXT);
    txtprop.format = 8;
    wine_tsx11_lock();
1169
    ret = XmbTextPropertyToTextList(display, &txtprop, &srcstr, &count);
1170
    wine_tsx11_unlock();
1171
    HeapFree(GetProcessHeap(), 0, txtprop.value);
1172
    if (ret != Success || !count) return 0;
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210

    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();

1211
    return hUnicodeText;
1212
}
1213

1214

1215
/**************************************************************************
1216 1217 1218
 *		X11DRV_CLIPBOARD_ImportXAPIXMAP
 *
 *  Import XA_PIXMAP, converting the image to CF_DIB.
1219
 */
1220
static HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(Display *display, Window w, Atom prop)
1221
{
1222 1223 1224
    HWND hwnd;
    HDC hdc;
    LPBYTE lpdata;
1225
    unsigned long cbytes;
1226 1227 1228
    Pixmap *pPixmap;
    HANDLE hClipData = 0;

1229
    if (X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1230 1231
    {
        pPixmap = (Pixmap *) lpdata;
1232

1233 1234
        hwnd = GetOpenClipboardWindow();
        hdc = GetDC(hwnd);
1235

1236 1237 1238 1239 1240 1241
        hClipData = X11DRV_DIB_CreateDIBFromPixmap(*pPixmap, hdc);
        ReleaseDC(hwnd, hdc);

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

1243
    return hClipData;
1244 1245 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 1284 1285 1286 1287 1288 1289 1290 1291 1292
/**************************************************************************
 *		X11DRV_CLIPBOARD_ImportImageBmp
 *
 *  Import image/bmp, converting the image to CF_DIB.
 */
static HANDLE X11DRV_CLIPBOARD_ImportImageBmp(Display *display, Window w, Atom prop)
{
    LPBYTE lpdata;
    unsigned long cbytes;
    HANDLE hClipData = 0;

    if (X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
    {
        BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)lpdata;

        if (cbytes >= sizeof(BITMAPFILEHEADER)+sizeof(BITMAPCOREHEADER) &&
            bfh->bfType == 0x4d42 /* "BM" */)
        {
            BITMAPINFO *bmi = (BITMAPINFO*)(bfh+1);
            HBITMAP hbmp;
            HDC hdc;

            hdc = GetDC(0);
            hbmp = CreateDIBitmap(
                hdc,
                &(bmi->bmiHeader),
                CBM_INIT,
                lpdata+bfh->bfOffBits,
                bmi,
                DIB_RGB_COLORS
                );

            hClipData = X11DRV_DIB_CreateDIBFromBitmap(hdc, hbmp);

            DeleteObject(hbmp);
            ReleaseDC(0, hdc);
        }

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

    return hClipData;
}


1293 1294 1295 1296 1297
/**************************************************************************
 *		X11DRV_CLIPBOARD_ImportMetaFilePict
 *
 *  Import MetaFilePict.
 */
1298
static HANDLE X11DRV_CLIPBOARD_ImportMetaFilePict(Display *display, Window w, Atom prop)
1299
{
1300
    LPBYTE lpdata;
1301
    unsigned long cbytes;
1302 1303
    HANDLE hClipData = 0;

1304
    if (X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1305 1306
    {
        if (cbytes)
1307
            hClipData = X11DRV_CLIPBOARD_SerializeMetafile(CF_METAFILEPICT, lpdata, (LPDWORD)&cbytes, FALSE);
1308 1309 1310 1311 1312 1313

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

    return hClipData;
1314 1315 1316 1317 1318 1319 1320 1321
}


/**************************************************************************
 *		X11DRV_ImportEnhMetaFile
 *
 *  Import EnhMetaFile.
 */
1322
static HANDLE X11DRV_CLIPBOARD_ImportEnhMetaFile(Display *display, Window w, Atom prop)
1323
{
1324
    LPBYTE lpdata;
1325
    unsigned long cbytes;
1326 1327
    HANDLE hClipData = 0;

1328
    if (X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1329 1330
    {
        if (cbytes)
1331
            hClipData = X11DRV_CLIPBOARD_SerializeMetafile(CF_ENHMETAFILE, lpdata, (LPDWORD)&cbytes, FALSE);
1332 1333 1334 1335 1336 1337

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

    return hClipData;
1338 1339 1340 1341 1342 1343 1344 1345
}


/**************************************************************************
 *		X11DRV_ImportClipbordaData
 *
 *  Generic import clipboard data routine.
 */
1346
static HANDLE X11DRV_CLIPBOARD_ImportClipboardData(Display *display, Window w, Atom prop)
1347 1348
{
    LPVOID lpClipData;
1349
    LPBYTE lpdata;
1350
    unsigned long cbytes;
1351 1352
    HANDLE hClipData = 0;

1353
    if (X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1354
    {
1355
        if (cbytes)
1356
        {
1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371
            /* 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;
            }
1372
        }
1373 1374 1375

        /* Free the retrieved property data */
        HeapFree(GetProcessHeap(), 0, lpdata);
1376 1377 1378 1379 1380 1381 1382
    }

    return hClipData;
}


/**************************************************************************
1383
 		X11DRV_CLIPBOARD_ExportClipboardData
1384 1385 1386
 *
 *  Generic export clipboard data routine.
 */
1387
static HANDLE X11DRV_CLIPBOARD_ExportClipboardData(Display *display, Window requestor, Atom aTarget,
1388
                                            Atom rprop, LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
1389 1390
{
    LPVOID lpClipData;
1391
    UINT datasize = 0;
1392 1393 1394 1395
    HANDLE hClipData = 0;

    *lpBytes = 0; /* Assume failure */

1396
    if (!X11DRV_CLIPBOARD_RenderFormat(display, lpData))
1397
        ERR("Failed to export %04x format\n", lpData->wFormatID);
1398 1399
    else
    {
1400
        datasize = GlobalSize(lpData->hData);
1401

1402
        hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, datasize);
1403
        if (hClipData == 0) return NULL;
1404 1405 1406

        if ((lpClipData = GlobalLock(hClipData)))
        {
1407
            LPVOID lpdata = GlobalLock(lpData->hData);
1408

1409 1410
            memcpy(lpClipData, lpdata, datasize);
            *lpBytes = datasize;
1411

1412
            GlobalUnlock(lpData->hData);
1413
            GlobalUnlock(hClipData);
1414 1415 1416
        } else {
            GlobalFree(hClipData);
            hClipData = 0;
1417
        }
1418
    }
1419

1420 1421
    return hClipData;
}
1422 1423


1424 1425 1426
/**************************************************************************
 *		X11DRV_CLIPBOARD_ExportXAString
 *
1427
 *  Export CF_TEXT converting the string to XA_STRING.
1428
 *  Helper function for X11DRV_CLIPBOARD_ExportString.
1429
 */
1430
static HANDLE X11DRV_CLIPBOARD_ExportXAString(LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
1431 1432 1433 1434 1435 1436 1437
{
    UINT i, j;
    UINT size;
    LPSTR text, lpstr = NULL;

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

1438
    text = GlobalLock(lpData->hData);
1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456
    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:
1457
    GlobalUnlock(lpData->hData);
1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469

    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)
1470
{
1471
    UINT i, j;
1472 1473
    UINT size;
    LPWSTR uni_text;
1474
    LPSTR text, lpstr = NULL;
1475 1476 1477

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

1478
    uni_text = GlobalLock(lpData->hData);
1479

1480
    size = WideCharToMultiByte(CP_UTF8, 0, uni_text, -1, NULL, 0, NULL, NULL);
1481 1482

    text = HeapAlloc(GetProcessHeap(), 0, size);
1483 1484 1485
    if (!text)
        goto done;
    WideCharToMultiByte(CP_UTF8, 0, uni_text, -1, text, size, NULL, NULL);
1486 1487

    /* remove carriage returns */
1488 1489 1490
    lpstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size--);
    if (lpstr == NULL)
        goto done;
1491

1492
    for (i = 0,j = 0; i < size && text[i]; i++)
1493
    {
1494 1495
        if (text[i] == '\r' && (text[i+1] == '\n' || text[i+1] == '\0'))
            continue;
1496 1497 1498 1499 1500 1501
        lpstr[j++] = text[i];
    }
    lpstr[j]='\0';

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

1502
done:
1503
    HeapFree(GetProcessHeap(), 0, text);
1504
    GlobalUnlock(lpData->hData);
1505 1506 1507 1508 1509

    return lpstr;
}


1510

1511 1512 1513
/**************************************************************************
 *		X11DRV_CLIPBOARD_ExportCompoundText
 *
1514
 *  Export CF_UNICODE to COMPOUND_TEXT
1515 1516
 *  Helper function for X11DRV_CLIPBOARD_ExportString.
 */
1517
static HANDLE X11DRV_CLIPBOARD_ExportCompoundText(Display *display, Window requestor, Atom aTarget, Atom rprop,
1518 1519 1520 1521 1522
    LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
{
    char* lpstr = 0;
    XTextProperty prop;
    XICCEncodingStyle style;
1523 1524 1525 1526
    UINT i, j;
    UINT size;
    LPWSTR uni_text;

1527
    uni_text = GlobalLock(lpData->hData);
1528 1529 1530 1531 1532

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

1534
    WideCharToMultiByte(CP_UNIXCP, 0, uni_text, -1, lpstr, size, NULL, NULL);
1535

1536 1537
    /* remove carriage returns */
    for (i = 0, j = 0; i < size && lpstr[i]; i++)
1538
    {
1539 1540 1541 1542 1543
        if (lpstr[i] == '\r' && (lpstr[i+1] == '\n' || lpstr[i+1] == '\0'))
            continue;
        lpstr[j++] = lpstr[i];
    }
    lpstr[j]='\0';
1544

1545
    GlobalUnlock(lpData->hData);
1546

1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557
    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);
1558
    }
1559 1560 1561
    wine_tsx11_unlock();

    HeapFree(GetProcessHeap(), 0, lpstr);
1562 1563 1564 1565 1566 1567 1568

    return 0;
}

/**************************************************************************
 *		X11DRV_CLIPBOARD_ExportString
 *
1569
 *  Export string
1570
 */
1571
static HANDLE X11DRV_CLIPBOARD_ExportString(Display *display, Window requestor, Atom aTarget, Atom rprop,
1572
                                     LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
1573
{
1574
    if (X11DRV_CLIPBOARD_RenderFormat(display, lpData))
1575 1576 1577
    {
        if (aTarget == XA_STRING)
            return X11DRV_CLIPBOARD_ExportXAString(lpData, lpBytes);
1578
        else if (aTarget == x11drv_atom(COMPOUND_TEXT) || aTarget == x11drv_atom(TEXT))
1579
            return X11DRV_CLIPBOARD_ExportCompoundText(display, requestor, aTarget,
1580 1581
                rprop, lpData, lpBytes);
        else
1582 1583 1584 1585
        {
            TRACE("Exporting target %ld to default UTF8_STRING\n", aTarget);
            return X11DRV_CLIPBOARD_ExportUTF8String(lpData, lpBytes);
        }
1586 1587
    }
    else
1588
        ERR("Failed to render %04x format\n", lpData->wFormatID);
1589 1590 1591 1592 1593

    return 0;
}


1594 1595 1596 1597 1598
/**************************************************************************
 *		X11DRV_CLIPBOARD_ExportXAPIXMAP
 *
 *  Export CF_DIB to XA_PIXMAP.
 */
1599
static HANDLE X11DRV_CLIPBOARD_ExportXAPIXMAP(Display *display, Window requestor, Atom aTarget, Atom rprop,
1600
    LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
1601 1602
{
    HDC hdc;
1603 1604
    HANDLE hData;
    unsigned char* lpData;
1605

1606
    if (!X11DRV_CLIPBOARD_RenderFormat(display, lpdata))
1607
    {
1608
        ERR("Failed to export %04x format\n", lpdata->wFormatID);
1609 1610 1611
        return 0;
    }

1612 1613 1614 1615
    if (!lpdata->drvData) /* If not already rendered */
    {
        /* For convert from packed DIB to Pixmap */
        hdc = GetDC(0);
1616
        lpdata->drvData = (UINT) X11DRV_DIB_CreatePixmapFromDIB(lpdata->hData, hdc);
1617 1618
        ReleaseDC(0, hdc);
    }
1619

1620
    *lpBytes = sizeof(Pixmap); /* pixmap is a 32bit value */
1621

1622 1623 1624 1625 1626
    /* Wrap pixmap so we can return a handle */
    hData = GlobalAlloc(0, *lpBytes);
    lpData = GlobalLock(hData);
    memcpy(lpData, &lpdata->drvData, *lpBytes);
    GlobalUnlock(hData);
1627

1628
    return hData;
1629 1630 1631
}


1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654
/**************************************************************************
 *		X11DRV_CLIPBOARD_ExportImageBmp
 *
 *  Export CF_DIB to image/bmp.
 */
static HANDLE X11DRV_CLIPBOARD_ExportImageBmp(Display *display, Window requestor, Atom aTarget, Atom rprop,
    LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
{
    HANDLE hpackeddib;
    LPBYTE dibdata;
    UINT bmpsize;
    HANDLE hbmpdata;
    LPBYTE bmpdata;
    BITMAPFILEHEADER *bfh;

    *lpBytes = 0;

    if (!X11DRV_CLIPBOARD_RenderFormat(display, lpdata))
    {
        ERR("Failed to export %04x format\n", lpdata->wFormatID);
        return 0;
    }

1655
    hpackeddib = lpdata->hData;
1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700

    dibdata = GlobalLock(hpackeddib);
    if (!dibdata)
    {
        ERR("Failed to lock packed DIB\n");
        return 0;
    }

    bmpsize = sizeof(BITMAPFILEHEADER) + GlobalSize(hpackeddib);

    hbmpdata = GlobalAlloc(0, bmpsize);

    if (hbmpdata)
    {
        bmpdata = GlobalLock(hbmpdata);

        if (!bmpdata)
        {
            GlobalFree(hbmpdata);
            GlobalUnlock(hpackeddib);
            return 0;
        }

        /* bitmap file header */
        bfh = (BITMAPFILEHEADER*)bmpdata;
        bfh->bfType = 0x4d42; /* "BM" */
        bfh->bfSize = bmpsize;
        bfh->bfReserved1 = 0;
        bfh->bfReserved2 = 0;
        bfh->bfOffBits = sizeof(BITMAPFILEHEADER) + bitmap_info_size((BITMAPINFO*)dibdata, DIB_RGB_COLORS);

        /* rest of bitmap is the same as the packed dib */
        memcpy(bfh+1, dibdata, bmpsize-sizeof(BITMAPFILEHEADER));

        *lpBytes = bmpsize;

        GlobalUnlock(hbmpdata);
    }

    GlobalUnlock(hpackeddib);

    return hbmpdata;
}


1701 1702 1703 1704 1705
/**************************************************************************
 *		X11DRV_CLIPBOARD_ExportMetaFilePict
 *
 *  Export MetaFilePict.
 */
1706
static HANDLE X11DRV_CLIPBOARD_ExportMetaFilePict(Display *display, Window requestor, Atom aTarget, Atom rprop,
1707
                                           LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
1708
{
1709
    if (!X11DRV_CLIPBOARD_RenderFormat(display, lpdata))
1710
    {
1711
        ERR("Failed to export %04x format\n", lpdata->wFormatID);
1712 1713 1714
        return 0;
    }

1715
    return X11DRV_CLIPBOARD_SerializeMetafile(CF_METAFILEPICT, lpdata->hData, lpBytes, TRUE);
1716 1717 1718 1719 1720 1721 1722 1723
}


/**************************************************************************
 *		X11DRV_CLIPBOARD_ExportEnhMetaFile
 *
 *  Export EnhMetaFile.
 */
1724
static HANDLE X11DRV_CLIPBOARD_ExportEnhMetaFile(Display *display, Window requestor, Atom aTarget, Atom rprop,
1725
                                          LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
1726
{
1727
    if (!X11DRV_CLIPBOARD_RenderFormat(display, lpdata))
1728
    {
1729
        ERR("Failed to export %04x format\n", lpdata->wFormatID);
1730 1731
        return 0;
    }
1732

1733
    return X11DRV_CLIPBOARD_SerializeMetafile(CF_ENHMETAFILE, lpdata->hData, lpBytes, TRUE);
1734
}
1735 1736


1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782
/**************************************************************************
 *		get_html_description_field
 *
 *  Find the value of a field in an HTML Format description.
 */
static LPCSTR get_html_description_field(LPCSTR data, LPCSTR keyword)
{
    LPCSTR pos=data;

    while (pos && *pos && *pos != '<')
    {
        if (memcmp(pos, keyword, strlen(keyword)) == 0)
            return pos+strlen(keyword);

        pos = strchr(pos, '\n');
        if (pos) pos++;
    }

    return NULL;
}


/**************************************************************************
 *		X11DRV_CLIPBOARD_ExportTextHtml
 *
 *  Export HTML Format to text/html.
 *
 * FIXME: We should attempt to add an <a base> tag and convert windows paths.
 */
static HANDLE X11DRV_CLIPBOARD_ExportTextHtml(Display *display, Window requestor, Atom aTarget,
    Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
{
    HANDLE hdata;
    LPCSTR data, field_value;
    UINT fragmentstart, fragmentend, htmlsize;
    HANDLE hhtmldata=NULL;
    LPSTR htmldata;

    *lpBytes = 0;

    if (!X11DRV_CLIPBOARD_RenderFormat(display, lpdata))
    {
        ERR("Failed to export %04x format\n", lpdata->wFormatID);
        return 0;
    }

1783
    hdata = lpdata->hData;
1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840

    data = GlobalLock(hdata);
    if (!data)
    {
        ERR("Failed to lock HTML Format data\n");
        return 0;
    }

    /* read the important fields */
    field_value = get_html_description_field(data, "StartFragment:");
    if (!field_value)
    {
        ERR("Couldn't find StartFragment value\n");
        goto end;
    }
    fragmentstart = atoi(field_value);

    field_value = get_html_description_field(data, "EndFragment:");
    if (!field_value)
    {
        ERR("Couldn't find EndFragment value\n");
        goto end;
    }
    fragmentend = atoi(field_value);

    /* export only the fragment */
    htmlsize = fragmentend - fragmentstart + 1;

    hhtmldata = GlobalAlloc(0, htmlsize);

    if (hhtmldata)
    {
        htmldata = GlobalLock(hhtmldata);

        if (!htmldata)
        {
            GlobalFree(hhtmldata);
            htmldata = NULL;
            goto end;
        }

        memcpy(htmldata, &data[fragmentstart], fragmentend-fragmentstart);
        htmldata[htmlsize-1] = '\0';

        *lpBytes = htmlsize;

        GlobalUnlock(htmldata);
    }

end:

    GlobalUnlock(hdata);

    return hhtmldata;
}


1841 1842 1843
/**************************************************************************
 *		X11DRV_CLIPBOARD_QueryTargets
 */
1844 1845
static BOOL X11DRV_CLIPBOARD_QueryTargets(Display *display, Window w, Atom selection,
    Atom target, XEvent *xe)
1846 1847 1848
{
    INT i;
    Bool res;
1849

1850
    wine_tsx11_lock();
1851 1852
    XConvertSelection(display, selection, target,
        x11drv_atom(SELECTION_DATA), w, CurrentTime);
1853
    wine_tsx11_unlock();
1854

1855 1856
    /*
     * Wait until SelectionNotify is received
1857
     */
1858
    for (i = 0; i < SELECTION_RETRIES; i++)
1859
    {
1860 1861 1862 1863
        wine_tsx11_lock();
        res = XCheckTypedWindowEvent(display, w, SelectionNotify, xe);
        wine_tsx11_unlock();
        if (res && xe->xselection.selection == selection) break;
1864

1865
        usleep(SELECTION_WAIT);
1866 1867
    }

1868 1869 1870 1871 1872
    if (i == SELECTION_RETRIES)
    {
        ERR("Timed out waiting for SelectionNotify event\n");
        return FALSE;
    }
1873
    /* Verify that the selection returned a valid TARGETS property */
1874
    if ((xe->xselection.target != target) || (xe->xselection.property == None))
1875 1876 1877 1878 1879
    {
        /* Selection owner failed to respond or we missed the SelectionNotify */
        WARN("Failed to retrieve TARGETS for selection %ld.\n", selection);
        return FALSE;
    }
1880

1881 1882 1883 1884
    return TRUE;
}


1885 1886 1887 1888 1889
static int is_atom_error( Display *display, XErrorEvent *event, void *arg )
{
    return (event->error_code == BadAtom);
}

1890 1891 1892
/**************************************************************************
 *		X11DRV_CLIPBOARD_InsertSelectionProperties
 *
1893
 * Mark properties available for future retrieval.
1894 1895 1896
 */
static VOID X11DRV_CLIPBOARD_InsertSelectionProperties(Display *display, Atom* properties, UINT count)
{
1897
     UINT i, nb_atoms = 0;
1898 1899 1900 1901 1902
     Atom *atoms = NULL;

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

1905 1906 1907 1908 1909 1910 1911 1912 1913 1914
         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)
             {
1915 1916
                 TRACE("Atom#%d Property(%d): --> Format %s\n",
                       i, lpFormat->drvData, debugstr_format(lpFormat->wFormatID));
1917
                 X11DRV_CLIPBOARD_InsertClipboardData(lpFormat->wFormatID, 0, 0, lpFormat, FALSE);
1918 1919 1920
                 lpFormat = X11DRV_CLIPBOARD_LookupProperty(lpFormat, properties[i]);
             }
         }
1921
         else if (properties[i])
1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935
         {
             /* 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)
         {
1936 1937 1938 1939 1940 1941 1942
             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;
             }
1943 1944
             for (i = 0; i < nb_atoms; i++)
             {
Jacek Caban's avatar
Jacek Caban committed
1945 1946 1947 1948 1949 1950
                 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);

1951
                 lpFormat = register_format( RegisterClipboardFormatW(wname), atoms[i] );
Jacek Caban's avatar
Jacek Caban committed
1952
                 HeapFree(GetProcessHeap(), 0, wname);
1953 1954 1955 1956 1957
                 if (!lpFormat)
                 {
                     ERR("Failed to register %s property. Type will not be cached.\n", names[i]);
                     continue;
                 }
1958 1959
                 TRACE("Atom#%d Property(%d): --> Format %s\n",
                       i, lpFormat->drvData, debugstr_format(lpFormat->wFormatID));
1960
                 X11DRV_CLIPBOARD_InsertClipboardData(lpFormat->wFormatID, 0, 0, lpFormat, FALSE);
1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971
             }
             wine_tsx11_lock();
             for (i = 0; i < nb_atoms; i++) XFree( names[i] );
             wine_tsx11_unlock();
             HeapFree( GetProcessHeap(), 0, names );
         }
         HeapFree( GetProcessHeap(), 0, atoms );
     }
}


1972
/**************************************************************************
1973
 *		X11DRV_CLIPBOARD_QueryAvailableData
1974 1975 1976 1977 1978
 *
 * 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.
 */
1979
static int X11DRV_CLIPBOARD_QueryAvailableData(Display *display, LPCLIPBOARDINFO lpcbinfo)
1980 1981 1982 1983 1984 1985 1986
{
    XEvent         xe;
    Atom           atype=AnyPropertyType;
    int		   aformat;
    unsigned long  remain;
    Atom*	   targetList=NULL;
    Window         w;
1987
    unsigned long  cSelectionTargets = 0;
1988

1989 1990 1991 1992
    if (selectionAcquired & (S_PRIMARY | S_CLIPBOARD))
    {
        ERR("Received request to cache selection but process is owner=(%08x)\n", 
            (unsigned) selectionWindow);
1993
        return -1; /* Prevent self request */
1994
    }
1995

1996 1997
    w = thread_selection_wnd();
    if (!w)
1998
    {
1999
        ERR("No window available to retrieve selection!\n");
2000
        return -1;
2001 2002
    }

2003 2004 2005
    /*
     * Query the selection owner for the TARGETS property
     */
2006
    wine_tsx11_lock();
2007
    if ((use_primary_selection && XGetSelectionOwner(display,XA_PRIMARY)) ||
2008
        XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)))
2009
    {
2010
        wine_tsx11_unlock();
2011
        if (use_primary_selection && (X11DRV_CLIPBOARD_QueryTargets(display, w, XA_PRIMARY, x11drv_atom(TARGETS), &xe)))
2012
            selectionCacheSrc = XA_PRIMARY;
2013
        else if (X11DRV_CLIPBOARD_QueryTargets(display, w, x11drv_atom(CLIPBOARD), x11drv_atom(TARGETS), &xe))
2014 2015
            selectionCacheSrc = x11drv_atom(CLIPBOARD);
        else
2016
        {
2017
            Atom xstr = XA_STRING;
2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037

            /* 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;
            }
        }
2038 2039
    }
    else /* No selection owner so report 0 targets available */
2040 2041
    {
        wine_tsx11_unlock();
2042
        return 0;
2043
    }
2044 2045

    /* Read the TARGETS property contents */
2046 2047
    wine_tsx11_lock();
    if(XGetWindowProperty(display, xe.xselection.requestor, xe.xselection.property,
2048 2049 2050
        0, 0x3FFF, True, AnyPropertyType/*XA_ATOM*/, &atype, &aformat, &cSelectionTargets, 
        &remain, (unsigned char**)&targetList) != Success)
    {
2051
        wine_tsx11_unlock();
2052 2053
        WARN("Failed to read TARGETS property\n");
    }
2054 2055
    else
    {
2056
        wine_tsx11_unlock();
2057 2058
       TRACE("Type %lx,Format %d,nItems %ld, Remain %ld\n",
             atype, aformat, cSelectionTargets, remain);
2059 2060 2061 2062
       /*
        * The TARGETS property should have returned us a list of atoms
        * corresponding to each selection target format supported.
        */
2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078
       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 );
           }
       }
2079 2080

       /* Free the list of targets */
2081 2082 2083
       wine_tsx11_lock();
       XFree(targetList);
       wine_tsx11_unlock();
2084
    }
2085

2086
    return cSelectionTargets;
2087 2088
}

2089 2090

/**************************************************************************
2091
 *	X11DRV_CLIPBOARD_ReadSelectionData
2092 2093 2094 2095 2096 2097
 *
 * 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.
 */
2098
static BOOL X11DRV_CLIPBOARD_ReadSelectionData(Display *display, LPWINE_CLIPDATA lpData)
2099 2100
{
    Bool res;
2101 2102 2103 2104
    DWORD i;
    XEvent xe;
    BOOL bRet = FALSE;

2105
    TRACE("%04x\n", lpData->wFormatID);
2106

2107 2108
    if (!lpData->lpFormat)
    {
2109
        ERR("Requesting format %04x but no source format linked to data.\n",
2110 2111 2112
            lpData->wFormatID);
        return FALSE;
    }
2113 2114 2115

    if (!selectionAcquired)
    {
2116
        Window w = thread_selection_wnd();
2117 2118
        if(!w)
        {
2119
            ERR("No window available to read selection data!\n");
2120 2121 2122
            return FALSE;
        }

2123
        TRACE("Requesting conversion of %s property (%d) from selection type %08x\n",
2124 2125
              debugstr_format(lpData->lpFormat->wFormatID), lpData->lpFormat->drvData,
              (UINT)selectionCacheSrc);
2126

2127 2128 2129 2130
        wine_tsx11_lock();
        XConvertSelection(display, selectionCacheSrc, lpData->lpFormat->drvData,
            x11drv_atom(SELECTION_DATA), w, CurrentTime);
        wine_tsx11_unlock();
2131

2132 2133 2134
        /* wait until SelectionNotify is received */
        for (i = 0; i < SELECTION_RETRIES; i++)
        {
2135
            wine_tsx11_lock();
2136
            res = XCheckTypedWindowEvent(display, w, SelectionNotify, &xe);
2137
            wine_tsx11_unlock();
2138
            if (res && xe.xselection.selection == selectionCacheSrc) break;
2139

2140 2141
            usleep(SELECTION_WAIT);
        }
2142

2143 2144 2145 2146
        if (i == SELECTION_RETRIES)
        {
            ERR("Timed out waiting for SelectionNotify event\n");
        }
2147
        /* Verify that the selection returned a valid TARGETS property */
2148
        else if (xe.xselection.property != None)
2149 2150 2151 2152 2153 2154
        {
            /*
             *  Read the contents of the X selection property 
             *  into WINE's clipboard cache and converting the 
             *  data format if necessary.
             */
2155
             HANDLE hData = lpData->lpFormat->lpDrvImportFunc(display, xe.xselection.requestor,
2156
                 xe.xselection.property);
2157

2158 2159 2160 2161
             if (hData)
                 bRet = X11DRV_CLIPBOARD_InsertClipboardData(lpData->wFormatID, hData, 0, lpData->lpFormat, TRUE);
             else
                 TRACE("Import function failed\n");
2162 2163 2164 2165
        }
        else
        {
            TRACE("Failed to convert selection\n");
2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178
        }
    }
    else
    {
        ERR("Received request to cache selection data but process is owner\n");
    }

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

    return bRet;
}


2179
/**************************************************************************
2180 2181
 *		X11DRV_CLIPBOARD_GetProperty
 *  Gets type, data and size.
2182
 */
2183 2184
static BOOL X11DRV_CLIPBOARD_GetProperty(Display *display, Window w, Atom prop,
    Atom *atype, unsigned char** data, unsigned long* datasize)
2185
{
2186
    int aformat;
2187 2188
    unsigned long pos = 0, nitems, remain, count;
    unsigned char *val = NULL, *buffer;
2189

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

2192
    for (;;)
2193
    {
2194 2195
        wine_tsx11_lock();
        if (XGetWindowProperty(display, w, prop, pos, INT_MAX / 4, False,
2196
                               AnyPropertyType, atype, &aformat, &nitems, &remain, &buffer) != Success)
2197 2198 2199 2200 2201 2202
        {
            wine_tsx11_unlock();
            WARN("Failed to read property\n");
            HeapFree( GetProcessHeap(), 0, val );
            return FALSE;
        }
2203

2204
        count = get_property_size( aformat, nitems );
2205 2206
        if (!val) *data = HeapAlloc( GetProcessHeap(), 0, pos * sizeof(int) + count + 1 );
        else *data = HeapReAlloc( GetProcessHeap(), 0, val, pos * sizeof(int) + count + 1 );
2207

2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225
        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);
2226
    }
2227

2228 2229
    /* Delete the property on the window now that we are done
     * This will send a PropertyNotify event to the selection owner. */
2230
    wine_tsx11_lock();
2231
    XDeleteProperty(display, w, prop);
2232
    wine_tsx11_unlock();
2233
    return TRUE;
2234
}
2235 2236


2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316
/**************************************************************************
 *		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;
}


2317 2318 2319 2320 2321 2322
/**************************************************************************
 *		CLIPBOARD_SerializeMetafile
 */
static HANDLE X11DRV_CLIPBOARD_SerializeMetafile(INT wformat, HANDLE hdata, LPDWORD lpcbytes, BOOL out)
{
    HANDLE h = 0;
2323

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

2326 2327 2328
    if (out) /* Serialize out, caller should free memory */
    {
        *lpcbytes = 0; /* Assume failure */
2329

2330 2331
        if (wformat == CF_METAFILEPICT)
        {
2332
            LPMETAFILEPICT lpmfp = GlobalLock(hdata);
2333
            unsigned int size = GetMetaFileBitsEx(lpmfp->hMF, 0, NULL);
2334

2335 2336 2337 2338
            h = GlobalAlloc(0, size + sizeof(METAFILEPICT));
            if (h)
            {
                char *pdata = GlobalLock(h);
2339

2340 2341
                memcpy(pdata, lpmfp, sizeof(METAFILEPICT));
                GetMetaFileBitsEx(lpmfp->hMF, size, pdata + sizeof(METAFILEPICT));
2342

2343
                *lpcbytes = size + sizeof(METAFILEPICT);
2344

2345 2346
                GlobalUnlock(h);
            }
2347

2348 2349 2350 2351 2352
            GlobalUnlock(hdata);
        }
        else if (wformat == CF_ENHMETAFILE)
        {
            int size = GetEnhMetaFileBits(hdata, 0, NULL);
2353

2354 2355 2356 2357
            h = GlobalAlloc(0, size);
            if (h)
            {
                LPVOID pdata = GlobalLock(h);
2358

2359 2360
                GetEnhMetaFileBits(hdata, size, pdata);
                *lpcbytes = size;
2361

2362 2363 2364
                GlobalUnlock(h);
            }
        }
2365
    }
2366 2367
    else
    {
2368 2369 2370 2371 2372
        if (wformat == CF_METAFILEPICT)
        {
            h = GlobalAlloc(0, sizeof(METAFILEPICT));
            if (h)
            {
2373
                unsigned int wiresize;
2374
                LPMETAFILEPICT lpmfp = GlobalLock(h);
2375

2376
                memcpy(lpmfp, hdata, sizeof(METAFILEPICT));
2377 2378
                wiresize = *lpcbytes - sizeof(METAFILEPICT);
                lpmfp->hMF = SetMetaFileBitsEx(wiresize,
2379
                    ((const BYTE *)hdata) + sizeof(METAFILEPICT));
2380 2381 2382 2383 2384
                GlobalUnlock(h);
            }
        }
        else if (wformat == CF_ENHMETAFILE)
        {
2385
            h = SetEnhMetaFileBits(*lpcbytes, hdata);
2386 2387 2388 2389
        }
    }

    return h;
2390 2391
}

2392

2393 2394 2395
/**************************************************************************
 *		X11DRV_CLIPBOARD_ReleaseSelection
 *
2396
 * Release XA_CLIPBOARD and XA_PRIMARY in response to a SelectionClear event.
2397
 */
2398
static void X11DRV_CLIPBOARD_ReleaseSelection(Display *display, Atom selType, Window w, HWND hwnd, Time time)
2399
{
2400
    /* w is the window that lost the selection
2401
     */
2402 2403
    TRACE("event->window = %08x (selectionWindow = %08x) selectionAcquired=0x%08x\n",
	  (unsigned)w, (unsigned)selectionWindow, (unsigned)selectionAcquired);
2404

2405
    if (selectionAcquired && (w == selectionWindow))
2406
    {
2407 2408 2409 2410 2411 2412 2413
        CLIPBOARDINFO cbinfo;

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

        X11DRV_CLIPBOARD_GetClipboardInfo(&cbinfo);

2414
        if (cbinfo.flags & CB_PROCESS)
2415
        {
2416
            /* Since we're still the owner, this wasn't initiated by
2417 2418
               another Wine process */
            if (OpenClipboard(hwnd))
2419
            {
2420 2421
                /* Destroy private objects */
                SendMessageW(cbinfo.hWndOwner, WM_DESTROYCLIPBOARD, 0, 0);
2422

2423 2424 2425 2426 2427
                /* Give up ownership of the windows clipboard */
                X11DRV_CLIPBOARD_ReleaseOwnership();
                CloseClipboard();
            }
        }
2428

2429 2430 2431
        if ((selType == x11drv_atom(CLIPBOARD)) && (selectionAcquired & S_PRIMARY))
        {
            TRACE("Lost clipboard. Check if we need to release PRIMARY\n");
2432

2433 2434 2435 2436 2437
            wine_tsx11_lock();
            if (selectionWindow == XGetSelectionOwner(display, XA_PRIMARY))
            {
                TRACE("We still own PRIMARY. Releasing PRIMARY.\n");
                XSetSelectionOwner(display, XA_PRIMARY, None, time);
2438
            }
2439 2440 2441 2442 2443 2444 2445 2446 2447 2448
            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)))
2449
            {
2450 2451
                TRACE("We still own CLIPBOARD. Releasing CLIPBOARD.\n");
                XSetSelectionOwner(display, x11drv_atom(CLIPBOARD), None, time);
2452
            }
2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463
            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;
2464
    }
2465
}
2466

2467

2468 2469 2470 2471 2472 2473 2474 2475
/**************************************************************************
 *		IsSelectionOwner (X11DRV.@)
 *
 * Returns: TRUE if the selection is owned by this process, FALSE otherwise
 */
static BOOL X11DRV_CLIPBOARD_IsSelectionOwner(void)
{
    return selectionAcquired;
2476 2477
}

2478 2479 2480 2481 2482 2483

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


2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518
static void selection_acquire(void)
{
    Window owner;
    Display *display;

    owner = thread_selection_wnd();
    display = thread_display();

    wine_tsx11_lock();

    selectionAcquired = 0;
    selectionWindow = 0;

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

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

    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)
    {
        selectionWindow = owner;
        TRACE("Grabbed X selection, owner=(%08x)\n", (unsigned) owner);
    }
}

2519
static DWORD WINAPI selection_thread_proc(LPVOID p)
2520
{
2521 2522 2523 2524
    HANDLE event = p;

    TRACE("\n");

2525
    selection_acquire();
2526
    SetEvent(event);
2527 2528 2529 2530 2531 2532 2533 2534

    while (selectionAcquired)
    {
        MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_SENDMESSAGE, 0);
    }

    return 0;
}
2535

2536
/**************************************************************************
2537
 *		AcquireClipboard (X11DRV.@)
2538
 */
2539
int CDECL X11DRV_AcquireClipboard(HWND hWndClipWindow)
2540
{
2541
    DWORD procid;
2542
    HANDLE selectionThread;
2543

2544 2545
    TRACE(" %p\n", hWndClipWindow);

2546
    /*
2547 2548 2549 2550
     * 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.
2551
     */
2552 2553
    if (hWndClipWindow &&
        GetCurrentThreadId() != GetWindowThreadProcessId(hWndClipWindow, &procid))
2554
    {
2555 2556 2557 2558 2559 2560
        if (procid != GetCurrentProcessId())
        {
            WARN("Setting clipboard owner to other process is not supported\n");
            hWndClipWindow = NULL;
        }
        else
2561
        {
2562
            TRACE("Thread %x is acquiring selection with thread %x's window %p\n",
2563
                GetCurrentThreadId(),
2564 2565 2566
                GetWindowThreadProcessId(hWndClipWindow, NULL), hWndClipWindow);

            return SendMessageW(hWndClipWindow, WM_X11DRV_ACQUIRE_SELECTION, 0, 0);
2567
        }
2568
    }
2569

2570 2571 2572 2573 2574 2575
    if (hWndClipWindow)
    {
        selection_acquire();
    }
    else
    {
2576
        HANDLE event = CreateEventW(NULL, FALSE, FALSE, NULL);
2577
        selectionThread = CreateThread(NULL, 0, selection_thread_proc, event, 0, NULL);
2578

2579 2580 2581 2582 2583
        if (!selectionThread)
        {
            WARN("Could not start clipboard thread\n");
            return 0;
        }
2584

2585 2586
        WaitForSingleObject(event, INFINITE);
        CloseHandle(event);
2587
        CloseHandle(selectionThread);
2588
    }
2589 2590

    return 1;
2591
}
2592

2593

2594
/**************************************************************************
2595
 *	X11DRV_EmptyClipboard
2596 2597
 *
 * Empty cached clipboard data. 
2598
 */
2599
void CDECL X11DRV_EmptyClipboard(BOOL keepunowned)
2600
{
2601
    WINE_CLIPDATA *data, *next;
2602

2603 2604 2605 2606 2607 2608 2609
    LIST_FOR_EACH_ENTRY_SAFE( data, next, &data_list, WINE_CLIPDATA, entry )
    {
        if (keepunowned && (data->wFlags & CF_FLAG_UNOWNED)) continue;
        list_remove( &data->entry );
        X11DRV_CLIPBOARD_FreeData( data );
        HeapFree( GetProcessHeap(), 0, data );
        ClipDataCount--;
2610
    }
2611

2612
    TRACE(" %d entries remaining in cache.\n", ClipDataCount);
2613
}
2614

2615

2616 2617 2618 2619

/**************************************************************************
 *		X11DRV_SetClipboardData
 */
2620
BOOL CDECL X11DRV_SetClipboardData(UINT wFormat, HANDLE hData, BOOL owner)
2621 2622 2623 2624 2625 2626 2627
{
    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)
2628
    {
2629 2630 2631 2632 2633
        CLIPBOARDINFO cbinfo;
        LPWINE_CLIPDATA lpRender;

        X11DRV_CLIPBOARD_UpdateCache(&cbinfo);

2634
        if (!hData ||
2635 2636 2637 2638 2639 2640
            ((lpRender = X11DRV_CLIPBOARD_LookupData(wFormat)) &&
            !(lpRender->wFlags & CF_FLAG_UNOWNED)))
            bResult = FALSE;
        else
            flags = CF_FLAG_UNOWNED;
    }
2641

2642
    bResult &= X11DRV_CLIPBOARD_InsertClipboardData(wFormat, hData, flags, NULL, TRUE);
2643 2644

    return bResult;
2645 2646
}

2647

2648
/**************************************************************************
2649
 *		CountClipboardFormats
2650
 */
2651
INT CDECL X11DRV_CountClipboardFormats(void)
2652
{
2653
    CLIPBOARDINFO cbinfo;
2654

2655 2656 2657
    X11DRV_CLIPBOARD_UpdateCache(&cbinfo);

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

2659
    return ClipDataCount;
2660 2661
}

2662

2663
/**************************************************************************
2664
 *		X11DRV_EnumClipboardFormats
2665
 */
2666
UINT CDECL X11DRV_EnumClipboardFormats(UINT wFormat)
2667
{
2668
    CLIPBOARDINFO cbinfo;
2669
    struct list *ptr = NULL;
2670 2671 2672 2673 2674 2675 2676

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

    X11DRV_CLIPBOARD_UpdateCache(&cbinfo);

    if (!wFormat)
    {
2677
        ptr = list_head( &data_list );
2678 2679 2680 2681
    }
    else
    {
        LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(wFormat);
2682
        if (lpData) ptr = list_next( &data_list, &lpData->entry );
2683 2684
    }

2685 2686
    if (!ptr) return 0;
    return LIST_ENTRY( ptr, WINE_CLIPDATA, entry )->wFormatID;
2687 2688
}

2689

2690
/**************************************************************************
2691
 *		X11DRV_IsClipboardFormatAvailable
2692
 */
2693
BOOL CDECL X11DRV_IsClipboardFormatAvailable(UINT wFormat)
2694
{
2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707
    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;
2708 2709
}

2710

2711
/**************************************************************************
2712
 *		GetClipboardData (USER.142)
2713
 */
2714
HANDLE CDECL X11DRV_GetClipboardData(UINT wFormat)
2715
{
2716 2717
    CLIPBOARDINFO cbinfo;
    LPWINE_CLIPDATA lpRender;
2718

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

2721 2722 2723
    X11DRV_CLIPBOARD_UpdateCache(&cbinfo);

    if ((lpRender = X11DRV_CLIPBOARD_LookupData(wFormat)))
2724
    {
2725
        if ( !lpRender->hData )
2726
            X11DRV_CLIPBOARD_RenderFormat(thread_init_display(), lpRender);
2727

2728 2729
        TRACE(" returning %p (type %04x)\n", lpRender->hData, lpRender->wFormatID);
        return lpRender->hData;
2730 2731 2732
    }

    return 0;
2733 2734
}

2735

2736
/**************************************************************************
2737
 *		ResetSelectionOwner
2738
 *
2739 2740 2741
 * 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.
2742
 */
2743
void X11DRV_ResetSelectionOwner(void)
2744
{
2745 2746
    HWND hwnd;
    DWORD procid;
2747

2748
    TRACE("\n");
2749

2750 2751
    if (!selectionAcquired  || thread_selection_wnd() != selectionWindow)
        return;
2752

2753 2754
    selectionAcquired = S_NOSELECTION;
    selectionWindow = 0;
2755

2756 2757
    hwnd = GetWindow(GetDesktopWindow(), GW_CHILD);
    do
2758
    {
2759
        if (GetCurrentThreadId() != GetWindowThreadProcessId(hwnd, &procid))
2760
        {
2761 2762 2763 2764 2765
            if (GetCurrentProcessId() == procid)
            {
                if (SendMessageW(hwnd, WM_X11DRV_ACQUIRE_SELECTION, 0, 0))
                    return;
            }
2766
        }
2767
    } while ((hwnd = GetWindow(hwnd, GW_HWNDNEXT)) != NULL);
2768

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

2771 2772
    X11DRV_CLIPBOARD_ReleaseOwnership();
    X11DRV_EmptyClipboard(FALSE);
2773 2774
}

2775 2776

/**************************************************************************
2777
 *                      X11DRV_CLIPBOARD_SynthesizeData
2778
 */
2779
static BOOL X11DRV_CLIPBOARD_SynthesizeData(UINT wFormatID)
2780
{
2781 2782
    BOOL bsyn = TRUE;
    LPWINE_CLIPDATA lpSource = NULL;
2783

2784
    TRACE(" %04x\n", wFormatID);
2785

2786 2787 2788
    /* Don't need to synthesize if it already exists */
    if (X11DRV_CLIPBOARD_LookupData(wFormatID))
        return TRUE;
2789

2790
    if (wFormatID == CF_UNICODETEXT || wFormatID == CF_TEXT || wFormatID == CF_OEMTEXT)
2791
    {
2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805
        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)
    {
2806
        bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_ENHMETAFILE)) &&
2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817
            ~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;
2818 2819
    }

2820
    if (bsyn)
2821
        X11DRV_CLIPBOARD_InsertClipboardData(wFormatID, 0, CF_FLAG_SYNTHESIZED, NULL, TRUE);
2822

2823
    return bsyn;
2824 2825 2826
}


2827

2828
/**************************************************************************
2829 2830 2831
 *              X11DRV_EndClipboardUpdate
 * TODO:
 *  Add locale if it hasn't already been added
2832
 */
2833
void CDECL X11DRV_EndClipboardUpdate(void)
2834
{
2835
    INT count = ClipDataCount;
2836

2837 2838 2839
    /* Do Unicode <-> Text <-> OEM mapping */
    X11DRV_CLIPBOARD_SynthesizeData(CF_TEXT);
    X11DRV_CLIPBOARD_SynthesizeData(CF_OEMTEXT);
2840
    X11DRV_CLIPBOARD_SynthesizeData(CF_UNICODETEXT);
2841

2842 2843 2844
    /* Enhmetafile <-> MetafilePict mapping */
    X11DRV_CLIPBOARD_SynthesizeData(CF_ENHMETAFILE);
    X11DRV_CLIPBOARD_SynthesizeData(CF_METAFILEPICT);
2845

2846 2847 2848
    /* DIB <-> Bitmap mapping */
    X11DRV_CLIPBOARD_SynthesizeData(CF_DIB);
    X11DRV_CLIPBOARD_SynthesizeData(CF_BITMAP);
2849

2850
    TRACE("%d formats added to cached data\n", ClipDataCount - count);
2851
}
2852 2853 2854 2855 2856 2857 2858 2859 2860


/***********************************************************************
 *           X11DRV_SelectionRequest_TARGETS
 *  Service a TARGETS selection request event
 */
static Atom X11DRV_SelectionRequest_TARGETS( Display *display, Window requestor,
                                             Atom target, Atom rprop )
{
2861
    UINT i;
2862 2863
    Atom* targets;
    ULONG cTargets;
2864
    LPWINE_CLIPFORMAT format;
2865
    LPWINE_CLIPDATA lpData;
2866

2867 2868 2869 2870 2871 2872 2873
    /* 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();

2874 2875 2876
    /*
     * Count the number of items we wish to expose as selection targets.
     */
2877
    cTargets = 1; /* Include TARGETS */
2878

2879
    if (!list_head( &data_list )) return None;
2880

2881
    LIST_FOR_EACH_ENTRY( lpData, &data_list, WINE_CLIPDATA, entry )
2882 2883 2884
        LIST_FOR_EACH_ENTRY( format, &format_list, WINE_CLIPFORMAT, entry )
            if ((format->wFormatID == lpData->wFormatID) &&
                format->lpDrvExportFunc && format->drvData)
2885
                cTargets++;
2886

2887
    TRACE(" found %d formats\n", cTargets);
2888 2889

    /* Allocate temp buffer */
2890
    targets = HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
2891 2892 2893
    if(targets == NULL)
        return None;

2894 2895 2896
    i = 0;
    targets[i++] = x11drv_atom(TARGETS);

2897
    LIST_FOR_EACH_ENTRY( lpData, &data_list, WINE_CLIPDATA, entry )
2898 2899 2900 2901
        LIST_FOR_EACH_ENTRY( format, &format_list, WINE_CLIPFORMAT, entry )
            if ((format->wFormatID == lpData->wFormatID) &&
                format->lpDrvExportFunc && format->drvData)
                targets[i++] = format->drvData;
2902 2903 2904 2905 2906 2907 2908 2909

    wine_tsx11_lock();

    if (TRACE_ON(clipboard))
    {
        unsigned int i;
        for ( i = 0; i < cTargets; i++)
        {
2910 2911 2912
            char *itemFmtName = XGetAtomName(display, targets[i]);
            TRACE("\tAtom# %d:  Property %ld Type %s\n", i, targets[i], itemFmtName);
            XFree(itemFmtName);
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
        }
    }

    /* 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
    {
2973 2974 2975 2976 2977 2978 2979
        if (TRACE_ON(clipboard))
        {
            char * const typeName = XGetAtomName(display, atype);
            TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
                  typeName, aformat, cTargetPropList, remain);
            XFree(typeName);
        }
2980 2981 2982 2983 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
        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 */
3022
                event = *pevent;
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 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090
                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
    {
3091
        LPWINE_CLIPFORMAT lpFormat = X11DRV_CLIPBOARD_LookupProperty(NULL, event->target);
3092 3093 3094 3095 3096 3097 3098 3099 3100

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

            if (lpData)
            {
                unsigned char* lpClipData;
                DWORD cBytes;
3101
                HANDLE hClipData = lpFormat->lpDrvExportFunc(display, request, event->target,
3102 3103 3104 3105
                                                             rprop, lpData, &cBytes);

                if (hClipData && (lpClipData = GlobalLock(hClipData)))
                {
3106 3107
                    int mode = PropModeReplace;

3108 3109
                    TRACE("\tUpdating property %s, %d bytes\n",
                          debugstr_format(lpFormat->wFormatID), cBytes);
3110
                    wine_tsx11_lock();
3111 3112 3113 3114 3115 3116 3117 3118 3119
                    do
                    {
                        int nelements = min(cBytes, 65536);
                        XChangeProperty(display, request, rprop, event->target,
                                        8, mode, lpClipData, nelements);
                        mode = PropModeAppend;
                        cBytes -= nelements;
                        lpClipData += nelements;
                    } while (cBytes > 0);
3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152
                    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
 */
3153
void X11DRV_SelectionRequest( HWND hWnd, XEvent *event )
3154
{
3155
    X11DRV_HandleSelectionRequest( hWnd, &event->xselectionrequest, FALSE );
3156 3157 3158 3159 3160 3161
}


/***********************************************************************
 *           X11DRV_SelectionClear
 */
3162
void X11DRV_SelectionClear( HWND hWnd, XEvent *xev )
3163
{
3164
    XSelectionClearEvent *event = &xev->xselectionclear;
3165
    if (event->selection == XA_PRIMARY || event->selection == x11drv_atom(CLIPBOARD))
3166 3167
        X11DRV_CLIPBOARD_ReleaseSelection( event->display, event->selection,
                                           event->window, hWnd, event->time );
3168
}
3169 3170 3171 3172 3173 3174 3175 3176 3177 3178

/***********************************************************************
 *           X11DRV_Clipboard_Cleanup
 */
void X11DRV_Clipboard_Cleanup(void)
{
    selectionAcquired = S_NOSELECTION;

    X11DRV_EmptyClipboard(FALSE);
}