winemac: Add support for delay-rendered (a.k.a. promised) clipboard data.
[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 "wine/list.h"
30 #include "wine/server.h"
31 #include "wine/unicode.h"
32
33
34 WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
35
36
37 /**************************************************************************
38  *              Types
39  **************************************************************************/
40
41 typedef struct
42 {
43     HWND hwnd_owner;
44     UINT flags;
45 } CLIPBOARDINFO, *LPCLIPBOARDINFO;
46
47 typedef HANDLE (*DRVIMPORTFUNC)(CFDataRef data);
48 typedef CFDataRef (*DRVEXPORTFUNC)(HANDLE data);
49
50 typedef struct
51 {
52     struct list     entry;
53     UINT            format_id;
54     CFStringRef     type;
55     DRVIMPORTFUNC   import_func;
56     DRVEXPORTFUNC   export_func;
57     BOOL            synthesized;
58 } WINE_CLIPFORMAT;
59
60
61 /**************************************************************************
62  *              Constants
63  **************************************************************************/
64
65
66 /**************************************************************************
67  *              Forward Function Declarations
68  **************************************************************************/
69
70 static HANDLE import_clipboard_data(CFDataRef data);
71 static HANDLE import_oemtext_to_text(CFDataRef data);
72 static HANDLE import_oemtext_to_unicodetext(CFDataRef data);
73 static HANDLE import_text_to_oemtext(CFDataRef data);
74 static HANDLE import_text_to_unicodetext(CFDataRef data);
75 static HANDLE import_unicodetext_to_oemtext(CFDataRef data);
76 static HANDLE import_unicodetext_to_text(CFDataRef data);
77 static HANDLE import_utf8_to_oemtext(CFDataRef data);
78 static HANDLE import_utf8_to_text(CFDataRef data);
79 static HANDLE import_utf8_to_unicodetext(CFDataRef data);
80
81 static CFDataRef export_clipboard_data(HANDLE data);
82 static CFDataRef export_oemtext_to_utf8(HANDLE data);
83 static CFDataRef export_text_to_utf8(HANDLE data);
84 static CFDataRef export_unicodetext_to_utf8(HANDLE data);
85
86
87 /**************************************************************************
88  *              Static Variables
89  **************************************************************************/
90
91 /* Clipboard formats */
92 static struct list format_list = LIST_INIT(format_list);
93
94 /*  There are two naming schemes involved and we want to have a mapping between
95     them.  There are Win32 clipboard format names and there are Mac pasteboard
96     types.
97
98     The Win32 standard clipboard formats don't have names, but they are associated
99     with Mac pasteboard types through the following tables, which are used to
100     initialize the format_list.  Where possible, the standard clipboard formats
101     are mapped to predefined pasteboard type UTIs.  Otherwise, we create Wine-
102     specific types of the form "org.winehq.builtin.<format>", where <format> is
103     the name of the symbolic constant for the format minus "CF_" and lowercased.
104     E.g. CF_BITMAP -> org.winehq.builtin.bitmap.
105
106     Win32 clipboard formats which originate in a Windows program may be registered
107     with an arbitrary name.  We construct a Mac pasteboard type from these by
108     prepending "org.winehq.registered." to the registered name.
109
110     Likewise, Mac pasteboard types which originate in other apps may have
111     arbitrary type strings.  We construct a Win32 clipboard format name from
112     these by prepending "org.winehq.mac-type." to the Mac pasteboard type.
113
114     Summary:
115     Win32 clipboard format names:
116         <none>                              standard clipboard format; maps via
117                                             format_list to either a predefined Mac UTI
118                                             or org.winehq.builtin.<format>.
119         org.winehq.mac-type.<Mac type>      representation of Mac type in Win32 land;
120                                             maps to <Mac type>
121         <other>                             name registered within Win32 land; maps to
122                                             org.winehq.registered.<other>
123     Mac pasteboard type names:
124         org.winehq.builtin.<format ID>      representation of Win32 standard clipboard
125                                             format for which there was no corresponding
126                                             predefined Mac UTI; maps via format_list
127         org.winehq.registered.<format name> representation of Win32 registered
128                                             clipboard format name; maps to <format name>
129         <other>                             Mac pasteboard type originating with system
130                                             or other apps; either maps via format_list
131                                             to a standard clipboard format or maps to
132                                             org.winehq.mac-type.<other>
133 */
134
135 static const struct
136 {
137     UINT          id;
138     CFStringRef   type;
139     DRVIMPORTFUNC import;
140     DRVEXPORTFUNC export;
141     BOOL          synthesized;
142 } builtin_format_ids[] =
143 {
144     { CF_UNICODETEXT,       CFSTR("org.winehq.builtin.unicodetext"),        import_clipboard_data,          export_clipboard_data,      FALSE },
145     { CF_TEXT,              CFSTR("org.winehq.builtin.unicodetext"),        import_unicodetext_to_text,     NULL,                       TRUE },
146     { CF_OEMTEXT,           CFSTR("org.winehq.builtin.unicodetext"),        import_unicodetext_to_oemtext,  NULL,                       TRUE },
147
148     { CF_TEXT,              CFSTR("org.winehq.builtin.text"),               import_clipboard_data,          export_clipboard_data,      FALSE },
149     { CF_UNICODETEXT,       CFSTR("org.winehq.builtin.text"),               import_text_to_unicodetext,     NULL,                       TRUE },
150     { CF_OEMTEXT,           CFSTR("org.winehq.builtin.text"),               import_text_to_oemtext,         NULL,                       TRUE },
151
152     { CF_OEMTEXT,           CFSTR("org.winehq.builtin.oemtext"),            import_clipboard_data,          export_clipboard_data,      FALSE },
153     { CF_UNICODETEXT,       CFSTR("org.winehq.builtin.oemtext"),            import_oemtext_to_unicodetext,  NULL,                       TRUE },
154     { CF_TEXT,              CFSTR("org.winehq.builtin.oemtext"),            import_oemtext_to_text,         NULL,                       TRUE },
155
156     { CF_UNICODETEXT,       CFSTR("public.utf8-plain-text"),                import_utf8_to_unicodetext,     export_unicodetext_to_utf8, TRUE },
157     { CF_TEXT,              CFSTR("public.utf8-plain-text"),                import_utf8_to_text,            export_text_to_utf8,        TRUE },
158     { CF_OEMTEXT,           CFSTR("public.utf8-plain-text"),                import_utf8_to_oemtext,         export_oemtext_to_utf8,     TRUE },
159 };
160
161 /* The prefix prepended to an external Mac pasteboard type to make a Win32 clipboard format name. org.winehq.mac-type. */
162 static const WCHAR mac_type_name_prefix[] = {'o','r','g','.','w','i','n','e','h','q','.','m','a','c','-','t','y','p','e','.',0};
163
164 /* The prefix prepended to a Win32 clipboard format name to make a Mac pasteboard type. */
165 static const CFStringRef registered_name_type_prefix = CFSTR("org.winehq.registered.");
166
167
168 /**************************************************************************
169  *              Internal Clipboard implementation methods
170  **************************************************************************/
171
172 /*
173  * format_list functions
174  */
175
176 /**************************************************************************
177  *              debugstr_format
178  */
179 static const char *debugstr_format(UINT id)
180 {
181     WCHAR buffer[256];
182
183     if (GetClipboardFormatNameW(id, buffer, 256))
184         return wine_dbg_sprintf("0x%04x %s", id, debugstr_w(buffer));
185
186     switch (id)
187     {
188 #define BUILTIN(id) case id: return #id;
189     BUILTIN(CF_TEXT)
190     BUILTIN(CF_BITMAP)
191     BUILTIN(CF_METAFILEPICT)
192     BUILTIN(CF_SYLK)
193     BUILTIN(CF_DIF)
194     BUILTIN(CF_TIFF)
195     BUILTIN(CF_OEMTEXT)
196     BUILTIN(CF_DIB)
197     BUILTIN(CF_PALETTE)
198     BUILTIN(CF_PENDATA)
199     BUILTIN(CF_RIFF)
200     BUILTIN(CF_WAVE)
201     BUILTIN(CF_UNICODETEXT)
202     BUILTIN(CF_ENHMETAFILE)
203     BUILTIN(CF_HDROP)
204     BUILTIN(CF_LOCALE)
205     BUILTIN(CF_DIBV5)
206     BUILTIN(CF_OWNERDISPLAY)
207     BUILTIN(CF_DSPTEXT)
208     BUILTIN(CF_DSPBITMAP)
209     BUILTIN(CF_DSPMETAFILEPICT)
210     BUILTIN(CF_DSPENHMETAFILE)
211 #undef BUILTIN
212     default: return wine_dbg_sprintf("0x%04x", id);
213     }
214 }
215
216
217 /**************************************************************************
218  *              insert_clipboard_format
219  */
220 static WINE_CLIPFORMAT *insert_clipboard_format(UINT id, CFStringRef type)
221 {
222     WINE_CLIPFORMAT *format;
223
224     format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format));
225
226     if (format == NULL)
227     {
228         WARN("No more memory for a new format!\n");
229         return NULL;
230     }
231     format->format_id = id;
232     format->import_func = import_clipboard_data;
233     format->export_func = export_clipboard_data;
234     format->synthesized = FALSE;
235
236     if (type)
237         format->type = CFStringCreateCopy(NULL, type);
238     else
239     {
240         WCHAR buffer[256];
241
242         GetClipboardFormatNameW(format->format_id, buffer, 256);
243         if (!strncmpW(buffer, mac_type_name_prefix, strlenW(mac_type_name_prefix)))
244         {
245             const WCHAR *p = buffer + strlenW(mac_type_name_prefix);
246             format->type = CFStringCreateWithCharacters(NULL, (UniChar*)p, strlenW(p));
247         }
248         else
249         {
250             format->type = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%S"),
251                                                     registered_name_type_prefix, buffer);
252         }
253     }
254
255     list_add_tail(&format_list, &format->entry);
256
257     TRACE("Registering format %s type %s\n", debugstr_format(format->format_id),
258           debugstr_cf(format->type));
259
260     return format;
261 }
262
263
264 /**************************************************************************
265  *              register_format
266  *
267  * Register a custom Mac clipboard format.
268  */
269 static WINE_CLIPFORMAT* register_format(UINT id, CFStringRef type)
270 {
271     WINE_CLIPFORMAT *format;
272
273     /* walk format chain to see if it's already registered */
274     LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
275         if (format->format_id == id) return format;
276
277     return insert_clipboard_format(id, type);
278 }
279
280
281 /**************************************************************************
282  *              format_for_type
283  */
284 static WINE_CLIPFORMAT* format_for_type(WINE_CLIPFORMAT *current, CFStringRef type)
285 {
286     struct list *ptr = current ? &current->entry : &format_list;
287     WINE_CLIPFORMAT *format = NULL;
288
289     TRACE("current %p/%s type %s\n", current, debugstr_format(current ? current->format_id : 0), debugstr_cf(type));
290
291     while ((ptr = list_next(&format_list, ptr)))
292     {
293         format = LIST_ENTRY(ptr, WINE_CLIPFORMAT, entry);
294         if (CFEqual(format->type, type))
295         {
296             TRACE(" -> %p/%s\n", format, debugstr_format(format->format_id));
297             return format;
298         }
299     }
300
301     if (!current)
302     {
303         LPWSTR name;
304
305         if (CFStringHasPrefix(type, CFSTR("org.winehq.builtin.")))
306         {
307             ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
308                 debugstr_cf(type));
309             return NULL;
310         }
311         else if (CFStringHasPrefix(type, registered_name_type_prefix))
312         {
313             int len = CFStringGetLength(type) - CFStringGetLength(registered_name_type_prefix);
314             name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
315             CFStringGetCharacters(type, CFRangeMake(CFStringGetLength(registered_name_type_prefix), len),
316                                   (UniChar*)name);
317             name[len] = 0;
318         }
319         else
320         {
321             int len = strlenW(mac_type_name_prefix) + CFStringGetLength(type);
322             name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
323             memcpy(name, mac_type_name_prefix, sizeof(mac_type_name_prefix));
324             CFStringGetCharacters(type, CFRangeMake(0, CFStringGetLength(type)),
325                                   (UniChar*)name + strlenW(mac_type_name_prefix));
326             name[len] = 0;
327         }
328
329         format = register_format(RegisterClipboardFormatW(name), type);
330         if (!format)
331             ERR("Failed to register format for type %s name %s\n", debugstr_cf(type), debugstr_w(name));
332
333         HeapFree(GetProcessHeap(), 0, name);
334     }
335
336     TRACE(" -> %p/%s\n", format, debugstr_format(format ? format->format_id : 0));
337     return format;
338 }
339
340
341 /**************************************************************************
342  *              convert_text
343  *
344  *  Convert string data between code pages or to/from wide characters.  The
345  *  special value of (UINT)-1 for a code page indicates to use wide
346  *  characters.
347  */
348 static HANDLE convert_text(const void *src, int src_len, UINT src_cp, UINT dest_cp)
349 {
350     HANDLE ret = NULL;
351     const WCHAR *wstr;
352     int wstr_len;
353     HANDLE handle;
354     char *p;
355
356     if (src_cp == (UINT)-1)
357     {
358         wstr = src;
359         wstr_len = src_len / sizeof(WCHAR);
360     }
361     else
362     {
363         WCHAR *temp;
364
365         wstr_len = MultiByteToWideChar(src_cp, 0, src, src_len, NULL, 0);
366         if (!src_len || ((const char*)src)[src_len - 1]) wstr_len += 1;
367         temp = HeapAlloc(GetProcessHeap(), 0, wstr_len * sizeof(WCHAR));
368         MultiByteToWideChar(src_cp, 0, src, src_len, temp, wstr_len);
369         temp[wstr_len - 1] = 0;
370         wstr = temp;
371     }
372
373     if (dest_cp == (UINT)-1)
374     {
375         handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, wstr_len * sizeof(WCHAR));
376         if (handle && (p = GlobalLock(handle)))
377         {
378             memcpy(p, wstr, wstr_len * sizeof(WCHAR));
379             GlobalUnlock(handle);
380             ret = handle;
381         }
382     }
383     else
384     {
385         INT len;
386
387         len = WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, NULL, 0, NULL, NULL);
388         if (!wstr_len || wstr[wstr_len - 1]) len += 1;
389         handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
390
391         if (handle && (p = GlobalLock(handle)))
392         {
393             WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, p, len, NULL, NULL);
394             p[len - 1] = 0;
395             GlobalUnlock(handle);
396             ret = handle;
397         }
398     }
399
400     return ret;
401 }
402
403
404 /**************************************************************************
405  *              convert_unicodetext_to_codepage
406  */
407 static HANDLE convert_unicodetext_to_codepage(HANDLE unicode_handle, UINT cp)
408 {
409     LPWSTR unicode_string = GlobalLock(unicode_handle);
410     HANDLE ret = NULL;
411
412     if (unicode_string)
413     {
414         ret = convert_text(unicode_string, GlobalSize(unicode_handle), -1, cp);
415         GlobalUnlock(unicode_handle);
416     }
417
418     return ret;
419 }
420
421
422 /**************************************************************************
423  *              import_clipboard_data
424  *
425  *  Generic import clipboard data routine.
426  */
427 static HANDLE import_clipboard_data(CFDataRef data)
428 {
429     HANDLE data_handle = NULL;
430
431     size_t len = CFDataGetLength(data);
432     if (len)
433     {
434         LPVOID p;
435
436         /* Turn on the DDESHARE flag to enable shared 32 bit memory */
437         data_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
438         if (!data_handle)
439             return NULL;
440
441         if ((p = GlobalLock(data_handle)))
442         {
443             memcpy(p, CFDataGetBytePtr(data), len);
444             GlobalUnlock(data_handle);
445         }
446         else
447         {
448             GlobalFree(data_handle);
449             data_handle = NULL;
450         }
451     }
452
453     return data_handle;
454 }
455
456
457 /**************************************************************************
458  *              import_oemtext_to_text
459  *
460  *  Import CF_OEMTEXT data, converting the string to CF_TEXT.
461  */
462 static HANDLE import_oemtext_to_text(CFDataRef data)
463 {
464     return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, CP_ACP);
465 }
466
467
468 /**************************************************************************
469  *              import_oemtext_to_unicodetext
470  *
471  *  Import CF_OEMTEXT data, converting the string to CF_UNICODETEXT.
472  */
473 static HANDLE import_oemtext_to_unicodetext(CFDataRef data)
474 {
475     return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, -1);
476 }
477
478
479 /**************************************************************************
480  *              import_text_to_oemtext
481  *
482  *  Import CF_TEXT data, converting the string to CF_OEMTEXT.
483  */
484 static HANDLE import_text_to_oemtext(CFDataRef data)
485 {
486     return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, CP_OEMCP);
487 }
488
489
490 /**************************************************************************
491  *              import_text_to_unicodetext
492  *
493  *  Import CF_TEXT data, converting the string to CF_UNICODETEXT.
494  */
495 static HANDLE import_text_to_unicodetext(CFDataRef data)
496 {
497     return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, -1);
498 }
499
500
501 /**************************************************************************
502  *              import_unicodetext_to_oemtext
503  *
504  *  Import a CF_UNICODETEXT string, converting the string to CF_OEMTEXT.
505  */
506 static HANDLE import_unicodetext_to_oemtext(CFDataRef data)
507 {
508     return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_OEMCP);
509 }
510
511
512 /**************************************************************************
513  *              import_unicodetext_to_text
514  *
515  *  Import a CF_UNICODETEXT string, converting the string to CF_TEXT.
516  */
517 static HANDLE import_unicodetext_to_text(CFDataRef data)
518 {
519     return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_ACP);
520 }
521
522
523 /**************************************************************************
524  *              import_utf8_to_oemtext
525  *
526  *  Import a UTF-8 string, converting the string to CF_OEMTEXT.
527  */
528 static HANDLE import_utf8_to_oemtext(CFDataRef data)
529 {
530     HANDLE unicode_handle = import_utf8_to_unicodetext(data);
531     HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_OEMCP);
532
533     GlobalFree(unicode_handle);
534     return ret;
535 }
536
537
538 /**************************************************************************
539  *              import_utf8_to_text
540  *
541  *  Import a UTF-8 string, converting the string to CF_TEXT.
542  */
543 static HANDLE import_utf8_to_text(CFDataRef data)
544 {
545     HANDLE unicode_handle = import_utf8_to_unicodetext(data);
546     HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_ACP);
547
548     GlobalFree(unicode_handle);
549     return ret;
550 }
551
552
553 /**************************************************************************
554  *              import_utf8_to_unicodetext
555  *
556  *  Import a UTF-8 string, converting the string to CF_UNICODETEXT.
557  */
558 static HANDLE import_utf8_to_unicodetext(CFDataRef data)
559 {
560     const BYTE *src;
561     unsigned long data_len;
562     unsigned long new_lines = 0;
563     LPSTR dst;
564     unsigned long i, j;
565     HANDLE unicode_handle = NULL;
566
567     src = CFDataGetBytePtr(data);
568     data_len = CFDataGetLength(data);
569     for (i = 0; i < data_len; i++)
570     {
571         if (src[i] == '\n')
572             new_lines++;
573     }
574
575     if ((dst = HeapAlloc(GetProcessHeap(), 0, data_len + new_lines + 1)))
576     {
577         UINT count;
578
579         for (i = 0, j = 0; i < data_len; i++)
580         {
581             if (src[i] == '\n')
582                 dst[j++] = '\r';
583
584             dst[j++] = src[i];
585         }
586         dst[j] = 0;
587
588         count = MultiByteToWideChar(CP_UTF8, 0, dst, -1, NULL, 0);
589         unicode_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, count * sizeof(WCHAR));
590
591         if (unicode_handle)
592         {
593             WCHAR *textW = GlobalLock(unicode_handle);
594             MultiByteToWideChar(CP_UTF8, 0, dst, -1, textW, count);
595             GlobalUnlock(unicode_handle);
596         }
597
598         HeapFree(GetProcessHeap(), 0, dst);
599     }
600
601     return unicode_handle;
602 }
603
604
605 /**************************************************************************
606  *              export_clipboard_data
607  *
608  *  Generic export clipboard data routine.
609  */
610 static CFDataRef export_clipboard_data(HANDLE data)
611 {
612     CFDataRef ret;
613     UINT len;
614     LPVOID src;
615
616     len = GlobalSize(data);
617     src = GlobalLock(data);
618     if (!src) return NULL;
619
620     ret = CFDataCreate(NULL, src, len);
621     GlobalUnlock(data);
622
623     return ret;
624 }
625
626
627 /**************************************************************************
628  *              export_codepage_to_utf8
629  *
630  *  Export string data in a specified codepage to UTF-8.
631  */
632 static CFDataRef export_codepage_to_utf8(HANDLE data, UINT cp)
633 {
634     CFDataRef ret = NULL;
635     const char* str;
636
637     if ((str = GlobalLock(data)))
638     {
639         HANDLE unicode = convert_text(str, GlobalSize(data), cp, -1);
640
641         ret = export_unicodetext_to_utf8(unicode);
642
643         GlobalFree(unicode);
644         GlobalUnlock(data);
645     }
646
647     return ret;
648 }
649
650
651 /**************************************************************************
652  *              export_oemtext_to_utf8
653  *
654  *  Export CF_OEMTEXT to UTF-8.
655  */
656 static CFDataRef export_oemtext_to_utf8(HANDLE data)
657 {
658     return export_codepage_to_utf8(data, CP_OEMCP);
659 }
660
661
662 /**************************************************************************
663  *              export_text_to_utf8
664  *
665  *  Export CF_TEXT to UTF-8.
666  */
667 static CFDataRef export_text_to_utf8(HANDLE data)
668 {
669     return export_codepage_to_utf8(data, CP_ACP);
670 }
671
672
673 /**************************************************************************
674  *              export_unicodetext_to_utf8
675  *
676  *  Export CF_UNICODETEXT to UTF-8.
677  */
678 static CFDataRef export_unicodetext_to_utf8(HANDLE data)
679 {
680     CFMutableDataRef ret;
681     LPVOID src;
682     INT dst_len;
683
684     src = GlobalLock(data);
685     if (!src) return NULL;
686
687     dst_len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
688     if (dst_len) dst_len--; /* Leave off null terminator. */
689     ret = CFDataCreateMutable(NULL, dst_len);
690     if (ret)
691     {
692         LPSTR dst;
693         int i, j;
694
695         CFDataSetLength(ret, dst_len);
696         dst = (LPSTR)CFDataGetMutableBytePtr(ret);
697         WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_len, NULL, NULL);
698
699         /* Remove carriage returns */
700         for (i = 0, j = 0; i < dst_len; i++)
701         {
702             if (dst[i] == '\r' &&
703                 (i + 1 >= dst_len || dst[i + 1] == '\n' || dst[i + 1] == '\0'))
704                 continue;
705             dst[j++] = dst[i];
706         }
707         CFDataSetLength(ret, j);
708     }
709     GlobalUnlock(data);
710
711     return ret;
712 }
713
714
715 /**************************************************************************
716  *              get_clipboard_info
717  */
718 static BOOL get_clipboard_info(LPCLIPBOARDINFO cbinfo)
719 {
720     BOOL ret = FALSE;
721
722     SERVER_START_REQ(set_clipboard_info)
723     {
724         req->flags = 0;
725
726         if (wine_server_call_err(req))
727         {
728             ERR("Failed to get clipboard owner.\n");
729         }
730         else
731         {
732             cbinfo->hwnd_owner = wine_server_ptr_handle(reply->old_owner);
733             cbinfo->flags = reply->flags;
734
735             ret = TRUE;
736         }
737     }
738     SERVER_END_REQ;
739
740     return ret;
741 }
742
743
744 /**************************************************************************
745  *              release_ownership
746  */
747 static BOOL release_ownership(void)
748 {
749     BOOL ret = FALSE;
750
751     SERVER_START_REQ(set_clipboard_info)
752     {
753         req->flags = SET_CB_RELOWNER | SET_CB_SEQNO;
754
755         if (wine_server_call_err(req))
756             ERR("Failed to set clipboard.\n");
757         else
758             ret = TRUE;
759     }
760     SERVER_END_REQ;
761
762     return ret;
763 }
764
765
766 /**************************************************************************
767  *              check_clipboard_ownership
768  */
769 static void check_clipboard_ownership(HWND *owner)
770 {
771     CLIPBOARDINFO cbinfo;
772
773     if (owner) *owner = NULL;
774
775     /* If Wine thinks we're the clipboard owner but Mac OS X thinks we're not
776        the pasteboard owner, update Wine. */
777     if (get_clipboard_info(&cbinfo) && (cbinfo.flags & CB_PROCESS))
778     {
779         if (!(cbinfo.flags & CB_OPEN) && !macdrv_is_pasteboard_owner())
780         {
781             TRACE("Lost clipboard ownership\n");
782
783             if (OpenClipboard(cbinfo.hwnd_owner))
784             {
785                 /* Destroy private objects */
786                 SendMessageW(cbinfo.hwnd_owner, WM_DESTROYCLIPBOARD, 0, 0);
787
788                 /* Give up ownership of the windows clipboard */
789                 release_ownership();
790                 CloseClipboard();
791             }
792         }
793         else if (owner)
794             *owner = cbinfo.hwnd_owner;
795     }
796 }
797
798
799 /**************************************************************************
800  *              Mac User Driver Clipboard Exports
801  **************************************************************************/
802
803
804 /**************************************************************************
805  *              AcquireClipboard (MACDRV.@)
806  */
807 int CDECL macdrv_AcquireClipboard(HWND hwnd)
808 {
809     TRACE("hwnd %p\n", hwnd);
810     check_clipboard_ownership(NULL);
811     return 0;
812 }
813
814
815 /**************************************************************************
816  *              CountClipboardFormats (MACDRV.@)
817  */
818 INT CDECL macdrv_CountClipboardFormats(void)
819 {
820     CFMutableSetRef seen_formats;
821     CFArrayRef types;
822     CFIndex count;
823     CFIndex i;
824     INT ret = 0;
825
826     TRACE("()\n");
827     check_clipboard_ownership(NULL);
828
829     seen_formats = CFSetCreateMutable(NULL, 0, NULL);
830     if (!seen_formats)
831     {
832         WARN("Failed to allocate set to track seen formats\n");
833         return 0;
834     }
835
836     types = macdrv_copy_pasteboard_types();
837     if (!types)
838     {
839         WARN("Failed to copy pasteboard types\n");
840         CFRelease(seen_formats);
841         return 0;
842     }
843
844     count = CFArrayGetCount(types);
845     TRACE("got %ld types\n", count);
846
847     for (i = 0; i < count; i++)
848     {
849         CFStringRef type = CFArrayGetValueAtIndex(types, i);
850         WINE_CLIPFORMAT* format;
851
852         format = NULL;
853         while ((format = format_for_type(format, type)))
854         {
855             TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
856
857             if (!CFSetContainsValue(seen_formats, (void*)format->format_id))
858             {
859                 ret++;
860                 CFSetAddValue(seen_formats, (void*)format->format_id);
861             }
862         }
863     }
864
865     CFRelease(seen_formats);
866     TRACE(" -> %d\n", ret);
867     return ret;
868 }
869
870
871 /**************************************************************************
872  *              EmptyClipboard (MACDRV.@)
873  *
874  * Empty cached clipboard data.
875  */
876 void CDECL macdrv_EmptyClipboard(BOOL keepunowned)
877 {
878     TRACE("keepunowned %d\n", keepunowned);
879     macdrv_clear_pasteboard();
880 }
881
882
883 /**************************************************************************
884  *              EndClipboardUpdate (MACDRV.@)
885  */
886 void CDECL macdrv_EndClipboardUpdate(void)
887 {
888     TRACE("()\n");
889     check_clipboard_ownership(NULL);
890 }
891
892
893 /**************************************************************************
894  *              EnumClipboardFormats (MACDRV.@)
895  */
896 UINT CDECL macdrv_EnumClipboardFormats(UINT prev_format)
897 {
898     CFArrayRef types;
899     CFIndex count;
900     CFIndex i;
901     UINT ret;
902
903     TRACE("prev_format %s\n", debugstr_format(prev_format));
904     check_clipboard_ownership(NULL);
905
906     types = macdrv_copy_pasteboard_types();
907     if (!types)
908     {
909         WARN("Failed to copy pasteboard types\n");
910         return 0;
911     }
912
913     count = CFArrayGetCount(types);
914     TRACE("got %ld types\n", count);
915
916     if (!count)
917     {
918         CFRelease(types);
919         return 0;
920     }
921
922     if (prev_format)
923     {
924         CFMutableArrayRef formats = CFArrayCreateMutable(NULL, 0, NULL);
925         if (!formats)
926         {
927             WARN("Failed to allocate array to track formats\n");
928             CFRelease(types);
929             return 0;
930         }
931
932         for (i = 0; i < count; i++)
933         {
934             CFStringRef type = CFArrayGetValueAtIndex(types, i);
935             WINE_CLIPFORMAT* format;
936
937             format = NULL;
938             while ((format = format_for_type(format, type)))
939             {
940                 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
941
942                 if (format->synthesized)
943                 {
944                     /* Don't override a real value with a synthesized value. */
945                     if (!CFArrayContainsValue(formats, CFRangeMake(0, CFArrayGetCount(formats)), (void*)format->format_id))
946                         CFArrayAppendValue(formats, (void*)format->format_id);
947                 }
948                 else
949                 {
950                     /* If the type was already in the array, it must have been synthesized
951                        because this one's real.  Remove the synthesized entry in favor of
952                        this one. */
953                     CFIndex index = CFArrayGetFirstIndexOfValue(formats, CFRangeMake(0, CFArrayGetCount(formats)),
954                                                                 (void*)format->format_id);
955                     if (index != kCFNotFound)
956                         CFArrayRemoveValueAtIndex(formats, index);
957                     CFArrayAppendValue(formats, (void*)format->format_id);
958                 }
959             }
960         }
961
962         count = CFArrayGetCount(formats);
963         i = CFArrayGetFirstIndexOfValue(formats, CFRangeMake(0, count), (void*)prev_format);
964         if (i == kCFNotFound || i + 1 >= count)
965             ret = 0;
966         else
967             ret = (UINT)CFArrayGetValueAtIndex(formats, i + 1);
968
969         CFRelease(formats);
970     }
971     else
972     {
973         CFStringRef type = CFArrayGetValueAtIndex(types, 0);
974         WINE_CLIPFORMAT *format = format_for_type(NULL, type);
975
976         ret = format ? format->format_id : 0;
977     }
978
979     CFRelease(types);
980     TRACE(" -> %u\n", ret);
981     return ret;
982 }
983
984
985 /**************************************************************************
986  *              GetClipboardData (MACDRV.@)
987  */
988 HANDLE CDECL macdrv_GetClipboardData(UINT desired_format)
989 {
990     CFArrayRef types;
991     CFIndex count;
992     CFIndex i;
993     CFStringRef type, best_type;
994     WINE_CLIPFORMAT* best_format = NULL;
995     HANDLE data = NULL;
996
997     TRACE("desired_format %s\n", debugstr_format(desired_format));
998     check_clipboard_ownership(NULL);
999
1000     types = macdrv_copy_pasteboard_types();
1001     if (!types)
1002     {
1003         WARN("Failed to copy pasteboard types\n");
1004         return NULL;
1005     }
1006
1007     count = CFArrayGetCount(types);
1008     TRACE("got %ld types\n", count);
1009
1010     for (i = 0; (!best_format || best_format->synthesized) && i < count; i++)
1011     {
1012         WINE_CLIPFORMAT* format;
1013
1014         type = CFArrayGetValueAtIndex(types, i);
1015
1016         format = NULL;
1017         while ((!best_format || best_format->synthesized) && (format = format_for_type(format, type)))
1018         {
1019             TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format ? format->format_id : 0));
1020
1021             if (format->format_id == desired_format)
1022             {
1023                 /* The best format is the matching one which is not synthesized.  Failing that,
1024                    the best format is the first matching synthesized format. */
1025                 if (!format->synthesized || !best_format)
1026                 {
1027                     best_type = type;
1028                     best_format = format;
1029                 }
1030             }
1031         }
1032     }
1033
1034     if (best_format)
1035     {
1036         CFDataRef pasteboard_data = macdrv_copy_pasteboard_data(best_type);
1037
1038         TRACE("got pasteboard data for type %s: %s\n", debugstr_cf(best_type), debugstr_cf(pasteboard_data));
1039
1040         if (pasteboard_data)
1041         {
1042             data = best_format->import_func(pasteboard_data);
1043             CFRelease(pasteboard_data);
1044         }
1045     }
1046
1047     CFRelease(types);
1048     TRACE(" -> %p\n", data);
1049     return data;
1050 }
1051
1052
1053 /**************************************************************************
1054  *              IsClipboardFormatAvailable (MACDRV.@)
1055  */
1056 BOOL CDECL macdrv_IsClipboardFormatAvailable(UINT desired_format)
1057 {
1058     CFArrayRef types;
1059     int count;
1060     UINT i;
1061     BOOL found = FALSE;
1062
1063     TRACE("desired_format %s\n", debugstr_format(desired_format));
1064     check_clipboard_ownership(NULL);
1065
1066     types = macdrv_copy_pasteboard_types();
1067     if (!types)
1068     {
1069         WARN("Failed to copy pasteboard types\n");
1070         return FALSE;
1071     }
1072
1073     count = CFArrayGetCount(types);
1074     TRACE("got %d types\n", count);
1075
1076     for (i = 0; !found && i < count; i++)
1077     {
1078         CFStringRef type = CFArrayGetValueAtIndex(types, i);
1079         WINE_CLIPFORMAT* format;
1080
1081         format = NULL;
1082         while (!found && (format = format_for_type(format, type)))
1083         {
1084             TRACE("for type %s got format %s\n", debugstr_cf(type), debugstr_format(format->format_id));
1085
1086             if (format->format_id == desired_format)
1087                 found = TRUE;
1088         }
1089     }
1090
1091     CFRelease(types);
1092     TRACE(" -> %d\n", found);
1093     return found;
1094 }
1095
1096
1097 /**************************************************************************
1098  *              SetClipboardData (MACDRV.@)
1099  */
1100 BOOL CDECL macdrv_SetClipboardData(UINT format_id, HANDLE data, BOOL owner)
1101 {
1102     HWND hwnd_owner;
1103     macdrv_window window;
1104     WINE_CLIPFORMAT *format;
1105     CFDataRef cfdata = NULL;
1106
1107     check_clipboard_ownership(&hwnd_owner);
1108     window = macdrv_get_cocoa_window(GetAncestor(hwnd_owner, GA_ROOT), FALSE);
1109     TRACE("format_id %s data %p owner %d hwnd_owner %p window %p)\n", debugstr_format(format_id), data, owner, hwnd_owner, window);
1110
1111     /* Find the "natural" format for this format_id (the one which isn't
1112        synthesized from another type). */
1113     LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1114         if (format->format_id == format_id && !format->synthesized) break;
1115
1116     if (&format->entry == &format_list && !(format = insert_clipboard_format(format_id, NULL)))
1117     {
1118         WARN("Failed to register clipboard format %s\n", debugstr_format(format_id));
1119         return FALSE;
1120     }
1121
1122     /* Export the data to the Mac pasteboard. */
1123     if (data)
1124     {
1125         if (!format->export_func || !(cfdata = format->export_func(data)))
1126         {
1127             WARN("Failed to export %s data to type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1128             return FALSE;
1129         }
1130     }
1131
1132     if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1133         TRACE("Set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1134     else
1135     {
1136         WARN("Failed to set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1137         if (cfdata) CFRelease(cfdata);
1138         return FALSE;
1139     }
1140
1141     if (cfdata) CFRelease(cfdata);
1142
1143     /* Find any other formats for this format_id (the exportable synthesized ones). */
1144     LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1145     {
1146         if (format->format_id == format_id && format->synthesized && format->export_func)
1147         {
1148             /* We have a synthesized format for this format ID.  Add its type to the pasteboard. */
1149             TRACE("Synthesized from format %s: type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1150
1151             if (data)
1152             {
1153                 cfdata = format->export_func(data);
1154                 if (!cfdata)
1155                 {
1156                     WARN("Failed to export %s data to type %s\n", debugstr_format(format->format_id), debugstr_cf(format->type));
1157                     continue;
1158                 }
1159             }
1160             else
1161                 cfdata = NULL;
1162
1163             if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1164                 TRACE("    ... set pasteboard data: %s\n", debugstr_cf(cfdata));
1165             else
1166                 WARN("    ... failed to set pasteboard data: %s\n", debugstr_cf(cfdata));
1167
1168             if (cfdata) CFRelease(cfdata);
1169         }
1170     }
1171
1172     if (data)
1173     {
1174         /* FIXME: According to MSDN, the caller is entitled to lock and read from
1175            data until CloseClipboard is called.  So, we should defer this cleanup. */
1176         if ((format_id >= CF_GDIOBJFIRST && format_id <= CF_GDIOBJLAST) ||
1177             format_id == CF_BITMAP ||
1178             format_id == CF_DIB ||
1179             format_id == CF_PALETTE)
1180         {
1181             DeleteObject(data);
1182         }
1183         else if (format_id == CF_METAFILEPICT)
1184         {
1185             DeleteMetaFile(((METAFILEPICT *)GlobalLock(data))->hMF);
1186             GlobalFree(data);
1187         }
1188         else if (format_id == CF_ENHMETAFILE)
1189         {
1190             DeleteEnhMetaFile(data);
1191         }
1192         else if (format_id < CF_PRIVATEFIRST || CF_PRIVATELAST < format_id)
1193         {
1194             GlobalFree(data);
1195         }
1196     }
1197
1198     return TRUE;
1199 }
1200
1201
1202 /**************************************************************************
1203  *              MACDRV Private Clipboard Exports
1204  **************************************************************************/
1205
1206
1207 /**************************************************************************
1208  *              macdrv_clipboard_process_attach
1209  */
1210 void macdrv_clipboard_process_attach(void)
1211 {
1212     UINT i;
1213
1214     /* Register built-in formats */
1215     for (i = 0; i < sizeof(builtin_format_ids)/sizeof(builtin_format_ids[0]); i++)
1216     {
1217         WINE_CLIPFORMAT *format;
1218
1219         if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
1220         format->format_id   = builtin_format_ids[i].id;
1221         format->type        = CFRetain(builtin_format_ids[i].type);
1222         format->import_func = builtin_format_ids[i].import;
1223         format->export_func = builtin_format_ids[i].export;
1224         format->synthesized = builtin_format_ids[i].synthesized;
1225         list_add_tail(&format_list, &format->entry);
1226     }
1227 }
1228
1229
1230 /**************************************************************************
1231  *              query_pasteboard_data
1232  */
1233 BOOL query_pasteboard_data(HWND hwnd, CFStringRef type)
1234 {
1235     BOOL ret = FALSE;
1236     CLIPBOARDINFO cbinfo;
1237     WINE_CLIPFORMAT* format;
1238     CFArrayRef types = NULL;
1239     CFRange range;
1240
1241     TRACE("hwnd %p type %s\n", hwnd, debugstr_cf(type));
1242
1243     if (get_clipboard_info(&cbinfo))
1244         hwnd = cbinfo.hwnd_owner;
1245
1246     format = NULL;
1247     while ((format = format_for_type(format, type)))
1248     {
1249         WINE_CLIPFORMAT* base_format;
1250
1251         TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1252
1253         if (!format->synthesized)
1254         {
1255             TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(format->format_id), hwnd);
1256             SendMessageW(hwnd, WM_RENDERFORMAT, format->format_id, 0);
1257             ret = TRUE;
1258             goto done;
1259         }
1260
1261         if (!types)
1262         {
1263             types = macdrv_copy_pasteboard_types();
1264             if (!types)
1265             {
1266                 WARN("Failed to copy pasteboard types\n");
1267                 break;
1268             }
1269
1270             range = CFRangeMake(0, CFArrayGetCount(types));
1271         }
1272
1273         /* The type maps to a synthesized format.  Now look up what type that format maps to natively
1274            (not synthesized).  For example, if type is "public.utf8-plain-text", then this format may
1275            have an ID of CF_TEXT.  From CF_TEXT, we want to find "org.winehq.builtin.text" to see if
1276            that type is present in the pasteboard.  If it is, then the app must have promised it and
1277            we can ask it to render it.  (If it had put it on the clipboard immediately, then the
1278            pasteboard would also have data for "public.utf8-plain-text" and we wouldn't be here.)  If
1279            "org.winehq.builtin.text" is not on the pasteboard, then one of the other text formats is
1280            presumably responsible for the promise that we're trying to satisfy, so we keep looking. */
1281         LIST_FOR_EACH_ENTRY(base_format, &format_list, WINE_CLIPFORMAT, entry)
1282         {
1283             if (base_format->format_id == format->format_id && !base_format->synthesized &&
1284                 CFArrayContainsValue(types, range, base_format->type))
1285             {
1286                 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(base_format->format_id), hwnd);
1287                 SendMessageW(hwnd, WM_RENDERFORMAT, base_format->format_id, 0);
1288                 ret = TRUE;
1289                 goto done;
1290             }
1291         }
1292     }
1293
1294 done:
1295     if (types) CFRelease(types);
1296
1297     return ret;
1298 }