webservices: Implement the Message Framing Protocol.
[wine.git] / dlls / winemac.drv / clipboard.c
blobac0dc3101a0ade1b69011a2702bb0e2de0f5a65b
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 HANDLE (*DRVIMPORTFUNC)(CFDataRef data);
44 typedef CFDataRef (*DRVEXPORTFUNC)(HANDLE data);
46 typedef struct _WINE_CLIPFORMAT
48 struct list entry;
49 UINT format_id;
50 CFStringRef type;
51 DRVIMPORTFUNC import_func;
52 DRVEXPORTFUNC export_func;
53 BOOL synthesized;
54 struct _WINE_CLIPFORMAT *natural_format;
55 } WINE_CLIPFORMAT;
58 /**************************************************************************
59 * Constants
60 **************************************************************************/
62 #define CLIPBOARD_UPDATE_DELAY 2000 /* delay between checks of the Mac pasteboard */
65 /**************************************************************************
66 * Forward Function Declarations
67 **************************************************************************/
69 static HANDLE import_clipboard_data(CFDataRef data);
70 static HANDLE import_bmp_to_bitmap(CFDataRef data);
71 static HANDLE import_bmp_to_dib(CFDataRef data);
72 static HANDLE import_enhmetafile(CFDataRef data);
73 static HANDLE import_html(CFDataRef data);
74 static HANDLE import_metafilepict(CFDataRef data);
75 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data);
76 static HANDLE import_utf8_to_text(CFDataRef data);
77 static HANDLE import_utf8_to_unicodetext(CFDataRef data);
78 static HANDLE import_utf16_to_unicodetext(CFDataRef data);
80 static CFDataRef export_clipboard_data(HANDLE data);
81 static CFDataRef export_bitmap_to_bmp(HANDLE data);
82 static CFDataRef export_dib_to_bmp(HANDLE data);
83 static CFDataRef export_enhmetafile(HANDLE data);
84 static CFDataRef export_hdrop_to_filenames(HANDLE data);
85 static CFDataRef export_html(HANDLE data);
86 static CFDataRef export_metafilepict(HANDLE data);
87 static CFDataRef export_text_to_utf8(HANDLE data);
88 static CFDataRef export_unicodetext_to_utf8(HANDLE data);
89 static CFDataRef export_unicodetext_to_utf16(HANDLE data);
92 /**************************************************************************
93 * Static Variables
94 **************************************************************************/
96 /* Clipboard formats */
97 static struct list format_list = LIST_INIT(format_list);
99 /* There are two naming schemes involved and we want to have a mapping between
100 them. There are Win32 clipboard format names and there are Mac pasteboard
101 types.
103 The Win32 standard clipboard formats don't have names, but they are associated
104 with Mac pasteboard types through the following tables, which are used to
105 initialize the format_list. Where possible, the standard clipboard formats
106 are mapped to predefined pasteboard type UTIs. Otherwise, we create Wine-
107 specific types of the form "org.winehq.builtin.<format>", where <format> is
108 the name of the symbolic constant for the format minus "CF_" and lowercased.
109 E.g. CF_BITMAP -> org.winehq.builtin.bitmap.
111 Win32 clipboard formats which originate in a Windows program may be registered
112 with an arbitrary name. We construct a Mac pasteboard type from these by
113 prepending "org.winehq.registered." to the registered name.
115 Likewise, Mac pasteboard types which originate in other apps may have
116 arbitrary type strings. We ignore these.
118 Summary:
119 Win32 clipboard format names:
120 <none> standard clipboard format; maps via
121 format_list to either a predefined Mac UTI
122 or org.winehq.builtin.<format>.
123 <other> name registered within Win32 land; maps to
124 org.winehq.registered.<other>
125 Mac pasteboard type names:
126 org.winehq.builtin.<format ID> representation of Win32 standard clipboard
127 format for which there was no corresponding
128 predefined Mac UTI; maps via format_list
129 org.winehq.registered.<format name> representation of Win32 registered
130 clipboard format name; maps to <format name>
131 <other> Mac pasteboard type originating with system
132 or other apps; either maps via format_list
133 to a standard clipboard format or ignored
136 static const struct
138 UINT id;
139 CFStringRef type;
140 DRVIMPORTFUNC import;
141 DRVEXPORTFUNC export;
142 BOOL synthesized;
143 } builtin_format_ids[] =
145 { CF_BITMAP, CFSTR("org.winehq.builtin.bitmap"), import_bmp_to_bitmap, export_bitmap_to_bmp, FALSE },
146 { CF_DIBV5, CFSTR("org.winehq.builtin.dibv5"), import_clipboard_data, export_clipboard_data, FALSE },
147 { CF_DIF, CFSTR("org.winehq.builtin.dif"), import_clipboard_data, export_clipboard_data, FALSE },
148 { CF_ENHMETAFILE, CFSTR("org.winehq.builtin.enhmetafile"), import_enhmetafile, export_enhmetafile, FALSE },
149 { CF_LOCALE, CFSTR("org.winehq.builtin.locale"), import_clipboard_data, export_clipboard_data, FALSE },
150 { CF_METAFILEPICT, CFSTR("org.winehq.builtin.metafilepict"), import_metafilepict, export_metafilepict, FALSE },
151 { CF_OEMTEXT, CFSTR("org.winehq.builtin.oemtext"), import_clipboard_data, export_clipboard_data, FALSE },
152 { CF_PALETTE, CFSTR("org.winehq.builtin.palette"), import_clipboard_data, export_clipboard_data, FALSE },
153 { CF_PENDATA, CFSTR("org.winehq.builtin.pendata"), import_clipboard_data, export_clipboard_data, FALSE },
154 { CF_RIFF, CFSTR("org.winehq.builtin.riff"), import_clipboard_data, export_clipboard_data, FALSE },
155 { CF_SYLK, CFSTR("org.winehq.builtin.sylk"), import_clipboard_data, export_clipboard_data, FALSE },
156 { CF_TEXT, CFSTR("org.winehq.builtin.text"), import_clipboard_data, export_clipboard_data, FALSE },
157 { CF_TIFF, CFSTR("public.tiff"), import_clipboard_data, export_clipboard_data, FALSE },
158 { CF_WAVE, CFSTR("com.microsoft.waveform-audio"), import_clipboard_data, export_clipboard_data, FALSE },
160 { CF_DIB, CFSTR("org.winehq.builtin.dib"), import_clipboard_data, export_clipboard_data, FALSE },
161 { CF_DIB, CFSTR("com.microsoft.bmp"), import_bmp_to_dib, export_dib_to_bmp, TRUE },
163 { CF_HDROP, CFSTR("org.winehq.builtin.hdrop"), import_clipboard_data, export_clipboard_data, FALSE },
164 { CF_HDROP, CFSTR("NSFilenamesPboardType"), import_nsfilenames_to_hdrop, export_hdrop_to_filenames, TRUE },
166 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.unicodetext"), import_clipboard_data, export_clipboard_data, FALSE },
167 { CF_UNICODETEXT, CFSTR("public.utf16-plain-text"), import_utf16_to_unicodetext, export_unicodetext_to_utf16,TRUE },
168 { CF_UNICODETEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_unicodetext, export_unicodetext_to_utf8, TRUE },
171 static const WCHAR wszRichTextFormat[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
172 static const WCHAR wszGIF[] = {'G','I','F',0};
173 static const WCHAR wszJFIF[] = {'J','F','I','F',0};
174 static const WCHAR wszPNG[] = {'P','N','G',0};
175 static const WCHAR wszHTMLFormat[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
176 static const struct
178 LPCWSTR name;
179 CFStringRef type;
180 DRVIMPORTFUNC import;
181 DRVEXPORTFUNC export;
182 BOOL synthesized;
183 } builtin_format_names[] =
185 { wszRichTextFormat, CFSTR("public.rtf"), import_clipboard_data, export_clipboard_data },
186 { wszGIF, CFSTR("com.compuserve.gif"), import_clipboard_data, export_clipboard_data },
187 { wszJFIF, CFSTR("public.jpeg"), import_clipboard_data, export_clipboard_data },
188 { wszPNG, CFSTR("public.png"), import_clipboard_data, export_clipboard_data },
189 { wszHTMLFormat, NULL, import_clipboard_data, export_clipboard_data },
190 { wszHTMLFormat, CFSTR("public.html"), import_html, export_html, TRUE },
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.");
197 static DWORD clipboard_thread_id;
198 static HWND clipboard_hwnd;
199 static BOOL is_clipboard_owner;
200 static macdrv_window clipboard_cocoa_window;
201 static ULONG64 last_clipboard_update;
202 static DWORD last_get_seqno;
203 static WINE_CLIPFORMAT **current_mac_formats;
204 static unsigned int nb_current_mac_formats;
205 static WCHAR clipboard_pipe_name[256];
208 /**************************************************************************
209 * Internal Clipboard implementation methods
210 **************************************************************************/
213 * format_list functions
216 /**************************************************************************
217 * debugstr_format
219 const char *debugstr_format(UINT id)
221 WCHAR buffer[256];
223 if (GetClipboardFormatNameW(id, buffer, 256))
224 return wine_dbg_sprintf("0x%04x %s", id, debugstr_w(buffer));
226 switch (id)
228 #define BUILTIN(id) case id: return #id;
229 BUILTIN(CF_TEXT)
230 BUILTIN(CF_BITMAP)
231 BUILTIN(CF_METAFILEPICT)
232 BUILTIN(CF_SYLK)
233 BUILTIN(CF_DIF)
234 BUILTIN(CF_TIFF)
235 BUILTIN(CF_OEMTEXT)
236 BUILTIN(CF_DIB)
237 BUILTIN(CF_PALETTE)
238 BUILTIN(CF_PENDATA)
239 BUILTIN(CF_RIFF)
240 BUILTIN(CF_WAVE)
241 BUILTIN(CF_UNICODETEXT)
242 BUILTIN(CF_ENHMETAFILE)
243 BUILTIN(CF_HDROP)
244 BUILTIN(CF_LOCALE)
245 BUILTIN(CF_DIBV5)
246 BUILTIN(CF_OWNERDISPLAY)
247 BUILTIN(CF_DSPTEXT)
248 BUILTIN(CF_DSPBITMAP)
249 BUILTIN(CF_DSPMETAFILEPICT)
250 BUILTIN(CF_DSPENHMETAFILE)
251 #undef BUILTIN
252 default: return wine_dbg_sprintf("0x%04x", id);
257 /**************************************************************************
258 * insert_clipboard_format
260 static WINE_CLIPFORMAT *insert_clipboard_format(UINT id, CFStringRef type)
262 WINE_CLIPFORMAT *format;
264 format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format));
266 if (format == NULL)
268 WARN("No more memory for a new format!\n");
269 return NULL;
271 format->format_id = id;
272 format->import_func = import_clipboard_data;
273 format->export_func = export_clipboard_data;
274 format->synthesized = FALSE;
275 format->natural_format = NULL;
277 if (type)
278 format->type = CFStringCreateCopy(NULL, type);
279 else
281 WCHAR buffer[256];
283 if (!GetClipboardFormatNameW(format->format_id, buffer, sizeof(buffer) / sizeof(buffer[0])))
285 WARN("failed to get name for format %s; error 0x%08x\n", debugstr_format(format->format_id), GetLastError());
286 HeapFree(GetProcessHeap(), 0, format);
287 return NULL;
290 format->type = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%S"),
291 registered_name_type_prefix, buffer);
294 list_add_tail(&format_list, &format->entry);
296 TRACE("Registering format %s type %s\n", debugstr_format(format->format_id),
297 debugstr_cf(format->type));
299 return format;
303 /**************************************************************************
304 * register_format
306 * Register a custom Mac clipboard format.
308 static WINE_CLIPFORMAT* register_format(UINT id, CFStringRef type)
310 WINE_CLIPFORMAT *format;
312 /* walk format chain to see if it's already registered */
313 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
314 if (format->format_id == id) return format;
316 return insert_clipboard_format(id, type);
320 /**************************************************************************
321 * natural_format_for_format
323 * Find the "natural" format for this format_id (the one which isn't
324 * synthesized from another type).
326 static WINE_CLIPFORMAT* natural_format_for_format(UINT format_id)
328 WINE_CLIPFORMAT *format;
330 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
331 if (format->format_id == format_id && !format->synthesized) break;
333 if (&format->entry == &format_list)
334 format = NULL;
336 TRACE("%s -> %p/%s\n", debugstr_format(format_id), format, debugstr_cf(format ? format->type : NULL));
337 return format;
341 /**************************************************************************
342 * register_builtin_formats
344 static void register_builtin_formats(void)
346 UINT i;
347 WINE_CLIPFORMAT *format;
349 /* Register built-in formats */
350 for (i = 0; i < sizeof(builtin_format_ids)/sizeof(builtin_format_ids[0]); i++)
352 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
353 format->format_id = builtin_format_ids[i].id;
354 format->type = CFRetain(builtin_format_ids[i].type);
355 format->import_func = builtin_format_ids[i].import;
356 format->export_func = builtin_format_ids[i].export;
357 format->synthesized = builtin_format_ids[i].synthesized;
358 format->natural_format = NULL;
359 list_add_tail(&format_list, &format->entry);
362 /* Register known mappings between Windows formats and Mac types */
363 for (i = 0; i < sizeof(builtin_format_names)/sizeof(builtin_format_names[0]); i++)
365 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
366 format->format_id = RegisterClipboardFormatW(builtin_format_names[i].name);
367 format->import_func = builtin_format_names[i].import;
368 format->export_func = builtin_format_names[i].export;
369 format->synthesized = builtin_format_names[i].synthesized;
370 format->natural_format = NULL;
372 if (builtin_format_names[i].type)
373 format->type = CFRetain(builtin_format_names[i].type);
374 else
376 format->type = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%S"),
377 registered_name_type_prefix, builtin_format_names[i].name);
380 list_add_tail(&format_list, &format->entry);
383 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
385 if (format->synthesized)
386 format->natural_format = natural_format_for_format(format->format_id);
391 /**************************************************************************
392 * format_for_type
394 static WINE_CLIPFORMAT* format_for_type(CFStringRef type)
396 WINE_CLIPFORMAT *format;
398 TRACE("type %s\n", debugstr_cf(type));
400 if (list_empty(&format_list)) register_builtin_formats();
402 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
404 if (CFEqual(format->type, type))
405 goto done;
408 format = NULL;
409 if (CFStringHasPrefix(type, CFSTR("org.winehq.builtin.")))
411 ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
412 debugstr_cf(type));
414 else if (CFStringHasPrefix(type, registered_name_type_prefix))
416 LPWSTR name;
417 int len = CFStringGetLength(type) - CFStringGetLength(registered_name_type_prefix);
419 name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
420 CFStringGetCharacters(type, CFRangeMake(CFStringGetLength(registered_name_type_prefix), len),
421 (UniChar*)name);
422 name[len] = 0;
424 format = register_format(RegisterClipboardFormatW(name), type);
425 if (!format)
426 ERR("Failed to register format for type %s name %s\n", debugstr_cf(type), debugstr_w(name));
428 HeapFree(GetProcessHeap(), 0, name);
431 done:
432 TRACE(" -> %p/%s\n", format, debugstr_format(format ? format->format_id : 0));
433 return format;
437 /***********************************************************************
438 * bitmap_info_size
440 * Return the size of the bitmap info structure including color table.
442 static int bitmap_info_size(const BITMAPINFO *info, WORD coloruse)
444 unsigned int colors, size, masks = 0;
446 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
448 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER*)info;
449 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
450 return sizeof(BITMAPCOREHEADER) + colors *
451 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
453 else /* assume BITMAPINFOHEADER */
455 colors = min(info->bmiHeader.biClrUsed, 256);
456 if (!colors && (info->bmiHeader.biBitCount <= 8))
457 colors = 1 << info->bmiHeader.biBitCount;
458 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
459 size = max(info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD));
460 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
465 /***********************************************************************
466 * create_dib_from_bitmap
468 * Allocates a packed DIB and copies the bitmap data into it.
470 static HGLOBAL create_dib_from_bitmap(HBITMAP bitmap)
472 HANDLE ret = 0;
473 BITMAPINFOHEADER header;
474 HDC hdc = GetDC(0);
475 DWORD header_size;
476 BITMAPINFO *bmi;
478 memset(&header, 0, sizeof(header));
479 header.biSize = sizeof(header);
480 if (!GetDIBits(hdc, bitmap, 0, 0, NULL, (BITMAPINFO *)&header, DIB_RGB_COLORS)) goto done;
482 header_size = bitmap_info_size((BITMAPINFO *)&header, DIB_RGB_COLORS);
483 if (!(ret = GlobalAlloc(GMEM_FIXED, header_size + header.biSizeImage))) goto done;
484 bmi = (BITMAPINFO *)ret;
485 memset(bmi, 0, header_size);
486 memcpy(bmi, &header, header.biSize);
487 GetDIBits(hdc, bitmap, 0, abs(header.biHeight), (char *)bmi + header_size, bmi, DIB_RGB_COLORS);
489 done:
490 ReleaseDC(0, hdc);
491 return ret;
495 /**************************************************************************
496 * create_bitmap_from_dib
498 * Given a packed DIB, creates a bitmap object from it.
500 static HANDLE create_bitmap_from_dib(HANDLE dib)
502 HANDLE ret = 0;
503 BITMAPINFO *bmi;
505 if (dib && (bmi = GlobalLock(dib)))
507 HDC hdc;
508 unsigned int offset;
510 hdc = GetDC(NULL);
512 offset = bitmap_info_size(bmi, DIB_RGB_COLORS);
514 ret = CreateDIBitmap(hdc, &bmi->bmiHeader, CBM_INIT, (LPBYTE)bmi + offset,
515 bmi, DIB_RGB_COLORS);
517 GlobalUnlock(dib);
518 ReleaseDC(NULL, hdc);
521 return ret;
525 /**************************************************************************
526 * get_html_description_field
528 * Find the value of a field in an HTML Format description.
530 static const char* get_html_description_field(const char* data, const char* keyword)
532 const char* pos = data;
534 while (pos && *pos && *pos != '<')
536 if (memcmp(pos, keyword, strlen(keyword)) == 0)
537 return pos + strlen(keyword);
539 pos = strchr(pos, '\n');
540 if (pos) pos++;
543 return NULL;
547 /**************************************************************************
548 * import_clipboard_data
550 * Generic import clipboard data routine.
552 static HANDLE import_clipboard_data(CFDataRef data)
554 HANDLE data_handle = NULL;
556 size_t len = CFDataGetLength(data);
557 if (len)
559 LPVOID p;
561 /* Turn on the DDESHARE flag to enable shared 32 bit memory */
562 data_handle = GlobalAlloc(GMEM_FIXED, len);
563 if (!data_handle)
564 return NULL;
566 if ((p = GlobalLock(data_handle)))
568 memcpy(p, CFDataGetBytePtr(data), len);
569 GlobalUnlock(data_handle);
571 else
573 GlobalFree(data_handle);
574 data_handle = NULL;
578 return data_handle;
582 /**************************************************************************
583 * import_bmp_to_bitmap
585 * Import BMP data, converting to CF_BITMAP format.
587 static HANDLE import_bmp_to_bitmap(CFDataRef data)
589 HANDLE ret;
590 HANDLE dib = import_bmp_to_dib(data);
592 ret = create_bitmap_from_dib(dib);
594 GlobalFree(dib);
595 return ret;
599 /**************************************************************************
600 * import_bmp_to_dib
602 * Import BMP data, converting to CF_DIB or CF_DIBV5 format. This just
603 * entails stripping the BMP file format header.
605 static HANDLE import_bmp_to_dib(CFDataRef data)
607 HANDLE ret = 0;
608 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)CFDataGetBytePtr(data);
609 CFIndex len = CFDataGetLength(data);
611 if (len >= sizeof(*bfh) + sizeof(BITMAPCOREHEADER) &&
612 bfh->bfType == 0x4d42 /* "BM" */)
614 BITMAPINFO *bmi = (BITMAPINFO*)(bfh + 1);
615 BYTE* p;
617 len -= sizeof(*bfh);
618 ret = GlobalAlloc(GMEM_FIXED, len);
619 if (!ret || !(p = GlobalLock(ret)))
621 GlobalFree(ret);
622 return 0;
625 memcpy(p, bmi, len);
626 GlobalUnlock(ret);
629 return ret;
633 /**************************************************************************
634 * import_enhmetafile
636 * Import enhanced metafile data, converting it to CF_ENHMETAFILE.
638 static HANDLE import_enhmetafile(CFDataRef data)
640 HANDLE ret = 0;
641 CFIndex len = CFDataGetLength(data);
643 TRACE("data %s\n", debugstr_cf(data));
645 if (len)
646 ret = SetEnhMetaFileBits(len, (const BYTE*)CFDataGetBytePtr(data));
648 return ret;
652 /**************************************************************************
653 * import_html
655 * Import HTML data.
657 static HANDLE import_html(CFDataRef data)
659 static const char header[] =
660 "Version:0.9\n"
661 "StartHTML:0000000100\n"
662 "EndHTML:%010lu\n"
663 "StartFragment:%010lu\n"
664 "EndFragment:%010lu\n"
665 "<!--StartFragment-->";
666 static const char trailer[] = "\n<!--EndFragment-->";
667 HANDLE ret;
668 SIZE_T len, total;
669 size_t size = CFDataGetLength(data);
671 len = strlen(header) + 12; /* 3 * 4 extra chars for %010lu */
672 total = len + size + sizeof(trailer);
673 if ((ret = GlobalAlloc(GMEM_FIXED, total)))
675 char *p = ret;
676 p += sprintf(p, header, total - 1, len, len + size + 1 /* include the final \n in the data */);
677 CFDataGetBytes(data, CFRangeMake(0, size), (UInt8*)p);
678 strcpy(p + size, trailer);
679 TRACE("returning %s\n", debugstr_a(ret));
681 return ret;
685 /**************************************************************************
686 * import_metafilepict
688 * Import metafile picture data, converting it to CF_METAFILEPICT.
690 static HANDLE import_metafilepict(CFDataRef data)
692 HANDLE ret = 0;
693 CFIndex len = CFDataGetLength(data);
694 METAFILEPICT *mfp;
696 TRACE("data %s\n", debugstr_cf(data));
698 if (len >= sizeof(*mfp) && (ret = GlobalAlloc(GMEM_FIXED, sizeof(*mfp))))
700 const BYTE *bytes = (const BYTE*)CFDataGetBytePtr(data);
702 mfp = GlobalLock(ret);
703 memcpy(mfp, bytes, sizeof(*mfp));
704 mfp->hMF = SetMetaFileBitsEx(len - sizeof(*mfp), bytes + sizeof(*mfp));
705 GlobalUnlock(ret);
708 return ret;
712 /**************************************************************************
713 * import_nsfilenames_to_hdrop
715 * Import NSFilenamesPboardType data, converting the property-list-
716 * serialized array of path strings to CF_HDROP.
718 static HANDLE import_nsfilenames_to_hdrop(CFDataRef data)
720 HDROP hdrop = NULL;
721 CFArrayRef names;
722 CFIndex count, i;
723 size_t len;
724 char *buffer = NULL;
725 WCHAR **paths = NULL;
726 DROPFILES* dropfiles;
727 UniChar* p;
729 TRACE("data %s\n", debugstr_cf(data));
731 names = (CFArrayRef)CFPropertyListCreateWithData(NULL, data, kCFPropertyListImmutable,
732 NULL, NULL);
733 if (!names || CFGetTypeID(names) != CFArrayGetTypeID())
735 WARN("failed to interpret data as a CFArray\n");
736 goto done;
739 count = CFArrayGetCount(names);
741 len = 0;
742 for (i = 0; i < count; i++)
744 CFIndex this_len;
745 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
746 TRACE(" %s\n", debugstr_cf(name));
747 if (CFGetTypeID(name) != CFStringGetTypeID())
749 WARN("non-string in array\n");
750 goto done;
753 this_len = CFStringGetMaximumSizeOfFileSystemRepresentation(name);
754 if (this_len > len)
755 len = this_len;
758 buffer = HeapAlloc(GetProcessHeap(), 0, len);
759 if (!buffer)
761 WARN("failed to allocate buffer for file-system representations\n");
762 goto done;
765 paths = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(paths[0]));
766 if (!paths)
768 WARN("failed to allocate array of DOS paths\n");
769 goto done;
772 for (i = 0; i < count; i++)
774 CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
775 if (!CFStringGetFileSystemRepresentation(name, buffer, len))
777 WARN("failed to get file-system representation for %s\n", debugstr_cf(name));
778 goto done;
780 paths[i] = wine_get_dos_file_name(buffer);
781 if (!paths[i])
783 WARN("failed to get DOS path for %s\n", debugstr_a(buffer));
784 goto done;
788 len = 1; /* for the terminating null */
789 for (i = 0; i < count; i++)
790 len += strlenW(paths[i]) + 1;
792 hdrop = GlobalAlloc(GMEM_FIXED, sizeof(*dropfiles) + len * sizeof(WCHAR));
793 if (!hdrop || !(dropfiles = GlobalLock(hdrop)))
795 WARN("failed to allocate HDROP\n");
796 GlobalFree(hdrop);
797 hdrop = NULL;
798 goto done;
801 dropfiles->pFiles = sizeof(*dropfiles);
802 dropfiles->pt.x = 0;
803 dropfiles->pt.y = 0;
804 dropfiles->fNC = FALSE;
805 dropfiles->fWide = TRUE;
807 p = (WCHAR*)(dropfiles + 1);
808 for (i = 0; i < count; i++)
810 strcpyW(p, paths[i]);
811 p += strlenW(p) + 1;
813 *p = 0;
815 GlobalUnlock(hdrop);
817 done:
818 if (paths)
820 for (i = 0; i < count; i++)
821 HeapFree(GetProcessHeap(), 0, paths[i]);
822 HeapFree(GetProcessHeap(), 0, paths);
824 HeapFree(GetProcessHeap(), 0, buffer);
825 if (names) CFRelease(names);
826 return hdrop;
830 /**************************************************************************
831 * import_utf8_to_text
833 * Import a UTF-8 string, converting the string to CF_TEXT.
835 static HANDLE import_utf8_to_text(CFDataRef data)
837 HANDLE ret = NULL;
838 HANDLE unicode_handle = import_utf8_to_unicodetext(data);
839 LPWSTR unicode_string = GlobalLock(unicode_handle);
841 if (unicode_string)
843 int unicode_len;
844 HANDLE handle;
845 char *p;
846 INT len;
848 unicode_len = GlobalSize(unicode_handle) / sizeof(WCHAR);
850 len = WideCharToMultiByte(CP_ACP, 0, unicode_string, unicode_len, NULL, 0, NULL, NULL);
851 if (!unicode_len || unicode_string[unicode_len - 1]) len += 1;
852 handle = GlobalAlloc(GMEM_FIXED, len);
854 if (handle && (p = GlobalLock(handle)))
856 WideCharToMultiByte(CP_ACP, 0, unicode_string, unicode_len, p, len, NULL, NULL);
857 p[len - 1] = 0;
858 GlobalUnlock(handle);
859 ret = handle;
861 GlobalUnlock(unicode_handle);
864 GlobalFree(unicode_handle);
865 return ret;
869 /**************************************************************************
870 * import_utf8_to_unicodetext
872 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
874 static HANDLE import_utf8_to_unicodetext(CFDataRef data)
876 const BYTE *src;
877 unsigned long src_len;
878 unsigned long new_lines = 0;
879 LPSTR dst;
880 unsigned long i, j;
881 HANDLE unicode_handle = NULL;
883 src = CFDataGetBytePtr(data);
884 src_len = CFDataGetLength(data);
885 for (i = 0; i < src_len; i++)
887 if (src[i] == '\n')
888 new_lines++;
891 if ((dst = HeapAlloc(GetProcessHeap(), 0, src_len + new_lines + 1)))
893 UINT count;
895 for (i = 0, j = 0; i < src_len; i++)
897 if (src[i] == '\n')
898 dst[j++] = '\r';
900 dst[j++] = src[i];
902 dst[j] = 0;
904 count = MultiByteToWideChar(CP_UTF8, 0, dst, -1, NULL, 0);
905 unicode_handle = GlobalAlloc(GMEM_FIXED, count * sizeof(WCHAR));
907 if (unicode_handle)
909 WCHAR *textW = GlobalLock(unicode_handle);
910 MultiByteToWideChar(CP_UTF8, 0, dst, -1, textW, count);
911 GlobalUnlock(unicode_handle);
914 HeapFree(GetProcessHeap(), 0, dst);
917 return unicode_handle;
921 /**************************************************************************
922 * import_utf16_to_unicodetext
924 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
926 static HANDLE import_utf16_to_unicodetext(CFDataRef data)
928 const WCHAR *src;
929 unsigned long src_len;
930 unsigned long new_lines = 0;
931 LPWSTR dst;
932 unsigned long i, j;
933 HANDLE unicode_handle;
935 src = (const WCHAR *)CFDataGetBytePtr(data);
936 src_len = CFDataGetLength(data) / sizeof(WCHAR);
937 for (i = 0; i < src_len; i++)
939 if (src[i] == '\n')
940 new_lines++;
941 else if (src[i] == '\r' && (i + 1 >= src_len || src[i + 1] != '\n'))
942 new_lines++;
945 if ((unicode_handle = GlobalAlloc(GMEM_FIXED, (src_len + new_lines + 1) * sizeof(WCHAR))))
947 dst = GlobalLock(unicode_handle);
949 for (i = 0, j = 0; i < src_len; i++)
951 if (src[i] == '\n')
952 dst[j++] = '\r';
954 dst[j++] = src[i];
956 if (src[i] == '\r' && (i + 1 >= src_len || src[i + 1] != '\n'))
957 dst[j++] = '\n';
959 dst[j] = 0;
961 GlobalUnlock(unicode_handle);
964 return unicode_handle;
968 /**************************************************************************
969 * export_clipboard_data
971 * Generic export clipboard data routine.
973 static CFDataRef export_clipboard_data(HANDLE data)
975 CFDataRef ret;
976 UINT len;
977 LPVOID src;
979 len = GlobalSize(data);
980 src = GlobalLock(data);
981 if (!src) return NULL;
983 ret = CFDataCreate(NULL, src, len);
984 GlobalUnlock(data);
986 return ret;
990 /**************************************************************************
991 * export_bitmap_to_bmp
993 * Export CF_BITMAP to BMP file format.
995 static CFDataRef export_bitmap_to_bmp(HANDLE data)
997 CFDataRef ret = NULL;
998 HGLOBAL dib;
1000 dib = create_dib_from_bitmap(data);
1001 if (dib)
1003 ret = export_dib_to_bmp(dib);
1004 GlobalFree(dib);
1007 return ret;
1011 /**************************************************************************
1012 * export_dib_to_bmp
1014 * Export CF_DIB or CF_DIBV5 to BMP file format. This just entails
1015 * prepending a BMP file format header to the data.
1017 static CFDataRef export_dib_to_bmp(HANDLE data)
1019 CFMutableDataRef ret = NULL;
1020 BYTE *dibdata;
1021 CFIndex len;
1022 BITMAPFILEHEADER bfh;
1024 dibdata = GlobalLock(data);
1025 if (!dibdata)
1026 return NULL;
1028 len = sizeof(bfh) + GlobalSize(data);
1029 ret = CFDataCreateMutable(NULL, len);
1030 if (ret)
1032 bfh.bfType = 0x4d42; /* "BM" */
1033 bfh.bfSize = len;
1034 bfh.bfReserved1 = 0;
1035 bfh.bfReserved2 = 0;
1036 bfh.bfOffBits = sizeof(bfh) + bitmap_info_size((BITMAPINFO*)dibdata, DIB_RGB_COLORS);
1037 CFDataAppendBytes(ret, (UInt8*)&bfh, sizeof(bfh));
1039 /* rest of bitmap is the same as the packed dib */
1040 CFDataAppendBytes(ret, (UInt8*)dibdata, len - sizeof(bfh));
1043 GlobalUnlock(data);
1045 return ret;
1049 /**************************************************************************
1050 * export_enhmetafile
1052 * Export an enhanced metafile to data.
1054 static CFDataRef export_enhmetafile(HANDLE data)
1056 CFMutableDataRef ret = NULL;
1057 unsigned int size = GetEnhMetaFileBits(data, 0, NULL);
1059 TRACE("data %p\n", data);
1061 ret = CFDataCreateMutable(NULL, size);
1062 if (ret)
1064 CFDataSetLength(ret, size);
1065 GetEnhMetaFileBits(data, size, (BYTE*)CFDataGetMutableBytePtr(ret));
1068 TRACE(" -> %s\n", debugstr_cf(ret));
1069 return ret;
1073 /**************************************************************************
1074 * export_hdrop_to_filenames
1076 * Export CF_HDROP to NSFilenamesPboardType data, which is a CFArray of
1077 * CFStrings (holding Unix paths) which is serialized as a property list.
1079 static CFDataRef export_hdrop_to_filenames(HANDLE data)
1081 CFDataRef ret = NULL;
1082 DROPFILES *dropfiles;
1083 CFMutableArrayRef filenames = NULL;
1084 void *p;
1085 WCHAR *buffer = NULL;
1086 size_t buffer_len = 0;
1088 TRACE("data %p\n", data);
1090 if (!(dropfiles = GlobalLock(data)))
1092 WARN("failed to lock data %p\n", data);
1093 goto done;
1096 filenames = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1097 if (!filenames)
1099 WARN("failed to create filenames array\n");
1100 goto done;
1103 p = (char*)dropfiles + dropfiles->pFiles;
1104 while (dropfiles->fWide ? *(WCHAR*)p : *(char*)p)
1106 char *unixname;
1107 CFStringRef filename;
1109 TRACE(" %s\n", dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1111 if (dropfiles->fWide)
1112 unixname = wine_get_unix_file_name(p);
1113 else
1115 int len = MultiByteToWideChar(CP_ACP, 0, p, -1, NULL, 0);
1116 if (len)
1118 if (len > buffer_len)
1120 HeapFree(GetProcessHeap(), 0, buffer);
1121 buffer_len = len * 2;
1122 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_len * sizeof(*buffer));
1125 MultiByteToWideChar(CP_ACP, 0, p, -1, buffer, buffer_len);
1126 unixname = wine_get_unix_file_name(buffer);
1128 else
1129 unixname = NULL;
1131 if (!unixname)
1133 WARN("failed to convert DOS path to Unix: %s\n",
1134 dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
1135 goto done;
1138 if (dropfiles->fWide)
1139 p = (WCHAR*)p + strlenW(p) + 1;
1140 else
1141 p = (char*)p + strlen(p) + 1;
1143 filename = CFStringCreateWithFileSystemRepresentation(NULL, unixname);
1144 HeapFree(GetProcessHeap(), 0, unixname);
1145 if (!filename)
1147 WARN("failed to create CFString from Unix path %s\n", debugstr_a(unixname));
1148 goto done;
1151 CFArrayAppendValue(filenames, filename);
1152 CFRelease(filename);
1155 ret = CFPropertyListCreateData(NULL, filenames, kCFPropertyListXMLFormat_v1_0, 0, NULL);
1157 done:
1158 HeapFree(GetProcessHeap(), 0, buffer);
1159 GlobalUnlock(data);
1160 if (filenames) CFRelease(filenames);
1161 TRACE(" -> %s\n", debugstr_cf(ret));
1162 return ret;
1166 /**************************************************************************
1167 * export_html
1169 * Export HTML Format to public.html data.
1171 * FIXME: We should attempt to add an <a base> tag and convert windows paths.
1173 static CFDataRef export_html(HANDLE handle)
1175 CFDataRef ret;
1176 const char *data, *field_value;
1177 int fragmentstart, fragmentend;
1179 data = GlobalLock(handle);
1181 /* read the important fields */
1182 field_value = get_html_description_field(data, "StartFragment:");
1183 if (!field_value)
1185 ERR("Couldn't find StartFragment value\n");
1186 goto failed;
1188 fragmentstart = atoi(field_value);
1190 field_value = get_html_description_field(data, "EndFragment:");
1191 if (!field_value)
1193 ERR("Couldn't find EndFragment value\n");
1194 goto failed;
1196 fragmentend = atoi(field_value);
1198 /* export only the fragment */
1199 ret = CFDataCreate(NULL, (const UInt8*)&data[fragmentstart], fragmentend - fragmentstart);
1200 GlobalUnlock(handle);
1201 return ret;
1203 failed:
1204 GlobalUnlock(handle);
1205 return NULL;
1209 /**************************************************************************
1210 * export_metafilepict
1212 * Export a metafile to data.
1214 static CFDataRef export_metafilepict(HANDLE data)
1216 CFMutableDataRef ret = NULL;
1217 METAFILEPICT *mfp = GlobalLock(data);
1218 unsigned int size = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
1220 TRACE("data %p\n", data);
1222 ret = CFDataCreateMutable(NULL, sizeof(*mfp) + size);
1223 if (ret)
1225 CFDataAppendBytes(ret, (UInt8*)mfp, sizeof(*mfp));
1226 CFDataIncreaseLength(ret, size);
1227 GetMetaFileBitsEx(mfp->hMF, size, (BYTE*)CFDataGetMutableBytePtr(ret) + sizeof(*mfp));
1230 GlobalUnlock(data);
1231 TRACE(" -> %s\n", debugstr_cf(ret));
1232 return ret;
1236 /**************************************************************************
1237 * export_text_to_utf8
1239 * Export CF_TEXT to UTF-8.
1241 static CFDataRef export_text_to_utf8(HANDLE data)
1243 CFDataRef ret = NULL;
1244 const char* str;
1246 if ((str = GlobalLock(data)))
1248 int str_len = GlobalSize(data);
1249 int wstr_len;
1250 WCHAR *wstr;
1251 HANDLE unicode;
1252 char *p;
1254 wstr_len = MultiByteToWideChar(CP_ACP, 0, str, str_len, NULL, 0);
1255 if (!str_len || str[str_len - 1]) wstr_len += 1;
1256 wstr = HeapAlloc(GetProcessHeap(), 0, wstr_len * sizeof(WCHAR));
1257 MultiByteToWideChar(CP_ACP, 0, str, str_len, wstr, wstr_len);
1258 wstr[wstr_len - 1] = 0;
1260 unicode = GlobalAlloc(GMEM_FIXED, wstr_len * sizeof(WCHAR));
1261 if (unicode && (p = GlobalLock(unicode)))
1263 memcpy(p, wstr, wstr_len * sizeof(WCHAR));
1264 GlobalUnlock(unicode);
1267 ret = export_unicodetext_to_utf8(unicode);
1269 GlobalFree(unicode);
1270 GlobalUnlock(data);
1273 return ret;
1277 /**************************************************************************
1278 * export_unicodetext_to_utf8
1280 * Export CF_UNICODETEXT to UTF-8.
1282 static CFDataRef export_unicodetext_to_utf8(HANDLE data)
1284 CFMutableDataRef ret;
1285 LPVOID src;
1286 INT dst_len;
1288 src = GlobalLock(data);
1289 if (!src) return NULL;
1291 dst_len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
1292 if (dst_len) dst_len--; /* Leave off null terminator. */
1293 ret = CFDataCreateMutable(NULL, dst_len);
1294 if (ret)
1296 LPSTR dst;
1297 int i, j;
1299 CFDataSetLength(ret, dst_len);
1300 dst = (LPSTR)CFDataGetMutableBytePtr(ret);
1301 WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_len, NULL, NULL);
1303 /* Remove carriage returns */
1304 for (i = 0, j = 0; i < dst_len; i++)
1306 if (dst[i] == '\r' &&
1307 (i + 1 >= dst_len || dst[i + 1] == '\n' || dst[i + 1] == '\0'))
1308 continue;
1309 dst[j++] = dst[i];
1311 CFDataSetLength(ret, j);
1313 GlobalUnlock(data);
1315 return ret;
1319 /**************************************************************************
1320 * export_unicodetext_to_utf16
1322 * Export CF_UNICODETEXT to UTF-16.
1324 static CFDataRef export_unicodetext_to_utf16(HANDLE data)
1326 CFMutableDataRef ret;
1327 const WCHAR *src;
1328 INT src_len;
1330 src = GlobalLock(data);
1331 if (!src) return NULL;
1333 src_len = GlobalSize(data) / sizeof(WCHAR);
1334 if (src_len) src_len--; /* Leave off null terminator. */
1335 ret = CFDataCreateMutable(NULL, src_len * sizeof(WCHAR));
1336 if (ret)
1338 LPWSTR dst;
1339 int i, j;
1341 CFDataSetLength(ret, src_len * sizeof(WCHAR));
1342 dst = (LPWSTR)CFDataGetMutableBytePtr(ret);
1344 /* Remove carriage returns */
1345 for (i = 0, j = 0; i < src_len; i++)
1347 if (src[i] == '\r' &&
1348 (i + 1 >= src_len || src[i + 1] == '\n' || src[i + 1] == '\0'))
1349 continue;
1350 dst[j++] = src[i];
1352 CFDataSetLength(ret, j * sizeof(WCHAR));
1354 GlobalUnlock(data);
1356 return ret;
1360 /**************************************************************************
1361 * macdrv_get_pasteboard_data
1363 HANDLE macdrv_get_pasteboard_data(CFTypeRef pasteboard, UINT desired_format)
1365 CFArrayRef types;
1366 CFIndex count;
1367 CFIndex i;
1368 CFStringRef type, best_type;
1369 WINE_CLIPFORMAT* best_format = NULL;
1370 HANDLE data = NULL;
1372 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1374 types = macdrv_copy_pasteboard_types(pasteboard);
1375 if (!types)
1377 WARN("Failed to copy pasteboard types\n");
1378 return NULL;
1381 count = CFArrayGetCount(types);
1382 TRACE("got %ld types\n", count);
1384 for (i = 0; (!best_format || best_format->synthesized) && i < count; i++)
1386 WINE_CLIPFORMAT* format;
1388 type = CFArrayGetValueAtIndex(types, i);
1390 if ((format = format_for_type(type)))
1392 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1394 if (format->format_id == desired_format)
1396 /* The best format is the matching one which is not synthesized. Failing that,
1397 the best format is the first matching synthesized format. */
1398 if (!format->synthesized || !best_format)
1400 best_type = type;
1401 best_format = format;
1407 if (best_format)
1409 CFDataRef pasteboard_data = macdrv_copy_pasteboard_data(pasteboard, best_type);
1411 TRACE("got pasteboard data for type %s: %s\n", debugstr_cf(best_type), debugstr_cf(pasteboard_data));
1413 if (pasteboard_data)
1415 data = best_format->import_func(pasteboard_data);
1416 CFRelease(pasteboard_data);
1420 CFRelease(types);
1421 TRACE(" -> %p\n", data);
1422 return data;
1426 /**************************************************************************
1427 * macdrv_pasteboard_has_format
1429 BOOL macdrv_pasteboard_has_format(CFTypeRef pasteboard, UINT desired_format)
1431 CFArrayRef types;
1432 int count;
1433 UINT i;
1434 BOOL found = FALSE;
1436 TRACE("pasteboard %p, desired_format %s\n", pasteboard, debugstr_format(desired_format));
1438 types = macdrv_copy_pasteboard_types(pasteboard);
1439 if (!types)
1441 WARN("Failed to copy pasteboard types\n");
1442 return FALSE;
1445 count = CFArrayGetCount(types);
1446 TRACE("got %d types\n", count);
1448 for (i = 0; i < count; i++)
1450 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1451 WINE_CLIPFORMAT* format = format_for_type(type);
1453 if (format)
1455 TRACE("for type %s got format %s\n", debugstr_cf(type), debugstr_format(format->format_id));
1457 if (format->format_id == desired_format)
1459 found = TRUE;
1460 break;
1465 CFRelease(types);
1466 TRACE(" -> %d\n", found);
1467 return found;
1471 /**************************************************************************
1472 * get_formats_for_pasteboard_types
1474 static WINE_CLIPFORMAT** get_formats_for_pasteboard_types(CFArrayRef types, UINT *num_formats)
1476 CFIndex count, i;
1477 CFMutableSetRef seen_formats;
1478 WINE_CLIPFORMAT** formats;
1479 UINT pos;
1481 count = CFArrayGetCount(types);
1482 TRACE("got %ld types\n", count);
1484 if (!count)
1485 return NULL;
1487 seen_formats = CFSetCreateMutable(NULL, count, NULL);
1488 if (!seen_formats)
1490 WARN("Failed to allocate seen formats set\n");
1491 return NULL;
1494 formats = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*formats));
1495 if (!formats)
1497 WARN("Failed to allocate formats array\n");
1498 CFRelease(seen_formats);
1499 return NULL;
1502 pos = 0;
1503 for (i = 0; i < count; i++)
1505 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1506 WINE_CLIPFORMAT* format = format_for_type(type);
1508 if (!format)
1510 TRACE("ignoring type %s\n", debugstr_cf(type));
1511 continue;
1514 if (!format->synthesized)
1516 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1517 CFSetAddValue(seen_formats, (void*)format->format_id);
1518 formats[pos++] = format;
1520 else if (format->natural_format &&
1521 CFArrayContainsValue(types, CFRangeMake(0, count), format->natural_format->type))
1523 TRACE("for type %s deferring synthesized formats because type %s is also present\n",
1524 debugstr_cf(type), debugstr_cf(format->natural_format->type));
1526 else if (CFSetContainsValue(seen_formats, (void*)format->format_id))
1528 TRACE("for type %s got duplicate synthesized format %p/%s; skipping\n", debugstr_cf(type), format,
1529 debugstr_format(format->format_id));
1531 else
1533 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1534 CFSetAddValue(seen_formats, (void*)format->format_id);
1535 formats[pos++] = format;
1539 /* Now go back through the types adding the synthesized formats that we deferred before. */
1540 for (i = 0; i < count; i++)
1542 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1543 WINE_CLIPFORMAT* format = format_for_type(type);
1545 if (!format) continue;
1546 if (!format->synthesized) continue;
1548 /* Don't duplicate a real value with a synthesized value. */
1549 if (CFSetContainsValue(seen_formats, (void*)format->format_id)) continue;
1551 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1552 CFSetAddValue(seen_formats, (void*)format->format_id);
1553 formats[pos++] = format;
1556 CFRelease(seen_formats);
1558 if (!pos)
1560 HeapFree(GetProcessHeap(), 0, formats);
1561 formats = NULL;
1564 *num_formats = pos;
1565 return formats;
1569 /**************************************************************************
1570 * get_formats_for_pasteboard
1572 static WINE_CLIPFORMAT** get_formats_for_pasteboard(CFTypeRef pasteboard, UINT *num_formats)
1574 CFArrayRef types;
1575 WINE_CLIPFORMAT** formats;
1577 TRACE("pasteboard %s\n", debugstr_cf(pasteboard));
1579 types = macdrv_copy_pasteboard_types(pasteboard);
1580 if (!types)
1582 WARN("Failed to copy pasteboard types\n");
1583 return NULL;
1586 formats = get_formats_for_pasteboard_types(types, num_formats);
1587 CFRelease(types);
1588 return formats;
1592 /**************************************************************************
1593 * macdrv_get_pasteboard_formats
1595 UINT* macdrv_get_pasteboard_formats(CFTypeRef pasteboard, UINT* num_formats)
1597 WINE_CLIPFORMAT** formats;
1598 UINT count, i;
1599 UINT* format_ids;
1601 formats = get_formats_for_pasteboard(pasteboard, &count);
1602 if (!formats)
1603 return NULL;
1605 format_ids = HeapAlloc(GetProcessHeap(), 0, count);
1606 if (!format_ids)
1608 WARN("Failed to allocate formats IDs array\n");
1609 HeapFree(GetProcessHeap(), 0, formats);
1610 return NULL;
1613 for (i = 0; i < count; i++)
1614 format_ids[i] = formats[i]->format_id;
1616 HeapFree(GetProcessHeap(), 0, formats);
1618 *num_formats = count;
1619 return format_ids;
1623 /**************************************************************************
1624 * register_win32_formats
1626 * Register Win32 clipboard formats the first time we encounter them.
1628 static void register_win32_formats(const UINT *ids, UINT size)
1630 unsigned int i;
1632 if (list_empty(&format_list)) register_builtin_formats();
1634 for (i = 0; i < size; i++)
1635 register_format(ids[i], NULL);
1639 /***********************************************************************
1640 * get_clipboard_formats
1642 * Return a list of all formats currently available on the Win32 clipboard.
1643 * Helper for set_mac_pasteboard_types_from_win32_clipboard.
1645 static UINT *get_clipboard_formats(UINT *size)
1647 UINT *ids;
1649 *size = 256;
1650 for (;;)
1652 if (!(ids = HeapAlloc(GetProcessHeap(), 0, *size * sizeof(*ids)))) return NULL;
1653 if (GetUpdatedClipboardFormats(ids, *size, size)) break;
1654 HeapFree(GetProcessHeap(), 0, ids);
1655 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return NULL;
1657 register_win32_formats(ids, *size);
1658 return ids;
1662 /**************************************************************************
1663 * set_mac_pasteboard_types_from_win32_clipboard
1665 static void set_mac_pasteboard_types_from_win32_clipboard(void)
1667 WINE_CLIPFORMAT *format;
1668 UINT count, i, *formats;
1670 if (!(formats = get_clipboard_formats(&count))) return;
1672 macdrv_clear_pasteboard(clipboard_cocoa_window);
1674 for (i = 0; i < count; i++)
1676 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1678 if (format->format_id != formats[i]) continue;
1679 TRACE("%s -> %s\n", debugstr_format(format->format_id), debugstr_cf(format->type));
1680 macdrv_set_pasteboard_data(format->type, NULL, clipboard_cocoa_window);
1684 HeapFree(GetProcessHeap(), 0, formats);
1685 return;
1689 /**************************************************************************
1690 * set_win32_clipboard_formats_from_mac_pasteboard
1692 static void set_win32_clipboard_formats_from_mac_pasteboard(CFArrayRef types)
1694 WINE_CLIPFORMAT** formats;
1695 UINT count, i;
1697 formats = get_formats_for_pasteboard_types(types, &count);
1698 if (!formats)
1699 return;
1701 for (i = 0; i < count; i++)
1703 TRACE("adding format %s\n", debugstr_format(formats[i]->format_id));
1704 SetClipboardData(formats[i]->format_id, 0);
1707 HeapFree(GetProcessHeap(), 0, current_mac_formats);
1708 current_mac_formats = formats;
1709 nb_current_mac_formats = count;
1713 /**************************************************************************
1714 * render_format
1716 static void render_format(UINT id)
1718 unsigned int i;
1720 for (i = 0; i < nb_current_mac_formats; i++)
1722 CFDataRef pasteboard_data;
1724 if (current_mac_formats[i]->format_id != id) continue;
1726 pasteboard_data = macdrv_copy_pasteboard_data(NULL, current_mac_formats[i]->type);
1727 if (pasteboard_data)
1729 HANDLE handle = current_mac_formats[i]->import_func(pasteboard_data);
1730 CFRelease(pasteboard_data);
1731 if (handle) SetClipboardData(id, handle);
1732 break;
1738 /**************************************************************************
1739 * grab_win32_clipboard
1741 * Grab the Win32 clipboard when a Mac app has taken ownership of the
1742 * pasteboard, and fill it with the pasteboard data types.
1744 static void grab_win32_clipboard(void)
1746 static CFArrayRef last_types;
1747 CFArrayRef types;
1749 types = macdrv_copy_pasteboard_types(NULL);
1750 if (!types)
1752 WARN("Failed to copy pasteboard types\n");
1753 return;
1756 if (!macdrv_has_pasteboard_changed() && last_types && CFEqual(types, last_types))
1758 CFRelease(types);
1759 return;
1762 if (last_types) CFRelease(last_types);
1763 last_types = types; /* takes ownership */
1765 if (!OpenClipboard(clipboard_hwnd)) return;
1766 EmptyClipboard();
1767 is_clipboard_owner = TRUE;
1768 last_clipboard_update = GetTickCount64();
1769 set_win32_clipboard_formats_from_mac_pasteboard(types);
1770 CloseClipboard();
1771 SetTimer(clipboard_hwnd, 1, CLIPBOARD_UPDATE_DELAY, NULL);
1775 /**************************************************************************
1776 * update_clipboard
1778 * Periodically update the clipboard while the clipboard is owned by a
1779 * Mac app.
1781 static void update_clipboard(void)
1783 static BOOL updating;
1785 TRACE("is_clipboard_owner %d last_clipboard_update %llu now %llu\n",
1786 is_clipboard_owner, last_clipboard_update, GetTickCount64());
1788 if (updating) return;
1789 updating = TRUE;
1791 if (is_clipboard_owner)
1793 if (GetTickCount64() - last_clipboard_update > CLIPBOARD_UPDATE_DELAY)
1794 grab_win32_clipboard();
1796 else if (!macdrv_is_pasteboard_owner(clipboard_cocoa_window))
1797 grab_win32_clipboard();
1799 updating = FALSE;
1803 /**************************************************************************
1804 * clipboard_wndproc
1806 * Window procedure for the clipboard manager.
1808 static LRESULT CALLBACK clipboard_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1810 switch (msg)
1812 case WM_NCCREATE:
1813 return TRUE;
1814 case WM_CLIPBOARDUPDATE:
1815 if (is_clipboard_owner) break; /* ignore our own changes */
1816 if ((LONG)(GetClipboardSequenceNumber() - last_get_seqno) <= 0) break;
1817 set_mac_pasteboard_types_from_win32_clipboard();
1818 break;
1819 case WM_RENDERFORMAT:
1820 render_format(wp);
1821 break;
1822 case WM_TIMER:
1823 if (!is_clipboard_owner) break;
1824 grab_win32_clipboard();
1825 break;
1826 case WM_DESTROYCLIPBOARD:
1827 TRACE("WM_DESTROYCLIPBOARD: lost ownership\n");
1828 is_clipboard_owner = FALSE;
1829 KillTimer(hwnd, 1);
1830 break;
1832 return DefWindowProcW(hwnd, msg, wp, lp);
1836 /**************************************************************************
1837 * wait_clipboard_mutex
1839 * Make sure that there's only one clipboard thread per window station.
1841 static BOOL wait_clipboard_mutex(void)
1843 static const WCHAR prefix[] = {'_','_','w','i','n','e','_','c','l','i','p','b','o','a','r','d','_'};
1844 WCHAR buffer[MAX_PATH + sizeof(prefix) / sizeof(WCHAR)];
1845 HANDLE mutex;
1847 memcpy(buffer, prefix, sizeof(prefix));
1848 if (!GetUserObjectInformationW(GetProcessWindowStation(), UOI_NAME,
1849 buffer + sizeof(prefix) / sizeof(WCHAR),
1850 sizeof(buffer) - sizeof(prefix), NULL))
1852 ERR("failed to get winstation name\n");
1853 return FALSE;
1855 mutex = CreateMutexW(NULL, TRUE, buffer);
1856 if (GetLastError() == ERROR_ALREADY_EXISTS)
1858 TRACE("waiting for mutex %s\n", debugstr_w(buffer));
1859 WaitForSingleObject(mutex, INFINITE);
1861 return TRUE;
1865 /**************************************************************************
1866 * init_pipe_name
1868 * Init-once helper for get_pipe_name.
1870 static BOOL CALLBACK init_pipe_name(INIT_ONCE* once, void* param, void** context)
1872 static const WCHAR prefix[] = {'\\','\\','.','\\','p','i','p','e','\\','_','_','w','i','n','e','_','c','l','i','p','b','o','a','r','d','_'};
1874 memcpy(clipboard_pipe_name, prefix, sizeof(prefix));
1875 if (!GetUserObjectInformationW(GetProcessWindowStation(), UOI_NAME,
1876 clipboard_pipe_name + sizeof(prefix) / sizeof(WCHAR),
1877 sizeof(clipboard_pipe_name) - sizeof(prefix), NULL))
1879 ERR("failed to get winstation name\n");
1880 return FALSE;
1883 return TRUE;
1887 /**************************************************************************
1888 * get_pipe_name
1890 * Get the name of the pipe used to communicate with the per-window-station
1891 * clipboard manager thread.
1893 static const WCHAR* get_pipe_name(void)
1895 static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
1896 InitOnceExecuteOnce(&once, init_pipe_name, NULL, NULL);
1897 return clipboard_pipe_name[0] ? clipboard_pipe_name : NULL;
1901 /**************************************************************************
1902 * clipboard_thread
1904 * Thread running inside the desktop process to manage the clipboard
1906 static DWORD WINAPI clipboard_thread(void *arg)
1908 static const WCHAR clipboard_classname[] = {'_','_','w','i','n','e','_','c','l','i','p','b','o','a','r','d','_','m','a','n','a','g','e','r',0};
1909 WNDCLASSW class;
1910 struct macdrv_window_features wf;
1911 const WCHAR* pipe_name;
1912 HANDLE pipe = NULL;
1913 HANDLE event = NULL;
1914 OVERLAPPED overlapped;
1915 BOOL need_connect = TRUE, pending = FALSE;
1916 MSG msg;
1918 if (!wait_clipboard_mutex()) return 0;
1920 memset(&class, 0, sizeof(class));
1921 class.lpfnWndProc = clipboard_wndproc;
1922 class.lpszClassName = clipboard_classname;
1924 if (!RegisterClassW(&class) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
1926 ERR("could not register clipboard window class err %u\n", GetLastError());
1927 return 0;
1929 if (!(clipboard_hwnd = CreateWindowW(clipboard_classname, NULL, 0, 0, 0, 0, 0,
1930 HWND_MESSAGE, 0, 0, NULL)))
1932 ERR("failed to create clipboard window err %u\n", GetLastError());
1933 return 0;
1936 memset(&wf, 0, sizeof(wf));
1937 clipboard_cocoa_window = macdrv_create_cocoa_window(&wf, CGRectMake(100, 100, 100, 100), clipboard_hwnd,
1938 macdrv_init_thread_data()->queue);
1939 if (!clipboard_cocoa_window)
1941 ERR("failed to create clipboard Cocoa window\n");
1942 goto done;
1945 pipe_name = get_pipe_name();
1946 if (!pipe_name)
1948 ERR("failed to get pipe name\n");
1949 goto done;
1952 pipe = CreateNamedPipeW(pipe_name, PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
1953 PIPE_TYPE_BYTE, PIPE_UNLIMITED_INSTANCES, 1, 1, 0, NULL);
1954 if (!pipe)
1956 ERR("failed to create named pipe: %u\n", GetLastError());
1957 goto done;
1960 event = CreateEventW(NULL, TRUE, FALSE, NULL);
1961 if (!event)
1963 ERR("failed to create event: %d\n", GetLastError());
1964 goto done;
1967 clipboard_thread_id = GetCurrentThreadId();
1968 AddClipboardFormatListener(clipboard_hwnd);
1969 register_builtin_formats();
1970 grab_win32_clipboard();
1972 TRACE("clipboard thread %04x running\n", GetCurrentThreadId());
1973 while (1)
1975 DWORD result;
1977 if (need_connect)
1979 pending = FALSE;
1980 memset(&overlapped, 0, sizeof(overlapped));
1981 overlapped.hEvent = event;
1982 if (ConnectNamedPipe(pipe, &overlapped))
1984 ERR("asynchronous ConnectNamedPipe unexpectedly returned true: %d\n", GetLastError());
1985 ResetEvent(event);
1987 else
1989 result = GetLastError();
1990 switch (result)
1992 case ERROR_PIPE_CONNECTED:
1993 case ERROR_NO_DATA:
1994 SetEvent(event);
1995 need_connect = FALSE;
1996 break;
1997 case ERROR_IO_PENDING:
1998 need_connect = FALSE;
1999 pending = TRUE;
2000 break;
2001 default:
2002 ERR("failed to initiate pipe connection: %d\n", result);
2003 break;
2008 result = MsgWaitForMultipleObjectsEx(1, &event, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
2009 switch (result)
2011 case WAIT_OBJECT_0:
2013 DWORD written;
2015 if (pending && !GetOverlappedResult(pipe, &overlapped, &written, FALSE))
2016 ERR("failed to connect pipe: %d\n", GetLastError());
2018 update_clipboard();
2019 DisconnectNamedPipe(pipe);
2020 need_connect = TRUE;
2021 break;
2023 case WAIT_OBJECT_0 + 1:
2024 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
2026 if (msg.message == WM_QUIT)
2027 goto done;
2028 DispatchMessageW(&msg);
2030 break;
2031 case WAIT_IO_COMPLETION:
2032 break;
2033 default:
2034 ERR("failed to wait for connection or input: %d\n", GetLastError());
2035 break;
2039 done:
2040 if (event) CloseHandle(event);
2041 if (pipe) CloseHandle(pipe);
2042 macdrv_destroy_cocoa_window(clipboard_cocoa_window);
2043 DestroyWindow(clipboard_hwnd);
2044 return 0;
2048 /**************************************************************************
2049 * Mac User Driver Clipboard Exports
2050 **************************************************************************/
2053 /**************************************************************************
2054 * macdrv_UpdateClipboard
2056 void CDECL macdrv_UpdateClipboard(void)
2058 static ULONG last_update;
2059 ULONG now, end;
2060 const WCHAR* pipe_name;
2061 HANDLE pipe;
2062 BYTE dummy;
2063 DWORD count;
2064 OVERLAPPED overlapped = { 0 };
2065 BOOL canceled = FALSE;
2067 if (GetCurrentThreadId() == clipboard_thread_id) return;
2069 TRACE("\n");
2071 now = GetTickCount();
2072 if ((int)(now - last_update) <= CLIPBOARD_UPDATE_DELAY) return;
2073 last_update = now;
2075 if (!(pipe_name = get_pipe_name())) return;
2076 pipe = CreateFileW(pipe_name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
2077 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
2078 if (pipe == INVALID_HANDLE_VALUE)
2080 WARN("failed to open pipe to clipboard manager: %d\n", GetLastError());
2081 return;
2084 overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
2085 if (!overlapped.hEvent)
2087 ERR("failed to create event: %d\n", GetLastError());
2088 goto done;
2091 /* We expect the read to fail because the server just closes our connection. This
2092 is just waiting for that close to happen. */
2093 if (ReadFile(pipe, &dummy, sizeof(dummy), NULL, &overlapped))
2095 WARN("asynchronous ReadFile unexpectedly returned true: %d\n", GetLastError());
2096 goto done;
2098 else
2100 DWORD error = GetLastError();
2101 if (error == ERROR_PIPE_NOT_CONNECTED || error == ERROR_BROKEN_PIPE)
2103 /* The server accepted, handled, and closed our connection before we
2104 attempted the read, which is fine. */
2105 goto done;
2107 else if (error != ERROR_IO_PENDING)
2109 ERR("failed to initiate read from pipe: %d\n", error);
2110 goto done;
2114 end = now + 500;
2115 while (1)
2117 DWORD result, timeout;
2119 if (canceled)
2120 timeout = INFINITE;
2121 else
2123 now = GetTickCount();
2124 timeout = end - now;
2125 if ((int)timeout < 0)
2126 timeout = 0;
2129 result = MsgWaitForMultipleObjectsEx(1, &overlapped.hEvent, timeout, QS_SENDMESSAGE, MWMO_ALERTABLE);
2130 switch (result)
2132 case WAIT_OBJECT_0:
2134 if (GetOverlappedResult(pipe, &overlapped, &count, FALSE))
2135 WARN("unexpectedly succeeded in reading from pipe\n");
2136 else
2138 result = GetLastError();
2139 if (result != ERROR_BROKEN_PIPE && result != ERROR_OPERATION_ABORTED &&
2140 result != ERROR_HANDLES_CLOSED)
2141 WARN("failed to read from pipe: %d\n", result);
2144 goto done;
2146 case WAIT_OBJECT_0 + 1:
2148 MSG msg;
2149 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE))
2150 DispatchMessageW(&msg);
2151 break;
2153 case WAIT_IO_COMPLETION:
2154 break;
2155 case WAIT_TIMEOUT:
2156 WARN("timed out waiting for read\n");
2157 CancelIoEx(pipe, &overlapped);
2158 canceled = TRUE;
2159 break;
2160 default:
2161 if (canceled)
2163 ERR("failed to wait for cancel: %d\n", GetLastError());
2164 goto done;
2167 ERR("failed to wait for read: %d\n", GetLastError());
2168 CancelIoEx(pipe, &overlapped);
2169 canceled = TRUE;
2170 break;
2174 done:
2175 if (overlapped.hEvent) CloseHandle(overlapped.hEvent);
2176 CloseHandle(pipe);
2180 /**************************************************************************
2181 * MACDRV Private Clipboard Exports
2182 **************************************************************************/
2185 /**************************************************************************
2186 * query_pasteboard_data
2188 BOOL query_pasteboard_data(HWND hwnd, CFStringRef type)
2190 WINE_CLIPFORMAT *format;
2191 BOOL ret = FALSE;
2192 HANDLE handle;
2194 TRACE("win %p/%p type %s\n", hwnd, clipboard_cocoa_window, debugstr_cf(type));
2196 format = format_for_type(type);
2197 if (!format) return FALSE;
2199 if (!OpenClipboard(clipboard_hwnd))
2201 ERR("failed to open clipboard for %s\n", debugstr_cf(type));
2202 return FALSE;
2205 if ((handle = GetClipboardData(format->format_id)))
2207 CFDataRef data;
2209 TRACE("exporting %s %p\n", debugstr_format(format->format_id), handle);
2211 if ((data = format->export_func(handle)))
2213 ret = macdrv_set_pasteboard_data(format->type, data, clipboard_cocoa_window);
2214 CFRelease(data);
2218 last_get_seqno = GetClipboardSequenceNumber();
2220 CloseClipboard();
2222 return ret;
2226 /**************************************************************************
2227 * macdrv_lost_pasteboard_ownership
2229 * Handler for the LOST_PASTEBOARD_OWNERSHIP event.
2231 void macdrv_lost_pasteboard_ownership(HWND hwnd)
2233 TRACE("win %p\n", hwnd);
2234 if (!macdrv_is_pasteboard_owner(clipboard_cocoa_window))
2235 grab_win32_clipboard();
2239 /**************************************************************************
2240 * macdrv_init_clipboard
2242 void macdrv_init_clipboard(void)
2244 DWORD id;
2245 HANDLE handle = CreateThread(NULL, 0, clipboard_thread, NULL, 0, &id);
2247 if (handle) CloseHandle(handle);
2248 else ERR("failed to create clipboard thread\n");