winemac: Reduce duplicated code by consolidating exit paths from format_for_type().
[wine.git] / dlls / winemac.drv / clipboard.c
blobf97faeaf3b457eeb2a8416ce6cafc8a81e08335a
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);
85 static HANDLE import_utf16_to_oemtext(CFDataRef data);
86 static HANDLE import_utf16_to_text(CFDataRef data);
87 static HANDLE import_utf16_to_unicodetext(CFDataRef data);
89 static CFDataRef export_clipboard_data(HANDLE data);
90 static CFDataRef export_bitmap_to_bmp(HANDLE data);
91 static CFDataRef export_dib_to_bmp(HANDLE data);
92 static CFDataRef export_hdrop_to_filenames(HANDLE data);
93 static CFDataRef export_oemtext_to_utf8(HANDLE data);
94 static CFDataRef export_oemtext_to_utf16(HANDLE data);
95 static CFDataRef export_text_to_utf8(HANDLE data);
96 static CFDataRef export_text_to_utf16(HANDLE data);
97 static CFDataRef export_unicodetext_to_utf8(HANDLE data);
98 static CFDataRef export_unicodetext_to_utf16(HANDLE data);
101 /**************************************************************************
102 * Static Variables
103 **************************************************************************/
105 /* Clipboard formats */
106 static struct list format_list = LIST_INIT(format_list);
108 /* There are two naming schemes involved and we want to have a mapping between
109 them. There are Win32 clipboard format names and there are Mac pasteboard
110 types.
112 The Win32 standard clipboard formats don't have names, but they are associated
113 with Mac pasteboard types through the following tables, which are used to
114 initialize the format_list. Where possible, the standard clipboard formats
115 are mapped to predefined pasteboard type UTIs. Otherwise, we create Wine-
116 specific types of the form "org.winehq.builtin.<format>", where <format> is
117 the name of the symbolic constant for the format minus "CF_" and lowercased.
118 E.g. CF_BITMAP -> org.winehq.builtin.bitmap.
120 Win32 clipboard formats which originate in a Windows program may be registered
121 with an arbitrary name. We construct a Mac pasteboard type from these by
122 prepending "org.winehq.registered." to the registered name.
124 Likewise, Mac pasteboard types which originate in other apps may have
125 arbitrary type strings. We construct a Win32 clipboard format name from
126 these by prepending "org.winehq.mac-type." to the Mac pasteboard type.
128 Summary:
129 Win32 clipboard format names:
130 <none> standard clipboard format; maps via
131 format_list to either a predefined Mac UTI
132 or org.winehq.builtin.<format>.
133 org.winehq.mac-type.<Mac type> representation of Mac type in Win32 land;
134 maps to <Mac type>
135 <other> name registered within Win32 land; maps to
136 org.winehq.registered.<other>
137 Mac pasteboard type names:
138 org.winehq.builtin.<format ID> representation of Win32 standard clipboard
139 format for which there was no corresponding
140 predefined Mac UTI; maps via format_list
141 org.winehq.registered.<format name> representation of Win32 registered
142 clipboard format name; maps to <format name>
143 <other> Mac pasteboard type originating with system
144 or other apps; either maps via format_list
145 to a standard clipboard format or maps to
146 org.winehq.mac-type.<other>
149 static const struct
151 UINT id;
152 CFStringRef type;
153 DRVIMPORTFUNC import;
154 DRVEXPORTFUNC export;
155 BOOL synthesized;
156 } builtin_format_ids[] =
158 { CF_DIBV5, CFSTR("org.winehq.builtin.dibv5"), import_clipboard_data, export_clipboard_data, FALSE },
159 { CF_DIF, CFSTR("org.winehq.builtin.dif"), import_clipboard_data, export_clipboard_data, FALSE },
160 { CF_DSPBITMAP, CFSTR("org.winehq.builtin.dspbitmap"), import_clipboard_data, export_clipboard_data, FALSE },
161 { CF_DSPENHMETAFILE, CFSTR("org.winehq.builtin.dspenhmetafile"), import_clipboard_data, export_clipboard_data, FALSE },
162 { CF_DSPMETAFILEPICT, CFSTR("org.winehq.builtin.dspmetafilepict"), import_clipboard_data, export_clipboard_data, FALSE },
163 { CF_DSPTEXT, CFSTR("org.winehq.builtin.dsptext"), import_clipboard_data, export_clipboard_data, FALSE },
164 { CF_LOCALE, CFSTR("org.winehq.builtin.locale"), import_clipboard_data, export_clipboard_data, FALSE },
165 { CF_OWNERDISPLAY, CFSTR("org.winehq.builtin.ownerdisplay"), import_clipboard_data, export_clipboard_data, FALSE },
166 { CF_PALETTE, CFSTR("org.winehq.builtin.palette"), import_clipboard_data, export_clipboard_data, FALSE },
167 { CF_PENDATA, CFSTR("org.winehq.builtin.pendata"), import_clipboard_data, export_clipboard_data, FALSE },
168 { CF_RIFF, CFSTR("org.winehq.builtin.riff"), import_clipboard_data, export_clipboard_data, FALSE },
169 { CF_SYLK, CFSTR("org.winehq.builtin.sylk"), import_clipboard_data, export_clipboard_data, FALSE },
170 { CF_TIFF, CFSTR("public.tiff"), import_clipboard_data, export_clipboard_data, FALSE },
171 { CF_WAVE, CFSTR("com.microsoft.waveform-audio"), import_clipboard_data, export_clipboard_data, FALSE },
173 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.unicodetext"), import_clipboard_data, export_clipboard_data, FALSE },
174 { CF_TEXT, CFSTR("org.winehq.builtin.unicodetext"), import_unicodetext_to_text, NULL, TRUE },
175 { CF_OEMTEXT, CFSTR("org.winehq.builtin.unicodetext"), import_unicodetext_to_oemtext, NULL, TRUE },
177 { CF_TEXT, CFSTR("org.winehq.builtin.text"), import_clipboard_data, export_clipboard_data, FALSE },
178 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.text"), import_text_to_unicodetext, NULL, TRUE },
179 { CF_OEMTEXT, CFSTR("org.winehq.builtin.text"), import_text_to_oemtext, NULL, TRUE },
181 { CF_OEMTEXT, CFSTR("org.winehq.builtin.oemtext"), import_clipboard_data, export_clipboard_data, FALSE },
182 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.oemtext"), import_oemtext_to_unicodetext, NULL, TRUE },
183 { CF_TEXT, CFSTR("org.winehq.builtin.oemtext"), import_oemtext_to_text, NULL, TRUE },
185 { CF_UNICODETEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_unicodetext, export_unicodetext_to_utf8, TRUE },
186 { CF_TEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_text, export_text_to_utf8, TRUE },
187 { CF_OEMTEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_oemtext, export_oemtext_to_utf8, TRUE },
189 { CF_UNICODETEXT, CFSTR("public.utf16-plain-text"), import_utf16_to_unicodetext, export_unicodetext_to_utf16,TRUE },
190 { CF_TEXT, CFSTR("public.utf16-plain-text"), import_utf16_to_text, export_text_to_utf16, TRUE },
191 { CF_OEMTEXT, CFSTR("public.utf16-plain-text"), import_utf16_to_oemtext, export_oemtext_to_utf16, TRUE },
193 { CF_DIB, CFSTR("org.winehq.builtin.dib"), import_clipboard_data, export_clipboard_data, FALSE },
194 { CF_DIB, CFSTR("com.microsoft.bmp"), import_bmp_to_dib, export_dib_to_bmp, TRUE },
196 { CF_BITMAP, CFSTR("org.winehq.builtin.bitmap"), import_bmp_to_bitmap, export_bitmap_to_bmp, FALSE },
197 { CF_BITMAP, CFSTR("com.microsoft.bmp"), import_bmp_to_bitmap, export_bitmap_to_bmp, TRUE },
199 { CF_HDROP, CFSTR("org.winehq.builtin.hdrop"), import_clipboard_data, export_clipboard_data, FALSE },
200 { CF_HDROP, CFSTR("NSFilenamesPboardType"), import_nsfilenames_to_hdrop, export_hdrop_to_filenames, TRUE },
203 static const WCHAR wszRichTextFormat[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
204 static const WCHAR wszGIF[] = {'G','I','F',0};
205 static const WCHAR wszJFIF[] = {'J','F','I','F',0};
206 static const WCHAR wszPNG[] = {'P','N','G',0};
207 static const WCHAR wszHTMLFormat[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
208 static const struct
210 LPCWSTR name;
211 CFStringRef type;
212 DRVIMPORTFUNC import;
213 DRVEXPORTFUNC export;
214 } builtin_format_names[] =
216 { wszRichTextFormat, CFSTR("public.rtf"), import_clipboard_data, export_clipboard_data },
217 { wszGIF, CFSTR("com.compuserve.gif"), import_clipboard_data, export_clipboard_data },
218 { wszJFIF, CFSTR("public.jpeg"), import_clipboard_data, export_clipboard_data },
219 { wszPNG, CFSTR("public.png"), import_clipboard_data, export_clipboard_data },
220 { wszHTMLFormat, CFSTR("public.html"), import_clipboard_data, export_clipboard_data },
221 { CFSTR_SHELLURLW, CFSTR("public.url"), import_utf8_to_text, export_text_to_utf8 },
224 /* The prefix prepended to an external Mac pasteboard type to make a Win32 clipboard format name. org.winehq.mac-type. */
225 static const WCHAR mac_type_name_prefix[] = {'o','r','g','.','w','i','n','e','h','q','.','m','a','c','-','t','y','p','e','.',0};
227 /* The prefix prepended to a Win32 clipboard format name to make a Mac pasteboard type. */
228 static const CFStringRef registered_name_type_prefix = CFSTR("org.winehq.registered.");
231 /**************************************************************************
232 * Internal Clipboard implementation methods
233 **************************************************************************/
236 * format_list functions
239 /**************************************************************************
240 * debugstr_format
242 const char *debugstr_format(UINT id)
244 WCHAR buffer[256];
246 if (GetClipboardFormatNameW(id, buffer, 256))
247 return wine_dbg_sprintf("0x%04x %s", id, debugstr_w(buffer));
249 switch (id)
251 #define BUILTIN(id) case id: return #id;
252 BUILTIN(CF_TEXT)
253 BUILTIN(CF_BITMAP)
254 BUILTIN(CF_METAFILEPICT)
255 BUILTIN(CF_SYLK)
256 BUILTIN(CF_DIF)
257 BUILTIN(CF_TIFF)
258 BUILTIN(CF_OEMTEXT)
259 BUILTIN(CF_DIB)
260 BUILTIN(CF_PALETTE)
261 BUILTIN(CF_PENDATA)
262 BUILTIN(CF_RIFF)
263 BUILTIN(CF_WAVE)
264 BUILTIN(CF_UNICODETEXT)
265 BUILTIN(CF_ENHMETAFILE)
266 BUILTIN(CF_HDROP)
267 BUILTIN(CF_LOCALE)
268 BUILTIN(CF_DIBV5)
269 BUILTIN(CF_OWNERDISPLAY)
270 BUILTIN(CF_DSPTEXT)
271 BUILTIN(CF_DSPBITMAP)
272 BUILTIN(CF_DSPMETAFILEPICT)
273 BUILTIN(CF_DSPENHMETAFILE)
274 #undef BUILTIN
275 default: return wine_dbg_sprintf("0x%04x", id);
280 /**************************************************************************
281 * insert_clipboard_format
283 static WINE_CLIPFORMAT *insert_clipboard_format(UINT id, CFStringRef type)
285 WINE_CLIPFORMAT *format;
287 format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format));
289 if (format == NULL)
291 WARN("No more memory for a new format!\n");
292 return NULL;
294 format->format_id = id;
295 format->import_func = import_clipboard_data;
296 format->export_func = export_clipboard_data;
297 format->synthesized = FALSE;
299 if (type)
300 format->type = CFStringCreateCopy(NULL, type);
301 else
303 WCHAR buffer[256];
305 if (!GetClipboardFormatNameW(format->format_id, buffer, sizeof(buffer) / sizeof(buffer[0])))
307 WARN("failed to get name for format %s; error 0x%08x\n", debugstr_format(format->format_id), GetLastError());
308 HeapFree(GetProcessHeap(), 0, format);
309 return NULL;
312 if (!strncmpW(buffer, mac_type_name_prefix, strlenW(mac_type_name_prefix)))
314 const WCHAR *p = buffer + strlenW(mac_type_name_prefix);
315 format->type = CFStringCreateWithCharacters(NULL, (UniChar*)p, strlenW(p));
317 else
319 format->type = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%S"),
320 registered_name_type_prefix, buffer);
324 list_add_tail(&format_list, &format->entry);
326 TRACE("Registering format %s type %s\n", debugstr_format(format->format_id),
327 debugstr_cf(format->type));
329 return format;
333 /**************************************************************************
334 * register_format
336 * Register a custom Mac clipboard format.
338 static WINE_CLIPFORMAT* register_format(UINT id, CFStringRef type)
340 WINE_CLIPFORMAT *format;
342 /* walk format chain to see if it's already registered */
343 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
344 if (format->format_id == id) return format;
346 return insert_clipboard_format(id, type);
350 /**************************************************************************
351 * format_for_type
353 static WINE_CLIPFORMAT* format_for_type(WINE_CLIPFORMAT *current, CFStringRef type)
355 struct list *ptr = current ? &current->entry : &format_list;
356 WINE_CLIPFORMAT *format = NULL;
358 TRACE("current %p/%s type %s\n", current, debugstr_format(current ? current->format_id : 0), debugstr_cf(type));
360 while ((ptr = list_next(&format_list, ptr)))
362 format = LIST_ENTRY(ptr, WINE_CLIPFORMAT, entry);
363 if (CFEqual(format->type, type))
364 goto done;
367 format = NULL;
368 if (!current)
370 LPWSTR name;
372 if (CFStringHasPrefix(type, CFSTR("org.winehq.builtin.")))
374 ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
375 debugstr_cf(type));
376 goto done;
378 else if (CFStringHasPrefix(type, registered_name_type_prefix))
380 int len = CFStringGetLength(type) - CFStringGetLength(registered_name_type_prefix);
381 name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
382 CFStringGetCharacters(type, CFRangeMake(CFStringGetLength(registered_name_type_prefix), len),
383 (UniChar*)name);
384 name[len] = 0;
386 else
388 int len = strlenW(mac_type_name_prefix) + CFStringGetLength(type);
389 name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
390 memcpy(name, mac_type_name_prefix, sizeof(mac_type_name_prefix));
391 CFStringGetCharacters(type, CFRangeMake(0, CFStringGetLength(type)),
392 (UniChar*)name + strlenW(mac_type_name_prefix));
393 name[len] = 0;
396 format = register_format(RegisterClipboardFormatW(name), type);
397 if (!format)
398 ERR("Failed to register format for type %s name %s\n", debugstr_cf(type), debugstr_w(name));
400 HeapFree(GetProcessHeap(), 0, name);
403 done:
404 TRACE(" -> %p/%s\n", format, debugstr_format(format ? format->format_id : 0));
405 return format;
409 /**************************************************************************
410 * convert_text
412 * Convert string data between code pages or to/from wide characters. The
413 * special value of (UINT)-1 for a code page indicates to use wide
414 * characters.
416 static HANDLE convert_text(const void *src, int src_len, UINT src_cp, UINT dest_cp)
418 HANDLE ret = NULL;
419 const WCHAR *wstr;
420 int wstr_len;
421 HANDLE handle;
422 char *p;
424 if (src_cp == (UINT)-1)
426 wstr = src;
427 wstr_len = src_len / sizeof(WCHAR);
429 else
431 WCHAR *temp;
433 wstr_len = MultiByteToWideChar(src_cp, 0, src, src_len, NULL, 0);
434 if (!src_len || ((const char*)src)[src_len - 1]) wstr_len += 1;
435 temp = HeapAlloc(GetProcessHeap(), 0, wstr_len * sizeof(WCHAR));
436 MultiByteToWideChar(src_cp, 0, src, src_len, temp, wstr_len);
437 temp[wstr_len - 1] = 0;
438 wstr = temp;
441 if (dest_cp == (UINT)-1)
443 handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, wstr_len * sizeof(WCHAR));
444 if (handle && (p = GlobalLock(handle)))
446 memcpy(p, wstr, wstr_len * sizeof(WCHAR));
447 GlobalUnlock(handle);
448 ret = handle;
451 else
453 INT len;
455 len = WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, NULL, 0, NULL, NULL);
456 if (!wstr_len || wstr[wstr_len - 1]) len += 1;
457 handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
459 if (handle && (p = GlobalLock(handle)))
461 WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, p, len, NULL, NULL);
462 p[len - 1] = 0;
463 GlobalUnlock(handle);
464 ret = handle;
468 return ret;
472 /**************************************************************************
473 * convert_unicodetext_to_codepage
475 static HANDLE convert_unicodetext_to_codepage(HANDLE unicode_handle, UINT cp)
477 LPWSTR unicode_string = GlobalLock(unicode_handle);
478 HANDLE ret = NULL;
480 if (unicode_string)
482 ret = convert_text(unicode_string, GlobalSize(unicode_handle), -1, cp);
483 GlobalUnlock(unicode_handle);
486 return ret;
490 /***********************************************************************
491 * bitmap_info_size
493 * Return the size of the bitmap info structure including color table.
495 static int bitmap_info_size(const BITMAPINFO *info, WORD coloruse)
497 unsigned int colors, size, masks = 0;
499 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
501 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER*)info;
502 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
503 return sizeof(BITMAPCOREHEADER) + colors *
504 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
506 else /* assume BITMAPINFOHEADER */
508 colors = info->bmiHeader.biClrUsed;
509 if (!colors && (info->bmiHeader.biBitCount <= 8))
510 colors = 1 << info->bmiHeader.biBitCount;
511 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
512 size = max(info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD));
513 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
518 /***********************************************************************
519 * create_dib_from_bitmap
521 * Allocates a packed DIB and copies the bitmap data into it.
523 static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp)
525 BITMAP bmp;
526 HDC hdc;
527 HGLOBAL hPackedDIB;
528 LPBYTE pPackedDIB;
529 LPBITMAPINFOHEADER pbmiHeader;
530 unsigned int cDataSize, cPackedSize, OffsetBits;
531 int nLinesCopied;
533 if (!GetObjectW(hBmp, sizeof(bmp), &bmp)) return 0;
536 * A packed DIB contains a BITMAPINFO structure followed immediately by
537 * an optional color palette and the pixel data.
540 /* Calculate the size of the packed DIB */
541 cDataSize = abs(bmp.bmHeight) * (((bmp.bmWidth * bmp.bmBitsPixel + 31) / 8) & ~3);
542 cPackedSize = sizeof(BITMAPINFOHEADER)
543 + ((bmp.bmBitsPixel <= 8) ? (sizeof(RGBQUAD) * (1 << bmp.bmBitsPixel)) : 0)
544 + cDataSize;
545 /* Get the offset to the bits */
546 OffsetBits = cPackedSize - cDataSize;
548 /* Allocate the packed DIB */
549 TRACE("\tAllocating packed DIB of size %d\n", cPackedSize);
550 hPackedDIB = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cPackedSize);
551 if (!hPackedDIB)
553 WARN("Could not allocate packed DIB!\n");
554 return 0;
557 /* A packed DIB starts with a BITMAPINFOHEADER */
558 pPackedDIB = GlobalLock(hPackedDIB);
559 pbmiHeader = (LPBITMAPINFOHEADER)pPackedDIB;
561 /* Init the BITMAPINFOHEADER */
562 pbmiHeader->biSize = sizeof(BITMAPINFOHEADER);
563 pbmiHeader->biWidth = bmp.bmWidth;
564 pbmiHeader->biHeight = bmp.bmHeight;
565 pbmiHeader->biPlanes = 1;
566 pbmiHeader->biBitCount = bmp.bmBitsPixel;
567 pbmiHeader->biCompression = BI_RGB;
568 pbmiHeader->biSizeImage = 0;
569 pbmiHeader->biXPelsPerMeter = pbmiHeader->biYPelsPerMeter = 0;
570 pbmiHeader->biClrUsed = 0;
571 pbmiHeader->biClrImportant = 0;
573 /* Retrieve the DIB bits from the bitmap and fill in the
574 * DIB color table if present */
575 hdc = GetDC(0);
576 nLinesCopied = GetDIBits(hdc, /* Handle to device context */
577 hBmp, /* Handle to bitmap */
578 0, /* First scan line to set in dest bitmap */
579 bmp.bmHeight, /* Number of scan lines to copy */
580 pPackedDIB + OffsetBits, /* [out] Address of array for bitmap bits */
581 (LPBITMAPINFO) pbmiHeader, /* [out] Address of BITMAPINFO structure */
582 0); /* RGB or palette index */
583 GlobalUnlock(hPackedDIB);
584 ReleaseDC(0, hdc);
586 /* Cleanup if GetDIBits failed */
587 if (nLinesCopied != bmp.bmHeight)
589 TRACE("\tGetDIBits returned %d. Actual lines=%d\n", nLinesCopied, bmp.bmHeight);
590 GlobalFree(hPackedDIB);
591 hPackedDIB = 0;
593 return hPackedDIB;
597 /**************************************************************************
598 * import_clipboard_data
600 * Generic import clipboard data routine.
602 static HANDLE import_clipboard_data(CFDataRef data)
604 HANDLE data_handle = NULL;
606 size_t len = CFDataGetLength(data);
607 if (len)
609 LPVOID p;
611 /* Turn on the DDESHARE flag to enable shared 32 bit memory */
612 data_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
613 if (!data_handle)
614 return NULL;
616 if ((p = GlobalLock(data_handle)))
618 memcpy(p, CFDataGetBytePtr(data), len);
619 GlobalUnlock(data_handle);
621 else
623 GlobalFree(data_handle);
624 data_handle = NULL;
628 return data_handle;
632 /**************************************************************************
633 * import_bmp_to_bitmap
635 * Import BMP data, converting to CF_BITMAP format.
637 static HANDLE import_bmp_to_bitmap(CFDataRef data)
639 HANDLE ret = 0;
640 HANDLE dib = import_bmp_to_dib(data);
641 BITMAPINFO *bmi;
643 if (dib && (bmi = GlobalLock(dib)))
645 HDC hdc;
646 unsigned int offset;
648 hdc = GetDC(NULL);
650 offset = bitmap_info_size(bmi, DIB_RGB_COLORS);
652 ret = CreateDIBitmap(hdc, &bmi->bmiHeader, CBM_INIT, (LPBYTE)bmi + offset,
653 bmi, DIB_RGB_COLORS);
655 GlobalUnlock(dib);
656 ReleaseDC(NULL, hdc);
659 GlobalFree(dib);
660 return ret;
664 /**************************************************************************
665 * import_bmp_to_dib
667 * Import BMP data, converting to CF_DIB format. This just entails
668 * stripping the BMP file format header.
670 static HANDLE import_bmp_to_dib(CFDataRef data)
672 HANDLE ret = 0;
673 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)CFDataGetBytePtr(data);
674 CFIndex len = CFDataGetLength(data);
676 if (len >= sizeof(*bfh) + sizeof(BITMAPCOREHEADER) &&
677 bfh->bfType == 0x4d42 /* "BM" */)
679 BITMAPINFO *bmi = (BITMAPINFO*)(bfh + 1);
680 BYTE* p;
682 len -= sizeof(*bfh);
683 ret = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
684 if (!ret || !(p = GlobalLock(ret)))
686 GlobalFree(ret);
687 return 0;
690 memcpy(p, bmi, len);
691 GlobalUnlock(ret);
694 return ret;
698 /**************************************************************************
699 * import_nsfilenames_to_hdrop
701 * Import NSFilenamesPboardType data, converting the property-list-
702 * serialized array of path strings to CF_HDROP.
704 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data)
706 HDROP hdrop = NULL;
707 CFArrayRef names;
708 CFIndex count, i;
709 size_t len;
710 char *buffer = NULL;
711 WCHAR **paths = NULL;
712 DROPFILES* dropfiles;
713 UniChar* p;
715 TRACE("data %s\n", debugstr_cf(data));
717 names = (CFArrayRef)CFPropertyListCreateWithData(NULL, data, kCFPropertyListImmutable,
718 NULL, NULL);
719 if (!names || CFGetTypeID(names) != CFArrayGetTypeID())
721 WARN("failed to interpret data as a CFArray\n");
722 goto done;
725 count = CFArrayGetCount(names);
727 len = 0;
728 for (i = 0; i < count; i++)
730 CFIndex this_len;
731 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
732 TRACE(" %s\n", debugstr_cf(name));
733 if (CFGetTypeID(name) != CFStringGetTypeID())
735 WARN("non-string in array\n");
736 goto done;
739 this_len = CFStringGetMaximumSizeOfFileSystemRepresentation(name);
740 if (this_len > len)
741 len = this_len;
744 buffer = HeapAlloc(GetProcessHeap(), 0, len);
745 if (!buffer)
747 WARN("failed to allocate buffer for file-system representations\n");
748 goto done;
751 paths = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(paths[0]));
752 if (!paths)
754 WARN("failed to allocate array of DOS paths\n");
755 goto done;
758 for (i = 0; i < count; i++)
760 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
761 if (!CFStringGetFileSystemRepresentation(name, buffer, len))
763 WARN("failed to get file-system representation for %s\n", debugstr_cf(name));
764 goto done;
766 paths[i] = wine_get_dos_file_name(buffer);
767 if (!paths[i])
769 WARN("failed to get DOS path for %s\n", debugstr_a(buffer));
770 goto done;
774 len = 1; /* for the terminating null */
775 for (i = 0; i < count; i++)
776 len += strlenW(paths[i]) + 1;
778 hdrop = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(*dropfiles) + len * sizeof(WCHAR));
779 if (!hdrop || !(dropfiles = GlobalLock(hdrop)))
781 WARN("failed to allocate HDROP\n");
782 GlobalFree(hdrop);
783 hdrop = NULL;
784 goto done;
787 dropfiles->pFiles = sizeof(*dropfiles);
788 dropfiles->pt.x = 0;
789 dropfiles->pt.y = 0;
790 dropfiles->fNC = FALSE;
791 dropfiles->fWide = TRUE;
793 p = (WCHAR*)(dropfiles + 1);
794 for (i = 0; i < count; i++)
796 strcpyW(p, paths[i]);
797 p += strlenW(p) + 1;
799 *p = 0;
801 GlobalUnlock(hdrop);
803 done:
804 if (paths)
806 for (i = 0; i < count; i++)
807 HeapFree(GetProcessHeap(), 0, paths[i]);
808 HeapFree(GetProcessHeap(), 0, paths);
810 HeapFree(GetProcessHeap(), 0, buffer);
811 if (names) CFRelease(names);
812 return hdrop;
816 /**************************************************************************
817 * import_oemtext_to_text
819 * Import CF_OEMTEXT data, converting the string to CF_TEXT.
821 static HANDLE import_oemtext_to_text(CFDataRef data)
823 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, CP_ACP);
827 /**************************************************************************
828 * import_oemtext_to_unicodetext
830 * Import CF_OEMTEXT data, converting the string to CF_UNICODETEXT.
832 static HANDLE import_oemtext_to_unicodetext(CFDataRef data)
834 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, -1);
838 /**************************************************************************
839 * import_text_to_oemtext
841 * Import CF_TEXT data, converting the string to CF_OEMTEXT.
843 static HANDLE import_text_to_oemtext(CFDataRef data)
845 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, CP_OEMCP);
849 /**************************************************************************
850 * import_text_to_unicodetext
852 * Import CF_TEXT data, converting the string to CF_UNICODETEXT.
854 static HANDLE import_text_to_unicodetext(CFDataRef data)
856 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, -1);
860 /**************************************************************************
861 * import_unicodetext_to_oemtext
863 * Import a CF_UNICODETEXT string, converting the string to CF_OEMTEXT.
865 static HANDLE import_unicodetext_to_oemtext(CFDataRef data)
867 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_OEMCP);
871 /**************************************************************************
872 * import_unicodetext_to_text
874 * Import a CF_UNICODETEXT string, converting the string to CF_TEXT.
876 static HANDLE import_unicodetext_to_text(CFDataRef data)
878 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_ACP);
882 /**************************************************************************
883 * import_utf8_to_oemtext
885 * Import a UTF-8 string, converting the string to CF_OEMTEXT.
887 static HANDLE import_utf8_to_oemtext(CFDataRef data)
889 HANDLE unicode_handle = import_utf8_to_unicodetext(data);
890 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_OEMCP);
892 GlobalFree(unicode_handle);
893 return ret;
897 /**************************************************************************
898 * import_utf8_to_text
900 * Import a UTF-8 string, converting the string to CF_TEXT.
902 static HANDLE import_utf8_to_text(CFDataRef data)
904 HANDLE unicode_handle = import_utf8_to_unicodetext(data);
905 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_ACP);
907 GlobalFree(unicode_handle);
908 return ret;
912 /**************************************************************************
913 * import_utf8_to_unicodetext
915 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
917 static HANDLE import_utf8_to_unicodetext(CFDataRef data)
919 const BYTE *src;
920 unsigned long src_len;
921 unsigned long new_lines = 0;
922 LPSTR dst;
923 unsigned long i, j;
924 HANDLE unicode_handle = NULL;
926 src = CFDataGetBytePtr(data);
927 src_len = CFDataGetLength(data);
928 for (i = 0; i < src_len; i++)
930 if (src[i] == '\n')
931 new_lines++;
934 if ((dst = HeapAlloc(GetProcessHeap(), 0, src_len + new_lines + 1)))
936 UINT count;
938 for (i = 0, j = 0; i < src_len; i++)
940 if (src[i] == '\n')
941 dst[j++] = '\r';
943 dst[j++] = src[i];
945 dst[j] = 0;
947 count = MultiByteToWideChar(CP_UTF8, 0, dst, -1, NULL, 0);
948 unicode_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, count * sizeof(WCHAR));
950 if (unicode_handle)
952 WCHAR *textW = GlobalLock(unicode_handle);
953 MultiByteToWideChar(CP_UTF8, 0, dst, -1, textW, count);
954 GlobalUnlock(unicode_handle);
957 HeapFree(GetProcessHeap(), 0, dst);
960 return unicode_handle;
964 /**************************************************************************
965 * import_utf16_to_oemtext
967 * Import a UTF-16 string, converting the string to CF_OEMTEXT.
969 static HANDLE import_utf16_to_oemtext(CFDataRef data)
971 HANDLE unicode_handle = import_utf16_to_unicodetext(data);
972 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_OEMCP);
974 GlobalFree(unicode_handle);
975 return ret;
979 /**************************************************************************
980 * import_utf16_to_text
982 * Import a UTF-16 string, converting the string to CF_TEXT.
984 static HANDLE import_utf16_to_text(CFDataRef data)
986 HANDLE unicode_handle = import_utf16_to_unicodetext(data);
987 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_ACP);
989 GlobalFree(unicode_handle);
990 return ret;
994 /**************************************************************************
995 * import_utf16_to_unicodetext
997 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
999 static HANDLE import_utf16_to_unicodetext(CFDataRef data)
1001 const WCHAR *src;
1002 unsigned long src_len;
1003 unsigned long new_lines = 0;
1004 LPWSTR dst;
1005 unsigned long i, j;
1006 HANDLE unicode_handle;
1008 src = (const WCHAR *)CFDataGetBytePtr(data);
1009 src_len = CFDataGetLength(data) / sizeof(WCHAR);
1010 for (i = 0; i < src_len; i++)
1012 if (src[i] == '\n')
1013 new_lines++;
1016 if ((unicode_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (src_len + new_lines + 1) * sizeof(WCHAR))))
1018 dst = GlobalLock(unicode_handle);
1020 for (i = 0, j = 0; i < src_len; i++)
1022 if (src[i] == '\n')
1023 dst[j++] = '\r';
1025 dst[j++] = src[i];
1027 dst[j] = 0;
1029 GlobalUnlock(unicode_handle);
1032 return unicode_handle;
1036 /**************************************************************************
1037 * export_clipboard_data
1039 * Generic export clipboard data routine.
1041 static CFDataRef export_clipboard_data(HANDLE data)
1043 CFDataRef ret;
1044 UINT len;
1045 LPVOID src;
1047 len = GlobalSize(data);
1048 src = GlobalLock(data);
1049 if (!src) return NULL;
1051 ret = CFDataCreate(NULL, src, len);
1052 GlobalUnlock(data);
1054 return ret;
1058 /**************************************************************************
1059 * export_bitmap_to_bmp
1061 * Export CF_BITMAP to BMP file format.
1063 static CFDataRef export_bitmap_to_bmp(HANDLE data)
1065 CFDataRef ret = NULL;
1066 HGLOBAL dib;
1068 dib = create_dib_from_bitmap(data);
1069 if (dib)
1071 ret = export_dib_to_bmp(dib);
1072 GlobalFree(dib);
1075 return ret;
1079 /**************************************************************************
1080 * export_codepage_to_utf8
1082 * Export string data in a specified codepage to UTF-8.
1084 static CFDataRef export_codepage_to_utf8(HANDLE data, UINT cp)
1086 CFDataRef ret = NULL;
1087 const char* str;
1089 if ((str = GlobalLock(data)))
1091 HANDLE unicode = convert_text(str, GlobalSize(data), cp, -1);
1093 ret = export_unicodetext_to_utf8(unicode);
1095 GlobalFree(unicode);
1096 GlobalUnlock(data);
1099 return ret;
1103 /**************************************************************************
1104 * export_codepage_to_utf16
1106 * Export string data in a specified codepage to UTF-16.
1108 static CFDataRef export_codepage_to_utf16(HANDLE data, UINT cp)
1110 CFDataRef ret = NULL;
1111 const char* str;
1113 if ((str = GlobalLock(data)))
1115 HANDLE unicode = convert_text(str, GlobalSize(data), cp, -1);
1117 ret = export_unicodetext_to_utf16(unicode);
1119 GlobalFree(unicode);
1120 GlobalUnlock(data);
1123 return ret;
1127 /**************************************************************************
1128 * export_dib_to_bmp
1130 * Export CF_DIB to BMP file format. This just entails prepending a BMP
1131 * file format header to the data.
1133 static CFDataRef export_dib_to_bmp(HANDLE data)
1135 CFMutableDataRef ret = NULL;
1136 BYTE *dibdata;
1137 CFIndex len;
1138 BITMAPFILEHEADER bfh;
1140 dibdata = GlobalLock(data);
1141 if (!dibdata)
1142 return NULL;
1144 len = sizeof(bfh) + GlobalSize(data);
1145 ret = CFDataCreateMutable(NULL, len);
1146 if (ret)
1148 bfh.bfType = 0x4d42; /* "BM" */
1149 bfh.bfSize = len;
1150 bfh.bfReserved1 = 0;
1151 bfh.bfReserved2 = 0;
1152 bfh.bfOffBits = sizeof(bfh) + bitmap_info_size((BITMAPINFO*)dibdata, DIB_RGB_COLORS);
1153 CFDataAppendBytes(ret, (UInt8*)&bfh, sizeof(bfh));
1155 /* rest of bitmap is the same as the packed dib */
1156 CFDataAppendBytes(ret, (UInt8*)dibdata, len - sizeof(bfh));
1159 GlobalUnlock(data);
1161 return ret;
1165 /**************************************************************************
1166 * export_hdrop_to_filenames
1168 * Export CF_HDROP to NSFilenamesPboardType data, which is a CFArray of
1169 * CFStrings (holding Unix paths) which is serialized as a property list.
1171 static CFDataRef export_hdrop_to_filenames(HANDLE data)
1173 CFDataRef ret = NULL;
1174 DROPFILES *dropfiles;
1175 CFMutableArrayRef filenames = NULL;
1176 void *p;
1177 WCHAR *buffer = NULL;
1178 size_t buffer_len = 0;
1180 TRACE("data %p\n", data);
1182 if (!(dropfiles = GlobalLock(data)))
1184 WARN("failed to lock data %p\n", data);
1185 goto done;
1188 filenames = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1189 if (!filenames)
1191 WARN("failed to create filenames array\n");
1192 goto done;
1195 p = (char*)dropfiles + dropfiles->pFiles;
1196 while (dropfiles->fWide ? *(WCHAR*)p : *(char*)p)
1198 char *unixname;
1199 CFStringRef filename;
1201 TRACE(" %s\n", dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1203 if (dropfiles->fWide)
1204 unixname = wine_get_unix_file_name(p);
1205 else
1207 int len = MultiByteToWideChar(CP_ACP, 0, p, -1, NULL, 0);
1208 if (len)
1210 if (len > buffer_len)
1212 HeapFree(GetProcessHeap(), 0, buffer);
1213 buffer_len = len * 2;
1214 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_len * sizeof(*buffer));
1217 MultiByteToWideChar(CP_ACP, 0, p, -1, buffer, buffer_len);
1218 unixname = wine_get_unix_file_name(buffer);
1220 else
1221 unixname = NULL;
1223 if (!unixname)
1225 WARN("failed to convert DOS path to Unix: %s\n",
1226 dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1227 goto done;
1230 if (dropfiles->fWide)
1231 p = (WCHAR*)p + strlenW(p) + 1;
1232 else
1233 p = (char*)p + strlen(p) + 1;
1235 filename = CFStringCreateWithFileSystemRepresentation(NULL, unixname);
1236 HeapFree(GetProcessHeap(), 0, unixname);
1237 if (!filename)
1239 WARN("failed to create CFString from Unix path %s\n", debugstr_a(unixname));
1240 goto done;
1243 CFArrayAppendValue(filenames, filename);
1244 CFRelease(filename);
1247 ret = CFPropertyListCreateData(NULL, filenames, kCFPropertyListXMLFormat_v1_0, 0, NULL);
1249 done:
1250 HeapFree(GetProcessHeap(), 0, buffer);
1251 GlobalUnlock(data);
1252 if (filenames) CFRelease(filenames);
1253 TRACE(" -> %s\n", debugstr_cf(ret));
1254 return ret;
1258 /**************************************************************************
1259 * export_oemtext_to_utf8
1261 * Export CF_OEMTEXT to UTF-8.
1263 static CFDataRef export_oemtext_to_utf8(HANDLE data)
1265 return export_codepage_to_utf8(data, CP_OEMCP);
1269 /**************************************************************************
1270 * export_oemtext_to_utf16
1272 * Export CF_OEMTEXT to UTF-16.
1274 static CFDataRef export_oemtext_to_utf16(HANDLE data)
1276 return export_codepage_to_utf16(data, CP_OEMCP);
1280 /**************************************************************************
1281 * export_text_to_utf8
1283 * Export CF_TEXT to UTF-8.
1285 static CFDataRef export_text_to_utf8(HANDLE data)
1287 return export_codepage_to_utf8(data, CP_ACP);
1291 /**************************************************************************
1292 * export_text_to_utf16
1294 * Export CF_TEXT to UTF-16.
1296 static CFDataRef export_text_to_utf16(HANDLE data)
1298 return export_codepage_to_utf16(data, CP_ACP);
1302 /**************************************************************************
1303 * export_unicodetext_to_utf8
1305 * Export CF_UNICODETEXT to UTF-8.
1307 static CFDataRef export_unicodetext_to_utf8(HANDLE data)
1309 CFMutableDataRef ret;
1310 LPVOID src;
1311 INT dst_len;
1313 src = GlobalLock(data);
1314 if (!src) return NULL;
1316 dst_len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
1317 if (dst_len) dst_len--; /* Leave off null terminator. */
1318 ret = CFDataCreateMutable(NULL, dst_len);
1319 if (ret)
1321 LPSTR dst;
1322 int i, j;
1324 CFDataSetLength(ret, dst_len);
1325 dst = (LPSTR)CFDataGetMutableBytePtr(ret);
1326 WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_len, NULL, NULL);
1328 /* Remove carriage returns */
1329 for (i = 0, j = 0; i < dst_len; i++)
1331 if (dst[i] == '\r' &&
1332 (i + 1 >= dst_len || dst[i + 1] == '\n' || dst[i + 1] == '\0'))
1333 continue;
1334 dst[j++] = dst[i];
1336 CFDataSetLength(ret, j);
1338 GlobalUnlock(data);
1340 return ret;
1344 /**************************************************************************
1345 * export_unicodetext_to_utf16
1347 * Export CF_UNICODETEXT to UTF-16.
1349 static CFDataRef export_unicodetext_to_utf16(HANDLE data)
1351 CFMutableDataRef ret;
1352 const WCHAR *src;
1353 INT src_len;
1355 src = GlobalLock(data);
1356 if (!src) return NULL;
1358 src_len = GlobalSize(data) / sizeof(WCHAR);
1359 if (src_len) src_len--; /* Leave off null terminator. */
1360 ret = CFDataCreateMutable(NULL, src_len * sizeof(WCHAR));
1361 if (ret)
1363 LPWSTR dst;
1364 int i, j;
1366 CFDataSetLength(ret, src_len * sizeof(WCHAR));
1367 dst = (LPWSTR)CFDataGetMutableBytePtr(ret);
1369 /* Remove carriage returns */
1370 for (i = 0, j = 0; i < src_len; i++)
1372 if (src[i] == '\r' &&
1373 (i + 1 >= src_len || src[i + 1] == '\n' || src[i + 1] == '\0'))
1374 continue;
1375 dst[j++] = src[i];
1377 CFDataSetLength(ret, j * sizeof(WCHAR));
1379 GlobalUnlock(data);
1381 return ret;
1385 /**************************************************************************
1386 * get_clipboard_info
1388 static BOOL get_clipboard_info(LPCLIPBOARDINFO cbinfo)
1390 BOOL ret = FALSE;
1392 SERVER_START_REQ(set_clipboard_info)
1394 req->flags = 0;
1396 if (wine_server_call_err(req))
1398 ERR("Failed to get clipboard owner.\n");
1400 else
1402 cbinfo->hwnd_owner = wine_server_ptr_handle(reply->old_owner);
1403 cbinfo->flags = reply->flags;
1405 ret = TRUE;
1408 SERVER_END_REQ;
1410 return ret;
1414 /**************************************************************************
1415 * release_ownership
1417 static BOOL release_ownership(void)
1419 BOOL ret = FALSE;
1421 SERVER_START_REQ(set_clipboard_info)
1423 req->flags = SET_CB_RELOWNER | SET_CB_SEQNO;
1425 if (wine_server_call_err(req))
1426 ERR("Failed to set clipboard.\n");
1427 else
1428 ret = TRUE;
1430 SERVER_END_REQ;
1432 return ret;
1436 /**************************************************************************
1437 * macdrv_get_pasteboard_data
1439 HANDLE macdrv_get_pasteboard_data(CFTypeRef pasteboard, UINT desired_format)
1441 CFArrayRef types;
1442 CFIndex count;
1443 CFIndex i;
1444 CFStringRef type, best_type;
1445 WINE_CLIPFORMAT* best_format = NULL;
1446 HANDLE data = NULL;
1448 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1450 types = macdrv_copy_pasteboard_types(pasteboard);
1451 if (!types)
1453 WARN("Failed to copy pasteboard types\n");
1454 return NULL;
1457 count = CFArrayGetCount(types);
1458 TRACE("got %ld types\n", count);
1460 for (i = 0; (!best_format || best_format->synthesized) && i < count; i++)
1462 WINE_CLIPFORMAT* format;
1464 type = CFArrayGetValueAtIndex(types, i);
1466 format = NULL;
1467 while ((!best_format || best_format->synthesized) && (format = format_for_type(format, type)))
1469 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format ? format->format_id : 0));
1471 if (format->format_id == desired_format)
1473 /* The best format is the matching one which is not synthesized. Failing that,
1474 the best format is the first matching synthesized format. */
1475 if (!format->synthesized || !best_format)
1477 best_type = type;
1478 best_format = format;
1484 if (best_format)
1486 CFDataRef pasteboard_data = macdrv_copy_pasteboard_data(pasteboard, best_type);
1488 TRACE("got pasteboard data for type %s: %s\n", debugstr_cf(best_type), debugstr_cf(pasteboard_data));
1490 if (pasteboard_data)
1492 data = best_format->import_func(pasteboard_data);
1493 CFRelease(pasteboard_data);
1497 CFRelease(types);
1498 TRACE(" -> %p\n", data);
1499 return data;
1503 /**************************************************************************
1504 * macdrv_pasteboard_has_format
1506 BOOL macdrv_pasteboard_has_format(CFTypeRef pasteboard, UINT desired_format)
1508 CFArrayRef types;
1509 int count;
1510 UINT i;
1511 BOOL found = FALSE;
1513 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1515 types = macdrv_copy_pasteboard_types(pasteboard);
1516 if (!types)
1518 WARN("Failed to copy pasteboard types\n");
1519 return FALSE;
1522 count = CFArrayGetCount(types);
1523 TRACE("got %d types\n", count);
1525 for (i = 0; !found && i < count; i++)
1527 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1528 WINE_CLIPFORMAT* format;
1530 format = NULL;
1531 while (!found && (format = format_for_type(format, type)))
1533 TRACE("for type %s got format %s\n", debugstr_cf(type), debugstr_format(format->format_id));
1535 if (format->format_id == desired_format)
1536 found = TRUE;
1540 CFRelease(types);
1541 TRACE(" -> %d\n", found);
1542 return found;
1546 /**************************************************************************
1547 * macdrv_copy_pasteboard_formats
1549 CFArrayRef macdrv_copy_pasteboard_formats(CFTypeRef pasteboard)
1551 CFArrayRef types;
1552 CFIndex count;
1553 CFMutableArrayRef formats;
1554 CFIndex i;
1556 TRACE("pasteboard %p\n", pasteboard);
1558 types = macdrv_copy_pasteboard_types(pasteboard);
1559 if (!types)
1561 WARN("Failed to copy pasteboard types\n");
1562 return NULL;
1565 count = CFArrayGetCount(types);
1566 TRACE("got %ld types\n", count);
1568 if (!count)
1570 CFRelease(types);
1571 return NULL;
1574 formats = CFArrayCreateMutable(NULL, 0, NULL);
1575 if (!formats)
1577 WARN("Failed to allocate formats array\n");
1578 CFRelease(types);
1579 return NULL;
1582 for (i = 0; i < count; i++)
1584 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1585 WINE_CLIPFORMAT* format;
1587 format = NULL;
1588 while ((format = format_for_type(format, type)))
1590 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1592 if (format->synthesized)
1594 /* Don't override a real value with a synthesized value. */
1595 if (!CFArrayContainsValue(formats, CFRangeMake(0, CFArrayGetCount(formats)), (void*)format->format_id))
1596 CFArrayAppendValue(formats, (void*)format->format_id);
1598 else
1600 /* If the type was already in the array, it must have been synthesized
1601 because this one's real. Remove the synthesized entry in favor of
1602 this one. */
1603 CFIndex index = CFArrayGetFirstIndexOfValue(formats, CFRangeMake(0, CFArrayGetCount(formats)),
1604 (void*)format->format_id);
1605 if (index != kCFNotFound)
1606 CFArrayRemoveValueAtIndex(formats, index);
1607 CFArrayAppendValue(formats, (void*)format->format_id);
1612 CFRelease(types);
1614 TRACE(" -> %s\n", debugstr_cf(formats));
1615 return formats;
1619 /**************************************************************************
1620 * check_clipboard_ownership
1622 static void check_clipboard_ownership(HWND *owner)
1624 CLIPBOARDINFO cbinfo;
1626 if (owner) *owner = NULL;
1628 /* If Wine thinks we're the clipboard owner but Mac OS X thinks we're not
1629 the pasteboard owner, update Wine. */
1630 if (get_clipboard_info(&cbinfo) && (cbinfo.flags & CB_PROCESS))
1632 if (!(cbinfo.flags & CB_OPEN) && !macdrv_is_pasteboard_owner())
1634 TRACE("Lost clipboard ownership\n");
1636 if (OpenClipboard(cbinfo.hwnd_owner))
1638 /* Destroy private objects */
1639 SendMessageW(cbinfo.hwnd_owner, WM_DESTROYCLIPBOARD, 0, 0);
1641 /* Give up ownership of the windows clipboard */
1642 release_ownership();
1643 CloseClipboard();
1646 else if (owner)
1647 *owner = cbinfo.hwnd_owner;
1652 /**************************************************************************
1653 * Mac User Driver Clipboard Exports
1654 **************************************************************************/
1657 /**************************************************************************
1658 * AcquireClipboard (MACDRV.@)
1660 int CDECL macdrv_AcquireClipboard(HWND hwnd)
1662 TRACE("hwnd %p\n", hwnd);
1663 check_clipboard_ownership(NULL);
1664 return 0;
1668 /**************************************************************************
1669 * CountClipboardFormats (MACDRV.@)
1671 INT CDECL macdrv_CountClipboardFormats(void)
1673 CFMutableSetRef seen_formats;
1674 CFArrayRef types;
1675 CFIndex count;
1676 CFIndex i;
1677 INT ret = 0;
1679 TRACE("()\n");
1680 check_clipboard_ownership(NULL);
1682 seen_formats = CFSetCreateMutable(NULL, 0, NULL);
1683 if (!seen_formats)
1685 WARN("Failed to allocate set to track seen formats\n");
1686 return 0;
1689 types = macdrv_copy_pasteboard_types(NULL);
1690 if (!types)
1692 WARN("Failed to copy pasteboard types\n");
1693 CFRelease(seen_formats);
1694 return 0;
1697 count = CFArrayGetCount(types);
1698 TRACE("got %ld types\n", count);
1700 for (i = 0; i < count; i++)
1702 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1703 WINE_CLIPFORMAT* format;
1705 format = NULL;
1706 while ((format = format_for_type(format, type)))
1708 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1710 if (!CFSetContainsValue(seen_formats, (void*)format->format_id))
1712 ret++;
1713 CFSetAddValue(seen_formats, (void*)format->format_id);
1718 CFRelease(types);
1719 CFRelease(seen_formats);
1720 TRACE(" -> %d\n", ret);
1721 return ret;
1725 /**************************************************************************
1726 * EmptyClipboard (MACDRV.@)
1728 * Empty cached clipboard data.
1730 void CDECL macdrv_EmptyClipboard(BOOL keepunowned)
1732 TRACE("keepunowned %d\n", keepunowned);
1733 macdrv_clear_pasteboard();
1737 /**************************************************************************
1738 * EndClipboardUpdate (MACDRV.@)
1740 void CDECL macdrv_EndClipboardUpdate(void)
1742 TRACE("()\n");
1743 check_clipboard_ownership(NULL);
1747 /**************************************************************************
1748 * EnumClipboardFormats (MACDRV.@)
1750 UINT CDECL macdrv_EnumClipboardFormats(UINT prev_format)
1752 CFIndex count;
1753 CFIndex i;
1754 UINT ret = 0;
1756 TRACE("prev_format %s\n", debugstr_format(prev_format));
1757 check_clipboard_ownership(NULL);
1759 if (prev_format)
1761 CFArrayRef formats = macdrv_copy_pasteboard_formats(NULL);
1762 if (formats)
1764 count = CFArrayGetCount(formats);
1765 i = CFArrayGetFirstIndexOfValue(formats, CFRangeMake(0, count), (void*)prev_format);
1766 if (i != kCFNotFound && i + 1 < count)
1767 ret = (UINT)CFArrayGetValueAtIndex(formats, i + 1);
1769 CFRelease(formats);
1772 else
1774 CFArrayRef types = macdrv_copy_pasteboard_types(NULL);
1775 if (types)
1777 count = CFArrayGetCount(types);
1778 TRACE("got %ld types\n", count);
1780 if (count)
1782 CFStringRef type = CFArrayGetValueAtIndex(types, 0);
1783 WINE_CLIPFORMAT *format = format_for_type(NULL, type);
1785 ret = format ? format->format_id : 0;
1788 CFRelease(types);
1790 else
1791 WARN("Failed to copy pasteboard types\n");
1794 TRACE(" -> %u\n", ret);
1795 return ret;
1799 /**************************************************************************
1800 * GetClipboardData (MACDRV.@)
1802 HANDLE CDECL macdrv_GetClipboardData(UINT desired_format)
1804 check_clipboard_ownership(NULL);
1806 return macdrv_get_pasteboard_data(NULL, desired_format);
1810 /**************************************************************************
1811 * IsClipboardFormatAvailable (MACDRV.@)
1813 BOOL CDECL macdrv_IsClipboardFormatAvailable(UINT desired_format)
1815 check_clipboard_ownership(NULL);
1816 return macdrv_pasteboard_has_format(NULL, desired_format);
1820 /**************************************************************************
1821 * SetClipboardData (MACDRV.@)
1823 BOOL CDECL macdrv_SetClipboardData(UINT format_id, HANDLE data, BOOL owner)
1825 HWND hwnd_owner;
1826 macdrv_window window;
1827 WINE_CLIPFORMAT *format;
1828 CFDataRef cfdata = NULL;
1830 check_clipboard_ownership(&hwnd_owner);
1831 window = macdrv_get_cocoa_window(GetAncestor(hwnd_owner, GA_ROOT), FALSE);
1832 TRACE("format_id %s data %p owner %d hwnd_owner %p window %p)\n", debugstr_format(format_id), data, owner, hwnd_owner, window);
1834 /* Find the "natural" format for this format_id (the one which isn't
1835 synthesized from another type). */
1836 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1837 if (format->format_id == format_id && !format->synthesized) break;
1839 if (&format->entry == &format_list && !(format = insert_clipboard_format(format_id, NULL)))
1841 WARN("Failed to register clipboard format %s\n", debugstr_format(format_id));
1842 return FALSE;
1845 /* Export the data to the Mac pasteboard. */
1846 if (data)
1848 if (!format->export_func || !(cfdata = format->export_func(data)))
1850 WARN("Failed to export %s data to type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1851 return FALSE;
1855 if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1856 TRACE("Set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1857 else
1859 WARN("Failed to set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1860 if (cfdata) CFRelease(cfdata);
1861 return FALSE;
1864 if (cfdata) CFRelease(cfdata);
1866 /* Find any other formats for this format_id (the exportable synthesized ones). */
1867 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1869 if (format->format_id == format_id && format->synthesized && format->export_func)
1871 /* We have a synthesized format for this format ID. Add its type to the pasteboard. */
1872 TRACE("Synthesized from format %s: type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1874 if (data)
1876 cfdata = format->export_func(data);
1877 if (!cfdata)
1879 WARN("Failed to export %s data to type %s\n", debugstr_format(format->format_id), debugstr_cf(format->type));
1880 continue;
1883 else
1884 cfdata = NULL;
1886 if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1887 TRACE(" ... set pasteboard data: %s\n", debugstr_cf(cfdata));
1888 else
1889 WARN(" ... failed to set pasteboard data: %s\n", debugstr_cf(cfdata));
1891 if (cfdata) CFRelease(cfdata);
1895 if (data)
1897 /* FIXME: According to MSDN, the caller is entitled to lock and read from
1898 data until CloseClipboard is called. So, we should defer this cleanup. */
1899 if ((format_id >= CF_GDIOBJFIRST && format_id <= CF_GDIOBJLAST) ||
1900 format_id == CF_BITMAP ||
1901 format_id == CF_DIB ||
1902 format_id == CF_PALETTE)
1904 DeleteObject(data);
1906 else if (format_id == CF_METAFILEPICT)
1908 DeleteMetaFile(((METAFILEPICT *)GlobalLock(data))->hMF);
1909 GlobalFree(data);
1911 else if (format_id == CF_ENHMETAFILE)
1913 DeleteEnhMetaFile(data);
1915 else if (format_id < CF_PRIVATEFIRST || CF_PRIVATELAST < format_id)
1917 GlobalFree(data);
1921 return TRUE;
1925 /**************************************************************************
1926 * MACDRV Private Clipboard Exports
1927 **************************************************************************/
1930 /**************************************************************************
1931 * macdrv_clipboard_process_attach
1933 void macdrv_clipboard_process_attach(void)
1935 UINT i;
1936 WINE_CLIPFORMAT *format;
1938 /* Register built-in formats */
1939 for (i = 0; i < sizeof(builtin_format_ids)/sizeof(builtin_format_ids[0]); i++)
1941 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
1942 format->format_id = builtin_format_ids[i].id;
1943 format->type = CFRetain(builtin_format_ids[i].type);
1944 format->import_func = builtin_format_ids[i].import;
1945 format->export_func = builtin_format_ids[i].export;
1946 format->synthesized = builtin_format_ids[i].synthesized;
1947 list_add_tail(&format_list, &format->entry);
1950 /* Register known mappings between Windows formats and Mac types */
1951 for (i = 0; i < sizeof(builtin_format_names)/sizeof(builtin_format_names[0]); i++)
1953 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
1954 format->format_id = RegisterClipboardFormatW(builtin_format_names[i].name);
1955 format->type = CFRetain(builtin_format_names[i].type);
1956 format->import_func = builtin_format_names[i].import;
1957 format->export_func = builtin_format_names[i].export;
1958 format->synthesized = FALSE;
1959 list_add_tail(&format_list, &format->entry);
1964 /**************************************************************************
1965 * query_pasteboard_data
1967 BOOL query_pasteboard_data(HWND hwnd, CFStringRef type)
1969 BOOL ret = FALSE;
1970 CLIPBOARDINFO cbinfo;
1971 WINE_CLIPFORMAT* format;
1972 CFArrayRef types = NULL;
1973 CFRange range;
1975 TRACE("hwnd %p type %s\n", hwnd, debugstr_cf(type));
1977 if (get_clipboard_info(&cbinfo))
1978 hwnd = cbinfo.hwnd_owner;
1980 format = NULL;
1981 while ((format = format_for_type(format, type)))
1983 WINE_CLIPFORMAT* base_format;
1985 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1987 if (!format->synthesized)
1989 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(format->format_id), hwnd);
1990 SendMessageW(hwnd, WM_RENDERFORMAT, format->format_id, 0);
1991 ret = TRUE;
1992 goto done;
1995 if (!types)
1997 types = macdrv_copy_pasteboard_types(NULL);
1998 if (!types)
2000 WARN("Failed to copy pasteboard types\n");
2001 break;
2004 range = CFRangeMake(0, CFArrayGetCount(types));
2007 /* The type maps to a synthesized format. Now look up what type that format maps to natively
2008 (not synthesized). For example, if type is "public.utf8-plain-text", then this format may
2009 have an ID of CF_TEXT. From CF_TEXT, we want to find "org.winehq.builtin.text" to see if
2010 that type is present in the pasteboard. If it is, then the app must have promised it and
2011 we can ask it to render it. (If it had put it on the clipboard immediately, then the
2012 pasteboard would also have data for "public.utf8-plain-text" and we wouldn't be here.) If
2013 "org.winehq.builtin.text" is not on the pasteboard, then one of the other text formats is
2014 presumably responsible for the promise that we're trying to satisfy, so we keep looking. */
2015 LIST_FOR_EACH_ENTRY(base_format, &format_list, WINE_CLIPFORMAT, entry)
2017 if (base_format->format_id == format->format_id && !base_format->synthesized &&
2018 CFArrayContainsValue(types, range, base_format->type))
2020 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(base_format->format_id), hwnd);
2021 SendMessageW(hwnd, WM_RENDERFORMAT, base_format->format_id, 0);
2022 ret = TRUE;
2023 goto done;
2028 done:
2029 if (types) CFRelease(types);
2031 return ret;