kernel32: Reset stdio handles when they are closed.
[wine] / dlls / winex11.drv / clipboard.c
1 /*
2  * X11 clipboard windows driver
3  *
4  * Copyright 1994 Martin Ayotte
5  *           1996 Alex Korobka
6  *           1999 Noel Borthwick
7  *           2003 Ulrich Czekalla for CodeWeavers
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * 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  * NOTES:
24  *    This file contains the X specific implementation for the windows
25  *    Clipboard API.
26  *
27  *    Wine's internal clipboard is exposed to external apps via the X
28  *    selection mechanism.
29  *    Currently the driver asserts ownership via two selection atoms:
30  *    1. PRIMARY(XA_PRIMARY)
31  *    2. CLIPBOARD
32  *
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.
35  *    When Wine takes ownership of the clipboard, it takes ownership of BOTH selections.
36  *    While giving up selection ownership, if the CLIPBOARD selection is lost,
37  *    it will lose both PRIMARY and CLIPBOARD and empty the clipboard.
38  *    However if only PRIMARY is lost, it will continue to hold the CLIPBOARD selection
39  *    (leaving the clipboard cache content unaffected).
40  *
41  *      Every format exposed via a windows clipboard format is also exposed through
42  *    a corresponding X selection target. A selection target atom is synthesized
43  *    whenever a new Windows clipboard format is registered via RegisterClipboardFormat,
44  *    or when a built-in format is used for the first time.
45  *    Windows native format are exposed by prefixing the format name with "<WCF>"
46  *    This allows us to uniquely identify windows native formats exposed by other
47  *    running WINE apps.
48  *
49  *      In order to allow external applications to query WINE for supported formats,
50  *    we respond to the "TARGETS" selection target. (See EVENT_SelectionRequest
51  *    for implementation) We use the same mechanism to query external clients for
52  *    availability of a particular format, by caching the list of available targets
53  *    by using the clipboard cache's "delayed render" mechanism. If a selection client
54  *    does not support the "TARGETS" selection target, we actually attempt to retrieve
55  *    the format requested as a fallback mechanism.
56  *
57  *      Certain Windows native formats are automatically converted to X native formats
58  *    and vice versa. If a native format is available in the selection, it takes
59  *    precedence, in order to avoid unnecessary conversions.
60  *
61  * FIXME: global format list needs a critical section
62  */
63
64 #include "config.h"
65 #include "wine/port.h"
66
67 #include <string.h>
68 #include <stdarg.h>
69 #include <stdio.h>
70 #include <stdlib.h>
71 #ifdef HAVE_UNISTD_H
72 # include <unistd.h>
73 #endif
74 #include <fcntl.h>
75 #include <limits.h>
76 #include <time.h>
77 #include <assert.h>
78
79 #include "windef.h"
80 #include "winbase.h"
81 #include "x11drv.h"
82 #include "wine/debug.h"
83 #include "wine/unicode.h"
84 #include "wine/server.h"
85
86 WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
87
88 /* Maximum wait time for selection notify */
89 #define SELECTION_RETRIES 500  /* wait for .1 seconds */
90 #define SELECTION_WAIT    1000 /* us */
91 /* Minimum seconds that must lapse between owner queries */
92 #define OWNERQUERYLAPSETIME 1
93
94 /* Selection masks */
95 #define S_NOSELECTION    0
96 #define S_PRIMARY        1
97 #define S_CLIPBOARD      2
98
99 typedef struct
100 {
101     HWND hWndOpen;
102     HWND hWndOwner;
103     HWND hWndViewer;
104     UINT seqno;
105     UINT flags;
106 } CLIPBOARDINFO, *LPCLIPBOARDINFO;
107
108 struct tagWINE_CLIPDATA; /* Forward */
109
110 typedef HANDLE (*DRVEXPORTFUNC)(Display *display, Window requestor, Atom aTarget, Atom rprop,
111     struct tagWINE_CLIPDATA* lpData, LPDWORD lpBytes);
112 typedef HANDLE (*DRVIMPORTFUNC)(Display *d, Window w, Atom prop);
113
114 typedef struct tagWINE_CLIPFORMAT {
115     UINT        wFormatID;
116     LPCWSTR     Name;
117     UINT        drvData;
118     UINT        wFlags;
119     DRVIMPORTFUNC  lpDrvImportFunc;
120     DRVEXPORTFUNC  lpDrvExportFunc;
121     struct tagWINE_CLIPFORMAT *PrevFormat;
122     struct tagWINE_CLIPFORMAT *NextFormat;
123 } WINE_CLIPFORMAT, *LPWINE_CLIPFORMAT;
124
125 typedef struct tagWINE_CLIPDATA {
126     UINT        wFormatID;
127     HANDLE      hData;
128     UINT        wFlags;
129     UINT        drvData;
130     LPWINE_CLIPFORMAT lpFormat;
131     struct tagWINE_CLIPDATA *PrevData;
132     struct tagWINE_CLIPDATA *NextData;
133 } WINE_CLIPDATA, *LPWINE_CLIPDATA;
134
135 #define CF_FLAG_BUILTINFMT   0x0001 /* Built-in windows format */
136 #define CF_FLAG_UNOWNED      0x0002 /* cached data is not owned */
137 #define CF_FLAG_SYNTHESIZED  0x0004 /* Implicitly converted data */
138 #define CF_FLAG_UNICODE      0x0008 /* Data is in unicode */
139
140 static int selectionAcquired = 0;              /* Contains the current selection masks */
141 static Window selectionWindow = None;          /* The top level X window which owns the selection */
142 static Atom selectionCacheSrc = XA_PRIMARY;    /* The selection source from which the clipboard cache was filled */
143
144 void CDECL X11DRV_EmptyClipboard(BOOL keepunowned);
145 void CDECL X11DRV_EndClipboardUpdate(void);
146 static HANDLE X11DRV_CLIPBOARD_ImportClipboardData(Display *d, Window w, Atom prop);
147 static HANDLE X11DRV_CLIPBOARD_ImportEnhMetaFile(Display *d, Window w, Atom prop);
148 static HANDLE X11DRV_CLIPBOARD_ImportMetaFilePict(Display *d, Window w, Atom prop);
149 static HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(Display *d, Window w, Atom prop);
150 static HANDLE X11DRV_CLIPBOARD_ImportImageBmp(Display *d, Window w, Atom prop);
151 static HANDLE X11DRV_CLIPBOARD_ImportXAString(Display *d, Window w, Atom prop);
152 static HANDLE X11DRV_CLIPBOARD_ImportUTF8(Display *d, Window w, Atom prop);
153 static HANDLE X11DRV_CLIPBOARD_ImportCompoundText(Display *d, Window w, Atom prop);
154 static HANDLE X11DRV_CLIPBOARD_ExportClipboardData(Display *display, Window requestor, Atom aTarget,
155     Atom rprop, LPWINE_CLIPDATA lpData, LPDWORD lpBytes);
156 static HANDLE X11DRV_CLIPBOARD_ExportString(Display *display, Window requestor, Atom aTarget,
157     Atom rprop, LPWINE_CLIPDATA lpData, LPDWORD lpBytes);
158 static HANDLE X11DRV_CLIPBOARD_ExportXAPIXMAP(Display *display, Window requestor, Atom aTarget,
159     Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
160 static HANDLE X11DRV_CLIPBOARD_ExportImageBmp(Display *display, Window requestor, Atom aTarget,
161     Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
162 static HANDLE X11DRV_CLIPBOARD_ExportMetaFilePict(Display *display, Window requestor, Atom aTarget,
163     Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
164 static HANDLE X11DRV_CLIPBOARD_ExportEnhMetaFile(Display *display, Window requestor, Atom aTarget,
165     Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
166 static HANDLE X11DRV_CLIPBOARD_ExportTextHtml(Display *display, Window requestor, Atom aTarget,
167     Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes);
168 static WINE_CLIPFORMAT *X11DRV_CLIPBOARD_InsertClipboardFormat(LPCWSTR FormatName, Atom prop);
169 static BOOL X11DRV_CLIPBOARD_RenderSynthesizedText(Display *display, UINT wFormatID);
170 static void X11DRV_CLIPBOARD_FreeData(LPWINE_CLIPDATA lpData);
171 static BOOL X11DRV_CLIPBOARD_IsSelectionOwner(void);
172 static int X11DRV_CLIPBOARD_QueryAvailableData(Display *display, LPCLIPBOARDINFO lpcbinfo);
173 static BOOL X11DRV_CLIPBOARD_ReadSelectionData(Display *display, LPWINE_CLIPDATA lpData);
174 static BOOL X11DRV_CLIPBOARD_ReadProperty(Display *display, Window w, Atom prop,
175     unsigned char** data, unsigned long* datasize);
176 static BOOL X11DRV_CLIPBOARD_RenderFormat(Display *display, LPWINE_CLIPDATA lpData);
177 static HANDLE X11DRV_CLIPBOARD_SerializeMetafile(INT wformat, HANDLE hdata, LPDWORD lpcbytes, BOOL out);
178 static BOOL X11DRV_CLIPBOARD_SynthesizeData(UINT wFormatID);
179 static BOOL X11DRV_CLIPBOARD_RenderSynthesizedFormat(Display *display, LPWINE_CLIPDATA lpData);
180 static BOOL X11DRV_CLIPBOARD_RenderSynthesizedDIB(Display *display);
181 static BOOL X11DRV_CLIPBOARD_RenderSynthesizedBitmap(Display *display);
182 static void X11DRV_HandleSelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
183
184 /* Clipboard formats
185  * WARNING: This data ordering is dependent on the WINE_CLIPFORMAT structure
186  * declared in clipboard.h
187  */
188 static const WCHAR wszCF_TEXT[] = {'W','C','F','_','T','E','X','T',0};
189 static const WCHAR wszCF_BITMAP[] = {'W','C','F','_','B','I','T','M','A','P',0};
190 static const WCHAR wszCF_METAFILEPICT[] = {'W','C','F','_','M','E','T','A','F','I','L','E','P','I','C','T',0};
191 static const WCHAR wszCF_SYLK[] = {'W','C','F','_','S','Y','L','K',0};
192 static const WCHAR wszCF_DIF[] = {'W','C','F','_','D','I','F',0};
193 static const WCHAR wszCF_TIFF[] = {'W','C','F','_','T','I','F','F',0};
194 static const WCHAR wszCF_OEMTEXT[] = {'W','C','F','_','O','E','M','T','E','X','T',0};
195 static const WCHAR wszCF_DIB[] = {'W','C','F','_','D','I','B',0};
196 static const WCHAR wszIMAGEBMP[] = {'i','m','a','g','e','/','b','m','p',0};
197 static const WCHAR wszCF_PALETTE[] = {'W','C','F','_','P','A','L','E','T','T','E',0};
198 static const WCHAR wszCF_PENDATA[] = {'W','C','F','_','P','E','N','D','A','T','A',0};
199 static const WCHAR wszCF_RIFF[] = {'W','C','F','_','R','I','F','F',0};
200 static const WCHAR wszCF_WAVE[] = {'W','C','F','_','W','A','V','E',0};
201 static const WCHAR wszCOMPOUNDTEXT[] = {'C','O','M','P','O','U','N','D','_','T','E','X','T',0};
202 static const WCHAR wszUTF8STRING[] = {'U','T','F','8','_','S','T','R','I','N','G',0};
203 static const WCHAR wszCF_ENHMETAFILE[] = {'W','C','F','_','E','N','H','M','E','T','A','F','I','L','E',0};
204 static const WCHAR wszCF_HDROP[] = {'W','C','F','_','H','D','R','O','P',0};
205 static const WCHAR wszCF_LOCALE[] = {'W','C','F','_','L','O','C','A','L','E',0};
206 static const WCHAR wszCF_DIBV5[] = {'W','C','F','_','D','I','B','V','5',0};
207 static const WCHAR wszCF_OWNERDISPLAY[] = {'W','C','F','_','O','W','N','E','R','D','I','S','P','L','A','Y',0};
208 static const WCHAR wszCF_DSPTEXT[] = {'W','C','F','_','D','S','P','T','E','X','T',0};
209 static const WCHAR wszCF_DSPBITMAP[] = {'W','C','F','_','D','S','P','B','I','T','M','A','P',0};
210 static const WCHAR wszCF_DSPMETAFILEPICT[] = {'W','C','F','_','D','S','P','M','E','T','A','F','I','L','E','P','I','C','T',0};
211 static const WCHAR wszCF_DSPENHMETAFILE[] = {'W','C','F','_','D','S','P','E','N','H','M','E','T','A','F','I','L','E',0};
212
213 static WINE_CLIPFORMAT ClipFormats[]  =
214 {
215     { CF_TEXT, wszCF_TEXT, XA_STRING, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportXAString,
216         X11DRV_CLIPBOARD_ExportString, NULL, &ClipFormats[1]},
217
218     { CF_BITMAP, wszCF_BITMAP, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
219         NULL, &ClipFormats[0], &ClipFormats[2]},
220
221     { CF_METAFILEPICT, wszCF_METAFILEPICT, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportMetaFilePict,
222         X11DRV_CLIPBOARD_ExportMetaFilePict, &ClipFormats[1], &ClipFormats[3]},
223
224     { CF_SYLK, wszCF_SYLK, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
225         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[2], &ClipFormats[4]},
226
227     { CF_DIF, wszCF_DIF, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
228         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[3], &ClipFormats[5]},
229
230     { CF_TIFF, wszCF_TIFF, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
231         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[4], &ClipFormats[6]},
232
233     { CF_OEMTEXT, wszCF_OEMTEXT, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
234         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[5], &ClipFormats[7]},
235
236     { CF_DIB, wszCF_DIB, XA_PIXMAP, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportXAPIXMAP,
237         X11DRV_CLIPBOARD_ExportXAPIXMAP, &ClipFormats[6], &ClipFormats[8]},
238
239     { CF_PALETTE, wszCF_PALETTE, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
240         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[7], &ClipFormats[9]},
241
242     { CF_PENDATA, wszCF_PENDATA, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
243         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[8], &ClipFormats[10]},
244
245     { CF_RIFF, wszCF_RIFF, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
246         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[9], &ClipFormats[11]},
247
248     { CF_WAVE, wszCF_WAVE, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
249         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[10], &ClipFormats[12]},
250
251     { CF_UNICODETEXT, wszUTF8STRING, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportUTF8,
252         X11DRV_CLIPBOARD_ExportString, &ClipFormats[11], &ClipFormats[13]},
253
254     /* If UTF8_STRING is not available, attempt COMPUND_TEXT */
255     { CF_UNICODETEXT, wszCOMPOUNDTEXT, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportCompoundText,
256         X11DRV_CLIPBOARD_ExportString, &ClipFormats[12], &ClipFormats[14]},
257
258     { CF_ENHMETAFILE, wszCF_ENHMETAFILE, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportEnhMetaFile,
259         X11DRV_CLIPBOARD_ExportEnhMetaFile, &ClipFormats[13], &ClipFormats[15]},
260
261     { CF_HDROP, wszCF_HDROP, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
262         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[14], &ClipFormats[16]},
263
264     { CF_LOCALE, wszCF_LOCALE, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
265         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[15], &ClipFormats[17]},
266
267     { CF_DIBV5, wszCF_DIBV5, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
268         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[16], &ClipFormats[18]},
269
270     { CF_OWNERDISPLAY, wszCF_OWNERDISPLAY, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
271         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[17], &ClipFormats[19]},
272
273     { CF_DSPTEXT, wszCF_DSPTEXT, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
274         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[18], &ClipFormats[20]},
275
276     { CF_DSPBITMAP, wszCF_DSPBITMAP, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
277         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[19], &ClipFormats[21]},
278
279     { CF_DSPMETAFILEPICT, wszCF_DSPMETAFILEPICT, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
280         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[20], &ClipFormats[22]},
281
282     { CF_DSPENHMETAFILE, wszCF_DSPENHMETAFILE, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportClipboardData,
283         X11DRV_CLIPBOARD_ExportClipboardData, &ClipFormats[21], &ClipFormats[23]},
284
285     { CF_DIB, wszIMAGEBMP, 0, CF_FLAG_BUILTINFMT, X11DRV_CLIPBOARD_ImportImageBmp,
286         X11DRV_CLIPBOARD_ExportImageBmp, &ClipFormats[22], NULL},
287 };
288
289 #define GET_ATOM(prop)  (((prop) < FIRST_XATOM) ? (Atom)(prop) : X11DRV_Atoms[(prop) - FIRST_XATOM])
290
291 /* Maps X properties to Windows formats */
292 static const WCHAR wszRichTextFormat[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
293 static const WCHAR wszGIF[] = {'G','I','F',0};
294 static const WCHAR wszJFIF[] = {'J','F','I','F',0};
295 static const WCHAR wszPNG[] = {'P','N','G',0};
296 static const WCHAR wszHTMLFormat[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
297 static const struct
298 {
299     LPCWSTR lpszFormat;
300     UINT   prop;
301 } PropertyFormatMap[] =
302 {
303     { wszRichTextFormat, XATOM_text_rtf },
304     { wszRichTextFormat, XATOM_text_richtext },
305     { wszGIF, XATOM_image_gif },
306     { wszJFIF, XATOM_image_jpeg },
307     { wszPNG, XATOM_image_png },
308     { wszHTMLFormat, XATOM_HTML_Format }, /* prefer this to text/html */
309 };
310
311
312 /*
313  * Cached clipboard data.
314  */
315 static LPWINE_CLIPDATA ClipData = NULL;
316 static UINT ClipDataCount = 0;
317
318 /*
319  * Clipboard sequence number
320  */
321 static UINT wSeqNo = 0;
322
323 /**************************************************************************
324  *                Internal Clipboard implementation methods
325  **************************************************************************/
326
327 static Window thread_selection_wnd(void)
328 {
329     struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
330     Window w = thread_data->selection_wnd;
331
332     if (!w)
333     {
334         XSetWindowAttributes attr;
335
336         attr.event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
337                        ButtonPressMask | ButtonReleaseMask | EnterWindowMask | PropertyChangeMask);
338
339         wine_tsx11_lock();
340         w = XCreateWindow(thread_data->display, root_window, 0, 0, 1, 1, 0, screen_depth,
341                           InputOutput, CopyFromParent, CWEventMask, &attr);
342         wine_tsx11_unlock();
343
344         if (w)
345             thread_data->selection_wnd = w;
346         else
347             FIXME("Failed to create window. Fetching selection data will fail.\n");
348     }
349
350     return w;
351 }
352
353 /**************************************************************************
354  *              X11DRV_InitClipboard
355  */
356 void X11DRV_InitClipboard(void)
357 {
358     UINT i;
359     WINE_CLIPFORMAT *format;
360
361     /* Register known mapping between window formats and X properties */
362     for (i = 0; i < sizeof(PropertyFormatMap)/sizeof(PropertyFormatMap[0]); i++)
363         X11DRV_CLIPBOARD_InsertClipboardFormat(PropertyFormatMap[i].lpszFormat, GET_ATOM(PropertyFormatMap[i].prop));
364
365     /* Set up a conversion function from "HTML Format" to "text/html" */
366     format = X11DRV_CLIPBOARD_InsertClipboardFormat(wszHTMLFormat, GET_ATOM(XATOM_text_html));
367     format->lpDrvExportFunc = X11DRV_CLIPBOARD_ExportTextHtml;
368 }
369
370
371 /**************************************************************************
372  *                intern_atoms
373  *
374  * Intern atoms for formats that don't have one yet.
375  */
376 static void intern_atoms(void)
377 {
378     LPWINE_CLIPFORMAT format;
379     int i, count, len;
380     char **names;
381     Atom *atoms;
382     Display *display;
383
384     for (format = ClipFormats, count = 0; format; format = format->NextFormat)
385         if (!format->drvData) count++;
386     if (!count) return;
387
388     display = thread_init_display();
389
390     names = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*names) );
391     atoms = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*atoms) );
392
393     for (format = ClipFormats, i = 0; format; format = format->NextFormat) {
394         if (!format->drvData) {
395             len = WideCharToMultiByte(CP_UNIXCP, 0, format->Name, -1, NULL, 0, NULL, NULL);
396             names[i] = HeapAlloc(GetProcessHeap(), 0, len);
397             WideCharToMultiByte(CP_UNIXCP, 0, format->Name, -1, names[i++], len, NULL, NULL);
398         }
399     }
400
401     wine_tsx11_lock();
402     XInternAtoms( display, names, count, False, atoms );
403     wine_tsx11_unlock();
404
405     for (format = ClipFormats, i = 0; format; format = format->NextFormat) {
406         if (!format->drvData) {
407             HeapFree(GetProcessHeap(), 0, names[i]);
408             format->drvData = atoms[i++];
409         }
410     }
411
412     HeapFree( GetProcessHeap(), 0, names );
413     HeapFree( GetProcessHeap(), 0, atoms );
414 }
415
416
417 /**************************************************************************
418  *              register_format
419  *
420  * Register a custom X clipboard format.
421  */
422 static WINE_CLIPFORMAT *register_format( LPCWSTR FormatName, Atom prop )
423 {
424     LPWINE_CLIPFORMAT lpFormat = ClipFormats;
425
426     TRACE("%s\n", debugstr_w(FormatName));
427
428     /* walk format chain to see if it's already registered */
429     while (lpFormat)
430     {
431         if (CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lpFormat->Name, -1, FormatName, -1) == CSTR_EQUAL
432             && (lpFormat->wFlags & CF_FLAG_BUILTINFMT) == 0)
433              return lpFormat;
434         lpFormat = lpFormat->NextFormat;
435     }
436
437     return X11DRV_CLIPBOARD_InsertClipboardFormat(FormatName, prop);
438 }
439
440
441 /**************************************************************************
442  *                X11DRV_CLIPBOARD_LookupFormat
443  */
444 static LPWINE_CLIPFORMAT X11DRV_CLIPBOARD_LookupFormat(WORD wID)
445 {
446     LPWINE_CLIPFORMAT lpFormat = ClipFormats;
447
448     while(lpFormat)
449     {
450         if (lpFormat->wFormatID == wID) 
451             break;
452
453         lpFormat = lpFormat->NextFormat;
454     }
455     if (lpFormat && !lpFormat->drvData) intern_atoms();
456     return lpFormat;
457 }
458
459
460 /**************************************************************************
461  *                X11DRV_CLIPBOARD_LookupProperty
462  */
463 static LPWINE_CLIPFORMAT X11DRV_CLIPBOARD_LookupProperty(LPWINE_CLIPFORMAT current, UINT drvData)
464 {
465     for (;;)
466     {
467         LPWINE_CLIPFORMAT lpFormat = ClipFormats;
468         BOOL need_intern = FALSE;
469
470         if (current)
471             lpFormat = current->NextFormat;
472
473         while(lpFormat)
474         {
475             if (lpFormat->drvData == drvData) return lpFormat;
476             if (!lpFormat->drvData) need_intern = TRUE;
477             lpFormat = lpFormat->NextFormat;
478         }
479         if (!need_intern) return NULL;
480         intern_atoms();
481         /* restart the search for the new atoms */
482     }
483 }
484
485
486 /**************************************************************************
487  *               X11DRV_CLIPBOARD_LookupData
488  */
489 static LPWINE_CLIPDATA X11DRV_CLIPBOARD_LookupData(DWORD wID)
490 {
491     LPWINE_CLIPDATA lpData = ClipData;
492
493     if (lpData)
494     {
495         do
496         {
497             if (lpData->wFormatID == wID) 
498                 break;
499
500             lpData = lpData->NextData;
501         }
502         while(lpData != ClipData);
503
504         if (lpData->wFormatID != wID)
505             lpData = NULL;
506     }
507
508     return lpData;
509 }
510
511
512 /**************************************************************************
513  *              InsertClipboardFormat
514  */
515 static WINE_CLIPFORMAT *X11DRV_CLIPBOARD_InsertClipboardFormat(LPCWSTR FormatName, Atom prop)
516 {
517     LPWINE_CLIPFORMAT lpFormat;
518     LPWINE_CLIPFORMAT lpNewFormat;
519     LPWSTR new_name;
520
521     /* allocate storage for new format entry */
522     lpNewFormat = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPFORMAT));
523
524     if(lpNewFormat == NULL) 
525     {
526         WARN("No more memory for a new format!\n");
527         return NULL;
528     }
529
530     if (!(new_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(FormatName)+1)*sizeof(WCHAR))))
531     {
532         WARN("No more memory for the new format name!\n");
533         HeapFree(GetProcessHeap(), 0, lpNewFormat);
534         return NULL;
535     }
536
537     lpNewFormat->Name = strcpyW(new_name, FormatName);
538     lpNewFormat->wFlags = 0;
539     lpNewFormat->wFormatID = GlobalAddAtomW(lpNewFormat->Name);
540     lpNewFormat->drvData = prop;
541     lpNewFormat->lpDrvImportFunc = X11DRV_CLIPBOARD_ImportClipboardData;
542     lpNewFormat->lpDrvExportFunc = X11DRV_CLIPBOARD_ExportClipboardData;
543
544     /* Link Format */
545     lpFormat = ClipFormats;
546
547     while(lpFormat->NextFormat) /* Move to last entry */
548         lpFormat = lpFormat->NextFormat;
549
550     lpNewFormat->NextFormat = NULL;
551     lpFormat->NextFormat = lpNewFormat;
552     lpNewFormat->PrevFormat = lpFormat;
553
554     TRACE("Registering format(%04x): %s drvData %d\n",
555         lpNewFormat->wFormatID, debugstr_w(FormatName), lpNewFormat->drvData);
556
557     return lpNewFormat;
558 }
559
560
561
562
563 /**************************************************************************
564  *                      X11DRV_CLIPBOARD_GetClipboardInfo
565  */
566 static BOOL X11DRV_CLIPBOARD_GetClipboardInfo(LPCLIPBOARDINFO cbInfo)
567 {
568     BOOL bRet = FALSE;
569
570     SERVER_START_REQ( set_clipboard_info )
571     {
572         req->flags = 0;
573
574         if (wine_server_call_err( req ))
575         {
576             ERR("Failed to get clipboard owner.\n");
577         }
578         else
579         {
580             cbInfo->hWndOpen = wine_server_ptr_handle( reply->old_clipboard );
581             cbInfo->hWndOwner = wine_server_ptr_handle( reply->old_owner );
582             cbInfo->hWndViewer = wine_server_ptr_handle( reply->old_viewer );
583             cbInfo->seqno = reply->seqno;
584             cbInfo->flags = reply->flags;
585
586             bRet = TRUE;
587         }
588     }
589     SERVER_END_REQ;
590
591     return bRet;
592 }
593
594
595 /**************************************************************************
596  *      X11DRV_CLIPBOARD_ReleaseOwnership
597  */
598 static BOOL X11DRV_CLIPBOARD_ReleaseOwnership(void)
599 {
600     BOOL bRet = FALSE;
601
602     SERVER_START_REQ( set_clipboard_info )
603     {
604         req->flags = SET_CB_RELOWNER | SET_CB_SEQNO;
605
606         if (wine_server_call_err( req ))
607         {
608             ERR("Failed to set clipboard.\n");
609         }
610         else
611         {
612             bRet = TRUE;
613         }
614     }
615     SERVER_END_REQ;
616
617     return bRet;
618 }
619
620
621
622 /**************************************************************************
623  *                      X11DRV_CLIPBOARD_InsertClipboardData
624  *
625  * Caller *must* have the clipboard open and be the owner.
626  */
627 static BOOL X11DRV_CLIPBOARD_InsertClipboardData(UINT wFormatID, HANDLE hData, DWORD flags,
628                                                  LPWINE_CLIPFORMAT lpFormat, BOOL override)
629 {
630     LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(wFormatID);
631
632     TRACE("format=%04x lpData=%p hData=%p flags=0x%08x lpFormat=%p override=%d\n",
633         wFormatID, lpData, hData, flags, lpFormat, override);
634
635     if (lpData && !override)
636         return TRUE;
637
638     if (lpData)
639     {
640         X11DRV_CLIPBOARD_FreeData(lpData);
641
642         lpData->hData = hData;
643     }
644     else
645     {
646         lpData = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPDATA));
647
648         lpData->wFormatID = wFormatID;
649         lpData->hData = hData;
650         lpData->lpFormat = lpFormat;
651         lpData->drvData = 0;
652
653         if (ClipData)
654         {
655             LPWINE_CLIPDATA lpPrevData = ClipData->PrevData;
656
657             lpData->PrevData = lpPrevData;
658             lpData->NextData = ClipData;
659
660             lpPrevData->NextData = lpData;
661             ClipData->PrevData = lpData;
662         }
663         else
664         {
665             lpData->NextData = lpData;
666             lpData->PrevData = lpData;
667             ClipData = lpData;
668         }
669
670         ClipDataCount++;
671     }
672
673     lpData->wFlags = flags;
674
675     return TRUE;
676 }
677
678
679 /**************************************************************************
680  *                      X11DRV_CLIPBOARD_FreeData
681  *
682  * Free clipboard data handle.
683  */
684 static void X11DRV_CLIPBOARD_FreeData(LPWINE_CLIPDATA lpData)
685 {
686     TRACE("%04x\n", lpData->wFormatID);
687
688     if ((lpData->wFormatID >= CF_GDIOBJFIRST &&
689         lpData->wFormatID <= CF_GDIOBJLAST) || 
690         lpData->wFormatID == CF_BITMAP || 
691         lpData->wFormatID == CF_DIB || 
692         lpData->wFormatID == CF_PALETTE)
693     {
694       if (lpData->hData)
695         DeleteObject(lpData->hData);
696
697       if ((lpData->wFormatID == CF_DIB) && lpData->drvData)
698           XFreePixmap(gdi_display, lpData->drvData);
699     }
700     else if (lpData->wFormatID == CF_METAFILEPICT)
701     {
702       if (lpData->hData)
703       {
704         DeleteMetaFile(((METAFILEPICT *)GlobalLock( lpData->hData ))->hMF );
705         GlobalFree(lpData->hData);
706       }
707     }
708     else if (lpData->wFormatID == CF_ENHMETAFILE)
709     {
710         if (lpData->hData)
711             DeleteEnhMetaFile(lpData->hData);
712     }
713     else if (lpData->wFormatID < CF_PRIVATEFIRST ||
714              lpData->wFormatID > CF_PRIVATELAST)
715     {
716       if (lpData->hData)
717         GlobalFree(lpData->hData);
718     }
719
720     lpData->hData = 0;
721     lpData->drvData = 0;
722 }
723
724
725 /**************************************************************************
726  *                      X11DRV_CLIPBOARD_UpdateCache
727  */
728 static BOOL X11DRV_CLIPBOARD_UpdateCache(LPCLIPBOARDINFO lpcbinfo)
729 {
730     BOOL bret = TRUE;
731
732     if (!X11DRV_CLIPBOARD_IsSelectionOwner())
733     {
734         if (!X11DRV_CLIPBOARD_GetClipboardInfo(lpcbinfo))
735         {
736             ERR("Failed to retrieve clipboard information.\n");
737             bret = FALSE;
738         }
739         else if (wSeqNo < lpcbinfo->seqno)
740         {
741             X11DRV_EmptyClipboard(TRUE);
742
743             if (X11DRV_CLIPBOARD_QueryAvailableData(thread_init_display(), lpcbinfo) < 0)
744             {
745                 ERR("Failed to cache clipboard data owned by another process.\n");
746                 bret = FALSE;
747             }
748             else
749             {
750                 X11DRV_EndClipboardUpdate();
751             }
752
753             wSeqNo = lpcbinfo->seqno;
754         }
755     }
756
757     return bret;
758 }
759
760
761 /**************************************************************************
762  *                      X11DRV_CLIPBOARD_RenderFormat
763  */
764 static BOOL X11DRV_CLIPBOARD_RenderFormat(Display *display, LPWINE_CLIPDATA lpData)
765 {
766     BOOL bret = TRUE;
767
768     TRACE(" 0x%04x hData(%p)\n", lpData->wFormatID, lpData->hData);
769
770     if (lpData->hData) return bret; /* Already rendered */
771
772     if (lpData->wFlags & CF_FLAG_SYNTHESIZED)
773         bret = X11DRV_CLIPBOARD_RenderSynthesizedFormat(display, lpData);
774     else if (!X11DRV_CLIPBOARD_IsSelectionOwner())
775     {
776         if (!X11DRV_CLIPBOARD_ReadSelectionData(display, lpData))
777         {
778             ERR("Failed to cache clipboard data owned by another process. Format=%04x\n",
779                 lpData->wFormatID);
780             bret = FALSE;
781         }
782     }
783     else
784     {
785         CLIPBOARDINFO cbInfo;
786
787         if (X11DRV_CLIPBOARD_GetClipboardInfo(&cbInfo) && cbInfo.hWndOwner)
788         {
789             /* Send a WM_RENDERFORMAT message to notify the owner to render the
790              * data requested into the clipboard.
791              */
792             TRACE("Sending WM_RENDERFORMAT message to hwnd(%p)\n", cbInfo.hWndOwner);
793             SendMessageW(cbInfo.hWndOwner, WM_RENDERFORMAT, lpData->wFormatID, 0);
794
795             if (!lpData->hData) bret = FALSE;
796         }
797         else
798         {
799             ERR("hWndClipOwner is lost!\n");
800             bret = FALSE;
801         }
802     }
803
804     return bret;
805 }
806
807
808 /**************************************************************************
809  *                      CLIPBOARD_ConvertText
810  * Returns number of required/converted characters - not bytes!
811  */
812 static INT CLIPBOARD_ConvertText(WORD src_fmt, void const *src, INT src_size,
813                                  WORD dst_fmt, void *dst, INT dst_size)
814 {
815     UINT cp;
816
817     if(src_fmt == CF_UNICODETEXT)
818     {
819         switch(dst_fmt)
820         {
821         case CF_TEXT:
822             cp = CP_ACP;
823             break;
824         case CF_OEMTEXT:
825             cp = CP_OEMCP;
826             break;
827         default:
828             return 0;
829         }
830         return WideCharToMultiByte(cp, 0, src, src_size, dst, dst_size, NULL, NULL);
831     }
832
833     if(dst_fmt == CF_UNICODETEXT)
834     {
835         switch(src_fmt)
836         {
837         case CF_TEXT:
838             cp = CP_ACP;
839             break;
840         case CF_OEMTEXT:
841             cp = CP_OEMCP;
842             break;
843         default:
844             return 0;
845         }
846         return MultiByteToWideChar(cp, 0, src, src_size, dst, dst_size);
847     }
848
849     if(!dst_size) return src_size;
850
851     if(dst_size > src_size) dst_size = src_size;
852
853     if(src_fmt == CF_TEXT )
854         CharToOemBuffA(src, dst, dst_size);
855     else
856         OemToCharBuffA(src, dst, dst_size);
857
858     return dst_size;
859 }
860
861
862 /**************************************************************************
863  *                      X11DRV_CLIPBOARD_RenderSynthesizedFormat
864  */
865 static BOOL X11DRV_CLIPBOARD_RenderSynthesizedFormat(Display *display, LPWINE_CLIPDATA lpData)
866 {
867     BOOL bret = FALSE;
868
869     TRACE("\n");
870
871     if (lpData->wFlags & CF_FLAG_SYNTHESIZED)
872     {
873         UINT wFormatID = lpData->wFormatID;
874
875         if (wFormatID == CF_UNICODETEXT || wFormatID == CF_TEXT || wFormatID == CF_OEMTEXT)
876             bret = X11DRV_CLIPBOARD_RenderSynthesizedText(display, wFormatID);
877         else 
878         {
879             switch (wFormatID)
880             {
881                 case CF_DIB:
882                     bret = X11DRV_CLIPBOARD_RenderSynthesizedDIB( display );
883                     break;
884
885                 case CF_BITMAP:
886                     bret = X11DRV_CLIPBOARD_RenderSynthesizedBitmap( display );
887                     break;
888
889                 case CF_ENHMETAFILE:
890                 case CF_METAFILEPICT:
891                     FIXME("Synthesizing wFormatID(0x%08x) not implemented\n", wFormatID);
892                     break;
893
894                 default:
895                     FIXME("Called to synthesize unknown format\n");
896                     break;
897             }
898         }
899
900         lpData->wFlags &= ~CF_FLAG_SYNTHESIZED;
901     }
902
903     return bret;
904 }
905
906
907 /**************************************************************************
908  *                      X11DRV_CLIPBOARD_RenderSynthesizedText
909  *
910  * Renders synthesized text
911  */
912 static BOOL X11DRV_CLIPBOARD_RenderSynthesizedText(Display *display, UINT wFormatID)
913 {
914     LPCSTR lpstrS;
915     LPSTR  lpstrT;
916     HANDLE hData;
917     INT src_chars, dst_chars, alloc_size;
918     LPWINE_CLIPDATA lpSource = NULL;
919
920     TRACE("%04x\n", wFormatID);
921
922     if ((lpSource = X11DRV_CLIPBOARD_LookupData(wFormatID)) &&
923         lpSource->hData)
924         return TRUE;
925
926     /* Look for rendered source or non-synthesized source */
927     if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_UNICODETEXT)) &&
928         (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData))
929     {
930         TRACE("UNICODETEXT -> %04x\n", wFormatID);
931     }
932     else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_TEXT)) &&
933         (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData))
934     {
935         TRACE("TEXT -> %04x\n", wFormatID);
936     }
937     else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_OEMTEXT)) &&
938         (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData))
939     {
940         TRACE("OEMTEXT -> %04x\n", wFormatID);
941     }
942
943     if (!lpSource || (lpSource->wFlags & CF_FLAG_SYNTHESIZED &&
944         !lpSource->hData))
945         return FALSE;
946
947     /* Ask the clipboard owner to render the source text if necessary */
948     if (!lpSource->hData && !X11DRV_CLIPBOARD_RenderFormat(display, lpSource))
949         return FALSE;
950
951     lpstrS = GlobalLock(lpSource->hData);
952     if (!lpstrS)
953         return FALSE;
954
955     /* Text always NULL terminated */
956     if(lpSource->wFormatID == CF_UNICODETEXT)
957         src_chars = strlenW((LPCWSTR)lpstrS) + 1;
958     else
959         src_chars = strlen(lpstrS) + 1;
960
961     /* Calculate number of characters in the destination buffer */
962     dst_chars = CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, 
963         src_chars, wFormatID, NULL, 0);
964
965     if (!dst_chars)
966         return FALSE;
967
968     TRACE("Converting from '%04x' to '%04x', %i chars\n",
969         lpSource->wFormatID, wFormatID, src_chars);
970
971     /* Convert characters to bytes */
972     if(wFormatID == CF_UNICODETEXT)
973         alloc_size = dst_chars * sizeof(WCHAR);
974     else
975         alloc_size = dst_chars;
976
977     hData = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE |
978         GMEM_DDESHARE, alloc_size);
979
980     lpstrT = GlobalLock(hData);
981
982     if (lpstrT)
983     {
984         CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, src_chars,
985             wFormatID, lpstrT, dst_chars);
986         GlobalUnlock(hData);
987     }
988
989     GlobalUnlock(lpSource->hData);
990
991     return X11DRV_CLIPBOARD_InsertClipboardData(wFormatID, hData, 0, NULL, TRUE);
992 }
993
994
995 /**************************************************************************
996  *                      X11DRV_CLIPBOARD_RenderSynthesizedDIB
997  *
998  * Renders synthesized DIB
999  */
1000 static BOOL X11DRV_CLIPBOARD_RenderSynthesizedDIB(Display *display)
1001 {
1002     BOOL bret = FALSE;
1003     LPWINE_CLIPDATA lpSource = NULL;
1004
1005     TRACE("\n");
1006
1007     if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIB)) && lpSource->hData)
1008     {
1009         bret = TRUE;
1010     }
1011     /* If we have a bitmap and it's not synthesized or it has been rendered */
1012     else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_BITMAP)) &&
1013         (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData))
1014     {
1015         /* Render source if required */
1016         if (lpSource->hData || X11DRV_CLIPBOARD_RenderFormat(display, lpSource))
1017         {
1018             HDC hdc;
1019             HGLOBAL hData;
1020
1021             hdc = GetDC(NULL);
1022             hData = X11DRV_DIB_CreateDIBFromBitmap(hdc, lpSource->hData);
1023             ReleaseDC(NULL, hdc);
1024
1025             if (hData)
1026             {
1027                 X11DRV_CLIPBOARD_InsertClipboardData(CF_DIB, hData, 0, NULL, TRUE);
1028                 bret = TRUE;
1029             }
1030         }
1031     }
1032
1033     return bret;
1034 }
1035
1036
1037 /**************************************************************************
1038  *                      X11DRV_CLIPBOARD_RenderSynthesizedBitmap
1039  *
1040  * Renders synthesized bitmap
1041  */
1042 static BOOL X11DRV_CLIPBOARD_RenderSynthesizedBitmap(Display *display)
1043 {
1044     BOOL bret = FALSE;
1045     LPWINE_CLIPDATA lpSource = NULL;
1046
1047     TRACE("\n");
1048
1049     if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_BITMAP)) && lpSource->hData)
1050     {
1051         bret = TRUE;
1052     }
1053     /* If we have a dib and it's not synthesized or it has been rendered */
1054     else if ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIB)) &&
1055         (!(lpSource->wFlags & CF_FLAG_SYNTHESIZED) || lpSource->hData))
1056     {
1057         /* Render source if required */
1058         if (lpSource->hData || X11DRV_CLIPBOARD_RenderFormat(display, lpSource))
1059         {
1060             HDC hdc;
1061             HBITMAP hData;
1062             unsigned int offset;
1063             LPBITMAPINFOHEADER lpbmih;
1064
1065             hdc = GetDC(NULL);
1066             lpbmih = GlobalLock(lpSource->hData);
1067
1068             offset = sizeof(BITMAPINFOHEADER)
1069                   + ((lpbmih->biBitCount <= 8) ? (sizeof(RGBQUAD) *
1070                     (1 << lpbmih->biBitCount)) : 0);
1071
1072             hData = CreateDIBitmap(hdc, lpbmih, CBM_INIT, (LPBYTE)lpbmih +
1073                 offset, (LPBITMAPINFO) lpbmih, DIB_RGB_COLORS);
1074
1075             GlobalUnlock(lpSource->hData);
1076             ReleaseDC(NULL, hdc);
1077
1078             if (hData)
1079             {
1080                 X11DRV_CLIPBOARD_InsertClipboardData(CF_BITMAP, hData, 0, NULL, TRUE);
1081                 bret = TRUE;
1082             }
1083         }
1084     }
1085
1086     return bret;
1087 }
1088
1089
1090 /**************************************************************************
1091  *              X11DRV_CLIPBOARD_ImportXAString
1092  *
1093  *  Import XA_STRING, converting the string to CF_TEXT.
1094  */
1095 static HANDLE X11DRV_CLIPBOARD_ImportXAString(Display *display, Window w, Atom prop)
1096 {
1097     LPBYTE lpdata;
1098     unsigned long cbytes;
1099     LPSTR lpstr;
1100     unsigned long i, inlcount = 0;
1101     HANDLE hText = 0;
1102
1103     if (!X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1104         return 0;
1105
1106     for (i = 0; i <= cbytes; i++)
1107     {
1108         if (lpdata[i] == '\n')
1109             inlcount++;
1110     }
1111
1112     if ((hText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cbytes + inlcount + 1)))
1113     {
1114         lpstr = GlobalLock(hText);
1115
1116         for (i = 0, inlcount = 0; i <= cbytes; i++)
1117         {
1118             if (lpdata[i] == '\n')
1119                 lpstr[inlcount++] = '\r';
1120
1121             lpstr[inlcount++] = lpdata[i];
1122         }
1123
1124         GlobalUnlock(hText);
1125     }
1126
1127     /* Free the retrieved property data */
1128     HeapFree(GetProcessHeap(), 0, lpdata);
1129
1130     return hText;
1131 }
1132
1133
1134 /**************************************************************************
1135  *              X11DRV_CLIPBOARD_ImportUTF8
1136  *
1137  *  Import XA_STRING, converting the string to CF_UNICODE.
1138  */
1139 static HANDLE X11DRV_CLIPBOARD_ImportUTF8(Display *display, Window w, Atom prop)
1140 {
1141     LPBYTE lpdata;
1142     unsigned long cbytes;
1143     LPSTR lpstr;
1144     unsigned long i, inlcount = 0;
1145     HANDLE hUnicodeText = 0;
1146
1147     if (!X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1148         return 0;
1149
1150     for (i = 0; i <= cbytes; i++)
1151     {
1152         if (lpdata[i] == '\n')
1153             inlcount++;
1154     }
1155
1156     if ((lpstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbytes + inlcount + 1)))
1157     {
1158         UINT count;
1159
1160         for (i = 0, inlcount = 0; i <= cbytes; i++)
1161         {
1162             if (lpdata[i] == '\n')
1163                 lpstr[inlcount++] = '\r';
1164
1165             lpstr[inlcount++] = lpdata[i];
1166         }
1167
1168         count = MultiByteToWideChar(CP_UTF8, 0, lpstr, -1, NULL, 0);
1169         hUnicodeText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, count * sizeof(WCHAR));
1170
1171         if (hUnicodeText)
1172         {
1173             WCHAR *textW = GlobalLock(hUnicodeText);
1174             MultiByteToWideChar(CP_UTF8, 0, lpstr, -1, textW, count);
1175             GlobalUnlock(hUnicodeText);
1176         }
1177
1178         HeapFree(GetProcessHeap(), 0, lpstr);
1179     }
1180
1181     /* Free the retrieved property data */
1182     HeapFree(GetProcessHeap(), 0, lpdata);
1183
1184     return hUnicodeText;
1185 }
1186
1187
1188 /**************************************************************************
1189  *              X11DRV_CLIPBOARD_ImportCompoundText
1190  *
1191  *  Import COMPOUND_TEXT to CF_UNICODE
1192  */
1193 static HANDLE X11DRV_CLIPBOARD_ImportCompoundText(Display *display, Window w, Atom prop)
1194 {
1195     int i, j, ret;
1196     char** srcstr;
1197     int count, lcount;
1198     int srclen, destlen;
1199     HANDLE hUnicodeText;
1200     XTextProperty txtprop;
1201
1202     if (!X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &txtprop.value, &txtprop.nitems))
1203     {
1204         return 0;
1205     }
1206
1207     txtprop.encoding = x11drv_atom(COMPOUND_TEXT);
1208     txtprop.format = 8;
1209     wine_tsx11_lock();
1210     ret = XmbTextPropertyToTextList(display, &txtprop, &srcstr, &count);
1211     wine_tsx11_unlock();
1212     HeapFree(GetProcessHeap(), 0, txtprop.value);
1213     if (ret != Success || !count) return 0;
1214
1215     TRACE("Importing %d line(s)\n", count);
1216
1217     /* Compute number of lines */
1218     srclen = strlen(srcstr[0]);
1219     for (i = 0, lcount = 0; i <= srclen; i++)
1220     {
1221         if (srcstr[0][i] == '\n')
1222             lcount++;
1223     }
1224
1225     destlen = MultiByteToWideChar(CP_UNIXCP, 0, srcstr[0], -1, NULL, 0);
1226
1227     TRACE("lcount = %d, destlen=%d, srcstr %s\n", lcount, destlen, srcstr[0]);
1228
1229     if ((hUnicodeText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (destlen + lcount + 1) * sizeof(WCHAR))))
1230     {
1231         WCHAR *deststr = GlobalLock(hUnicodeText);
1232         MultiByteToWideChar(CP_UNIXCP, 0, srcstr[0], -1, deststr, destlen);
1233
1234         if (lcount)
1235         {
1236             for (i = destlen - 1, j = destlen + lcount - 1; i >= 0; i--, j--)
1237             {
1238                 deststr[j] = deststr[i];
1239
1240                 if (deststr[i] == '\n')
1241                     deststr[--j] = '\r';
1242             }
1243         }
1244
1245         GlobalUnlock(hUnicodeText);
1246     }
1247
1248     wine_tsx11_lock();
1249     XFreeStringList(srcstr);
1250     wine_tsx11_unlock();
1251
1252     return hUnicodeText;
1253 }
1254
1255
1256 /**************************************************************************
1257  *              X11DRV_CLIPBOARD_ImportXAPIXMAP
1258  *
1259  *  Import XA_PIXMAP, converting the image to CF_DIB.
1260  */
1261 static HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(Display *display, Window w, Atom prop)
1262 {
1263     HWND hwnd;
1264     HDC hdc;
1265     LPBYTE lpdata;
1266     unsigned long cbytes;
1267     Pixmap *pPixmap;
1268     HANDLE hClipData = 0;
1269
1270     if (X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1271     {
1272         pPixmap = (Pixmap *) lpdata;
1273
1274         hwnd = GetOpenClipboardWindow();
1275         hdc = GetDC(hwnd);
1276
1277         hClipData = X11DRV_DIB_CreateDIBFromPixmap(*pPixmap, hdc);
1278         ReleaseDC(hwnd, hdc);
1279
1280         /* Free the retrieved property data */
1281         HeapFree(GetProcessHeap(), 0, lpdata);
1282     }
1283
1284     return hClipData;
1285 }
1286
1287
1288 /**************************************************************************
1289  *              X11DRV_CLIPBOARD_ImportImageBmp
1290  *
1291  *  Import image/bmp, converting the image to CF_DIB.
1292  */
1293 static HANDLE X11DRV_CLIPBOARD_ImportImageBmp(Display *display, Window w, Atom prop)
1294 {
1295     LPBYTE lpdata;
1296     unsigned long cbytes;
1297     HANDLE hClipData = 0;
1298
1299     if (X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1300     {
1301         BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)lpdata;
1302
1303         if (cbytes >= sizeof(BITMAPFILEHEADER)+sizeof(BITMAPCOREHEADER) &&
1304             bfh->bfType == 0x4d42 /* "BM" */)
1305         {
1306             BITMAPINFO *bmi = (BITMAPINFO*)(bfh+1);
1307             HBITMAP hbmp;
1308             HDC hdc;
1309
1310             hdc = GetDC(0);
1311             hbmp = CreateDIBitmap(
1312                 hdc,
1313                 &(bmi->bmiHeader),
1314                 CBM_INIT,
1315                 lpdata+bfh->bfOffBits,
1316                 bmi,
1317                 DIB_RGB_COLORS
1318                 );
1319
1320             hClipData = X11DRV_DIB_CreateDIBFromBitmap(hdc, hbmp);
1321
1322             DeleteObject(hbmp);
1323             ReleaseDC(0, hdc);
1324         }
1325
1326         /* Free the retrieved property data */
1327         HeapFree(GetProcessHeap(), 0, lpdata);
1328     }
1329
1330     return hClipData;
1331 }
1332
1333
1334 /**************************************************************************
1335  *              X11DRV_CLIPBOARD_ImportMetaFilePict
1336  *
1337  *  Import MetaFilePict.
1338  */
1339 static HANDLE X11DRV_CLIPBOARD_ImportMetaFilePict(Display *display, Window w, Atom prop)
1340 {
1341     LPBYTE lpdata;
1342     unsigned long cbytes;
1343     HANDLE hClipData = 0;
1344
1345     if (X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1346     {
1347         if (cbytes)
1348             hClipData = X11DRV_CLIPBOARD_SerializeMetafile(CF_METAFILEPICT, lpdata, (LPDWORD)&cbytes, FALSE);
1349
1350         /* Free the retrieved property data */
1351         HeapFree(GetProcessHeap(), 0, lpdata);
1352     }
1353
1354     return hClipData;
1355 }
1356
1357
1358 /**************************************************************************
1359  *              X11DRV_ImportEnhMetaFile
1360  *
1361  *  Import EnhMetaFile.
1362  */
1363 static HANDLE X11DRV_CLIPBOARD_ImportEnhMetaFile(Display *display, Window w, Atom prop)
1364 {
1365     LPBYTE lpdata;
1366     unsigned long cbytes;
1367     HANDLE hClipData = 0;
1368
1369     if (X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1370     {
1371         if (cbytes)
1372             hClipData = X11DRV_CLIPBOARD_SerializeMetafile(CF_ENHMETAFILE, lpdata, (LPDWORD)&cbytes, FALSE);
1373
1374         /* Free the retrieved property data */
1375         HeapFree(GetProcessHeap(), 0, lpdata);
1376     }
1377
1378     return hClipData;
1379 }
1380
1381
1382 /**************************************************************************
1383  *              X11DRV_ImportClipbordaData
1384  *
1385  *  Generic import clipboard data routine.
1386  */
1387 static HANDLE X11DRV_CLIPBOARD_ImportClipboardData(Display *display, Window w, Atom prop)
1388 {
1389     LPVOID lpClipData;
1390     LPBYTE lpdata;
1391     unsigned long cbytes;
1392     HANDLE hClipData = 0;
1393
1394     if (X11DRV_CLIPBOARD_ReadProperty(display, w, prop, &lpdata, &cbytes))
1395     {
1396         if (cbytes)
1397         {
1398             /* Turn on the DDESHARE flag to enable shared 32 bit memory */
1399             hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cbytes);
1400             if (hClipData == 0)
1401                 return NULL;
1402
1403             if ((lpClipData = GlobalLock(hClipData)))
1404             {
1405                 memcpy(lpClipData, lpdata, cbytes);
1406                 GlobalUnlock(hClipData);
1407             }
1408             else
1409             {
1410                 GlobalFree(hClipData);
1411                 hClipData = 0;
1412             }
1413         }
1414
1415         /* Free the retrieved property data */
1416         HeapFree(GetProcessHeap(), 0, lpdata);
1417     }
1418
1419     return hClipData;
1420 }
1421
1422
1423 /**************************************************************************
1424                 X11DRV_CLIPBOARD_ExportClipboardData
1425  *
1426  *  Generic export clipboard data routine.
1427  */
1428 static HANDLE X11DRV_CLIPBOARD_ExportClipboardData(Display *display, Window requestor, Atom aTarget,
1429                                             Atom rprop, LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
1430 {
1431     LPVOID lpClipData;
1432     UINT datasize = 0;
1433     HANDLE hClipData = 0;
1434
1435     *lpBytes = 0; /* Assume failure */
1436
1437     if (!X11DRV_CLIPBOARD_RenderFormat(display, lpData))
1438         ERR("Failed to export %04x format\n", lpData->wFormatID);
1439     else
1440     {
1441         datasize = GlobalSize(lpData->hData);
1442
1443         hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, datasize);
1444         if (hClipData == 0) return NULL;
1445
1446         if ((lpClipData = GlobalLock(hClipData)))
1447         {
1448             LPVOID lpdata = GlobalLock(lpData->hData);
1449
1450             memcpy(lpClipData, lpdata, datasize);
1451             *lpBytes = datasize;
1452
1453             GlobalUnlock(lpData->hData);
1454             GlobalUnlock(hClipData);
1455         } else {
1456             GlobalFree(hClipData);
1457             hClipData = 0;
1458         }
1459     }
1460
1461     return hClipData;
1462 }
1463
1464
1465 /**************************************************************************
1466  *              X11DRV_CLIPBOARD_ExportXAString
1467  *
1468  *  Export CF_TEXT converting the string to XA_STRING.
1469  *  Helper function for X11DRV_CLIPBOARD_ExportString.
1470  */
1471 static HANDLE X11DRV_CLIPBOARD_ExportXAString(LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
1472 {
1473     UINT i, j;
1474     UINT size;
1475     LPSTR text, lpstr = NULL;
1476
1477     *lpBytes = 0; /* Assume return has zero bytes */
1478
1479     text = GlobalLock(lpData->hData);
1480     size = strlen(text);
1481
1482     /* remove carriage returns */
1483     lpstr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + 1);
1484     if (lpstr == NULL)
1485         goto done;
1486
1487     for (i = 0,j = 0; i < size && text[i]; i++)
1488     {
1489         if (text[i] == '\r' && (text[i+1] == '\n' || text[i+1] == '\0'))
1490             continue;
1491         lpstr[j++] = text[i];
1492     }
1493
1494     lpstr[j]='\0';
1495     *lpBytes = j; /* Number of bytes in string */
1496
1497 done:
1498     HeapFree(GetProcessHeap(), 0, text);
1499     GlobalUnlock(lpData->hData);
1500
1501     return lpstr;
1502 }
1503
1504
1505 /**************************************************************************
1506  *              X11DRV_CLIPBOARD_ExportUTF8String
1507  *
1508  *  Export CF_UNICODE converting the string to UTF8.
1509  *  Helper function for X11DRV_CLIPBOARD_ExportString.
1510  */
1511 static HANDLE X11DRV_CLIPBOARD_ExportUTF8String(LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
1512 {
1513     UINT i, j;
1514     UINT size;
1515     LPWSTR uni_text;
1516     LPSTR text, lpstr = NULL;
1517
1518     *lpBytes = 0; /* Assume return has zero bytes */
1519
1520     uni_text = GlobalLock(lpData->hData);
1521
1522     size = WideCharToMultiByte(CP_UTF8, 0, uni_text, -1, NULL, 0, NULL, NULL);
1523
1524     text = HeapAlloc(GetProcessHeap(), 0, size);
1525     if (!text)
1526         goto done;
1527     WideCharToMultiByte(CP_UTF8, 0, uni_text, -1, text, size, NULL, NULL);
1528
1529     /* remove carriage returns */
1530     lpstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size--);
1531     if (lpstr == NULL)
1532         goto done;
1533
1534     for (i = 0,j = 0; i < size && text[i]; i++)
1535     {
1536         if (text[i] == '\r' && (text[i+1] == '\n' || text[i+1] == '\0'))
1537             continue;
1538         lpstr[j++] = text[i];
1539     }
1540     lpstr[j]='\0';
1541
1542     *lpBytes = j; /* Number of bytes in string */
1543
1544 done:
1545     HeapFree(GetProcessHeap(), 0, text);
1546     GlobalUnlock(lpData->hData);
1547
1548     return lpstr;
1549 }
1550
1551
1552
1553 /**************************************************************************
1554  *              X11DRV_CLIPBOARD_ExportCompoundText
1555  *
1556  *  Export CF_UNICODE to COMPOUND_TEXT
1557  *  Helper function for X11DRV_CLIPBOARD_ExportString.
1558  */
1559 static HANDLE X11DRV_CLIPBOARD_ExportCompoundText(Display *display, Window requestor, Atom aTarget, Atom rprop,
1560     LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
1561 {
1562     char* lpstr = 0;
1563     XTextProperty prop;
1564     XICCEncodingStyle style;
1565     UINT i, j;
1566     UINT size;
1567     LPWSTR uni_text;
1568
1569     uni_text = GlobalLock(lpData->hData);
1570
1571     size = WideCharToMultiByte(CP_UNIXCP, 0, uni_text, -1, NULL, 0, NULL, NULL);
1572     lpstr = HeapAlloc(GetProcessHeap(), 0, size);
1573     if (!lpstr)
1574         return 0;
1575
1576     WideCharToMultiByte(CP_UNIXCP, 0, uni_text, -1, lpstr, size, NULL, NULL);
1577
1578     /* remove carriage returns */
1579     for (i = 0, j = 0; i < size && lpstr[i]; i++)
1580     {
1581         if (lpstr[i] == '\r' && (lpstr[i+1] == '\n' || lpstr[i+1] == '\0'))
1582             continue;
1583         lpstr[j++] = lpstr[i];
1584     }
1585     lpstr[j]='\0';
1586
1587     GlobalUnlock(lpData->hData);
1588
1589     if (aTarget == x11drv_atom(COMPOUND_TEXT))
1590         style = XCompoundTextStyle;
1591     else
1592         style = XStdICCTextStyle;
1593
1594     /* Update the X property */
1595     wine_tsx11_lock();
1596     if (XmbTextListToTextProperty(display, &lpstr, 1, style, &prop) == Success)
1597     {
1598         XSetTextProperty(display, requestor, &prop, rprop);
1599         XFree(prop.value);
1600     }
1601     wine_tsx11_unlock();
1602
1603     HeapFree(GetProcessHeap(), 0, lpstr);
1604
1605     return 0;
1606 }
1607
1608 /**************************************************************************
1609  *              X11DRV_CLIPBOARD_ExportString
1610  *
1611  *  Export string
1612  */
1613 static HANDLE X11DRV_CLIPBOARD_ExportString(Display *display, Window requestor, Atom aTarget, Atom rprop,
1614                                      LPWINE_CLIPDATA lpData, LPDWORD lpBytes)
1615 {
1616     if (X11DRV_CLIPBOARD_RenderFormat(display, lpData))
1617     {
1618         if (aTarget == XA_STRING)
1619             return X11DRV_CLIPBOARD_ExportXAString(lpData, lpBytes);
1620         else if (aTarget == x11drv_atom(COMPOUND_TEXT) || aTarget == x11drv_atom(TEXT))
1621             return X11DRV_CLIPBOARD_ExportCompoundText(display, requestor, aTarget,
1622                 rprop, lpData, lpBytes);
1623         else
1624         {
1625             TRACE("Exporting target %ld to default UTF8_STRING\n", aTarget);
1626             return X11DRV_CLIPBOARD_ExportUTF8String(lpData, lpBytes);
1627         }
1628     }
1629     else
1630         ERR("Failed to render %04x format\n", lpData->wFormatID);
1631
1632     return 0;
1633 }
1634
1635
1636 /**************************************************************************
1637  *              X11DRV_CLIPBOARD_ExportXAPIXMAP
1638  *
1639  *  Export CF_DIB to XA_PIXMAP.
1640  */
1641 static HANDLE X11DRV_CLIPBOARD_ExportXAPIXMAP(Display *display, Window requestor, Atom aTarget, Atom rprop,
1642     LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
1643 {
1644     HDC hdc;
1645     HANDLE hData;
1646     unsigned char* lpData;
1647
1648     if (!X11DRV_CLIPBOARD_RenderFormat(display, lpdata))
1649     {
1650         ERR("Failed to export %04x format\n", lpdata->wFormatID);
1651         return 0;
1652     }
1653
1654     if (!lpdata->drvData) /* If not already rendered */
1655     {
1656         /* For convert from packed DIB to Pixmap */
1657         hdc = GetDC(0);
1658         lpdata->drvData = (UINT) X11DRV_DIB_CreatePixmapFromDIB(lpdata->hData, hdc);
1659         ReleaseDC(0, hdc);
1660     }
1661
1662     *lpBytes = sizeof(Pixmap); /* pixmap is a 32bit value */
1663
1664     /* Wrap pixmap so we can return a handle */
1665     hData = GlobalAlloc(0, *lpBytes);
1666     lpData = GlobalLock(hData);
1667     memcpy(lpData, &lpdata->drvData, *lpBytes);
1668     GlobalUnlock(hData);
1669
1670     return hData;
1671 }
1672
1673
1674 /**************************************************************************
1675  *              X11DRV_CLIPBOARD_ExportImageBmp
1676  *
1677  *  Export CF_DIB to image/bmp.
1678  */
1679 static HANDLE X11DRV_CLIPBOARD_ExportImageBmp(Display *display, Window requestor, Atom aTarget, Atom rprop,
1680     LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
1681 {
1682     HANDLE hpackeddib;
1683     LPBYTE dibdata;
1684     UINT bmpsize;
1685     HANDLE hbmpdata;
1686     LPBYTE bmpdata;
1687     BITMAPFILEHEADER *bfh;
1688
1689     *lpBytes = 0;
1690
1691     if (!X11DRV_CLIPBOARD_RenderFormat(display, lpdata))
1692     {
1693         ERR("Failed to export %04x format\n", lpdata->wFormatID);
1694         return 0;
1695     }
1696
1697     hpackeddib = lpdata->hData;
1698
1699     dibdata = GlobalLock(hpackeddib);
1700     if (!dibdata)
1701     {
1702         ERR("Failed to lock packed DIB\n");
1703         return 0;
1704     }
1705
1706     bmpsize = sizeof(BITMAPFILEHEADER) + GlobalSize(hpackeddib);
1707
1708     hbmpdata = GlobalAlloc(0, bmpsize);
1709
1710     if (hbmpdata)
1711     {
1712         bmpdata = GlobalLock(hbmpdata);
1713
1714         if (!bmpdata)
1715         {
1716             GlobalFree(hbmpdata);
1717             GlobalUnlock(hpackeddib);
1718             return 0;
1719         }
1720
1721         /* bitmap file header */
1722         bfh = (BITMAPFILEHEADER*)bmpdata;
1723         bfh->bfType = 0x4d42; /* "BM" */
1724         bfh->bfSize = bmpsize;
1725         bfh->bfReserved1 = 0;
1726         bfh->bfReserved2 = 0;
1727         bfh->bfOffBits = sizeof(BITMAPFILEHEADER) + bitmap_info_size((BITMAPINFO*)dibdata, DIB_RGB_COLORS);
1728
1729         /* rest of bitmap is the same as the packed dib */
1730         memcpy(bfh+1, dibdata, bmpsize-sizeof(BITMAPFILEHEADER));
1731
1732         *lpBytes = bmpsize;
1733
1734         GlobalUnlock(hbmpdata);
1735     }
1736
1737     GlobalUnlock(hpackeddib);
1738
1739     return hbmpdata;
1740 }
1741
1742
1743 /**************************************************************************
1744  *              X11DRV_CLIPBOARD_ExportMetaFilePict
1745  *
1746  *  Export MetaFilePict.
1747  */
1748 static HANDLE X11DRV_CLIPBOARD_ExportMetaFilePict(Display *display, Window requestor, Atom aTarget, Atom rprop,
1749                                            LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
1750 {
1751     if (!X11DRV_CLIPBOARD_RenderFormat(display, lpdata))
1752     {
1753         ERR("Failed to export %04x format\n", lpdata->wFormatID);
1754         return 0;
1755     }
1756
1757     return X11DRV_CLIPBOARD_SerializeMetafile(CF_METAFILEPICT, lpdata->hData, lpBytes, TRUE);
1758 }
1759
1760
1761 /**************************************************************************
1762  *              X11DRV_CLIPBOARD_ExportEnhMetaFile
1763  *
1764  *  Export EnhMetaFile.
1765  */
1766 static HANDLE X11DRV_CLIPBOARD_ExportEnhMetaFile(Display *display, Window requestor, Atom aTarget, Atom rprop,
1767                                           LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
1768 {
1769     if (!X11DRV_CLIPBOARD_RenderFormat(display, lpdata))
1770     {
1771         ERR("Failed to export %04x format\n", lpdata->wFormatID);
1772         return 0;
1773     }
1774
1775     return X11DRV_CLIPBOARD_SerializeMetafile(CF_ENHMETAFILE, lpdata->hData, lpBytes, TRUE);
1776 }
1777
1778
1779 /**************************************************************************
1780  *              get_html_description_field
1781  *
1782  *  Find the value of a field in an HTML Format description.
1783  */
1784 static LPCSTR get_html_description_field(LPCSTR data, LPCSTR keyword)
1785 {
1786     LPCSTR pos=data;
1787
1788     while (pos && *pos && *pos != '<')
1789     {
1790         if (memcmp(pos, keyword, strlen(keyword)) == 0)
1791             return pos+strlen(keyword);
1792
1793         pos = strchr(pos, '\n');
1794         if (pos) pos++;
1795     }
1796
1797     return NULL;
1798 }
1799
1800
1801 /**************************************************************************
1802  *              X11DRV_CLIPBOARD_ExportTextHtml
1803  *
1804  *  Export HTML Format to text/html.
1805  *
1806  * FIXME: We should attempt to add an <a base> tag and convert windows paths.
1807  */
1808 static HANDLE X11DRV_CLIPBOARD_ExportTextHtml(Display *display, Window requestor, Atom aTarget,
1809     Atom rprop, LPWINE_CLIPDATA lpdata, LPDWORD lpBytes)
1810 {
1811     HANDLE hdata;
1812     LPCSTR data, field_value;
1813     UINT fragmentstart, fragmentend, htmlsize;
1814     HANDLE hhtmldata=NULL;
1815     LPSTR htmldata;
1816
1817     *lpBytes = 0;
1818
1819     if (!X11DRV_CLIPBOARD_RenderFormat(display, lpdata))
1820     {
1821         ERR("Failed to export %04x format\n", lpdata->wFormatID);
1822         return 0;
1823     }
1824
1825     hdata = lpdata->hData;
1826
1827     data = GlobalLock(hdata);
1828     if (!data)
1829     {
1830         ERR("Failed to lock HTML Format data\n");
1831         return 0;
1832     }
1833
1834     /* read the important fields */
1835     field_value = get_html_description_field(data, "StartFragment:");
1836     if (!field_value)
1837     {
1838         ERR("Couldn't find StartFragment value\n");
1839         goto end;
1840     }
1841     fragmentstart = atoi(field_value);
1842
1843     field_value = get_html_description_field(data, "EndFragment:");
1844     if (!field_value)
1845     {
1846         ERR("Couldn't find EndFragment value\n");
1847         goto end;
1848     }
1849     fragmentend = atoi(field_value);
1850
1851     /* export only the fragment */
1852     htmlsize = fragmentend - fragmentstart + 1;
1853
1854     hhtmldata = GlobalAlloc(0, htmlsize);
1855
1856     if (hhtmldata)
1857     {
1858         htmldata = GlobalLock(hhtmldata);
1859
1860         if (!htmldata)
1861         {
1862             GlobalFree(hhtmldata);
1863             htmldata = NULL;
1864             goto end;
1865         }
1866
1867         memcpy(htmldata, &data[fragmentstart], fragmentend-fragmentstart);
1868         htmldata[htmlsize-1] = '\0';
1869
1870         *lpBytes = htmlsize;
1871
1872         GlobalUnlock(htmldata);
1873     }
1874
1875 end:
1876
1877     GlobalUnlock(hdata);
1878
1879     return hhtmldata;
1880 }
1881
1882
1883 /**************************************************************************
1884  *              X11DRV_CLIPBOARD_QueryTargets
1885  */
1886 static BOOL X11DRV_CLIPBOARD_QueryTargets(Display *display, Window w, Atom selection,
1887     Atom target, XEvent *xe)
1888 {
1889     INT i;
1890     Bool res;
1891
1892     wine_tsx11_lock();
1893     XConvertSelection(display, selection, target,
1894         x11drv_atom(SELECTION_DATA), w, CurrentTime);
1895     wine_tsx11_unlock();
1896
1897     /*
1898      * Wait until SelectionNotify is received
1899      */
1900     for (i = 0; i < SELECTION_RETRIES; i++)
1901     {
1902         wine_tsx11_lock();
1903         res = XCheckTypedWindowEvent(display, w, SelectionNotify, xe);
1904         wine_tsx11_unlock();
1905         if (res && xe->xselection.selection == selection) break;
1906
1907         usleep(SELECTION_WAIT);
1908     }
1909
1910     if (i == SELECTION_RETRIES)
1911     {
1912         ERR("Timed out waiting for SelectionNotify event\n");
1913         return FALSE;
1914     }
1915     /* Verify that the selection returned a valid TARGETS property */
1916     if ((xe->xselection.target != target) || (xe->xselection.property == None))
1917     {
1918         /* Selection owner failed to respond or we missed the SelectionNotify */
1919         WARN("Failed to retrieve TARGETS for selection %ld.\n", selection);
1920         return FALSE;
1921     }
1922
1923     return TRUE;
1924 }
1925
1926
1927 static int is_atom_error( Display *display, XErrorEvent *event, void *arg )
1928 {
1929     return (event->error_code == BadAtom);
1930 }
1931
1932 /**************************************************************************
1933  *              X11DRV_CLIPBOARD_InsertSelectionProperties
1934  *
1935  * Mark properties available for future retrieval.
1936  */
1937 static VOID X11DRV_CLIPBOARD_InsertSelectionProperties(Display *display, Atom* properties, UINT count)
1938 {
1939      UINT i, nb_atoms = 0;
1940      Atom *atoms = NULL;
1941
1942      /* Cache these formats in the clipboard cache */
1943      for (i = 0; i < count; i++)
1944      {
1945          LPWINE_CLIPFORMAT lpFormat = X11DRV_CLIPBOARD_LookupProperty(NULL, properties[i]);
1946
1947          if (lpFormat)
1948          {
1949              /* We found at least one Window's format that mapps to the property.
1950               * Continue looking for more.
1951               *
1952               * If more than one property map to a Window's format then we use the first 
1953               * one and ignore the rest.
1954               */
1955              while (lpFormat)
1956              {
1957                  TRACE("Atom#%d Property(%d): --> FormatID(%04x) %s\n",
1958                        i, lpFormat->drvData, lpFormat->wFormatID, debugstr_w(lpFormat->Name));
1959                  X11DRV_CLIPBOARD_InsertClipboardData(lpFormat->wFormatID, 0, 0, lpFormat, FALSE);
1960                  lpFormat = X11DRV_CLIPBOARD_LookupProperty(lpFormat, properties[i]);
1961              }
1962          }
1963          else if (properties[i])
1964          {
1965              /* add it to the list of atoms that we don't know about yet */
1966              if (!atoms) atoms = HeapAlloc( GetProcessHeap(), 0,
1967                                             (count - i) * sizeof(*atoms) );
1968              if (atoms) atoms[nb_atoms++] = properties[i];
1969          }
1970      }
1971
1972      /* query all unknown atoms in one go */
1973      if (atoms)
1974      {
1975          char **names = HeapAlloc( GetProcessHeap(), 0, nb_atoms * sizeof(*names) );
1976          if (names)
1977          {
1978              X11DRV_expect_error( display, is_atom_error, NULL );
1979              if (!XGetAtomNames( display, atoms, nb_atoms, names )) nb_atoms = 0;
1980              if (X11DRV_check_error())
1981              {
1982                  WARN( "got some bad atoms, ignoring\n" );
1983                  nb_atoms = 0;
1984              }
1985              for (i = 0; i < nb_atoms; i++)
1986              {
1987                  WINE_CLIPFORMAT *lpFormat;
1988                  LPWSTR wname;
1989                  int len = MultiByteToWideChar(CP_UNIXCP, 0, names[i], -1, NULL, 0);
1990                  wname = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
1991                  MultiByteToWideChar(CP_UNIXCP, 0, names[i], -1, wname, len);
1992
1993                  lpFormat = register_format( wname, atoms[i] );
1994                  HeapFree(GetProcessHeap(), 0, wname);
1995                  if (!lpFormat)
1996                  {
1997                      ERR("Failed to register %s property. Type will not be cached.\n", names[i]);
1998                      continue;
1999                  }
2000                  TRACE("Atom#%d Property(%d): --> FormatID(%04x) %s\n",
2001                        i, lpFormat->drvData, lpFormat->wFormatID, debugstr_w(lpFormat->Name));
2002                  X11DRV_CLIPBOARD_InsertClipboardData(lpFormat->wFormatID, 0, 0, lpFormat, FALSE);
2003              }
2004              wine_tsx11_lock();
2005              for (i = 0; i < nb_atoms; i++) XFree( names[i] );
2006              wine_tsx11_unlock();
2007              HeapFree( GetProcessHeap(), 0, names );
2008          }
2009          HeapFree( GetProcessHeap(), 0, atoms );
2010      }
2011 }
2012
2013
2014 /**************************************************************************
2015  *              X11DRV_CLIPBOARD_QueryAvailableData
2016  *
2017  * Caches the list of data formats available from the current selection.
2018  * This queries the selection owner for the TARGETS property and saves all
2019  * reported property types.
2020  */
2021 static int X11DRV_CLIPBOARD_QueryAvailableData(Display *display, LPCLIPBOARDINFO lpcbinfo)
2022 {
2023     XEvent         xe;
2024     Atom           atype=AnyPropertyType;
2025     int            aformat;
2026     unsigned long  remain;
2027     Atom*          targetList=NULL;
2028     Window         w;
2029     unsigned long  cSelectionTargets = 0;
2030
2031     if (selectionAcquired & (S_PRIMARY | S_CLIPBOARD))
2032     {
2033         ERR("Received request to cache selection but process is owner=(%08x)\n", 
2034             (unsigned) selectionWindow);
2035         return -1; /* Prevent self request */
2036     }
2037
2038     w = thread_selection_wnd();
2039     if (!w)
2040     {
2041         ERR("No window available to retrieve selection!\n");
2042         return -1;
2043     }
2044
2045     /*
2046      * Query the selection owner for the TARGETS property
2047      */
2048     wine_tsx11_lock();
2049     if ((use_primary_selection && XGetSelectionOwner(display,XA_PRIMARY)) ||
2050         XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)))
2051     {
2052         wine_tsx11_unlock();
2053         if (use_primary_selection && (X11DRV_CLIPBOARD_QueryTargets(display, w, XA_PRIMARY, x11drv_atom(TARGETS), &xe)))
2054             selectionCacheSrc = XA_PRIMARY;
2055         else if (X11DRV_CLIPBOARD_QueryTargets(display, w, x11drv_atom(CLIPBOARD), x11drv_atom(TARGETS), &xe))
2056             selectionCacheSrc = x11drv_atom(CLIPBOARD);
2057         else
2058         {
2059             Atom xstr = XA_STRING;
2060
2061             /* Selection Owner doesn't understand TARGETS, try retrieving XA_STRING */
2062             if (X11DRV_CLIPBOARD_QueryTargets(display, w, XA_PRIMARY, XA_STRING, &xe))
2063             {
2064                 X11DRV_CLIPBOARD_InsertSelectionProperties(display, &xstr, 1);
2065                 selectionCacheSrc = XA_PRIMARY;
2066                 return 1;
2067             }
2068             else if (X11DRV_CLIPBOARD_QueryTargets(display, w, x11drv_atom(CLIPBOARD), XA_STRING, &xe))
2069             {
2070                 X11DRV_CLIPBOARD_InsertSelectionProperties(display, &xstr, 1);
2071                 selectionCacheSrc = x11drv_atom(CLIPBOARD);
2072                 return 1;
2073             }
2074             else
2075             {
2076                 WARN("Failed to query selection owner for available data.\n");
2077                 return -1;
2078             }
2079         }
2080     }
2081     else /* No selection owner so report 0 targets available */
2082     {
2083         wine_tsx11_unlock();
2084         return 0;
2085     }
2086
2087     /* Read the TARGETS property contents */
2088     wine_tsx11_lock();
2089     if(XGetWindowProperty(display, xe.xselection.requestor, xe.xselection.property,
2090         0, 0x3FFF, True, AnyPropertyType/*XA_ATOM*/, &atype, &aformat, &cSelectionTargets, 
2091         &remain, (unsigned char**)&targetList) != Success)
2092     {
2093         wine_tsx11_unlock();
2094         WARN("Failed to read TARGETS property\n");
2095     }
2096     else
2097     {
2098         wine_tsx11_unlock();
2099        TRACE("Type %lx,Format %d,nItems %ld, Remain %ld\n",
2100              atype, aformat, cSelectionTargets, remain);
2101        /*
2102         * The TARGETS property should have returned us a list of atoms
2103         * corresponding to each selection target format supported.
2104         */
2105        if (atype == XA_ATOM || atype == x11drv_atom(TARGETS))
2106        {
2107            if (aformat == 32)
2108            {
2109                X11DRV_CLIPBOARD_InsertSelectionProperties(display, targetList, cSelectionTargets);
2110            }
2111            else if (aformat == 8)  /* work around quartz-wm brain damage */
2112            {
2113                unsigned long i, count = cSelectionTargets / sizeof(CARD32);
2114                Atom *atoms = HeapAlloc( GetProcessHeap(), 0, count * sizeof(Atom) );
2115                for (i = 0; i < count; i++)
2116                    atoms[i] = ((CARD32 *)targetList)[i];  /* FIXME: byte swapping */
2117                X11DRV_CLIPBOARD_InsertSelectionProperties( display, atoms, count );
2118                HeapFree( GetProcessHeap(), 0, atoms );
2119            }
2120        }
2121
2122        /* Free the list of targets */
2123        wine_tsx11_lock();
2124        XFree(targetList);
2125        wine_tsx11_unlock();
2126     }
2127
2128     return cSelectionTargets;
2129 }
2130
2131
2132 /**************************************************************************
2133  *      X11DRV_CLIPBOARD_ReadSelectionData
2134  *
2135  * This method is invoked only when we DO NOT own the X selection
2136  *
2137  * We always get the data from the selection client each time,
2138  * since we have no way of determining if the data in our cache is stale.
2139  */
2140 static BOOL X11DRV_CLIPBOARD_ReadSelectionData(Display *display, LPWINE_CLIPDATA lpData)
2141 {
2142     Bool res;
2143     DWORD i;
2144     XEvent xe;
2145     BOOL bRet = FALSE;
2146
2147     TRACE("%04x\n", lpData->wFormatID);
2148
2149     if (!lpData->lpFormat)
2150     {
2151         ERR("Requesting format %04x but no source format linked to data.\n",
2152             lpData->wFormatID);
2153         return FALSE;
2154     }
2155
2156     if (!selectionAcquired)
2157     {
2158         Window w = thread_selection_wnd();
2159         if(!w)
2160         {
2161             ERR("No window available to read selection data!\n");
2162             return FALSE;
2163         }
2164
2165         TRACE("Requesting conversion of %s property (%d) from selection type %08x\n",
2166             debugstr_w(lpData->lpFormat->Name), lpData->lpFormat->drvData, (UINT)selectionCacheSrc);
2167
2168         wine_tsx11_lock();
2169         XConvertSelection(display, selectionCacheSrc, lpData->lpFormat->drvData,
2170             x11drv_atom(SELECTION_DATA), w, CurrentTime);
2171         wine_tsx11_unlock();
2172
2173         /* wait until SelectionNotify is received */
2174         for (i = 0; i < SELECTION_RETRIES; i++)
2175         {
2176             wine_tsx11_lock();
2177             res = XCheckTypedWindowEvent(display, w, SelectionNotify, &xe);
2178             wine_tsx11_unlock();
2179             if (res && xe.xselection.selection == selectionCacheSrc) break;
2180
2181             usleep(SELECTION_WAIT);
2182         }
2183
2184         if (i == SELECTION_RETRIES)
2185         {
2186             ERR("Timed out waiting for SelectionNotify event\n");
2187         }
2188         /* Verify that the selection returned a valid TARGETS property */
2189         else if (xe.xselection.property != None)
2190         {
2191             /*
2192              *  Read the contents of the X selection property 
2193              *  into WINE's clipboard cache and converting the 
2194              *  data format if necessary.
2195              */
2196              HANDLE hData = lpData->lpFormat->lpDrvImportFunc(display, xe.xselection.requestor,
2197                  xe.xselection.property);
2198
2199              if (hData)
2200                  bRet = X11DRV_CLIPBOARD_InsertClipboardData(lpData->wFormatID, hData, 0, lpData->lpFormat, TRUE);
2201              else
2202                  TRACE("Import function failed\n");
2203         }
2204         else
2205         {
2206             TRACE("Failed to convert selection\n");
2207         }
2208     }
2209     else
2210     {
2211         ERR("Received request to cache selection data but process is owner\n");
2212     }
2213
2214     TRACE("Returning %d\n", bRet);
2215
2216     return bRet;
2217 }
2218
2219
2220 /**************************************************************************
2221  *              X11DRV_CLIPBOARD_GetProperty
2222  *  Gets type, data and size.
2223  */
2224 static BOOL X11DRV_CLIPBOARD_GetProperty(Display *display, Window w, Atom prop,
2225     Atom *atype, unsigned char** data, unsigned long* datasize)
2226 {
2227     int aformat;
2228     unsigned long pos = 0, nitems, remain, count;
2229     unsigned char *val = NULL, *buffer;
2230
2231     TRACE("Reading property %lu from X window %lx\n", prop, w);
2232
2233     for (;;)
2234     {
2235         wine_tsx11_lock();
2236         if (XGetWindowProperty(display, w, prop, pos, INT_MAX / 4, False,
2237                                AnyPropertyType, atype, &aformat, &nitems, &remain, &buffer) != Success)
2238         {
2239             wine_tsx11_unlock();
2240             WARN("Failed to read property\n");
2241             HeapFree( GetProcessHeap(), 0, val );
2242             return FALSE;
2243         }
2244
2245         count = get_property_size( aformat, nitems );
2246         if (!val) *data = HeapAlloc( GetProcessHeap(), 0, pos * sizeof(int) + count + 1 );
2247         else *data = HeapReAlloc( GetProcessHeap(), 0, val, pos * sizeof(int) + count + 1 );
2248
2249         if (!*data)
2250         {
2251             XFree( buffer );
2252             wine_tsx11_unlock();
2253             HeapFree( GetProcessHeap(), 0, val );
2254             return FALSE;
2255         }
2256         val = *data;
2257         memcpy( (int *)val + pos, buffer, count );
2258         XFree( buffer );
2259         wine_tsx11_unlock();
2260         if (!remain)
2261         {
2262             *datasize = pos * sizeof(int) + count;
2263             val[*datasize] = 0;
2264             break;
2265         }
2266         pos += count / sizeof(int);
2267     }
2268
2269     /* Delete the property on the window now that we are done
2270      * This will send a PropertyNotify event to the selection owner. */
2271     wine_tsx11_lock();
2272     XDeleteProperty(display, w, prop);
2273     wine_tsx11_unlock();
2274     return TRUE;
2275 }
2276
2277
2278 /**************************************************************************
2279  *              X11DRV_CLIPBOARD_ReadProperty
2280  *  Reads the contents of the X selection property.
2281  */
2282 static BOOL X11DRV_CLIPBOARD_ReadProperty(Display *display, Window w, Atom prop,
2283     unsigned char** data, unsigned long* datasize)
2284 {
2285     Atom atype;
2286     XEvent xe;
2287
2288     if (prop == None)
2289         return FALSE;
2290
2291     if (!X11DRV_CLIPBOARD_GetProperty(display, w, prop, &atype, data, datasize))
2292         return FALSE;
2293
2294     wine_tsx11_lock();
2295     while (XCheckTypedWindowEvent(display, w, PropertyNotify, &xe))
2296         ;
2297     wine_tsx11_unlock();
2298
2299     if (atype == x11drv_atom(INCR))
2300     {
2301         unsigned char *buf = *data;
2302         unsigned long bufsize = 0;
2303
2304         for (;;)
2305         {
2306             int i;
2307             unsigned char *prop_data, *tmp;
2308             unsigned long prop_size;
2309
2310             /* Wait until PropertyNotify is received */
2311             for (i = 0; i < SELECTION_RETRIES; i++)
2312             {
2313                 Bool res;
2314
2315                 wine_tsx11_lock();
2316                 res = XCheckTypedWindowEvent(display, w, PropertyNotify, &xe);
2317                 wine_tsx11_unlock();
2318                 if (res && xe.xproperty.atom == prop &&
2319                     xe.xproperty.state == PropertyNewValue)
2320                     break;
2321                 usleep(SELECTION_WAIT);
2322             }
2323
2324             if (i >= SELECTION_RETRIES ||
2325                 !X11DRV_CLIPBOARD_GetProperty(display, w, prop, &atype, &prop_data, &prop_size))
2326             {
2327                 HeapFree(GetProcessHeap(), 0, buf);
2328                 return FALSE;
2329             }
2330
2331             /* Retrieved entire data. */
2332             if (prop_size == 0)
2333             {
2334                 HeapFree(GetProcessHeap(), 0, prop_data);
2335                 *data = buf;
2336                 *datasize = bufsize;
2337                 return TRUE;
2338             }
2339
2340             tmp = HeapReAlloc(GetProcessHeap(), 0, buf, bufsize + prop_size + 1);
2341             if (!tmp)
2342             {
2343                 HeapFree(GetProcessHeap(), 0, buf);
2344                 return FALSE;
2345             }
2346
2347             buf = tmp;
2348             memcpy(buf + bufsize, prop_data, prop_size + 1);
2349             bufsize += prop_size;
2350             HeapFree(GetProcessHeap(), 0, prop_data);
2351         }
2352     }
2353
2354     return TRUE;
2355 }
2356
2357
2358 /**************************************************************************
2359  *              CLIPBOARD_SerializeMetafile
2360  */
2361 static HANDLE X11DRV_CLIPBOARD_SerializeMetafile(INT wformat, HANDLE hdata, LPDWORD lpcbytes, BOOL out)
2362 {
2363     HANDLE h = 0;
2364
2365     TRACE(" wFormat=%d hdata=%p out=%d\n", wformat, hdata, out);
2366
2367     if (out) /* Serialize out, caller should free memory */
2368     {
2369         *lpcbytes = 0; /* Assume failure */
2370
2371         if (wformat == CF_METAFILEPICT)
2372         {
2373             LPMETAFILEPICT lpmfp = GlobalLock(hdata);
2374             unsigned int size = GetMetaFileBitsEx(lpmfp->hMF, 0, NULL);
2375
2376             h = GlobalAlloc(0, size + sizeof(METAFILEPICT));
2377             if (h)
2378             {
2379                 char *pdata = GlobalLock(h);
2380
2381                 memcpy(pdata, lpmfp, sizeof(METAFILEPICT));
2382                 GetMetaFileBitsEx(lpmfp->hMF, size, pdata + sizeof(METAFILEPICT));
2383
2384                 *lpcbytes = size + sizeof(METAFILEPICT);
2385
2386                 GlobalUnlock(h);
2387             }
2388
2389             GlobalUnlock(hdata);
2390         }
2391         else if (wformat == CF_ENHMETAFILE)
2392         {
2393             int size = GetEnhMetaFileBits(hdata, 0, NULL);
2394
2395             h = GlobalAlloc(0, size);
2396             if (h)
2397             {
2398                 LPVOID pdata = GlobalLock(h);
2399
2400                 GetEnhMetaFileBits(hdata, size, pdata);
2401                 *lpcbytes = size;
2402
2403                 GlobalUnlock(h);
2404             }
2405         }
2406     }
2407     else
2408     {
2409         if (wformat == CF_METAFILEPICT)
2410         {
2411             h = GlobalAlloc(0, sizeof(METAFILEPICT));
2412             if (h)
2413             {
2414                 unsigned int wiresize;
2415                 LPMETAFILEPICT lpmfp = GlobalLock(h);
2416
2417                 memcpy(lpmfp, hdata, sizeof(METAFILEPICT));
2418                 wiresize = *lpcbytes - sizeof(METAFILEPICT);
2419                 lpmfp->hMF = SetMetaFileBitsEx(wiresize,
2420                     ((const BYTE *)hdata) + sizeof(METAFILEPICT));
2421                 GlobalUnlock(h);
2422             }
2423         }
2424         else if (wformat == CF_ENHMETAFILE)
2425         {
2426             h = SetEnhMetaFileBits(*lpcbytes, hdata);
2427         }
2428     }
2429
2430     return h;
2431 }
2432
2433
2434 /**************************************************************************
2435  *              X11DRV_CLIPBOARD_ReleaseSelection
2436  *
2437  * Release XA_CLIPBOARD and XA_PRIMARY in response to a SelectionClear event.
2438  */
2439 static void X11DRV_CLIPBOARD_ReleaseSelection(Display *display, Atom selType, Window w, HWND hwnd, Time time)
2440 {
2441     /* w is the window that lost the selection
2442      */
2443     TRACE("event->window = %08x (selectionWindow = %08x) selectionAcquired=0x%08x\n",
2444           (unsigned)w, (unsigned)selectionWindow, (unsigned)selectionAcquired);
2445
2446     if (selectionAcquired && (w == selectionWindow))
2447     {
2448         CLIPBOARDINFO cbinfo;
2449
2450         /* completely give up the selection */
2451         TRACE("Lost CLIPBOARD (+PRIMARY) selection\n");
2452
2453         X11DRV_CLIPBOARD_GetClipboardInfo(&cbinfo);
2454
2455         if (cbinfo.flags & CB_PROCESS)
2456         {
2457             /* Since we're still the owner, this wasn't initiated by
2458                another Wine process */
2459             if (OpenClipboard(hwnd))
2460             {
2461                 /* Destroy private objects */
2462                 SendMessageW(cbinfo.hWndOwner, WM_DESTROYCLIPBOARD, 0, 0);
2463
2464                 /* Give up ownership of the windows clipboard */
2465                 X11DRV_CLIPBOARD_ReleaseOwnership();
2466                 CloseClipboard();
2467             }
2468         }
2469
2470         if ((selType == x11drv_atom(CLIPBOARD)) && (selectionAcquired & S_PRIMARY))
2471         {
2472             TRACE("Lost clipboard. Check if we need to release PRIMARY\n");
2473
2474             wine_tsx11_lock();
2475             if (selectionWindow == XGetSelectionOwner(display, XA_PRIMARY))
2476             {
2477                 TRACE("We still own PRIMARY. Releasing PRIMARY.\n");
2478                 XSetSelectionOwner(display, XA_PRIMARY, None, time);
2479             }
2480             else
2481                 TRACE("We no longer own PRIMARY\n");
2482             wine_tsx11_unlock();
2483         }
2484         else if ((selType == XA_PRIMARY) && (selectionAcquired & S_CLIPBOARD))
2485         {
2486             TRACE("Lost PRIMARY. Check if we need to release CLIPBOARD\n");
2487
2488             wine_tsx11_lock();
2489             if (selectionWindow == XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)))
2490             {
2491                 TRACE("We still own CLIPBOARD. Releasing CLIPBOARD.\n");
2492                 XSetSelectionOwner(display, x11drv_atom(CLIPBOARD), None, time);
2493             }
2494             else
2495                 TRACE("We no longer own CLIPBOARD\n");
2496             wine_tsx11_unlock();
2497         }
2498
2499         selectionWindow = None;
2500
2501         X11DRV_EmptyClipboard(FALSE);
2502
2503         /* Reset the selection flags now that we are done */
2504         selectionAcquired = S_NOSELECTION;
2505     }
2506 }
2507
2508
2509 /**************************************************************************
2510  *              IsSelectionOwner (X11DRV.@)
2511  *
2512  * Returns: TRUE if the selection is owned by this process, FALSE otherwise
2513  */
2514 static BOOL X11DRV_CLIPBOARD_IsSelectionOwner(void)
2515 {
2516     return selectionAcquired;
2517 }
2518
2519
2520 /**************************************************************************
2521  *                X11DRV Clipboard Exports
2522  **************************************************************************/
2523
2524
2525 /**************************************************************************
2526  *              RegisterClipboardFormat (X11DRV.@)
2527  *
2528  * Registers a custom X clipboard format
2529  * Returns: Format id or 0 on failure
2530  */
2531 UINT CDECL X11DRV_RegisterClipboardFormat(LPCWSTR FormatName)
2532 {
2533     LPWINE_CLIPFORMAT lpFormat;
2534
2535     if (FormatName == NULL) return 0;
2536     if (!(lpFormat = register_format( FormatName, 0 ))) return 0;
2537     return lpFormat->wFormatID;
2538 }
2539
2540
2541 /**************************************************************************
2542  *              X11DRV_GetClipboardFormatName
2543  */
2544 INT CDECL X11DRV_GetClipboardFormatName(UINT wFormat, LPWSTR retStr, INT maxlen)
2545 {
2546     LPWINE_CLIPFORMAT lpFormat;
2547
2548     TRACE("(%04X, %p, %d) !\n", wFormat, retStr, maxlen);
2549
2550     if (wFormat < 0xc000)
2551     {
2552         SetLastError(ERROR_INVALID_PARAMETER);
2553         return 0;
2554     }
2555
2556     lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
2557
2558     if (!lpFormat || (lpFormat->wFlags & CF_FLAG_BUILTINFMT))
2559     {
2560         TRACE("Unknown format 0x%08x!\n", wFormat);
2561         SetLastError(ERROR_INVALID_HANDLE);
2562         return 0;
2563     }
2564
2565     lstrcpynW(retStr, lpFormat->Name, maxlen);
2566
2567     return strlenW(retStr);
2568 }
2569
2570 static void selection_acquire(void)
2571 {
2572     Window owner;
2573     Display *display;
2574
2575     owner = thread_selection_wnd();
2576     display = thread_display();
2577
2578     wine_tsx11_lock();
2579
2580     selectionAcquired = 0;
2581     selectionWindow = 0;
2582
2583     /* Grab PRIMARY selection if not owned */
2584     if (use_primary_selection)
2585         XSetSelectionOwner(display, XA_PRIMARY, owner, CurrentTime);
2586
2587     /* Grab CLIPBOARD selection if not owned */
2588     XSetSelectionOwner(display, x11drv_atom(CLIPBOARD), owner, CurrentTime);
2589
2590     if (use_primary_selection && XGetSelectionOwner(display, XA_PRIMARY) == owner)
2591         selectionAcquired |= S_PRIMARY;
2592
2593     if (XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)) == owner)
2594         selectionAcquired |= S_CLIPBOARD;
2595
2596     wine_tsx11_unlock();
2597
2598     if (selectionAcquired)
2599     {
2600         selectionWindow = owner;
2601         TRACE("Grabbed X selection, owner=(%08x)\n", (unsigned) owner);
2602     }
2603 }
2604
2605 static DWORD WINAPI selection_thread_proc(LPVOID p)
2606 {
2607     HANDLE event = p;
2608
2609     TRACE("\n");
2610
2611     selection_acquire();
2612     SetEvent(event);
2613
2614     while (selectionAcquired)
2615     {
2616         MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_SENDMESSAGE, 0);
2617     }
2618
2619     return 0;
2620 }
2621
2622 /**************************************************************************
2623  *              AcquireClipboard (X11DRV.@)
2624  */
2625 int CDECL X11DRV_AcquireClipboard(HWND hWndClipWindow)
2626 {
2627     DWORD procid;
2628     HANDLE selectionThread;
2629
2630     TRACE(" %p\n", hWndClipWindow);
2631
2632     /*
2633      * It's important that the selection get acquired from the thread
2634      * that owns the clipboard window. The primary reason is that we know 
2635      * it is running a message loop and therefore can process the 
2636      * X selection events.
2637      */
2638     if (hWndClipWindow &&
2639         GetCurrentThreadId() != GetWindowThreadProcessId(hWndClipWindow, &procid))
2640     {
2641         if (procid != GetCurrentProcessId())
2642         {
2643             WARN("Setting clipboard owner to other process is not supported\n");
2644             hWndClipWindow = NULL;
2645         }
2646         else
2647         {
2648             TRACE("Thread %x is acquiring selection with thread %x's window %p\n",
2649                 GetCurrentThreadId(),
2650                 GetWindowThreadProcessId(hWndClipWindow, NULL), hWndClipWindow);
2651
2652             return SendMessageW(hWndClipWindow, WM_X11DRV_ACQUIRE_SELECTION, 0, 0);
2653         }
2654     }
2655
2656     if (hWndClipWindow)
2657     {
2658         selection_acquire();
2659     }
2660     else
2661     {
2662         HANDLE event = CreateEventW(NULL, FALSE, FALSE, NULL);
2663         selectionThread = CreateThread(NULL, 0, &selection_thread_proc, event, 0, NULL);
2664
2665         if (!selectionThread)
2666         {
2667             WARN("Could not start clipboard thread\n");
2668             return 0;
2669         }
2670
2671         WaitForSingleObject(event, INFINITE);
2672         CloseHandle(event);
2673         CloseHandle(selectionThread);
2674     }
2675
2676     return 1;
2677 }
2678
2679
2680 /**************************************************************************
2681  *      X11DRV_EmptyClipboard
2682  *
2683  * Empty cached clipboard data. 
2684  */
2685 void CDECL X11DRV_EmptyClipboard(BOOL keepunowned)
2686 {
2687     if (ClipData)
2688     {
2689         LPWINE_CLIPDATA lpData, lpStart;
2690         LPWINE_CLIPDATA lpNext = ClipData;
2691
2692         TRACE(" called with %d entries in cache.\n", ClipDataCount);
2693
2694         do
2695         {
2696             lpStart = ClipData;
2697             lpData = lpNext;
2698             lpNext = lpData->NextData;
2699
2700             if (!keepunowned || !(lpData->wFlags & CF_FLAG_UNOWNED))
2701             {
2702             lpData->PrevData->NextData = lpData->NextData;
2703             lpData->NextData->PrevData = lpData->PrevData;
2704
2705                 if (lpData == ClipData)
2706                     ClipData = lpNext != lpData ? lpNext : NULL;
2707
2708             X11DRV_CLIPBOARD_FreeData(lpData);
2709             HeapFree(GetProcessHeap(), 0, lpData);
2710
2711                 ClipDataCount--;
2712             }
2713         } while (lpNext != lpStart);
2714     }
2715
2716     TRACE(" %d entries remaining in cache.\n", ClipDataCount);
2717 }
2718
2719
2720
2721 /**************************************************************************
2722  *              X11DRV_SetClipboardData
2723  */
2724 BOOL CDECL X11DRV_SetClipboardData(UINT wFormat, HANDLE hData, BOOL owner)
2725 {
2726     DWORD flags = 0;
2727     BOOL bResult = TRUE;
2728
2729     /* If it's not owned, data can only be set if the format data is not already owned
2730        and its rendering is not delayed */
2731     if (!owner)
2732     {
2733         CLIPBOARDINFO cbinfo;
2734         LPWINE_CLIPDATA lpRender;
2735
2736         X11DRV_CLIPBOARD_UpdateCache(&cbinfo);
2737
2738         if (!hData ||
2739             ((lpRender = X11DRV_CLIPBOARD_LookupData(wFormat)) &&
2740             !(lpRender->wFlags & CF_FLAG_UNOWNED)))
2741             bResult = FALSE;
2742         else
2743             flags = CF_FLAG_UNOWNED;
2744     }
2745
2746     bResult &= X11DRV_CLIPBOARD_InsertClipboardData(wFormat, hData, flags, NULL, TRUE);
2747
2748     return bResult;
2749 }
2750
2751
2752 /**************************************************************************
2753  *              CountClipboardFormats
2754  */
2755 INT CDECL X11DRV_CountClipboardFormats(void)
2756 {
2757     CLIPBOARDINFO cbinfo;
2758
2759     X11DRV_CLIPBOARD_UpdateCache(&cbinfo);
2760
2761     TRACE(" count=%d\n", ClipDataCount);
2762
2763     return ClipDataCount;
2764 }
2765
2766
2767 /**************************************************************************
2768  *              X11DRV_EnumClipboardFormats
2769  */
2770 UINT CDECL X11DRV_EnumClipboardFormats(UINT wFormat)
2771 {
2772     CLIPBOARDINFO cbinfo;
2773     UINT wNextFormat = 0;
2774
2775     TRACE("(%04X)\n", wFormat);
2776
2777     X11DRV_CLIPBOARD_UpdateCache(&cbinfo);
2778
2779     if (!wFormat)
2780     {
2781         if (ClipData)
2782             wNextFormat = ClipData->wFormatID;
2783     }
2784     else
2785     {
2786         LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(wFormat);
2787
2788         if (lpData && lpData->NextData != ClipData)
2789             wNextFormat = lpData->NextData->wFormatID;
2790     }
2791
2792     return wNextFormat;
2793 }
2794
2795
2796 /**************************************************************************
2797  *              X11DRV_IsClipboardFormatAvailable
2798  */
2799 BOOL CDECL X11DRV_IsClipboardFormatAvailable(UINT wFormat)
2800 {
2801     BOOL bRet = FALSE;
2802     CLIPBOARDINFO cbinfo;
2803
2804     TRACE("(%04X)\n", wFormat);
2805
2806     X11DRV_CLIPBOARD_UpdateCache(&cbinfo);
2807
2808     if (wFormat != 0 && X11DRV_CLIPBOARD_LookupData(wFormat))
2809         bRet = TRUE;
2810
2811     TRACE("(%04X)- ret(%d)\n", wFormat, bRet);
2812
2813     return bRet;
2814 }
2815
2816
2817 /**************************************************************************
2818  *              GetClipboardData (USER.142)
2819  */
2820 HANDLE CDECL X11DRV_GetClipboardData(UINT wFormat)
2821 {
2822     CLIPBOARDINFO cbinfo;
2823     LPWINE_CLIPDATA lpRender;
2824
2825     TRACE("(%04X)\n", wFormat);
2826
2827     X11DRV_CLIPBOARD_UpdateCache(&cbinfo);
2828
2829     if ((lpRender = X11DRV_CLIPBOARD_LookupData(wFormat)))
2830     {
2831         if ( !lpRender->hData )
2832             X11DRV_CLIPBOARD_RenderFormat(thread_init_display(), lpRender);
2833
2834         TRACE(" returning %p (type %04x)\n", lpRender->hData, lpRender->wFormatID);
2835         return lpRender->hData;
2836     }
2837
2838     return 0;
2839 }
2840
2841
2842 /**************************************************************************
2843  *              ResetSelectionOwner
2844  *
2845  * Called when the thread owning the selection is destroyed and we need to
2846  * preserve the selection ownership. We look for another top level window
2847  * in this process and send it a message to acquire the selection.
2848  */
2849 void X11DRV_ResetSelectionOwner(void)
2850 {
2851     HWND hwnd;
2852     DWORD procid;
2853
2854     TRACE("\n");
2855
2856     if (!selectionAcquired  || thread_selection_wnd() != selectionWindow)
2857         return;
2858
2859     selectionAcquired = S_NOSELECTION;
2860     selectionWindow = 0;
2861
2862     hwnd = GetWindow(GetDesktopWindow(), GW_CHILD);
2863     do
2864     {
2865         if (GetCurrentThreadId() != GetWindowThreadProcessId(hwnd, &procid))
2866         {
2867             if (GetCurrentProcessId() == procid)
2868             {
2869                 if (SendMessageW(hwnd, WM_X11DRV_ACQUIRE_SELECTION, 0, 0))
2870                     return;
2871             }
2872         }
2873     } while ((hwnd = GetWindow(hwnd, GW_HWNDNEXT)) != NULL);
2874
2875     WARN("Failed to find another thread to take selection ownership. Clipboard data will be lost.\n");
2876
2877     X11DRV_CLIPBOARD_ReleaseOwnership();
2878     X11DRV_EmptyClipboard(FALSE);
2879 }
2880
2881
2882 /**************************************************************************
2883  *                      X11DRV_CLIPBOARD_SynthesizeData
2884  */
2885 static BOOL X11DRV_CLIPBOARD_SynthesizeData(UINT wFormatID)
2886 {
2887     BOOL bsyn = TRUE;
2888     LPWINE_CLIPDATA lpSource = NULL;
2889
2890     TRACE(" %04x\n", wFormatID);
2891
2892     /* Don't need to synthesize if it already exists */
2893     if (X11DRV_CLIPBOARD_LookupData(wFormatID))
2894         return TRUE;
2895
2896     if (wFormatID == CF_UNICODETEXT || wFormatID == CF_TEXT || wFormatID == CF_OEMTEXT)
2897     {
2898         bsyn = ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_UNICODETEXT)) &&
2899             ~lpSource->wFlags & CF_FLAG_SYNTHESIZED) ||
2900             ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_TEXT)) &&
2901             ~lpSource->wFlags & CF_FLAG_SYNTHESIZED) ||
2902             ((lpSource = X11DRV_CLIPBOARD_LookupData(CF_OEMTEXT)) &&
2903             ~lpSource->wFlags & CF_FLAG_SYNTHESIZED);
2904     }
2905     else if (wFormatID == CF_ENHMETAFILE)
2906     {
2907         bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_METAFILEPICT)) &&
2908             ~lpSource->wFlags & CF_FLAG_SYNTHESIZED;
2909     }
2910     else if (wFormatID == CF_METAFILEPICT)
2911     {
2912         bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_ENHMETAFILE)) &&
2913             ~lpSource->wFlags & CF_FLAG_SYNTHESIZED;
2914     }
2915     else if (wFormatID == CF_DIB)
2916     {
2917         bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_BITMAP)) &&
2918             ~lpSource->wFlags & CF_FLAG_SYNTHESIZED;
2919     }
2920     else if (wFormatID == CF_BITMAP)
2921     {
2922         bsyn = (lpSource = X11DRV_CLIPBOARD_LookupData(CF_DIB)) &&
2923             ~lpSource->wFlags & CF_FLAG_SYNTHESIZED;
2924     }
2925
2926     if (bsyn)
2927         X11DRV_CLIPBOARD_InsertClipboardData(wFormatID, 0, CF_FLAG_SYNTHESIZED, NULL, TRUE);
2928
2929     return bsyn;
2930 }
2931
2932
2933
2934 /**************************************************************************
2935  *              X11DRV_EndClipboardUpdate
2936  * TODO:
2937  *  Add locale if it hasn't already been added
2938  */
2939 void CDECL X11DRV_EndClipboardUpdate(void)
2940 {
2941     INT count = ClipDataCount;
2942
2943     /* Do Unicode <-> Text <-> OEM mapping */
2944     X11DRV_CLIPBOARD_SynthesizeData(CF_TEXT);
2945     X11DRV_CLIPBOARD_SynthesizeData(CF_OEMTEXT);
2946     X11DRV_CLIPBOARD_SynthesizeData(CF_UNICODETEXT);
2947
2948     /* Enhmetafile <-> MetafilePict mapping */
2949     X11DRV_CLIPBOARD_SynthesizeData(CF_ENHMETAFILE);
2950     X11DRV_CLIPBOARD_SynthesizeData(CF_METAFILEPICT);
2951
2952     /* DIB <-> Bitmap mapping */
2953     X11DRV_CLIPBOARD_SynthesizeData(CF_DIB);
2954     X11DRV_CLIPBOARD_SynthesizeData(CF_BITMAP);
2955
2956     TRACE("%d formats added to cached data\n", ClipDataCount - count);
2957 }
2958
2959
2960 /***********************************************************************
2961  *           X11DRV_SelectionRequest_TARGETS
2962  *  Service a TARGETS selection request event
2963  */
2964 static Atom X11DRV_SelectionRequest_TARGETS( Display *display, Window requestor,
2965                                              Atom target, Atom rprop )
2966 {
2967     UINT i;
2968     Atom* targets;
2969     ULONG cTargets;
2970     LPWINE_CLIPFORMAT lpFormats;
2971     LPWINE_CLIPDATA lpData;
2972
2973     /* Create X atoms for any clipboard types which don't have atoms yet.
2974      * This avoids sending bogus zero atoms.
2975      * Without this, copying might not have access to all clipboard types.
2976      * FIXME: is it safe to call this here?
2977      */
2978     intern_atoms();
2979
2980     /*
2981      * Count the number of items we wish to expose as selection targets.
2982      */
2983     cTargets = 1; /* Include TARGETS */
2984
2985     if (!(lpData = ClipData)) return None;
2986
2987     do
2988     {
2989         lpFormats = ClipFormats;
2990
2991         while (lpFormats)
2992         {
2993             if ((lpFormats->wFormatID == lpData->wFormatID) &&
2994                 lpFormats->lpDrvExportFunc && lpFormats->drvData)
2995                 cTargets++;
2996
2997             lpFormats = lpFormats->NextFormat;
2998         }
2999
3000         lpData = lpData->NextData;
3001     }
3002     while (lpData != ClipData);
3003
3004     TRACE(" found %d formats\n", cTargets);
3005
3006     /* Allocate temp buffer */
3007     targets = HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
3008     if(targets == NULL)
3009         return None;
3010
3011     i = 0;
3012     lpData = ClipData;
3013     targets[i++] = x11drv_atom(TARGETS);
3014
3015     do
3016     {
3017         lpFormats = ClipFormats;
3018
3019         while (lpFormats)
3020         {
3021             if ((lpFormats->wFormatID == lpData->wFormatID) &&
3022                 lpFormats->lpDrvExportFunc && lpFormats->drvData)
3023                 targets[i++] = lpFormats->drvData;
3024
3025             lpFormats = lpFormats->NextFormat;
3026         }
3027
3028         lpData = lpData->NextData;
3029     }
3030     while (lpData != ClipData);
3031
3032     wine_tsx11_lock();
3033
3034     if (TRACE_ON(clipboard))
3035     {
3036         unsigned int i;
3037         for ( i = 0; i < cTargets; i++)
3038         {
3039             char *itemFmtName = XGetAtomName(display, targets[i]);
3040             TRACE("\tAtom# %d:  Property %ld Type %s\n", i, targets[i], itemFmtName);
3041             XFree(itemFmtName);
3042         }
3043     }
3044
3045     /* We may want to consider setting the type to xaTargets instead,
3046      * in case some apps expect this instead of XA_ATOM */
3047     XChangeProperty(display, requestor, rprop, XA_ATOM, 32,
3048                     PropModeReplace, (unsigned char *)targets, cTargets);
3049     wine_tsx11_unlock();
3050
3051     HeapFree(GetProcessHeap(), 0, targets);
3052
3053     return rprop;
3054 }
3055
3056
3057 /***********************************************************************
3058  *           X11DRV_SelectionRequest_MULTIPLE
3059  *  Service a MULTIPLE selection request event
3060  *  rprop contains a list of (target,property) atom pairs.
3061  *  The first atom names a target and the second names a property.
3062  *  The effect is as if we have received a sequence of SelectionRequest events
3063  *  (one for each atom pair) except that:
3064  *  1. We reply with a SelectionNotify only when all the requested conversions
3065  *  have been performed.
3066  *  2. If we fail to convert the target named by an atom in the MULTIPLE property,
3067  *  we replace the atom in the property by None.
3068  */
3069 static Atom X11DRV_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
3070 {
3071     Display *display = pevent->display;
3072     Atom           rprop;
3073     Atom           atype=AnyPropertyType;
3074     int            aformat;
3075     unsigned long  remain;
3076     Atom*          targetPropList=NULL;
3077     unsigned long  cTargetPropList = 0;
3078
3079     /* If the specified property is None the requestor is an obsolete client.
3080      * We support these by using the specified target atom as the reply property.
3081      */
3082     rprop = pevent->property;
3083     if( rprop == None )
3084         rprop = pevent->target;
3085     if (!rprop)
3086         return 0;
3087
3088     /* Read the MULTIPLE property contents. This should contain a list of
3089      * (target,property) atom pairs.
3090      */
3091     wine_tsx11_lock();
3092     if(XGetWindowProperty(display, pevent->requestor, rprop,
3093                           0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
3094                           &cTargetPropList, &remain,
3095                           (unsigned char**)&targetPropList) != Success)
3096     {
3097         wine_tsx11_unlock();
3098         TRACE("\tCouldn't read MULTIPLE property\n");
3099     }
3100     else
3101     {
3102         TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
3103               XGetAtomName(display, atype), aformat, cTargetPropList, remain);
3104         wine_tsx11_unlock();
3105
3106         /*
3107          * Make sure we got what we expect.
3108          * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
3109          * in a MULTIPLE selection request should be of type ATOM_PAIR.
3110          * However some X apps(such as XPaint) are not compliant with this and return
3111          * a user defined atom in atype when XGetWindowProperty is called.
3112          * The data *is* an atom pair but is not denoted as such.
3113          */
3114         if(aformat == 32 /* atype == xAtomPair */ )
3115         {
3116             unsigned int i;
3117
3118             /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
3119              * for each (target,property) pair */
3120
3121             for (i = 0; i < cTargetPropList; i+=2)
3122             {
3123                 XSelectionRequestEvent event;
3124
3125                 if (TRACE_ON(clipboard))
3126                 {
3127                     char *targetName, *propName;
3128                     wine_tsx11_lock();
3129                     targetName = XGetAtomName(display, targetPropList[i]);
3130                     propName = XGetAtomName(display, targetPropList[i+1]);
3131                     TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
3132                           i/2, targetName, propName);
3133                     XFree(targetName);
3134                     XFree(propName);
3135                     wine_tsx11_unlock();
3136                 }
3137
3138                 /* We must have a non "None" property to service a MULTIPLE target atom */
3139                 if ( !targetPropList[i+1] )
3140                 {
3141                     TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
3142                     continue;
3143                 }
3144
3145                 /* Set up an XSelectionRequestEvent for this (target,property) pair */
3146                 event = *pevent;
3147                 event.target = targetPropList[i];
3148                 event.property = targetPropList[i+1];
3149
3150                 /* Fire a SelectionRequest, informing the handler that we are processing
3151                  * a MULTIPLE selection request event.
3152                  */
3153                 X11DRV_HandleSelectionRequest( hWnd, &event, TRUE );
3154             }
3155         }
3156
3157         /* Free the list of targets/properties */
3158         wine_tsx11_lock();
3159         XFree(targetPropList);
3160         wine_tsx11_unlock();
3161     }
3162
3163     return rprop;
3164 }
3165
3166
3167 /***********************************************************************
3168  *           X11DRV_HandleSelectionRequest
3169  *  Process an event selection request event.
3170  *  The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
3171  *  recursively while servicing a "MULTIPLE" selection target.
3172  *
3173  *  Note: We only receive this event when WINE owns the X selection
3174  */
3175 static void X11DRV_HandleSelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
3176 {
3177     Display *display = event->display;
3178     XSelectionEvent result;
3179     Atom rprop = None;
3180     Window request = event->requestor;
3181
3182     TRACE("\n");
3183
3184     /*
3185      * We can only handle the selection request if :
3186      * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
3187      * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
3188      * since this has been already done.
3189      */
3190     if ( !bIsMultiple )
3191     {
3192         if (((event->selection != XA_PRIMARY) && (event->selection != x11drv_atom(CLIPBOARD))))
3193             goto END;
3194     }
3195
3196     /* If the specified property is None the requestor is an obsolete client.
3197      * We support these by using the specified target atom as the reply property.
3198      */
3199     rprop = event->property;
3200     if( rprop == None )
3201         rprop = event->target;
3202
3203     if(event->target == x11drv_atom(TARGETS))  /*  Return a list of all supported targets */
3204     {
3205         /* TARGETS selection request */
3206         rprop = X11DRV_SelectionRequest_TARGETS( display, request, event->target, rprop );
3207     }
3208     else if(event->target == x11drv_atom(MULTIPLE))  /*  rprop contains a list of (target, property) atom pairs */
3209     {
3210         /* MULTIPLE selection request */
3211         rprop = X11DRV_SelectionRequest_MULTIPLE( hWnd, event );
3212     }
3213     else
3214     {
3215         LPWINE_CLIPFORMAT lpFormat = X11DRV_CLIPBOARD_LookupProperty(NULL, event->target);
3216
3217         if (lpFormat && lpFormat->lpDrvExportFunc)
3218         {
3219             LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(lpFormat->wFormatID);
3220
3221             if (lpData)
3222             {
3223                 unsigned char* lpClipData;
3224                 DWORD cBytes;
3225                 HANDLE hClipData = lpFormat->lpDrvExportFunc(display, request, event->target,
3226                                                              rprop, lpData, &cBytes);
3227
3228                 if (hClipData && (lpClipData = GlobalLock(hClipData)))
3229                 {
3230                     TRACE("\tUpdating property %s, %d bytes\n", debugstr_w(lpFormat->Name), cBytes);
3231
3232                     wine_tsx11_lock();
3233                     XChangeProperty(display, request, rprop, event->target,
3234                                     8, PropModeReplace, lpClipData, cBytes);
3235                     wine_tsx11_unlock();
3236
3237                     GlobalUnlock(hClipData);
3238                     GlobalFree(hClipData);
3239                 }
3240             }
3241         }
3242     }
3243
3244 END:
3245     /* reply to sender
3246      * SelectionNotify should be sent only at the end of a MULTIPLE request
3247      */
3248     if ( !bIsMultiple )
3249     {
3250         result.type = SelectionNotify;
3251         result.display = display;
3252         result.requestor = request;
3253         result.selection = event->selection;
3254         result.property = rprop;
3255         result.target = event->target;
3256         result.time = event->time;
3257         TRACE("Sending SelectionNotify event...\n");
3258         wine_tsx11_lock();
3259         XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
3260         wine_tsx11_unlock();
3261     }
3262 }
3263
3264
3265 /***********************************************************************
3266  *           X11DRV_SelectionRequest
3267  */
3268 void X11DRV_SelectionRequest( HWND hWnd, XEvent *event )
3269 {
3270     X11DRV_HandleSelectionRequest( hWnd, &event->xselectionrequest, FALSE );
3271 }
3272
3273
3274 /***********************************************************************
3275  *           X11DRV_SelectionClear
3276  */
3277 void X11DRV_SelectionClear( HWND hWnd, XEvent *xev )
3278 {
3279     XSelectionClearEvent *event = &xev->xselectionclear;
3280     if (event->selection == XA_PRIMARY || event->selection == x11drv_atom(CLIPBOARD))
3281         X11DRV_CLIPBOARD_ReleaseSelection( event->display, event->selection,
3282                                            event->window, hWnd, event->time );
3283 }
3284
3285 /***********************************************************************
3286  *           X11DRV_Clipboard_Cleanup
3287  */
3288 void X11DRV_Clipboard_Cleanup(void)
3289 {
3290     selectionAcquired = S_NOSELECTION;
3291
3292     X11DRV_EmptyClipboard(FALSE);
3293 }