dwrite: Break out basic IDWriteFont creation from requiring a logfont.
[wine/multimedia.git] / dlls / winemac.drv / clipboard.c
blobfe42023821146e38b67f33d52017518f24897198
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 struct
45 HWND hwnd_owner;
46 UINT flags;
47 } CLIPBOARDINFO, *LPCLIPBOARDINFO;
49 typedef HANDLE (*DRVIMPORTFUNC)(CFDataRef data);
50 typedef CFDataRef (*DRVEXPORTFUNC)(HANDLE data);
52 typedef struct _WINE_CLIPFORMAT
54 struct list entry;
55 UINT format_id;
56 CFStringRef type;
57 DRVIMPORTFUNC import_func;
58 DRVEXPORTFUNC export_func;
59 BOOL synthesized;
60 struct _WINE_CLIPFORMAT *natural_format;
61 } WINE_CLIPFORMAT;
64 /**************************************************************************
65 * Constants
66 **************************************************************************/
69 /**************************************************************************
70 * Forward Function Declarations
71 **************************************************************************/
73 static HANDLE import_clipboard_data(CFDataRef data);
74 static HANDLE import_bmp_to_bitmap(CFDataRef data);
75 static HANDLE import_bmp_to_dib(CFDataRef data);
76 static HANDLE import_enhmetafile(CFDataRef data);
77 static HANDLE import_enhmetafile_to_metafilepict(CFDataRef data);
78 static HANDLE import_metafilepict(CFDataRef data);
79 static HANDLE import_metafilepict_to_enhmetafile(CFDataRef data);
80 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data);
81 static HANDLE import_oemtext_to_text(CFDataRef data);
82 static HANDLE import_oemtext_to_unicodetext(CFDataRef data);
83 static HANDLE import_text_to_oemtext(CFDataRef data);
84 static HANDLE import_text_to_unicodetext(CFDataRef data);
85 static HANDLE import_unicodetext_to_oemtext(CFDataRef data);
86 static HANDLE import_unicodetext_to_text(CFDataRef data);
87 static HANDLE import_utf8_to_oemtext(CFDataRef data);
88 static HANDLE import_utf8_to_text(CFDataRef data);
89 static HANDLE import_utf8_to_unicodetext(CFDataRef data);
90 static HANDLE import_utf16_to_oemtext(CFDataRef data);
91 static HANDLE import_utf16_to_text(CFDataRef data);
92 static HANDLE import_utf16_to_unicodetext(CFDataRef data);
94 static CFDataRef export_clipboard_data(HANDLE data);
95 static CFDataRef export_bitmap_to_bmp(HANDLE data);
96 static CFDataRef export_dib_to_bmp(HANDLE data);
97 static CFDataRef export_enhmetafile(HANDLE data);
98 static CFDataRef export_hdrop_to_filenames(HANDLE data);
99 static CFDataRef export_metafilepict(HANDLE data);
100 static CFDataRef export_oemtext_to_utf8(HANDLE data);
101 static CFDataRef export_oemtext_to_utf16(HANDLE data);
102 static CFDataRef export_text_to_utf8(HANDLE data);
103 static CFDataRef export_text_to_utf16(HANDLE data);
104 static CFDataRef export_unicodetext_to_utf8(HANDLE data);
105 static CFDataRef export_unicodetext_to_utf16(HANDLE data);
108 /**************************************************************************
109 * Static Variables
110 **************************************************************************/
112 /* Clipboard formats */
113 static struct list format_list = LIST_INIT(format_list);
115 /* There are two naming schemes involved and we want to have a mapping between
116 them. There are Win32 clipboard format names and there are Mac pasteboard
117 types.
119 The Win32 standard clipboard formats don't have names, but they are associated
120 with Mac pasteboard types through the following tables, which are used to
121 initialize the format_list. Where possible, the standard clipboard formats
122 are mapped to predefined pasteboard type UTIs. Otherwise, we create Wine-
123 specific types of the form "org.winehq.builtin.<format>", where <format> is
124 the name of the symbolic constant for the format minus "CF_" and lowercased.
125 E.g. CF_BITMAP -> org.winehq.builtin.bitmap.
127 Win32 clipboard formats which originate in a Windows program may be registered
128 with an arbitrary name. We construct a Mac pasteboard type from these by
129 prepending "org.winehq.registered." to the registered name.
131 Likewise, Mac pasteboard types which originate in other apps may have
132 arbitrary type strings. We ignore these.
134 Summary:
135 Win32 clipboard format names:
136 <none> standard clipboard format; maps via
137 format_list to either a predefined Mac UTI
138 or org.winehq.builtin.<format>.
139 <other> name registered within Win32 land; maps to
140 org.winehq.registered.<other>
141 Mac pasteboard type names:
142 org.winehq.builtin.<format ID> representation of Win32 standard clipboard
143 format for which there was no corresponding
144 predefined Mac UTI; maps via format_list
145 org.winehq.registered.<format name> representation of Win32 registered
146 clipboard format name; maps to <format name>
147 <other> Mac pasteboard type originating with system
148 or other apps; either maps via format_list
149 to a standard clipboard format or ignored
152 static const struct
154 UINT id;
155 CFStringRef type;
156 DRVIMPORTFUNC import;
157 DRVEXPORTFUNC export;
158 BOOL synthesized;
159 } builtin_format_ids[] =
161 { CF_DIBV5, CFSTR("org.winehq.builtin.dibv5"), import_clipboard_data, export_clipboard_data, FALSE },
162 { CF_DIF, CFSTR("org.winehq.builtin.dif"), import_clipboard_data, export_clipboard_data, FALSE },
163 { CF_DSPBITMAP, CFSTR("org.winehq.builtin.dspbitmap"), import_clipboard_data, export_clipboard_data, FALSE },
164 { CF_DSPENHMETAFILE, CFSTR("org.winehq.builtin.dspenhmetafile"), import_clipboard_data, export_clipboard_data, FALSE },
165 { CF_DSPMETAFILEPICT, CFSTR("org.winehq.builtin.dspmetafilepict"), import_clipboard_data, export_clipboard_data, FALSE },
166 { CF_DSPTEXT, CFSTR("org.winehq.builtin.dsptext"), import_clipboard_data, export_clipboard_data, FALSE },
167 { CF_LOCALE, CFSTR("org.winehq.builtin.locale"), import_clipboard_data, export_clipboard_data, FALSE },
168 { CF_OWNERDISPLAY, CFSTR("org.winehq.builtin.ownerdisplay"), import_clipboard_data, export_clipboard_data, FALSE },
169 { CF_PALETTE, CFSTR("org.winehq.builtin.palette"), import_clipboard_data, export_clipboard_data, FALSE },
170 { CF_PENDATA, CFSTR("org.winehq.builtin.pendata"), import_clipboard_data, export_clipboard_data, FALSE },
171 { CF_RIFF, CFSTR("org.winehq.builtin.riff"), import_clipboard_data, export_clipboard_data, FALSE },
172 { CF_SYLK, CFSTR("org.winehq.builtin.sylk"), import_clipboard_data, export_clipboard_data, FALSE },
173 { CF_TIFF, CFSTR("public.tiff"), import_clipboard_data, export_clipboard_data, FALSE },
174 { CF_WAVE, CFSTR("com.microsoft.waveform-audio"), import_clipboard_data, export_clipboard_data, FALSE },
176 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.unicodetext"), import_clipboard_data, export_clipboard_data, FALSE },
177 { CF_TEXT, CFSTR("org.winehq.builtin.unicodetext"), import_unicodetext_to_text, NULL, TRUE },
178 { CF_OEMTEXT, CFSTR("org.winehq.builtin.unicodetext"), import_unicodetext_to_oemtext, NULL, TRUE },
180 { CF_TEXT, CFSTR("org.winehq.builtin.text"), import_clipboard_data, export_clipboard_data, FALSE },
181 { CF_OEMTEXT, CFSTR("org.winehq.builtin.text"), import_text_to_oemtext, NULL, TRUE },
182 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.text"), import_text_to_unicodetext, NULL, TRUE },
184 { CF_OEMTEXT, CFSTR("org.winehq.builtin.oemtext"), import_clipboard_data, export_clipboard_data, FALSE },
185 { CF_TEXT, CFSTR("org.winehq.builtin.oemtext"), import_oemtext_to_text, NULL, TRUE },
186 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.oemtext"), import_oemtext_to_unicodetext, NULL, TRUE },
188 { CF_TEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_text, export_text_to_utf8, TRUE },
189 { CF_OEMTEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_oemtext, export_oemtext_to_utf8, TRUE },
190 { CF_UNICODETEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_unicodetext, export_unicodetext_to_utf8, TRUE },
192 { CF_TEXT, CFSTR("public.utf16-plain-text"), import_utf16_to_text, export_text_to_utf16, TRUE },
193 { CF_OEMTEXT, CFSTR("public.utf16-plain-text"), import_utf16_to_oemtext, export_oemtext_to_utf16, TRUE },
194 { CF_UNICODETEXT, CFSTR("public.utf16-plain-text"), import_utf16_to_unicodetext, export_unicodetext_to_utf16,TRUE },
196 { CF_DIB, CFSTR("org.winehq.builtin.dib"), import_clipboard_data, export_clipboard_data, FALSE },
197 { CF_DIB, CFSTR("com.microsoft.bmp"), import_bmp_to_dib, export_dib_to_bmp, TRUE },
199 { CF_BITMAP, CFSTR("org.winehq.builtin.bitmap"), import_bmp_to_bitmap, export_bitmap_to_bmp, FALSE },
200 { CF_BITMAP, CFSTR("com.microsoft.bmp"), import_bmp_to_bitmap, export_bitmap_to_bmp, TRUE },
202 { CF_HDROP, CFSTR("org.winehq.builtin.hdrop"), import_clipboard_data, export_clipboard_data, FALSE },
203 { CF_HDROP, CFSTR("NSFilenamesPboardType"), import_nsfilenames_to_hdrop, export_hdrop_to_filenames, TRUE },
205 { CF_ENHMETAFILE, CFSTR("org.winehq.builtin.enhmetafile"), import_enhmetafile, export_enhmetafile, FALSE },
206 { CF_METAFILEPICT, CFSTR("org.winehq.builtin.enhmetafile"), import_enhmetafile_to_metafilepict, NULL, TRUE },
208 { CF_METAFILEPICT, CFSTR("org.winehq.builtin.metafilepict"), import_metafilepict, export_metafilepict, FALSE },
209 { CF_ENHMETAFILE, CFSTR("org.winehq.builtin.metafilepict"), import_metafilepict_to_enhmetafile, NULL, TRUE },
212 static const WCHAR wszRichTextFormat[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
213 static const WCHAR wszGIF[] = {'G','I','F',0};
214 static const WCHAR wszJFIF[] = {'J','F','I','F',0};
215 static const WCHAR wszPNG[] = {'P','N','G',0};
216 static const WCHAR wszHTMLFormat[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
217 static const struct
219 LPCWSTR name;
220 CFStringRef type;
221 DRVIMPORTFUNC import;
222 DRVEXPORTFUNC export;
223 } builtin_format_names[] =
225 { wszRichTextFormat, CFSTR("public.rtf"), import_clipboard_data, export_clipboard_data },
226 { wszGIF, CFSTR("com.compuserve.gif"), import_clipboard_data, export_clipboard_data },
227 { wszJFIF, CFSTR("public.jpeg"), import_clipboard_data, export_clipboard_data },
228 { wszPNG, CFSTR("public.png"), import_clipboard_data, export_clipboard_data },
229 { wszHTMLFormat, CFSTR("public.html"), import_clipboard_data, export_clipboard_data },
230 { CFSTR_SHELLURLW, CFSTR("public.url"), import_utf8_to_text, export_text_to_utf8 },
233 /* The prefix prepended to a Win32 clipboard format name to make a Mac pasteboard type. */
234 static const CFStringRef registered_name_type_prefix = CFSTR("org.winehq.registered.");
237 /**************************************************************************
238 * Internal Clipboard implementation methods
239 **************************************************************************/
242 * format_list functions
245 /**************************************************************************
246 * debugstr_format
248 const char *debugstr_format(UINT id)
250 WCHAR buffer[256];
252 if (GetClipboardFormatNameW(id, buffer, 256))
253 return wine_dbg_sprintf("0x%04x %s", id, debugstr_w(buffer));
255 switch (id)
257 #define BUILTIN(id) case id: return #id;
258 BUILTIN(CF_TEXT)
259 BUILTIN(CF_BITMAP)
260 BUILTIN(CF_METAFILEPICT)
261 BUILTIN(CF_SYLK)
262 BUILTIN(CF_DIF)
263 BUILTIN(CF_TIFF)
264 BUILTIN(CF_OEMTEXT)
265 BUILTIN(CF_DIB)
266 BUILTIN(CF_PALETTE)
267 BUILTIN(CF_PENDATA)
268 BUILTIN(CF_RIFF)
269 BUILTIN(CF_WAVE)
270 BUILTIN(CF_UNICODETEXT)
271 BUILTIN(CF_ENHMETAFILE)
272 BUILTIN(CF_HDROP)
273 BUILTIN(CF_LOCALE)
274 BUILTIN(CF_DIBV5)
275 BUILTIN(CF_OWNERDISPLAY)
276 BUILTIN(CF_DSPTEXT)
277 BUILTIN(CF_DSPBITMAP)
278 BUILTIN(CF_DSPMETAFILEPICT)
279 BUILTIN(CF_DSPENHMETAFILE)
280 #undef BUILTIN
281 default: return wine_dbg_sprintf("0x%04x", id);
286 /**************************************************************************
287 * insert_clipboard_format
289 static WINE_CLIPFORMAT *insert_clipboard_format(UINT id, CFStringRef type)
291 WINE_CLIPFORMAT *format;
293 format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format));
295 if (format == NULL)
297 WARN("No more memory for a new format!\n");
298 return NULL;
300 format->format_id = id;
301 format->import_func = import_clipboard_data;
302 format->export_func = export_clipboard_data;
303 format->synthesized = FALSE;
304 format->natural_format = NULL;
306 if (type)
307 format->type = CFStringCreateCopy(NULL, type);
308 else
310 WCHAR buffer[256];
312 if (!GetClipboardFormatNameW(format->format_id, buffer, sizeof(buffer) / sizeof(buffer[0])))
314 WARN("failed to get name for format %s; error 0x%08x\n", debugstr_format(format->format_id), GetLastError());
315 HeapFree(GetProcessHeap(), 0, format);
316 return NULL;
319 format->type = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%S"),
320 registered_name_type_prefix, buffer);
323 list_add_tail(&format_list, &format->entry);
325 TRACE("Registering format %s type %s\n", debugstr_format(format->format_id),
326 debugstr_cf(format->type));
328 return format;
332 /**************************************************************************
333 * register_format
335 * Register a custom Mac clipboard format.
337 static WINE_CLIPFORMAT* register_format(UINT id, CFStringRef type)
339 WINE_CLIPFORMAT *format;
341 /* walk format chain to see if it's already registered */
342 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
343 if (format->format_id == id) return format;
345 return insert_clipboard_format(id, type);
349 /**************************************************************************
350 * format_for_type
352 static WINE_CLIPFORMAT* format_for_type(WINE_CLIPFORMAT *current, CFStringRef type)
354 struct list *ptr = current ? &current->entry : &format_list;
355 WINE_CLIPFORMAT *format = NULL;
357 TRACE("current %p/%s type %s\n", current, debugstr_format(current ? current->format_id : 0), debugstr_cf(type));
359 while ((ptr = list_next(&format_list, ptr)))
361 format = LIST_ENTRY(ptr, WINE_CLIPFORMAT, entry);
362 if (CFEqual(format->type, type))
363 goto done;
366 format = NULL;
367 if (!current)
369 if (CFStringHasPrefix(type, CFSTR("org.winehq.builtin.")))
371 ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
372 debugstr_cf(type));
374 else if (CFStringHasPrefix(type, registered_name_type_prefix))
376 LPWSTR name;
377 int len = CFStringGetLength(type) - CFStringGetLength(registered_name_type_prefix);
379 name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
380 CFStringGetCharacters(type, CFRangeMake(CFStringGetLength(registered_name_type_prefix), len),
381 (UniChar*)name);
382 name[len] = 0;
384 format = register_format(RegisterClipboardFormatW(name), type);
385 if (!format)
386 ERR("Failed to register format for type %s name %s\n", debugstr_cf(type), debugstr_w(name));
388 HeapFree(GetProcessHeap(), 0, name);
392 done:
393 TRACE(" -> %p/%s\n", format, debugstr_format(format ? format->format_id : 0));
394 return format;
398 /**************************************************************************
399 * natural_format_for_format
401 * Find the "natural" format for this format_id (the one which isn't
402 * synthesized from another type).
404 static WINE_CLIPFORMAT* natural_format_for_format(UINT format_id)
406 WINE_CLIPFORMAT *format;
408 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
409 if (format->format_id == format_id && !format->synthesized) break;
411 if (&format->entry == &format_list)
412 format = NULL;
414 TRACE("%s -> %p/%s\n", debugstr_format(format_id), format, debugstr_cf(format ? format->type : NULL));
415 return format;
419 /**************************************************************************
420 * convert_text
422 * Convert string data between code pages or to/from wide characters. The
423 * special value of (UINT)-1 for a code page indicates to use wide
424 * characters.
426 static HANDLE convert_text(const void *src, int src_len, UINT src_cp, UINT dest_cp)
428 HANDLE ret = NULL;
429 const WCHAR *wstr;
430 int wstr_len;
431 HANDLE handle;
432 char *p;
434 if (src_cp == (UINT)-1)
436 wstr = src;
437 wstr_len = src_len / sizeof(WCHAR);
439 else
441 WCHAR *temp;
443 wstr_len = MultiByteToWideChar(src_cp, 0, src, src_len, NULL, 0);
444 if (!src_len || ((const char*)src)[src_len - 1]) wstr_len += 1;
445 temp = HeapAlloc(GetProcessHeap(), 0, wstr_len * sizeof(WCHAR));
446 MultiByteToWideChar(src_cp, 0, src, src_len, temp, wstr_len);
447 temp[wstr_len - 1] = 0;
448 wstr = temp;
451 if (dest_cp == (UINT)-1)
453 handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, wstr_len * sizeof(WCHAR));
454 if (handle && (p = GlobalLock(handle)))
456 memcpy(p, wstr, wstr_len * sizeof(WCHAR));
457 GlobalUnlock(handle);
458 ret = handle;
461 else
463 INT len;
465 len = WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, NULL, 0, NULL, NULL);
466 if (!wstr_len || wstr[wstr_len - 1]) len += 1;
467 handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
469 if (handle && (p = GlobalLock(handle)))
471 WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, p, len, NULL, NULL);
472 p[len - 1] = 0;
473 GlobalUnlock(handle);
474 ret = handle;
478 return ret;
482 /**************************************************************************
483 * convert_unicodetext_to_codepage
485 static HANDLE convert_unicodetext_to_codepage(HANDLE unicode_handle, UINT cp)
487 LPWSTR unicode_string = GlobalLock(unicode_handle);
488 HANDLE ret = NULL;
490 if (unicode_string)
492 ret = convert_text(unicode_string, GlobalSize(unicode_handle), -1, cp);
493 GlobalUnlock(unicode_handle);
496 return ret;
500 /***********************************************************************
501 * bitmap_info_size
503 * Return the size of the bitmap info structure including color table.
505 static int bitmap_info_size(const BITMAPINFO *info, WORD coloruse)
507 unsigned int colors, size, masks = 0;
509 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
511 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER*)info;
512 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
513 return sizeof(BITMAPCOREHEADER) + colors *
514 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
516 else /* assume BITMAPINFOHEADER */
518 colors = info->bmiHeader.biClrUsed;
519 if (!colors && (info->bmiHeader.biBitCount <= 8))
520 colors = 1 << info->bmiHeader.biBitCount;
521 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
522 size = max(info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD));
523 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
528 /***********************************************************************
529 * create_dib_from_bitmap
531 * Allocates a packed DIB and copies the bitmap data into it.
533 static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp)
535 BITMAP bmp;
536 HDC hdc;
537 HGLOBAL hPackedDIB;
538 LPBYTE pPackedDIB;
539 LPBITMAPINFOHEADER pbmiHeader;
540 unsigned int cDataSize, cPackedSize, OffsetBits;
541 int nLinesCopied;
543 if (!GetObjectW(hBmp, sizeof(bmp), &bmp)) return 0;
546 * A packed DIB contains a BITMAPINFO structure followed immediately by
547 * an optional color palette and the pixel data.
550 /* Calculate the size of the packed DIB */
551 cDataSize = abs(bmp.bmHeight) * (((bmp.bmWidth * bmp.bmBitsPixel + 31) / 8) & ~3);
552 cPackedSize = sizeof(BITMAPINFOHEADER)
553 + ((bmp.bmBitsPixel <= 8) ? (sizeof(RGBQUAD) * (1 << bmp.bmBitsPixel)) : 0)
554 + cDataSize;
555 /* Get the offset to the bits */
556 OffsetBits = cPackedSize - cDataSize;
558 /* Allocate the packed DIB */
559 TRACE("\tAllocating packed DIB of size %d\n", cPackedSize);
560 hPackedDIB = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cPackedSize);
561 if (!hPackedDIB)
563 WARN("Could not allocate packed DIB!\n");
564 return 0;
567 /* A packed DIB starts with a BITMAPINFOHEADER */
568 pPackedDIB = GlobalLock(hPackedDIB);
569 pbmiHeader = (LPBITMAPINFOHEADER)pPackedDIB;
571 /* Init the BITMAPINFOHEADER */
572 pbmiHeader->biSize = sizeof(BITMAPINFOHEADER);
573 pbmiHeader->biWidth = bmp.bmWidth;
574 pbmiHeader->biHeight = bmp.bmHeight;
575 pbmiHeader->biPlanes = 1;
576 pbmiHeader->biBitCount = bmp.bmBitsPixel;
577 pbmiHeader->biCompression = BI_RGB;
578 pbmiHeader->biSizeImage = 0;
579 pbmiHeader->biXPelsPerMeter = pbmiHeader->biYPelsPerMeter = 0;
580 pbmiHeader->biClrUsed = 0;
581 pbmiHeader->biClrImportant = 0;
583 /* Retrieve the DIB bits from the bitmap and fill in the
584 * DIB color table if present */
585 hdc = GetDC(0);
586 nLinesCopied = GetDIBits(hdc, /* Handle to device context */
587 hBmp, /* Handle to bitmap */
588 0, /* First scan line to set in dest bitmap */
589 bmp.bmHeight, /* Number of scan lines to copy */
590 pPackedDIB + OffsetBits, /* [out] Address of array for bitmap bits */
591 (LPBITMAPINFO) pbmiHeader, /* [out] Address of BITMAPINFO structure */
592 0); /* RGB or palette index */
593 GlobalUnlock(hPackedDIB);
594 ReleaseDC(0, hdc);
596 /* Cleanup if GetDIBits failed */
597 if (nLinesCopied != bmp.bmHeight)
599 TRACE("\tGetDIBits returned %d. Actual lines=%d\n", nLinesCopied, bmp.bmHeight);
600 GlobalFree(hPackedDIB);
601 hPackedDIB = 0;
603 return hPackedDIB;
607 /**************************************************************************
608 * import_clipboard_data
610 * Generic import clipboard data routine.
612 static HANDLE import_clipboard_data(CFDataRef data)
614 HANDLE data_handle = NULL;
616 size_t len = CFDataGetLength(data);
617 if (len)
619 LPVOID p;
621 /* Turn on the DDESHARE flag to enable shared 32 bit memory */
622 data_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
623 if (!data_handle)
624 return NULL;
626 if ((p = GlobalLock(data_handle)))
628 memcpy(p, CFDataGetBytePtr(data), len);
629 GlobalUnlock(data_handle);
631 else
633 GlobalFree(data_handle);
634 data_handle = NULL;
638 return data_handle;
642 /**************************************************************************
643 * import_bmp_to_bitmap
645 * Import BMP data, converting to CF_BITMAP format.
647 static HANDLE import_bmp_to_bitmap(CFDataRef data)
649 HANDLE ret = 0;
650 HANDLE dib = import_bmp_to_dib(data);
651 BITMAPINFO *bmi;
653 if (dib && (bmi = GlobalLock(dib)))
655 HDC hdc;
656 unsigned int offset;
658 hdc = GetDC(NULL);
660 offset = bitmap_info_size(bmi, DIB_RGB_COLORS);
662 ret = CreateDIBitmap(hdc, &bmi->bmiHeader, CBM_INIT, (LPBYTE)bmi + offset,
663 bmi, DIB_RGB_COLORS);
665 GlobalUnlock(dib);
666 ReleaseDC(NULL, hdc);
669 GlobalFree(dib);
670 return ret;
674 /**************************************************************************
675 * import_bmp_to_dib
677 * Import BMP data, converting to CF_DIB format. This just entails
678 * stripping the BMP file format header.
680 static HANDLE import_bmp_to_dib(CFDataRef data)
682 HANDLE ret = 0;
683 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)CFDataGetBytePtr(data);
684 CFIndex len = CFDataGetLength(data);
686 if (len >= sizeof(*bfh) + sizeof(BITMAPCOREHEADER) &&
687 bfh->bfType == 0x4d42 /* "BM" */)
689 BITMAPINFO *bmi = (BITMAPINFO*)(bfh + 1);
690 BYTE* p;
692 len -= sizeof(*bfh);
693 ret = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
694 if (!ret || !(p = GlobalLock(ret)))
696 GlobalFree(ret);
697 return 0;
700 memcpy(p, bmi, len);
701 GlobalUnlock(ret);
704 return ret;
708 /**************************************************************************
709 * import_enhmetafile
711 * Import enhanced metafile data, converting it to CF_ENHMETAFILE.
713 static HANDLE import_enhmetafile(CFDataRef data)
715 HANDLE ret = 0;
716 CFIndex len = CFDataGetLength(data);
718 TRACE("data %s\n", debugstr_cf(data));
720 if (len)
721 ret = SetEnhMetaFileBits(len, (const BYTE*)CFDataGetBytePtr(data));
723 return ret;
727 /**************************************************************************
728 * import_enhmetafile_to_metafilepict
730 * Import enhanced metafile data, converting it to CF_METAFILEPICT.
732 static HANDLE import_enhmetafile_to_metafilepict(CFDataRef data)
734 HANDLE ret = 0, hmf;
735 HANDLE hemf;
736 METAFILEPICT *mfp;
738 if ((hmf = GlobalAlloc(0, sizeof(*mfp))) && (hemf = import_enhmetafile(data)))
740 ENHMETAHEADER header;
741 HDC hdc = CreateCompatibleDC(0);
742 unsigned int size = GetWinMetaFileBits(hemf, 0, NULL, MM_ISOTROPIC, hdc);
743 BYTE *bytes;
745 bytes = HeapAlloc(GetProcessHeap(), 0, size);
746 if (bytes && GetEnhMetaFileHeader(hemf, sizeof(header), &header) &&
747 GetWinMetaFileBits(hemf, size, bytes, MM_ISOTROPIC, hdc))
749 mfp = GlobalLock(hmf);
750 mfp->mm = MM_ISOTROPIC;
751 mfp->xExt = header.rclFrame.right - header.rclFrame.left;
752 mfp->yExt = header.rclFrame.bottom - header.rclFrame.top;
753 mfp->hMF = SetMetaFileBitsEx(size, bytes);
754 GlobalUnlock(hmf);
756 ret = hmf;
759 if (hdc) DeleteDC(hdc);
760 HeapFree(GetProcessHeap(), 0, bytes);
761 DeleteEnhMetaFile(hemf);
764 if (!ret) GlobalFree(hmf);
765 return ret;
769 /**************************************************************************
770 * import_metafilepict
772 * Import metafile picture data, converting it to CF_METAFILEPICT.
774 static HANDLE import_metafilepict(CFDataRef data)
776 HANDLE ret = 0;
777 CFIndex len = CFDataGetLength(data);
778 METAFILEPICT *mfp;
780 TRACE("data %s\n", debugstr_cf(data));
782 if (len >= sizeof(*mfp) && (ret = GlobalAlloc(0, sizeof(*mfp))))
784 const BYTE *bytes = (const BYTE*)CFDataGetBytePtr(data);
786 mfp = GlobalLock(ret);
787 memcpy(mfp, bytes, sizeof(*mfp));
788 mfp->hMF = SetMetaFileBitsEx(len - sizeof(*mfp), bytes + sizeof(*mfp));
789 GlobalUnlock(ret);
792 return ret;
796 /**************************************************************************
797 * import_metafilepict_to_enhmetafile
799 * Import metafile picture data, converting it to CF_ENHMETAFILE.
801 static HANDLE import_metafilepict_to_enhmetafile(CFDataRef data)
803 HANDLE ret = 0;
804 CFIndex len = CFDataGetLength(data);
805 const METAFILEPICT *mfp;
807 TRACE("data %s\n", debugstr_cf(data));
809 if (len >= sizeof(*mfp))
811 mfp = (const METAFILEPICT*)CFDataGetBytePtr(data);
812 ret = SetWinMetaFileBits(len - sizeof(*mfp), (const BYTE*)(mfp + 1), NULL, mfp);
815 return ret;
819 /**************************************************************************
820 * import_nsfilenames_to_hdrop
822 * Import NSFilenamesPboardType data, converting the property-list-
823 * serialized array of path strings to CF_HDROP.
825 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data)
827 HDROP hdrop = NULL;
828 CFArrayRef names;
829 CFIndex count, i;
830 size_t len;
831 char *buffer = NULL;
832 WCHAR **paths = NULL;
833 DROPFILES* dropfiles;
834 UniChar* p;
836 TRACE("data %s\n", debugstr_cf(data));
838 names = (CFArrayRef)CFPropertyListCreateWithData(NULL, data, kCFPropertyListImmutable,
839 NULL, NULL);
840 if (!names || CFGetTypeID(names) != CFArrayGetTypeID())
842 WARN("failed to interpret data as a CFArray\n");
843 goto done;
846 count = CFArrayGetCount(names);
848 len = 0;
849 for (i = 0; i < count; i++)
851 CFIndex this_len;
852 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
853 TRACE(" %s\n", debugstr_cf(name));
854 if (CFGetTypeID(name) != CFStringGetTypeID())
856 WARN("non-string in array\n");
857 goto done;
860 this_len = CFStringGetMaximumSizeOfFileSystemRepresentation(name);
861 if (this_len > len)
862 len = this_len;
865 buffer = HeapAlloc(GetProcessHeap(), 0, len);
866 if (!buffer)
868 WARN("failed to allocate buffer for file-system representations\n");
869 goto done;
872 paths = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(paths[0]));
873 if (!paths)
875 WARN("failed to allocate array of DOS paths\n");
876 goto done;
879 for (i = 0; i < count; i++)
881 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
882 if (!CFStringGetFileSystemRepresentation(name, buffer, len))
884 WARN("failed to get file-system representation for %s\n", debugstr_cf(name));
885 goto done;
887 paths[i] = wine_get_dos_file_name(buffer);
888 if (!paths[i])
890 WARN("failed to get DOS path for %s\n", debugstr_a(buffer));
891 goto done;
895 len = 1; /* for the terminating null */
896 for (i = 0; i < count; i++)
897 len += strlenW(paths[i]) + 1;
899 hdrop = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(*dropfiles) + len * sizeof(WCHAR));
900 if (!hdrop || !(dropfiles = GlobalLock(hdrop)))
902 WARN("failed to allocate HDROP\n");
903 GlobalFree(hdrop);
904 hdrop = NULL;
905 goto done;
908 dropfiles->pFiles = sizeof(*dropfiles);
909 dropfiles->pt.x = 0;
910 dropfiles->pt.y = 0;
911 dropfiles->fNC = FALSE;
912 dropfiles->fWide = TRUE;
914 p = (WCHAR*)(dropfiles + 1);
915 for (i = 0; i < count; i++)
917 strcpyW(p, paths[i]);
918 p += strlenW(p) + 1;
920 *p = 0;
922 GlobalUnlock(hdrop);
924 done:
925 if (paths)
927 for (i = 0; i < count; i++)
928 HeapFree(GetProcessHeap(), 0, paths[i]);
929 HeapFree(GetProcessHeap(), 0, paths);
931 HeapFree(GetProcessHeap(), 0, buffer);
932 if (names) CFRelease(names);
933 return hdrop;
937 /**************************************************************************
938 * import_oemtext_to_text
940 * Import CF_OEMTEXT data, converting the string to CF_TEXT.
942 static HANDLE import_oemtext_to_text(CFDataRef data)
944 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, CP_ACP);
948 /**************************************************************************
949 * import_oemtext_to_unicodetext
951 * Import CF_OEMTEXT data, converting the string to CF_UNICODETEXT.
953 static HANDLE import_oemtext_to_unicodetext(CFDataRef data)
955 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, -1);
959 /**************************************************************************
960 * import_text_to_oemtext
962 * Import CF_TEXT data, converting the string to CF_OEMTEXT.
964 static HANDLE import_text_to_oemtext(CFDataRef data)
966 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, CP_OEMCP);
970 /**************************************************************************
971 * import_text_to_unicodetext
973 * Import CF_TEXT data, converting the string to CF_UNICODETEXT.
975 static HANDLE import_text_to_unicodetext(CFDataRef data)
977 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, -1);
981 /**************************************************************************
982 * import_unicodetext_to_oemtext
984 * Import a CF_UNICODETEXT string, converting the string to CF_OEMTEXT.
986 static HANDLE import_unicodetext_to_oemtext(CFDataRef data)
988 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_OEMCP);
992 /**************************************************************************
993 * import_unicodetext_to_text
995 * Import a CF_UNICODETEXT string, converting the string to CF_TEXT.
997 static HANDLE import_unicodetext_to_text(CFDataRef data)
999 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_ACP);
1003 /**************************************************************************
1004 * import_utf8_to_oemtext
1006 * Import a UTF-8 string, converting the string to CF_OEMTEXT.
1008 static HANDLE import_utf8_to_oemtext(CFDataRef data)
1010 HANDLE unicode_handle = import_utf8_to_unicodetext(data);
1011 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_OEMCP);
1013 GlobalFree(unicode_handle);
1014 return ret;
1018 /**************************************************************************
1019 * import_utf8_to_text
1021 * Import a UTF-8 string, converting the string to CF_TEXT.
1023 static HANDLE import_utf8_to_text(CFDataRef data)
1025 HANDLE unicode_handle = import_utf8_to_unicodetext(data);
1026 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_ACP);
1028 GlobalFree(unicode_handle);
1029 return ret;
1033 /**************************************************************************
1034 * import_utf8_to_unicodetext
1036 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
1038 static HANDLE import_utf8_to_unicodetext(CFDataRef data)
1040 const BYTE *src;
1041 unsigned long src_len;
1042 unsigned long new_lines = 0;
1043 LPSTR dst;
1044 unsigned long i, j;
1045 HANDLE unicode_handle = NULL;
1047 src = CFDataGetBytePtr(data);
1048 src_len = CFDataGetLength(data);
1049 for (i = 0; i < src_len; i++)
1051 if (src[i] == '\n')
1052 new_lines++;
1055 if ((dst = HeapAlloc(GetProcessHeap(), 0, src_len + new_lines + 1)))
1057 UINT count;
1059 for (i = 0, j = 0; i < src_len; i++)
1061 if (src[i] == '\n')
1062 dst[j++] = '\r';
1064 dst[j++] = src[i];
1066 dst[j] = 0;
1068 count = MultiByteToWideChar(CP_UTF8, 0, dst, -1, NULL, 0);
1069 unicode_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, count * sizeof(WCHAR));
1071 if (unicode_handle)
1073 WCHAR *textW = GlobalLock(unicode_handle);
1074 MultiByteToWideChar(CP_UTF8, 0, dst, -1, textW, count);
1075 GlobalUnlock(unicode_handle);
1078 HeapFree(GetProcessHeap(), 0, dst);
1081 return unicode_handle;
1085 /**************************************************************************
1086 * import_utf16_to_oemtext
1088 * Import a UTF-16 string, converting the string to CF_OEMTEXT.
1090 static HANDLE import_utf16_to_oemtext(CFDataRef data)
1092 HANDLE unicode_handle = import_utf16_to_unicodetext(data);
1093 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_OEMCP);
1095 GlobalFree(unicode_handle);
1096 return ret;
1100 /**************************************************************************
1101 * import_utf16_to_text
1103 * Import a UTF-16 string, converting the string to CF_TEXT.
1105 static HANDLE import_utf16_to_text(CFDataRef data)
1107 HANDLE unicode_handle = import_utf16_to_unicodetext(data);
1108 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_ACP);
1110 GlobalFree(unicode_handle);
1111 return ret;
1115 /**************************************************************************
1116 * import_utf16_to_unicodetext
1118 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
1120 static HANDLE import_utf16_to_unicodetext(CFDataRef data)
1122 const WCHAR *src;
1123 unsigned long src_len;
1124 unsigned long new_lines = 0;
1125 LPWSTR dst;
1126 unsigned long i, j;
1127 HANDLE unicode_handle;
1129 src = (const WCHAR *)CFDataGetBytePtr(data);
1130 src_len = CFDataGetLength(data) / sizeof(WCHAR);
1131 for (i = 0; i < src_len; i++)
1133 if (src[i] == '\n')
1134 new_lines++;
1137 if ((unicode_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (src_len + new_lines + 1) * sizeof(WCHAR))))
1139 dst = GlobalLock(unicode_handle);
1141 for (i = 0, j = 0; i < src_len; i++)
1143 if (src[i] == '\n')
1144 dst[j++] = '\r';
1146 dst[j++] = src[i];
1148 dst[j] = 0;
1150 GlobalUnlock(unicode_handle);
1153 return unicode_handle;
1157 /**************************************************************************
1158 * export_clipboard_data
1160 * Generic export clipboard data routine.
1162 static CFDataRef export_clipboard_data(HANDLE data)
1164 CFDataRef ret;
1165 UINT len;
1166 LPVOID src;
1168 len = GlobalSize(data);
1169 src = GlobalLock(data);
1170 if (!src) return NULL;
1172 ret = CFDataCreate(NULL, src, len);
1173 GlobalUnlock(data);
1175 return ret;
1179 /**************************************************************************
1180 * export_bitmap_to_bmp
1182 * Export CF_BITMAP to BMP file format.
1184 static CFDataRef export_bitmap_to_bmp(HANDLE data)
1186 CFDataRef ret = NULL;
1187 HGLOBAL dib;
1189 dib = create_dib_from_bitmap(data);
1190 if (dib)
1192 ret = export_dib_to_bmp(dib);
1193 GlobalFree(dib);
1196 return ret;
1200 /**************************************************************************
1201 * export_codepage_to_utf8
1203 * Export string data in a specified codepage to UTF-8.
1205 static CFDataRef export_codepage_to_utf8(HANDLE data, UINT cp)
1207 CFDataRef ret = NULL;
1208 const char* str;
1210 if ((str = GlobalLock(data)))
1212 HANDLE unicode = convert_text(str, GlobalSize(data), cp, -1);
1214 ret = export_unicodetext_to_utf8(unicode);
1216 GlobalFree(unicode);
1217 GlobalUnlock(data);
1220 return ret;
1224 /**************************************************************************
1225 * export_codepage_to_utf16
1227 * Export string data in a specified codepage to UTF-16.
1229 static CFDataRef export_codepage_to_utf16(HANDLE data, UINT cp)
1231 CFDataRef ret = NULL;
1232 const char* str;
1234 if ((str = GlobalLock(data)))
1236 HANDLE unicode = convert_text(str, GlobalSize(data), cp, -1);
1238 ret = export_unicodetext_to_utf16(unicode);
1240 GlobalFree(unicode);
1241 GlobalUnlock(data);
1244 return ret;
1248 /**************************************************************************
1249 * export_dib_to_bmp
1251 * Export CF_DIB to BMP file format. This just entails prepending a BMP
1252 * file format header to the data.
1254 static CFDataRef export_dib_to_bmp(HANDLE data)
1256 CFMutableDataRef ret = NULL;
1257 BYTE *dibdata;
1258 CFIndex len;
1259 BITMAPFILEHEADER bfh;
1261 dibdata = GlobalLock(data);
1262 if (!dibdata)
1263 return NULL;
1265 len = sizeof(bfh) + GlobalSize(data);
1266 ret = CFDataCreateMutable(NULL, len);
1267 if (ret)
1269 bfh.bfType = 0x4d42; /* "BM" */
1270 bfh.bfSize = len;
1271 bfh.bfReserved1 = 0;
1272 bfh.bfReserved2 = 0;
1273 bfh.bfOffBits = sizeof(bfh) + bitmap_info_size((BITMAPINFO*)dibdata, DIB_RGB_COLORS);
1274 CFDataAppendBytes(ret, (UInt8*)&bfh, sizeof(bfh));
1276 /* rest of bitmap is the same as the packed dib */
1277 CFDataAppendBytes(ret, (UInt8*)dibdata, len - sizeof(bfh));
1280 GlobalUnlock(data);
1282 return ret;
1286 /**************************************************************************
1287 * export_enhmetafile
1289 * Export an enhanced metafile to data.
1291 static CFDataRef export_enhmetafile(HANDLE data)
1293 CFMutableDataRef ret = NULL;
1294 unsigned int size = GetEnhMetaFileBits(data, 0, NULL);
1296 TRACE("data %p\n", data);
1298 ret = CFDataCreateMutable(NULL, size);
1299 if (ret)
1301 CFDataSetLength(ret, size);
1302 GetEnhMetaFileBits(data, size, (BYTE*)CFDataGetMutableBytePtr(ret));
1305 TRACE(" -> %s\n", debugstr_cf(ret));
1306 return ret;
1310 /**************************************************************************
1311 * export_hdrop_to_filenames
1313 * Export CF_HDROP to NSFilenamesPboardType data, which is a CFArray of
1314 * CFStrings (holding Unix paths) which is serialized as a property list.
1316 static CFDataRef export_hdrop_to_filenames(HANDLE data)
1318 CFDataRef ret = NULL;
1319 DROPFILES *dropfiles;
1320 CFMutableArrayRef filenames = NULL;
1321 void *p;
1322 WCHAR *buffer = NULL;
1323 size_t buffer_len = 0;
1325 TRACE("data %p\n", data);
1327 if (!(dropfiles = GlobalLock(data)))
1329 WARN("failed to lock data %p\n", data);
1330 goto done;
1333 filenames = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1334 if (!filenames)
1336 WARN("failed to create filenames array\n");
1337 goto done;
1340 p = (char*)dropfiles + dropfiles->pFiles;
1341 while (dropfiles->fWide ? *(WCHAR*)p : *(char*)p)
1343 char *unixname;
1344 CFStringRef filename;
1346 TRACE(" %s\n", dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1348 if (dropfiles->fWide)
1349 unixname = wine_get_unix_file_name(p);
1350 else
1352 int len = MultiByteToWideChar(CP_ACP, 0, p, -1, NULL, 0);
1353 if (len)
1355 if (len > buffer_len)
1357 HeapFree(GetProcessHeap(), 0, buffer);
1358 buffer_len = len * 2;
1359 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_len * sizeof(*buffer));
1362 MultiByteToWideChar(CP_ACP, 0, p, -1, buffer, buffer_len);
1363 unixname = wine_get_unix_file_name(buffer);
1365 else
1366 unixname = NULL;
1368 if (!unixname)
1370 WARN("failed to convert DOS path to Unix: %s\n",
1371 dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1372 goto done;
1375 if (dropfiles->fWide)
1376 p = (WCHAR*)p + strlenW(p) + 1;
1377 else
1378 p = (char*)p + strlen(p) + 1;
1380 filename = CFStringCreateWithFileSystemRepresentation(NULL, unixname);
1381 HeapFree(GetProcessHeap(), 0, unixname);
1382 if (!filename)
1384 WARN("failed to create CFString from Unix path %s\n", debugstr_a(unixname));
1385 goto done;
1388 CFArrayAppendValue(filenames, filename);
1389 CFRelease(filename);
1392 ret = CFPropertyListCreateData(NULL, filenames, kCFPropertyListXMLFormat_v1_0, 0, NULL);
1394 done:
1395 HeapFree(GetProcessHeap(), 0, buffer);
1396 GlobalUnlock(data);
1397 if (filenames) CFRelease(filenames);
1398 TRACE(" -> %s\n", debugstr_cf(ret));
1399 return ret;
1403 /**************************************************************************
1404 * export_metafilepict
1406 * Export a metafile to data.
1408 static CFDataRef export_metafilepict(HANDLE data)
1410 CFMutableDataRef ret = NULL;
1411 METAFILEPICT *mfp = GlobalLock(data);
1412 unsigned int size = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
1414 TRACE("data %p\n", data);
1416 ret = CFDataCreateMutable(NULL, sizeof(*mfp) + size);
1417 if (ret)
1419 CFDataAppendBytes(ret, (UInt8*)mfp, sizeof(*mfp));
1420 CFDataIncreaseLength(ret, size);
1421 GetMetaFileBitsEx(mfp->hMF, size, (BYTE*)CFDataGetMutableBytePtr(ret) + sizeof(*mfp));
1424 GlobalUnlock(data);
1425 TRACE(" -> %s\n", debugstr_cf(ret));
1426 return ret;
1430 /**************************************************************************
1431 * export_oemtext_to_utf8
1433 * Export CF_OEMTEXT to UTF-8.
1435 static CFDataRef export_oemtext_to_utf8(HANDLE data)
1437 return export_codepage_to_utf8(data, CP_OEMCP);
1441 /**************************************************************************
1442 * export_oemtext_to_utf16
1444 * Export CF_OEMTEXT to UTF-16.
1446 static CFDataRef export_oemtext_to_utf16(HANDLE data)
1448 return export_codepage_to_utf16(data, CP_OEMCP);
1452 /**************************************************************************
1453 * export_text_to_utf8
1455 * Export CF_TEXT to UTF-8.
1457 static CFDataRef export_text_to_utf8(HANDLE data)
1459 return export_codepage_to_utf8(data, CP_ACP);
1463 /**************************************************************************
1464 * export_text_to_utf16
1466 * Export CF_TEXT to UTF-16.
1468 static CFDataRef export_text_to_utf16(HANDLE data)
1470 return export_codepage_to_utf16(data, CP_ACP);
1474 /**************************************************************************
1475 * export_unicodetext_to_utf8
1477 * Export CF_UNICODETEXT to UTF-8.
1479 static CFDataRef export_unicodetext_to_utf8(HANDLE data)
1481 CFMutableDataRef ret;
1482 LPVOID src;
1483 INT dst_len;
1485 src = GlobalLock(data);
1486 if (!src) return NULL;
1488 dst_len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
1489 if (dst_len) dst_len--; /* Leave off null terminator. */
1490 ret = CFDataCreateMutable(NULL, dst_len);
1491 if (ret)
1493 LPSTR dst;
1494 int i, j;
1496 CFDataSetLength(ret, dst_len);
1497 dst = (LPSTR)CFDataGetMutableBytePtr(ret);
1498 WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_len, NULL, NULL);
1500 /* Remove carriage returns */
1501 for (i = 0, j = 0; i < dst_len; i++)
1503 if (dst[i] == '\r' &&
1504 (i + 1 >= dst_len || dst[i + 1] == '\n' || dst[i + 1] == '\0'))
1505 continue;
1506 dst[j++] = dst[i];
1508 CFDataSetLength(ret, j);
1510 GlobalUnlock(data);
1512 return ret;
1516 /**************************************************************************
1517 * export_unicodetext_to_utf16
1519 * Export CF_UNICODETEXT to UTF-16.
1521 static CFDataRef export_unicodetext_to_utf16(HANDLE data)
1523 CFMutableDataRef ret;
1524 const WCHAR *src;
1525 INT src_len;
1527 src = GlobalLock(data);
1528 if (!src) return NULL;
1530 src_len = GlobalSize(data) / sizeof(WCHAR);
1531 if (src_len) src_len--; /* Leave off null terminator. */
1532 ret = CFDataCreateMutable(NULL, src_len * sizeof(WCHAR));
1533 if (ret)
1535 LPWSTR dst;
1536 int i, j;
1538 CFDataSetLength(ret, src_len * sizeof(WCHAR));
1539 dst = (LPWSTR)CFDataGetMutableBytePtr(ret);
1541 /* Remove carriage returns */
1542 for (i = 0, j = 0; i < src_len; i++)
1544 if (src[i] == '\r' &&
1545 (i + 1 >= src_len || src[i + 1] == '\n' || src[i + 1] == '\0'))
1546 continue;
1547 dst[j++] = src[i];
1549 CFDataSetLength(ret, j * sizeof(WCHAR));
1551 GlobalUnlock(data);
1553 return ret;
1557 /**************************************************************************
1558 * get_clipboard_info
1560 static BOOL get_clipboard_info(LPCLIPBOARDINFO cbinfo)
1562 BOOL ret = FALSE;
1564 SERVER_START_REQ(set_clipboard_info)
1566 req->flags = 0;
1568 if (wine_server_call_err(req))
1570 ERR("Failed to get clipboard owner.\n");
1572 else
1574 cbinfo->hwnd_owner = wine_server_ptr_handle(reply->old_owner);
1575 cbinfo->flags = reply->flags;
1577 ret = TRUE;
1580 SERVER_END_REQ;
1582 return ret;
1586 /**************************************************************************
1587 * release_ownership
1589 static BOOL release_ownership(void)
1591 BOOL ret = FALSE;
1593 SERVER_START_REQ(set_clipboard_info)
1595 req->flags = SET_CB_RELOWNER | SET_CB_SEQNO;
1597 if (wine_server_call_err(req))
1598 ERR("Failed to set clipboard.\n");
1599 else
1600 ret = TRUE;
1602 SERVER_END_REQ;
1604 return ret;
1608 /**************************************************************************
1609 * macdrv_get_pasteboard_data
1611 HANDLE macdrv_get_pasteboard_data(CFTypeRef pasteboard, UINT desired_format)
1613 CFArrayRef types;
1614 CFIndex count;
1615 CFIndex i;
1616 CFStringRef type, best_type;
1617 WINE_CLIPFORMAT* best_format = NULL;
1618 HANDLE data = NULL;
1620 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1622 types = macdrv_copy_pasteboard_types(pasteboard);
1623 if (!types)
1625 WARN("Failed to copy pasteboard types\n");
1626 return NULL;
1629 count = CFArrayGetCount(types);
1630 TRACE("got %ld types\n", count);
1632 for (i = 0; (!best_format || best_format->synthesized) && i < count; i++)
1634 WINE_CLIPFORMAT* format;
1636 type = CFArrayGetValueAtIndex(types, i);
1638 format = NULL;
1639 while ((!best_format || best_format->synthesized) && (format = format_for_type(format, type)))
1641 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format ? format->format_id : 0));
1643 if (format->format_id == desired_format)
1645 /* The best format is the matching one which is not synthesized. Failing that,
1646 the best format is the first matching synthesized format. */
1647 if (!format->synthesized || !best_format)
1649 best_type = type;
1650 best_format = format;
1656 if (best_format)
1658 CFDataRef pasteboard_data = macdrv_copy_pasteboard_data(pasteboard, best_type);
1660 TRACE("got pasteboard data for type %s: %s\n", debugstr_cf(best_type), debugstr_cf(pasteboard_data));
1662 if (pasteboard_data)
1664 data = best_format->import_func(pasteboard_data);
1665 CFRelease(pasteboard_data);
1669 CFRelease(types);
1670 TRACE(" -> %p\n", data);
1671 return data;
1675 /**************************************************************************
1676 * macdrv_pasteboard_has_format
1678 BOOL macdrv_pasteboard_has_format(CFTypeRef pasteboard, UINT desired_format)
1680 CFArrayRef types;
1681 int count;
1682 UINT i;
1683 BOOL found = FALSE;
1685 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1687 types = macdrv_copy_pasteboard_types(pasteboard);
1688 if (!types)
1690 WARN("Failed to copy pasteboard types\n");
1691 return FALSE;
1694 count = CFArrayGetCount(types);
1695 TRACE("got %d types\n", count);
1697 for (i = 0; !found && i < count; i++)
1699 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1700 WINE_CLIPFORMAT* format;
1702 format = NULL;
1703 while (!found && (format = format_for_type(format, type)))
1705 TRACE("for type %s got format %s\n", debugstr_cf(type), debugstr_format(format->format_id));
1707 if (format->format_id == desired_format)
1708 found = TRUE;
1712 CFRelease(types);
1713 TRACE(" -> %d\n", found);
1714 return found;
1718 /**************************************************************************
1719 * macdrv_copy_pasteboard_formats
1721 CFArrayRef macdrv_copy_pasteboard_formats(CFTypeRef pasteboard)
1723 CFArrayRef types;
1724 CFIndex count;
1725 CFMutableArrayRef formats;
1726 CFIndex i;
1727 WINE_CLIPFORMAT* format;
1729 TRACE("pasteboard %p\n", pasteboard);
1731 types = macdrv_copy_pasteboard_types(pasteboard);
1732 if (!types)
1734 WARN("Failed to copy pasteboard types\n");
1735 return NULL;
1738 count = CFArrayGetCount(types);
1739 TRACE("got %ld types\n", count);
1741 if (!count)
1743 CFRelease(types);
1744 return NULL;
1747 formats = CFArrayCreateMutable(NULL, 0, NULL);
1748 if (!formats)
1750 WARN("Failed to allocate formats array\n");
1751 CFRelease(types);
1752 return NULL;
1755 for (i = 0; i < count; i++)
1757 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1758 BOOL found = FALSE;
1760 format = NULL;
1761 while ((format = format_for_type(format, type)))
1763 /* Suppose type is "public.utf8-plain-text". format->format_id will be each of
1764 CF_TEXT, CF_OEMTEXT, and CF_UNICODETEXT in turn. We want to look up the natural
1765 type for each of those IDs (e.g. CF_TEXT -> "org.winehq.builtin.text") and then see
1766 if that type is present in the pasteboard. If it is, then we don't want to add the
1767 format to the list yet because it would be out of order.
1769 For example, if a Mac app put "public.utf8-plain-text" and "public.tiff" on the
1770 pasteboard, then we want the Win32 clipboard formats to be CF_TEXT, CF_OEMTEXT, and
1771 CF_UNICODETEXT, and CF_TIFF, in that order. All of the text formats belong before
1772 CF_TIFF because the Mac app expressed that text was "better" than the TIFF. In
1773 this case, as soon as we encounter "public.utf8-plain-text" we should add all of
1774 the associated text format IDs.
1776 But if a Wine process put "org.winehq.builtin.unicodetext",
1777 "public.utf8-plain-text", "public.utf16-plain-text", and "public.tiff", then we
1778 want the clipboard formats to be CF_UNICODETEXT, CF_TIFF, CF_TEXT, and CF_OEMTEXT,
1779 in that order. The Windows program presumably added CF_UNICODETEXT and CF_TIFF.
1780 We're synthesizing CF_TEXT and CF_OEMTEXT from CF_UNICODETEXT but we want them to
1781 come after the non-synthesized CF_TIFF. In this case, we don't want to add the
1782 text formats upon encountering "public.utf8-plain-text",
1784 We tell the two cases apart by seeing that one of the natural types for the text
1785 formats (i.e. "org.winehq.builtin.unicodetext") is present on the pasteboard.
1786 "found" indicates that. */
1788 if (!format->synthesized)
1790 TRACE("for type %s got primary format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1791 CFArrayAppendValue(formats, (void*)format->format_id);
1792 found = TRUE;
1794 else if (!found && format->natural_format &&
1795 CFArrayContainsValue(types, CFRangeMake(0, count), format->natural_format->type))
1797 TRACE("for type %s deferring synthesized formats because type %s is also present\n",
1798 debugstr_cf(type), debugstr_cf(format->natural_format->type));
1799 found = TRUE;
1803 if (!found)
1805 while ((format = format_for_type(format, type)))
1807 /* Don't override a real value with a synthesized value. */
1808 if (!CFArrayContainsValue(formats, CFRangeMake(0, CFArrayGetCount(formats)), (void*)format->format_id))
1810 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1811 CFArrayAppendValue(formats, (void*)format->format_id);
1817 /* Now go back through the types adding the synthesized formats that we deferred before. */
1818 for (i = 0; i < count; i++)
1820 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1822 format = NULL;
1823 while ((format = format_for_type(format, type)))
1825 if (format->synthesized)
1827 /* Don't override a real value with a synthesized value. */
1828 if (!CFArrayContainsValue(formats, CFRangeMake(0, CFArrayGetCount(formats)), (void*)format->format_id))
1830 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1831 CFArrayAppendValue(formats, (void*)format->format_id);
1837 CFRelease(types);
1839 TRACE(" -> %s\n", debugstr_cf(formats));
1840 return formats;
1844 /**************************************************************************
1845 * check_clipboard_ownership
1847 static void check_clipboard_ownership(HWND *owner)
1849 CLIPBOARDINFO cbinfo;
1851 if (owner) *owner = NULL;
1853 /* If Wine thinks we're the clipboard owner but Mac OS X thinks we're not
1854 the pasteboard owner, update Wine. */
1855 if (get_clipboard_info(&cbinfo) && (cbinfo.flags & CB_PROCESS))
1857 if (!(cbinfo.flags & CB_OPEN) && !macdrv_is_pasteboard_owner())
1859 TRACE("Lost clipboard ownership\n");
1861 if (OpenClipboard(cbinfo.hwnd_owner))
1863 /* Destroy private objects */
1864 SendMessageW(cbinfo.hwnd_owner, WM_DESTROYCLIPBOARD, 0, 0);
1866 /* Give up ownership of the windows clipboard */
1867 release_ownership();
1868 CloseClipboard();
1871 else if (owner)
1872 *owner = cbinfo.hwnd_owner;
1877 /**************************************************************************
1878 * Mac User Driver Clipboard Exports
1879 **************************************************************************/
1882 /**************************************************************************
1883 * AcquireClipboard (MACDRV.@)
1885 int CDECL macdrv_AcquireClipboard(HWND hwnd)
1887 TRACE("hwnd %p\n", hwnd);
1888 check_clipboard_ownership(NULL);
1889 return 0;
1893 /**************************************************************************
1894 * CountClipboardFormats (MACDRV.@)
1896 INT CDECL macdrv_CountClipboardFormats(void)
1898 CFMutableSetRef seen_formats;
1899 CFArrayRef types;
1900 CFIndex count;
1901 CFIndex i;
1902 INT ret = 0;
1904 TRACE("()\n");
1905 check_clipboard_ownership(NULL);
1907 seen_formats = CFSetCreateMutable(NULL, 0, NULL);
1908 if (!seen_formats)
1910 WARN("Failed to allocate set to track seen formats\n");
1911 return 0;
1914 types = macdrv_copy_pasteboard_types(NULL);
1915 if (!types)
1917 WARN("Failed to copy pasteboard types\n");
1918 CFRelease(seen_formats);
1919 return 0;
1922 count = CFArrayGetCount(types);
1923 TRACE("got %ld types\n", count);
1925 for (i = 0; i < count; i++)
1927 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1928 WINE_CLIPFORMAT* format;
1930 format = NULL;
1931 while ((format = format_for_type(format, type)))
1933 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1935 if (!CFSetContainsValue(seen_formats, (void*)format->format_id))
1937 ret++;
1938 CFSetAddValue(seen_formats, (void*)format->format_id);
1943 CFRelease(types);
1944 CFRelease(seen_formats);
1945 TRACE(" -> %d\n", ret);
1946 return ret;
1950 /**************************************************************************
1951 * EmptyClipboard (MACDRV.@)
1953 * Empty cached clipboard data.
1955 void CDECL macdrv_EmptyClipboard(BOOL keepunowned)
1957 TRACE("keepunowned %d\n", keepunowned);
1958 macdrv_clear_pasteboard();
1962 /**************************************************************************
1963 * EndClipboardUpdate (MACDRV.@)
1965 void CDECL macdrv_EndClipboardUpdate(void)
1967 TRACE("()\n");
1968 check_clipboard_ownership(NULL);
1972 /**************************************************************************
1973 * EnumClipboardFormats (MACDRV.@)
1975 UINT CDECL macdrv_EnumClipboardFormats(UINT prev_format)
1977 CFArrayRef formats;
1978 CFIndex count;
1979 CFIndex i;
1980 UINT ret = 0;
1982 TRACE("prev_format %s\n", debugstr_format(prev_format));
1983 check_clipboard_ownership(NULL);
1985 formats = macdrv_copy_pasteboard_formats(NULL);
1986 if (formats)
1988 count = CFArrayGetCount(formats);
1989 if (prev_format)
1991 i = CFArrayGetFirstIndexOfValue(formats, CFRangeMake(0, count), (void*)prev_format);
1992 if (i != kCFNotFound)
1993 i++;
1995 else
1996 i = 0;
1998 if (i != kCFNotFound && i < count)
1999 ret = (UINT)CFArrayGetValueAtIndex(formats, i);
2001 CFRelease(formats);
2004 TRACE(" -> %u\n", ret);
2005 return ret;
2009 /**************************************************************************
2010 * GetClipboardData (MACDRV.@)
2012 HANDLE CDECL macdrv_GetClipboardData(UINT desired_format)
2014 check_clipboard_ownership(NULL);
2016 return macdrv_get_pasteboard_data(NULL, desired_format);
2020 /**************************************************************************
2021 * IsClipboardFormatAvailable (MACDRV.@)
2023 BOOL CDECL macdrv_IsClipboardFormatAvailable(UINT desired_format)
2025 check_clipboard_ownership(NULL);
2026 return macdrv_pasteboard_has_format(NULL, desired_format);
2030 /**************************************************************************
2031 * SetClipboardData (MACDRV.@)
2033 BOOL CDECL macdrv_SetClipboardData(UINT format_id, HANDLE data, BOOL owner)
2035 HWND hwnd_owner;
2036 macdrv_window window;
2037 WINE_CLIPFORMAT *format;
2038 CFDataRef cfdata = NULL;
2040 check_clipboard_ownership(&hwnd_owner);
2041 window = macdrv_get_cocoa_window(GetAncestor(hwnd_owner, GA_ROOT), FALSE);
2042 TRACE("format_id %s data %p owner %d hwnd_owner %p window %p)\n", debugstr_format(format_id), data, owner, hwnd_owner, window);
2044 format = natural_format_for_format(format_id);
2045 if (!format && !(format = insert_clipboard_format(format_id, NULL)))
2047 WARN("Failed to register clipboard format %s\n", debugstr_format(format_id));
2048 return FALSE;
2051 /* Export the data to the Mac pasteboard. */
2052 if (data)
2054 if (!format->export_func || !(cfdata = format->export_func(data)))
2056 WARN("Failed to export %s data to type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
2057 return FALSE;
2061 if (macdrv_set_pasteboard_data(format->type, cfdata, window))
2062 TRACE("Set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
2063 else
2065 WARN("Failed to set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
2066 if (cfdata) CFRelease(cfdata);
2067 return FALSE;
2070 if (cfdata) CFRelease(cfdata);
2072 /* Find any other formats for this format_id (the exportable synthesized ones). */
2073 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
2075 if (format->format_id == format_id && format->synthesized && format->export_func)
2077 /* We have a synthesized format for this format ID. Add its type to the pasteboard. */
2078 TRACE("Synthesized from format %s: type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
2080 if (data)
2082 cfdata = format->export_func(data);
2083 if (!cfdata)
2085 WARN("Failed to export %s data to type %s\n", debugstr_format(format->format_id), debugstr_cf(format->type));
2086 continue;
2089 else
2090 cfdata = NULL;
2092 if (macdrv_set_pasteboard_data(format->type, cfdata, window))
2093 TRACE(" ... set pasteboard data: %s\n", debugstr_cf(cfdata));
2094 else
2095 WARN(" ... failed to set pasteboard data: %s\n", debugstr_cf(cfdata));
2097 if (cfdata) CFRelease(cfdata);
2101 if (data)
2103 /* FIXME: According to MSDN, the caller is entitled to lock and read from
2104 data until CloseClipboard is called. So, we should defer this cleanup. */
2105 if ((format_id >= CF_GDIOBJFIRST && format_id <= CF_GDIOBJLAST) ||
2106 format_id == CF_BITMAP ||
2107 format_id == CF_DIB ||
2108 format_id == CF_PALETTE)
2110 DeleteObject(data);
2112 else if (format_id == CF_METAFILEPICT)
2114 DeleteMetaFile(((METAFILEPICT *)GlobalLock(data))->hMF);
2115 GlobalFree(data);
2117 else if (format_id == CF_ENHMETAFILE)
2119 DeleteEnhMetaFile(data);
2121 else if (format_id < CF_PRIVATEFIRST || CF_PRIVATELAST < format_id)
2123 GlobalFree(data);
2127 return TRUE;
2131 /**************************************************************************
2132 * MACDRV Private Clipboard Exports
2133 **************************************************************************/
2136 /**************************************************************************
2137 * macdrv_clipboard_process_attach
2139 void macdrv_clipboard_process_attach(void)
2141 UINT i;
2142 WINE_CLIPFORMAT *format;
2144 /* Register built-in formats */
2145 for (i = 0; i < sizeof(builtin_format_ids)/sizeof(builtin_format_ids[0]); i++)
2147 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
2148 format->format_id = builtin_format_ids[i].id;
2149 format->type = CFRetain(builtin_format_ids[i].type);
2150 format->import_func = builtin_format_ids[i].import;
2151 format->export_func = builtin_format_ids[i].export;
2152 format->synthesized = builtin_format_ids[i].synthesized;
2153 format->natural_format = NULL;
2154 list_add_tail(&format_list, &format->entry);
2157 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
2159 if (format->synthesized)
2160 format->natural_format = natural_format_for_format(format->format_id);
2163 /* Register known mappings between Windows formats and Mac types */
2164 for (i = 0; i < sizeof(builtin_format_names)/sizeof(builtin_format_names[0]); i++)
2166 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
2167 format->format_id = RegisterClipboardFormatW(builtin_format_names[i].name);
2168 format->type = CFRetain(builtin_format_names[i].type);
2169 format->import_func = builtin_format_names[i].import;
2170 format->export_func = builtin_format_names[i].export;
2171 format->synthesized = FALSE;
2172 format->natural_format = NULL;
2173 list_add_tail(&format_list, &format->entry);
2178 /**************************************************************************
2179 * query_pasteboard_data
2181 BOOL query_pasteboard_data(HWND hwnd, CFStringRef type)
2183 BOOL ret = FALSE;
2184 CLIPBOARDINFO cbinfo;
2185 WINE_CLIPFORMAT* format;
2186 CFArrayRef types = NULL;
2187 CFRange range;
2189 TRACE("hwnd %p type %s\n", hwnd, debugstr_cf(type));
2191 if (get_clipboard_info(&cbinfo))
2192 hwnd = cbinfo.hwnd_owner;
2194 format = NULL;
2195 while ((format = format_for_type(format, type)))
2197 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
2199 if (!format->synthesized)
2201 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(format->format_id), hwnd);
2202 SendMessageW(hwnd, WM_RENDERFORMAT, format->format_id, 0);
2203 ret = TRUE;
2204 goto done;
2207 if (!types)
2209 types = macdrv_copy_pasteboard_types(NULL);
2210 if (!types)
2212 WARN("Failed to copy pasteboard types\n");
2213 break;
2216 range = CFRangeMake(0, CFArrayGetCount(types));
2219 /* The type maps to a synthesized format. Now look up what type that format maps to natively
2220 (not synthesized). For example, if type is "public.utf8-plain-text", then this format may
2221 have an ID of CF_TEXT. From CF_TEXT, we want to find "org.winehq.builtin.text" to see if
2222 that type is present in the pasteboard. If it is, then the app must have promised it and
2223 we can ask it to render it. (If it had put it on the clipboard immediately, then the
2224 pasteboard would also have data for "public.utf8-plain-text" and we wouldn't be here.) If
2225 "org.winehq.builtin.text" is not on the pasteboard, then one of the other text formats is
2226 presumably responsible for the promise that we're trying to satisfy, so we keep looking. */
2227 if (format->natural_format && CFArrayContainsValue(types, range, format->natural_format->type))
2229 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(format->format_id), hwnd);
2230 SendMessageW(hwnd, WM_RENDERFORMAT, format->format_id, 0);
2231 ret = TRUE;
2232 goto done;
2236 done:
2237 if (types) CFRelease(types);
2239 return ret;