winemac: Remove support for converting among standard clipboard formats.
[wine.git] / dlls / winemac.drv / clipboard.c
blob8737a565041221308aaee57fbdf9dc9e52e61a56
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_metafilepict(CFDataRef data);
78 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data);
79 static HANDLE import_utf8_to_oemtext(CFDataRef data);
80 static HANDLE import_utf8_to_text(CFDataRef data);
81 static HANDLE import_utf8_to_unicodetext(CFDataRef data);
82 static HANDLE import_utf16_to_oemtext(CFDataRef data);
83 static HANDLE import_utf16_to_text(CFDataRef data);
84 static HANDLE import_utf16_to_unicodetext(CFDataRef data);
86 static CFDataRef export_clipboard_data(HANDLE data);
87 static CFDataRef export_bitmap_to_bmp(HANDLE data);
88 static CFDataRef export_dib_to_bmp(HANDLE data);
89 static CFDataRef export_enhmetafile(HANDLE data);
90 static CFDataRef export_hdrop_to_filenames(HANDLE data);
91 static CFDataRef export_metafilepict(HANDLE data);
92 static CFDataRef export_oemtext_to_utf8(HANDLE data);
93 static CFDataRef export_oemtext_to_utf16(HANDLE data);
94 static CFDataRef export_text_to_utf8(HANDLE data);
95 static CFDataRef export_text_to_utf16(HANDLE data);
96 static CFDataRef export_unicodetext_to_utf8(HANDLE data);
97 static CFDataRef export_unicodetext_to_utf16(HANDLE data);
100 /**************************************************************************
101 * Static Variables
102 **************************************************************************/
104 /* Clipboard formats */
105 static struct list format_list = LIST_INIT(format_list);
107 /* There are two naming schemes involved and we want to have a mapping between
108 them. There are Win32 clipboard format names and there are Mac pasteboard
109 types.
111 The Win32 standard clipboard formats don't have names, but they are associated
112 with Mac pasteboard types through the following tables, which are used to
113 initialize the format_list. Where possible, the standard clipboard formats
114 are mapped to predefined pasteboard type UTIs. Otherwise, we create Wine-
115 specific types of the form "org.winehq.builtin.<format>", where <format> is
116 the name of the symbolic constant for the format minus "CF_" and lowercased.
117 E.g. CF_BITMAP -> org.winehq.builtin.bitmap.
119 Win32 clipboard formats which originate in a Windows program may be registered
120 with an arbitrary name. We construct a Mac pasteboard type from these by
121 prepending "org.winehq.registered." to the registered name.
123 Likewise, Mac pasteboard types which originate in other apps may have
124 arbitrary type strings. We ignore these.
126 Summary:
127 Win32 clipboard format names:
128 <none> standard clipboard format; maps via
129 format_list to either a predefined Mac UTI
130 or org.winehq.builtin.<format>.
131 <other> name registered within Win32 land; maps to
132 org.winehq.registered.<other>
133 Mac pasteboard type names:
134 org.winehq.builtin.<format ID> representation of Win32 standard clipboard
135 format for which there was no corresponding
136 predefined Mac UTI; maps via format_list
137 org.winehq.registered.<format name> representation of Win32 registered
138 clipboard format name; maps to <format name>
139 <other> Mac pasteboard type originating with system
140 or other apps; either maps via format_list
141 to a standard clipboard format or ignored
144 static const struct
146 UINT id;
147 CFStringRef type;
148 DRVIMPORTFUNC import;
149 DRVEXPORTFUNC export;
150 BOOL synthesized;
151 } builtin_format_ids[] =
153 { CF_DIF, CFSTR("org.winehq.builtin.dif"), import_clipboard_data, export_clipboard_data, FALSE },
154 { CF_ENHMETAFILE, CFSTR("org.winehq.builtin.enhmetafile"), import_enhmetafile, export_enhmetafile, FALSE },
155 { CF_LOCALE, CFSTR("org.winehq.builtin.locale"), import_clipboard_data, export_clipboard_data, FALSE },
156 { CF_METAFILEPICT, CFSTR("org.winehq.builtin.metafilepict"), import_metafilepict, export_metafilepict, FALSE },
157 { CF_PALETTE, CFSTR("org.winehq.builtin.palette"), import_clipboard_data, export_clipboard_data, FALSE },
158 { CF_PENDATA, CFSTR("org.winehq.builtin.pendata"), import_clipboard_data, export_clipboard_data, FALSE },
159 { CF_RIFF, CFSTR("org.winehq.builtin.riff"), import_clipboard_data, export_clipboard_data, FALSE },
160 { CF_SYLK, CFSTR("org.winehq.builtin.sylk"), import_clipboard_data, export_clipboard_data, FALSE },
161 { CF_TIFF, CFSTR("public.tiff"), import_clipboard_data, export_clipboard_data, FALSE },
162 { CF_WAVE, CFSTR("com.microsoft.waveform-audio"), import_clipboard_data, export_clipboard_data, FALSE },
164 { CF_BITMAP, CFSTR("org.winehq.builtin.bitmap"), import_bmp_to_bitmap, export_bitmap_to_bmp, FALSE },
165 { CF_BITMAP, CFSTR("com.microsoft.bmp"), import_bmp_to_bitmap, export_bitmap_to_bmp, TRUE },
167 { CF_DIB, CFSTR("org.winehq.builtin.dib"), import_clipboard_data, export_clipboard_data, FALSE },
168 { CF_DIB, CFSTR("com.microsoft.bmp"), import_bmp_to_dib, export_dib_to_bmp, TRUE },
170 { CF_DIBV5, CFSTR("org.winehq.builtin.dibv5"), import_clipboard_data, export_clipboard_data, FALSE },
171 { CF_DIBV5, CFSTR("com.microsoft.bmp"), import_bmp_to_dib, export_dib_to_bmp, TRUE },
173 { CF_HDROP, CFSTR("org.winehq.builtin.hdrop"), import_clipboard_data, export_clipboard_data, FALSE },
174 { CF_HDROP, CFSTR("NSFilenamesPboardType"), import_nsfilenames_to_hdrop, export_hdrop_to_filenames, TRUE },
176 { CF_OEMTEXT, CFSTR("org.winehq.builtin.oemtext"), import_clipboard_data, export_clipboard_data, FALSE },
177 { CF_OEMTEXT, CFSTR("public.utf16-plain-text"), import_utf16_to_oemtext, export_oemtext_to_utf16, TRUE },
178 { CF_OEMTEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_oemtext, export_oemtext_to_utf8, TRUE },
180 { CF_TEXT, CFSTR("org.winehq.builtin.text"), import_clipboard_data, export_clipboard_data, FALSE },
181 { CF_TEXT, CFSTR("public.utf16-plain-text"), import_utf16_to_text, export_text_to_utf16, TRUE },
182 { CF_TEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_text, export_text_to_utf8, TRUE },
184 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.unicodetext"), import_clipboard_data, export_clipboard_data, FALSE },
185 { CF_UNICODETEXT, CFSTR("public.utf16-plain-text"), import_utf16_to_unicodetext, export_unicodetext_to_utf16,TRUE },
186 { CF_UNICODETEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_unicodetext, export_unicodetext_to_utf8, TRUE },
189 static const WCHAR wszRichTextFormat[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
190 static const WCHAR wszGIF[] = {'G','I','F',0};
191 static const WCHAR wszJFIF[] = {'J','F','I','F',0};
192 static const WCHAR wszPNG[] = {'P','N','G',0};
193 static const WCHAR wszHTMLFormat[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
194 static const struct
196 LPCWSTR name;
197 CFStringRef type;
198 DRVIMPORTFUNC import;
199 DRVEXPORTFUNC export;
200 } builtin_format_names[] =
202 { wszRichTextFormat, CFSTR("public.rtf"), import_clipboard_data, export_clipboard_data },
203 { wszGIF, CFSTR("com.compuserve.gif"), import_clipboard_data, export_clipboard_data },
204 { wszJFIF, CFSTR("public.jpeg"), import_clipboard_data, export_clipboard_data },
205 { wszPNG, CFSTR("public.png"), import_clipboard_data, export_clipboard_data },
206 { wszHTMLFormat, CFSTR("public.html"), import_clipboard_data, export_clipboard_data },
207 { CFSTR_SHELLURLW, CFSTR("public.url"), import_utf8_to_text, export_text_to_utf8 },
210 /* The prefix prepended to a Win32 clipboard format name to make a Mac pasteboard type. */
211 static const CFStringRef registered_name_type_prefix = CFSTR("org.winehq.registered.");
214 /**************************************************************************
215 * Internal Clipboard implementation methods
216 **************************************************************************/
219 * format_list functions
222 /**************************************************************************
223 * debugstr_format
225 const char *debugstr_format(UINT id)
227 WCHAR buffer[256];
229 if (GetClipboardFormatNameW(id, buffer, 256))
230 return wine_dbg_sprintf("0x%04x %s", id, debugstr_w(buffer));
232 switch (id)
234 #define BUILTIN(id) case id: return #id;
235 BUILTIN(CF_TEXT)
236 BUILTIN(CF_BITMAP)
237 BUILTIN(CF_METAFILEPICT)
238 BUILTIN(CF_SYLK)
239 BUILTIN(CF_DIF)
240 BUILTIN(CF_TIFF)
241 BUILTIN(CF_OEMTEXT)
242 BUILTIN(CF_DIB)
243 BUILTIN(CF_PALETTE)
244 BUILTIN(CF_PENDATA)
245 BUILTIN(CF_RIFF)
246 BUILTIN(CF_WAVE)
247 BUILTIN(CF_UNICODETEXT)
248 BUILTIN(CF_ENHMETAFILE)
249 BUILTIN(CF_HDROP)
250 BUILTIN(CF_LOCALE)
251 BUILTIN(CF_DIBV5)
252 BUILTIN(CF_OWNERDISPLAY)
253 BUILTIN(CF_DSPTEXT)
254 BUILTIN(CF_DSPBITMAP)
255 BUILTIN(CF_DSPMETAFILEPICT)
256 BUILTIN(CF_DSPENHMETAFILE)
257 #undef BUILTIN
258 default: return wine_dbg_sprintf("0x%04x", id);
263 /**************************************************************************
264 * insert_clipboard_format
266 static WINE_CLIPFORMAT *insert_clipboard_format(UINT id, CFStringRef type)
268 WINE_CLIPFORMAT *format;
270 format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format));
272 if (format == NULL)
274 WARN("No more memory for a new format!\n");
275 return NULL;
277 format->format_id = id;
278 format->import_func = import_clipboard_data;
279 format->export_func = export_clipboard_data;
280 format->synthesized = FALSE;
281 format->natural_format = NULL;
283 if (type)
284 format->type = CFStringCreateCopy(NULL, type);
285 else
287 WCHAR buffer[256];
289 if (!GetClipboardFormatNameW(format->format_id, buffer, sizeof(buffer) / sizeof(buffer[0])))
291 WARN("failed to get name for format %s; error 0x%08x\n", debugstr_format(format->format_id), GetLastError());
292 HeapFree(GetProcessHeap(), 0, format);
293 return NULL;
296 format->type = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%S"),
297 registered_name_type_prefix, buffer);
300 list_add_tail(&format_list, &format->entry);
302 TRACE("Registering format %s type %s\n", debugstr_format(format->format_id),
303 debugstr_cf(format->type));
305 return format;
309 /**************************************************************************
310 * register_format
312 * Register a custom Mac clipboard format.
314 static WINE_CLIPFORMAT* register_format(UINT id, CFStringRef type)
316 WINE_CLIPFORMAT *format;
318 /* walk format chain to see if it's already registered */
319 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
320 if (format->format_id == id) return format;
322 return insert_clipboard_format(id, type);
326 /**************************************************************************
327 * format_for_type
329 static WINE_CLIPFORMAT* format_for_type(WINE_CLIPFORMAT *current, CFStringRef type)
331 struct list *ptr = current ? &current->entry : &format_list;
332 WINE_CLIPFORMAT *format = NULL;
334 TRACE("current %p/%s type %s\n", current, debugstr_format(current ? current->format_id : 0), debugstr_cf(type));
336 while ((ptr = list_next(&format_list, ptr)))
338 format = LIST_ENTRY(ptr, WINE_CLIPFORMAT, entry);
339 if (CFEqual(format->type, type))
340 goto done;
343 format = NULL;
344 if (!current)
346 if (CFStringHasPrefix(type, CFSTR("org.winehq.builtin.")))
348 ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
349 debugstr_cf(type));
351 else if (CFStringHasPrefix(type, registered_name_type_prefix))
353 LPWSTR name;
354 int len = CFStringGetLength(type) - CFStringGetLength(registered_name_type_prefix);
356 name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
357 CFStringGetCharacters(type, CFRangeMake(CFStringGetLength(registered_name_type_prefix), len),
358 (UniChar*)name);
359 name[len] = 0;
361 format = register_format(RegisterClipboardFormatW(name), type);
362 if (!format)
363 ERR("Failed to register format for type %s name %s\n", debugstr_cf(type), debugstr_w(name));
365 HeapFree(GetProcessHeap(), 0, name);
369 done:
370 TRACE(" -> %p/%s\n", format, debugstr_format(format ? format->format_id : 0));
371 return format;
375 /**************************************************************************
376 * natural_format_for_format
378 * Find the "natural" format for this format_id (the one which isn't
379 * synthesized from another type).
381 static WINE_CLIPFORMAT* natural_format_for_format(UINT format_id)
383 WINE_CLIPFORMAT *format;
385 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
386 if (format->format_id == format_id && !format->synthesized) break;
388 if (&format->entry == &format_list)
389 format = NULL;
391 TRACE("%s -> %p/%s\n", debugstr_format(format_id), format, debugstr_cf(format ? format->type : NULL));
392 return format;
396 /**************************************************************************
397 * convert_text
399 * Convert string data between code pages or to/from wide characters. The
400 * special value of (UINT)-1 for a code page indicates to use wide
401 * characters.
403 static HANDLE convert_text(const void *src, int src_len, UINT src_cp, UINT dest_cp)
405 HANDLE ret = NULL;
406 const WCHAR *wstr;
407 int wstr_len;
408 HANDLE handle;
409 char *p;
411 if (src_cp == (UINT)-1)
413 wstr = src;
414 wstr_len = src_len / sizeof(WCHAR);
416 else
418 WCHAR *temp;
420 wstr_len = MultiByteToWideChar(src_cp, 0, src, src_len, NULL, 0);
421 if (!src_len || ((const char*)src)[src_len - 1]) wstr_len += 1;
422 temp = HeapAlloc(GetProcessHeap(), 0, wstr_len * sizeof(WCHAR));
423 MultiByteToWideChar(src_cp, 0, src, src_len, temp, wstr_len);
424 temp[wstr_len - 1] = 0;
425 wstr = temp;
428 if (dest_cp == (UINT)-1)
430 handle = GlobalAlloc(GMEM_FIXED, wstr_len * sizeof(WCHAR));
431 if (handle && (p = GlobalLock(handle)))
433 memcpy(p, wstr, wstr_len * sizeof(WCHAR));
434 GlobalUnlock(handle);
435 ret = handle;
438 else
440 INT len;
442 len = WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, NULL, 0, NULL, NULL);
443 if (!wstr_len || wstr[wstr_len - 1]) len += 1;
444 handle = GlobalAlloc(GMEM_FIXED, len);
446 if (handle && (p = GlobalLock(handle)))
448 WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, p, len, NULL, NULL);
449 p[len - 1] = 0;
450 GlobalUnlock(handle);
451 ret = handle;
455 return ret;
459 /**************************************************************************
460 * convert_unicodetext_to_codepage
462 static HANDLE convert_unicodetext_to_codepage(HANDLE unicode_handle, UINT cp)
464 LPWSTR unicode_string = GlobalLock(unicode_handle);
465 HANDLE ret = NULL;
467 if (unicode_string)
469 ret = convert_text(unicode_string, GlobalSize(unicode_handle), -1, cp);
470 GlobalUnlock(unicode_handle);
473 return ret;
477 /***********************************************************************
478 * bitmap_info_size
480 * Return the size of the bitmap info structure including color table.
482 static int bitmap_info_size(const BITMAPINFO *info, WORD coloruse)
484 unsigned int colors, size, masks = 0;
486 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
488 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER*)info;
489 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
490 return sizeof(BITMAPCOREHEADER) + colors *
491 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
493 else /* assume BITMAPINFOHEADER */
495 colors = info->bmiHeader.biClrUsed;
496 if (!colors && (info->bmiHeader.biBitCount <= 8))
497 colors = 1 << info->bmiHeader.biBitCount;
498 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
499 size = max(info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD));
500 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
505 /***********************************************************************
506 * create_dib_from_bitmap
508 * Allocates a packed DIB and copies the bitmap data into it.
510 static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp)
512 BITMAP bmp;
513 HDC hdc;
514 HGLOBAL hPackedDIB;
515 LPBYTE pPackedDIB;
516 LPBITMAPINFOHEADER pbmiHeader;
517 unsigned int cDataSize, cPackedSize, OffsetBits;
518 int nLinesCopied;
520 if (!GetObjectW(hBmp, sizeof(bmp), &bmp)) return 0;
523 * A packed DIB contains a BITMAPINFO structure followed immediately by
524 * an optional color palette and the pixel data.
527 /* Calculate the size of the packed DIB */
528 cDataSize = abs(bmp.bmHeight) * (((bmp.bmWidth * bmp.bmBitsPixel + 31) / 8) & ~3);
529 cPackedSize = sizeof(BITMAPINFOHEADER)
530 + ((bmp.bmBitsPixel <= 8) ? (sizeof(RGBQUAD) * (1 << bmp.bmBitsPixel)) : 0)
531 + cDataSize;
532 /* Get the offset to the bits */
533 OffsetBits = cPackedSize - cDataSize;
535 /* Allocate the packed DIB */
536 TRACE("\tAllocating packed DIB of size %d\n", cPackedSize);
537 hPackedDIB = GlobalAlloc(GMEM_FIXED, cPackedSize);
538 if (!hPackedDIB)
540 WARN("Could not allocate packed DIB!\n");
541 return 0;
544 /* A packed DIB starts with a BITMAPINFOHEADER */
545 pPackedDIB = GlobalLock(hPackedDIB);
546 pbmiHeader = (LPBITMAPINFOHEADER)pPackedDIB;
548 /* Init the BITMAPINFOHEADER */
549 pbmiHeader->biSize = sizeof(BITMAPINFOHEADER);
550 pbmiHeader->biWidth = bmp.bmWidth;
551 pbmiHeader->biHeight = bmp.bmHeight;
552 pbmiHeader->biPlanes = 1;
553 pbmiHeader->biBitCount = bmp.bmBitsPixel;
554 pbmiHeader->biCompression = BI_RGB;
555 pbmiHeader->biSizeImage = 0;
556 pbmiHeader->biXPelsPerMeter = pbmiHeader->biYPelsPerMeter = 0;
557 pbmiHeader->biClrUsed = 0;
558 pbmiHeader->biClrImportant = 0;
560 /* Retrieve the DIB bits from the bitmap and fill in the
561 * DIB color table if present */
562 hdc = GetDC(0);
563 nLinesCopied = GetDIBits(hdc, /* Handle to device context */
564 hBmp, /* Handle to bitmap */
565 0, /* First scan line to set in dest bitmap */
566 bmp.bmHeight, /* Number of scan lines to copy */
567 pPackedDIB + OffsetBits, /* [out] Address of array for bitmap bits */
568 (LPBITMAPINFO) pbmiHeader, /* [out] Address of BITMAPINFO structure */
569 0); /* RGB or palette index */
570 GlobalUnlock(hPackedDIB);
571 ReleaseDC(0, hdc);
573 /* Cleanup if GetDIBits failed */
574 if (nLinesCopied != bmp.bmHeight)
576 TRACE("\tGetDIBits returned %d. Actual lines=%d\n", nLinesCopied, bmp.bmHeight);
577 GlobalFree(hPackedDIB);
578 hPackedDIB = 0;
580 return hPackedDIB;
584 /**************************************************************************
585 * create_bitmap_from_dib
587 * Given a packed DIB, creates a bitmap object from it.
589 static HANDLE create_bitmap_from_dib(HANDLE dib)
591 HANDLE ret = 0;
592 BITMAPINFO *bmi;
594 if (dib && (bmi = GlobalLock(dib)))
596 HDC hdc;
597 unsigned int offset;
599 hdc = GetDC(NULL);
601 offset = bitmap_info_size(bmi, DIB_RGB_COLORS);
603 ret = CreateDIBitmap(hdc, &bmi->bmiHeader, CBM_INIT, (LPBYTE)bmi + offset,
604 bmi, DIB_RGB_COLORS);
606 GlobalUnlock(dib);
607 ReleaseDC(NULL, hdc);
610 return ret;
614 /**************************************************************************
615 * import_clipboard_data
617 * Generic import clipboard data routine.
619 static HANDLE import_clipboard_data(CFDataRef data)
621 HANDLE data_handle = NULL;
623 size_t len = CFDataGetLength(data);
624 if (len)
626 LPVOID p;
628 /* Turn on the DDESHARE flag to enable shared 32 bit memory */
629 data_handle = GlobalAlloc(GMEM_FIXED, len);
630 if (!data_handle)
631 return NULL;
633 if ((p = GlobalLock(data_handle)))
635 memcpy(p, CFDataGetBytePtr(data), len);
636 GlobalUnlock(data_handle);
638 else
640 GlobalFree(data_handle);
641 data_handle = NULL;
645 return data_handle;
649 /**************************************************************************
650 * import_bmp_to_bitmap
652 * Import BMP data, converting to CF_BITMAP format.
654 static HANDLE import_bmp_to_bitmap(CFDataRef data)
656 HANDLE ret;
657 HANDLE dib = import_bmp_to_dib(data);
659 ret = create_bitmap_from_dib(dib);
661 GlobalFree(dib);
662 return ret;
666 /**************************************************************************
667 * import_bmp_to_dib
669 * Import BMP data, converting to CF_DIB or CF_DIBV5 format. This just
670 * entails stripping the BMP file format header.
672 static HANDLE import_bmp_to_dib(CFDataRef data)
674 HANDLE ret = 0;
675 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)CFDataGetBytePtr(data);
676 CFIndex len = CFDataGetLength(data);
678 if (len >= sizeof(*bfh) + sizeof(BITMAPCOREHEADER) &&
679 bfh->bfType == 0x4d42 /* "BM" */)
681 BITMAPINFO *bmi = (BITMAPINFO*)(bfh + 1);
682 BYTE* p;
684 len -= sizeof(*bfh);
685 ret = GlobalAlloc(GMEM_FIXED, len);
686 if (!ret || !(p = GlobalLock(ret)))
688 GlobalFree(ret);
689 return 0;
692 memcpy(p, bmi, len);
693 GlobalUnlock(ret);
696 return ret;
700 /**************************************************************************
701 * import_enhmetafile
703 * Import enhanced metafile data, converting it to CF_ENHMETAFILE.
705 static HANDLE import_enhmetafile(CFDataRef data)
707 HANDLE ret = 0;
708 CFIndex len = CFDataGetLength(data);
710 TRACE("data %s\n", debugstr_cf(data));
712 if (len)
713 ret = SetEnhMetaFileBits(len, (const BYTE*)CFDataGetBytePtr(data));
715 return ret;
719 /**************************************************************************
720 * import_metafilepict
722 * Import metafile picture data, converting it to CF_METAFILEPICT.
724 static HANDLE import_metafilepict(CFDataRef data)
726 HANDLE ret = 0;
727 CFIndex len = CFDataGetLength(data);
728 METAFILEPICT *mfp;
730 TRACE("data %s\n", debugstr_cf(data));
732 if (len >= sizeof(*mfp) && (ret = GlobalAlloc(GMEM_FIXED, sizeof(*mfp))))
734 const BYTE *bytes = (const BYTE*)CFDataGetBytePtr(data);
736 mfp = GlobalLock(ret);
737 memcpy(mfp, bytes, sizeof(*mfp));
738 mfp->hMF = SetMetaFileBitsEx(len - sizeof(*mfp), bytes + sizeof(*mfp));
739 GlobalUnlock(ret);
742 return ret;
746 /**************************************************************************
747 * import_nsfilenames_to_hdrop
749 * Import NSFilenamesPboardType data, converting the property-list-
750 * serialized array of path strings to CF_HDROP.
752 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data)
754 HDROP hdrop = NULL;
755 CFArrayRef names;
756 CFIndex count, i;
757 size_t len;
758 char *buffer = NULL;
759 WCHAR **paths = NULL;
760 DROPFILES* dropfiles;
761 UniChar* p;
763 TRACE("data %s\n", debugstr_cf(data));
765 names = (CFArrayRef)CFPropertyListCreateWithData(NULL, data, kCFPropertyListImmutable,
766 NULL, NULL);
767 if (!names || CFGetTypeID(names) != CFArrayGetTypeID())
769 WARN("failed to interpret data as a CFArray\n");
770 goto done;
773 count = CFArrayGetCount(names);
775 len = 0;
776 for (i = 0; i < count; i++)
778 CFIndex this_len;
779 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
780 TRACE(" %s\n", debugstr_cf(name));
781 if (CFGetTypeID(name) != CFStringGetTypeID())
783 WARN("non-string in array\n");
784 goto done;
787 this_len = CFStringGetMaximumSizeOfFileSystemRepresentation(name);
788 if (this_len > len)
789 len = this_len;
792 buffer = HeapAlloc(GetProcessHeap(), 0, len);
793 if (!buffer)
795 WARN("failed to allocate buffer for file-system representations\n");
796 goto done;
799 paths = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(paths[0]));
800 if (!paths)
802 WARN("failed to allocate array of DOS paths\n");
803 goto done;
806 for (i = 0; i < count; i++)
808 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
809 if (!CFStringGetFileSystemRepresentation(name, buffer, len))
811 WARN("failed to get file-system representation for %s\n", debugstr_cf(name));
812 goto done;
814 paths[i] = wine_get_dos_file_name(buffer);
815 if (!paths[i])
817 WARN("failed to get DOS path for %s\n", debugstr_a(buffer));
818 goto done;
822 len = 1; /* for the terminating null */
823 for (i = 0; i < count; i++)
824 len += strlenW(paths[i]) + 1;
826 hdrop = GlobalAlloc(GMEM_FIXED, sizeof(*dropfiles) + len * sizeof(WCHAR));
827 if (!hdrop || !(dropfiles = GlobalLock(hdrop)))
829 WARN("failed to allocate HDROP\n");
830 GlobalFree(hdrop);
831 hdrop = NULL;
832 goto done;
835 dropfiles->pFiles = sizeof(*dropfiles);
836 dropfiles->pt.x = 0;
837 dropfiles->pt.y = 0;
838 dropfiles->fNC = FALSE;
839 dropfiles->fWide = TRUE;
841 p = (WCHAR*)(dropfiles + 1);
842 for (i = 0; i < count; i++)
844 strcpyW(p, paths[i]);
845 p += strlenW(p) + 1;
847 *p = 0;
849 GlobalUnlock(hdrop);
851 done:
852 if (paths)
854 for (i = 0; i < count; i++)
855 HeapFree(GetProcessHeap(), 0, paths[i]);
856 HeapFree(GetProcessHeap(), 0, paths);
858 HeapFree(GetProcessHeap(), 0, buffer);
859 if (names) CFRelease(names);
860 return hdrop;
864 /**************************************************************************
865 * import_utf8_to_oemtext
867 * Import a UTF-8 string, converting the string to CF_OEMTEXT.
869 static HANDLE import_utf8_to_oemtext(CFDataRef data)
871 HANDLE unicode_handle = import_utf8_to_unicodetext(data);
872 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_OEMCP);
874 GlobalFree(unicode_handle);
875 return ret;
879 /**************************************************************************
880 * import_utf8_to_text
882 * Import a UTF-8 string, converting the string to CF_TEXT.
884 static HANDLE import_utf8_to_text(CFDataRef data)
886 HANDLE unicode_handle = import_utf8_to_unicodetext(data);
887 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_ACP);
889 GlobalFree(unicode_handle);
890 return ret;
894 /**************************************************************************
895 * import_utf8_to_unicodetext
897 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
899 static HANDLE import_utf8_to_unicodetext(CFDataRef data)
901 const BYTE *src;
902 unsigned long src_len;
903 unsigned long new_lines = 0;
904 LPSTR dst;
905 unsigned long i, j;
906 HANDLE unicode_handle = NULL;
908 src = CFDataGetBytePtr(data);
909 src_len = CFDataGetLength(data);
910 for (i = 0; i < src_len; i++)
912 if (src[i] == '\n')
913 new_lines++;
916 if ((dst = HeapAlloc(GetProcessHeap(), 0, src_len + new_lines + 1)))
918 UINT count;
920 for (i = 0, j = 0; i < src_len; i++)
922 if (src[i] == '\n')
923 dst[j++] = '\r';
925 dst[j++] = src[i];
927 dst[j] = 0;
929 count = MultiByteToWideChar(CP_UTF8, 0, dst, -1, NULL, 0);
930 unicode_handle = GlobalAlloc(GMEM_FIXED, count * sizeof(WCHAR));
932 if (unicode_handle)
934 WCHAR *textW = GlobalLock(unicode_handle);
935 MultiByteToWideChar(CP_UTF8, 0, dst, -1, textW, count);
936 GlobalUnlock(unicode_handle);
939 HeapFree(GetProcessHeap(), 0, dst);
942 return unicode_handle;
946 /**************************************************************************
947 * import_utf16_to_oemtext
949 * Import a UTF-16 string, converting the string to CF_OEMTEXT.
951 static HANDLE import_utf16_to_oemtext(CFDataRef data)
953 HANDLE unicode_handle = import_utf16_to_unicodetext(data);
954 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_OEMCP);
956 GlobalFree(unicode_handle);
957 return ret;
961 /**************************************************************************
962 * import_utf16_to_text
964 * Import a UTF-16 string, converting the string to CF_TEXT.
966 static HANDLE import_utf16_to_text(CFDataRef data)
968 HANDLE unicode_handle = import_utf16_to_unicodetext(data);
969 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_ACP);
971 GlobalFree(unicode_handle);
972 return ret;
976 /**************************************************************************
977 * import_utf16_to_unicodetext
979 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
981 static HANDLE import_utf16_to_unicodetext(CFDataRef data)
983 const WCHAR *src;
984 unsigned long src_len;
985 unsigned long new_lines = 0;
986 LPWSTR dst;
987 unsigned long i, j;
988 HANDLE unicode_handle;
990 src = (const WCHAR *)CFDataGetBytePtr(data);
991 src_len = CFDataGetLength(data) / sizeof(WCHAR);
992 for (i = 0; i < src_len; i++)
994 if (src[i] == '\n')
995 new_lines++;
996 else if (src[i] == '\r' && (i + 1 >= src_len || src[i + 1] != '\n'))
997 new_lines++;
1000 if ((unicode_handle = GlobalAlloc(GMEM_FIXED, (src_len + new_lines + 1) * sizeof(WCHAR))))
1002 dst = GlobalLock(unicode_handle);
1004 for (i = 0, j = 0; i < src_len; i++)
1006 if (src[i] == '\n')
1007 dst[j++] = '\r';
1009 dst[j++] = src[i];
1011 if (src[i] == '\r' && (i + 1 >= src_len || src[i + 1] != '\n'))
1012 dst[j++] = '\n';
1014 dst[j] = 0;
1016 GlobalUnlock(unicode_handle);
1019 return unicode_handle;
1023 /**************************************************************************
1024 * export_clipboard_data
1026 * Generic export clipboard data routine.
1028 static CFDataRef export_clipboard_data(HANDLE data)
1030 CFDataRef ret;
1031 UINT len;
1032 LPVOID src;
1034 len = GlobalSize(data);
1035 src = GlobalLock(data);
1036 if (!src) return NULL;
1038 ret = CFDataCreate(NULL, src, len);
1039 GlobalUnlock(data);
1041 return ret;
1045 /**************************************************************************
1046 * export_bitmap_to_bmp
1048 * Export CF_BITMAP to BMP file format.
1050 static CFDataRef export_bitmap_to_bmp(HANDLE data)
1052 CFDataRef ret = NULL;
1053 HGLOBAL dib;
1055 dib = create_dib_from_bitmap(data);
1056 if (dib)
1058 ret = export_dib_to_bmp(dib);
1059 GlobalFree(dib);
1062 return ret;
1066 /**************************************************************************
1067 * export_codepage_to_utf8
1069 * Export string data in a specified codepage to UTF-8.
1071 static CFDataRef export_codepage_to_utf8(HANDLE data, UINT cp)
1073 CFDataRef ret = NULL;
1074 const char* str;
1076 if ((str = GlobalLock(data)))
1078 HANDLE unicode = convert_text(str, GlobalSize(data), cp, -1);
1080 ret = export_unicodetext_to_utf8(unicode);
1082 GlobalFree(unicode);
1083 GlobalUnlock(data);
1086 return ret;
1090 /**************************************************************************
1091 * export_codepage_to_utf16
1093 * Export string data in a specified codepage to UTF-16.
1095 static CFDataRef export_codepage_to_utf16(HANDLE data, UINT cp)
1097 CFDataRef ret = NULL;
1098 const char* str;
1100 if ((str = GlobalLock(data)))
1102 HANDLE unicode = convert_text(str, GlobalSize(data), cp, -1);
1104 ret = export_unicodetext_to_utf16(unicode);
1106 GlobalFree(unicode);
1107 GlobalUnlock(data);
1110 return ret;
1114 /**************************************************************************
1115 * export_dib_to_bmp
1117 * Export CF_DIB or CF_DIBV5 to BMP file format. This just entails
1118 * prepending a BMP file format header to the data.
1120 static CFDataRef export_dib_to_bmp(HANDLE data)
1122 CFMutableDataRef ret = NULL;
1123 BYTE *dibdata;
1124 CFIndex len;
1125 BITMAPFILEHEADER bfh;
1127 dibdata = GlobalLock(data);
1128 if (!dibdata)
1129 return NULL;
1131 len = sizeof(bfh) + GlobalSize(data);
1132 ret = CFDataCreateMutable(NULL, len);
1133 if (ret)
1135 bfh.bfType = 0x4d42; /* "BM" */
1136 bfh.bfSize = len;
1137 bfh.bfReserved1 = 0;
1138 bfh.bfReserved2 = 0;
1139 bfh.bfOffBits = sizeof(bfh) + bitmap_info_size((BITMAPINFO*)dibdata, DIB_RGB_COLORS);
1140 CFDataAppendBytes(ret, (UInt8*)&bfh, sizeof(bfh));
1142 /* rest of bitmap is the same as the packed dib */
1143 CFDataAppendBytes(ret, (UInt8*)dibdata, len - sizeof(bfh));
1146 GlobalUnlock(data);
1148 return ret;
1152 /**************************************************************************
1153 * export_enhmetafile
1155 * Export an enhanced metafile to data.
1157 static CFDataRef export_enhmetafile(HANDLE data)
1159 CFMutableDataRef ret = NULL;
1160 unsigned int size = GetEnhMetaFileBits(data, 0, NULL);
1162 TRACE("data %p\n", data);
1164 ret = CFDataCreateMutable(NULL, size);
1165 if (ret)
1167 CFDataSetLength(ret, size);
1168 GetEnhMetaFileBits(data, size, (BYTE*)CFDataGetMutableBytePtr(ret));
1171 TRACE(" -> %s\n", debugstr_cf(ret));
1172 return ret;
1176 /**************************************************************************
1177 * export_hdrop_to_filenames
1179 * Export CF_HDROP to NSFilenamesPboardType data, which is a CFArray of
1180 * CFStrings (holding Unix paths) which is serialized as a property list.
1182 static CFDataRef export_hdrop_to_filenames(HANDLE data)
1184 CFDataRef ret = NULL;
1185 DROPFILES *dropfiles;
1186 CFMutableArrayRef filenames = NULL;
1187 void *p;
1188 WCHAR *buffer = NULL;
1189 size_t buffer_len = 0;
1191 TRACE("data %p\n", data);
1193 if (!(dropfiles = GlobalLock(data)))
1195 WARN("failed to lock data %p\n", data);
1196 goto done;
1199 filenames = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1200 if (!filenames)
1202 WARN("failed to create filenames array\n");
1203 goto done;
1206 p = (char*)dropfiles + dropfiles->pFiles;
1207 while (dropfiles->fWide ? *(WCHAR*)p : *(char*)p)
1209 char *unixname;
1210 CFStringRef filename;
1212 TRACE(" %s\n", dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1214 if (dropfiles->fWide)
1215 unixname = wine_get_unix_file_name(p);
1216 else
1218 int len = MultiByteToWideChar(CP_ACP, 0, p, -1, NULL, 0);
1219 if (len)
1221 if (len > buffer_len)
1223 HeapFree(GetProcessHeap(), 0, buffer);
1224 buffer_len = len * 2;
1225 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_len * sizeof(*buffer));
1228 MultiByteToWideChar(CP_ACP, 0, p, -1, buffer, buffer_len);
1229 unixname = wine_get_unix_file_name(buffer);
1231 else
1232 unixname = NULL;
1234 if (!unixname)
1236 WARN("failed to convert DOS path to Unix: %s\n",
1237 dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1238 goto done;
1241 if (dropfiles->fWide)
1242 p = (WCHAR*)p + strlenW(p) + 1;
1243 else
1244 p = (char*)p + strlen(p) + 1;
1246 filename = CFStringCreateWithFileSystemRepresentation(NULL, unixname);
1247 HeapFree(GetProcessHeap(), 0, unixname);
1248 if (!filename)
1250 WARN("failed to create CFString from Unix path %s\n", debugstr_a(unixname));
1251 goto done;
1254 CFArrayAppendValue(filenames, filename);
1255 CFRelease(filename);
1258 ret = CFPropertyListCreateData(NULL, filenames, kCFPropertyListXMLFormat_v1_0, 0, NULL);
1260 done:
1261 HeapFree(GetProcessHeap(), 0, buffer);
1262 GlobalUnlock(data);
1263 if (filenames) CFRelease(filenames);
1264 TRACE(" -> %s\n", debugstr_cf(ret));
1265 return ret;
1269 /**************************************************************************
1270 * export_metafilepict
1272 * Export a metafile to data.
1274 static CFDataRef export_metafilepict(HANDLE data)
1276 CFMutableDataRef ret = NULL;
1277 METAFILEPICT *mfp = GlobalLock(data);
1278 unsigned int size = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
1280 TRACE("data %p\n", data);
1282 ret = CFDataCreateMutable(NULL, sizeof(*mfp) + size);
1283 if (ret)
1285 CFDataAppendBytes(ret, (UInt8*)mfp, sizeof(*mfp));
1286 CFDataIncreaseLength(ret, size);
1287 GetMetaFileBitsEx(mfp->hMF, size, (BYTE*)CFDataGetMutableBytePtr(ret) + sizeof(*mfp));
1290 GlobalUnlock(data);
1291 TRACE(" -> %s\n", debugstr_cf(ret));
1292 return ret;
1296 /**************************************************************************
1297 * export_oemtext_to_utf8
1299 * Export CF_OEMTEXT to UTF-8.
1301 static CFDataRef export_oemtext_to_utf8(HANDLE data)
1303 return export_codepage_to_utf8(data, CP_OEMCP);
1307 /**************************************************************************
1308 * export_oemtext_to_utf16
1310 * Export CF_OEMTEXT to UTF-16.
1312 static CFDataRef export_oemtext_to_utf16(HANDLE data)
1314 return export_codepage_to_utf16(data, CP_OEMCP);
1318 /**************************************************************************
1319 * export_text_to_utf8
1321 * Export CF_TEXT to UTF-8.
1323 static CFDataRef export_text_to_utf8(HANDLE data)
1325 return export_codepage_to_utf8(data, CP_ACP);
1329 /**************************************************************************
1330 * export_text_to_utf16
1332 * Export CF_TEXT to UTF-16.
1334 static CFDataRef export_text_to_utf16(HANDLE data)
1336 return export_codepage_to_utf16(data, CP_ACP);
1340 /**************************************************************************
1341 * export_unicodetext_to_utf8
1343 * Export CF_UNICODETEXT to UTF-8.
1345 static CFDataRef export_unicodetext_to_utf8(HANDLE data)
1347 CFMutableDataRef ret;
1348 LPVOID src;
1349 INT dst_len;
1351 src = GlobalLock(data);
1352 if (!src) return NULL;
1354 dst_len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
1355 if (dst_len) dst_len--; /* Leave off null terminator. */
1356 ret = CFDataCreateMutable(NULL, dst_len);
1357 if (ret)
1359 LPSTR dst;
1360 int i, j;
1362 CFDataSetLength(ret, dst_len);
1363 dst = (LPSTR)CFDataGetMutableBytePtr(ret);
1364 WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_len, NULL, NULL);
1366 /* Remove carriage returns */
1367 for (i = 0, j = 0; i < dst_len; i++)
1369 if (dst[i] == '\r' &&
1370 (i + 1 >= dst_len || dst[i + 1] == '\n' || dst[i + 1] == '\0'))
1371 continue;
1372 dst[j++] = dst[i];
1374 CFDataSetLength(ret, j);
1376 GlobalUnlock(data);
1378 return ret;
1382 /**************************************************************************
1383 * export_unicodetext_to_utf16
1385 * Export CF_UNICODETEXT to UTF-16.
1387 static CFDataRef export_unicodetext_to_utf16(HANDLE data)
1389 CFMutableDataRef ret;
1390 const WCHAR *src;
1391 INT src_len;
1393 src = GlobalLock(data);
1394 if (!src) return NULL;
1396 src_len = GlobalSize(data) / sizeof(WCHAR);
1397 if (src_len) src_len--; /* Leave off null terminator. */
1398 ret = CFDataCreateMutable(NULL, src_len * sizeof(WCHAR));
1399 if (ret)
1401 LPWSTR dst;
1402 int i, j;
1404 CFDataSetLength(ret, src_len * sizeof(WCHAR));
1405 dst = (LPWSTR)CFDataGetMutableBytePtr(ret);
1407 /* Remove carriage returns */
1408 for (i = 0, j = 0; i < src_len; i++)
1410 if (src[i] == '\r' &&
1411 (i + 1 >= src_len || src[i + 1] == '\n' || src[i + 1] == '\0'))
1412 continue;
1413 dst[j++] = src[i];
1415 CFDataSetLength(ret, j * sizeof(WCHAR));
1417 GlobalUnlock(data);
1419 return ret;
1423 /**************************************************************************
1424 * get_clipboard_info
1426 static BOOL get_clipboard_info(LPCLIPBOARDINFO cbinfo)
1428 BOOL ret = FALSE;
1430 SERVER_START_REQ(set_clipboard_info)
1432 req->flags = 0;
1434 if (wine_server_call_err(req))
1436 ERR("Failed to get clipboard owner.\n");
1438 else
1440 cbinfo->hwnd_owner = wine_server_ptr_handle(reply->old_owner);
1441 cbinfo->flags = reply->flags;
1443 ret = TRUE;
1446 SERVER_END_REQ;
1448 return ret;
1452 /**************************************************************************
1453 * release_ownership
1455 static BOOL release_ownership(void)
1457 BOOL ret = FALSE;
1459 SERVER_START_REQ(set_clipboard_info)
1461 req->flags = SET_CB_RELOWNER | SET_CB_SEQNO;
1463 if (wine_server_call_err(req))
1464 ERR("Failed to set clipboard.\n");
1465 else
1466 ret = TRUE;
1468 SERVER_END_REQ;
1470 return ret;
1474 /**************************************************************************
1475 * macdrv_get_pasteboard_data
1477 HANDLE macdrv_get_pasteboard_data(CFTypeRef pasteboard, UINT desired_format)
1479 CFArrayRef types;
1480 CFIndex count;
1481 CFIndex i;
1482 CFStringRef type, best_type;
1483 WINE_CLIPFORMAT* best_format = NULL;
1484 HANDLE data = NULL;
1486 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1488 types = macdrv_copy_pasteboard_types(pasteboard);
1489 if (!types)
1491 WARN("Failed to copy pasteboard types\n");
1492 return NULL;
1495 count = CFArrayGetCount(types);
1496 TRACE("got %ld types\n", count);
1498 for (i = 0; (!best_format || best_format->synthesized) && i < count; i++)
1500 WINE_CLIPFORMAT* format;
1502 type = CFArrayGetValueAtIndex(types, i);
1504 format = NULL;
1505 while ((!best_format || best_format->synthesized) && (format = format_for_type(format, type)))
1507 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format ? format->format_id : 0));
1509 if (format->format_id == desired_format)
1511 /* The best format is the matching one which is not synthesized. Failing that,
1512 the best format is the first matching synthesized format. */
1513 if (!format->synthesized || !best_format)
1515 best_type = type;
1516 best_format = format;
1522 if (best_format)
1524 CFDataRef pasteboard_data = macdrv_copy_pasteboard_data(pasteboard, best_type);
1526 TRACE("got pasteboard data for type %s: %s\n", debugstr_cf(best_type), debugstr_cf(pasteboard_data));
1528 if (pasteboard_data)
1530 data = best_format->import_func(pasteboard_data);
1531 CFRelease(pasteboard_data);
1535 CFRelease(types);
1536 TRACE(" -> %p\n", data);
1537 return data;
1541 /**************************************************************************
1542 * macdrv_pasteboard_has_format
1544 BOOL macdrv_pasteboard_has_format(CFTypeRef pasteboard, UINT desired_format)
1546 CFArrayRef types;
1547 int count;
1548 UINT i;
1549 BOOL found = FALSE;
1551 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1553 types = macdrv_copy_pasteboard_types(pasteboard);
1554 if (!types)
1556 WARN("Failed to copy pasteboard types\n");
1557 return FALSE;
1560 count = CFArrayGetCount(types);
1561 TRACE("got %d types\n", count);
1563 for (i = 0; !found && i < count; i++)
1565 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1566 WINE_CLIPFORMAT* format;
1568 format = NULL;
1569 while (!found && (format = format_for_type(format, type)))
1571 TRACE("for type %s got format %s\n", debugstr_cf(type), debugstr_format(format->format_id));
1573 if (format->format_id == desired_format)
1574 found = TRUE;
1578 CFRelease(types);
1579 TRACE(" -> %d\n", found);
1580 return found;
1584 /**************************************************************************
1585 * macdrv_copy_pasteboard_formats
1587 CFArrayRef macdrv_copy_pasteboard_formats(CFTypeRef pasteboard)
1589 CFArrayRef types;
1590 CFIndex count;
1591 CFMutableArrayRef formats;
1592 CFIndex i;
1593 WINE_CLIPFORMAT* format;
1595 TRACE("pasteboard %p\n", pasteboard);
1597 types = macdrv_copy_pasteboard_types(pasteboard);
1598 if (!types)
1600 WARN("Failed to copy pasteboard types\n");
1601 return NULL;
1604 count = CFArrayGetCount(types);
1605 TRACE("got %ld types\n", count);
1607 if (!count)
1609 CFRelease(types);
1610 return NULL;
1613 formats = CFArrayCreateMutable(NULL, 0, NULL);
1614 if (!formats)
1616 WARN("Failed to allocate formats array\n");
1617 CFRelease(types);
1618 return NULL;
1621 for (i = 0; i < count; i++)
1623 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1624 BOOL found = FALSE;
1626 format = NULL;
1627 while ((format = format_for_type(format, type)))
1629 /* Suppose type is "public.utf8-plain-text". format->format_id will be each of
1630 CF_TEXT, CF_OEMTEXT, and CF_UNICODETEXT in turn. We want to look up the natural
1631 type for each of those IDs (e.g. CF_TEXT -> "org.winehq.builtin.text") and then see
1632 if that type is present in the pasteboard. If it is, then we don't want to add the
1633 format to the list yet because it would be out of order.
1635 For example, if a Mac app put "public.utf8-plain-text" and "public.tiff" on the
1636 pasteboard, then we want the Win32 clipboard formats to be CF_TEXT, CF_OEMTEXT, and
1637 CF_UNICODETEXT, and CF_TIFF, in that order. All of the text formats belong before
1638 CF_TIFF because the Mac app expressed that text was "better" than the TIFF. In
1639 this case, as soon as we encounter "public.utf8-plain-text" we should add all of
1640 the associated text format IDs.
1642 But if a Wine process put "org.winehq.builtin.unicodetext",
1643 "public.utf8-plain-text", "public.utf16-plain-text", and "public.tiff", then we
1644 want the clipboard formats to be CF_UNICODETEXT, CF_TIFF, CF_TEXT, and CF_OEMTEXT,
1645 in that order. The Windows program presumably added CF_UNICODETEXT and CF_TIFF.
1646 We're synthesizing CF_TEXT and CF_OEMTEXT from CF_UNICODETEXT but we want them to
1647 come after the non-synthesized CF_TIFF. In this case, we don't want to add the
1648 text formats upon encountering "public.utf8-plain-text",
1650 We tell the two cases apart by seeing that one of the natural types for the text
1651 formats (i.e. "org.winehq.builtin.unicodetext") is present on the pasteboard.
1652 "found" indicates that. */
1654 if (!format->synthesized)
1656 TRACE("for type %s got primary format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1657 CFArrayAppendValue(formats, (void*)format->format_id);
1658 found = TRUE;
1660 else if (!found && format->natural_format &&
1661 CFArrayContainsValue(types, CFRangeMake(0, count), format->natural_format->type))
1663 TRACE("for type %s deferring synthesized formats because type %s is also present\n",
1664 debugstr_cf(type), debugstr_cf(format->natural_format->type));
1665 found = TRUE;
1669 if (!found)
1671 while ((format = format_for_type(format, type)))
1673 /* Don't override a real value with a synthesized value. */
1674 if (!CFArrayContainsValue(formats, CFRangeMake(0, CFArrayGetCount(formats)), (void*)format->format_id))
1676 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1677 CFArrayAppendValue(formats, (void*)format->format_id);
1683 /* Now go back through the types adding the synthesized formats that we deferred before. */
1684 for (i = 0; i < count; i++)
1686 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1688 format = NULL;
1689 while ((format = format_for_type(format, type)))
1691 if (format->synthesized)
1693 /* Don't override a real value with a synthesized value. */
1694 if (!CFArrayContainsValue(formats, CFRangeMake(0, CFArrayGetCount(formats)), (void*)format->format_id))
1696 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1697 CFArrayAppendValue(formats, (void*)format->format_id);
1703 CFRelease(types);
1705 TRACE(" -> %s\n", debugstr_cf(formats));
1706 return formats;
1710 /**************************************************************************
1711 * check_clipboard_ownership
1713 static void check_clipboard_ownership(HWND *owner)
1715 CLIPBOARDINFO cbinfo;
1717 if (owner) *owner = NULL;
1719 /* If Wine thinks we're the clipboard owner but Mac OS X thinks we're not
1720 the pasteboard owner, update Wine. */
1721 if (get_clipboard_info(&cbinfo) && (cbinfo.flags & CB_PROCESS))
1723 if (!(cbinfo.flags & CB_OPEN) && !macdrv_is_pasteboard_owner())
1725 TRACE("Lost clipboard ownership\n");
1727 if (OpenClipboard(cbinfo.hwnd_owner))
1729 /* Destroy private objects */
1730 SendMessageW(cbinfo.hwnd_owner, WM_DESTROYCLIPBOARD, 0, 0);
1732 /* Give up ownership of the windows clipboard */
1733 release_ownership();
1734 CloseClipboard();
1737 else if (owner)
1738 *owner = cbinfo.hwnd_owner;
1743 /**************************************************************************
1744 * Mac User Driver Clipboard Exports
1745 **************************************************************************/
1748 /**************************************************************************
1749 * CountClipboardFormats (MACDRV.@)
1751 INT CDECL macdrv_CountClipboardFormats(void)
1753 CFMutableSetRef seen_formats;
1754 CFArrayRef types;
1755 CFIndex count;
1756 CFIndex i;
1757 INT ret = 0;
1759 TRACE("()\n");
1760 check_clipboard_ownership(NULL);
1762 seen_formats = CFSetCreateMutable(NULL, 0, NULL);
1763 if (!seen_formats)
1765 WARN("Failed to allocate set to track seen formats\n");
1766 return 0;
1769 types = macdrv_copy_pasteboard_types(NULL);
1770 if (!types)
1772 WARN("Failed to copy pasteboard types\n");
1773 CFRelease(seen_formats);
1774 return 0;
1777 count = CFArrayGetCount(types);
1778 TRACE("got %ld types\n", count);
1780 for (i = 0; i < count; i++)
1782 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1783 WINE_CLIPFORMAT* format;
1785 format = NULL;
1786 while ((format = format_for_type(format, type)))
1788 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1790 if (!CFSetContainsValue(seen_formats, (void*)format->format_id))
1792 ret++;
1793 CFSetAddValue(seen_formats, (void*)format->format_id);
1798 CFRelease(types);
1799 CFRelease(seen_formats);
1800 TRACE(" -> %d\n", ret);
1801 return ret;
1805 /**************************************************************************
1806 * EmptyClipboard (MACDRV.@)
1808 * Empty cached clipboard data.
1810 void CDECL macdrv_EmptyClipboard(void)
1812 TRACE("()\n");
1813 check_clipboard_ownership(NULL);
1814 macdrv_clear_pasteboard();
1818 /**************************************************************************
1819 * EndClipboardUpdate (MACDRV.@)
1821 void CDECL macdrv_EndClipboardUpdate(void)
1823 TRACE("()\n");
1824 check_clipboard_ownership(NULL);
1828 /**************************************************************************
1829 * EnumClipboardFormats (MACDRV.@)
1831 UINT CDECL macdrv_EnumClipboardFormats(UINT prev_format)
1833 CFArrayRef formats;
1834 CFIndex count;
1835 CFIndex i;
1836 UINT ret = 0;
1838 TRACE("prev_format %s\n", debugstr_format(prev_format));
1839 check_clipboard_ownership(NULL);
1841 formats = macdrv_copy_pasteboard_formats(NULL);
1842 if (formats)
1844 count = CFArrayGetCount(formats);
1845 if (prev_format)
1847 i = CFArrayGetFirstIndexOfValue(formats, CFRangeMake(0, count), (void*)prev_format);
1848 if (i != kCFNotFound)
1849 i++;
1851 else
1852 i = 0;
1854 if (i != kCFNotFound && i < count)
1855 ret = (UINT)CFArrayGetValueAtIndex(formats, i);
1857 CFRelease(formats);
1860 TRACE(" -> %u\n", ret);
1861 return ret;
1865 /**************************************************************************
1866 * GetClipboardData (MACDRV.@)
1868 HANDLE CDECL macdrv_GetClipboardData(UINT desired_format)
1870 check_clipboard_ownership(NULL);
1872 return macdrv_get_pasteboard_data(NULL, desired_format);
1876 /**************************************************************************
1877 * IsClipboardFormatAvailable (MACDRV.@)
1879 BOOL CDECL macdrv_IsClipboardFormatAvailable(UINT desired_format)
1881 check_clipboard_ownership(NULL);
1882 return macdrv_pasteboard_has_format(NULL, desired_format);
1886 /**************************************************************************
1887 * SetClipboardData (MACDRV.@)
1889 BOOL CDECL macdrv_SetClipboardData(UINT format_id, HANDLE data, BOOL owner)
1891 HWND hwnd_owner;
1892 macdrv_window window;
1893 WINE_CLIPFORMAT *format;
1894 CFDataRef cfdata = NULL;
1896 check_clipboard_ownership(&hwnd_owner);
1897 window = macdrv_get_cocoa_window(GetAncestor(hwnd_owner, GA_ROOT), FALSE);
1898 TRACE("format_id %s data %p owner %d hwnd_owner %p window %p)\n", debugstr_format(format_id), data, owner, hwnd_owner, window);
1900 format = natural_format_for_format(format_id);
1901 if (!format && !(format = insert_clipboard_format(format_id, NULL)))
1903 WARN("Failed to register clipboard format %s\n", debugstr_format(format_id));
1904 return FALSE;
1907 /* Export the data to the Mac pasteboard. */
1908 if (data)
1910 if (!format->export_func || !(cfdata = format->export_func(data)))
1912 WARN("Failed to export %s data to type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1913 return FALSE;
1917 if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1918 TRACE("Set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1919 else
1921 WARN("Failed to set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1922 if (cfdata) CFRelease(cfdata);
1923 return FALSE;
1926 if (cfdata) CFRelease(cfdata);
1928 /* Find any other formats for this format_id (the exportable synthesized ones). */
1929 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1931 if (format->format_id == format_id && format->synthesized && format->export_func)
1933 /* We have a synthesized format for this format ID. Add its type to the pasteboard. */
1934 TRACE("Synthesized from format %s: type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1936 if (data)
1938 cfdata = format->export_func(data);
1939 if (!cfdata)
1941 WARN("Failed to export %s data to type %s\n", debugstr_format(format->format_id), debugstr_cf(format->type));
1942 continue;
1945 else
1946 cfdata = NULL;
1948 if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1949 TRACE(" ... set pasteboard data: %s\n", debugstr_cf(cfdata));
1950 else
1951 WARN(" ... failed to set pasteboard data: %s\n", debugstr_cf(cfdata));
1953 if (cfdata) CFRelease(cfdata);
1957 if (data)
1959 /* FIXME: According to MSDN, the caller is entitled to lock and read from
1960 data until CloseClipboard is called. So, we should defer this cleanup. */
1961 if ((format_id >= CF_GDIOBJFIRST && format_id <= CF_GDIOBJLAST) ||
1962 format_id == CF_BITMAP ||
1963 format_id == CF_DIB ||
1964 format_id == CF_PALETTE)
1966 DeleteObject(data);
1968 else if (format_id == CF_METAFILEPICT)
1970 DeleteMetaFile(((METAFILEPICT *)GlobalLock(data))->hMF);
1971 GlobalFree(data);
1973 else if (format_id == CF_ENHMETAFILE)
1975 DeleteEnhMetaFile(data);
1977 else if (format_id < CF_PRIVATEFIRST || CF_PRIVATELAST < format_id)
1979 GlobalFree(data);
1983 return TRUE;
1987 /**************************************************************************
1988 * MACDRV Private Clipboard Exports
1989 **************************************************************************/
1992 /**************************************************************************
1993 * macdrv_clipboard_process_attach
1995 void macdrv_clipboard_process_attach(void)
1997 UINT i;
1998 WINE_CLIPFORMAT *format;
2000 /* Register built-in formats */
2001 for (i = 0; i < sizeof(builtin_format_ids)/sizeof(builtin_format_ids[0]); i++)
2003 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
2004 format->format_id = builtin_format_ids[i].id;
2005 format->type = CFRetain(builtin_format_ids[i].type);
2006 format->import_func = builtin_format_ids[i].import;
2007 format->export_func = builtin_format_ids[i].export;
2008 format->synthesized = builtin_format_ids[i].synthesized;
2009 format->natural_format = NULL;
2010 list_add_tail(&format_list, &format->entry);
2013 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
2015 if (format->synthesized)
2016 format->natural_format = natural_format_for_format(format->format_id);
2019 /* Register known mappings between Windows formats and Mac types */
2020 for (i = 0; i < sizeof(builtin_format_names)/sizeof(builtin_format_names[0]); i++)
2022 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
2023 format->format_id = RegisterClipboardFormatW(builtin_format_names[i].name);
2024 format->type = CFRetain(builtin_format_names[i].type);
2025 format->import_func = builtin_format_names[i].import;
2026 format->export_func = builtin_format_names[i].export;
2027 format->synthesized = FALSE;
2028 format->natural_format = NULL;
2029 list_add_tail(&format_list, &format->entry);
2034 /**************************************************************************
2035 * query_pasteboard_data
2037 BOOL query_pasteboard_data(HWND hwnd, CFStringRef type)
2039 BOOL ret = FALSE;
2040 CLIPBOARDINFO cbinfo;
2041 WINE_CLIPFORMAT* format;
2042 CFArrayRef types = NULL;
2043 CFRange range;
2045 TRACE("hwnd %p type %s\n", hwnd, debugstr_cf(type));
2047 if (get_clipboard_info(&cbinfo))
2048 hwnd = cbinfo.hwnd_owner;
2050 format = NULL;
2051 while ((format = format_for_type(format, type)))
2053 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
2055 if (!format->synthesized)
2057 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(format->format_id), hwnd);
2058 SendMessageW(hwnd, WM_RENDERFORMAT, format->format_id, 0);
2059 ret = TRUE;
2060 goto done;
2063 if (!types)
2065 types = macdrv_copy_pasteboard_types(NULL);
2066 if (!types)
2068 WARN("Failed to copy pasteboard types\n");
2069 break;
2072 range = CFRangeMake(0, CFArrayGetCount(types));
2075 /* The type maps to a synthesized format. Now look up what type that format maps to natively
2076 (not synthesized). For example, if type is "public.utf8-plain-text", then this format may
2077 have an ID of CF_TEXT. From CF_TEXT, we want to find "org.winehq.builtin.text" to see if
2078 that type is present in the pasteboard. If it is, then the app must have promised it and
2079 we can ask it to render it. (If it had put it on the clipboard immediately, then the
2080 pasteboard would also have data for "public.utf8-plain-text" and we wouldn't be here.) If
2081 "org.winehq.builtin.text" is not on the pasteboard, then one of the other text formats is
2082 presumably responsible for the promise that we're trying to satisfy, so we keep looking. */
2083 if (format->natural_format && CFArrayContainsValue(types, range, format->natural_format->type))
2085 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(format->format_id), hwnd);
2086 SendMessageW(hwnd, WM_RENDERFORMAT, format->format_id, 0);
2087 ret = TRUE;
2088 goto done;
2092 done:
2093 if (types) CFRelease(types);
2095 return ret;