winemac: Clamp the number of colors to <= 256 in bitmap_info_size().
[wine.git] / dlls / winemac.drv / clipboard.c
blob4c66b9ffa6cd9900d54a724b72bbe77a0aec51a8
1 /*
2 * Mac clipboard driver
4 * Copyright 1994 Martin Ayotte
5 * 1996 Alex Korobka
6 * 1999 Noel Borthwick
7 * 2003 Ulrich Czekalla for CodeWeavers
8 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "config.h"
27 #include "macdrv.h"
28 #include "winuser.h"
29 #include "shellapi.h"
30 #include "shlobj.h"
31 #include "wine/list.h"
32 #include "wine/server.h"
33 #include "wine/unicode.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
39 /**************************************************************************
40 * Types
41 **************************************************************************/
43 typedef struct
45 HWND hwnd_owner;
46 UINT flags;
47 } CLIPBOARDINFO, *LPCLIPBOARDINFO;
49 typedef HANDLE (*DRVIMPORTFUNC)(CFDataRef data);
50 typedef CFDataRef (*DRVEXPORTFUNC)(HANDLE data);
52 typedef struct _WINE_CLIPFORMAT
54 struct list entry;
55 UINT format_id;
56 CFStringRef type;
57 DRVIMPORTFUNC import_func;
58 DRVEXPORTFUNC export_func;
59 BOOL synthesized;
60 struct _WINE_CLIPFORMAT *natural_format;
61 } WINE_CLIPFORMAT;
64 /**************************************************************************
65 * Constants
66 **************************************************************************/
69 /**************************************************************************
70 * Forward Function Declarations
71 **************************************************************************/
73 static HANDLE import_clipboard_data(CFDataRef data);
74 static HANDLE import_bmp_to_bitmap(CFDataRef data);
75 static HANDLE import_bmp_to_dib(CFDataRef data);
76 static HANDLE import_enhmetafile(CFDataRef data);
77 static HANDLE import_metafilepict(CFDataRef data);
78 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data);
79 static HANDLE import_utf8_to_text(CFDataRef data);
80 static HANDLE import_utf8_to_unicodetext(CFDataRef data);
81 static HANDLE import_utf16_to_unicodetext(CFDataRef data);
83 static CFDataRef export_clipboard_data(HANDLE data);
84 static CFDataRef export_bitmap_to_bmp(HANDLE data);
85 static CFDataRef export_dib_to_bmp(HANDLE data);
86 static CFDataRef export_enhmetafile(HANDLE data);
87 static CFDataRef export_hdrop_to_filenames(HANDLE data);
88 static CFDataRef export_metafilepict(HANDLE data);
89 static CFDataRef export_text_to_utf8(HANDLE data);
90 static CFDataRef export_unicodetext_to_utf8(HANDLE data);
91 static CFDataRef export_unicodetext_to_utf16(HANDLE data);
94 /**************************************************************************
95 * Static Variables
96 **************************************************************************/
98 /* Clipboard formats */
99 static struct list format_list = LIST_INIT(format_list);
101 /* There are two naming schemes involved and we want to have a mapping between
102 them. There are Win32 clipboard format names and there are Mac pasteboard
103 types.
105 The Win32 standard clipboard formats don't have names, but they are associated
106 with Mac pasteboard types through the following tables, which are used to
107 initialize the format_list. Where possible, the standard clipboard formats
108 are mapped to predefined pasteboard type UTIs. Otherwise, we create Wine-
109 specific types of the form "org.winehq.builtin.<format>", where <format> is
110 the name of the symbolic constant for the format minus "CF_" and lowercased.
111 E.g. CF_BITMAP -> org.winehq.builtin.bitmap.
113 Win32 clipboard formats which originate in a Windows program may be registered
114 with an arbitrary name. We construct a Mac pasteboard type from these by
115 prepending "org.winehq.registered." to the registered name.
117 Likewise, Mac pasteboard types which originate in other apps may have
118 arbitrary type strings. We ignore these.
120 Summary:
121 Win32 clipboard format names:
122 <none> standard clipboard format; maps via
123 format_list to either a predefined Mac UTI
124 or org.winehq.builtin.<format>.
125 <other> name registered within Win32 land; maps to
126 org.winehq.registered.<other>
127 Mac pasteboard type names:
128 org.winehq.builtin.<format ID> representation of Win32 standard clipboard
129 format for which there was no corresponding
130 predefined Mac UTI; maps via format_list
131 org.winehq.registered.<format name> representation of Win32 registered
132 clipboard format name; maps to <format name>
133 <other> Mac pasteboard type originating with system
134 or other apps; either maps via format_list
135 to a standard clipboard format or ignored
138 static const struct
140 UINT id;
141 CFStringRef type;
142 DRVIMPORTFUNC import;
143 DRVEXPORTFUNC export;
144 BOOL synthesized;
145 } builtin_format_ids[] =
147 { CF_BITMAP, CFSTR("org.winehq.builtin.bitmap"), import_bmp_to_bitmap, export_bitmap_to_bmp, FALSE },
148 { CF_DIBV5, CFSTR("org.winehq.builtin.dibv5"), import_clipboard_data, export_clipboard_data, FALSE },
149 { CF_DIF, CFSTR("org.winehq.builtin.dif"), import_clipboard_data, export_clipboard_data, FALSE },
150 { CF_ENHMETAFILE, CFSTR("org.winehq.builtin.enhmetafile"), import_enhmetafile, export_enhmetafile, FALSE },
151 { CF_LOCALE, CFSTR("org.winehq.builtin.locale"), import_clipboard_data, export_clipboard_data, FALSE },
152 { CF_METAFILEPICT, CFSTR("org.winehq.builtin.metafilepict"), import_metafilepict, export_metafilepict, FALSE },
153 { CF_OEMTEXT, CFSTR("org.winehq.builtin.oemtext"), import_clipboard_data, export_clipboard_data, FALSE },
154 { CF_PALETTE, CFSTR("org.winehq.builtin.palette"), import_clipboard_data, export_clipboard_data, FALSE },
155 { CF_PENDATA, CFSTR("org.winehq.builtin.pendata"), import_clipboard_data, export_clipboard_data, FALSE },
156 { CF_RIFF, CFSTR("org.winehq.builtin.riff"), import_clipboard_data, export_clipboard_data, FALSE },
157 { CF_SYLK, CFSTR("org.winehq.builtin.sylk"), import_clipboard_data, export_clipboard_data, FALSE },
158 { CF_TEXT, CFSTR("org.winehq.builtin.text"), import_clipboard_data, export_clipboard_data, FALSE },
159 { CF_TIFF, CFSTR("public.tiff"), import_clipboard_data, export_clipboard_data, FALSE },
160 { CF_WAVE, CFSTR("com.microsoft.waveform-audio"), import_clipboard_data, export_clipboard_data, FALSE },
162 { CF_DIB, CFSTR("org.winehq.builtin.dib"), import_clipboard_data, export_clipboard_data, FALSE },
163 { CF_DIB, CFSTR("com.microsoft.bmp"), import_bmp_to_dib, export_dib_to_bmp, TRUE },
165 { CF_HDROP, CFSTR("org.winehq.builtin.hdrop"), import_clipboard_data, export_clipboard_data, FALSE },
166 { CF_HDROP, CFSTR("NSFilenamesPboardType"), import_nsfilenames_to_hdrop, export_hdrop_to_filenames, TRUE },
168 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.unicodetext"), import_clipboard_data, export_clipboard_data, FALSE },
169 { CF_UNICODETEXT, CFSTR("public.utf16-plain-text"), import_utf16_to_unicodetext, export_unicodetext_to_utf16,TRUE },
170 { CF_UNICODETEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_unicodetext, export_unicodetext_to_utf8, TRUE },
173 static const WCHAR wszRichTextFormat[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
174 static const WCHAR wszGIF[] = {'G','I','F',0};
175 static const WCHAR wszJFIF[] = {'J','F','I','F',0};
176 static const WCHAR wszPNG[] = {'P','N','G',0};
177 static const WCHAR wszHTMLFormat[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
178 static const struct
180 LPCWSTR name;
181 CFStringRef type;
182 DRVIMPORTFUNC import;
183 DRVEXPORTFUNC export;
184 } builtin_format_names[] =
186 { wszRichTextFormat, CFSTR("public.rtf"), import_clipboard_data, export_clipboard_data },
187 { wszGIF, CFSTR("com.compuserve.gif"), import_clipboard_data, export_clipboard_data },
188 { wszJFIF, CFSTR("public.jpeg"), import_clipboard_data, export_clipboard_data },
189 { wszPNG, CFSTR("public.png"), import_clipboard_data, export_clipboard_data },
190 { wszHTMLFormat, CFSTR("public.html"), import_clipboard_data, export_clipboard_data },
191 { CFSTR_SHELLURLW, CFSTR("public.url"), import_utf8_to_text, export_text_to_utf8 },
194 /* The prefix prepended to a Win32 clipboard format name to make a Mac pasteboard type. */
195 static const CFStringRef registered_name_type_prefix = CFSTR("org.winehq.registered.");
198 /**************************************************************************
199 * Internal Clipboard implementation methods
200 **************************************************************************/
203 * format_list functions
206 /**************************************************************************
207 * debugstr_format
209 const char *debugstr_format(UINT id)
211 WCHAR buffer[256];
213 if (GetClipboardFormatNameW(id, buffer, 256))
214 return wine_dbg_sprintf("0x%04x %s", id, debugstr_w(buffer));
216 switch (id)
218 #define BUILTIN(id) case id: return #id;
219 BUILTIN(CF_TEXT)
220 BUILTIN(CF_BITMAP)
221 BUILTIN(CF_METAFILEPICT)
222 BUILTIN(CF_SYLK)
223 BUILTIN(CF_DIF)
224 BUILTIN(CF_TIFF)
225 BUILTIN(CF_OEMTEXT)
226 BUILTIN(CF_DIB)
227 BUILTIN(CF_PALETTE)
228 BUILTIN(CF_PENDATA)
229 BUILTIN(CF_RIFF)
230 BUILTIN(CF_WAVE)
231 BUILTIN(CF_UNICODETEXT)
232 BUILTIN(CF_ENHMETAFILE)
233 BUILTIN(CF_HDROP)
234 BUILTIN(CF_LOCALE)
235 BUILTIN(CF_DIBV5)
236 BUILTIN(CF_OWNERDISPLAY)
237 BUILTIN(CF_DSPTEXT)
238 BUILTIN(CF_DSPBITMAP)
239 BUILTIN(CF_DSPMETAFILEPICT)
240 BUILTIN(CF_DSPENHMETAFILE)
241 #undef BUILTIN
242 default: return wine_dbg_sprintf("0x%04x", id);
247 /**************************************************************************
248 * insert_clipboard_format
250 static WINE_CLIPFORMAT *insert_clipboard_format(UINT id, CFStringRef type)
252 WINE_CLIPFORMAT *format;
254 format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format));
256 if (format == NULL)
258 WARN("No more memory for a new format!\n");
259 return NULL;
261 format->format_id = id;
262 format->import_func = import_clipboard_data;
263 format->export_func = export_clipboard_data;
264 format->synthesized = FALSE;
265 format->natural_format = NULL;
267 if (type)
268 format->type = CFStringCreateCopy(NULL, type);
269 else
271 WCHAR buffer[256];
273 if (!GetClipboardFormatNameW(format->format_id, buffer, sizeof(buffer) / sizeof(buffer[0])))
275 WARN("failed to get name for format %s; error 0x%08x\n", debugstr_format(format->format_id), GetLastError());
276 HeapFree(GetProcessHeap(), 0, format);
277 return NULL;
280 format->type = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%S"),
281 registered_name_type_prefix, buffer);
284 list_add_tail(&format_list, &format->entry);
286 TRACE("Registering format %s type %s\n", debugstr_format(format->format_id),
287 debugstr_cf(format->type));
289 return format;
293 /**************************************************************************
294 * register_format
296 * Register a custom Mac clipboard format.
298 static WINE_CLIPFORMAT* register_format(UINT id, CFStringRef type)
300 WINE_CLIPFORMAT *format;
302 /* walk format chain to see if it's already registered */
303 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
304 if (format->format_id == id) return format;
306 return insert_clipboard_format(id, type);
310 /**************************************************************************
311 * format_for_type
313 static WINE_CLIPFORMAT* format_for_type(WINE_CLIPFORMAT *current, CFStringRef type)
315 struct list *ptr = current ? &current->entry : &format_list;
316 WINE_CLIPFORMAT *format = NULL;
318 TRACE("current %p/%s type %s\n", current, debugstr_format(current ? current->format_id : 0), debugstr_cf(type));
320 while ((ptr = list_next(&format_list, ptr)))
322 format = LIST_ENTRY(ptr, WINE_CLIPFORMAT, entry);
323 if (CFEqual(format->type, type))
324 goto done;
327 format = NULL;
328 if (!current)
330 if (CFStringHasPrefix(type, CFSTR("org.winehq.builtin.")))
332 ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
333 debugstr_cf(type));
335 else if (CFStringHasPrefix(type, registered_name_type_prefix))
337 LPWSTR name;
338 int len = CFStringGetLength(type) - CFStringGetLength(registered_name_type_prefix);
340 name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
341 CFStringGetCharacters(type, CFRangeMake(CFStringGetLength(registered_name_type_prefix), len),
342 (UniChar*)name);
343 name[len] = 0;
345 format = register_format(RegisterClipboardFormatW(name), type);
346 if (!format)
347 ERR("Failed to register format for type %s name %s\n", debugstr_cf(type), debugstr_w(name));
349 HeapFree(GetProcessHeap(), 0, name);
353 done:
354 TRACE(" -> %p/%s\n", format, debugstr_format(format ? format->format_id : 0));
355 return format;
359 /**************************************************************************
360 * natural_format_for_format
362 * Find the "natural" format for this format_id (the one which isn't
363 * synthesized from another type).
365 static WINE_CLIPFORMAT* natural_format_for_format(UINT format_id)
367 WINE_CLIPFORMAT *format;
369 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
370 if (format->format_id == format_id && !format->synthesized) break;
372 if (&format->entry == &format_list)
373 format = NULL;
375 TRACE("%s -> %p/%s\n", debugstr_format(format_id), format, debugstr_cf(format ? format->type : NULL));
376 return format;
380 /***********************************************************************
381 * bitmap_info_size
383 * Return the size of the bitmap info structure including color table.
385 static int bitmap_info_size(const BITMAPINFO *info, WORD coloruse)
387 unsigned int colors, size, masks = 0;
389 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
391 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER*)info;
392 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
393 return sizeof(BITMAPCOREHEADER) + colors *
394 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
396 else /* assume BITMAPINFOHEADER */
398 colors = MIN(info->bmiHeader.biClrUsed, 256);
399 if (!colors && (info->bmiHeader.biBitCount <= 8))
400 colors = 1 << info->bmiHeader.biBitCount;
401 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
402 size = max(info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD));
403 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
408 /***********************************************************************
409 * create_dib_from_bitmap
411 * Allocates a packed DIB and copies the bitmap data into it.
413 static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp)
415 BITMAP bmp;
416 HDC hdc;
417 HGLOBAL hPackedDIB;
418 LPBYTE pPackedDIB;
419 LPBITMAPINFOHEADER pbmiHeader;
420 unsigned int cDataSize, cPackedSize, OffsetBits;
421 int nLinesCopied;
423 if (!GetObjectW(hBmp, sizeof(bmp), &bmp)) return 0;
426 * A packed DIB contains a BITMAPINFO structure followed immediately by
427 * an optional color palette and the pixel data.
430 /* Calculate the size of the packed DIB */
431 cDataSize = abs(bmp.bmHeight) * (((bmp.bmWidth * bmp.bmBitsPixel + 31) / 8) & ~3);
432 cPackedSize = sizeof(BITMAPINFOHEADER)
433 + ((bmp.bmBitsPixel <= 8) ? (sizeof(RGBQUAD) * (1 << bmp.bmBitsPixel)) : 0)
434 + cDataSize;
435 /* Get the offset to the bits */
436 OffsetBits = cPackedSize - cDataSize;
438 /* Allocate the packed DIB */
439 TRACE("\tAllocating packed DIB of size %d\n", cPackedSize);
440 hPackedDIB = GlobalAlloc(GMEM_FIXED, cPackedSize);
441 if (!hPackedDIB)
443 WARN("Could not allocate packed DIB!\n");
444 return 0;
447 /* A packed DIB starts with a BITMAPINFOHEADER */
448 pPackedDIB = GlobalLock(hPackedDIB);
449 pbmiHeader = (LPBITMAPINFOHEADER)pPackedDIB;
451 /* Init the BITMAPINFOHEADER */
452 pbmiHeader->biSize = sizeof(BITMAPINFOHEADER);
453 pbmiHeader->biWidth = bmp.bmWidth;
454 pbmiHeader->biHeight = bmp.bmHeight;
455 pbmiHeader->biPlanes = 1;
456 pbmiHeader->biBitCount = bmp.bmBitsPixel;
457 pbmiHeader->biCompression = BI_RGB;
458 pbmiHeader->biSizeImage = 0;
459 pbmiHeader->biXPelsPerMeter = pbmiHeader->biYPelsPerMeter = 0;
460 pbmiHeader->biClrUsed = 0;
461 pbmiHeader->biClrImportant = 0;
463 /* Retrieve the DIB bits from the bitmap and fill in the
464 * DIB color table if present */
465 hdc = GetDC(0);
466 nLinesCopied = GetDIBits(hdc, /* Handle to device context */
467 hBmp, /* Handle to bitmap */
468 0, /* First scan line to set in dest bitmap */
469 bmp.bmHeight, /* Number of scan lines to copy */
470 pPackedDIB + OffsetBits, /* [out] Address of array for bitmap bits */
471 (LPBITMAPINFO) pbmiHeader, /* [out] Address of BITMAPINFO structure */
472 0); /* RGB or palette index */
473 GlobalUnlock(hPackedDIB);
474 ReleaseDC(0, hdc);
476 /* Cleanup if GetDIBits failed */
477 if (nLinesCopied != bmp.bmHeight)
479 TRACE("\tGetDIBits returned %d. Actual lines=%d\n", nLinesCopied, bmp.bmHeight);
480 GlobalFree(hPackedDIB);
481 hPackedDIB = 0;
483 return hPackedDIB;
487 /**************************************************************************
488 * create_bitmap_from_dib
490 * Given a packed DIB, creates a bitmap object from it.
492 static HANDLE create_bitmap_from_dib(HANDLE dib)
494 HANDLE ret = 0;
495 BITMAPINFO *bmi;
497 if (dib && (bmi = GlobalLock(dib)))
499 HDC hdc;
500 unsigned int offset;
502 hdc = GetDC(NULL);
504 offset = bitmap_info_size(bmi, DIB_RGB_COLORS);
506 ret = CreateDIBitmap(hdc, &bmi->bmiHeader, CBM_INIT, (LPBYTE)bmi + offset,
507 bmi, DIB_RGB_COLORS);
509 GlobalUnlock(dib);
510 ReleaseDC(NULL, hdc);
513 return ret;
517 /**************************************************************************
518 * import_clipboard_data
520 * Generic import clipboard data routine.
522 static HANDLE import_clipboard_data(CFDataRef data)
524 HANDLE data_handle = NULL;
526 size_t len = CFDataGetLength(data);
527 if (len)
529 LPVOID p;
531 /* Turn on the DDESHARE flag to enable shared 32 bit memory */
532 data_handle = GlobalAlloc(GMEM_FIXED, len);
533 if (!data_handle)
534 return NULL;
536 if ((p = GlobalLock(data_handle)))
538 memcpy(p, CFDataGetBytePtr(data), len);
539 GlobalUnlock(data_handle);
541 else
543 GlobalFree(data_handle);
544 data_handle = NULL;
548 return data_handle;
552 /**************************************************************************
553 * import_bmp_to_bitmap
555 * Import BMP data, converting to CF_BITMAP format.
557 static HANDLE import_bmp_to_bitmap(CFDataRef data)
559 HANDLE ret;
560 HANDLE dib = import_bmp_to_dib(data);
562 ret = create_bitmap_from_dib(dib);
564 GlobalFree(dib);
565 return ret;
569 /**************************************************************************
570 * import_bmp_to_dib
572 * Import BMP data, converting to CF_DIB or CF_DIBV5 format. This just
573 * entails stripping the BMP file format header.
575 static HANDLE import_bmp_to_dib(CFDataRef data)
577 HANDLE ret = 0;
578 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)CFDataGetBytePtr(data);
579 CFIndex len = CFDataGetLength(data);
581 if (len >= sizeof(*bfh) + sizeof(BITMAPCOREHEADER) &&
582 bfh->bfType == 0x4d42 /* "BM" */)
584 BITMAPINFO *bmi = (BITMAPINFO*)(bfh + 1);
585 BYTE* p;
587 len -= sizeof(*bfh);
588 ret = GlobalAlloc(GMEM_FIXED, len);
589 if (!ret || !(p = GlobalLock(ret)))
591 GlobalFree(ret);
592 return 0;
595 memcpy(p, bmi, len);
596 GlobalUnlock(ret);
599 return ret;
603 /**************************************************************************
604 * import_enhmetafile
606 * Import enhanced metafile data, converting it to CF_ENHMETAFILE.
608 static HANDLE import_enhmetafile(CFDataRef data)
610 HANDLE ret = 0;
611 CFIndex len = CFDataGetLength(data);
613 TRACE("data %s\n", debugstr_cf(data));
615 if (len)
616 ret = SetEnhMetaFileBits(len, (const BYTE*)CFDataGetBytePtr(data));
618 return ret;
622 /**************************************************************************
623 * import_metafilepict
625 * Import metafile picture data, converting it to CF_METAFILEPICT.
627 static HANDLE import_metafilepict(CFDataRef data)
629 HANDLE ret = 0;
630 CFIndex len = CFDataGetLength(data);
631 METAFILEPICT *mfp;
633 TRACE("data %s\n", debugstr_cf(data));
635 if (len >= sizeof(*mfp) && (ret = GlobalAlloc(GMEM_FIXED, sizeof(*mfp))))
637 const BYTE *bytes = (const BYTE*)CFDataGetBytePtr(data);
639 mfp = GlobalLock(ret);
640 memcpy(mfp, bytes, sizeof(*mfp));
641 mfp->hMF = SetMetaFileBitsEx(len - sizeof(*mfp), bytes + sizeof(*mfp));
642 GlobalUnlock(ret);
645 return ret;
649 /**************************************************************************
650 * import_nsfilenames_to_hdrop
652 * Import NSFilenamesPboardType data, converting the property-list-
653 * serialized array of path strings to CF_HDROP.
655 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data)
657 HDROP hdrop = NULL;
658 CFArrayRef names;
659 CFIndex count, i;
660 size_t len;
661 char *buffer = NULL;
662 WCHAR **paths = NULL;
663 DROPFILES* dropfiles;
664 UniChar* p;
666 TRACE("data %s\n", debugstr_cf(data));
668 names = (CFArrayRef)CFPropertyListCreateWithData(NULL, data, kCFPropertyListImmutable,
669 NULL, NULL);
670 if (!names || CFGetTypeID(names) != CFArrayGetTypeID())
672 WARN("failed to interpret data as a CFArray\n");
673 goto done;
676 count = CFArrayGetCount(names);
678 len = 0;
679 for (i = 0; i < count; i++)
681 CFIndex this_len;
682 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
683 TRACE(" %s\n", debugstr_cf(name));
684 if (CFGetTypeID(name) != CFStringGetTypeID())
686 WARN("non-string in array\n");
687 goto done;
690 this_len = CFStringGetMaximumSizeOfFileSystemRepresentation(name);
691 if (this_len > len)
692 len = this_len;
695 buffer = HeapAlloc(GetProcessHeap(), 0, len);
696 if (!buffer)
698 WARN("failed to allocate buffer for file-system representations\n");
699 goto done;
702 paths = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(paths[0]));
703 if (!paths)
705 WARN("failed to allocate array of DOS paths\n");
706 goto done;
709 for (i = 0; i < count; i++)
711 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
712 if (!CFStringGetFileSystemRepresentation(name, buffer, len))
714 WARN("failed to get file-system representation for %s\n", debugstr_cf(name));
715 goto done;
717 paths[i] = wine_get_dos_file_name(buffer);
718 if (!paths[i])
720 WARN("failed to get DOS path for %s\n", debugstr_a(buffer));
721 goto done;
725 len = 1; /* for the terminating null */
726 for (i = 0; i < count; i++)
727 len += strlenW(paths[i]) + 1;
729 hdrop = GlobalAlloc(GMEM_FIXED, sizeof(*dropfiles) + len * sizeof(WCHAR));
730 if (!hdrop || !(dropfiles = GlobalLock(hdrop)))
732 WARN("failed to allocate HDROP\n");
733 GlobalFree(hdrop);
734 hdrop = NULL;
735 goto done;
738 dropfiles->pFiles = sizeof(*dropfiles);
739 dropfiles->pt.x = 0;
740 dropfiles->pt.y = 0;
741 dropfiles->fNC = FALSE;
742 dropfiles->fWide = TRUE;
744 p = (WCHAR*)(dropfiles + 1);
745 for (i = 0; i < count; i++)
747 strcpyW(p, paths[i]);
748 p += strlenW(p) + 1;
750 *p = 0;
752 GlobalUnlock(hdrop);
754 done:
755 if (paths)
757 for (i = 0; i < count; i++)
758 HeapFree(GetProcessHeap(), 0, paths[i]);
759 HeapFree(GetProcessHeap(), 0, paths);
761 HeapFree(GetProcessHeap(), 0, buffer);
762 if (names) CFRelease(names);
763 return hdrop;
767 /**************************************************************************
768 * import_utf8_to_text
770 * Import a UTF-8 string, converting the string to CF_TEXT.
772 static HANDLE import_utf8_to_text(CFDataRef data)
774 HANDLE ret = NULL;
775 HANDLE unicode_handle = import_utf8_to_unicodetext(data);
776 LPWSTR unicode_string = GlobalLock(unicode_handle);
778 if (unicode_string)
780 int unicode_len;
781 HANDLE handle;
782 char *p;
783 INT len;
785 unicode_len = GlobalSize(unicode_handle) / sizeof(WCHAR);
787 len = WideCharToMultiByte(CP_ACP, 0, unicode_string, unicode_len, NULL, 0, NULL, NULL);
788 if (!unicode_len || unicode_string[unicode_len - 1]) len += 1;
789 handle = GlobalAlloc(GMEM_FIXED, len);
791 if (handle && (p = GlobalLock(handle)))
793 WideCharToMultiByte(CP_ACP, 0, unicode_string, unicode_len, p, len, NULL, NULL);
794 p[len - 1] = 0;
795 GlobalUnlock(handle);
796 ret = handle;
798 GlobalUnlock(unicode_handle);
801 GlobalFree(unicode_handle);
802 return ret;
806 /**************************************************************************
807 * import_utf8_to_unicodetext
809 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
811 static HANDLE import_utf8_to_unicodetext(CFDataRef data)
813 const BYTE *src;
814 unsigned long src_len;
815 unsigned long new_lines = 0;
816 LPSTR dst;
817 unsigned long i, j;
818 HANDLE unicode_handle = NULL;
820 src = CFDataGetBytePtr(data);
821 src_len = CFDataGetLength(data);
822 for (i = 0; i < src_len; i++)
824 if (src[i] == '\n')
825 new_lines++;
828 if ((dst = HeapAlloc(GetProcessHeap(), 0, src_len + new_lines + 1)))
830 UINT count;
832 for (i = 0, j = 0; i < src_len; i++)
834 if (src[i] == '\n')
835 dst[j++] = '\r';
837 dst[j++] = src[i];
839 dst[j] = 0;
841 count = MultiByteToWideChar(CP_UTF8, 0, dst, -1, NULL, 0);
842 unicode_handle = GlobalAlloc(GMEM_FIXED, count * sizeof(WCHAR));
844 if (unicode_handle)
846 WCHAR *textW = GlobalLock(unicode_handle);
847 MultiByteToWideChar(CP_UTF8, 0, dst, -1, textW, count);
848 GlobalUnlock(unicode_handle);
851 HeapFree(GetProcessHeap(), 0, dst);
854 return unicode_handle;
858 /**************************************************************************
859 * import_utf16_to_unicodetext
861 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
863 static HANDLE import_utf16_to_unicodetext(CFDataRef data)
865 const WCHAR *src;
866 unsigned long src_len;
867 unsigned long new_lines = 0;
868 LPWSTR dst;
869 unsigned long i, j;
870 HANDLE unicode_handle;
872 src = (const WCHAR *)CFDataGetBytePtr(data);
873 src_len = CFDataGetLength(data) / sizeof(WCHAR);
874 for (i = 0; i < src_len; i++)
876 if (src[i] == '\n')
877 new_lines++;
878 else if (src[i] == '\r' && (i + 1 >= src_len || src[i + 1] != '\n'))
879 new_lines++;
882 if ((unicode_handle = GlobalAlloc(GMEM_FIXED, (src_len + new_lines + 1) * sizeof(WCHAR))))
884 dst = GlobalLock(unicode_handle);
886 for (i = 0, j = 0; i < src_len; i++)
888 if (src[i] == '\n')
889 dst[j++] = '\r';
891 dst[j++] = src[i];
893 if (src[i] == '\r' && (i + 1 >= src_len || src[i + 1] != '\n'))
894 dst[j++] = '\n';
896 dst[j] = 0;
898 GlobalUnlock(unicode_handle);
901 return unicode_handle;
905 /**************************************************************************
906 * export_clipboard_data
908 * Generic export clipboard data routine.
910 static CFDataRef export_clipboard_data(HANDLE data)
912 CFDataRef ret;
913 UINT len;
914 LPVOID src;
916 len = GlobalSize(data);
917 src = GlobalLock(data);
918 if (!src) return NULL;
920 ret = CFDataCreate(NULL, src, len);
921 GlobalUnlock(data);
923 return ret;
927 /**************************************************************************
928 * export_bitmap_to_bmp
930 * Export CF_BITMAP to BMP file format.
932 static CFDataRef export_bitmap_to_bmp(HANDLE data)
934 CFDataRef ret = NULL;
935 HGLOBAL dib;
937 dib = create_dib_from_bitmap(data);
938 if (dib)
940 ret = export_dib_to_bmp(dib);
941 GlobalFree(dib);
944 return ret;
948 /**************************************************************************
949 * export_dib_to_bmp
951 * Export CF_DIB or CF_DIBV5 to BMP file format. This just entails
952 * prepending a BMP file format header to the data.
954 static CFDataRef export_dib_to_bmp(HANDLE data)
956 CFMutableDataRef ret = NULL;
957 BYTE *dibdata;
958 CFIndex len;
959 BITMAPFILEHEADER bfh;
961 dibdata = GlobalLock(data);
962 if (!dibdata)
963 return NULL;
965 len = sizeof(bfh) + GlobalSize(data);
966 ret = CFDataCreateMutable(NULL, len);
967 if (ret)
969 bfh.bfType = 0x4d42; /* "BM" */
970 bfh.bfSize = len;
971 bfh.bfReserved1 = 0;
972 bfh.bfReserved2 = 0;
973 bfh.bfOffBits = sizeof(bfh) + bitmap_info_size((BITMAPINFO*)dibdata, DIB_RGB_COLORS);
974 CFDataAppendBytes(ret, (UInt8*)&bfh, sizeof(bfh));
976 /* rest of bitmap is the same as the packed dib */
977 CFDataAppendBytes(ret, (UInt8*)dibdata, len - sizeof(bfh));
980 GlobalUnlock(data);
982 return ret;
986 /**************************************************************************
987 * export_enhmetafile
989 * Export an enhanced metafile to data.
991 static CFDataRef export_enhmetafile(HANDLE data)
993 CFMutableDataRef ret = NULL;
994 unsigned int size = GetEnhMetaFileBits(data, 0, NULL);
996 TRACE("data %p\n", data);
998 ret = CFDataCreateMutable(NULL, size);
999 if (ret)
1001 CFDataSetLength(ret, size);
1002 GetEnhMetaFileBits(data, size, (BYTE*)CFDataGetMutableBytePtr(ret));
1005 TRACE(" -> %s\n", debugstr_cf(ret));
1006 return ret;
1010 /**************************************************************************
1011 * export_hdrop_to_filenames
1013 * Export CF_HDROP to NSFilenamesPboardType data, which is a CFArray of
1014 * CFStrings (holding Unix paths) which is serialized as a property list.
1016 static CFDataRef export_hdrop_to_filenames(HANDLE data)
1018 CFDataRef ret = NULL;
1019 DROPFILES *dropfiles;
1020 CFMutableArrayRef filenames = NULL;
1021 void *p;
1022 WCHAR *buffer = NULL;
1023 size_t buffer_len = 0;
1025 TRACE("data %p\n", data);
1027 if (!(dropfiles = GlobalLock(data)))
1029 WARN("failed to lock data %p\n", data);
1030 goto done;
1033 filenames = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1034 if (!filenames)
1036 WARN("failed to create filenames array\n");
1037 goto done;
1040 p = (char*)dropfiles + dropfiles->pFiles;
1041 while (dropfiles->fWide ? *(WCHAR*)p : *(char*)p)
1043 char *unixname;
1044 CFStringRef filename;
1046 TRACE(" %s\n", dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1048 if (dropfiles->fWide)
1049 unixname = wine_get_unix_file_name(p);
1050 else
1052 int len = MultiByteToWideChar(CP_ACP, 0, p, -1, NULL, 0);
1053 if (len)
1055 if (len > buffer_len)
1057 HeapFree(GetProcessHeap(), 0, buffer);
1058 buffer_len = len * 2;
1059 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_len * sizeof(*buffer));
1062 MultiByteToWideChar(CP_ACP, 0, p, -1, buffer, buffer_len);
1063 unixname = wine_get_unix_file_name(buffer);
1065 else
1066 unixname = NULL;
1068 if (!unixname)
1070 WARN("failed to convert DOS path to Unix: %s\n",
1071 dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1072 goto done;
1075 if (dropfiles->fWide)
1076 p = (WCHAR*)p + strlenW(p) + 1;
1077 else
1078 p = (char*)p + strlen(p) + 1;
1080 filename = CFStringCreateWithFileSystemRepresentation(NULL, unixname);
1081 HeapFree(GetProcessHeap(), 0, unixname);
1082 if (!filename)
1084 WARN("failed to create CFString from Unix path %s\n", debugstr_a(unixname));
1085 goto done;
1088 CFArrayAppendValue(filenames, filename);
1089 CFRelease(filename);
1092 ret = CFPropertyListCreateData(NULL, filenames, kCFPropertyListXMLFormat_v1_0, 0, NULL);
1094 done:
1095 HeapFree(GetProcessHeap(), 0, buffer);
1096 GlobalUnlock(data);
1097 if (filenames) CFRelease(filenames);
1098 TRACE(" -> %s\n", debugstr_cf(ret));
1099 return ret;
1103 /**************************************************************************
1104 * export_metafilepict
1106 * Export a metafile to data.
1108 static CFDataRef export_metafilepict(HANDLE data)
1110 CFMutableDataRef ret = NULL;
1111 METAFILEPICT *mfp = GlobalLock(data);
1112 unsigned int size = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
1114 TRACE("data %p\n", data);
1116 ret = CFDataCreateMutable(NULL, sizeof(*mfp) + size);
1117 if (ret)
1119 CFDataAppendBytes(ret, (UInt8*)mfp, sizeof(*mfp));
1120 CFDataIncreaseLength(ret, size);
1121 GetMetaFileBitsEx(mfp->hMF, size, (BYTE*)CFDataGetMutableBytePtr(ret) + sizeof(*mfp));
1124 GlobalUnlock(data);
1125 TRACE(" -> %s\n", debugstr_cf(ret));
1126 return ret;
1130 /**************************************************************************
1131 * export_text_to_utf8
1133 * Export CF_TEXT to UTF-8.
1135 static CFDataRef export_text_to_utf8(HANDLE data)
1137 CFDataRef ret = NULL;
1138 const char* str;
1140 if ((str = GlobalLock(data)))
1142 int str_len = GlobalSize(data);
1143 int wstr_len;
1144 WCHAR *wstr;
1145 HANDLE unicode;
1146 char *p;
1148 wstr_len = MultiByteToWideChar(CP_ACP, 0, str, str_len, NULL, 0);
1149 if (!str_len || str[str_len - 1]) wstr_len += 1;
1150 wstr = HeapAlloc(GetProcessHeap(), 0, wstr_len * sizeof(WCHAR));
1151 MultiByteToWideChar(CP_ACP, 0, str, str_len, wstr, wstr_len);
1152 wstr[wstr_len - 1] = 0;
1154 unicode = GlobalAlloc(GMEM_FIXED, wstr_len * sizeof(WCHAR));
1155 if (unicode && (p = GlobalLock(unicode)))
1157 memcpy(p, wstr, wstr_len * sizeof(WCHAR));
1158 GlobalUnlock(unicode);
1161 ret = export_unicodetext_to_utf8(unicode);
1163 GlobalFree(unicode);
1164 GlobalUnlock(data);
1167 return ret;
1171 /**************************************************************************
1172 * export_unicodetext_to_utf8
1174 * Export CF_UNICODETEXT to UTF-8.
1176 static CFDataRef export_unicodetext_to_utf8(HANDLE data)
1178 CFMutableDataRef ret;
1179 LPVOID src;
1180 INT dst_len;
1182 src = GlobalLock(data);
1183 if (!src) return NULL;
1185 dst_len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
1186 if (dst_len) dst_len--; /* Leave off null terminator. */
1187 ret = CFDataCreateMutable(NULL, dst_len);
1188 if (ret)
1190 LPSTR dst;
1191 int i, j;
1193 CFDataSetLength(ret, dst_len);
1194 dst = (LPSTR)CFDataGetMutableBytePtr(ret);
1195 WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_len, NULL, NULL);
1197 /* Remove carriage returns */
1198 for (i = 0, j = 0; i < dst_len; i++)
1200 if (dst[i] == '\r' &&
1201 (i + 1 >= dst_len || dst[i + 1] == '\n' || dst[i + 1] == '\0'))
1202 continue;
1203 dst[j++] = dst[i];
1205 CFDataSetLength(ret, j);
1207 GlobalUnlock(data);
1209 return ret;
1213 /**************************************************************************
1214 * export_unicodetext_to_utf16
1216 * Export CF_UNICODETEXT to UTF-16.
1218 static CFDataRef export_unicodetext_to_utf16(HANDLE data)
1220 CFMutableDataRef ret;
1221 const WCHAR *src;
1222 INT src_len;
1224 src = GlobalLock(data);
1225 if (!src) return NULL;
1227 src_len = GlobalSize(data) / sizeof(WCHAR);
1228 if (src_len) src_len--; /* Leave off null terminator. */
1229 ret = CFDataCreateMutable(NULL, src_len * sizeof(WCHAR));
1230 if (ret)
1232 LPWSTR dst;
1233 int i, j;
1235 CFDataSetLength(ret, src_len * sizeof(WCHAR));
1236 dst = (LPWSTR)CFDataGetMutableBytePtr(ret);
1238 /* Remove carriage returns */
1239 for (i = 0, j = 0; i < src_len; i++)
1241 if (src[i] == '\r' &&
1242 (i + 1 >= src_len || src[i + 1] == '\n' || src[i + 1] == '\0'))
1243 continue;
1244 dst[j++] = src[i];
1246 CFDataSetLength(ret, j * sizeof(WCHAR));
1248 GlobalUnlock(data);
1250 return ret;
1254 /**************************************************************************
1255 * get_clipboard_info
1257 static BOOL get_clipboard_info(LPCLIPBOARDINFO cbinfo)
1259 BOOL ret = FALSE;
1261 SERVER_START_REQ(set_clipboard_info)
1263 req->flags = 0;
1265 if (wine_server_call_err(req))
1267 ERR("Failed to get clipboard owner.\n");
1269 else
1271 cbinfo->hwnd_owner = wine_server_ptr_handle(reply->old_owner);
1272 cbinfo->flags = reply->flags;
1274 ret = TRUE;
1277 SERVER_END_REQ;
1279 return ret;
1283 /**************************************************************************
1284 * release_ownership
1286 static BOOL release_ownership(void)
1288 BOOL ret = FALSE;
1290 SERVER_START_REQ(set_clipboard_info)
1292 req->flags = SET_CB_RELOWNER | SET_CB_SEQNO;
1294 if (wine_server_call_err(req))
1295 ERR("Failed to set clipboard.\n");
1296 else
1297 ret = TRUE;
1299 SERVER_END_REQ;
1301 return ret;
1305 /**************************************************************************
1306 * macdrv_get_pasteboard_data
1308 HANDLE macdrv_get_pasteboard_data(CFTypeRef pasteboard, UINT desired_format)
1310 CFArrayRef types;
1311 CFIndex count;
1312 CFIndex i;
1313 CFStringRef type, best_type;
1314 WINE_CLIPFORMAT* best_format = NULL;
1315 HANDLE data = NULL;
1317 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1319 types = macdrv_copy_pasteboard_types(pasteboard);
1320 if (!types)
1322 WARN("Failed to copy pasteboard types\n");
1323 return NULL;
1326 count = CFArrayGetCount(types);
1327 TRACE("got %ld types\n", count);
1329 for (i = 0; (!best_format || best_format->synthesized) && i < count; i++)
1331 WINE_CLIPFORMAT* format;
1333 type = CFArrayGetValueAtIndex(types, i);
1335 format = NULL;
1336 while ((!best_format || best_format->synthesized) && (format = format_for_type(format, type)))
1338 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format ? format->format_id : 0));
1340 if (format->format_id == desired_format)
1342 /* The best format is the matching one which is not synthesized. Failing that,
1343 the best format is the first matching synthesized format. */
1344 if (!format->synthesized || !best_format)
1346 best_type = type;
1347 best_format = format;
1353 if (best_format)
1355 CFDataRef pasteboard_data = macdrv_copy_pasteboard_data(pasteboard, best_type);
1357 TRACE("got pasteboard data for type %s: %s\n", debugstr_cf(best_type), debugstr_cf(pasteboard_data));
1359 if (pasteboard_data)
1361 data = best_format->import_func(pasteboard_data);
1362 CFRelease(pasteboard_data);
1366 CFRelease(types);
1367 TRACE(" -> %p\n", data);
1368 return data;
1372 /**************************************************************************
1373 * macdrv_pasteboard_has_format
1375 BOOL macdrv_pasteboard_has_format(CFTypeRef pasteboard, UINT desired_format)
1377 CFArrayRef types;
1378 int count;
1379 UINT i;
1380 BOOL found = FALSE;
1382 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1384 types = macdrv_copy_pasteboard_types(pasteboard);
1385 if (!types)
1387 WARN("Failed to copy pasteboard types\n");
1388 return FALSE;
1391 count = CFArrayGetCount(types);
1392 TRACE("got %d types\n", count);
1394 for (i = 0; !found && i < count; i++)
1396 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1397 WINE_CLIPFORMAT* format;
1399 format = NULL;
1400 while (!found && (format = format_for_type(format, type)))
1402 TRACE("for type %s got format %s\n", debugstr_cf(type), debugstr_format(format->format_id));
1404 if (format->format_id == desired_format)
1405 found = TRUE;
1409 CFRelease(types);
1410 TRACE(" -> %d\n", found);
1411 return found;
1415 /**************************************************************************
1416 * macdrv_copy_pasteboard_formats
1418 CFArrayRef macdrv_copy_pasteboard_formats(CFTypeRef pasteboard)
1420 CFArrayRef types;
1421 CFIndex count;
1422 CFMutableArrayRef formats;
1423 CFIndex i;
1424 WINE_CLIPFORMAT* format;
1426 TRACE("pasteboard %p\n", pasteboard);
1428 types = macdrv_copy_pasteboard_types(pasteboard);
1429 if (!types)
1431 WARN("Failed to copy pasteboard types\n");
1432 return NULL;
1435 count = CFArrayGetCount(types);
1436 TRACE("got %ld types\n", count);
1438 if (!count)
1440 CFRelease(types);
1441 return NULL;
1444 formats = CFArrayCreateMutable(NULL, 0, NULL);
1445 if (!formats)
1447 WARN("Failed to allocate formats array\n");
1448 CFRelease(types);
1449 return NULL;
1452 for (i = 0; i < count; i++)
1454 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1455 BOOL found = FALSE;
1457 format = NULL;
1458 while ((format = format_for_type(format, type)))
1460 /* Suppose type is "public.utf8-plain-text". format->format_id will be each of
1461 CF_TEXT, CF_OEMTEXT, and CF_UNICODETEXT in turn. We want to look up the natural
1462 type for each of those IDs (e.g. CF_TEXT -> "org.winehq.builtin.text") and then see
1463 if that type is present in the pasteboard. If it is, then we don't want to add the
1464 format to the list yet because it would be out of order.
1466 For example, if a Mac app put "public.utf8-plain-text" and "public.tiff" on the
1467 pasteboard, then we want the Win32 clipboard formats to be CF_TEXT, CF_OEMTEXT, and
1468 CF_UNICODETEXT, and CF_TIFF, in that order. All of the text formats belong before
1469 CF_TIFF because the Mac app expressed that text was "better" than the TIFF. In
1470 this case, as soon as we encounter "public.utf8-plain-text" we should add all of
1471 the associated text format IDs.
1473 But if a Wine process put "org.winehq.builtin.unicodetext",
1474 "public.utf8-plain-text", "public.utf16-plain-text", and "public.tiff", then we
1475 want the clipboard formats to be CF_UNICODETEXT, CF_TIFF, CF_TEXT, and CF_OEMTEXT,
1476 in that order. The Windows program presumably added CF_UNICODETEXT and CF_TIFF.
1477 We're synthesizing CF_TEXT and CF_OEMTEXT from CF_UNICODETEXT but we want them to
1478 come after the non-synthesized CF_TIFF. In this case, we don't want to add the
1479 text formats upon encountering "public.utf8-plain-text",
1481 We tell the two cases apart by seeing that one of the natural types for the text
1482 formats (i.e. "org.winehq.builtin.unicodetext") is present on the pasteboard.
1483 "found" indicates that. */
1485 if (!format->synthesized)
1487 TRACE("for type %s got primary format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1488 CFArrayAppendValue(formats, (void*)format->format_id);
1489 found = TRUE;
1491 else if (!found && format->natural_format &&
1492 CFArrayContainsValue(types, CFRangeMake(0, count), format->natural_format->type))
1494 TRACE("for type %s deferring synthesized formats because type %s is also present\n",
1495 debugstr_cf(type), debugstr_cf(format->natural_format->type));
1496 found = TRUE;
1500 if (!found)
1502 while ((format = format_for_type(format, type)))
1504 /* Don't override a real value with a synthesized value. */
1505 if (!CFArrayContainsValue(formats, CFRangeMake(0, CFArrayGetCount(formats)), (void*)format->format_id))
1507 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1508 CFArrayAppendValue(formats, (void*)format->format_id);
1514 /* Now go back through the types adding the synthesized formats that we deferred before. */
1515 for (i = 0; i < count; i++)
1517 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1519 format = NULL;
1520 while ((format = format_for_type(format, type)))
1522 if (format->synthesized)
1524 /* Don't override a real value with a synthesized value. */
1525 if (!CFArrayContainsValue(formats, CFRangeMake(0, CFArrayGetCount(formats)), (void*)format->format_id))
1527 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1528 CFArrayAppendValue(formats, (void*)format->format_id);
1534 CFRelease(types);
1536 TRACE(" -> %s\n", debugstr_cf(formats));
1537 return formats;
1541 /**************************************************************************
1542 * check_clipboard_ownership
1544 static void check_clipboard_ownership(HWND *owner)
1546 CLIPBOARDINFO cbinfo;
1548 if (owner) *owner = NULL;
1550 /* If Wine thinks we're the clipboard owner but Mac OS X thinks we're not
1551 the pasteboard owner, update Wine. */
1552 if (get_clipboard_info(&cbinfo) && (cbinfo.flags & CB_PROCESS))
1554 if (!(cbinfo.flags & CB_OPEN) && !macdrv_is_pasteboard_owner())
1556 TRACE("Lost clipboard ownership\n");
1558 if (OpenClipboard(cbinfo.hwnd_owner))
1560 /* Destroy private objects */
1561 SendMessageW(cbinfo.hwnd_owner, WM_DESTROYCLIPBOARD, 0, 0);
1563 /* Give up ownership of the windows clipboard */
1564 release_ownership();
1565 CloseClipboard();
1568 else if (owner)
1569 *owner = cbinfo.hwnd_owner;
1574 /**************************************************************************
1575 * Mac User Driver Clipboard Exports
1576 **************************************************************************/
1579 /**************************************************************************
1580 * CountClipboardFormats (MACDRV.@)
1582 INT CDECL macdrv_CountClipboardFormats(void)
1584 CFMutableSetRef seen_formats;
1585 CFArrayRef types;
1586 CFIndex count;
1587 CFIndex i;
1588 INT ret = 0;
1590 TRACE("()\n");
1591 check_clipboard_ownership(NULL);
1593 seen_formats = CFSetCreateMutable(NULL, 0, NULL);
1594 if (!seen_formats)
1596 WARN("Failed to allocate set to track seen formats\n");
1597 return 0;
1600 types = macdrv_copy_pasteboard_types(NULL);
1601 if (!types)
1603 WARN("Failed to copy pasteboard types\n");
1604 CFRelease(seen_formats);
1605 return 0;
1608 count = CFArrayGetCount(types);
1609 TRACE("got %ld types\n", count);
1611 for (i = 0; i < count; i++)
1613 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1614 WINE_CLIPFORMAT* format;
1616 format = NULL;
1617 while ((format = format_for_type(format, type)))
1619 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1621 if (!CFSetContainsValue(seen_formats, (void*)format->format_id))
1623 ret++;
1624 CFSetAddValue(seen_formats, (void*)format->format_id);
1629 CFRelease(types);
1630 CFRelease(seen_formats);
1631 TRACE(" -> %d\n", ret);
1632 return ret;
1636 /**************************************************************************
1637 * EmptyClipboard (MACDRV.@)
1639 * Empty cached clipboard data.
1641 void CDECL macdrv_EmptyClipboard(void)
1643 TRACE("()\n");
1644 check_clipboard_ownership(NULL);
1645 macdrv_clear_pasteboard();
1649 /**************************************************************************
1650 * EndClipboardUpdate (MACDRV.@)
1652 void CDECL macdrv_EndClipboardUpdate(void)
1654 TRACE("()\n");
1655 check_clipboard_ownership(NULL);
1659 /**************************************************************************
1660 * EnumClipboardFormats (MACDRV.@)
1662 UINT CDECL macdrv_EnumClipboardFormats(UINT prev_format)
1664 CFArrayRef formats;
1665 CFIndex count;
1666 CFIndex i;
1667 UINT ret = 0;
1669 TRACE("prev_format %s\n", debugstr_format(prev_format));
1670 check_clipboard_ownership(NULL);
1672 formats = macdrv_copy_pasteboard_formats(NULL);
1673 if (formats)
1675 count = CFArrayGetCount(formats);
1676 if (prev_format)
1678 i = CFArrayGetFirstIndexOfValue(formats, CFRangeMake(0, count), (void*)prev_format);
1679 if (i != kCFNotFound)
1680 i++;
1682 else
1683 i = 0;
1685 if (i != kCFNotFound && i < count)
1686 ret = (UINT)CFArrayGetValueAtIndex(formats, i);
1688 CFRelease(formats);
1691 TRACE(" -> %u\n", ret);
1692 return ret;
1696 /**************************************************************************
1697 * GetClipboardData (MACDRV.@)
1699 HANDLE CDECL macdrv_GetClipboardData(UINT desired_format)
1701 check_clipboard_ownership(NULL);
1703 return macdrv_get_pasteboard_data(NULL, desired_format);
1707 /**************************************************************************
1708 * IsClipboardFormatAvailable (MACDRV.@)
1710 BOOL CDECL macdrv_IsClipboardFormatAvailable(UINT desired_format)
1712 check_clipboard_ownership(NULL);
1713 return macdrv_pasteboard_has_format(NULL, desired_format);
1717 /**************************************************************************
1718 * SetClipboardData (MACDRV.@)
1720 BOOL CDECL macdrv_SetClipboardData(UINT format_id, HANDLE data, BOOL owner)
1722 HWND hwnd_owner;
1723 macdrv_window window;
1724 WINE_CLIPFORMAT *format;
1725 CFDataRef cfdata = NULL;
1727 check_clipboard_ownership(&hwnd_owner);
1728 window = macdrv_get_cocoa_window(GetAncestor(hwnd_owner, GA_ROOT), FALSE);
1729 TRACE("format_id %s data %p owner %d hwnd_owner %p window %p)\n", debugstr_format(format_id), data, owner, hwnd_owner, window);
1731 format = natural_format_for_format(format_id);
1732 if (!format && !(format = insert_clipboard_format(format_id, NULL)))
1734 WARN("Failed to register clipboard format %s\n", debugstr_format(format_id));
1735 return FALSE;
1738 /* Export the data to the Mac pasteboard. */
1739 if (data)
1741 if (!format->export_func || !(cfdata = format->export_func(data)))
1743 WARN("Failed to export %s data to type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1744 return FALSE;
1748 if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1749 TRACE("Set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1750 else
1752 WARN("Failed to set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1753 if (cfdata) CFRelease(cfdata);
1754 return FALSE;
1757 if (cfdata) CFRelease(cfdata);
1759 /* Find any other formats for this format_id (the exportable synthesized ones). */
1760 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1762 if (format->format_id == format_id && format->synthesized && format->export_func)
1764 /* We have a synthesized format for this format ID. Add its type to the pasteboard. */
1765 TRACE("Synthesized from format %s: type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1767 if (data)
1769 cfdata = format->export_func(data);
1770 if (!cfdata)
1772 WARN("Failed to export %s data to type %s\n", debugstr_format(format->format_id), debugstr_cf(format->type));
1773 continue;
1776 else
1777 cfdata = NULL;
1779 if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1780 TRACE(" ... set pasteboard data: %s\n", debugstr_cf(cfdata));
1781 else
1782 WARN(" ... failed to set pasteboard data: %s\n", debugstr_cf(cfdata));
1784 if (cfdata) CFRelease(cfdata);
1788 if (data)
1790 /* FIXME: According to MSDN, the caller is entitled to lock and read from
1791 data until CloseClipboard is called. So, we should defer this cleanup. */
1792 if ((format_id >= CF_GDIOBJFIRST && format_id <= CF_GDIOBJLAST) ||
1793 format_id == CF_BITMAP ||
1794 format_id == CF_DIB ||
1795 format_id == CF_PALETTE)
1797 DeleteObject(data);
1799 else if (format_id == CF_METAFILEPICT)
1801 DeleteMetaFile(((METAFILEPICT *)GlobalLock(data))->hMF);
1802 GlobalFree(data);
1804 else if (format_id == CF_ENHMETAFILE)
1806 DeleteEnhMetaFile(data);
1808 else if (format_id < CF_PRIVATEFIRST || CF_PRIVATELAST < format_id)
1810 GlobalFree(data);
1814 return TRUE;
1818 /**************************************************************************
1819 * MACDRV Private Clipboard Exports
1820 **************************************************************************/
1823 /**************************************************************************
1824 * macdrv_clipboard_process_attach
1826 void macdrv_clipboard_process_attach(void)
1828 UINT i;
1829 WINE_CLIPFORMAT *format;
1831 /* Register built-in formats */
1832 for (i = 0; i < sizeof(builtin_format_ids)/sizeof(builtin_format_ids[0]); i++)
1834 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
1835 format->format_id = builtin_format_ids[i].id;
1836 format->type = CFRetain(builtin_format_ids[i].type);
1837 format->import_func = builtin_format_ids[i].import;
1838 format->export_func = builtin_format_ids[i].export;
1839 format->synthesized = builtin_format_ids[i].synthesized;
1840 format->natural_format = NULL;
1841 list_add_tail(&format_list, &format->entry);
1844 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1846 if (format->synthesized)
1847 format->natural_format = natural_format_for_format(format->format_id);
1850 /* Register known mappings between Windows formats and Mac types */
1851 for (i = 0; i < sizeof(builtin_format_names)/sizeof(builtin_format_names[0]); i++)
1853 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
1854 format->format_id = RegisterClipboardFormatW(builtin_format_names[i].name);
1855 format->type = CFRetain(builtin_format_names[i].type);
1856 format->import_func = builtin_format_names[i].import;
1857 format->export_func = builtin_format_names[i].export;
1858 format->synthesized = FALSE;
1859 format->natural_format = NULL;
1860 list_add_tail(&format_list, &format->entry);
1865 /**************************************************************************
1866 * query_pasteboard_data
1868 BOOL query_pasteboard_data(HWND hwnd, CFStringRef type)
1870 BOOL ret = FALSE;
1871 CLIPBOARDINFO cbinfo;
1872 WINE_CLIPFORMAT* format;
1873 CFArrayRef types = NULL;
1874 CFRange range;
1876 TRACE("hwnd %p type %s\n", hwnd, debugstr_cf(type));
1878 if (get_clipboard_info(&cbinfo))
1879 hwnd = cbinfo.hwnd_owner;
1881 format = NULL;
1882 while ((format = format_for_type(format, type)))
1884 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1886 if (!format->synthesized)
1888 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(format->format_id), hwnd);
1889 SendMessageW(hwnd, WM_RENDERFORMAT, format->format_id, 0);
1890 ret = TRUE;
1891 goto done;
1894 if (!types)
1896 types = macdrv_copy_pasteboard_types(NULL);
1897 if (!types)
1899 WARN("Failed to copy pasteboard types\n");
1900 break;
1903 range = CFRangeMake(0, CFArrayGetCount(types));
1906 /* The type maps to a synthesized format. Now look up what type that format maps to natively
1907 (not synthesized). For example, if type is "public.utf8-plain-text", then this format may
1908 have an ID of CF_TEXT. From CF_TEXT, we want to find "org.winehq.builtin.text" to see if
1909 that type is present in the pasteboard. If it is, then the app must have promised it and
1910 we can ask it to render it. (If it had put it on the clipboard immediately, then the
1911 pasteboard would also have data for "public.utf8-plain-text" and we wouldn't be here.) If
1912 "org.winehq.builtin.text" is not on the pasteboard, then one of the other text formats is
1913 presumably responsible for the promise that we're trying to satisfy, so we keep looking. */
1914 if (format->natural_format && CFArrayContainsValue(types, range, format->natural_format->type))
1916 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(format->format_id), hwnd);
1917 SendMessageW(hwnd, WM_RENDERFORMAT, format->format_id, 0);
1918 ret = TRUE;
1919 goto done;
1923 done:
1924 if (types) CFRelease(types);
1926 return ret;