winemac: Handle failure to get clipboard format name; don't use uninitialized buffer.
[wine.git] / dlls / winemac.drv / clipboard.c
blob53b1448715f8fc1177c4eddf2edad42e461d3198
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 DRVIMPORTFUNC import;
203 DRVEXPORTFUNC export;
204 } builtin_format_names[] =
206 { wszRichTextFormat, CFSTR("public.rtf"), import_clipboard_data, export_clipboard_data },
207 { wszGIF, CFSTR("com.compuserve.gif"), import_clipboard_data, export_clipboard_data },
208 { wszJFIF, CFSTR("public.jpeg"), import_clipboard_data, export_clipboard_data },
209 { wszPNG, CFSTR("public.png"), import_clipboard_data, export_clipboard_data },
210 { wszHTMLFormat, CFSTR("public.html"), import_clipboard_data, export_clipboard_data },
211 { CFSTR_SHELLURLW, CFSTR("public.url"), import_utf8_to_text, export_text_to_utf8 },
214 /* The prefix prepended to an external Mac pasteboard type to make a Win32 clipboard format name. org.winehq.mac-type. */
215 static const WCHAR mac_type_name_prefix[] = {'o','r','g','.','w','i','n','e','h','q','.','m','a','c','-','t','y','p','e','.',0};
217 /* The prefix prepended to a Win32 clipboard format name to make a Mac pasteboard type. */
218 static const CFStringRef registered_name_type_prefix = CFSTR("org.winehq.registered.");
221 /**************************************************************************
222 * Internal Clipboard implementation methods
223 **************************************************************************/
226 * format_list functions
229 /**************************************************************************
230 * debugstr_format
232 const char *debugstr_format(UINT id)
234 WCHAR buffer[256];
236 if (GetClipboardFormatNameW(id, buffer, 256))
237 return wine_dbg_sprintf("0x%04x %s", id, debugstr_w(buffer));
239 switch (id)
241 #define BUILTIN(id) case id: return #id;
242 BUILTIN(CF_TEXT)
243 BUILTIN(CF_BITMAP)
244 BUILTIN(CF_METAFILEPICT)
245 BUILTIN(CF_SYLK)
246 BUILTIN(CF_DIF)
247 BUILTIN(CF_TIFF)
248 BUILTIN(CF_OEMTEXT)
249 BUILTIN(CF_DIB)
250 BUILTIN(CF_PALETTE)
251 BUILTIN(CF_PENDATA)
252 BUILTIN(CF_RIFF)
253 BUILTIN(CF_WAVE)
254 BUILTIN(CF_UNICODETEXT)
255 BUILTIN(CF_ENHMETAFILE)
256 BUILTIN(CF_HDROP)
257 BUILTIN(CF_LOCALE)
258 BUILTIN(CF_DIBV5)
259 BUILTIN(CF_OWNERDISPLAY)
260 BUILTIN(CF_DSPTEXT)
261 BUILTIN(CF_DSPBITMAP)
262 BUILTIN(CF_DSPMETAFILEPICT)
263 BUILTIN(CF_DSPENHMETAFILE)
264 #undef BUILTIN
265 default: return wine_dbg_sprintf("0x%04x", id);
270 /**************************************************************************
271 * insert_clipboard_format
273 static WINE_CLIPFORMAT *insert_clipboard_format(UINT id, CFStringRef type)
275 WINE_CLIPFORMAT *format;
277 format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format));
279 if (format == NULL)
281 WARN("No more memory for a new format!\n");
282 return NULL;
284 format->format_id = id;
285 format->import_func = import_clipboard_data;
286 format->export_func = export_clipboard_data;
287 format->synthesized = FALSE;
289 if (type)
290 format->type = CFStringCreateCopy(NULL, type);
291 else
293 WCHAR buffer[256];
295 if (!GetClipboardFormatNameW(format->format_id, buffer, sizeof(buffer) / sizeof(buffer[0])))
297 WARN("failed to get name for format %s; error 0x%08x\n", debugstr_format(format->format_id), GetLastError());
298 HeapFree(GetProcessHeap(), 0, format);
299 return NULL;
302 if (!strncmpW(buffer, mac_type_name_prefix, strlenW(mac_type_name_prefix)))
304 const WCHAR *p = buffer + strlenW(mac_type_name_prefix);
305 format->type = CFStringCreateWithCharacters(NULL, (UniChar*)p, strlenW(p));
307 else
309 format->type = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%S"),
310 registered_name_type_prefix, buffer);
314 list_add_tail(&format_list, &format->entry);
316 TRACE("Registering format %s type %s\n", debugstr_format(format->format_id),
317 debugstr_cf(format->type));
319 return format;
323 /**************************************************************************
324 * register_format
326 * Register a custom Mac clipboard format.
328 static WINE_CLIPFORMAT* register_format(UINT id, CFStringRef type)
330 WINE_CLIPFORMAT *format;
332 /* walk format chain to see if it's already registered */
333 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
334 if (format->format_id == id) return format;
336 return insert_clipboard_format(id, type);
340 /**************************************************************************
341 * format_for_type
343 static WINE_CLIPFORMAT* format_for_type(WINE_CLIPFORMAT *current, CFStringRef type)
345 struct list *ptr = current ? &current->entry : &format_list;
346 WINE_CLIPFORMAT *format = NULL;
348 TRACE("current %p/%s type %s\n", current, debugstr_format(current ? current->format_id : 0), debugstr_cf(type));
350 while ((ptr = list_next(&format_list, ptr)))
352 format = LIST_ENTRY(ptr, WINE_CLIPFORMAT, entry);
353 if (CFEqual(format->type, type))
355 TRACE(" -> %p/%s\n", format, debugstr_format(format->format_id));
356 return format;
360 if (!current)
362 LPWSTR name;
364 if (CFStringHasPrefix(type, CFSTR("org.winehq.builtin.")))
366 ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
367 debugstr_cf(type));
368 return NULL;
370 else if (CFStringHasPrefix(type, registered_name_type_prefix))
372 int len = CFStringGetLength(type) - CFStringGetLength(registered_name_type_prefix);
373 name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
374 CFStringGetCharacters(type, CFRangeMake(CFStringGetLength(registered_name_type_prefix), len),
375 (UniChar*)name);
376 name[len] = 0;
378 else
380 int len = strlenW(mac_type_name_prefix) + CFStringGetLength(type);
381 name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
382 memcpy(name, mac_type_name_prefix, sizeof(mac_type_name_prefix));
383 CFStringGetCharacters(type, CFRangeMake(0, CFStringGetLength(type)),
384 (UniChar*)name + strlenW(mac_type_name_prefix));
385 name[len] = 0;
388 format = register_format(RegisterClipboardFormatW(name), type);
389 if (!format)
390 ERR("Failed to register format for type %s name %s\n", debugstr_cf(type), debugstr_w(name));
392 HeapFree(GetProcessHeap(), 0, name);
395 TRACE(" -> %p/%s\n", format, debugstr_format(format ? format->format_id : 0));
396 return format;
400 /**************************************************************************
401 * convert_text
403 * Convert string data between code pages or to/from wide characters. The
404 * special value of (UINT)-1 for a code page indicates to use wide
405 * characters.
407 static HANDLE convert_text(const void *src, int src_len, UINT src_cp, UINT dest_cp)
409 HANDLE ret = NULL;
410 const WCHAR *wstr;
411 int wstr_len;
412 HANDLE handle;
413 char *p;
415 if (src_cp == (UINT)-1)
417 wstr = src;
418 wstr_len = src_len / sizeof(WCHAR);
420 else
422 WCHAR *temp;
424 wstr_len = MultiByteToWideChar(src_cp, 0, src, src_len, NULL, 0);
425 if (!src_len || ((const char*)src)[src_len - 1]) wstr_len += 1;
426 temp = HeapAlloc(GetProcessHeap(), 0, wstr_len * sizeof(WCHAR));
427 MultiByteToWideChar(src_cp, 0, src, src_len, temp, wstr_len);
428 temp[wstr_len - 1] = 0;
429 wstr = temp;
432 if (dest_cp == (UINT)-1)
434 handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, wstr_len * sizeof(WCHAR));
435 if (handle && (p = GlobalLock(handle)))
437 memcpy(p, wstr, wstr_len * sizeof(WCHAR));
438 GlobalUnlock(handle);
439 ret = handle;
442 else
444 INT len;
446 len = WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, NULL, 0, NULL, NULL);
447 if (!wstr_len || wstr[wstr_len - 1]) len += 1;
448 handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
450 if (handle && (p = GlobalLock(handle)))
452 WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, p, len, NULL, NULL);
453 p[len - 1] = 0;
454 GlobalUnlock(handle);
455 ret = handle;
459 return ret;
463 /**************************************************************************
464 * convert_unicodetext_to_codepage
466 static HANDLE convert_unicodetext_to_codepage(HANDLE unicode_handle, UINT cp)
468 LPWSTR unicode_string = GlobalLock(unicode_handle);
469 HANDLE ret = NULL;
471 if (unicode_string)
473 ret = convert_text(unicode_string, GlobalSize(unicode_handle), -1, cp);
474 GlobalUnlock(unicode_handle);
477 return ret;
481 /***********************************************************************
482 * bitmap_info_size
484 * Return the size of the bitmap info structure including color table.
486 static int bitmap_info_size(const BITMAPINFO *info, WORD coloruse)
488 unsigned int colors, size, masks = 0;
490 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
492 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER*)info;
493 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
494 return sizeof(BITMAPCOREHEADER) + colors *
495 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
497 else /* assume BITMAPINFOHEADER */
499 colors = info->bmiHeader.biClrUsed;
500 if (!colors && (info->bmiHeader.biBitCount <= 8))
501 colors = 1 << info->bmiHeader.biBitCount;
502 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
503 size = max(info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD));
504 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
509 /***********************************************************************
510 * create_dib_from_bitmap
512 * Allocates a packed DIB and copies the bitmap data into it.
514 static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp)
516 BITMAP bmp;
517 HDC hdc;
518 HGLOBAL hPackedDIB;
519 LPBYTE pPackedDIB;
520 LPBITMAPINFOHEADER pbmiHeader;
521 unsigned int cDataSize, cPackedSize, OffsetBits;
522 int nLinesCopied;
524 if (!GetObjectW(hBmp, sizeof(bmp), &bmp)) return 0;
527 * A packed DIB contains a BITMAPINFO structure followed immediately by
528 * an optional color palette and the pixel data.
531 /* Calculate the size of the packed DIB */
532 cDataSize = abs(bmp.bmHeight) * (((bmp.bmWidth * bmp.bmBitsPixel + 31) / 8) & ~3);
533 cPackedSize = sizeof(BITMAPINFOHEADER)
534 + ((bmp.bmBitsPixel <= 8) ? (sizeof(RGBQUAD) * (1 << bmp.bmBitsPixel)) : 0)
535 + cDataSize;
536 /* Get the offset to the bits */
537 OffsetBits = cPackedSize - cDataSize;
539 /* Allocate the packed DIB */
540 TRACE("\tAllocating packed DIB of size %d\n", cPackedSize);
541 hPackedDIB = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cPackedSize);
542 if (!hPackedDIB)
544 WARN("Could not allocate packed DIB!\n");
545 return 0;
548 /* A packed DIB starts with a BITMAPINFOHEADER */
549 pPackedDIB = GlobalLock(hPackedDIB);
550 pbmiHeader = (LPBITMAPINFOHEADER)pPackedDIB;
552 /* Init the BITMAPINFOHEADER */
553 pbmiHeader->biSize = sizeof(BITMAPINFOHEADER);
554 pbmiHeader->biWidth = bmp.bmWidth;
555 pbmiHeader->biHeight = bmp.bmHeight;
556 pbmiHeader->biPlanes = 1;
557 pbmiHeader->biBitCount = bmp.bmBitsPixel;
558 pbmiHeader->biCompression = BI_RGB;
559 pbmiHeader->biSizeImage = 0;
560 pbmiHeader->biXPelsPerMeter = pbmiHeader->biYPelsPerMeter = 0;
561 pbmiHeader->biClrUsed = 0;
562 pbmiHeader->biClrImportant = 0;
564 /* Retrieve the DIB bits from the bitmap and fill in the
565 * DIB color table if present */
566 hdc = GetDC(0);
567 nLinesCopied = GetDIBits(hdc, /* Handle to device context */
568 hBmp, /* Handle to bitmap */
569 0, /* First scan line to set in dest bitmap */
570 bmp.bmHeight, /* Number of scan lines to copy */
571 pPackedDIB + OffsetBits, /* [out] Address of array for bitmap bits */
572 (LPBITMAPINFO) pbmiHeader, /* [out] Address of BITMAPINFO structure */
573 0); /* RGB or palette index */
574 GlobalUnlock(hPackedDIB);
575 ReleaseDC(0, hdc);
577 /* Cleanup if GetDIBits failed */
578 if (nLinesCopied != bmp.bmHeight)
580 TRACE("\tGetDIBits returned %d. Actual lines=%d\n", nLinesCopied, bmp.bmHeight);
581 GlobalFree(hPackedDIB);
582 hPackedDIB = 0;
584 return hPackedDIB;
588 /**************************************************************************
589 * import_clipboard_data
591 * Generic import clipboard data routine.
593 static HANDLE import_clipboard_data(CFDataRef data)
595 HANDLE data_handle = NULL;
597 size_t len = CFDataGetLength(data);
598 if (len)
600 LPVOID p;
602 /* Turn on the DDESHARE flag to enable shared 32 bit memory */
603 data_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
604 if (!data_handle)
605 return NULL;
607 if ((p = GlobalLock(data_handle)))
609 memcpy(p, CFDataGetBytePtr(data), len);
610 GlobalUnlock(data_handle);
612 else
614 GlobalFree(data_handle);
615 data_handle = NULL;
619 return data_handle;
623 /**************************************************************************
624 * import_bmp_to_bitmap
626 * Import BMP data, converting to CF_BITMAP format.
628 static HANDLE import_bmp_to_bitmap(CFDataRef data)
630 HANDLE ret = 0;
631 HANDLE dib = import_bmp_to_dib(data);
632 BITMAPINFO *bmi;
634 if (dib && (bmi = GlobalLock(dib)))
636 HDC hdc;
637 unsigned int offset;
639 hdc = GetDC(NULL);
641 offset = bitmap_info_size(bmi, DIB_RGB_COLORS);
643 ret = CreateDIBitmap(hdc, &bmi->bmiHeader, CBM_INIT, (LPBYTE)bmi + offset,
644 bmi, DIB_RGB_COLORS);
646 GlobalUnlock(dib);
647 ReleaseDC(NULL, hdc);
650 GlobalFree(dib);
651 return ret;
655 /**************************************************************************
656 * import_bmp_to_dib
658 * Import BMP data, converting to CF_DIB format. This just entails
659 * stripping the BMP file format header.
661 static HANDLE import_bmp_to_dib(CFDataRef data)
663 HANDLE ret = 0;
664 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)CFDataGetBytePtr(data);
665 CFIndex len = CFDataGetLength(data);
667 if (len >= sizeof(*bfh) + sizeof(BITMAPCOREHEADER) &&
668 bfh->bfType == 0x4d42 /* "BM" */)
670 BITMAPINFO *bmi = (BITMAPINFO*)(bfh + 1);
671 BYTE* p;
673 len -= sizeof(*bfh);
674 ret = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
675 if (!ret || !(p = GlobalLock(ret)))
677 GlobalFree(ret);
678 return 0;
681 memcpy(p, bmi, len);
682 GlobalUnlock(ret);
685 return ret;
689 /**************************************************************************
690 * import_nsfilenames_to_hdrop
692 * Import NSFilenamesPboardType data, converting the property-list-
693 * serialized array of path strings to CF_HDROP.
695 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data)
697 HDROP hdrop = NULL;
698 CFArrayRef names;
699 CFIndex count, i;
700 size_t len;
701 char *buffer = NULL;
702 WCHAR **paths = NULL;
703 DROPFILES* dropfiles;
704 UniChar* p;
706 TRACE("data %s\n", debugstr_cf(data));
708 names = (CFArrayRef)CFPropertyListCreateWithData(NULL, data, kCFPropertyListImmutable,
709 NULL, NULL);
710 if (!names || CFGetTypeID(names) != CFArrayGetTypeID())
712 WARN("failed to interpret data as a CFArray\n");
713 goto done;
716 count = CFArrayGetCount(names);
718 len = 0;
719 for (i = 0; i < count; i++)
721 CFIndex this_len;
722 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
723 TRACE(" %s\n", debugstr_cf(name));
724 if (CFGetTypeID(name) != CFStringGetTypeID())
726 WARN("non-string in array\n");
727 goto done;
730 this_len = CFStringGetMaximumSizeOfFileSystemRepresentation(name);
731 if (this_len > len)
732 len = this_len;
735 buffer = HeapAlloc(GetProcessHeap(), 0, len);
736 if (!buffer)
738 WARN("failed to allocate buffer for file-system representations\n");
739 goto done;
742 paths = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(paths[0]));
743 if (!paths)
745 WARN("failed to allocate array of DOS paths\n");
746 goto done;
749 for (i = 0; i < count; i++)
751 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
752 if (!CFStringGetFileSystemRepresentation(name, buffer, len))
754 WARN("failed to get file-system representation for %s\n", debugstr_cf(name));
755 goto done;
757 paths[i] = wine_get_dos_file_name(buffer);
758 if (!paths[i])
760 WARN("failed to get DOS path for %s\n", debugstr_a(buffer));
761 goto done;
765 len = 1; /* for the terminating null */
766 for (i = 0; i < count; i++)
767 len += strlenW(paths[i]) + 1;
769 hdrop = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(*dropfiles) + len * sizeof(WCHAR));
770 if (!hdrop || !(dropfiles = GlobalLock(hdrop)))
772 WARN("failed to allocate HDROP\n");
773 GlobalFree(hdrop);
774 hdrop = NULL;
775 goto done;
778 dropfiles->pFiles = sizeof(*dropfiles);
779 dropfiles->pt.x = 0;
780 dropfiles->pt.y = 0;
781 dropfiles->fNC = FALSE;
782 dropfiles->fWide = TRUE;
784 p = (WCHAR*)(dropfiles + 1);
785 for (i = 0; i < count; i++)
787 strcpyW(p, paths[i]);
788 p += strlenW(p) + 1;
790 *p = 0;
792 GlobalUnlock(hdrop);
794 done:
795 if (paths)
797 for (i = 0; i < count; i++)
798 HeapFree(GetProcessHeap(), 0, paths[i]);
799 HeapFree(GetProcessHeap(), 0, paths);
801 HeapFree(GetProcessHeap(), 0, buffer);
802 if (names) CFRelease(names);
803 return hdrop;
807 /**************************************************************************
808 * import_oemtext_to_text
810 * Import CF_OEMTEXT data, converting the string to CF_TEXT.
812 static HANDLE import_oemtext_to_text(CFDataRef data)
814 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, CP_ACP);
818 /**************************************************************************
819 * import_oemtext_to_unicodetext
821 * Import CF_OEMTEXT data, converting the string to CF_UNICODETEXT.
823 static HANDLE import_oemtext_to_unicodetext(CFDataRef data)
825 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, -1);
829 /**************************************************************************
830 * import_text_to_oemtext
832 * Import CF_TEXT data, converting the string to CF_OEMTEXT.
834 static HANDLE import_text_to_oemtext(CFDataRef data)
836 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, CP_OEMCP);
840 /**************************************************************************
841 * import_text_to_unicodetext
843 * Import CF_TEXT data, converting the string to CF_UNICODETEXT.
845 static HANDLE import_text_to_unicodetext(CFDataRef data)
847 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, -1);
851 /**************************************************************************
852 * import_unicodetext_to_oemtext
854 * Import a CF_UNICODETEXT string, converting the string to CF_OEMTEXT.
856 static HANDLE import_unicodetext_to_oemtext(CFDataRef data)
858 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_OEMCP);
862 /**************************************************************************
863 * import_unicodetext_to_text
865 * Import a CF_UNICODETEXT string, converting the string to CF_TEXT.
867 static HANDLE import_unicodetext_to_text(CFDataRef data)
869 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_ACP);
873 /**************************************************************************
874 * import_utf8_to_oemtext
876 * Import a UTF-8 string, converting the string to CF_OEMTEXT.
878 static HANDLE import_utf8_to_oemtext(CFDataRef data)
880 HANDLE unicode_handle = import_utf8_to_unicodetext(data);
881 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_OEMCP);
883 GlobalFree(unicode_handle);
884 return ret;
888 /**************************************************************************
889 * import_utf8_to_text
891 * Import a UTF-8 string, converting the string to CF_TEXT.
893 static HANDLE import_utf8_to_text(CFDataRef data)
895 HANDLE unicode_handle = import_utf8_to_unicodetext(data);
896 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_ACP);
898 GlobalFree(unicode_handle);
899 return ret;
903 /**************************************************************************
904 * import_utf8_to_unicodetext
906 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
908 static HANDLE import_utf8_to_unicodetext(CFDataRef data)
910 const BYTE *src;
911 unsigned long data_len;
912 unsigned long new_lines = 0;
913 LPSTR dst;
914 unsigned long i, j;
915 HANDLE unicode_handle = NULL;
917 src = CFDataGetBytePtr(data);
918 data_len = CFDataGetLength(data);
919 for (i = 0; i < data_len; i++)
921 if (src[i] == '\n')
922 new_lines++;
925 if ((dst = HeapAlloc(GetProcessHeap(), 0, data_len + new_lines + 1)))
927 UINT count;
929 for (i = 0, j = 0; i < data_len; i++)
931 if (src[i] == '\n')
932 dst[j++] = '\r';
934 dst[j++] = src[i];
936 dst[j] = 0;
938 count = MultiByteToWideChar(CP_UTF8, 0, dst, -1, NULL, 0);
939 unicode_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, count * sizeof(WCHAR));
941 if (unicode_handle)
943 WCHAR *textW = GlobalLock(unicode_handle);
944 MultiByteToWideChar(CP_UTF8, 0, dst, -1, textW, count);
945 GlobalUnlock(unicode_handle);
948 HeapFree(GetProcessHeap(), 0, dst);
951 return unicode_handle;
955 /**************************************************************************
956 * export_clipboard_data
958 * Generic export clipboard data routine.
960 static CFDataRef export_clipboard_data(HANDLE data)
962 CFDataRef ret;
963 UINT len;
964 LPVOID src;
966 len = GlobalSize(data);
967 src = GlobalLock(data);
968 if (!src) return NULL;
970 ret = CFDataCreate(NULL, src, len);
971 GlobalUnlock(data);
973 return ret;
977 /**************************************************************************
978 * export_bitmap_to_bmp
980 * Export CF_BITMAP to BMP file format.
982 static CFDataRef export_bitmap_to_bmp(HANDLE data)
984 CFDataRef ret = NULL;
985 HGLOBAL dib;
987 dib = create_dib_from_bitmap(data);
988 if (dib)
990 ret = export_dib_to_bmp(dib);
991 GlobalFree(dib);
994 return ret;
998 /**************************************************************************
999 * export_codepage_to_utf8
1001 * Export string data in a specified codepage to UTF-8.
1003 static CFDataRef export_codepage_to_utf8(HANDLE data, UINT cp)
1005 CFDataRef ret = NULL;
1006 const char* str;
1008 if ((str = GlobalLock(data)))
1010 HANDLE unicode = convert_text(str, GlobalSize(data), cp, -1);
1012 ret = export_unicodetext_to_utf8(unicode);
1014 GlobalFree(unicode);
1015 GlobalUnlock(data);
1018 return ret;
1022 /**************************************************************************
1023 * export_dib_to_bmp
1025 * Export CF_DIB to BMP file format. This just entails prepending a BMP
1026 * file format header to the data.
1028 static CFDataRef export_dib_to_bmp(HANDLE data)
1030 CFMutableDataRef ret = NULL;
1031 BYTE *dibdata;
1032 CFIndex len;
1033 BITMAPFILEHEADER bfh;
1035 dibdata = GlobalLock(data);
1036 if (!dibdata)
1037 return NULL;
1039 len = sizeof(bfh) + GlobalSize(data);
1040 ret = CFDataCreateMutable(NULL, len);
1041 if (ret)
1043 bfh.bfType = 0x4d42; /* "BM" */
1044 bfh.bfSize = len;
1045 bfh.bfReserved1 = 0;
1046 bfh.bfReserved2 = 0;
1047 bfh.bfOffBits = sizeof(bfh) + bitmap_info_size((BITMAPINFO*)dibdata, DIB_RGB_COLORS);
1048 CFDataAppendBytes(ret, (UInt8*)&bfh, sizeof(bfh));
1050 /* rest of bitmap is the same as the packed dib */
1051 CFDataAppendBytes(ret, (UInt8*)dibdata, len - sizeof(bfh));
1054 GlobalUnlock(data);
1056 return ret;
1060 /**************************************************************************
1061 * export_hdrop_to_filenames
1063 * Export CF_HDROP to NSFilenamesPboardType data, which is a CFArray of
1064 * CFStrings (holding Unix paths) which is serialized as a property list.
1066 static CFDataRef export_hdrop_to_filenames(HANDLE data)
1068 CFDataRef ret = NULL;
1069 DROPFILES *dropfiles;
1070 CFMutableArrayRef filenames = NULL;
1071 void *p;
1072 WCHAR *buffer = NULL;
1073 size_t buffer_len = 0;
1075 TRACE("data %p\n", data);
1077 if (!(dropfiles = GlobalLock(data)))
1079 WARN("failed to lock data %p\n", data);
1080 goto done;
1083 filenames = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1084 if (!filenames)
1086 WARN("failed to create filenames array\n");
1087 goto done;
1090 p = (char*)dropfiles + dropfiles->pFiles;
1091 while (dropfiles->fWide ? *(WCHAR*)p : *(char*)p)
1093 char *unixname;
1094 CFStringRef filename;
1096 TRACE(" %s\n", dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1098 if (dropfiles->fWide)
1099 unixname = wine_get_unix_file_name(p);
1100 else
1102 int len = MultiByteToWideChar(CP_ACP, 0, p, -1, NULL, 0);
1103 if (len)
1105 if (len > buffer_len)
1107 HeapFree(GetProcessHeap(), 0, buffer);
1108 buffer_len = len * 2;
1109 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_len * sizeof(*buffer));
1112 MultiByteToWideChar(CP_ACP, 0, p, -1, buffer, buffer_len);
1113 unixname = wine_get_unix_file_name(buffer);
1115 else
1116 unixname = NULL;
1118 if (!unixname)
1120 WARN("failed to convert DOS path to Unix: %s\n",
1121 dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1122 goto done;
1125 if (dropfiles->fWide)
1126 p = (WCHAR*)p + strlenW(p) + 1;
1127 else
1128 p = (char*)p + strlen(p) + 1;
1130 filename = CFStringCreateWithFileSystemRepresentation(NULL, unixname);
1131 HeapFree(GetProcessHeap(), 0, unixname);
1132 if (!filename)
1134 WARN("failed to create CFString from Unix path %s\n", debugstr_a(unixname));
1135 goto done;
1138 CFArrayAppendValue(filenames, filename);
1139 CFRelease(filename);
1142 ret = CFPropertyListCreateData(NULL, filenames, kCFPropertyListXMLFormat_v1_0, 0, NULL);
1144 done:
1145 HeapFree(GetProcessHeap(), 0, buffer);
1146 GlobalUnlock(data);
1147 if (filenames) CFRelease(filenames);
1148 TRACE(" -> %s\n", debugstr_cf(ret));
1149 return ret;
1153 /**************************************************************************
1154 * export_oemtext_to_utf8
1156 * Export CF_OEMTEXT to UTF-8.
1158 static CFDataRef export_oemtext_to_utf8(HANDLE data)
1160 return export_codepage_to_utf8(data, CP_OEMCP);
1164 /**************************************************************************
1165 * export_text_to_utf8
1167 * Export CF_TEXT to UTF-8.
1169 static CFDataRef export_text_to_utf8(HANDLE data)
1171 return export_codepage_to_utf8(data, CP_ACP);
1175 /**************************************************************************
1176 * export_unicodetext_to_utf8
1178 * Export CF_UNICODETEXT to UTF-8.
1180 static CFDataRef export_unicodetext_to_utf8(HANDLE data)
1182 CFMutableDataRef ret;
1183 LPVOID src;
1184 INT dst_len;
1186 src = GlobalLock(data);
1187 if (!src) return NULL;
1189 dst_len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
1190 if (dst_len) dst_len--; /* Leave off null terminator. */
1191 ret = CFDataCreateMutable(NULL, dst_len);
1192 if (ret)
1194 LPSTR dst;
1195 int i, j;
1197 CFDataSetLength(ret, dst_len);
1198 dst = (LPSTR)CFDataGetMutableBytePtr(ret);
1199 WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_len, NULL, NULL);
1201 /* Remove carriage returns */
1202 for (i = 0, j = 0; i < dst_len; i++)
1204 if (dst[i] == '\r' &&
1205 (i + 1 >= dst_len || dst[i + 1] == '\n' || dst[i + 1] == '\0'))
1206 continue;
1207 dst[j++] = dst[i];
1209 CFDataSetLength(ret, j);
1211 GlobalUnlock(data);
1213 return ret;
1217 /**************************************************************************
1218 * get_clipboard_info
1220 static BOOL get_clipboard_info(LPCLIPBOARDINFO cbinfo)
1222 BOOL ret = FALSE;
1224 SERVER_START_REQ(set_clipboard_info)
1226 req->flags = 0;
1228 if (wine_server_call_err(req))
1230 ERR("Failed to get clipboard owner.\n");
1232 else
1234 cbinfo->hwnd_owner = wine_server_ptr_handle(reply->old_owner);
1235 cbinfo->flags = reply->flags;
1237 ret = TRUE;
1240 SERVER_END_REQ;
1242 return ret;
1246 /**************************************************************************
1247 * release_ownership
1249 static BOOL release_ownership(void)
1251 BOOL ret = FALSE;
1253 SERVER_START_REQ(set_clipboard_info)
1255 req->flags = SET_CB_RELOWNER | SET_CB_SEQNO;
1257 if (wine_server_call_err(req))
1258 ERR("Failed to set clipboard.\n");
1259 else
1260 ret = TRUE;
1262 SERVER_END_REQ;
1264 return ret;
1268 /**************************************************************************
1269 * macdrv_get_pasteboard_data
1271 HANDLE macdrv_get_pasteboard_data(CFTypeRef pasteboard, UINT desired_format)
1273 CFArrayRef types;
1274 CFIndex count;
1275 CFIndex i;
1276 CFStringRef type, best_type;
1277 WINE_CLIPFORMAT* best_format = NULL;
1278 HANDLE data = NULL;
1280 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1282 types = macdrv_copy_pasteboard_types(pasteboard);
1283 if (!types)
1285 WARN("Failed to copy pasteboard types\n");
1286 return NULL;
1289 count = CFArrayGetCount(types);
1290 TRACE("got %ld types\n", count);
1292 for (i = 0; (!best_format || best_format->synthesized) && i < count; i++)
1294 WINE_CLIPFORMAT* format;
1296 type = CFArrayGetValueAtIndex(types, i);
1298 format = NULL;
1299 while ((!best_format || best_format->synthesized) && (format = format_for_type(format, type)))
1301 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format ? format->format_id : 0));
1303 if (format->format_id == desired_format)
1305 /* The best format is the matching one which is not synthesized. Failing that,
1306 the best format is the first matching synthesized format. */
1307 if (!format->synthesized || !best_format)
1309 best_type = type;
1310 best_format = format;
1316 if (best_format)
1318 CFDataRef pasteboard_data = macdrv_copy_pasteboard_data(pasteboard, best_type);
1320 TRACE("got pasteboard data for type %s: %s\n", debugstr_cf(best_type), debugstr_cf(pasteboard_data));
1322 if (pasteboard_data)
1324 data = best_format->import_func(pasteboard_data);
1325 CFRelease(pasteboard_data);
1329 CFRelease(types);
1330 TRACE(" -> %p\n", data);
1331 return data;
1335 /**************************************************************************
1336 * macdrv_pasteboard_has_format
1338 BOOL macdrv_pasteboard_has_format(CFTypeRef pasteboard, UINT desired_format)
1340 CFArrayRef types;
1341 int count;
1342 UINT i;
1343 BOOL found = FALSE;
1345 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1347 types = macdrv_copy_pasteboard_types(pasteboard);
1348 if (!types)
1350 WARN("Failed to copy pasteboard types\n");
1351 return FALSE;
1354 count = CFArrayGetCount(types);
1355 TRACE("got %d types\n", count);
1357 for (i = 0; !found && i < count; i++)
1359 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1360 WINE_CLIPFORMAT* format;
1362 format = NULL;
1363 while (!found && (format = format_for_type(format, type)))
1365 TRACE("for type %s got format %s\n", debugstr_cf(type), debugstr_format(format->format_id));
1367 if (format->format_id == desired_format)
1368 found = TRUE;
1372 CFRelease(types);
1373 TRACE(" -> %d\n", found);
1374 return found;
1378 /**************************************************************************
1379 * macdrv_copy_pasteboard_formats
1381 CFArrayRef macdrv_copy_pasteboard_formats(CFTypeRef pasteboard)
1383 CFArrayRef types;
1384 CFIndex count;
1385 CFMutableArrayRef formats;
1386 CFIndex i;
1388 TRACE("pasteboard %p\n", pasteboard);
1390 types = macdrv_copy_pasteboard_types(pasteboard);
1391 if (!types)
1393 WARN("Failed to copy pasteboard types\n");
1394 return NULL;
1397 count = CFArrayGetCount(types);
1398 TRACE("got %ld types\n", count);
1400 if (!count)
1402 CFRelease(types);
1403 return NULL;
1406 formats = CFArrayCreateMutable(NULL, 0, NULL);
1407 if (!formats)
1409 WARN("Failed to allocate formats array\n");
1410 CFRelease(types);
1411 return NULL;
1414 for (i = 0; i < count; i++)
1416 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1417 WINE_CLIPFORMAT* format;
1419 format = NULL;
1420 while ((format = format_for_type(format, type)))
1422 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1424 if (format->synthesized)
1426 /* Don't override a real value with a synthesized value. */
1427 if (!CFArrayContainsValue(formats, CFRangeMake(0, CFArrayGetCount(formats)), (void*)format->format_id))
1428 CFArrayAppendValue(formats, (void*)format->format_id);
1430 else
1432 /* If the type was already in the array, it must have been synthesized
1433 because this one's real. Remove the synthesized entry in favor of
1434 this one. */
1435 CFIndex index = CFArrayGetFirstIndexOfValue(formats, CFRangeMake(0, CFArrayGetCount(formats)),
1436 (void*)format->format_id);
1437 if (index != kCFNotFound)
1438 CFArrayRemoveValueAtIndex(formats, index);
1439 CFArrayAppendValue(formats, (void*)format->format_id);
1444 CFRelease(types);
1446 TRACE(" -> %s\n", debugstr_cf(formats));
1447 return formats;
1451 /**************************************************************************
1452 * check_clipboard_ownership
1454 static void check_clipboard_ownership(HWND *owner)
1456 CLIPBOARDINFO cbinfo;
1458 if (owner) *owner = NULL;
1460 /* If Wine thinks we're the clipboard owner but Mac OS X thinks we're not
1461 the pasteboard owner, update Wine. */
1462 if (get_clipboard_info(&cbinfo) && (cbinfo.flags & CB_PROCESS))
1464 if (!(cbinfo.flags & CB_OPEN) && !macdrv_is_pasteboard_owner())
1466 TRACE("Lost clipboard ownership\n");
1468 if (OpenClipboard(cbinfo.hwnd_owner))
1470 /* Destroy private objects */
1471 SendMessageW(cbinfo.hwnd_owner, WM_DESTROYCLIPBOARD, 0, 0);
1473 /* Give up ownership of the windows clipboard */
1474 release_ownership();
1475 CloseClipboard();
1478 else if (owner)
1479 *owner = cbinfo.hwnd_owner;
1484 /**************************************************************************
1485 * Mac User Driver Clipboard Exports
1486 **************************************************************************/
1489 /**************************************************************************
1490 * AcquireClipboard (MACDRV.@)
1492 int CDECL macdrv_AcquireClipboard(HWND hwnd)
1494 TRACE("hwnd %p\n", hwnd);
1495 check_clipboard_ownership(NULL);
1496 return 0;
1500 /**************************************************************************
1501 * CountClipboardFormats (MACDRV.@)
1503 INT CDECL macdrv_CountClipboardFormats(void)
1505 CFMutableSetRef seen_formats;
1506 CFArrayRef types;
1507 CFIndex count;
1508 CFIndex i;
1509 INT ret = 0;
1511 TRACE("()\n");
1512 check_clipboard_ownership(NULL);
1514 seen_formats = CFSetCreateMutable(NULL, 0, NULL);
1515 if (!seen_formats)
1517 WARN("Failed to allocate set to track seen formats\n");
1518 return 0;
1521 types = macdrv_copy_pasteboard_types(NULL);
1522 if (!types)
1524 WARN("Failed to copy pasteboard types\n");
1525 CFRelease(seen_formats);
1526 return 0;
1529 count = CFArrayGetCount(types);
1530 TRACE("got %ld types\n", count);
1532 for (i = 0; i < count; i++)
1534 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1535 WINE_CLIPFORMAT* format;
1537 format = NULL;
1538 while ((format = format_for_type(format, type)))
1540 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1542 if (!CFSetContainsValue(seen_formats, (void*)format->format_id))
1544 ret++;
1545 CFSetAddValue(seen_formats, (void*)format->format_id);
1550 CFRelease(seen_formats);
1551 TRACE(" -> %d\n", ret);
1552 return ret;
1556 /**************************************************************************
1557 * EmptyClipboard (MACDRV.@)
1559 * Empty cached clipboard data.
1561 void CDECL macdrv_EmptyClipboard(BOOL keepunowned)
1563 TRACE("keepunowned %d\n", keepunowned);
1564 macdrv_clear_pasteboard();
1568 /**************************************************************************
1569 * EndClipboardUpdate (MACDRV.@)
1571 void CDECL macdrv_EndClipboardUpdate(void)
1573 TRACE("()\n");
1574 check_clipboard_ownership(NULL);
1578 /**************************************************************************
1579 * EnumClipboardFormats (MACDRV.@)
1581 UINT CDECL macdrv_EnumClipboardFormats(UINT prev_format)
1583 CFIndex count;
1584 CFIndex i;
1585 UINT ret = 0;
1587 TRACE("prev_format %s\n", debugstr_format(prev_format));
1588 check_clipboard_ownership(NULL);
1590 if (prev_format)
1592 CFArrayRef formats = macdrv_copy_pasteboard_formats(NULL);
1593 if (formats)
1595 count = CFArrayGetCount(formats);
1596 i = CFArrayGetFirstIndexOfValue(formats, CFRangeMake(0, count), (void*)prev_format);
1597 if (i != kCFNotFound && i + 1 < count)
1598 ret = (UINT)CFArrayGetValueAtIndex(formats, i + 1);
1600 CFRelease(formats);
1603 else
1605 CFArrayRef types = macdrv_copy_pasteboard_types(NULL);
1606 if (types)
1608 count = CFArrayGetCount(types);
1609 TRACE("got %ld types\n", count);
1611 if (count)
1613 CFStringRef type = CFArrayGetValueAtIndex(types, 0);
1614 WINE_CLIPFORMAT *format = format_for_type(NULL, type);
1616 ret = format ? format->format_id : 0;
1619 CFRelease(types);
1621 else
1622 WARN("Failed to copy pasteboard types\n");
1625 TRACE(" -> %u\n", ret);
1626 return ret;
1630 /**************************************************************************
1631 * GetClipboardData (MACDRV.@)
1633 HANDLE CDECL macdrv_GetClipboardData(UINT desired_format)
1635 check_clipboard_ownership(NULL);
1637 return macdrv_get_pasteboard_data(NULL, desired_format);
1641 /**************************************************************************
1642 * IsClipboardFormatAvailable (MACDRV.@)
1644 BOOL CDECL macdrv_IsClipboardFormatAvailable(UINT desired_format)
1646 check_clipboard_ownership(NULL);
1647 return macdrv_pasteboard_has_format(NULL, desired_format);
1651 /**************************************************************************
1652 * SetClipboardData (MACDRV.@)
1654 BOOL CDECL macdrv_SetClipboardData(UINT format_id, HANDLE data, BOOL owner)
1656 HWND hwnd_owner;
1657 macdrv_window window;
1658 WINE_CLIPFORMAT *format;
1659 CFDataRef cfdata = NULL;
1661 check_clipboard_ownership(&hwnd_owner);
1662 window = macdrv_get_cocoa_window(GetAncestor(hwnd_owner, GA_ROOT), FALSE);
1663 TRACE("format_id %s data %p owner %d hwnd_owner %p window %p)\n", debugstr_format(format_id), data, owner, hwnd_owner, window);
1665 /* Find the "natural" format for this format_id (the one which isn't
1666 synthesized from another type). */
1667 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1668 if (format->format_id == format_id && !format->synthesized) break;
1670 if (&format->entry == &format_list && !(format = insert_clipboard_format(format_id, NULL)))
1672 WARN("Failed to register clipboard format %s\n", debugstr_format(format_id));
1673 return FALSE;
1676 /* Export the data to the Mac pasteboard. */
1677 if (data)
1679 if (!format->export_func || !(cfdata = format->export_func(data)))
1681 WARN("Failed to export %s data to type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1682 return FALSE;
1686 if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1687 TRACE("Set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1688 else
1690 WARN("Failed to set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1691 if (cfdata) CFRelease(cfdata);
1692 return FALSE;
1695 if (cfdata) CFRelease(cfdata);
1697 /* Find any other formats for this format_id (the exportable synthesized ones). */
1698 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1700 if (format->format_id == format_id && format->synthesized && format->export_func)
1702 /* We have a synthesized format for this format ID. Add its type to the pasteboard. */
1703 TRACE("Synthesized from format %s: type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1705 if (data)
1707 cfdata = format->export_func(data);
1708 if (!cfdata)
1710 WARN("Failed to export %s data to type %s\n", debugstr_format(format->format_id), debugstr_cf(format->type));
1711 continue;
1714 else
1715 cfdata = NULL;
1717 if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1718 TRACE(" ... set pasteboard data: %s\n", debugstr_cf(cfdata));
1719 else
1720 WARN(" ... failed to set pasteboard data: %s\n", debugstr_cf(cfdata));
1722 if (cfdata) CFRelease(cfdata);
1726 if (data)
1728 /* FIXME: According to MSDN, the caller is entitled to lock and read from
1729 data until CloseClipboard is called. So, we should defer this cleanup. */
1730 if ((format_id >= CF_GDIOBJFIRST && format_id <= CF_GDIOBJLAST) ||
1731 format_id == CF_BITMAP ||
1732 format_id == CF_DIB ||
1733 format_id == CF_PALETTE)
1735 DeleteObject(data);
1737 else if (format_id == CF_METAFILEPICT)
1739 DeleteMetaFile(((METAFILEPICT *)GlobalLock(data))->hMF);
1740 GlobalFree(data);
1742 else if (format_id == CF_ENHMETAFILE)
1744 DeleteEnhMetaFile(data);
1746 else if (format_id < CF_PRIVATEFIRST || CF_PRIVATELAST < format_id)
1748 GlobalFree(data);
1752 return TRUE;
1756 /**************************************************************************
1757 * MACDRV Private Clipboard Exports
1758 **************************************************************************/
1761 /**************************************************************************
1762 * macdrv_clipboard_process_attach
1764 void macdrv_clipboard_process_attach(void)
1766 UINT i;
1767 WINE_CLIPFORMAT *format;
1769 /* Register built-in formats */
1770 for (i = 0; i < sizeof(builtin_format_ids)/sizeof(builtin_format_ids[0]); i++)
1772 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
1773 format->format_id = builtin_format_ids[i].id;
1774 format->type = CFRetain(builtin_format_ids[i].type);
1775 format->import_func = builtin_format_ids[i].import;
1776 format->export_func = builtin_format_ids[i].export;
1777 format->synthesized = builtin_format_ids[i].synthesized;
1778 list_add_tail(&format_list, &format->entry);
1781 /* Register known mappings between Windows formats and Mac types */
1782 for (i = 0; i < sizeof(builtin_format_names)/sizeof(builtin_format_names[0]); i++)
1784 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
1785 format->format_id = RegisterClipboardFormatW(builtin_format_names[i].name);
1786 format->type = CFRetain(builtin_format_names[i].type);
1787 format->import_func = builtin_format_names[i].import;
1788 format->export_func = builtin_format_names[i].export;
1789 format->synthesized = FALSE;
1790 list_add_tail(&format_list, &format->entry);
1795 /**************************************************************************
1796 * query_pasteboard_data
1798 BOOL query_pasteboard_data(HWND hwnd, CFStringRef type)
1800 BOOL ret = FALSE;
1801 CLIPBOARDINFO cbinfo;
1802 WINE_CLIPFORMAT* format;
1803 CFArrayRef types = NULL;
1804 CFRange range;
1806 TRACE("hwnd %p type %s\n", hwnd, debugstr_cf(type));
1808 if (get_clipboard_info(&cbinfo))
1809 hwnd = cbinfo.hwnd_owner;
1811 format = NULL;
1812 while ((format = format_for_type(format, type)))
1814 WINE_CLIPFORMAT* base_format;
1816 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1818 if (!format->synthesized)
1820 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(format->format_id), hwnd);
1821 SendMessageW(hwnd, WM_RENDERFORMAT, format->format_id, 0);
1822 ret = TRUE;
1823 goto done;
1826 if (!types)
1828 types = macdrv_copy_pasteboard_types(NULL);
1829 if (!types)
1831 WARN("Failed to copy pasteboard types\n");
1832 break;
1835 range = CFRangeMake(0, CFArrayGetCount(types));
1838 /* The type maps to a synthesized format. Now look up what type that format maps to natively
1839 (not synthesized). For example, if type is "public.utf8-plain-text", then this format may
1840 have an ID of CF_TEXT. From CF_TEXT, we want to find "org.winehq.builtin.text" to see if
1841 that type is present in the pasteboard. If it is, then the app must have promised it and
1842 we can ask it to render it. (If it had put it on the clipboard immediately, then the
1843 pasteboard would also have data for "public.utf8-plain-text" and we wouldn't be here.) If
1844 "org.winehq.builtin.text" is not on the pasteboard, then one of the other text formats is
1845 presumably responsible for the promise that we're trying to satisfy, so we keep looking. */
1846 LIST_FOR_EACH_ENTRY(base_format, &format_list, WINE_CLIPFORMAT, entry)
1848 if (base_format->format_id == format->format_id && !base_format->synthesized &&
1849 CFArrayContainsValue(types, range, base_format->type))
1851 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(base_format->format_id), hwnd);
1852 SendMessageW(hwnd, WM_RENDERFORMAT, base_format->format_id, 0);
1853 ret = TRUE;
1854 goto done;
1859 done:
1860 if (types) CFRelease(types);
1862 return ret;