winemac: Extract new function from macdrv_IsClipboardFormatAvailable() parameterized...
[wine/wine-gecko.git] / dlls / winemac.drv / clipboard.c
blobfa4857b998fb87d90164ceaaaa2fa77294e412e8
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
54 struct list entry;
55 UINT format_id;
56 CFStringRef type;
57 DRVIMPORTFUNC import_func;
58 DRVEXPORTFUNC export_func;
59 BOOL synthesized;
60 } WINE_CLIPFORMAT;
63 /**************************************************************************
64 * Constants
65 **************************************************************************/
68 /**************************************************************************
69 * Forward Function Declarations
70 **************************************************************************/
72 static HANDLE import_clipboard_data(CFDataRef data);
73 static HANDLE import_bmp_to_bitmap(CFDataRef data);
74 static HANDLE import_bmp_to_dib(CFDataRef data);
75 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data);
76 static HANDLE import_oemtext_to_text(CFDataRef data);
77 static HANDLE import_oemtext_to_unicodetext(CFDataRef data);
78 static HANDLE import_text_to_oemtext(CFDataRef data);
79 static HANDLE import_text_to_unicodetext(CFDataRef data);
80 static HANDLE import_unicodetext_to_oemtext(CFDataRef data);
81 static HANDLE import_unicodetext_to_text(CFDataRef data);
82 static HANDLE import_utf8_to_oemtext(CFDataRef data);
83 static HANDLE import_utf8_to_text(CFDataRef data);
84 static HANDLE import_utf8_to_unicodetext(CFDataRef data);
86 static CFDataRef export_clipboard_data(HANDLE data);
87 static CFDataRef export_bitmap_to_bmp(HANDLE data);
88 static CFDataRef export_dib_to_bmp(HANDLE data);
89 static CFDataRef export_hdrop_to_filenames(HANDLE data);
90 static CFDataRef export_oemtext_to_utf8(HANDLE data);
91 static CFDataRef export_text_to_utf8(HANDLE data);
92 static CFDataRef export_unicodetext_to_utf8(HANDLE data);
95 /**************************************************************************
96 * Static Variables
97 **************************************************************************/
99 /* Clipboard formats */
100 static struct list format_list = LIST_INIT(format_list);
102 /* There are two naming schemes involved and we want to have a mapping between
103 them. There are Win32 clipboard format names and there are Mac pasteboard
104 types.
106 The Win32 standard clipboard formats don't have names, but they are associated
107 with Mac pasteboard types through the following tables, which are used to
108 initialize the format_list. Where possible, the standard clipboard formats
109 are mapped to predefined pasteboard type UTIs. Otherwise, we create Wine-
110 specific types of the form "org.winehq.builtin.<format>", where <format> is
111 the name of the symbolic constant for the format minus "CF_" and lowercased.
112 E.g. CF_BITMAP -> org.winehq.builtin.bitmap.
114 Win32 clipboard formats which originate in a Windows program may be registered
115 with an arbitrary name. We construct a Mac pasteboard type from these by
116 prepending "org.winehq.registered." to the registered name.
118 Likewise, Mac pasteboard types which originate in other apps may have
119 arbitrary type strings. We construct a Win32 clipboard format name from
120 these by prepending "org.winehq.mac-type." to the Mac pasteboard type.
122 Summary:
123 Win32 clipboard format names:
124 <none> standard clipboard format; maps via
125 format_list to either a predefined Mac UTI
126 or org.winehq.builtin.<format>.
127 org.winehq.mac-type.<Mac type> representation of Mac type in Win32 land;
128 maps to <Mac type>
129 <other> name registered within Win32 land; maps to
130 org.winehq.registered.<other>
131 Mac pasteboard type names:
132 org.winehq.builtin.<format ID> representation of Win32 standard clipboard
133 format for which there was no corresponding
134 predefined Mac UTI; maps via format_list
135 org.winehq.registered.<format name> representation of Win32 registered
136 clipboard format name; maps to <format name>
137 <other> Mac pasteboard type originating with system
138 or other apps; either maps via format_list
139 to a standard clipboard format or maps to
140 org.winehq.mac-type.<other>
143 static const struct
145 UINT id;
146 CFStringRef type;
147 DRVIMPORTFUNC import;
148 DRVEXPORTFUNC export;
149 BOOL synthesized;
150 } builtin_format_ids[] =
152 { CF_DIBV5, CFSTR("org.winehq.builtin.dibv5"), import_clipboard_data, export_clipboard_data, FALSE },
153 { CF_DIF, CFSTR("org.winehq.builtin.dif"), import_clipboard_data, export_clipboard_data, FALSE },
154 { CF_DSPBITMAP, CFSTR("org.winehq.builtin.dspbitmap"), import_clipboard_data, export_clipboard_data, FALSE },
155 { CF_DSPENHMETAFILE, CFSTR("org.winehq.builtin.dspenhmetafile"), import_clipboard_data, export_clipboard_data, FALSE },
156 { CF_DSPMETAFILEPICT, CFSTR("org.winehq.builtin.dspmetafilepict"), import_clipboard_data, export_clipboard_data, FALSE },
157 { CF_DSPTEXT, CFSTR("org.winehq.builtin.dsptext"), import_clipboard_data, export_clipboard_data, FALSE },
158 { CF_LOCALE, CFSTR("org.winehq.builtin.locale"), import_clipboard_data, export_clipboard_data, FALSE },
159 { CF_OWNERDISPLAY, CFSTR("org.winehq.builtin.ownerdisplay"), import_clipboard_data, export_clipboard_data, FALSE },
160 { CF_PALETTE, CFSTR("org.winehq.builtin.palette"), import_clipboard_data, export_clipboard_data, FALSE },
161 { CF_PENDATA, CFSTR("org.winehq.builtin.pendata"), import_clipboard_data, export_clipboard_data, FALSE },
162 { CF_RIFF, CFSTR("org.winehq.builtin.riff"), import_clipboard_data, export_clipboard_data, FALSE },
163 { CF_SYLK, CFSTR("org.winehq.builtin.sylk"), import_clipboard_data, export_clipboard_data, FALSE },
164 { CF_TIFF, CFSTR("public.tiff"), import_clipboard_data, export_clipboard_data, FALSE },
165 { CF_WAVE, CFSTR("com.microsoft.waveform-audio"), import_clipboard_data, export_clipboard_data, FALSE },
167 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.unicodetext"), import_clipboard_data, export_clipboard_data, FALSE },
168 { CF_TEXT, CFSTR("org.winehq.builtin.unicodetext"), import_unicodetext_to_text, NULL, TRUE },
169 { CF_OEMTEXT, CFSTR("org.winehq.builtin.unicodetext"), import_unicodetext_to_oemtext, NULL, TRUE },
171 { CF_TEXT, CFSTR("org.winehq.builtin.text"), import_clipboard_data, export_clipboard_data, FALSE },
172 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.text"), import_text_to_unicodetext, NULL, TRUE },
173 { CF_OEMTEXT, CFSTR("org.winehq.builtin.text"), import_text_to_oemtext, NULL, TRUE },
175 { CF_OEMTEXT, CFSTR("org.winehq.builtin.oemtext"), import_clipboard_data, export_clipboard_data, FALSE },
176 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.oemtext"), import_oemtext_to_unicodetext, NULL, TRUE },
177 { CF_TEXT, CFSTR("org.winehq.builtin.oemtext"), import_oemtext_to_text, NULL, TRUE },
179 { CF_UNICODETEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_unicodetext, export_unicodetext_to_utf8, TRUE },
180 { CF_TEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_text, export_text_to_utf8, TRUE },
181 { CF_OEMTEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_oemtext, export_oemtext_to_utf8, TRUE },
183 { CF_DIB, CFSTR("org.winehq.builtin.dib"), import_clipboard_data, export_clipboard_data, FALSE },
184 { CF_DIB, CFSTR("com.microsoft.bmp"), import_bmp_to_dib, export_dib_to_bmp, TRUE },
186 { CF_BITMAP, CFSTR("org.winehq.builtin.bitmap"), import_bmp_to_bitmap, export_bitmap_to_bmp, FALSE },
187 { CF_BITMAP, CFSTR("com.microsoft.bmp"), import_bmp_to_bitmap, export_bitmap_to_bmp, TRUE },
189 { CF_HDROP, CFSTR("org.winehq.builtin.hdrop"), import_clipboard_data, export_clipboard_data, FALSE },
190 { CF_HDROP, CFSTR("NSFilenamesPboardType"), import_nsfilenames_to_hdrop, export_hdrop_to_filenames, TRUE },
193 static const WCHAR wszRichTextFormat[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
194 static const WCHAR wszGIF[] = {'G','I','F',0};
195 static const WCHAR wszJFIF[] = {'J','F','I','F',0};
196 static const WCHAR wszPNG[] = {'P','N','G',0};
197 static const WCHAR wszHTMLFormat[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
198 static const struct
200 LPCWSTR name;
201 CFStringRef type;
202 } builtin_format_names[] =
204 { wszRichTextFormat, CFSTR("public.rtf") },
205 { wszGIF, CFSTR("com.compuserve.gif") },
206 { wszJFIF, CFSTR("public.jpeg") },
207 { wszPNG, CFSTR("public.png") },
208 { wszHTMLFormat, CFSTR("public.html") },
211 /* The prefix prepended to an external Mac pasteboard type to make a Win32 clipboard format name. org.winehq.mac-type. */
212 static const WCHAR mac_type_name_prefix[] = {'o','r','g','.','w','i','n','e','h','q','.','m','a','c','-','t','y','p','e','.',0};
214 /* The prefix prepended to a Win32 clipboard format name to make a Mac pasteboard type. */
215 static const CFStringRef registered_name_type_prefix = CFSTR("org.winehq.registered.");
218 /**************************************************************************
219 * Internal Clipboard implementation methods
220 **************************************************************************/
223 * format_list functions
226 /**************************************************************************
227 * debugstr_format
229 static const char *debugstr_format(UINT id)
231 WCHAR buffer[256];
233 if (GetClipboardFormatNameW(id, buffer, 256))
234 return wine_dbg_sprintf("0x%04x %s", id, debugstr_w(buffer));
236 switch (id)
238 #define BUILTIN(id) case id: return #id;
239 BUILTIN(CF_TEXT)
240 BUILTIN(CF_BITMAP)
241 BUILTIN(CF_METAFILEPICT)
242 BUILTIN(CF_SYLK)
243 BUILTIN(CF_DIF)
244 BUILTIN(CF_TIFF)
245 BUILTIN(CF_OEMTEXT)
246 BUILTIN(CF_DIB)
247 BUILTIN(CF_PALETTE)
248 BUILTIN(CF_PENDATA)
249 BUILTIN(CF_RIFF)
250 BUILTIN(CF_WAVE)
251 BUILTIN(CF_UNICODETEXT)
252 BUILTIN(CF_ENHMETAFILE)
253 BUILTIN(CF_HDROP)
254 BUILTIN(CF_LOCALE)
255 BUILTIN(CF_DIBV5)
256 BUILTIN(CF_OWNERDISPLAY)
257 BUILTIN(CF_DSPTEXT)
258 BUILTIN(CF_DSPBITMAP)
259 BUILTIN(CF_DSPMETAFILEPICT)
260 BUILTIN(CF_DSPENHMETAFILE)
261 #undef BUILTIN
262 default: return wine_dbg_sprintf("0x%04x", id);
267 /**************************************************************************
268 * insert_clipboard_format
270 static WINE_CLIPFORMAT *insert_clipboard_format(UINT id, CFStringRef type)
272 WINE_CLIPFORMAT *format;
274 format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format));
276 if (format == NULL)
278 WARN("No more memory for a new format!\n");
279 return NULL;
281 format->format_id = id;
282 format->import_func = import_clipboard_data;
283 format->export_func = export_clipboard_data;
284 format->synthesized = FALSE;
286 if (type)
287 format->type = CFStringCreateCopy(NULL, type);
288 else
290 WCHAR buffer[256];
292 GetClipboardFormatNameW(format->format_id, buffer, 256);
293 if (!strncmpW(buffer, mac_type_name_prefix, strlenW(mac_type_name_prefix)))
295 const WCHAR *p = buffer + strlenW(mac_type_name_prefix);
296 format->type = CFStringCreateWithCharacters(NULL, (UniChar*)p, strlenW(p));
298 else
300 format->type = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%S"),
301 registered_name_type_prefix, buffer);
305 list_add_tail(&format_list, &format->entry);
307 TRACE("Registering format %s type %s\n", debugstr_format(format->format_id),
308 debugstr_cf(format->type));
310 return format;
314 /**************************************************************************
315 * register_format
317 * Register a custom Mac clipboard format.
319 static WINE_CLIPFORMAT* register_format(UINT id, CFStringRef type)
321 WINE_CLIPFORMAT *format;
323 /* walk format chain to see if it's already registered */
324 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
325 if (format->format_id == id) return format;
327 return insert_clipboard_format(id, type);
331 /**************************************************************************
332 * format_for_type
334 static WINE_CLIPFORMAT* format_for_type(WINE_CLIPFORMAT *current, CFStringRef type)
336 struct list *ptr = current ? &current->entry : &format_list;
337 WINE_CLIPFORMAT *format = NULL;
339 TRACE("current %p/%s type %s\n", current, debugstr_format(current ? current->format_id : 0), debugstr_cf(type));
341 while ((ptr = list_next(&format_list, ptr)))
343 format = LIST_ENTRY(ptr, WINE_CLIPFORMAT, entry);
344 if (CFEqual(format->type, type))
346 TRACE(" -> %p/%s\n", format, debugstr_format(format->format_id));
347 return format;
351 if (!current)
353 LPWSTR name;
355 if (CFStringHasPrefix(type, CFSTR("org.winehq.builtin.")))
357 ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
358 debugstr_cf(type));
359 return NULL;
361 else if (CFStringHasPrefix(type, registered_name_type_prefix))
363 int len = CFStringGetLength(type) - CFStringGetLength(registered_name_type_prefix);
364 name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
365 CFStringGetCharacters(type, CFRangeMake(CFStringGetLength(registered_name_type_prefix), len),
366 (UniChar*)name);
367 name[len] = 0;
369 else
371 int len = strlenW(mac_type_name_prefix) + CFStringGetLength(type);
372 name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
373 memcpy(name, mac_type_name_prefix, sizeof(mac_type_name_prefix));
374 CFStringGetCharacters(type, CFRangeMake(0, CFStringGetLength(type)),
375 (UniChar*)name + strlenW(mac_type_name_prefix));
376 name[len] = 0;
379 format = register_format(RegisterClipboardFormatW(name), type);
380 if (!format)
381 ERR("Failed to register format for type %s name %s\n", debugstr_cf(type), debugstr_w(name));
383 HeapFree(GetProcessHeap(), 0, name);
386 TRACE(" -> %p/%s\n", format, debugstr_format(format ? format->format_id : 0));
387 return format;
391 /**************************************************************************
392 * convert_text
394 * Convert string data between code pages or to/from wide characters. The
395 * special value of (UINT)-1 for a code page indicates to use wide
396 * characters.
398 static HANDLE convert_text(const void *src, int src_len, UINT src_cp, UINT dest_cp)
400 HANDLE ret = NULL;
401 const WCHAR *wstr;
402 int wstr_len;
403 HANDLE handle;
404 char *p;
406 if (src_cp == (UINT)-1)
408 wstr = src;
409 wstr_len = src_len / sizeof(WCHAR);
411 else
413 WCHAR *temp;
415 wstr_len = MultiByteToWideChar(src_cp, 0, src, src_len, NULL, 0);
416 if (!src_len || ((const char*)src)[src_len - 1]) wstr_len += 1;
417 temp = HeapAlloc(GetProcessHeap(), 0, wstr_len * sizeof(WCHAR));
418 MultiByteToWideChar(src_cp, 0, src, src_len, temp, wstr_len);
419 temp[wstr_len - 1] = 0;
420 wstr = temp;
423 if (dest_cp == (UINT)-1)
425 handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, wstr_len * sizeof(WCHAR));
426 if (handle && (p = GlobalLock(handle)))
428 memcpy(p, wstr, wstr_len * sizeof(WCHAR));
429 GlobalUnlock(handle);
430 ret = handle;
433 else
435 INT len;
437 len = WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, NULL, 0, NULL, NULL);
438 if (!wstr_len || wstr[wstr_len - 1]) len += 1;
439 handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
441 if (handle && (p = GlobalLock(handle)))
443 WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, p, len, NULL, NULL);
444 p[len - 1] = 0;
445 GlobalUnlock(handle);
446 ret = handle;
450 return ret;
454 /**************************************************************************
455 * convert_unicodetext_to_codepage
457 static HANDLE convert_unicodetext_to_codepage(HANDLE unicode_handle, UINT cp)
459 LPWSTR unicode_string = GlobalLock(unicode_handle);
460 HANDLE ret = NULL;
462 if (unicode_string)
464 ret = convert_text(unicode_string, GlobalSize(unicode_handle), -1, cp);
465 GlobalUnlock(unicode_handle);
468 return ret;
472 /***********************************************************************
473 * bitmap_info_size
475 * Return the size of the bitmap info structure including color table.
477 static int bitmap_info_size(const BITMAPINFO *info, WORD coloruse)
479 unsigned int colors, size, masks = 0;
481 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
483 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER*)info;
484 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
485 return sizeof(BITMAPCOREHEADER) + colors *
486 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
488 else /* assume BITMAPINFOHEADER */
490 colors = info->bmiHeader.biClrUsed;
491 if (!colors && (info->bmiHeader.biBitCount <= 8))
492 colors = 1 << info->bmiHeader.biBitCount;
493 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
494 size = max(info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD));
495 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
500 /***********************************************************************
501 * create_dib_from_bitmap
503 * Allocates a packed DIB and copies the bitmap data into it.
505 static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp)
507 BITMAP bmp;
508 HDC hdc;
509 HGLOBAL hPackedDIB;
510 LPBYTE pPackedDIB;
511 LPBITMAPINFOHEADER pbmiHeader;
512 unsigned int cDataSize, cPackedSize, OffsetBits;
513 int nLinesCopied;
515 if (!GetObjectW(hBmp, sizeof(bmp), &bmp)) return 0;
518 * A packed DIB contains a BITMAPINFO structure followed immediately by
519 * an optional color palette and the pixel data.
522 /* Calculate the size of the packed DIB */
523 cDataSize = abs(bmp.bmHeight) * (((bmp.bmWidth * bmp.bmBitsPixel + 31) / 8) & ~3);
524 cPackedSize = sizeof(BITMAPINFOHEADER)
525 + ((bmp.bmBitsPixel <= 8) ? (sizeof(RGBQUAD) * (1 << bmp.bmBitsPixel)) : 0)
526 + cDataSize;
527 /* Get the offset to the bits */
528 OffsetBits = cPackedSize - cDataSize;
530 /* Allocate the packed DIB */
531 TRACE("\tAllocating packed DIB of size %d\n", cPackedSize);
532 hPackedDIB = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cPackedSize);
533 if (!hPackedDIB)
535 WARN("Could not allocate packed DIB!\n");
536 return 0;
539 /* A packed DIB starts with a BITMAPINFOHEADER */
540 pPackedDIB = GlobalLock(hPackedDIB);
541 pbmiHeader = (LPBITMAPINFOHEADER)pPackedDIB;
543 /* Init the BITMAPINFOHEADER */
544 pbmiHeader->biSize = sizeof(BITMAPINFOHEADER);
545 pbmiHeader->biWidth = bmp.bmWidth;
546 pbmiHeader->biHeight = bmp.bmHeight;
547 pbmiHeader->biPlanes = 1;
548 pbmiHeader->biBitCount = bmp.bmBitsPixel;
549 pbmiHeader->biCompression = BI_RGB;
550 pbmiHeader->biSizeImage = 0;
551 pbmiHeader->biXPelsPerMeter = pbmiHeader->biYPelsPerMeter = 0;
552 pbmiHeader->biClrUsed = 0;
553 pbmiHeader->biClrImportant = 0;
555 /* Retrieve the DIB bits from the bitmap and fill in the
556 * DIB color table if present */
557 hdc = GetDC(0);
558 nLinesCopied = GetDIBits(hdc, /* Handle to device context */
559 hBmp, /* Handle to bitmap */
560 0, /* First scan line to set in dest bitmap */
561 bmp.bmHeight, /* Number of scan lines to copy */
562 pPackedDIB + OffsetBits, /* [out] Address of array for bitmap bits */
563 (LPBITMAPINFO) pbmiHeader, /* [out] Address of BITMAPINFO structure */
564 0); /* RGB or palette index */
565 GlobalUnlock(hPackedDIB);
566 ReleaseDC(0, hdc);
568 /* Cleanup if GetDIBits failed */
569 if (nLinesCopied != bmp.bmHeight)
571 TRACE("\tGetDIBits returned %d. Actual lines=%d\n", nLinesCopied, bmp.bmHeight);
572 GlobalFree(hPackedDIB);
573 hPackedDIB = 0;
575 return hPackedDIB;
579 /**************************************************************************
580 * import_clipboard_data
582 * Generic import clipboard data routine.
584 static HANDLE import_clipboard_data(CFDataRef data)
586 HANDLE data_handle = NULL;
588 size_t len = CFDataGetLength(data);
589 if (len)
591 LPVOID p;
593 /* Turn on the DDESHARE flag to enable shared 32 bit memory */
594 data_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
595 if (!data_handle)
596 return NULL;
598 if ((p = GlobalLock(data_handle)))
600 memcpy(p, CFDataGetBytePtr(data), len);
601 GlobalUnlock(data_handle);
603 else
605 GlobalFree(data_handle);
606 data_handle = NULL;
610 return data_handle;
614 /**************************************************************************
615 * import_bmp_to_bitmap
617 * Import BMP data, converting to CF_BITMAP format.
619 static HANDLE import_bmp_to_bitmap(CFDataRef data)
621 HANDLE ret = 0;
622 HANDLE dib = import_bmp_to_dib(data);
623 BITMAPINFO *bmi;
625 if (dib && (bmi = GlobalLock(dib)))
627 HDC hdc;
628 unsigned int offset;
630 hdc = GetDC(NULL);
632 offset = bitmap_info_size(bmi, DIB_RGB_COLORS);
634 ret = CreateDIBitmap(hdc, &bmi->bmiHeader, CBM_INIT, (LPBYTE)bmi + offset,
635 bmi, DIB_RGB_COLORS);
637 GlobalUnlock(dib);
638 ReleaseDC(NULL, hdc);
641 GlobalFree(dib);
642 return ret;
646 /**************************************************************************
647 * import_bmp_to_dib
649 * Import BMP data, converting to CF_DIB format. This just entails
650 * stripping the BMP file format header.
652 static HANDLE import_bmp_to_dib(CFDataRef data)
654 HANDLE ret = 0;
655 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)CFDataGetBytePtr(data);
656 CFIndex len = CFDataGetLength(data);
658 if (len >= sizeof(*bfh) + sizeof(BITMAPCOREHEADER) &&
659 bfh->bfType == 0x4d42 /* "BM" */)
661 BITMAPINFO *bmi = (BITMAPINFO*)(bfh + 1);
662 BYTE* p;
664 len -= sizeof(*bfh);
665 ret = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
666 if (!ret || !(p = GlobalLock(ret)))
668 GlobalFree(ret);
669 return 0;
672 memcpy(p, bmi, len);
673 GlobalUnlock(ret);
676 return ret;
680 /**************************************************************************
681 * import_nsfilenames_to_hdrop
683 * Import NSFilenamesPboardType data, converting the property-list-
684 * serialized array of path strings to CF_HDROP.
686 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data)
688 HDROP hdrop = NULL;
689 CFArrayRef names;
690 CFIndex count, i;
691 size_t len;
692 char *buffer = NULL;
693 WCHAR **paths = NULL;
694 DROPFILES* dropfiles;
695 UniChar* p;
697 TRACE("data %s\n", debugstr_cf(data));
699 names = (CFArrayRef)CFPropertyListCreateWithData(NULL, data, kCFPropertyListImmutable,
700 NULL, NULL);
701 if (!names || CFGetTypeID(names) != CFArrayGetTypeID())
703 WARN("failed to interpret data as a CFArray\n");
704 goto done;
707 count = CFArrayGetCount(names);
709 len = 0;
710 for (i = 0; i < count; i++)
712 CFIndex this_len;
713 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
714 TRACE(" %s\n", debugstr_cf(name));
715 if (CFGetTypeID(name) != CFStringGetTypeID())
717 WARN("non-string in array\n");
718 goto done;
721 this_len = CFStringGetMaximumSizeOfFileSystemRepresentation(name);
722 if (this_len > len)
723 len = this_len;
726 buffer = HeapAlloc(GetProcessHeap(), 0, len);
727 if (!buffer)
729 WARN("failed to allocate buffer for file-system representations\n");
730 goto done;
733 paths = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(paths[0]));
734 if (!paths)
736 WARN("failed to allocate array of DOS paths\n");
737 goto done;
740 for (i = 0; i < count; i++)
742 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
743 if (!CFStringGetFileSystemRepresentation(name, buffer, len))
745 WARN("failed to get file-system representation for %s\n", debugstr_cf(name));
746 goto done;
748 paths[i] = wine_get_dos_file_name(buffer);
749 if (!paths[i])
751 WARN("failed to get DOS path for %s\n", debugstr_a(buffer));
752 goto done;
756 len = 1; /* for the terminating null */
757 for (i = 0; i < count; i++)
758 len += strlenW(paths[i]) + 1;
760 hdrop = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(*dropfiles) + len * sizeof(WCHAR));
761 if (!hdrop || !(dropfiles = GlobalLock(hdrop)))
763 WARN("failed to allocate HDROP\n");
764 GlobalFree(hdrop);
765 hdrop = NULL;
766 goto done;
769 dropfiles->pFiles = sizeof(*dropfiles);
770 dropfiles->pt.x = 0;
771 dropfiles->pt.y = 0;
772 dropfiles->fNC = FALSE;
773 dropfiles->fWide = TRUE;
775 p = (WCHAR*)(dropfiles + 1);
776 for (i = 0; i < count; i++)
778 strcpyW(p, paths[i]);
779 p += strlenW(p) + 1;
781 *p = 0;
783 GlobalUnlock(hdrop);
785 done:
786 if (paths)
788 for (i = 0; i < count; i++)
789 HeapFree(GetProcessHeap(), 0, paths[i]);
790 HeapFree(GetProcessHeap(), 0, paths);
792 HeapFree(GetProcessHeap(), 0, buffer);
793 if (names) CFRelease(names);
794 return hdrop;
798 /**************************************************************************
799 * import_oemtext_to_text
801 * Import CF_OEMTEXT data, converting the string to CF_TEXT.
803 static HANDLE import_oemtext_to_text(CFDataRef data)
805 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, CP_ACP);
809 /**************************************************************************
810 * import_oemtext_to_unicodetext
812 * Import CF_OEMTEXT data, converting the string to CF_UNICODETEXT.
814 static HANDLE import_oemtext_to_unicodetext(CFDataRef data)
816 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, -1);
820 /**************************************************************************
821 * import_text_to_oemtext
823 * Import CF_TEXT data, converting the string to CF_OEMTEXT.
825 static HANDLE import_text_to_oemtext(CFDataRef data)
827 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, CP_OEMCP);
831 /**************************************************************************
832 * import_text_to_unicodetext
834 * Import CF_TEXT data, converting the string to CF_UNICODETEXT.
836 static HANDLE import_text_to_unicodetext(CFDataRef data)
838 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, -1);
842 /**************************************************************************
843 * import_unicodetext_to_oemtext
845 * Import a CF_UNICODETEXT string, converting the string to CF_OEMTEXT.
847 static HANDLE import_unicodetext_to_oemtext(CFDataRef data)
849 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_OEMCP);
853 /**************************************************************************
854 * import_unicodetext_to_text
856 * Import a CF_UNICODETEXT string, converting the string to CF_TEXT.
858 static HANDLE import_unicodetext_to_text(CFDataRef data)
860 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_ACP);
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 data_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 data_len = CFDataGetLength(data);
910 for (i = 0; i < data_len; i++)
912 if (src[i] == '\n')
913 new_lines++;
916 if ((dst = HeapAlloc(GetProcessHeap(), 0, data_len + new_lines + 1)))
918 UINT count;
920 for (i = 0, j = 0; i < data_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_MOVEABLE | GMEM_DDESHARE, 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 * export_clipboard_data
949 * Generic export clipboard data routine.
951 static CFDataRef export_clipboard_data(HANDLE data)
953 CFDataRef ret;
954 UINT len;
955 LPVOID src;
957 len = GlobalSize(data);
958 src = GlobalLock(data);
959 if (!src) return NULL;
961 ret = CFDataCreate(NULL, src, len);
962 GlobalUnlock(data);
964 return ret;
968 /**************************************************************************
969 * export_bitmap_to_bmp
971 * Export CF_BITMAP to BMP file format.
973 static CFDataRef export_bitmap_to_bmp(HANDLE data)
975 CFDataRef ret = NULL;
976 HGLOBAL dib;
978 dib = create_dib_from_bitmap(data);
979 if (dib)
981 ret = export_dib_to_bmp(dib);
982 GlobalFree(dib);
985 return ret;
989 /**************************************************************************
990 * export_codepage_to_utf8
992 * Export string data in a specified codepage to UTF-8.
994 static CFDataRef export_codepage_to_utf8(HANDLE data, UINT cp)
996 CFDataRef ret = NULL;
997 const char* str;
999 if ((str = GlobalLock(data)))
1001 HANDLE unicode = convert_text(str, GlobalSize(data), cp, -1);
1003 ret = export_unicodetext_to_utf8(unicode);
1005 GlobalFree(unicode);
1006 GlobalUnlock(data);
1009 return ret;
1013 /**************************************************************************
1014 * export_dib_to_bmp
1016 * Export CF_DIB to BMP file format. This just entails prepending a BMP
1017 * file format header to the data.
1019 static CFDataRef export_dib_to_bmp(HANDLE data)
1021 CFMutableDataRef ret = NULL;
1022 BYTE *dibdata;
1023 CFIndex len;
1024 BITMAPFILEHEADER bfh;
1026 dibdata = GlobalLock(data);
1027 if (!dibdata)
1028 return NULL;
1030 len = sizeof(bfh) + GlobalSize(data);
1031 ret = CFDataCreateMutable(NULL, len);
1032 if (ret)
1034 bfh.bfType = 0x4d42; /* "BM" */
1035 bfh.bfSize = len;
1036 bfh.bfReserved1 = 0;
1037 bfh.bfReserved2 = 0;
1038 bfh.bfOffBits = sizeof(bfh) + bitmap_info_size((BITMAPINFO*)dibdata, DIB_RGB_COLORS);
1039 CFDataAppendBytes(ret, (UInt8*)&bfh, sizeof(bfh));
1041 /* rest of bitmap is the same as the packed dib */
1042 CFDataAppendBytes(ret, (UInt8*)dibdata, len - sizeof(bfh));
1045 GlobalUnlock(data);
1047 return ret;
1051 /**************************************************************************
1052 * export_hdrop_to_filenames
1054 * Export CF_HDROP to NSFilenamesPboardType data, which is a CFArray of
1055 * CFStrings (holding Unix paths) which is serialized as a property list.
1057 static CFDataRef export_hdrop_to_filenames(HANDLE data)
1059 CFDataRef ret = NULL;
1060 DROPFILES *dropfiles;
1061 CFMutableArrayRef filenames = NULL;
1062 void *p;
1063 WCHAR *buffer = NULL;
1064 size_t buffer_len = 0;
1066 TRACE("data %p\n", data);
1068 if (!(dropfiles = GlobalLock(data)))
1070 WARN("failed to lock data %p\n", data);
1071 goto done;
1074 filenames = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1075 if (!filenames)
1077 WARN("failed to create filenames array\n");
1078 goto done;
1081 p = (char*)dropfiles + dropfiles->pFiles;
1082 while (dropfiles->fWide ? *(WCHAR*)p : *(char*)p)
1084 char *unixname;
1085 CFStringRef filename;
1087 TRACE(" %s\n", dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1089 if (dropfiles->fWide)
1090 unixname = wine_get_unix_file_name(p);
1091 else
1093 int len = MultiByteToWideChar(CP_ACP, 0, p, -1, NULL, 0);
1094 if (len)
1096 if (len > buffer_len)
1098 HeapFree(GetProcessHeap(), 0, buffer);
1099 buffer_len = len * 2;
1100 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_len * sizeof(*buffer));
1103 MultiByteToWideChar(CP_ACP, 0, p, -1, buffer, buffer_len);
1104 unixname = wine_get_unix_file_name(buffer);
1106 else
1107 unixname = NULL;
1109 if (!unixname)
1111 WARN("failed to convert DOS path to Unix: %s\n",
1112 dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1113 goto done;
1116 if (dropfiles->fWide)
1117 p = (WCHAR*)p + strlenW(p) + 1;
1118 else
1119 p = (char*)p + strlen(p) + 1;
1121 filename = CFStringCreateWithFileSystemRepresentation(NULL, unixname);
1122 HeapFree(GetProcessHeap(), 0, unixname);
1123 if (!filename)
1125 WARN("failed to create CFString from Unix path %s\n", debugstr_a(unixname));
1126 goto done;
1129 CFArrayAppendValue(filenames, filename);
1130 CFRelease(filename);
1133 ret = CFPropertyListCreateData(NULL, filenames, kCFPropertyListXMLFormat_v1_0, 0, NULL);
1135 done:
1136 HeapFree(GetProcessHeap(), 0, buffer);
1137 GlobalUnlock(data);
1138 if (filenames) CFRelease(filenames);
1139 TRACE(" -> %s\n", debugstr_cf(ret));
1140 return ret;
1144 /**************************************************************************
1145 * export_oemtext_to_utf8
1147 * Export CF_OEMTEXT to UTF-8.
1149 static CFDataRef export_oemtext_to_utf8(HANDLE data)
1151 return export_codepage_to_utf8(data, CP_OEMCP);
1155 /**************************************************************************
1156 * export_text_to_utf8
1158 * Export CF_TEXT to UTF-8.
1160 static CFDataRef export_text_to_utf8(HANDLE data)
1162 return export_codepage_to_utf8(data, CP_ACP);
1166 /**************************************************************************
1167 * export_unicodetext_to_utf8
1169 * Export CF_UNICODETEXT to UTF-8.
1171 static CFDataRef export_unicodetext_to_utf8(HANDLE data)
1173 CFMutableDataRef ret;
1174 LPVOID src;
1175 INT dst_len;
1177 src = GlobalLock(data);
1178 if (!src) return NULL;
1180 dst_len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
1181 if (dst_len) dst_len--; /* Leave off null terminator. */
1182 ret = CFDataCreateMutable(NULL, dst_len);
1183 if (ret)
1185 LPSTR dst;
1186 int i, j;
1188 CFDataSetLength(ret, dst_len);
1189 dst = (LPSTR)CFDataGetMutableBytePtr(ret);
1190 WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_len, NULL, NULL);
1192 /* Remove carriage returns */
1193 for (i = 0, j = 0; i < dst_len; i++)
1195 if (dst[i] == '\r' &&
1196 (i + 1 >= dst_len || dst[i + 1] == '\n' || dst[i + 1] == '\0'))
1197 continue;
1198 dst[j++] = dst[i];
1200 CFDataSetLength(ret, j);
1202 GlobalUnlock(data);
1204 return ret;
1208 /**************************************************************************
1209 * get_clipboard_info
1211 static BOOL get_clipboard_info(LPCLIPBOARDINFO cbinfo)
1213 BOOL ret = FALSE;
1215 SERVER_START_REQ(set_clipboard_info)
1217 req->flags = 0;
1219 if (wine_server_call_err(req))
1221 ERR("Failed to get clipboard owner.\n");
1223 else
1225 cbinfo->hwnd_owner = wine_server_ptr_handle(reply->old_owner);
1226 cbinfo->flags = reply->flags;
1228 ret = TRUE;
1231 SERVER_END_REQ;
1233 return ret;
1237 /**************************************************************************
1238 * release_ownership
1240 static BOOL release_ownership(void)
1242 BOOL ret = FALSE;
1244 SERVER_START_REQ(set_clipboard_info)
1246 req->flags = SET_CB_RELOWNER | SET_CB_SEQNO;
1248 if (wine_server_call_err(req))
1249 ERR("Failed to set clipboard.\n");
1250 else
1251 ret = TRUE;
1253 SERVER_END_REQ;
1255 return ret;
1259 /**************************************************************************
1260 * macdrv_get_pasteboard_data
1262 static HANDLE macdrv_get_pasteboard_data(CFTypeRef pasteboard, UINT desired_format)
1264 CFArrayRef types;
1265 CFIndex count;
1266 CFIndex i;
1267 CFStringRef type, best_type;
1268 WINE_CLIPFORMAT* best_format = NULL;
1269 HANDLE data = NULL;
1271 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1273 types = macdrv_copy_pasteboard_types(pasteboard);
1274 if (!types)
1276 WARN("Failed to copy pasteboard types\n");
1277 return NULL;
1280 count = CFArrayGetCount(types);
1281 TRACE("got %ld types\n", count);
1283 for (i = 0; (!best_format || best_format->synthesized) && i < count; i++)
1285 WINE_CLIPFORMAT* format;
1287 type = CFArrayGetValueAtIndex(types, i);
1289 format = NULL;
1290 while ((!best_format || best_format->synthesized) && (format = format_for_type(format, type)))
1292 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format ? format->format_id : 0));
1294 if (format->format_id == desired_format)
1296 /* The best format is the matching one which is not synthesized. Failing that,
1297 the best format is the first matching synthesized format. */
1298 if (!format->synthesized || !best_format)
1300 best_type = type;
1301 best_format = format;
1307 if (best_format)
1309 CFDataRef pasteboard_data = macdrv_copy_pasteboard_data(pasteboard, best_type);
1311 TRACE("got pasteboard data for type %s: %s\n", debugstr_cf(best_type), debugstr_cf(pasteboard_data));
1313 if (pasteboard_data)
1315 data = best_format->import_func(pasteboard_data);
1316 CFRelease(pasteboard_data);
1320 CFRelease(types);
1321 TRACE(" -> %p\n", data);
1322 return data;
1326 /**************************************************************************
1327 * macdrv_pasteboard_has_format
1329 static BOOL macdrv_pasteboard_has_format(CFTypeRef pasteboard, UINT desired_format)
1331 CFArrayRef types;
1332 int count;
1333 UINT i;
1334 BOOL found = FALSE;
1336 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1338 types = macdrv_copy_pasteboard_types(pasteboard);
1339 if (!types)
1341 WARN("Failed to copy pasteboard types\n");
1342 return FALSE;
1345 count = CFArrayGetCount(types);
1346 TRACE("got %d types\n", count);
1348 for (i = 0; !found && i < count; i++)
1350 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1351 WINE_CLIPFORMAT* format;
1353 format = NULL;
1354 while (!found && (format = format_for_type(format, type)))
1356 TRACE("for type %s got format %s\n", debugstr_cf(type), debugstr_format(format->format_id));
1358 if (format->format_id == desired_format)
1359 found = TRUE;
1363 CFRelease(types);
1364 TRACE(" -> %d\n", found);
1365 return found;
1369 /**************************************************************************
1370 * check_clipboard_ownership
1372 static void check_clipboard_ownership(HWND *owner)
1374 CLIPBOARDINFO cbinfo;
1376 if (owner) *owner = NULL;
1378 /* If Wine thinks we're the clipboard owner but Mac OS X thinks we're not
1379 the pasteboard owner, update Wine. */
1380 if (get_clipboard_info(&cbinfo) && (cbinfo.flags & CB_PROCESS))
1382 if (!(cbinfo.flags & CB_OPEN) && !macdrv_is_pasteboard_owner())
1384 TRACE("Lost clipboard ownership\n");
1386 if (OpenClipboard(cbinfo.hwnd_owner))
1388 /* Destroy private objects */
1389 SendMessageW(cbinfo.hwnd_owner, WM_DESTROYCLIPBOARD, 0, 0);
1391 /* Give up ownership of the windows clipboard */
1392 release_ownership();
1393 CloseClipboard();
1396 else if (owner)
1397 *owner = cbinfo.hwnd_owner;
1402 /**************************************************************************
1403 * Mac User Driver Clipboard Exports
1404 **************************************************************************/
1407 /**************************************************************************
1408 * AcquireClipboard (MACDRV.@)
1410 int CDECL macdrv_AcquireClipboard(HWND hwnd)
1412 TRACE("hwnd %p\n", hwnd);
1413 check_clipboard_ownership(NULL);
1414 return 0;
1418 /**************************************************************************
1419 * CountClipboardFormats (MACDRV.@)
1421 INT CDECL macdrv_CountClipboardFormats(void)
1423 CFMutableSetRef seen_formats;
1424 CFArrayRef types;
1425 CFIndex count;
1426 CFIndex i;
1427 INT ret = 0;
1429 TRACE("()\n");
1430 check_clipboard_ownership(NULL);
1432 seen_formats = CFSetCreateMutable(NULL, 0, NULL);
1433 if (!seen_formats)
1435 WARN("Failed to allocate set to track seen formats\n");
1436 return 0;
1439 types = macdrv_copy_pasteboard_types(NULL);
1440 if (!types)
1442 WARN("Failed to copy pasteboard types\n");
1443 CFRelease(seen_formats);
1444 return 0;
1447 count = CFArrayGetCount(types);
1448 TRACE("got %ld types\n", count);
1450 for (i = 0; i < count; i++)
1452 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1453 WINE_CLIPFORMAT* format;
1455 format = NULL;
1456 while ((format = format_for_type(format, type)))
1458 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1460 if (!CFSetContainsValue(seen_formats, (void*)format->format_id))
1462 ret++;
1463 CFSetAddValue(seen_formats, (void*)format->format_id);
1468 CFRelease(seen_formats);
1469 TRACE(" -> %d\n", ret);
1470 return ret;
1474 /**************************************************************************
1475 * EmptyClipboard (MACDRV.@)
1477 * Empty cached clipboard data.
1479 void CDECL macdrv_EmptyClipboard(BOOL keepunowned)
1481 TRACE("keepunowned %d\n", keepunowned);
1482 macdrv_clear_pasteboard();
1486 /**************************************************************************
1487 * EndClipboardUpdate (MACDRV.@)
1489 void CDECL macdrv_EndClipboardUpdate(void)
1491 TRACE("()\n");
1492 check_clipboard_ownership(NULL);
1496 /**************************************************************************
1497 * EnumClipboardFormats (MACDRV.@)
1499 UINT CDECL macdrv_EnumClipboardFormats(UINT prev_format)
1501 CFArrayRef types;
1502 CFIndex count;
1503 CFIndex i;
1504 UINT ret;
1506 TRACE("prev_format %s\n", debugstr_format(prev_format));
1507 check_clipboard_ownership(NULL);
1509 types = macdrv_copy_pasteboard_types(NULL);
1510 if (!types)
1512 WARN("Failed to copy pasteboard types\n");
1513 return 0;
1516 count = CFArrayGetCount(types);
1517 TRACE("got %ld types\n", count);
1519 if (!count)
1521 CFRelease(types);
1522 return 0;
1525 if (prev_format)
1527 CFMutableArrayRef formats = CFArrayCreateMutable(NULL, 0, NULL);
1528 if (!formats)
1530 WARN("Failed to allocate array to track formats\n");
1531 CFRelease(types);
1532 return 0;
1535 for (i = 0; i < count; i++)
1537 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1538 WINE_CLIPFORMAT* format;
1540 format = NULL;
1541 while ((format = format_for_type(format, type)))
1543 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1545 if (format->synthesized)
1547 /* Don't override a real value with a synthesized value. */
1548 if (!CFArrayContainsValue(formats, CFRangeMake(0, CFArrayGetCount(formats)), (void*)format->format_id))
1549 CFArrayAppendValue(formats, (void*)format->format_id);
1551 else
1553 /* If the type was already in the array, it must have been synthesized
1554 because this one's real. Remove the synthesized entry in favor of
1555 this one. */
1556 CFIndex index = CFArrayGetFirstIndexOfValue(formats, CFRangeMake(0, CFArrayGetCount(formats)),
1557 (void*)format->format_id);
1558 if (index != kCFNotFound)
1559 CFArrayRemoveValueAtIndex(formats, index);
1560 CFArrayAppendValue(formats, (void*)format->format_id);
1565 count = CFArrayGetCount(formats);
1566 i = CFArrayGetFirstIndexOfValue(formats, CFRangeMake(0, count), (void*)prev_format);
1567 if (i == kCFNotFound || i + 1 >= count)
1568 ret = 0;
1569 else
1570 ret = (UINT)CFArrayGetValueAtIndex(formats, i + 1);
1572 CFRelease(formats);
1574 else
1576 CFStringRef type = CFArrayGetValueAtIndex(types, 0);
1577 WINE_CLIPFORMAT *format = format_for_type(NULL, type);
1579 ret = format ? format->format_id : 0;
1582 CFRelease(types);
1583 TRACE(" -> %u\n", ret);
1584 return ret;
1588 /**************************************************************************
1589 * GetClipboardData (MACDRV.@)
1591 HANDLE CDECL macdrv_GetClipboardData(UINT desired_format)
1593 check_clipboard_ownership(NULL);
1595 return macdrv_get_pasteboard_data(NULL, desired_format);
1599 /**************************************************************************
1600 * IsClipboardFormatAvailable (MACDRV.@)
1602 BOOL CDECL macdrv_IsClipboardFormatAvailable(UINT desired_format)
1604 check_clipboard_ownership(NULL);
1605 return macdrv_pasteboard_has_format(NULL, desired_format);
1609 /**************************************************************************
1610 * SetClipboardData (MACDRV.@)
1612 BOOL CDECL macdrv_SetClipboardData(UINT format_id, HANDLE data, BOOL owner)
1614 HWND hwnd_owner;
1615 macdrv_window window;
1616 WINE_CLIPFORMAT *format;
1617 CFDataRef cfdata = NULL;
1619 check_clipboard_ownership(&hwnd_owner);
1620 window = macdrv_get_cocoa_window(GetAncestor(hwnd_owner, GA_ROOT), FALSE);
1621 TRACE("format_id %s data %p owner %d hwnd_owner %p window %p)\n", debugstr_format(format_id), data, owner, hwnd_owner, window);
1623 /* Find the "natural" format for this format_id (the one which isn't
1624 synthesized from another type). */
1625 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1626 if (format->format_id == format_id && !format->synthesized) break;
1628 if (&format->entry == &format_list && !(format = insert_clipboard_format(format_id, NULL)))
1630 WARN("Failed to register clipboard format %s\n", debugstr_format(format_id));
1631 return FALSE;
1634 /* Export the data to the Mac pasteboard. */
1635 if (data)
1637 if (!format->export_func || !(cfdata = format->export_func(data)))
1639 WARN("Failed to export %s data to type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1640 return FALSE;
1644 if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1645 TRACE("Set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1646 else
1648 WARN("Failed to set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1649 if (cfdata) CFRelease(cfdata);
1650 return FALSE;
1653 if (cfdata) CFRelease(cfdata);
1655 /* Find any other formats for this format_id (the exportable synthesized ones). */
1656 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1658 if (format->format_id == format_id && format->synthesized && format->export_func)
1660 /* We have a synthesized format for this format ID. Add its type to the pasteboard. */
1661 TRACE("Synthesized from format %s: type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1663 if (data)
1665 cfdata = format->export_func(data);
1666 if (!cfdata)
1668 WARN("Failed to export %s data to type %s\n", debugstr_format(format->format_id), debugstr_cf(format->type));
1669 continue;
1672 else
1673 cfdata = NULL;
1675 if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1676 TRACE(" ... set pasteboard data: %s\n", debugstr_cf(cfdata));
1677 else
1678 WARN(" ... failed to set pasteboard data: %s\n", debugstr_cf(cfdata));
1680 if (cfdata) CFRelease(cfdata);
1684 if (data)
1686 /* FIXME: According to MSDN, the caller is entitled to lock and read from
1687 data until CloseClipboard is called. So, we should defer this cleanup. */
1688 if ((format_id >= CF_GDIOBJFIRST && format_id <= CF_GDIOBJLAST) ||
1689 format_id == CF_BITMAP ||
1690 format_id == CF_DIB ||
1691 format_id == CF_PALETTE)
1693 DeleteObject(data);
1695 else if (format_id == CF_METAFILEPICT)
1697 DeleteMetaFile(((METAFILEPICT *)GlobalLock(data))->hMF);
1698 GlobalFree(data);
1700 else if (format_id == CF_ENHMETAFILE)
1702 DeleteEnhMetaFile(data);
1704 else if (format_id < CF_PRIVATEFIRST || CF_PRIVATELAST < format_id)
1706 GlobalFree(data);
1710 return TRUE;
1714 /**************************************************************************
1715 * MACDRV Private Clipboard Exports
1716 **************************************************************************/
1719 /**************************************************************************
1720 * macdrv_clipboard_process_attach
1722 void macdrv_clipboard_process_attach(void)
1724 UINT i;
1726 /* Register built-in formats */
1727 for (i = 0; i < sizeof(builtin_format_ids)/sizeof(builtin_format_ids[0]); i++)
1729 WINE_CLIPFORMAT *format;
1731 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
1732 format->format_id = builtin_format_ids[i].id;
1733 format->type = CFRetain(builtin_format_ids[i].type);
1734 format->import_func = builtin_format_ids[i].import;
1735 format->export_func = builtin_format_ids[i].export;
1736 format->synthesized = builtin_format_ids[i].synthesized;
1737 list_add_tail(&format_list, &format->entry);
1740 /* Register known mappings between Windows formats and Mac types */
1741 for (i = 0; i < sizeof(builtin_format_names)/sizeof(builtin_format_names[0]); i++)
1742 insert_clipboard_format(RegisterClipboardFormatW(builtin_format_names[i].name),
1743 builtin_format_names[i].type);
1747 /**************************************************************************
1748 * query_pasteboard_data
1750 BOOL query_pasteboard_data(HWND hwnd, CFStringRef type)
1752 BOOL ret = FALSE;
1753 CLIPBOARDINFO cbinfo;
1754 WINE_CLIPFORMAT* format;
1755 CFArrayRef types = NULL;
1756 CFRange range;
1758 TRACE("hwnd %p type %s\n", hwnd, debugstr_cf(type));
1760 if (get_clipboard_info(&cbinfo))
1761 hwnd = cbinfo.hwnd_owner;
1763 format = NULL;
1764 while ((format = format_for_type(format, type)))
1766 WINE_CLIPFORMAT* base_format;
1768 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1770 if (!format->synthesized)
1772 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(format->format_id), hwnd);
1773 SendMessageW(hwnd, WM_RENDERFORMAT, format->format_id, 0);
1774 ret = TRUE;
1775 goto done;
1778 if (!types)
1780 types = macdrv_copy_pasteboard_types(NULL);
1781 if (!types)
1783 WARN("Failed to copy pasteboard types\n");
1784 break;
1787 range = CFRangeMake(0, CFArrayGetCount(types));
1790 /* The type maps to a synthesized format. Now look up what type that format maps to natively
1791 (not synthesized). For example, if type is "public.utf8-plain-text", then this format may
1792 have an ID of CF_TEXT. From CF_TEXT, we want to find "org.winehq.builtin.text" to see if
1793 that type is present in the pasteboard. If it is, then the app must have promised it and
1794 we can ask it to render it. (If it had put it on the clipboard immediately, then the
1795 pasteboard would also have data for "public.utf8-plain-text" and we wouldn't be here.) If
1796 "org.winehq.builtin.text" is not on the pasteboard, then one of the other text formats is
1797 presumably responsible for the promise that we're trying to satisfy, so we keep looking. */
1798 LIST_FOR_EACH_ENTRY(base_format, &format_list, WINE_CLIPFORMAT, entry)
1800 if (base_format->format_id == format->format_id && !base_format->synthesized &&
1801 CFArrayContainsValue(types, range, base_format->type))
1803 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(base_format->format_id), hwnd);
1804 SendMessageW(hwnd, WM_RENDERFORMAT, base_format->format_id, 0);
1805 ret = TRUE;
1806 goto done;
1811 done:
1812 if (types) CFRelease(types);
1814 return ret;