winemac: Add support for CF_HDROP clipboard format, mapped to/from Cocoa's NSFilename...
[wine] / dlls / winemac.drv / clipboard.c
1 /*
2  * Mac clipboard driver
3  *
4  * Copyright 1994 Martin Ayotte
5  *           1996 Alex Korobka
6  *           1999 Noel Borthwick
7  *           2003 Ulrich Czekalla for CodeWeavers
8  * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24
25 #include "config.h"
26
27 #include "macdrv.h"
28 #include "winuser.h"
29 #include "shellapi.h"
30 #include "shlobj.h"
31 #include "wine/list.h"
32 #include "wine/server.h"
33 #include "wine/unicode.h"
34
35
36 WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
37
38
39 /**************************************************************************
40  *              Types
41  **************************************************************************/
42
43 typedef struct
44 {
45     HWND hwnd_owner;
46     UINT flags;
47 } CLIPBOARDINFO, *LPCLIPBOARDINFO;
48
49 typedef HANDLE (*DRVIMPORTFUNC)(CFDataRef data);
50 typedef CFDataRef (*DRVEXPORTFUNC)(HANDLE data);
51
52 typedef struct
53 {
54     struct list     entry;
55     UINT            format_id;
56     CFStringRef     type;
57     DRVIMPORTFUNC   import_func;
58     DRVEXPORTFUNC   export_func;
59     BOOL            synthesized;
60 } WINE_CLIPFORMAT;
61
62
63 /**************************************************************************
64  *              Constants
65  **************************************************************************/
66
67
68 /**************************************************************************
69  *              Forward Function Declarations
70  **************************************************************************/
71
72 static HANDLE import_clipboard_data(CFDataRef data);
73 static HANDLE import_bmp_to_bitmap(CFDataRef data);
74 static HANDLE import_bmp_to_dib(CFDataRef data);
75 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data);
76 static HANDLE import_oemtext_to_text(CFDataRef data);
77 static HANDLE import_oemtext_to_unicodetext(CFDataRef data);
78 static HANDLE import_text_to_oemtext(CFDataRef data);
79 static HANDLE import_text_to_unicodetext(CFDataRef data);
80 static HANDLE import_unicodetext_to_oemtext(CFDataRef data);
81 static HANDLE import_unicodetext_to_text(CFDataRef data);
82 static HANDLE import_utf8_to_oemtext(CFDataRef data);
83 static HANDLE import_utf8_to_text(CFDataRef data);
84 static HANDLE import_utf8_to_unicodetext(CFDataRef data);
85
86 static CFDataRef export_clipboard_data(HANDLE data);
87 static CFDataRef export_bitmap_to_bmp(HANDLE data);
88 static CFDataRef export_dib_to_bmp(HANDLE data);
89 static CFDataRef export_hdrop_to_filenames(HANDLE data);
90 static CFDataRef export_oemtext_to_utf8(HANDLE data);
91 static CFDataRef export_text_to_utf8(HANDLE data);
92 static CFDataRef export_unicodetext_to_utf8(HANDLE data);
93
94
95 /**************************************************************************
96  *              Static Variables
97  **************************************************************************/
98
99 /* Clipboard formats */
100 static struct list format_list = LIST_INIT(format_list);
101
102 /*  There are two naming schemes involved and we want to have a mapping between
103     them.  There are Win32 clipboard format names and there are Mac pasteboard
104     types.
105
106     The Win32 standard clipboard formats don't have names, but they are associated
107     with Mac pasteboard types through the following tables, which are used to
108     initialize the format_list.  Where possible, the standard clipboard formats
109     are mapped to predefined pasteboard type UTIs.  Otherwise, we create Wine-
110     specific types of the form "org.winehq.builtin.<format>", where <format> is
111     the name of the symbolic constant for the format minus "CF_" and lowercased.
112     E.g. CF_BITMAP -> org.winehq.builtin.bitmap.
113
114     Win32 clipboard formats which originate in a Windows program may be registered
115     with an arbitrary name.  We construct a Mac pasteboard type from these by
116     prepending "org.winehq.registered." to the registered name.
117
118     Likewise, Mac pasteboard types which originate in other apps may have
119     arbitrary type strings.  We construct a Win32 clipboard format name from
120     these by prepending "org.winehq.mac-type." to the Mac pasteboard type.
121
122     Summary:
123     Win32 clipboard format names:
124         <none>                              standard clipboard format; maps via
125                                             format_list to either a predefined Mac UTI
126                                             or org.winehq.builtin.<format>.
127         org.winehq.mac-type.<Mac type>      representation of Mac type in Win32 land;
128                                             maps to <Mac type>
129         <other>                             name registered within Win32 land; maps to
130                                             org.winehq.registered.<other>
131     Mac pasteboard type names:
132         org.winehq.builtin.<format ID>      representation of Win32 standard clipboard
133                                             format for which there was no corresponding
134                                             predefined Mac UTI; maps via format_list
135         org.winehq.registered.<format name> representation of Win32 registered
136                                             clipboard format name; maps to <format name>
137         <other>                             Mac pasteboard type originating with system
138                                             or other apps; either maps via format_list
139                                             to a standard clipboard format or maps to
140                                             org.winehq.mac-type.<other>
141 */
142
143 static const struct
144 {
145     UINT          id;
146     CFStringRef   type;
147     DRVIMPORTFUNC import;
148     DRVEXPORTFUNC export;
149     BOOL          synthesized;
150 } builtin_format_ids[] =
151 {
152     { CF_DIBV5,             CFSTR("org.winehq.builtin.dibv5"),              import_clipboard_data,          export_clipboard_data,      FALSE },
153     { CF_DIF,               CFSTR("org.winehq.builtin.dif"),                import_clipboard_data,          export_clipboard_data,      FALSE },
154     { CF_DSPBITMAP,         CFSTR("org.winehq.builtin.dspbitmap"),          import_clipboard_data,          export_clipboard_data,      FALSE },
155     { CF_DSPENHMETAFILE,    CFSTR("org.winehq.builtin.dspenhmetafile"),     import_clipboard_data,          export_clipboard_data,      FALSE },
156     { CF_DSPMETAFILEPICT,   CFSTR("org.winehq.builtin.dspmetafilepict"),    import_clipboard_data,          export_clipboard_data,      FALSE },
157     { CF_DSPTEXT,           CFSTR("org.winehq.builtin.dsptext"),            import_clipboard_data,          export_clipboard_data,      FALSE },
158     { CF_LOCALE,            CFSTR("org.winehq.builtin.locale"),             import_clipboard_data,          export_clipboard_data,      FALSE },
159     { CF_OWNERDISPLAY,      CFSTR("org.winehq.builtin.ownerdisplay"),       import_clipboard_data,          export_clipboard_data,      FALSE },
160     { CF_PALETTE,           CFSTR("org.winehq.builtin.palette"),            import_clipboard_data,          export_clipboard_data,      FALSE },
161     { CF_PENDATA,           CFSTR("org.winehq.builtin.pendata"),            import_clipboard_data,          export_clipboard_data,      FALSE },
162     { CF_RIFF,              CFSTR("org.winehq.builtin.riff"),               import_clipboard_data,          export_clipboard_data,      FALSE },
163     { CF_SYLK,              CFSTR("org.winehq.builtin.sylk"),               import_clipboard_data,          export_clipboard_data,      FALSE },
164     { CF_TIFF,              CFSTR("public.tiff"),                           import_clipboard_data,          export_clipboard_data,      FALSE },
165     { CF_WAVE,              CFSTR("com.microsoft.waveform-audio"),          import_clipboard_data,          export_clipboard_data,      FALSE },
166
167     { CF_UNICODETEXT,       CFSTR("org.winehq.builtin.unicodetext"),        import_clipboard_data,          export_clipboard_data,      FALSE },
168     { CF_TEXT,              CFSTR("org.winehq.builtin.unicodetext"),        import_unicodetext_to_text,     NULL,                       TRUE },
169     { CF_OEMTEXT,           CFSTR("org.winehq.builtin.unicodetext"),        import_unicodetext_to_oemtext,  NULL,                       TRUE },
170
171     { CF_TEXT,              CFSTR("org.winehq.builtin.text"),               import_clipboard_data,          export_clipboard_data,      FALSE },
172     { CF_UNICODETEXT,       CFSTR("org.winehq.builtin.text"),               import_text_to_unicodetext,     NULL,                       TRUE },
173     { CF_OEMTEXT,           CFSTR("org.winehq.builtin.text"),               import_text_to_oemtext,         NULL,                       TRUE },
174
175     { CF_OEMTEXT,           CFSTR("org.winehq.builtin.oemtext"),            import_clipboard_data,          export_clipboard_data,      FALSE },
176     { CF_UNICODETEXT,       CFSTR("org.winehq.builtin.oemtext"),            import_oemtext_to_unicodetext,  NULL,                       TRUE },
177     { CF_TEXT,              CFSTR("org.winehq.builtin.oemtext"),            import_oemtext_to_text,         NULL,                       TRUE },
178
179     { CF_UNICODETEXT,       CFSTR("public.utf8-plain-text"),                import_utf8_to_unicodetext,     export_unicodetext_to_utf8, TRUE },
180     { CF_TEXT,              CFSTR("public.utf8-plain-text"),                import_utf8_to_text,            export_text_to_utf8,        TRUE },
181     { CF_OEMTEXT,           CFSTR("public.utf8-plain-text"),                import_utf8_to_oemtext,         export_oemtext_to_utf8,     TRUE },
182
183     { CF_DIB,               CFSTR("org.winehq.builtin.dib"),                import_clipboard_data,          export_clipboard_data,      FALSE },
184     { CF_DIB,               CFSTR("com.microsoft.bmp"),                     import_bmp_to_dib,              export_dib_to_bmp,          TRUE },
185
186     { CF_BITMAP,            CFSTR("org.winehq.builtin.bitmap"),             import_bmp_to_bitmap,           export_bitmap_to_bmp,       FALSE },
187     { CF_BITMAP,            CFSTR("com.microsoft.bmp"),                     import_bmp_to_bitmap,           export_bitmap_to_bmp,       TRUE },
188
189     { CF_HDROP,             CFSTR("org.winehq.builtin.hdrop"),              import_clipboard_data,          export_clipboard_data,      FALSE },
190     { CF_HDROP,             CFSTR("NSFilenamesPboardType"),                 import_nsfilenames_to_hdrop,    export_hdrop_to_filenames,  TRUE },
191 };
192
193 static const WCHAR wszRichTextFormat[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
194 static const WCHAR wszGIF[] = {'G','I','F',0};
195 static const WCHAR wszJFIF[] = {'J','F','I','F',0};
196 static const WCHAR wszPNG[] = {'P','N','G',0};
197 static const WCHAR wszHTMLFormat[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
198 static const struct
199 {
200     LPCWSTR     name;
201     CFStringRef type;
202 } builtin_format_names[] =
203 {
204     { wszRichTextFormat,    CFSTR("public.rtf") },
205     { wszGIF,               CFSTR("com.compuserve.gif") },
206     { wszJFIF,              CFSTR("public.jpeg") },
207     { wszPNG,               CFSTR("public.png") },
208     { wszHTMLFormat,        CFSTR("public.html") },
209 };
210
211 /* The prefix prepended to an external Mac pasteboard type to make a Win32 clipboard format name. org.winehq.mac-type. */
212 static const WCHAR mac_type_name_prefix[] = {'o','r','g','.','w','i','n','e','h','q','.','m','a','c','-','t','y','p','e','.',0};
213
214 /* The prefix prepended to a Win32 clipboard format name to make a Mac pasteboard type. */
215 static const CFStringRef registered_name_type_prefix = CFSTR("org.winehq.registered.");
216
217
218 /**************************************************************************
219  *              Internal Clipboard implementation methods
220  **************************************************************************/
221
222 /*
223  * format_list functions
224  */
225
226 /**************************************************************************
227  *              debugstr_format
228  */
229 static const char *debugstr_format(UINT id)
230 {
231     WCHAR buffer[256];
232
233     if (GetClipboardFormatNameW(id, buffer, 256))
234         return wine_dbg_sprintf("0x%04x %s", id, debugstr_w(buffer));
235
236     switch (id)
237     {
238 #define BUILTIN(id) case id: return #id;
239     BUILTIN(CF_TEXT)
240     BUILTIN(CF_BITMAP)
241     BUILTIN(CF_METAFILEPICT)
242     BUILTIN(CF_SYLK)
243     BUILTIN(CF_DIF)
244     BUILTIN(CF_TIFF)
245     BUILTIN(CF_OEMTEXT)
246     BUILTIN(CF_DIB)
247     BUILTIN(CF_PALETTE)
248     BUILTIN(CF_PENDATA)
249     BUILTIN(CF_RIFF)
250     BUILTIN(CF_WAVE)
251     BUILTIN(CF_UNICODETEXT)
252     BUILTIN(CF_ENHMETAFILE)
253     BUILTIN(CF_HDROP)
254     BUILTIN(CF_LOCALE)
255     BUILTIN(CF_DIBV5)
256     BUILTIN(CF_OWNERDISPLAY)
257     BUILTIN(CF_DSPTEXT)
258     BUILTIN(CF_DSPBITMAP)
259     BUILTIN(CF_DSPMETAFILEPICT)
260     BUILTIN(CF_DSPENHMETAFILE)
261 #undef BUILTIN
262     default: return wine_dbg_sprintf("0x%04x", id);
263     }
264 }
265
266
267 /**************************************************************************
268  *              insert_clipboard_format
269  */
270 static WINE_CLIPFORMAT *insert_clipboard_format(UINT id, CFStringRef type)
271 {
272     WINE_CLIPFORMAT *format;
273
274     format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format));
275
276     if (format == NULL)
277     {
278         WARN("No more memory for a new format!\n");
279         return NULL;
280     }
281     format->format_id = id;
282     format->import_func = import_clipboard_data;
283     format->export_func = export_clipboard_data;
284     format->synthesized = FALSE;
285
286     if (type)
287         format->type = CFStringCreateCopy(NULL, type);
288     else
289     {
290         WCHAR buffer[256];
291
292         GetClipboardFormatNameW(format->format_id, buffer, 256);
293         if (!strncmpW(buffer, mac_type_name_prefix, strlenW(mac_type_name_prefix)))
294         {
295             const WCHAR *p = buffer + strlenW(mac_type_name_prefix);
296             format->type = CFStringCreateWithCharacters(NULL, (UniChar*)p, strlenW(p));
297         }
298         else
299         {
300             format->type = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%S"),
301                                                     registered_name_type_prefix, buffer);
302         }
303     }
304
305     list_add_tail(&format_list, &format->entry);
306
307     TRACE("Registering format %s type %s\n", debugstr_format(format->format_id),
308           debugstr_cf(format->type));
309
310     return format;
311 }
312
313
314 /**************************************************************************
315  *              register_format
316  *
317  * Register a custom Mac clipboard format.
318  */
319 static WINE_CLIPFORMAT* register_format(UINT id, CFStringRef type)
320 {
321     WINE_CLIPFORMAT *format;
322
323     /* walk format chain to see if it's already registered */
324     LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
325         if (format->format_id == id) return format;
326
327     return insert_clipboard_format(id, type);
328 }
329
330
331 /**************************************************************************
332  *              format_for_type
333  */
334 static WINE_CLIPFORMAT* format_for_type(WINE_CLIPFORMAT *current, CFStringRef type)
335 {
336     struct list *ptr = current ? &current->entry : &format_list;
337     WINE_CLIPFORMAT *format = NULL;
338
339     TRACE("current %p/%s type %s\n", current, debugstr_format(current ? current->format_id : 0), debugstr_cf(type));
340
341     while ((ptr = list_next(&format_list, ptr)))
342     {
343         format = LIST_ENTRY(ptr, WINE_CLIPFORMAT, entry);
344         if (CFEqual(format->type, type))
345         {
346             TRACE(" -> %p/%s\n", format, debugstr_format(format->format_id));
347             return format;
348         }
349     }
350
351     if (!current)
352     {
353         LPWSTR name;
354
355         if (CFStringHasPrefix(type, CFSTR("org.winehq.builtin.")))
356         {
357             ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
358                 debugstr_cf(type));
359             return NULL;
360         }
361         else if (CFStringHasPrefix(type, registered_name_type_prefix))
362         {
363             int len = CFStringGetLength(type) - CFStringGetLength(registered_name_type_prefix);
364             name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
365             CFStringGetCharacters(type, CFRangeMake(CFStringGetLength(registered_name_type_prefix), len),
366                                   (UniChar*)name);
367             name[len] = 0;
368         }
369         else
370         {
371             int len = strlenW(mac_type_name_prefix) + CFStringGetLength(type);
372             name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
373             memcpy(name, mac_type_name_prefix, sizeof(mac_type_name_prefix));
374             CFStringGetCharacters(type, CFRangeMake(0, CFStringGetLength(type)),
375                                   (UniChar*)name + strlenW(mac_type_name_prefix));
376             name[len] = 0;
377         }
378
379         format = register_format(RegisterClipboardFormatW(name), type);
380         if (!format)
381             ERR("Failed to register format for type %s name %s\n", debugstr_cf(type), debugstr_w(name));
382
383         HeapFree(GetProcessHeap(), 0, name);
384     }
385
386     TRACE(" -> %p/%s\n", format, debugstr_format(format ? format->format_id : 0));
387     return format;
388 }
389
390
391 /**************************************************************************
392  *              convert_text
393  *
394  *  Convert string data between code pages or to/from wide characters.  The
395  *  special value of (UINT)-1 for a code page indicates to use wide
396  *  characters.
397  */
398 static HANDLE convert_text(const void *src, int src_len, UINT src_cp, UINT dest_cp)
399 {
400     HANDLE ret = NULL;
401     const WCHAR *wstr;
402     int wstr_len;
403     HANDLE handle;
404     char *p;
405
406     if (src_cp == (UINT)-1)
407     {
408         wstr = src;
409         wstr_len = src_len / sizeof(WCHAR);
410     }
411     else
412     {
413         WCHAR *temp;
414
415         wstr_len = MultiByteToWideChar(src_cp, 0, src, src_len, NULL, 0);
416         if (!src_len || ((const char*)src)[src_len - 1]) wstr_len += 1;
417         temp = HeapAlloc(GetProcessHeap(), 0, wstr_len * sizeof(WCHAR));
418         MultiByteToWideChar(src_cp, 0, src, src_len, temp, wstr_len);
419         temp[wstr_len - 1] = 0;
420         wstr = temp;
421     }
422
423     if (dest_cp == (UINT)-1)
424     {
425         handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, wstr_len * sizeof(WCHAR));
426         if (handle && (p = GlobalLock(handle)))
427         {
428             memcpy(p, wstr, wstr_len * sizeof(WCHAR));
429             GlobalUnlock(handle);
430             ret = handle;
431         }
432     }
433     else
434     {
435         INT len;
436
437         len = WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, NULL, 0, NULL, NULL);
438         if (!wstr_len || wstr[wstr_len - 1]) len += 1;
439         handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
440
441         if (handle && (p = GlobalLock(handle)))
442         {
443             WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, p, len, NULL, NULL);
444             p[len - 1] = 0;
445             GlobalUnlock(handle);
446             ret = handle;
447         }
448     }
449
450     return ret;
451 }
452
453
454 /**************************************************************************
455  *              convert_unicodetext_to_codepage
456  */
457 static HANDLE convert_unicodetext_to_codepage(HANDLE unicode_handle, UINT cp)
458 {
459     LPWSTR unicode_string = GlobalLock(unicode_handle);
460     HANDLE ret = NULL;
461
462     if (unicode_string)
463     {
464         ret = convert_text(unicode_string, GlobalSize(unicode_handle), -1, cp);
465         GlobalUnlock(unicode_handle);
466     }
467
468     return ret;
469 }
470
471
472 /***********************************************************************
473  *              bitmap_info_size
474  *
475  * Return the size of the bitmap info structure including color table.
476  */
477 static int bitmap_info_size(const BITMAPINFO *info, WORD coloruse)
478 {
479     unsigned int colors, size, masks = 0;
480
481     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
482     {
483         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER*)info;
484         colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
485         return sizeof(BITMAPCOREHEADER) + colors *
486              ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
487     }
488     else  /* assume BITMAPINFOHEADER */
489     {
490         colors = info->bmiHeader.biClrUsed;
491         if (!colors && (info->bmiHeader.biBitCount <= 8))
492             colors = 1 << info->bmiHeader.biBitCount;
493         if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
494         size = max(info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD));
495         return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
496     }
497 }
498
499
500 /***********************************************************************
501  *              create_dib_from_bitmap
502  *
503  * Allocates a packed DIB and copies the bitmap data into it.
504  */
505 static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp)
506 {
507     BITMAP bmp;
508     HDC hdc;
509     HGLOBAL hPackedDIB;
510     LPBYTE pPackedDIB;
511     LPBITMAPINFOHEADER pbmiHeader;
512     unsigned int cDataSize, cPackedSize, OffsetBits;
513     int nLinesCopied;
514
515     if (!GetObjectW(hBmp, sizeof(bmp), &bmp)) return 0;
516
517     /*
518      * A packed DIB contains a BITMAPINFO structure followed immediately by
519      * an optional color palette and the pixel data.
520      */
521
522     /* Calculate the size of the packed DIB */
523     cDataSize = abs(bmp.bmHeight) * (((bmp.bmWidth * bmp.bmBitsPixel + 31) / 8) & ~3);
524     cPackedSize = sizeof(BITMAPINFOHEADER)
525                   + ((bmp.bmBitsPixel <= 8) ? (sizeof(RGBQUAD) * (1 << bmp.bmBitsPixel)) : 0)
526                   + cDataSize;
527     /* Get the offset to the bits */
528     OffsetBits = cPackedSize - cDataSize;
529
530     /* Allocate the packed DIB */
531     TRACE("\tAllocating packed DIB of size %d\n", cPackedSize);
532     hPackedDIB = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cPackedSize);
533     if (!hPackedDIB)
534     {
535         WARN("Could not allocate packed DIB!\n");
536         return 0;
537     }
538
539     /* A packed DIB starts with a BITMAPINFOHEADER */
540     pPackedDIB = GlobalLock(hPackedDIB);
541     pbmiHeader = (LPBITMAPINFOHEADER)pPackedDIB;
542
543     /* Init the BITMAPINFOHEADER */
544     pbmiHeader->biSize = sizeof(BITMAPINFOHEADER);
545     pbmiHeader->biWidth = bmp.bmWidth;
546     pbmiHeader->biHeight = bmp.bmHeight;
547     pbmiHeader->biPlanes = 1;
548     pbmiHeader->biBitCount = bmp.bmBitsPixel;
549     pbmiHeader->biCompression = BI_RGB;
550     pbmiHeader->biSizeImage = 0;
551     pbmiHeader->biXPelsPerMeter = pbmiHeader->biYPelsPerMeter = 0;
552     pbmiHeader->biClrUsed = 0;
553     pbmiHeader->biClrImportant = 0;
554
555     /* Retrieve the DIB bits from the bitmap and fill in the
556      * DIB color table if present */
557     hdc = GetDC(0);
558     nLinesCopied = GetDIBits(hdc,                       /* Handle to device context */
559                              hBmp,                      /* Handle to bitmap */
560                              0,                         /* First scan line to set in dest bitmap */
561                              bmp.bmHeight,              /* Number of scan lines to copy */
562                              pPackedDIB + OffsetBits,   /* [out] Address of array for bitmap bits */
563                              (LPBITMAPINFO) pbmiHeader, /* [out] Address of BITMAPINFO structure */
564                              0);                        /* RGB or palette index */
565     GlobalUnlock(hPackedDIB);
566     ReleaseDC(0, hdc);
567
568     /* Cleanup if GetDIBits failed */
569     if (nLinesCopied != bmp.bmHeight)
570     {
571         TRACE("\tGetDIBits returned %d. Actual lines=%d\n", nLinesCopied, bmp.bmHeight);
572         GlobalFree(hPackedDIB);
573         hPackedDIB = 0;
574     }
575     return hPackedDIB;
576 }
577
578
579 /**************************************************************************
580  *              import_clipboard_data
581  *
582  *  Generic import clipboard data routine.
583  */
584 static HANDLE import_clipboard_data(CFDataRef data)
585 {
586     HANDLE data_handle = NULL;
587
588     size_t len = CFDataGetLength(data);
589     if (len)
590     {
591         LPVOID p;
592
593         /* Turn on the DDESHARE flag to enable shared 32 bit memory */
594         data_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
595         if (!data_handle)
596             return NULL;
597
598         if ((p = GlobalLock(data_handle)))
599         {
600             memcpy(p, CFDataGetBytePtr(data), len);
601             GlobalUnlock(data_handle);
602         }
603         else
604         {
605             GlobalFree(data_handle);
606             data_handle = NULL;
607         }
608     }
609
610     return data_handle;
611 }
612
613
614 /**************************************************************************
615  *              import_bmp_to_bitmap
616  *
617  *  Import BMP data, converting to CF_BITMAP format.
618  */
619 static HANDLE import_bmp_to_bitmap(CFDataRef data)
620 {
621     HANDLE ret = 0;
622     HANDLE dib = import_bmp_to_dib(data);
623     BITMAPINFO *bmi;
624
625     if (dib && (bmi = GlobalLock(dib)))
626     {
627         HDC hdc;
628         unsigned int offset;
629
630         hdc = GetDC(NULL);
631
632         offset = bitmap_info_size(bmi, DIB_RGB_COLORS);
633
634         ret = CreateDIBitmap(hdc, &bmi->bmiHeader, CBM_INIT, (LPBYTE)bmi + offset,
635                              bmi, DIB_RGB_COLORS);
636
637         GlobalUnlock(dib);
638         ReleaseDC(NULL, hdc);
639     }
640
641     GlobalFree(dib);
642     return ret;
643 }
644
645
646 /**************************************************************************
647  *              import_bmp_to_dib
648  *
649  *  Import BMP data, converting to CF_DIB format.  This just entails
650  *  stripping the BMP file format header.
651  */
652 static HANDLE import_bmp_to_dib(CFDataRef data)
653 {
654     HANDLE ret = 0;
655     BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)CFDataGetBytePtr(data);
656     CFIndex len = CFDataGetLength(data);
657
658     if (len >= sizeof(*bfh) + sizeof(BITMAPCOREHEADER) &&
659         bfh->bfType == 0x4d42 /* "BM" */)
660     {
661         BITMAPINFO *bmi = (BITMAPINFO*)(bfh + 1);
662         BYTE* p;
663
664         len -= sizeof(*bfh);
665         ret = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
666         if (!ret || !(p = GlobalLock(ret)))
667         {
668             GlobalFree(ret);
669             return 0;
670         }
671
672         memcpy(p, bmi, len);
673         GlobalUnlock(ret);
674     }
675
676     return ret;
677 }
678
679
680 /**************************************************************************
681  *              import_nsfilenames_to_hdrop
682  *
683  *  Import NSFilenamesPboardType data, converting the property-list-
684  *  serialized array of path strings to CF_HDROP.
685  */
686 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data)
687 {
688     HDROP hdrop = NULL;
689     CFArrayRef names;
690     CFIndex count, i;
691     size_t len;
692     char *buffer = NULL;
693     WCHAR **paths = NULL;
694     DROPFILES* dropfiles;
695     UniChar* p;
696
697     TRACE("data %s\n", debugstr_cf(data));
698
699     names = (CFArrayRef)CFPropertyListCreateWithData(NULL, data, kCFPropertyListImmutable,
700                                                      NULL, NULL);
701     if (!names || CFGetTypeID(names) != CFArrayGetTypeID())
702     {
703         WARN("failed to interpret data as a CFArray\n");
704         goto done;
705     }
706
707     count = CFArrayGetCount(names);
708
709     len = 0;
710     for (i = 0; i < count; i++)
711     {
712         CFIndex this_len;
713         CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
714         TRACE("    %s\n", debugstr_cf(name));
715         if (CFGetTypeID(name) != CFStringGetTypeID())
716         {
717             WARN("non-string in array\n");
718             goto done;
719         }
720
721         this_len = CFStringGetMaximumSizeOfFileSystemRepresentation(name);
722         if (this_len > len)
723             len = this_len;
724     }
725
726     buffer = HeapAlloc(GetProcessHeap(), 0, len);
727     if (!buffer)
728     {
729         WARN("failed to allocate buffer for file-system representations\n");
730         goto done;
731     }
732
733     paths = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(paths[0]));
734     if (!paths)
735     {
736         WARN("failed to allocate array of DOS paths\n");
737         goto done;
738     }
739
740     for (i = 0; i < count; i++)
741     {
742         CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
743         if (!CFStringGetFileSystemRepresentation(name, buffer, len))
744         {
745             WARN("failed to get file-system representation for %s\n", debugstr_cf(name));
746             goto done;
747         }
748         paths[i] = wine_get_dos_file_name(buffer);
749         if (!paths[i])
750         {
751             WARN("failed to get DOS path for %s\n", debugstr_a(buffer));
752             goto done;
753         }
754     }
755
756     len = 1; /* for the terminating null */
757     for (i = 0; i < count; i++)
758         len += strlenW(paths[i]) + 1;
759
760     hdrop = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(*dropfiles) + len * sizeof(WCHAR));
761     if (!hdrop || !(dropfiles = GlobalLock(hdrop)))
762     {
763         WARN("failed to allocate HDROP\n");
764         GlobalFree(hdrop);
765         hdrop = NULL;
766         goto done;
767     }
768
769     dropfiles->pFiles   = sizeof(*dropfiles);
770     dropfiles->pt.x     = 0;
771     dropfiles->pt.y     = 0;
772     dropfiles->fNC      = FALSE;
773     dropfiles->fWide    = TRUE;
774
775     p = (WCHAR*)(dropfiles + 1);
776     for (i = 0; i < count; i++)
777     {
778         strcpyW(p, paths[i]);
779         p += strlenW(p) + 1;
780     }
781     *p = 0;
782
783     GlobalUnlock(hdrop);
784
785 done:
786     if (paths)
787     {
788         for (i = 0; i < count; i++)
789             HeapFree(GetProcessHeap(), 0, paths[i]);
790         HeapFree(GetProcessHeap(), 0, paths);
791     }
792     HeapFree(GetProcessHeap(), 0, buffer);
793     if (names) CFRelease(names);
794     return hdrop;
795 }
796
797
798 /**************************************************************************
799  *              import_oemtext_to_text
800  *
801  *  Import CF_OEMTEXT data, converting the string to CF_TEXT.
802  */
803 static HANDLE import_oemtext_to_text(CFDataRef data)
804 {
805     return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, CP_ACP);
806 }
807
808
809 /**************************************************************************
810  *              import_oemtext_to_unicodetext
811  *
812  *  Import CF_OEMTEXT data, converting the string to CF_UNICODETEXT.
813  */
814 static HANDLE import_oemtext_to_unicodetext(CFDataRef data)
815 {
816     return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, -1);
817 }
818
819
820 /**************************************************************************
821  *              import_text_to_oemtext
822  *
823  *  Import CF_TEXT data, converting the string to CF_OEMTEXT.
824  */
825 static HANDLE import_text_to_oemtext(CFDataRef data)
826 {
827     return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, CP_OEMCP);
828 }
829
830
831 /**************************************************************************
832  *              import_text_to_unicodetext
833  *
834  *  Import CF_TEXT data, converting the string to CF_UNICODETEXT.
835  */
836 static HANDLE import_text_to_unicodetext(CFDataRef data)
837 {
838     return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, -1);
839 }
840
841
842 /**************************************************************************
843  *              import_unicodetext_to_oemtext
844  *
845  *  Import a CF_UNICODETEXT string, converting the string to CF_OEMTEXT.
846  */
847 static HANDLE import_unicodetext_to_oemtext(CFDataRef data)
848 {
849     return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_OEMCP);
850 }
851
852
853 /**************************************************************************
854  *              import_unicodetext_to_text
855  *
856  *  Import a CF_UNICODETEXT string, converting the string to CF_TEXT.
857  */
858 static HANDLE import_unicodetext_to_text(CFDataRef data)
859 {
860     return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_ACP);
861 }
862
863
864 /**************************************************************************
865  *              import_utf8_to_oemtext
866  *
867  *  Import a UTF-8 string, converting the string to CF_OEMTEXT.
868  */
869 static HANDLE import_utf8_to_oemtext(CFDataRef data)
870 {
871     HANDLE unicode_handle = import_utf8_to_unicodetext(data);
872     HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_OEMCP);
873
874     GlobalFree(unicode_handle);
875     return ret;
876 }
877
878
879 /**************************************************************************
880  *              import_utf8_to_text
881  *
882  *  Import a UTF-8 string, converting the string to CF_TEXT.
883  */
884 static HANDLE import_utf8_to_text(CFDataRef data)
885 {
886     HANDLE unicode_handle = import_utf8_to_unicodetext(data);
887     HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_ACP);
888
889     GlobalFree(unicode_handle);
890     return ret;
891 }
892
893
894 /**************************************************************************
895  *              import_utf8_to_unicodetext
896  *
897  *  Import a UTF-8 string, converting the string to CF_UNICODETEXT.
898  */
899 static HANDLE import_utf8_to_unicodetext(CFDataRef data)
900 {
901     const BYTE *src;
902     unsigned long data_len;
903     unsigned long new_lines = 0;
904     LPSTR dst;
905     unsigned long i, j;
906     HANDLE unicode_handle = NULL;
907
908     src = CFDataGetBytePtr(data);
909     data_len = CFDataGetLength(data);
910     for (i = 0; i < data_len; i++)
911     {
912         if (src[i] == '\n')
913             new_lines++;
914     }
915
916     if ((dst = HeapAlloc(GetProcessHeap(), 0, data_len + new_lines + 1)))
917     {
918         UINT count;
919
920         for (i = 0, j = 0; i < data_len; i++)
921         {
922             if (src[i] == '\n')
923                 dst[j++] = '\r';
924
925             dst[j++] = src[i];
926         }
927         dst[j] = 0;
928
929         count = MultiByteToWideChar(CP_UTF8, 0, dst, -1, NULL, 0);
930         unicode_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, count * sizeof(WCHAR));
931
932         if (unicode_handle)
933         {
934             WCHAR *textW = GlobalLock(unicode_handle);
935             MultiByteToWideChar(CP_UTF8, 0, dst, -1, textW, count);
936             GlobalUnlock(unicode_handle);
937         }
938
939         HeapFree(GetProcessHeap(), 0, dst);
940     }
941
942     return unicode_handle;
943 }
944
945
946 /**************************************************************************
947  *              export_clipboard_data
948  *
949  *  Generic export clipboard data routine.
950  */
951 static CFDataRef export_clipboard_data(HANDLE data)
952 {
953     CFDataRef ret;
954     UINT len;
955     LPVOID src;
956
957     len = GlobalSize(data);
958     src = GlobalLock(data);
959     if (!src) return NULL;
960
961     ret = CFDataCreate(NULL, src, len);
962     GlobalUnlock(data);
963
964     return ret;
965 }
966
967
968 /**************************************************************************
969  *              export_bitmap_to_bmp
970  *
971  *  Export CF_BITMAP to BMP file format.
972  */
973 static CFDataRef export_bitmap_to_bmp(HANDLE data)
974 {
975     CFDataRef ret = NULL;
976     HGLOBAL dib;
977
978     dib = create_dib_from_bitmap(data);
979     if (dib)
980     {
981         ret = export_dib_to_bmp(dib);
982         GlobalFree(dib);
983     }
984
985     return ret;
986 }
987
988
989 /**************************************************************************
990  *              export_codepage_to_utf8
991  *
992  *  Export string data in a specified codepage to UTF-8.
993  */
994 static CFDataRef export_codepage_to_utf8(HANDLE data, UINT cp)
995 {
996     CFDataRef ret = NULL;
997     const char* str;
998
999     if ((str = GlobalLock(data)))
1000     {
1001         HANDLE unicode = convert_text(str, GlobalSize(data), cp, -1);
1002
1003         ret = export_unicodetext_to_utf8(unicode);
1004
1005         GlobalFree(unicode);
1006         GlobalUnlock(data);
1007     }
1008
1009     return ret;
1010 }
1011
1012
1013 /**************************************************************************
1014  *              export_dib_to_bmp
1015  *
1016  *  Export CF_DIB to BMP file format.  This just entails prepending a BMP
1017  *  file format header to the data.
1018  */
1019 static CFDataRef export_dib_to_bmp(HANDLE data)
1020 {
1021     CFMutableDataRef ret = NULL;
1022     BYTE *dibdata;
1023     CFIndex len;
1024     BITMAPFILEHEADER bfh;
1025
1026     dibdata = GlobalLock(data);
1027     if (!dibdata)
1028         return NULL;
1029
1030     len = sizeof(bfh) + GlobalSize(data);
1031     ret = CFDataCreateMutable(NULL, len);
1032     if (ret)
1033     {
1034         bfh.bfType = 0x4d42; /* "BM" */
1035         bfh.bfSize = len;
1036         bfh.bfReserved1 = 0;
1037         bfh.bfReserved2 = 0;
1038         bfh.bfOffBits = sizeof(bfh) + bitmap_info_size((BITMAPINFO*)dibdata, DIB_RGB_COLORS);
1039         CFDataAppendBytes(ret, (UInt8*)&bfh, sizeof(bfh));
1040
1041         /* rest of bitmap is the same as the packed dib */
1042         CFDataAppendBytes(ret, (UInt8*)dibdata, len - sizeof(bfh));
1043     }
1044
1045     GlobalUnlock(data);
1046
1047     return ret;
1048 }
1049
1050
1051 /**************************************************************************
1052  *              export_hdrop_to_filenames
1053  *
1054  *  Export CF_HDROP to NSFilenamesPboardType data, which is a CFArray of
1055  *  CFStrings (holding Unix paths) which is serialized as a property list.
1056  */
1057 static CFDataRef export_hdrop_to_filenames(HANDLE data)
1058 {
1059     CFDataRef ret = NULL;
1060     DROPFILES *dropfiles;
1061     CFMutableArrayRef filenames = NULL;
1062     void *p;
1063     WCHAR *buffer = NULL;
1064     size_t buffer_len = 0;
1065
1066     TRACE("data %p\n", data);
1067
1068     if (!(dropfiles = GlobalLock(data)))
1069     {
1070         WARN("failed to lock data %p\n", data);
1071         goto done;
1072     }
1073
1074     filenames = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1075     if (!filenames)
1076     {
1077         WARN("failed to create filenames array\n");
1078         goto done;
1079     }
1080
1081     p = (char*)dropfiles + dropfiles->pFiles;
1082     while (dropfiles->fWide ? *(WCHAR*)p : *(char*)p)
1083     {
1084         char *unixname;
1085         CFStringRef filename;
1086
1087         TRACE("    %s\n", dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1088
1089         if (dropfiles->fWide)
1090             unixname = wine_get_unix_file_name(p);
1091         else
1092         {
1093             int len = MultiByteToWideChar(CP_ACP, 0, p, -1, NULL, 0);
1094             if (len)
1095             {
1096                 if (len > buffer_len)
1097                 {
1098                     HeapFree(GetProcessHeap(), 0, buffer);
1099                     buffer_len = len * 2;
1100                     buffer = HeapAlloc(GetProcessHeap(), 0, buffer_len * sizeof(*buffer));
1101                 }
1102
1103                 MultiByteToWideChar(CP_ACP, 0, p, -1, buffer, buffer_len);
1104                 unixname = wine_get_unix_file_name(buffer);
1105             }
1106             else
1107                 unixname = NULL;
1108         }
1109         if (!unixname)
1110         {
1111             WARN("failed to convert DOS path to Unix: %s\n",
1112                  dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1113             goto done;
1114         }
1115
1116         if (dropfiles->fWide)
1117             p = (WCHAR*)p + strlenW(p) + 1;
1118         else
1119             p = (char*)p + strlen(p) + 1;
1120
1121         filename = CFStringCreateWithFileSystemRepresentation(NULL, unixname);
1122         HeapFree(GetProcessHeap(), 0, unixname);
1123         if (!filename)
1124         {
1125             WARN("failed to create CFString from Unix path %s\n", debugstr_a(unixname));
1126             goto done;
1127         }
1128
1129         CFArrayAppendValue(filenames, filename);
1130         CFRelease(filename);
1131     }
1132
1133     ret = CFPropertyListCreateData(NULL, filenames, kCFPropertyListXMLFormat_v1_0, 0, NULL);
1134
1135 done:
1136     HeapFree(GetProcessHeap(), 0, buffer);
1137     GlobalUnlock(data);
1138     if (filenames) CFRelease(filenames);
1139     TRACE(" -> %s\n", debugstr_cf(ret));
1140     return ret;
1141 }
1142
1143
1144 /**************************************************************************
1145  *              export_oemtext_to_utf8
1146  *
1147  *  Export CF_OEMTEXT to UTF-8.
1148  */
1149 static CFDataRef export_oemtext_to_utf8(HANDLE data)
1150 {
1151     return export_codepage_to_utf8(data, CP_OEMCP);
1152 }
1153
1154
1155 /**************************************************************************
1156  *              export_text_to_utf8
1157  *
1158  *  Export CF_TEXT to UTF-8.
1159  */
1160 static CFDataRef export_text_to_utf8(HANDLE data)
1161 {
1162     return export_codepage_to_utf8(data, CP_ACP);
1163 }
1164
1165
1166 /**************************************************************************
1167  *              export_unicodetext_to_utf8
1168  *
1169  *  Export CF_UNICODETEXT to UTF-8.
1170  */
1171 static CFDataRef export_unicodetext_to_utf8(HANDLE data)
1172 {
1173     CFMutableDataRef ret;
1174     LPVOID src;
1175     INT dst_len;
1176
1177     src = GlobalLock(data);
1178     if (!src) return NULL;
1179
1180     dst_len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
1181     if (dst_len) dst_len--; /* Leave off null terminator. */
1182     ret = CFDataCreateMutable(NULL, dst_len);
1183     if (ret)
1184     {
1185         LPSTR dst;
1186         int i, j;
1187
1188         CFDataSetLength(ret, dst_len);
1189         dst = (LPSTR)CFDataGetMutableBytePtr(ret);
1190         WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_len, NULL, NULL);
1191
1192         /* Remove carriage returns */
1193         for (i = 0, j = 0; i < dst_len; i++)
1194         {
1195             if (dst[i] == '\r' &&
1196                 (i + 1 >= dst_len || dst[i + 1] == '\n' || dst[i + 1] == '\0'))
1197                 continue;
1198             dst[j++] = dst[i];
1199         }
1200         CFDataSetLength(ret, j);
1201     }
1202     GlobalUnlock(data);
1203
1204     return ret;
1205 }
1206
1207
1208 /**************************************************************************
1209  *              get_clipboard_info
1210  */
1211 static BOOL get_clipboard_info(LPCLIPBOARDINFO cbinfo)
1212 {
1213     BOOL ret = FALSE;
1214
1215     SERVER_START_REQ(set_clipboard_info)
1216     {
1217         req->flags = 0;
1218
1219         if (wine_server_call_err(req))
1220         {
1221             ERR("Failed to get clipboard owner.\n");
1222         }
1223         else
1224         {
1225             cbinfo->hwnd_owner = wine_server_ptr_handle(reply->old_owner);
1226             cbinfo->flags = reply->flags;
1227
1228             ret = TRUE;
1229         }
1230     }
1231     SERVER_END_REQ;
1232
1233     return ret;
1234 }
1235
1236
1237 /**************************************************************************
1238  *              release_ownership
1239  */
1240 static BOOL release_ownership(void)
1241 {
1242     BOOL ret = FALSE;
1243
1244     SERVER_START_REQ(set_clipboard_info)
1245     {
1246         req->flags = SET_CB_RELOWNER | SET_CB_SEQNO;
1247
1248         if (wine_server_call_err(req))
1249             ERR("Failed to set clipboard.\n");
1250         else
1251             ret = TRUE;
1252     }
1253     SERVER_END_REQ;
1254
1255     return ret;
1256 }
1257
1258
1259 /**************************************************************************
1260  *              check_clipboard_ownership
1261  */
1262 static void check_clipboard_ownership(HWND *owner)
1263 {
1264     CLIPBOARDINFO cbinfo;
1265
1266     if (owner) *owner = NULL;
1267
1268     /* If Wine thinks we're the clipboard owner but Mac OS X thinks we're not
1269        the pasteboard owner, update Wine. */
1270     if (get_clipboard_info(&cbinfo) && (cbinfo.flags & CB_PROCESS))
1271     {
1272         if (!(cbinfo.flags & CB_OPEN) && !macdrv_is_pasteboard_owner())
1273         {
1274             TRACE("Lost clipboard ownership\n");
1275
1276             if (OpenClipboard(cbinfo.hwnd_owner))
1277             {
1278                 /* Destroy private objects */
1279                 SendMessageW(cbinfo.hwnd_owner, WM_DESTROYCLIPBOARD, 0, 0);
1280
1281                 /* Give up ownership of the windows clipboard */
1282                 release_ownership();
1283                 CloseClipboard();
1284             }
1285         }
1286         else if (owner)
1287             *owner = cbinfo.hwnd_owner;
1288     }
1289 }
1290
1291
1292 /**************************************************************************
1293  *              Mac User Driver Clipboard Exports
1294  **************************************************************************/
1295
1296
1297 /**************************************************************************
1298  *              AcquireClipboard (MACDRV.@)
1299  */
1300 int CDECL macdrv_AcquireClipboard(HWND hwnd)
1301 {
1302     TRACE("hwnd %p\n", hwnd);
1303     check_clipboard_ownership(NULL);
1304     return 0;
1305 }
1306
1307
1308 /**************************************************************************
1309  *              CountClipboardFormats (MACDRV.@)
1310  */
1311 INT CDECL macdrv_CountClipboardFormats(void)
1312 {
1313     CFMutableSetRef seen_formats;
1314     CFArrayRef types;
1315     CFIndex count;
1316     CFIndex i;
1317     INT ret = 0;
1318
1319     TRACE("()\n");
1320     check_clipboard_ownership(NULL);
1321
1322     seen_formats = CFSetCreateMutable(NULL, 0, NULL);
1323     if (!seen_formats)
1324     {
1325         WARN("Failed to allocate set to track seen formats\n");
1326         return 0;
1327     }
1328
1329     types = macdrv_copy_pasteboard_types();
1330     if (!types)
1331     {
1332         WARN("Failed to copy pasteboard types\n");
1333         CFRelease(seen_formats);
1334         return 0;
1335     }
1336
1337     count = CFArrayGetCount(types);
1338     TRACE("got %ld types\n", count);
1339
1340     for (i = 0; i < count; i++)
1341     {
1342         CFStringRef type = CFArrayGetValueAtIndex(types, i);
1343         WINE_CLIPFORMAT* format;
1344
1345         format = NULL;
1346         while ((format = format_for_type(format, type)))
1347         {
1348             TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1349
1350             if (!CFSetContainsValue(seen_formats, (void*)format->format_id))
1351             {
1352                 ret++;
1353                 CFSetAddValue(seen_formats, (void*)format->format_id);
1354             }
1355         }
1356     }
1357
1358     CFRelease(seen_formats);
1359     TRACE(" -> %d\n", ret);
1360     return ret;
1361 }
1362
1363
1364 /**************************************************************************
1365  *              EmptyClipboard (MACDRV.@)
1366  *
1367  * Empty cached clipboard data.
1368  */
1369 void CDECL macdrv_EmptyClipboard(BOOL keepunowned)
1370 {
1371     TRACE("keepunowned %d\n", keepunowned);
1372     macdrv_clear_pasteboard();
1373 }
1374
1375
1376 /**************************************************************************
1377  *              EndClipboardUpdate (MACDRV.@)
1378  */
1379 void CDECL macdrv_EndClipboardUpdate(void)
1380 {
1381     TRACE("()\n");
1382     check_clipboard_ownership(NULL);
1383 }
1384
1385
1386 /**************************************************************************
1387  *              EnumClipboardFormats (MACDRV.@)
1388  */
1389 UINT CDECL macdrv_EnumClipboardFormats(UINT prev_format)
1390 {
1391     CFArrayRef types;
1392     CFIndex count;
1393     CFIndex i;
1394     UINT ret;
1395
1396     TRACE("prev_format %s\n", debugstr_format(prev_format));
1397     check_clipboard_ownership(NULL);
1398
1399     types = macdrv_copy_pasteboard_types();
1400     if (!types)
1401     {
1402         WARN("Failed to copy pasteboard types\n");
1403         return 0;
1404     }
1405
1406     count = CFArrayGetCount(types);
1407     TRACE("got %ld types\n", count);
1408
1409     if (!count)
1410     {
1411         CFRelease(types);
1412         return 0;
1413     }
1414
1415     if (prev_format)
1416     {
1417         CFMutableArrayRef formats = CFArrayCreateMutable(NULL, 0, NULL);
1418         if (!formats)
1419         {
1420             WARN("Failed to allocate array to track formats\n");
1421             CFRelease(types);
1422             return 0;
1423         }
1424
1425         for (i = 0; i < count; i++)
1426         {
1427             CFStringRef type = CFArrayGetValueAtIndex(types, i);
1428             WINE_CLIPFORMAT* format;
1429
1430             format = NULL;
1431             while ((format = format_for_type(format, type)))
1432             {
1433                 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1434
1435                 if (format->synthesized)
1436                 {
1437                     /* Don't override a real value with a synthesized value. */
1438                     if (!CFArrayContainsValue(formats, CFRangeMake(0, CFArrayGetCount(formats)), (void*)format->format_id))
1439                         CFArrayAppendValue(formats, (void*)format->format_id);
1440                 }
1441                 else
1442                 {
1443                     /* If the type was already in the array, it must have been synthesized
1444                        because this one's real.  Remove the synthesized entry in favor of
1445                        this one. */
1446                     CFIndex index = CFArrayGetFirstIndexOfValue(formats, CFRangeMake(0, CFArrayGetCount(formats)),
1447                                                                 (void*)format->format_id);
1448                     if (index != kCFNotFound)
1449                         CFArrayRemoveValueAtIndex(formats, index);
1450                     CFArrayAppendValue(formats, (void*)format->format_id);
1451                 }
1452             }
1453         }
1454
1455         count = CFArrayGetCount(formats);
1456         i = CFArrayGetFirstIndexOfValue(formats, CFRangeMake(0, count), (void*)prev_format);
1457         if (i == kCFNotFound || i + 1 >= count)
1458             ret = 0;
1459         else
1460             ret = (UINT)CFArrayGetValueAtIndex(formats, i + 1);
1461
1462         CFRelease(formats);
1463     }
1464     else
1465     {
1466         CFStringRef type = CFArrayGetValueAtIndex(types, 0);
1467         WINE_CLIPFORMAT *format = format_for_type(NULL, type);
1468
1469         ret = format ? format->format_id : 0;
1470     }
1471
1472     CFRelease(types);
1473     TRACE(" -> %u\n", ret);
1474     return ret;
1475 }
1476
1477
1478 /**************************************************************************
1479  *              GetClipboardData (MACDRV.@)
1480  */
1481 HANDLE CDECL macdrv_GetClipboardData(UINT desired_format)
1482 {
1483     CFArrayRef types;
1484     CFIndex count;
1485     CFIndex i;
1486     CFStringRef type, best_type;
1487     WINE_CLIPFORMAT* best_format = NULL;
1488     HANDLE data = NULL;
1489
1490     TRACE("desired_format %s\n", debugstr_format(desired_format));
1491     check_clipboard_ownership(NULL);
1492
1493     types = macdrv_copy_pasteboard_types();
1494     if (!types)
1495     {
1496         WARN("Failed to copy pasteboard types\n");
1497         return NULL;
1498     }
1499
1500     count = CFArrayGetCount(types);
1501     TRACE("got %ld types\n", count);
1502
1503     for (i = 0; (!best_format || best_format->synthesized) && i < count; i++)
1504     {
1505         WINE_CLIPFORMAT* format;
1506
1507         type = CFArrayGetValueAtIndex(types, i);
1508
1509         format = NULL;
1510         while ((!best_format || best_format->synthesized) && (format = format_for_type(format, type)))
1511         {
1512             TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format ? format->format_id : 0));
1513
1514             if (format->format_id == desired_format)
1515             {
1516                 /* The best format is the matching one which is not synthesized.  Failing that,
1517                    the best format is the first matching synthesized format. */
1518                 if (!format->synthesized || !best_format)
1519                 {
1520                     best_type = type;
1521                     best_format = format;
1522                 }
1523             }
1524         }
1525     }
1526
1527     if (best_format)
1528     {
1529         CFDataRef pasteboard_data = macdrv_copy_pasteboard_data(best_type);
1530
1531         TRACE("got pasteboard data for type %s: %s\n", debugstr_cf(best_type), debugstr_cf(pasteboard_data));
1532
1533         if (pasteboard_data)
1534         {
1535             data = best_format->import_func(pasteboard_data);
1536             CFRelease(pasteboard_data);
1537         }
1538     }
1539
1540     CFRelease(types);
1541     TRACE(" -> %p\n", data);
1542     return data;
1543 }
1544
1545
1546 /**************************************************************************
1547  *              IsClipboardFormatAvailable (MACDRV.@)
1548  */
1549 BOOL CDECL macdrv_IsClipboardFormatAvailable(UINT desired_format)
1550 {
1551     CFArrayRef types;
1552     int count;
1553     UINT i;
1554     BOOL found = FALSE;
1555
1556     TRACE("desired_format %s\n", debugstr_format(desired_format));
1557     check_clipboard_ownership(NULL);
1558
1559     types = macdrv_copy_pasteboard_types();
1560     if (!types)
1561     {
1562         WARN("Failed to copy pasteboard types\n");
1563         return FALSE;
1564     }
1565
1566     count = CFArrayGetCount(types);
1567     TRACE("got %d types\n", count);
1568
1569     for (i = 0; !found && i < count; i++)
1570     {
1571         CFStringRef type = CFArrayGetValueAtIndex(types, i);
1572         WINE_CLIPFORMAT* format;
1573
1574         format = NULL;
1575         while (!found && (format = format_for_type(format, type)))
1576         {
1577             TRACE("for type %s got format %s\n", debugstr_cf(type), debugstr_format(format->format_id));
1578
1579             if (format->format_id == desired_format)
1580                 found = TRUE;
1581         }
1582     }
1583
1584     CFRelease(types);
1585     TRACE(" -> %d\n", found);
1586     return found;
1587 }
1588
1589
1590 /**************************************************************************
1591  *              SetClipboardData (MACDRV.@)
1592  */
1593 BOOL CDECL macdrv_SetClipboardData(UINT format_id, HANDLE data, BOOL owner)
1594 {
1595     HWND hwnd_owner;
1596     macdrv_window window;
1597     WINE_CLIPFORMAT *format;
1598     CFDataRef cfdata = NULL;
1599
1600     check_clipboard_ownership(&hwnd_owner);
1601     window = macdrv_get_cocoa_window(GetAncestor(hwnd_owner, GA_ROOT), FALSE);
1602     TRACE("format_id %s data %p owner %d hwnd_owner %p window %p)\n", debugstr_format(format_id), data, owner, hwnd_owner, window);
1603
1604     /* Find the "natural" format for this format_id (the one which isn't
1605        synthesized from another type). */
1606     LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1607         if (format->format_id == format_id && !format->synthesized) break;
1608
1609     if (&format->entry == &format_list && !(format = insert_clipboard_format(format_id, NULL)))
1610     {
1611         WARN("Failed to register clipboard format %s\n", debugstr_format(format_id));
1612         return FALSE;
1613     }
1614
1615     /* Export the data to the Mac pasteboard. */
1616     if (data)
1617     {
1618         if (!format->export_func || !(cfdata = format->export_func(data)))
1619         {
1620             WARN("Failed to export %s data to type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1621             return FALSE;
1622         }
1623     }
1624
1625     if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1626         TRACE("Set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1627     else
1628     {
1629         WARN("Failed to set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1630         if (cfdata) CFRelease(cfdata);
1631         return FALSE;
1632     }
1633
1634     if (cfdata) CFRelease(cfdata);
1635
1636     /* Find any other formats for this format_id (the exportable synthesized ones). */
1637     LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1638     {
1639         if (format->format_id == format_id && format->synthesized && format->export_func)
1640         {
1641             /* We have a synthesized format for this format ID.  Add its type to the pasteboard. */
1642             TRACE("Synthesized from format %s: type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1643
1644             if (data)
1645             {
1646                 cfdata = format->export_func(data);
1647                 if (!cfdata)
1648                 {
1649                     WARN("Failed to export %s data to type %s\n", debugstr_format(format->format_id), debugstr_cf(format->type));
1650                     continue;
1651                 }
1652             }
1653             else
1654                 cfdata = NULL;
1655
1656             if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1657                 TRACE("    ... set pasteboard data: %s\n", debugstr_cf(cfdata));
1658             else
1659                 WARN("    ... failed to set pasteboard data: %s\n", debugstr_cf(cfdata));
1660
1661             if (cfdata) CFRelease(cfdata);
1662         }
1663     }
1664
1665     if (data)
1666     {
1667         /* FIXME: According to MSDN, the caller is entitled to lock and read from
1668            data until CloseClipboard is called.  So, we should defer this cleanup. */
1669         if ((format_id >= CF_GDIOBJFIRST && format_id <= CF_GDIOBJLAST) ||
1670             format_id == CF_BITMAP ||
1671             format_id == CF_DIB ||
1672             format_id == CF_PALETTE)
1673         {
1674             DeleteObject(data);
1675         }
1676         else if (format_id == CF_METAFILEPICT)
1677         {
1678             DeleteMetaFile(((METAFILEPICT *)GlobalLock(data))->hMF);
1679             GlobalFree(data);
1680         }
1681         else if (format_id == CF_ENHMETAFILE)
1682         {
1683             DeleteEnhMetaFile(data);
1684         }
1685         else if (format_id < CF_PRIVATEFIRST || CF_PRIVATELAST < format_id)
1686         {
1687             GlobalFree(data);
1688         }
1689     }
1690
1691     return TRUE;
1692 }
1693
1694
1695 /**************************************************************************
1696  *              MACDRV Private Clipboard Exports
1697  **************************************************************************/
1698
1699
1700 /**************************************************************************
1701  *              macdrv_clipboard_process_attach
1702  */
1703 void macdrv_clipboard_process_attach(void)
1704 {
1705     UINT i;
1706
1707     /* Register built-in formats */
1708     for (i = 0; i < sizeof(builtin_format_ids)/sizeof(builtin_format_ids[0]); i++)
1709     {
1710         WINE_CLIPFORMAT *format;
1711
1712         if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
1713         format->format_id   = builtin_format_ids[i].id;
1714         format->type        = CFRetain(builtin_format_ids[i].type);
1715         format->import_func = builtin_format_ids[i].import;
1716         format->export_func = builtin_format_ids[i].export;
1717         format->synthesized = builtin_format_ids[i].synthesized;
1718         list_add_tail(&format_list, &format->entry);
1719     }
1720
1721     /* Register known mappings between Windows formats and Mac types */
1722     for (i = 0; i < sizeof(builtin_format_names)/sizeof(builtin_format_names[0]); i++)
1723         insert_clipboard_format(RegisterClipboardFormatW(builtin_format_names[i].name),
1724                                 builtin_format_names[i].type);
1725 }
1726
1727
1728 /**************************************************************************
1729  *              query_pasteboard_data
1730  */
1731 BOOL query_pasteboard_data(HWND hwnd, CFStringRef type)
1732 {
1733     BOOL ret = FALSE;
1734     CLIPBOARDINFO cbinfo;
1735     WINE_CLIPFORMAT* format;
1736     CFArrayRef types = NULL;
1737     CFRange range;
1738
1739     TRACE("hwnd %p type %s\n", hwnd, debugstr_cf(type));
1740
1741     if (get_clipboard_info(&cbinfo))
1742         hwnd = cbinfo.hwnd_owner;
1743
1744     format = NULL;
1745     while ((format = format_for_type(format, type)))
1746     {
1747         WINE_CLIPFORMAT* base_format;
1748
1749         TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1750
1751         if (!format->synthesized)
1752         {
1753             TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(format->format_id), hwnd);
1754             SendMessageW(hwnd, WM_RENDERFORMAT, format->format_id, 0);
1755             ret = TRUE;
1756             goto done;
1757         }
1758
1759         if (!types)
1760         {
1761             types = macdrv_copy_pasteboard_types();
1762             if (!types)
1763             {
1764                 WARN("Failed to copy pasteboard types\n");
1765                 break;
1766             }
1767
1768             range = CFRangeMake(0, CFArrayGetCount(types));
1769         }
1770
1771         /* The type maps to a synthesized format.  Now look up what type that format maps to natively
1772            (not synthesized).  For example, if type is "public.utf8-plain-text", then this format may
1773            have an ID of CF_TEXT.  From CF_TEXT, we want to find "org.winehq.builtin.text" to see if
1774            that type is present in the pasteboard.  If it is, then the app must have promised it and
1775            we can ask it to render it.  (If it had put it on the clipboard immediately, then the
1776            pasteboard would also have data for "public.utf8-plain-text" and we wouldn't be here.)  If
1777            "org.winehq.builtin.text" is not on the pasteboard, then one of the other text formats is
1778            presumably responsible for the promise that we're trying to satisfy, so we keep looking. */
1779         LIST_FOR_EACH_ENTRY(base_format, &format_list, WINE_CLIPFORMAT, entry)
1780         {
1781             if (base_format->format_id == format->format_id && !base_format->synthesized &&
1782                 CFArrayContainsValue(types, range, base_format->type))
1783             {
1784                 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(base_format->format_id), hwnd);
1785                 SendMessageW(hwnd, WM_RENDERFORMAT, base_format->format_id, 0);
1786                 ret = TRUE;
1787                 goto done;
1788             }
1789         }
1790     }
1791
1792 done:
1793     if (types) CFRelease(types);
1794
1795     return ret;
1796 }