winemac: Run a single clipboard manager thread per window station, inside the explore...
[wine.git] / dlls / winemac.drv / clipboard.c
blob936fa21986430a7080184ddb168c432ec4a57ef6
1 /*
2 * Mac clipboard driver
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.
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.
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.
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
25 #include "config.h"
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"
36 WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
39 /**************************************************************************
40 * Types
41 **************************************************************************/
43 typedef HANDLE (*DRVIMPORTFUNC)(CFDataRef data);
44 typedef CFDataRef (*DRVEXPORTFUNC)(HANDLE data);
46 typedef struct _WINE_CLIPFORMAT
48 struct list entry;
49 UINT format_id;
50 CFStringRef type;
51 DRVIMPORTFUNC import_func;
52 DRVEXPORTFUNC export_func;
53 BOOL synthesized;
54 struct _WINE_CLIPFORMAT *natural_format;
55 } WINE_CLIPFORMAT;
58 /**************************************************************************
59 * Constants
60 **************************************************************************/
63 /**************************************************************************
64 * Forward Function Declarations
65 **************************************************************************/
67 static HANDLE import_clipboard_data(CFDataRef data);
68 static HANDLE import_bmp_to_bitmap(CFDataRef data);
69 static HANDLE import_bmp_to_dib(CFDataRef data);
70 static HANDLE import_enhmetafile(CFDataRef data);
71 static HANDLE import_metafilepict(CFDataRef data);
72 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data);
73 static HANDLE import_utf8_to_text(CFDataRef data);
74 static HANDLE import_utf8_to_unicodetext(CFDataRef data);
75 static HANDLE import_utf16_to_unicodetext(CFDataRef data);
77 static CFDataRef export_clipboard_data(HANDLE data);
78 static CFDataRef export_bitmap_to_bmp(HANDLE data);
79 static CFDataRef export_dib_to_bmp(HANDLE data);
80 static CFDataRef export_enhmetafile(HANDLE data);
81 static CFDataRef export_hdrop_to_filenames(HANDLE data);
82 static CFDataRef export_metafilepict(HANDLE data);
83 static CFDataRef export_text_to_utf8(HANDLE data);
84 static CFDataRef export_unicodetext_to_utf8(HANDLE data);
85 static CFDataRef export_unicodetext_to_utf16(HANDLE data);
88 /**************************************************************************
89 * Static Variables
90 **************************************************************************/
92 /* Clipboard formats */
93 static struct list format_list = LIST_INIT(format_list);
95 /* There are two naming schemes involved and we want to have a mapping between
96 them. There are Win32 clipboard format names and there are Mac pasteboard
97 types.
99 The Win32 standard clipboard formats don't have names, but they are associated
100 with Mac pasteboard types through the following tables, which are used to
101 initialize the format_list. Where possible, the standard clipboard formats
102 are mapped to predefined pasteboard type UTIs. Otherwise, we create Wine-
103 specific types of the form "org.winehq.builtin.<format>", where <format> is
104 the name of the symbolic constant for the format minus "CF_" and lowercased.
105 E.g. CF_BITMAP -> org.winehq.builtin.bitmap.
107 Win32 clipboard formats which originate in a Windows program may be registered
108 with an arbitrary name. We construct a Mac pasteboard type from these by
109 prepending "org.winehq.registered." to the registered name.
111 Likewise, Mac pasteboard types which originate in other apps may have
112 arbitrary type strings. We ignore these.
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 <other> name registered within Win32 land; maps to
120 org.winehq.registered.<other>
121 Mac pasteboard type names:
122 org.winehq.builtin.<format ID> representation of Win32 standard clipboard
123 format for which there was no corresponding
124 predefined Mac UTI; maps via format_list
125 org.winehq.registered.<format name> representation of Win32 registered
126 clipboard format name; maps to <format name>
127 <other> Mac pasteboard type originating with system
128 or other apps; either maps via format_list
129 to a standard clipboard format or ignored
132 static const struct
134 UINT id;
135 CFStringRef type;
136 DRVIMPORTFUNC import;
137 DRVEXPORTFUNC export;
138 BOOL synthesized;
139 } builtin_format_ids[] =
141 { CF_BITMAP, CFSTR("org.winehq.builtin.bitmap"), import_bmp_to_bitmap, export_bitmap_to_bmp, FALSE },
142 { CF_DIBV5, CFSTR("org.winehq.builtin.dibv5"), import_clipboard_data, export_clipboard_data, FALSE },
143 { CF_DIF, CFSTR("org.winehq.builtin.dif"), import_clipboard_data, export_clipboard_data, FALSE },
144 { CF_ENHMETAFILE, CFSTR("org.winehq.builtin.enhmetafile"), import_enhmetafile, export_enhmetafile, FALSE },
145 { CF_LOCALE, CFSTR("org.winehq.builtin.locale"), import_clipboard_data, export_clipboard_data, FALSE },
146 { CF_METAFILEPICT, CFSTR("org.winehq.builtin.metafilepict"), import_metafilepict, export_metafilepict, FALSE },
147 { CF_OEMTEXT, CFSTR("org.winehq.builtin.oemtext"), import_clipboard_data, export_clipboard_data, FALSE },
148 { CF_PALETTE, CFSTR("org.winehq.builtin.palette"), import_clipboard_data, export_clipboard_data, FALSE },
149 { CF_PENDATA, CFSTR("org.winehq.builtin.pendata"), import_clipboard_data, export_clipboard_data, FALSE },
150 { CF_RIFF, CFSTR("org.winehq.builtin.riff"), import_clipboard_data, export_clipboard_data, FALSE },
151 { CF_SYLK, CFSTR("org.winehq.builtin.sylk"), import_clipboard_data, export_clipboard_data, FALSE },
152 { CF_TEXT, CFSTR("org.winehq.builtin.text"), import_clipboard_data, export_clipboard_data, FALSE },
153 { CF_TIFF, CFSTR("public.tiff"), import_clipboard_data, export_clipboard_data, FALSE },
154 { CF_WAVE, CFSTR("com.microsoft.waveform-audio"), import_clipboard_data, export_clipboard_data, FALSE },
156 { CF_DIB, CFSTR("org.winehq.builtin.dib"), import_clipboard_data, export_clipboard_data, FALSE },
157 { CF_DIB, CFSTR("com.microsoft.bmp"), import_bmp_to_dib, export_dib_to_bmp, TRUE },
159 { CF_HDROP, CFSTR("org.winehq.builtin.hdrop"), import_clipboard_data, export_clipboard_data, FALSE },
160 { CF_HDROP, CFSTR("NSFilenamesPboardType"), import_nsfilenames_to_hdrop, export_hdrop_to_filenames, TRUE },
162 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.unicodetext"), import_clipboard_data, export_clipboard_data, FALSE },
163 { CF_UNICODETEXT, CFSTR("public.utf16-plain-text"), import_utf16_to_unicodetext, export_unicodetext_to_utf16,TRUE },
164 { CF_UNICODETEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_unicodetext, export_unicodetext_to_utf8, TRUE },
167 static const WCHAR wszRichTextFormat[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
168 static const WCHAR wszGIF[] = {'G','I','F',0};
169 static const WCHAR wszJFIF[] = {'J','F','I','F',0};
170 static const WCHAR wszPNG[] = {'P','N','G',0};
171 static const WCHAR wszHTMLFormat[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
172 static const struct
174 LPCWSTR name;
175 CFStringRef type;
176 DRVIMPORTFUNC import;
177 DRVEXPORTFUNC export;
178 } builtin_format_names[] =
180 { wszRichTextFormat, CFSTR("public.rtf"), import_clipboard_data, export_clipboard_data },
181 { wszGIF, CFSTR("com.compuserve.gif"), import_clipboard_data, export_clipboard_data },
182 { wszJFIF, CFSTR("public.jpeg"), import_clipboard_data, export_clipboard_data },
183 { wszPNG, CFSTR("public.png"), import_clipboard_data, export_clipboard_data },
184 { wszHTMLFormat, CFSTR("public.html"), import_clipboard_data, export_clipboard_data },
185 { CFSTR_SHELLURLW, CFSTR("public.url"), import_utf8_to_text, export_text_to_utf8 },
188 /* The prefix prepended to a Win32 clipboard format name to make a Mac pasteboard type. */
189 static const CFStringRef registered_name_type_prefix = CFSTR("org.winehq.registered.");
191 static DWORD clipboard_thread_id;
192 static HWND clipboard_hwnd;
193 static BOOL is_clipboard_owner;
194 static macdrv_window clipboard_cocoa_window;
195 static ULONG64 last_clipboard_update;
196 static WINE_CLIPFORMAT **current_mac_formats;
197 static unsigned int nb_current_mac_formats;
200 /**************************************************************************
201 * Internal Clipboard implementation methods
202 **************************************************************************/
205 * format_list functions
208 /**************************************************************************
209 * debugstr_format
211 const char *debugstr_format(UINT id)
213 WCHAR buffer[256];
215 if (GetClipboardFormatNameW(id, buffer, 256))
216 return wine_dbg_sprintf("0x%04x %s", id, debugstr_w(buffer));
218 switch (id)
220 #define BUILTIN(id) case id: return #id;
221 BUILTIN(CF_TEXT)
222 BUILTIN(CF_BITMAP)
223 BUILTIN(CF_METAFILEPICT)
224 BUILTIN(CF_SYLK)
225 BUILTIN(CF_DIF)
226 BUILTIN(CF_TIFF)
227 BUILTIN(CF_OEMTEXT)
228 BUILTIN(CF_DIB)
229 BUILTIN(CF_PALETTE)
230 BUILTIN(CF_PENDATA)
231 BUILTIN(CF_RIFF)
232 BUILTIN(CF_WAVE)
233 BUILTIN(CF_UNICODETEXT)
234 BUILTIN(CF_ENHMETAFILE)
235 BUILTIN(CF_HDROP)
236 BUILTIN(CF_LOCALE)
237 BUILTIN(CF_DIBV5)
238 BUILTIN(CF_OWNERDISPLAY)
239 BUILTIN(CF_DSPTEXT)
240 BUILTIN(CF_DSPBITMAP)
241 BUILTIN(CF_DSPMETAFILEPICT)
242 BUILTIN(CF_DSPENHMETAFILE)
243 #undef BUILTIN
244 default: return wine_dbg_sprintf("0x%04x", id);
249 /**************************************************************************
250 * insert_clipboard_format
252 static WINE_CLIPFORMAT *insert_clipboard_format(UINT id, CFStringRef type)
254 WINE_CLIPFORMAT *format;
256 format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format));
258 if (format == NULL)
260 WARN("No more memory for a new format!\n");
261 return NULL;
263 format->format_id = id;
264 format->import_func = import_clipboard_data;
265 format->export_func = export_clipboard_data;
266 format->synthesized = FALSE;
267 format->natural_format = NULL;
269 if (type)
270 format->type = CFStringCreateCopy(NULL, type);
271 else
273 WCHAR buffer[256];
275 if (!GetClipboardFormatNameW(format->format_id, buffer, sizeof(buffer) / sizeof(buffer[0])))
277 WARN("failed to get name for format %s; error 0x%08x\n", debugstr_format(format->format_id), GetLastError());
278 HeapFree(GetProcessHeap(), 0, format);
279 return NULL;
282 format->type = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%S"),
283 registered_name_type_prefix, buffer);
286 list_add_tail(&format_list, &format->entry);
288 TRACE("Registering format %s type %s\n", debugstr_format(format->format_id),
289 debugstr_cf(format->type));
291 return format;
295 /**************************************************************************
296 * register_format
298 * Register a custom Mac clipboard format.
300 static WINE_CLIPFORMAT* register_format(UINT id, CFStringRef type)
302 WINE_CLIPFORMAT *format;
304 /* walk format chain to see if it's already registered */
305 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
306 if (format->format_id == id) return format;
308 return insert_clipboard_format(id, type);
312 /**************************************************************************
313 * natural_format_for_format
315 * Find the "natural" format for this format_id (the one which isn't
316 * synthesized from another type).
318 static WINE_CLIPFORMAT* natural_format_for_format(UINT format_id)
320 WINE_CLIPFORMAT *format;
322 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
323 if (format->format_id == format_id && !format->synthesized) break;
325 if (&format->entry == &format_list)
326 format = NULL;
328 TRACE("%s -> %p/%s\n", debugstr_format(format_id), format, debugstr_cf(format ? format->type : NULL));
329 return format;
333 /**************************************************************************
334 * register_builtin_formats
336 static void register_builtin_formats(void)
338 UINT i;
339 WINE_CLIPFORMAT *format;
341 /* Register built-in formats */
342 for (i = 0; i < sizeof(builtin_format_ids)/sizeof(builtin_format_ids[0]); i++)
344 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
345 format->format_id = builtin_format_ids[i].id;
346 format->type = CFRetain(builtin_format_ids[i].type);
347 format->import_func = builtin_format_ids[i].import;
348 format->export_func = builtin_format_ids[i].export;
349 format->synthesized = builtin_format_ids[i].synthesized;
350 format->natural_format = NULL;
351 list_add_tail(&format_list, &format->entry);
354 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
356 if (format->synthesized)
357 format->natural_format = natural_format_for_format(format->format_id);
360 /* Register known mappings between Windows formats and Mac types */
361 for (i = 0; i < sizeof(builtin_format_names)/sizeof(builtin_format_names[0]); i++)
363 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
364 format->format_id = RegisterClipboardFormatW(builtin_format_names[i].name);
365 format->type = CFRetain(builtin_format_names[i].type);
366 format->import_func = builtin_format_names[i].import;
367 format->export_func = builtin_format_names[i].export;
368 format->synthesized = FALSE;
369 format->natural_format = NULL;
370 list_add_tail(&format_list, &format->entry);
375 /**************************************************************************
376 * format_for_type
378 static WINE_CLIPFORMAT* format_for_type(CFStringRef type)
380 WINE_CLIPFORMAT *format;
382 TRACE("type %s\n", debugstr_cf(type));
384 if (list_empty(&format_list)) register_builtin_formats();
386 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
388 if (CFEqual(format->type, type))
389 goto done;
392 format = NULL;
393 if (CFStringHasPrefix(type, CFSTR("org.winehq.builtin.")))
395 ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
396 debugstr_cf(type));
398 else if (CFStringHasPrefix(type, registered_name_type_prefix))
400 LPWSTR name;
401 int len = CFStringGetLength(type) - CFStringGetLength(registered_name_type_prefix);
403 name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
404 CFStringGetCharacters(type, CFRangeMake(CFStringGetLength(registered_name_type_prefix), len),
405 (UniChar*)name);
406 name[len] = 0;
408 format = register_format(RegisterClipboardFormatW(name), type);
409 if (!format)
410 ERR("Failed to register format for type %s name %s\n", debugstr_cf(type), debugstr_w(name));
412 HeapFree(GetProcessHeap(), 0, name);
415 done:
416 TRACE(" -> %p/%s\n", format, debugstr_format(format ? format->format_id : 0));
417 return format;
421 /***********************************************************************
422 * bitmap_info_size
424 * Return the size of the bitmap info structure including color table.
426 static int bitmap_info_size(const BITMAPINFO *info, WORD coloruse)
428 unsigned int colors, size, masks = 0;
430 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
432 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER*)info;
433 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
434 return sizeof(BITMAPCOREHEADER) + colors *
435 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
437 else /* assume BITMAPINFOHEADER */
439 colors = MIN(info->bmiHeader.biClrUsed, 256);
440 if (!colors && (info->bmiHeader.biBitCount <= 8))
441 colors = 1 << info->bmiHeader.biBitCount;
442 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
443 size = max(info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD));
444 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
449 /***********************************************************************
450 * create_dib_from_bitmap
452 * Allocates a packed DIB and copies the bitmap data into it.
454 static HGLOBAL create_dib_from_bitmap(HBITMAP bitmap)
456 HANDLE ret = 0;
457 BITMAPINFOHEADER header;
458 HDC hdc = GetDC(0);
459 DWORD header_size;
460 BITMAPINFO *bmi;
462 memset(&header, 0, sizeof(header));
463 header.biSize = sizeof(header);
464 if (!GetDIBits(hdc, bitmap, 0, 0, NULL, (BITMAPINFO *)&header, DIB_RGB_COLORS)) goto done;
466 header_size = bitmap_info_size((BITMAPINFO *)&header, DIB_RGB_COLORS);
467 if (!(ret = GlobalAlloc(GMEM_FIXED, header_size + header.biSizeImage))) goto done;
468 bmi = (BITMAPINFO *)ret;
469 memset(bmi, 0, header_size);
470 memcpy(bmi, &header, header.biSize);
471 GetDIBits(hdc, bitmap, 0, abs(header.biHeight), (char *)bmi + header_size, bmi, DIB_RGB_COLORS);
473 done:
474 ReleaseDC(0, hdc);
475 return ret;
479 /**************************************************************************
480 * create_bitmap_from_dib
482 * Given a packed DIB, creates a bitmap object from it.
484 static HANDLE create_bitmap_from_dib(HANDLE dib)
486 HANDLE ret = 0;
487 BITMAPINFO *bmi;
489 if (dib && (bmi = GlobalLock(dib)))
491 HDC hdc;
492 unsigned int offset;
494 hdc = GetDC(NULL);
496 offset = bitmap_info_size(bmi, DIB_RGB_COLORS);
498 ret = CreateDIBitmap(hdc, &bmi->bmiHeader, CBM_INIT, (LPBYTE)bmi + offset,
499 bmi, DIB_RGB_COLORS);
501 GlobalUnlock(dib);
502 ReleaseDC(NULL, hdc);
505 return ret;
509 /**************************************************************************
510 * import_clipboard_data
512 * Generic import clipboard data routine.
514 static HANDLE import_clipboard_data(CFDataRef data)
516 HANDLE data_handle = NULL;
518 size_t len = CFDataGetLength(data);
519 if (len)
521 LPVOID p;
523 /* Turn on the DDESHARE flag to enable shared 32 bit memory */
524 data_handle = GlobalAlloc(GMEM_FIXED, len);
525 if (!data_handle)
526 return NULL;
528 if ((p = GlobalLock(data_handle)))
530 memcpy(p, CFDataGetBytePtr(data), len);
531 GlobalUnlock(data_handle);
533 else
535 GlobalFree(data_handle);
536 data_handle = NULL;
540 return data_handle;
544 /**************************************************************************
545 * import_bmp_to_bitmap
547 * Import BMP data, converting to CF_BITMAP format.
549 static HANDLE import_bmp_to_bitmap(CFDataRef data)
551 HANDLE ret;
552 HANDLE dib = import_bmp_to_dib(data);
554 ret = create_bitmap_from_dib(dib);
556 GlobalFree(dib);
557 return ret;
561 /**************************************************************************
562 * import_bmp_to_dib
564 * Import BMP data, converting to CF_DIB or CF_DIBV5 format. This just
565 * entails stripping the BMP file format header.
567 static HANDLE import_bmp_to_dib(CFDataRef data)
569 HANDLE ret = 0;
570 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)CFDataGetBytePtr(data);
571 CFIndex len = CFDataGetLength(data);
573 if (len >= sizeof(*bfh) + sizeof(BITMAPCOREHEADER) &&
574 bfh->bfType == 0x4d42 /* "BM" */)
576 BITMAPINFO *bmi = (BITMAPINFO*)(bfh + 1);
577 BYTE* p;
579 len -= sizeof(*bfh);
580 ret = GlobalAlloc(GMEM_FIXED, len);
581 if (!ret || !(p = GlobalLock(ret)))
583 GlobalFree(ret);
584 return 0;
587 memcpy(p, bmi, len);
588 GlobalUnlock(ret);
591 return ret;
595 /**************************************************************************
596 * import_enhmetafile
598 * Import enhanced metafile data, converting it to CF_ENHMETAFILE.
600 static HANDLE import_enhmetafile(CFDataRef data)
602 HANDLE ret = 0;
603 CFIndex len = CFDataGetLength(data);
605 TRACE("data %s\n", debugstr_cf(data));
607 if (len)
608 ret = SetEnhMetaFileBits(len, (const BYTE*)CFDataGetBytePtr(data));
610 return ret;
614 /**************************************************************************
615 * import_metafilepict
617 * Import metafile picture data, converting it to CF_METAFILEPICT.
619 static HANDLE import_metafilepict(CFDataRef data)
621 HANDLE ret = 0;
622 CFIndex len = CFDataGetLength(data);
623 METAFILEPICT *mfp;
625 TRACE("data %s\n", debugstr_cf(data));
627 if (len >= sizeof(*mfp) && (ret = GlobalAlloc(GMEM_FIXED, sizeof(*mfp))))
629 const BYTE *bytes = (const BYTE*)CFDataGetBytePtr(data);
631 mfp = GlobalLock(ret);
632 memcpy(mfp, bytes, sizeof(*mfp));
633 mfp->hMF = SetMetaFileBitsEx(len - sizeof(*mfp), bytes + sizeof(*mfp));
634 GlobalUnlock(ret);
637 return ret;
641 /**************************************************************************
642 * import_nsfilenames_to_hdrop
644 * Import NSFilenamesPboardType data, converting the property-list-
645 * serialized array of path strings to CF_HDROP.
647 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data)
649 HDROP hdrop = NULL;
650 CFArrayRef names;
651 CFIndex count, i;
652 size_t len;
653 char *buffer = NULL;
654 WCHAR **paths = NULL;
655 DROPFILES* dropfiles;
656 UniChar* p;
658 TRACE("data %s\n", debugstr_cf(data));
660 names = (CFArrayRef)CFPropertyListCreateWithData(NULL, data, kCFPropertyListImmutable,
661 NULL, NULL);
662 if (!names || CFGetTypeID(names) != CFArrayGetTypeID())
664 WARN("failed to interpret data as a CFArray\n");
665 goto done;
668 count = CFArrayGetCount(names);
670 len = 0;
671 for (i = 0; i < count; i++)
673 CFIndex this_len;
674 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
675 TRACE(" %s\n", debugstr_cf(name));
676 if (CFGetTypeID(name) != CFStringGetTypeID())
678 WARN("non-string in array\n");
679 goto done;
682 this_len = CFStringGetMaximumSizeOfFileSystemRepresentation(name);
683 if (this_len > len)
684 len = this_len;
687 buffer = HeapAlloc(GetProcessHeap(), 0, len);
688 if (!buffer)
690 WARN("failed to allocate buffer for file-system representations\n");
691 goto done;
694 paths = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(paths[0]));
695 if (!paths)
697 WARN("failed to allocate array of DOS paths\n");
698 goto done;
701 for (i = 0; i < count; i++)
703 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
704 if (!CFStringGetFileSystemRepresentation(name, buffer, len))
706 WARN("failed to get file-system representation for %s\n", debugstr_cf(name));
707 goto done;
709 paths[i] = wine_get_dos_file_name(buffer);
710 if (!paths[i])
712 WARN("failed to get DOS path for %s\n", debugstr_a(buffer));
713 goto done;
717 len = 1; /* for the terminating null */
718 for (i = 0; i < count; i++)
719 len += strlenW(paths[i]) + 1;
721 hdrop = GlobalAlloc(GMEM_FIXED, sizeof(*dropfiles) + len * sizeof(WCHAR));
722 if (!hdrop || !(dropfiles = GlobalLock(hdrop)))
724 WARN("failed to allocate HDROP\n");
725 GlobalFree(hdrop);
726 hdrop = NULL;
727 goto done;
730 dropfiles->pFiles = sizeof(*dropfiles);
731 dropfiles->pt.x = 0;
732 dropfiles->pt.y = 0;
733 dropfiles->fNC = FALSE;
734 dropfiles->fWide = TRUE;
736 p = (WCHAR*)(dropfiles + 1);
737 for (i = 0; i < count; i++)
739 strcpyW(p, paths[i]);
740 p += strlenW(p) + 1;
742 *p = 0;
744 GlobalUnlock(hdrop);
746 done:
747 if (paths)
749 for (i = 0; i < count; i++)
750 HeapFree(GetProcessHeap(), 0, paths[i]);
751 HeapFree(GetProcessHeap(), 0, paths);
753 HeapFree(GetProcessHeap(), 0, buffer);
754 if (names) CFRelease(names);
755 return hdrop;
759 /**************************************************************************
760 * import_utf8_to_text
762 * Import a UTF-8 string, converting the string to CF_TEXT.
764 static HANDLE import_utf8_to_text(CFDataRef data)
766 HANDLE ret = NULL;
767 HANDLE unicode_handle = import_utf8_to_unicodetext(data);
768 LPWSTR unicode_string = GlobalLock(unicode_handle);
770 if (unicode_string)
772 int unicode_len;
773 HANDLE handle;
774 char *p;
775 INT len;
777 unicode_len = GlobalSize(unicode_handle) / sizeof(WCHAR);
779 len = WideCharToMultiByte(CP_ACP, 0, unicode_string, unicode_len, NULL, 0, NULL, NULL);
780 if (!unicode_len || unicode_string[unicode_len - 1]) len += 1;
781 handle = GlobalAlloc(GMEM_FIXED, len);
783 if (handle && (p = GlobalLock(handle)))
785 WideCharToMultiByte(CP_ACP, 0, unicode_string, unicode_len, p, len, NULL, NULL);
786 p[len - 1] = 0;
787 GlobalUnlock(handle);
788 ret = handle;
790 GlobalUnlock(unicode_handle);
793 GlobalFree(unicode_handle);
794 return ret;
798 /**************************************************************************
799 * import_utf8_to_unicodetext
801 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
803 static HANDLE import_utf8_to_unicodetext(CFDataRef data)
805 const BYTE *src;
806 unsigned long src_len;
807 unsigned long new_lines = 0;
808 LPSTR dst;
809 unsigned long i, j;
810 HANDLE unicode_handle = NULL;
812 src = CFDataGetBytePtr(data);
813 src_len = CFDataGetLength(data);
814 for (i = 0; i < src_len; i++)
816 if (src[i] == '\n')
817 new_lines++;
820 if ((dst = HeapAlloc(GetProcessHeap(), 0, src_len + new_lines + 1)))
822 UINT count;
824 for (i = 0, j = 0; i < src_len; i++)
826 if (src[i] == '\n')
827 dst[j++] = '\r';
829 dst[j++] = src[i];
831 dst[j] = 0;
833 count = MultiByteToWideChar(CP_UTF8, 0, dst, -1, NULL, 0);
834 unicode_handle = GlobalAlloc(GMEM_FIXED, count * sizeof(WCHAR));
836 if (unicode_handle)
838 WCHAR *textW = GlobalLock(unicode_handle);
839 MultiByteToWideChar(CP_UTF8, 0, dst, -1, textW, count);
840 GlobalUnlock(unicode_handle);
843 HeapFree(GetProcessHeap(), 0, dst);
846 return unicode_handle;
850 /**************************************************************************
851 * import_utf16_to_unicodetext
853 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
855 static HANDLE import_utf16_to_unicodetext(CFDataRef data)
857 const WCHAR *src;
858 unsigned long src_len;
859 unsigned long new_lines = 0;
860 LPWSTR dst;
861 unsigned long i, j;
862 HANDLE unicode_handle;
864 src = (const WCHAR *)CFDataGetBytePtr(data);
865 src_len = CFDataGetLength(data) / sizeof(WCHAR);
866 for (i = 0; i < src_len; i++)
868 if (src[i] == '\n')
869 new_lines++;
870 else if (src[i] == '\r' && (i + 1 >= src_len || src[i + 1] != '\n'))
871 new_lines++;
874 if ((unicode_handle = GlobalAlloc(GMEM_FIXED, (src_len + new_lines + 1) * sizeof(WCHAR))))
876 dst = GlobalLock(unicode_handle);
878 for (i = 0, j = 0; i < src_len; i++)
880 if (src[i] == '\n')
881 dst[j++] = '\r';
883 dst[j++] = src[i];
885 if (src[i] == '\r' && (i + 1 >= src_len || src[i + 1] != '\n'))
886 dst[j++] = '\n';
888 dst[j] = 0;
890 GlobalUnlock(unicode_handle);
893 return unicode_handle;
897 /**************************************************************************
898 * export_clipboard_data
900 * Generic export clipboard data routine.
902 static CFDataRef export_clipboard_data(HANDLE data)
904 CFDataRef ret;
905 UINT len;
906 LPVOID src;
908 len = GlobalSize(data);
909 src = GlobalLock(data);
910 if (!src) return NULL;
912 ret = CFDataCreate(NULL, src, len);
913 GlobalUnlock(data);
915 return ret;
919 /**************************************************************************
920 * export_bitmap_to_bmp
922 * Export CF_BITMAP to BMP file format.
924 static CFDataRef export_bitmap_to_bmp(HANDLE data)
926 CFDataRef ret = NULL;
927 HGLOBAL dib;
929 dib = create_dib_from_bitmap(data);
930 if (dib)
932 ret = export_dib_to_bmp(dib);
933 GlobalFree(dib);
936 return ret;
940 /**************************************************************************
941 * export_dib_to_bmp
943 * Export CF_DIB or CF_DIBV5 to BMP file format. This just entails
944 * prepending a BMP file format header to the data.
946 static CFDataRef export_dib_to_bmp(HANDLE data)
948 CFMutableDataRef ret = NULL;
949 BYTE *dibdata;
950 CFIndex len;
951 BITMAPFILEHEADER bfh;
953 dibdata = GlobalLock(data);
954 if (!dibdata)
955 return NULL;
957 len = sizeof(bfh) + GlobalSize(data);
958 ret = CFDataCreateMutable(NULL, len);
959 if (ret)
961 bfh.bfType = 0x4d42; /* "BM" */
962 bfh.bfSize = len;
963 bfh.bfReserved1 = 0;
964 bfh.bfReserved2 = 0;
965 bfh.bfOffBits = sizeof(bfh) + bitmap_info_size((BITMAPINFO*)dibdata, DIB_RGB_COLORS);
966 CFDataAppendBytes(ret, (UInt8*)&bfh, sizeof(bfh));
968 /* rest of bitmap is the same as the packed dib */
969 CFDataAppendBytes(ret, (UInt8*)dibdata, len - sizeof(bfh));
972 GlobalUnlock(data);
974 return ret;
978 /**************************************************************************
979 * export_enhmetafile
981 * Export an enhanced metafile to data.
983 static CFDataRef export_enhmetafile(HANDLE data)
985 CFMutableDataRef ret = NULL;
986 unsigned int size = GetEnhMetaFileBits(data, 0, NULL);
988 TRACE("data %p\n", data);
990 ret = CFDataCreateMutable(NULL, size);
991 if (ret)
993 CFDataSetLength(ret, size);
994 GetEnhMetaFileBits(data, size, (BYTE*)CFDataGetMutableBytePtr(ret));
997 TRACE(" -> %s\n", debugstr_cf(ret));
998 return ret;
1002 /**************************************************************************
1003 * export_hdrop_to_filenames
1005 * Export CF_HDROP to NSFilenamesPboardType data, which is a CFArray of
1006 * CFStrings (holding Unix paths) which is serialized as a property list.
1008 static CFDataRef export_hdrop_to_filenames(HANDLE data)
1010 CFDataRef ret = NULL;
1011 DROPFILES *dropfiles;
1012 CFMutableArrayRef filenames = NULL;
1013 void *p;
1014 WCHAR *buffer = NULL;
1015 size_t buffer_len = 0;
1017 TRACE("data %p\n", data);
1019 if (!(dropfiles = GlobalLock(data)))
1021 WARN("failed to lock data %p\n", data);
1022 goto done;
1025 filenames = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1026 if (!filenames)
1028 WARN("failed to create filenames array\n");
1029 goto done;
1032 p = (char*)dropfiles + dropfiles->pFiles;
1033 while (dropfiles->fWide ? *(WCHAR*)p : *(char*)p)
1035 char *unixname;
1036 CFStringRef filename;
1038 TRACE(" %s\n", dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1040 if (dropfiles->fWide)
1041 unixname = wine_get_unix_file_name(p);
1042 else
1044 int len = MultiByteToWideChar(CP_ACP, 0, p, -1, NULL, 0);
1045 if (len)
1047 if (len > buffer_len)
1049 HeapFree(GetProcessHeap(), 0, buffer);
1050 buffer_len = len * 2;
1051 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_len * sizeof(*buffer));
1054 MultiByteToWideChar(CP_ACP, 0, p, -1, buffer, buffer_len);
1055 unixname = wine_get_unix_file_name(buffer);
1057 else
1058 unixname = NULL;
1060 if (!unixname)
1062 WARN("failed to convert DOS path to Unix: %s\n",
1063 dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1064 goto done;
1067 if (dropfiles->fWide)
1068 p = (WCHAR*)p + strlenW(p) + 1;
1069 else
1070 p = (char*)p + strlen(p) + 1;
1072 filename = CFStringCreateWithFileSystemRepresentation(NULL, unixname);
1073 HeapFree(GetProcessHeap(), 0, unixname);
1074 if (!filename)
1076 WARN("failed to create CFString from Unix path %s\n", debugstr_a(unixname));
1077 goto done;
1080 CFArrayAppendValue(filenames, filename);
1081 CFRelease(filename);
1084 ret = CFPropertyListCreateData(NULL, filenames, kCFPropertyListXMLFormat_v1_0, 0, NULL);
1086 done:
1087 HeapFree(GetProcessHeap(), 0, buffer);
1088 GlobalUnlock(data);
1089 if (filenames) CFRelease(filenames);
1090 TRACE(" -> %s\n", debugstr_cf(ret));
1091 return ret;
1095 /**************************************************************************
1096 * export_metafilepict
1098 * Export a metafile to data.
1100 static CFDataRef export_metafilepict(HANDLE data)
1102 CFMutableDataRef ret = NULL;
1103 METAFILEPICT *mfp = GlobalLock(data);
1104 unsigned int size = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
1106 TRACE("data %p\n", data);
1108 ret = CFDataCreateMutable(NULL, sizeof(*mfp) + size);
1109 if (ret)
1111 CFDataAppendBytes(ret, (UInt8*)mfp, sizeof(*mfp));
1112 CFDataIncreaseLength(ret, size);
1113 GetMetaFileBitsEx(mfp->hMF, size, (BYTE*)CFDataGetMutableBytePtr(ret) + sizeof(*mfp));
1116 GlobalUnlock(data);
1117 TRACE(" -> %s\n", debugstr_cf(ret));
1118 return ret;
1122 /**************************************************************************
1123 * export_text_to_utf8
1125 * Export CF_TEXT to UTF-8.
1127 static CFDataRef export_text_to_utf8(HANDLE data)
1129 CFDataRef ret = NULL;
1130 const char* str;
1132 if ((str = GlobalLock(data)))
1134 int str_len = GlobalSize(data);
1135 int wstr_len;
1136 WCHAR *wstr;
1137 HANDLE unicode;
1138 char *p;
1140 wstr_len = MultiByteToWideChar(CP_ACP, 0, str, str_len, NULL, 0);
1141 if (!str_len || str[str_len - 1]) wstr_len += 1;
1142 wstr = HeapAlloc(GetProcessHeap(), 0, wstr_len * sizeof(WCHAR));
1143 MultiByteToWideChar(CP_ACP, 0, str, str_len, wstr, wstr_len);
1144 wstr[wstr_len - 1] = 0;
1146 unicode = GlobalAlloc(GMEM_FIXED, wstr_len * sizeof(WCHAR));
1147 if (unicode && (p = GlobalLock(unicode)))
1149 memcpy(p, wstr, wstr_len * sizeof(WCHAR));
1150 GlobalUnlock(unicode);
1153 ret = export_unicodetext_to_utf8(unicode);
1155 GlobalFree(unicode);
1156 GlobalUnlock(data);
1159 return ret;
1163 /**************************************************************************
1164 * export_unicodetext_to_utf8
1166 * Export CF_UNICODETEXT to UTF-8.
1168 static CFDataRef export_unicodetext_to_utf8(HANDLE data)
1170 CFMutableDataRef ret;
1171 LPVOID src;
1172 INT dst_len;
1174 src = GlobalLock(data);
1175 if (!src) return NULL;
1177 dst_len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
1178 if (dst_len) dst_len--; /* Leave off null terminator. */
1179 ret = CFDataCreateMutable(NULL, dst_len);
1180 if (ret)
1182 LPSTR dst;
1183 int i, j;
1185 CFDataSetLength(ret, dst_len);
1186 dst = (LPSTR)CFDataGetMutableBytePtr(ret);
1187 WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_len, NULL, NULL);
1189 /* Remove carriage returns */
1190 for (i = 0, j = 0; i < dst_len; i++)
1192 if (dst[i] == '\r' &&
1193 (i + 1 >= dst_len || dst[i + 1] == '\n' || dst[i + 1] == '\0'))
1194 continue;
1195 dst[j++] = dst[i];
1197 CFDataSetLength(ret, j);
1199 GlobalUnlock(data);
1201 return ret;
1205 /**************************************************************************
1206 * export_unicodetext_to_utf16
1208 * Export CF_UNICODETEXT to UTF-16.
1210 static CFDataRef export_unicodetext_to_utf16(HANDLE data)
1212 CFMutableDataRef ret;
1213 const WCHAR *src;
1214 INT src_len;
1216 src = GlobalLock(data);
1217 if (!src) return NULL;
1219 src_len = GlobalSize(data) / sizeof(WCHAR);
1220 if (src_len) src_len--; /* Leave off null terminator. */
1221 ret = CFDataCreateMutable(NULL, src_len * sizeof(WCHAR));
1222 if (ret)
1224 LPWSTR dst;
1225 int i, j;
1227 CFDataSetLength(ret, src_len * sizeof(WCHAR));
1228 dst = (LPWSTR)CFDataGetMutableBytePtr(ret);
1230 /* Remove carriage returns */
1231 for (i = 0, j = 0; i < src_len; i++)
1233 if (src[i] == '\r' &&
1234 (i + 1 >= src_len || src[i + 1] == '\n' || src[i + 1] == '\0'))
1235 continue;
1236 dst[j++] = src[i];
1238 CFDataSetLength(ret, j * sizeof(WCHAR));
1240 GlobalUnlock(data);
1242 return ret;
1246 /**************************************************************************
1247 * macdrv_get_pasteboard_data
1249 HANDLE macdrv_get_pasteboard_data(CFTypeRef pasteboard, UINT desired_format)
1251 CFArrayRef types;
1252 CFIndex count;
1253 CFIndex i;
1254 CFStringRef type, best_type;
1255 WINE_CLIPFORMAT* best_format = NULL;
1256 HANDLE data = NULL;
1258 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1260 types = macdrv_copy_pasteboard_types(pasteboard);
1261 if (!types)
1263 WARN("Failed to copy pasteboard types\n");
1264 return NULL;
1267 count = CFArrayGetCount(types);
1268 TRACE("got %ld types\n", count);
1270 for (i = 0; (!best_format || best_format->synthesized) && i < count; i++)
1272 WINE_CLIPFORMAT* format;
1274 type = CFArrayGetValueAtIndex(types, i);
1276 if ((format = format_for_type(type)))
1278 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1280 if (format->format_id == desired_format)
1282 /* The best format is the matching one which is not synthesized. Failing that,
1283 the best format is the first matching synthesized format. */
1284 if (!format->synthesized || !best_format)
1286 best_type = type;
1287 best_format = format;
1293 if (best_format)
1295 CFDataRef pasteboard_data = macdrv_copy_pasteboard_data(pasteboard, best_type);
1297 TRACE("got pasteboard data for type %s: %s\n", debugstr_cf(best_type), debugstr_cf(pasteboard_data));
1299 if (pasteboard_data)
1301 data = best_format->import_func(pasteboard_data);
1302 CFRelease(pasteboard_data);
1306 CFRelease(types);
1307 TRACE(" -> %p\n", data);
1308 return data;
1312 /**************************************************************************
1313 * macdrv_pasteboard_has_format
1315 BOOL macdrv_pasteboard_has_format(CFTypeRef pasteboard, UINT desired_format)
1317 CFArrayRef types;
1318 int count;
1319 UINT i;
1320 BOOL found = FALSE;
1322 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1324 types = macdrv_copy_pasteboard_types(pasteboard);
1325 if (!types)
1327 WARN("Failed to copy pasteboard types\n");
1328 return FALSE;
1331 count = CFArrayGetCount(types);
1332 TRACE("got %d types\n", count);
1334 for (i = 0; i < count; i++)
1336 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1337 WINE_CLIPFORMAT* format = format_for_type(type);
1339 if (format)
1341 TRACE("for type %s got format %s\n", debugstr_cf(type), debugstr_format(format->format_id));
1343 if (format->format_id == desired_format)
1345 found = TRUE;
1346 break;
1351 CFRelease(types);
1352 TRACE(" -> %d\n", found);
1353 return found;
1357 /**************************************************************************
1358 * get_formats_for_pasteboard
1360 static WINE_CLIPFORMAT** get_formats_for_pasteboard(CFTypeRef pasteboard, UINT *num_formats)
1362 CFArrayRef types;
1363 CFIndex count, i;
1364 CFMutableSetRef seen_formats;
1365 WINE_CLIPFORMAT** formats;
1366 UINT pos;
1368 TRACE("pasteboard %s\n", debugstr_cf(pasteboard));
1370 types = macdrv_copy_pasteboard_types(pasteboard);
1371 if (!types)
1373 WARN("Failed to copy pasteboard types\n");
1374 return NULL;
1377 count = CFArrayGetCount(types);
1378 TRACE("got %ld types\n", count);
1380 if (!count)
1382 CFRelease(types);
1383 return NULL;
1386 seen_formats = CFSetCreateMutable(NULL, count, NULL);
1387 if (!seen_formats)
1389 WARN("Failed to allocate seen formats set\n");
1390 CFRelease(types);
1391 return NULL;
1394 formats = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*formats));
1395 if (!formats)
1397 WARN("Failed to allocate formats array\n");
1398 CFRelease(types);
1399 CFRelease(seen_formats);
1400 return NULL;
1403 pos = 0;
1404 for (i = 0; i < count; i++)
1406 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1407 WINE_CLIPFORMAT* format = format_for_type(type);
1409 if (!format)
1411 TRACE("ignoring type %s\n", debugstr_cf(type));
1412 continue;
1415 if (!format->synthesized)
1417 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1418 CFSetAddValue(seen_formats, (void*)format->format_id);
1419 formats[pos++] = format;
1421 else if (format->natural_format &&
1422 CFArrayContainsValue(types, CFRangeMake(0, count), format->natural_format->type))
1424 TRACE("for type %s deferring synthesized formats because type %s is also present\n",
1425 debugstr_cf(type), debugstr_cf(format->natural_format->type));
1427 else if (CFSetContainsValue(seen_formats, (void*)format->format_id))
1429 TRACE("for type %s got duplicate synthesized format %p/%s; skipping\n", debugstr_cf(type), format,
1430 debugstr_format(format->format_id));
1432 else
1434 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1435 CFSetAddValue(seen_formats, (void*)format->format_id);
1436 formats[pos++] = format;
1440 /* Now go back through the types adding the synthesized formats that we deferred before. */
1441 for (i = 0; i < count; i++)
1443 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1444 WINE_CLIPFORMAT* format = format_for_type(type);
1446 if (!format) continue;
1447 if (!format->synthesized) continue;
1449 /* Don't duplicate a real value with a synthesized value. */
1450 if (CFSetContainsValue(seen_formats, (void*)format->format_id)) continue;
1452 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1453 CFSetAddValue(seen_formats, (void*)format->format_id);
1454 formats[pos++] = format;
1457 CFRelease(types);
1458 CFRelease(seen_formats);
1460 if (!pos)
1462 HeapFree(GetProcessHeap(), 0, formats);
1463 formats = NULL;
1466 *num_formats = pos;
1467 return formats;
1471 /**************************************************************************
1472 * macdrv_get_pasteboard_formats
1474 UINT* macdrv_get_pasteboard_formats(CFTypeRef pasteboard, UINT* num_formats)
1476 WINE_CLIPFORMAT** formats;
1477 UINT count, i;
1478 UINT* format_ids;
1480 formats = get_formats_for_pasteboard(pasteboard, &count);
1481 if (!formats)
1482 return NULL;
1484 format_ids = HeapAlloc(GetProcessHeap(), 0, count);
1485 if (!format_ids)
1487 WARN("Failed to allocate formats IDs array\n");
1488 HeapFree(GetProcessHeap(), 0, formats);
1489 return NULL;
1492 for (i = 0; i < count; i++)
1493 format_ids[i] = formats[i]->format_id;
1495 HeapFree(GetProcessHeap(), 0, formats);
1497 *num_formats = count;
1498 return format_ids;
1502 /**************************************************************************
1503 * register_win32_formats
1505 * Register Win32 clipboard formats the first time we encounter them.
1507 static void register_win32_formats(const UINT *ids, UINT size)
1509 unsigned int i;
1511 if (list_empty(&format_list)) register_builtin_formats();
1513 for (i = 0; i < size; i++)
1514 register_format(ids[i], NULL);
1518 /***********************************************************************
1519 * get_clipboard_formats
1521 * Return a list of all formats currently available on the Win32 clipboard.
1522 * Helper for set_mac_pasteboard_types_from_win32_clipboard.
1524 static UINT *get_clipboard_formats(UINT *size)
1526 UINT *ids;
1528 *size = 256;
1529 for (;;)
1531 if (!(ids = HeapAlloc(GetProcessHeap(), 0, *size * sizeof(*ids)))) return NULL;
1532 if (GetUpdatedClipboardFormats(ids, *size, size)) break;
1533 HeapFree(GetProcessHeap(), 0, ids);
1534 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return NULL;
1536 register_win32_formats(ids, *size);
1537 return ids;
1541 /**************************************************************************
1542 * set_mac_pasteboard_types_from_win32_clipboard
1544 static void set_mac_pasteboard_types_from_win32_clipboard(void)
1546 WINE_CLIPFORMAT *format;
1547 UINT count, i, *formats;
1549 if (!(formats = get_clipboard_formats(&count))) return;
1551 macdrv_clear_pasteboard();
1553 for (i = 0; i < count; i++)
1555 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1557 if (format->format_id != formats[i]) continue;
1558 TRACE("%s -> %s\n", debugstr_format(format->format_id), debugstr_cf(format->type));
1559 macdrv_set_pasteboard_data(format->type, NULL, clipboard_cocoa_window);
1563 HeapFree(GetProcessHeap(), 0, formats);
1564 return;
1568 /**************************************************************************
1569 * set_win32_clipboard_formats_from_mac_pasteboard
1571 static void set_win32_clipboard_formats_from_mac_pasteboard(void)
1573 WINE_CLIPFORMAT** formats;
1574 UINT count, i;
1576 formats = get_formats_for_pasteboard(NULL, &count);
1577 if (!formats)
1578 return;
1580 for (i = 0; i < count; i++)
1582 TRACE("adding format %s\n", debugstr_format(formats[i]->format_id));
1583 SetClipboardData(formats[i]->format_id, 0);
1586 HeapFree(GetProcessHeap(), 0, current_mac_formats);
1587 current_mac_formats = formats;
1588 nb_current_mac_formats = count;
1592 /**************************************************************************
1593 * render_format
1595 static void render_format(UINT id)
1597 unsigned int i;
1599 for (i = 0; i < nb_current_mac_formats; i++)
1601 CFDataRef pasteboard_data;
1603 if (current_mac_formats[i]->format_id != id) continue;
1605 pasteboard_data = macdrv_copy_pasteboard_data(NULL, current_mac_formats[i]->type);
1606 if (pasteboard_data)
1608 HANDLE handle = current_mac_formats[i]->import_func(pasteboard_data);
1609 CFRelease(pasteboard_data);
1610 if (handle) SetClipboardData(id, handle);
1611 break;
1617 /**************************************************************************
1618 * grab_win32_clipboard
1620 * Grab the Win32 clipboard when a Mac app has taken ownership of the
1621 * pasteboard, and fill it with the pasteboard data types.
1623 static BOOL grab_win32_clipboard(void)
1625 if (!OpenClipboard(clipboard_hwnd)) return FALSE;
1626 EmptyClipboard();
1627 is_clipboard_owner = TRUE;
1628 last_clipboard_update = GetTickCount64();
1629 set_win32_clipboard_formats_from_mac_pasteboard();
1630 CloseClipboard();
1631 return TRUE;
1635 /**************************************************************************
1636 * clipboard_wndproc
1638 * Window procedure for the clipboard manager.
1640 static LRESULT CALLBACK clipboard_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1642 switch (msg)
1644 case WM_NCCREATE:
1645 return TRUE;
1646 case WM_CLIPBOARDUPDATE:
1647 if (is_clipboard_owner) break; /* ignore our own changes */
1648 set_mac_pasteboard_types_from_win32_clipboard();
1649 break;
1650 case WM_RENDERFORMAT:
1651 render_format(wp);
1652 break;
1653 case WM_DESTROYCLIPBOARD:
1654 TRACE("WM_DESTROYCLIPBOARD: lost ownership\n");
1655 is_clipboard_owner = FALSE;
1656 break;
1658 return DefWindowProcW(hwnd, msg, wp, lp);
1662 /**************************************************************************
1663 * wait_clipboard_mutex
1665 * Make sure that there's only one clipboard thread per window station.
1667 static BOOL wait_clipboard_mutex(void)
1669 static const WCHAR prefix[] = {'_','_','w','i','n','e','_','c','l','i','p','b','o','a','r','d','_'};
1670 WCHAR buffer[MAX_PATH + sizeof(prefix) / sizeof(WCHAR)];
1671 HANDLE mutex;
1673 memcpy(buffer, prefix, sizeof(prefix));
1674 if (!GetUserObjectInformationW(GetProcessWindowStation(), UOI_NAME,
1675 buffer + sizeof(prefix) / sizeof(WCHAR),
1676 sizeof(buffer) - sizeof(prefix), NULL))
1678 ERR("failed to get winstation name\n");
1679 return FALSE;
1681 mutex = CreateMutexW(NULL, TRUE, buffer);
1682 if (GetLastError() == ERROR_ALREADY_EXISTS)
1684 TRACE("waiting for mutex %s\n", debugstr_w(buffer));
1685 WaitForSingleObject(mutex, INFINITE);
1687 return TRUE;
1691 /**************************************************************************
1692 * clipboard_thread
1694 * Thread running inside the desktop process to manage the clipboard
1696 static DWORD WINAPI clipboard_thread(void *arg)
1698 static const WCHAR clipboard_classname[] = {'_','_','w','i','n','e','_','c','l','i','p','b','o','a','r','d','_','m','a','n','a','g','e','r',0};
1699 WNDCLASSW class;
1700 struct macdrv_window_features wf;
1701 MSG msg;
1703 if (!wait_clipboard_mutex()) return 0;
1705 memset(&class, 0, sizeof(class));
1706 class.lpfnWndProc = clipboard_wndproc;
1707 class.lpszClassName = clipboard_classname;
1709 if (!RegisterClassW(&class) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
1711 ERR("could not register clipboard window class err %u\n", GetLastError());
1712 return 0;
1714 if (!(clipboard_hwnd = CreateWindowW(clipboard_classname, NULL, 0, 0, 0, 0, 0,
1715 HWND_MESSAGE, 0, 0, NULL)))
1717 ERR("failed to create clipboard window err %u\n", GetLastError());
1718 return 0;
1721 memset(&wf, 0, sizeof(wf));
1722 clipboard_cocoa_window = macdrv_create_cocoa_window(&wf, CGRectMake(100, 100, 100, 100), clipboard_hwnd,
1723 macdrv_init_thread_data()->queue);
1724 if (!clipboard_cocoa_window)
1726 ERR("failed to create clipboard Cocoa window\n");
1727 goto done;
1730 clipboard_thread_id = GetCurrentThreadId();
1731 AddClipboardFormatListener(clipboard_hwnd);
1732 register_builtin_formats();
1733 grab_win32_clipboard();
1735 TRACE("clipboard thread %04x running\n", GetCurrentThreadId());
1736 while (GetMessageW(&msg, NULL, 0, 0))
1737 DispatchMessageW(&msg);
1739 done:
1740 macdrv_destroy_cocoa_window(clipboard_cocoa_window);
1741 DestroyWindow(clipboard_hwnd);
1742 return 0;
1746 /**************************************************************************
1747 * Mac User Driver Clipboard Exports
1748 **************************************************************************/
1751 /**************************************************************************
1752 * MACDRV Private Clipboard Exports
1753 **************************************************************************/
1756 /**************************************************************************
1757 * query_pasteboard_data
1759 BOOL query_pasteboard_data(HWND hwnd, CFStringRef type)
1761 WINE_CLIPFORMAT *format;
1762 BOOL ret = FALSE;
1763 HANDLE handle;
1765 TRACE("win %p/%p type %s\n", hwnd, clipboard_cocoa_window, debugstr_cf(type));
1767 format = format_for_type(type);
1768 if (!format) return FALSE;
1770 if (!OpenClipboard(clipboard_hwnd))
1772 ERR("failed to open clipboard for %s\n", debugstr_cf(type));
1773 return FALSE;
1776 if ((handle = GetClipboardData(format->format_id)))
1778 CFDataRef data;
1780 TRACE("exporting %s %p\n", debugstr_format(format->format_id), handle);
1782 if ((data = format->export_func(handle)))
1784 ret = macdrv_set_pasteboard_data(format->type, data, clipboard_cocoa_window);
1785 CFRelease(data);
1789 CloseClipboard();
1791 return ret;
1795 /**************************************************************************
1796 * macdrv_init_clipboard
1798 void macdrv_init_clipboard(void)
1800 DWORD id;
1801 HANDLE handle = CreateThread(NULL, 0, clipboard_thread, NULL, 0, &id);
1803 if (handle) CloseHandle(handle);
1804 else ERR("failed to create clipboard thread\n");