4 * Copyright 1994 Martin Ayotte
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
29 #include "wine/list.h"
30 #include "wine/server.h"
31 #include "wine/unicode.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
37 /**************************************************************************
39 **************************************************************************/
45 } CLIPBOARDINFO, *LPCLIPBOARDINFO;
47 typedef HANDLE (*DRVIMPORTFUNC)(CFDataRef data);
48 typedef CFDataRef (*DRVEXPORTFUNC)(HANDLE data);
55 DRVIMPORTFUNC import_func;
56 DRVEXPORTFUNC export_func;
61 /**************************************************************************
63 **************************************************************************/
66 /**************************************************************************
67 * Forward Function Declarations
68 **************************************************************************/
70 static HANDLE import_clipboard_data(CFDataRef data);
71 static HANDLE import_oemtext_to_text(CFDataRef data);
72 static HANDLE import_oemtext_to_unicodetext(CFDataRef data);
73 static HANDLE import_text_to_oemtext(CFDataRef data);
74 static HANDLE import_text_to_unicodetext(CFDataRef data);
75 static HANDLE import_unicodetext_to_oemtext(CFDataRef data);
76 static HANDLE import_unicodetext_to_text(CFDataRef data);
77 static HANDLE import_utf8_to_oemtext(CFDataRef data);
78 static HANDLE import_utf8_to_text(CFDataRef data);
79 static HANDLE import_utf8_to_unicodetext(CFDataRef data);
81 static CFDataRef export_clipboard_data(HANDLE data);
82 static CFDataRef export_oemtext_to_utf8(HANDLE data);
83 static CFDataRef export_text_to_utf8(HANDLE data);
84 static CFDataRef export_unicodetext_to_utf8(HANDLE data);
87 /**************************************************************************
89 **************************************************************************/
91 /* Clipboard formats */
92 static struct list format_list = LIST_INIT(format_list);
94 /* There are two naming schemes involved and we want to have a mapping between
95 them. There are Win32 clipboard format names and there are Mac pasteboard
98 The Win32 standard clipboard formats don't have names, but they are associated
99 with Mac pasteboard types through the following tables, which are used to
100 initialize the format_list. Where possible, the standard clipboard formats
101 are mapped to predefined pasteboard type UTIs. Otherwise, we create Wine-
102 specific types of the form "org.winehq.builtin.<format>", where <format> is
103 the name of the symbolic constant for the format minus "CF_" and lowercased.
104 E.g. CF_BITMAP -> org.winehq.builtin.bitmap.
106 Win32 clipboard formats which originate in a Windows program may be registered
107 with an arbitrary name. We construct a Mac pasteboard type from these by
108 prepending "org.winehq.registered." to the registered name.
110 Likewise, Mac pasteboard types which originate in other apps may have
111 arbitrary type strings. We construct a Win32 clipboard format name from
112 these by prepending "org.winehq.mac-type." to the Mac pasteboard type.
115 Win32 clipboard format names:
116 <none> standard clipboard format; maps via
117 format_list to either a predefined Mac UTI
118 or org.winehq.builtin.<format>.
119 org.winehq.mac-type.<Mac type> representation of Mac type in Win32 land;
121 <other> name registered within Win32 land; maps to
122 org.winehq.registered.<other>
123 Mac pasteboard type names:
124 org.winehq.builtin.<format ID> representation of Win32 standard clipboard
125 format for which there was no corresponding
126 predefined Mac UTI; maps via format_list
127 org.winehq.registered.<format name> representation of Win32 registered
128 clipboard format name; maps to <format name>
129 <other> Mac pasteboard type originating with system
130 or other apps; either maps via format_list
131 to a standard clipboard format or maps to
132 org.winehq.mac-type.<other>
139 DRVIMPORTFUNC import;
140 DRVEXPORTFUNC export;
142 } builtin_format_ids[] =
144 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.unicodetext"), import_clipboard_data, export_clipboard_data, FALSE },
145 { CF_TEXT, CFSTR("org.winehq.builtin.unicodetext"), import_unicodetext_to_text, NULL, TRUE },
146 { CF_OEMTEXT, CFSTR("org.winehq.builtin.unicodetext"), import_unicodetext_to_oemtext, NULL, TRUE },
148 { CF_TEXT, CFSTR("org.winehq.builtin.text"), import_clipboard_data, export_clipboard_data, FALSE },
149 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.text"), import_text_to_unicodetext, NULL, TRUE },
150 { CF_OEMTEXT, CFSTR("org.winehq.builtin.text"), import_text_to_oemtext, NULL, TRUE },
152 { CF_OEMTEXT, CFSTR("org.winehq.builtin.oemtext"), import_clipboard_data, export_clipboard_data, FALSE },
153 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.oemtext"), import_oemtext_to_unicodetext, NULL, TRUE },
154 { CF_TEXT, CFSTR("org.winehq.builtin.oemtext"), import_oemtext_to_text, NULL, TRUE },
156 { CF_UNICODETEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_unicodetext, export_unicodetext_to_utf8, TRUE },
157 { CF_TEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_text, export_text_to_utf8, TRUE },
158 { CF_OEMTEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_oemtext, export_oemtext_to_utf8, TRUE },
161 /* The prefix prepended to an external Mac pasteboard type to make a Win32 clipboard format name. org.winehq.mac-type. */
162 static const WCHAR mac_type_name_prefix[] = {'o','r','g','.','w','i','n','e','h','q','.','m','a','c','-','t','y','p','e','.',0};
164 /* The prefix prepended to a Win32 clipboard format name to make a Mac pasteboard type. */
165 static const CFStringRef registered_name_type_prefix = CFSTR("org.winehq.registered.");
168 /**************************************************************************
169 * Internal Clipboard implementation methods
170 **************************************************************************/
173 * format_list functions
176 /**************************************************************************
179 static const char *debugstr_format(UINT id)
183 if (GetClipboardFormatNameW(id, buffer, 256))
184 return wine_dbg_sprintf("0x%04x %s", id, debugstr_w(buffer));
188 #define BUILTIN(id) case id: return #id;
191 BUILTIN(CF_METAFILEPICT)
201 BUILTIN(CF_UNICODETEXT)
202 BUILTIN(CF_ENHMETAFILE)
206 BUILTIN(CF_OWNERDISPLAY)
208 BUILTIN(CF_DSPBITMAP)
209 BUILTIN(CF_DSPMETAFILEPICT)
210 BUILTIN(CF_DSPENHMETAFILE)
212 default: return wine_dbg_sprintf("0x%04x", id);
217 /**************************************************************************
218 * insert_clipboard_format
220 static WINE_CLIPFORMAT *insert_clipboard_format(UINT id, CFStringRef type)
222 WINE_CLIPFORMAT *format;
224 format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format));
228 WARN("No more memory for a new format!\n");
231 format->format_id = id;
232 format->import_func = import_clipboard_data;
233 format->export_func = export_clipboard_data;
234 format->synthesized = FALSE;
237 format->type = CFStringCreateCopy(NULL, type);
242 GetClipboardFormatNameW(format->format_id, buffer, 256);
243 if (!strncmpW(buffer, mac_type_name_prefix, strlenW(mac_type_name_prefix)))
245 const WCHAR *p = buffer + strlenW(mac_type_name_prefix);
246 format->type = CFStringCreateWithCharacters(NULL, (UniChar*)p, strlenW(p));
250 format->type = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%S"),
251 registered_name_type_prefix, buffer);
255 list_add_tail(&format_list, &format->entry);
257 TRACE("Registering format %s type %s\n", debugstr_format(format->format_id),
258 debugstr_cf(format->type));
264 /**************************************************************************
267 * Register a custom Mac clipboard format.
269 static WINE_CLIPFORMAT* register_format(UINT id, CFStringRef type)
271 WINE_CLIPFORMAT *format;
273 /* walk format chain to see if it's already registered */
274 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
275 if (format->format_id == id) return format;
277 return insert_clipboard_format(id, type);
281 /**************************************************************************
284 static WINE_CLIPFORMAT* format_for_type(WINE_CLIPFORMAT *current, CFStringRef type)
286 struct list *ptr = current ? ¤t->entry : &format_list;
287 WINE_CLIPFORMAT *format = NULL;
289 TRACE("current %p/%s type %s\n", current, debugstr_format(current ? current->format_id : 0), debugstr_cf(type));
291 while ((ptr = list_next(&format_list, ptr)))
293 format = LIST_ENTRY(ptr, WINE_CLIPFORMAT, entry);
294 if (CFEqual(format->type, type))
296 TRACE(" -> %p/%s\n", format, debugstr_format(format->format_id));
305 if (CFStringHasPrefix(type, CFSTR("org.winehq.builtin.")))
307 ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
311 else if (CFStringHasPrefix(type, registered_name_type_prefix))
313 int len = CFStringGetLength(type) - CFStringGetLength(registered_name_type_prefix);
314 name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
315 CFStringGetCharacters(type, CFRangeMake(CFStringGetLength(registered_name_type_prefix), len),
321 int len = strlenW(mac_type_name_prefix) + CFStringGetLength(type);
322 name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
323 memcpy(name, mac_type_name_prefix, sizeof(mac_type_name_prefix));
324 CFStringGetCharacters(type, CFRangeMake(0, CFStringGetLength(type)),
325 (UniChar*)name + strlenW(mac_type_name_prefix));
329 format = register_format(RegisterClipboardFormatW(name), type);
331 ERR("Failed to register format for type %s name %s\n", debugstr_cf(type), debugstr_w(name));
333 HeapFree(GetProcessHeap(), 0, name);
336 TRACE(" -> %p/%s\n", format, debugstr_format(format ? format->format_id : 0));
341 /**************************************************************************
344 * Convert string data between code pages or to/from wide characters. The
345 * special value of (UINT)-1 for a code page indicates to use wide
348 static HANDLE convert_text(const void *src, int src_len, UINT src_cp, UINT dest_cp)
356 if (src_cp == (UINT)-1)
359 wstr_len = src_len / sizeof(WCHAR);
365 wstr_len = MultiByteToWideChar(src_cp, 0, src, src_len, NULL, 0);
366 if (!src_len || ((const char*)src)[src_len - 1]) wstr_len += 1;
367 temp = HeapAlloc(GetProcessHeap(), 0, wstr_len * sizeof(WCHAR));
368 MultiByteToWideChar(src_cp, 0, src, src_len, temp, wstr_len);
369 temp[wstr_len - 1] = 0;
373 if (dest_cp == (UINT)-1)
375 handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, wstr_len * sizeof(WCHAR));
376 if (handle && (p = GlobalLock(handle)))
378 memcpy(p, wstr, wstr_len * sizeof(WCHAR));
379 GlobalUnlock(handle);
387 len = WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, NULL, 0, NULL, NULL);
388 if (!wstr_len || wstr[wstr_len - 1]) len += 1;
389 handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
391 if (handle && (p = GlobalLock(handle)))
393 WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, p, len, NULL, NULL);
395 GlobalUnlock(handle);
404 /**************************************************************************
405 * convert_unicodetext_to_codepage
407 static HANDLE convert_unicodetext_to_codepage(HANDLE unicode_handle, UINT cp)
409 LPWSTR unicode_string = GlobalLock(unicode_handle);
414 ret = convert_text(unicode_string, GlobalSize(unicode_handle), -1, cp);
415 GlobalUnlock(unicode_handle);
422 /**************************************************************************
423 * import_clipboard_data
425 * Generic import clipboard data routine.
427 static HANDLE import_clipboard_data(CFDataRef data)
429 HANDLE data_handle = NULL;
431 size_t len = CFDataGetLength(data);
436 /* Turn on the DDESHARE flag to enable shared 32 bit memory */
437 data_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
441 if ((p = GlobalLock(data_handle)))
443 memcpy(p, CFDataGetBytePtr(data), len);
444 GlobalUnlock(data_handle);
448 GlobalFree(data_handle);
457 /**************************************************************************
458 * import_oemtext_to_text
460 * Import CF_OEMTEXT data, converting the string to CF_TEXT.
462 static HANDLE import_oemtext_to_text(CFDataRef data)
464 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, CP_ACP);
468 /**************************************************************************
469 * import_oemtext_to_unicodetext
471 * Import CF_OEMTEXT data, converting the string to CF_UNICODETEXT.
473 static HANDLE import_oemtext_to_unicodetext(CFDataRef data)
475 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, -1);
479 /**************************************************************************
480 * import_text_to_oemtext
482 * Import CF_TEXT data, converting the string to CF_OEMTEXT.
484 static HANDLE import_text_to_oemtext(CFDataRef data)
486 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, CP_OEMCP);
490 /**************************************************************************
491 * import_text_to_unicodetext
493 * Import CF_TEXT data, converting the string to CF_UNICODETEXT.
495 static HANDLE import_text_to_unicodetext(CFDataRef data)
497 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, -1);
501 /**************************************************************************
502 * import_unicodetext_to_oemtext
504 * Import a CF_UNICODETEXT string, converting the string to CF_OEMTEXT.
506 static HANDLE import_unicodetext_to_oemtext(CFDataRef data)
508 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_OEMCP);
512 /**************************************************************************
513 * import_unicodetext_to_text
515 * Import a CF_UNICODETEXT string, converting the string to CF_TEXT.
517 static HANDLE import_unicodetext_to_text(CFDataRef data)
519 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_ACP);
523 /**************************************************************************
524 * import_utf8_to_oemtext
526 * Import a UTF-8 string, converting the string to CF_OEMTEXT.
528 static HANDLE import_utf8_to_oemtext(CFDataRef data)
530 HANDLE unicode_handle = import_utf8_to_unicodetext(data);
531 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_OEMCP);
533 GlobalFree(unicode_handle);
538 /**************************************************************************
539 * import_utf8_to_text
541 * Import a UTF-8 string, converting the string to CF_TEXT.
543 static HANDLE import_utf8_to_text(CFDataRef data)
545 HANDLE unicode_handle = import_utf8_to_unicodetext(data);
546 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_ACP);
548 GlobalFree(unicode_handle);
553 /**************************************************************************
554 * import_utf8_to_unicodetext
556 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
558 static HANDLE import_utf8_to_unicodetext(CFDataRef data)
561 unsigned long data_len;
562 unsigned long new_lines = 0;
565 HANDLE unicode_handle = NULL;
567 src = CFDataGetBytePtr(data);
568 data_len = CFDataGetLength(data);
569 for (i = 0; i < data_len; i++)
575 if ((dst = HeapAlloc(GetProcessHeap(), 0, data_len + new_lines + 1)))
579 for (i = 0, j = 0; i < data_len; i++)
588 count = MultiByteToWideChar(CP_UTF8, 0, dst, -1, NULL, 0);
589 unicode_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, count * sizeof(WCHAR));
593 WCHAR *textW = GlobalLock(unicode_handle);
594 MultiByteToWideChar(CP_UTF8, 0, dst, -1, textW, count);
595 GlobalUnlock(unicode_handle);
598 HeapFree(GetProcessHeap(), 0, dst);
601 return unicode_handle;
605 /**************************************************************************
606 * export_clipboard_data
608 * Generic export clipboard data routine.
610 static CFDataRef export_clipboard_data(HANDLE data)
616 len = GlobalSize(data);
617 src = GlobalLock(data);
618 if (!src) return NULL;
620 ret = CFDataCreate(NULL, src, len);
627 /**************************************************************************
628 * export_codepage_to_utf8
630 * Export string data in a specified codepage to UTF-8.
632 static CFDataRef export_codepage_to_utf8(HANDLE data, UINT cp)
634 CFDataRef ret = NULL;
637 if ((str = GlobalLock(data)))
639 HANDLE unicode = convert_text(str, GlobalSize(data), cp, -1);
641 ret = export_unicodetext_to_utf8(unicode);
651 /**************************************************************************
652 * export_oemtext_to_utf8
654 * Export CF_OEMTEXT to UTF-8.
656 static CFDataRef export_oemtext_to_utf8(HANDLE data)
658 return export_codepage_to_utf8(data, CP_OEMCP);
662 /**************************************************************************
663 * export_text_to_utf8
665 * Export CF_TEXT to UTF-8.
667 static CFDataRef export_text_to_utf8(HANDLE data)
669 return export_codepage_to_utf8(data, CP_ACP);
673 /**************************************************************************
674 * export_unicodetext_to_utf8
676 * Export CF_UNICODETEXT to UTF-8.
678 static CFDataRef export_unicodetext_to_utf8(HANDLE data)
680 CFMutableDataRef ret;
684 src = GlobalLock(data);
685 if (!src) return NULL;
687 dst_len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
688 if (dst_len) dst_len--; /* Leave off null terminator. */
689 ret = CFDataCreateMutable(NULL, dst_len);
695 CFDataSetLength(ret, dst_len);
696 dst = (LPSTR)CFDataGetMutableBytePtr(ret);
697 WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_len, NULL, NULL);
699 /* Remove carriage returns */
700 for (i = 0, j = 0; i < dst_len; i++)
702 if (dst[i] == '\r' &&
703 (i + 1 >= dst_len || dst[i + 1] == '\n' || dst[i + 1] == '\0'))
707 CFDataSetLength(ret, j);
715 /**************************************************************************
718 static BOOL get_clipboard_info(LPCLIPBOARDINFO cbinfo)
722 SERVER_START_REQ(set_clipboard_info)
726 if (wine_server_call_err(req))
728 ERR("Failed to get clipboard owner.\n");
732 cbinfo->hwnd_owner = wine_server_ptr_handle(reply->old_owner);
733 cbinfo->flags = reply->flags;
744 /**************************************************************************
747 static BOOL release_ownership(void)
751 SERVER_START_REQ(set_clipboard_info)
753 req->flags = SET_CB_RELOWNER | SET_CB_SEQNO;
755 if (wine_server_call_err(req))
756 ERR("Failed to set clipboard.\n");
766 /**************************************************************************
767 * check_clipboard_ownership
769 static void check_clipboard_ownership(HWND *owner)
771 CLIPBOARDINFO cbinfo;
773 if (owner) *owner = NULL;
775 /* If Wine thinks we're the clipboard owner but Mac OS X thinks we're not
776 the pasteboard owner, update Wine. */
777 if (get_clipboard_info(&cbinfo) && (cbinfo.flags & CB_PROCESS))
779 if (!(cbinfo.flags & CB_OPEN) && !macdrv_is_pasteboard_owner())
781 TRACE("Lost clipboard ownership\n");
783 if (OpenClipboard(cbinfo.hwnd_owner))
785 /* Destroy private objects */
786 SendMessageW(cbinfo.hwnd_owner, WM_DESTROYCLIPBOARD, 0, 0);
788 /* Give up ownership of the windows clipboard */
794 *owner = cbinfo.hwnd_owner;
799 /**************************************************************************
800 * Mac User Driver Clipboard Exports
801 **************************************************************************/
804 /**************************************************************************
805 * AcquireClipboard (MACDRV.@)
807 int CDECL macdrv_AcquireClipboard(HWND hwnd)
809 TRACE("hwnd %p\n", hwnd);
810 check_clipboard_ownership(NULL);
815 /**************************************************************************
816 * CountClipboardFormats (MACDRV.@)
818 INT CDECL macdrv_CountClipboardFormats(void)
820 CFMutableSetRef seen_formats;
827 check_clipboard_ownership(NULL);
829 seen_formats = CFSetCreateMutable(NULL, 0, NULL);
832 WARN("Failed to allocate set to track seen formats\n");
836 types = macdrv_copy_pasteboard_types();
839 WARN("Failed to copy pasteboard types\n");
840 CFRelease(seen_formats);
844 count = CFArrayGetCount(types);
845 TRACE("got %ld types\n", count);
847 for (i = 0; i < count; i++)
849 CFStringRef type = CFArrayGetValueAtIndex(types, i);
850 WINE_CLIPFORMAT* format;
853 while ((format = format_for_type(format, type)))
855 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
857 if (!CFSetContainsValue(seen_formats, (void*)format->format_id))
860 CFSetAddValue(seen_formats, (void*)format->format_id);
865 CFRelease(seen_formats);
866 TRACE(" -> %d\n", ret);
871 /**************************************************************************
872 * EmptyClipboard (MACDRV.@)
874 * Empty cached clipboard data.
876 void CDECL macdrv_EmptyClipboard(BOOL keepunowned)
878 TRACE("keepunowned %d\n", keepunowned);
879 macdrv_clear_pasteboard();
883 /**************************************************************************
884 * EndClipboardUpdate (MACDRV.@)
886 void CDECL macdrv_EndClipboardUpdate(void)
889 check_clipboard_ownership(NULL);
893 /**************************************************************************
894 * EnumClipboardFormats (MACDRV.@)
896 UINT CDECL macdrv_EnumClipboardFormats(UINT prev_format)
903 TRACE("prev_format %s\n", debugstr_format(prev_format));
904 check_clipboard_ownership(NULL);
906 types = macdrv_copy_pasteboard_types();
909 WARN("Failed to copy pasteboard types\n");
913 count = CFArrayGetCount(types);
914 TRACE("got %ld types\n", count);
924 CFMutableArrayRef formats = CFArrayCreateMutable(NULL, 0, NULL);
927 WARN("Failed to allocate array to track formats\n");
932 for (i = 0; i < count; i++)
934 CFStringRef type = CFArrayGetValueAtIndex(types, i);
935 WINE_CLIPFORMAT* format;
938 while ((format = format_for_type(format, type)))
940 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
942 if (format->synthesized)
944 /* Don't override a real value with a synthesized value. */
945 if (!CFArrayContainsValue(formats, CFRangeMake(0, CFArrayGetCount(formats)), (void*)format->format_id))
946 CFArrayAppendValue(formats, (void*)format->format_id);
950 /* If the type was already in the array, it must have been synthesized
951 because this one's real. Remove the synthesized entry in favor of
953 CFIndex index = CFArrayGetFirstIndexOfValue(formats, CFRangeMake(0, CFArrayGetCount(formats)),
954 (void*)format->format_id);
955 if (index != kCFNotFound)
956 CFArrayRemoveValueAtIndex(formats, index);
957 CFArrayAppendValue(formats, (void*)format->format_id);
962 count = CFArrayGetCount(formats);
963 i = CFArrayGetFirstIndexOfValue(formats, CFRangeMake(0, count), (void*)prev_format);
964 if (i == kCFNotFound || i + 1 >= count)
967 ret = (UINT)CFArrayGetValueAtIndex(formats, i + 1);
973 CFStringRef type = CFArrayGetValueAtIndex(types, 0);
974 WINE_CLIPFORMAT *format = format_for_type(NULL, type);
976 ret = format ? format->format_id : 0;
980 TRACE(" -> %u\n", ret);
985 /**************************************************************************
986 * GetClipboardData (MACDRV.@)
988 HANDLE CDECL macdrv_GetClipboardData(UINT desired_format)
993 CFStringRef type, best_type;
994 WINE_CLIPFORMAT* best_format = NULL;
997 TRACE("desired_format %s\n", debugstr_format(desired_format));
998 check_clipboard_ownership(NULL);
1000 types = macdrv_copy_pasteboard_types();
1003 WARN("Failed to copy pasteboard types\n");
1007 count = CFArrayGetCount(types);
1008 TRACE("got %ld types\n", count);
1010 for (i = 0; (!best_format || best_format->synthesized) && i < count; i++)
1012 WINE_CLIPFORMAT* format;
1014 type = CFArrayGetValueAtIndex(types, i);
1017 while ((!best_format || best_format->synthesized) && (format = format_for_type(format, type)))
1019 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format ? format->format_id : 0));
1021 if (format->format_id == desired_format)
1023 /* The best format is the matching one which is not synthesized. Failing that,
1024 the best format is the first matching synthesized format. */
1025 if (!format->synthesized || !best_format)
1028 best_format = format;
1036 CFDataRef pasteboard_data = macdrv_copy_pasteboard_data(best_type);
1038 TRACE("got pasteboard data for type %s: %s\n", debugstr_cf(best_type), debugstr_cf(pasteboard_data));
1040 if (pasteboard_data)
1042 data = best_format->import_func(pasteboard_data);
1043 CFRelease(pasteboard_data);
1048 TRACE(" -> %p\n", data);
1053 /**************************************************************************
1054 * IsClipboardFormatAvailable (MACDRV.@)
1056 BOOL CDECL macdrv_IsClipboardFormatAvailable(UINT desired_format)
1063 TRACE("desired_format %s\n", debugstr_format(desired_format));
1064 check_clipboard_ownership(NULL);
1066 types = macdrv_copy_pasteboard_types();
1069 WARN("Failed to copy pasteboard types\n");
1073 count = CFArrayGetCount(types);
1074 TRACE("got %d types\n", count);
1076 for (i = 0; !found && i < count; i++)
1078 CFStringRef type = CFArrayGetValueAtIndex(types, i);
1079 WINE_CLIPFORMAT* format;
1082 while (!found && (format = format_for_type(format, type)))
1084 TRACE("for type %s got format %s\n", debugstr_cf(type), debugstr_format(format->format_id));
1086 if (format->format_id == desired_format)
1092 TRACE(" -> %d\n", found);
1097 /**************************************************************************
1098 * SetClipboardData (MACDRV.@)
1100 BOOL CDECL macdrv_SetClipboardData(UINT format_id, HANDLE data, BOOL owner)
1103 macdrv_window window;
1104 WINE_CLIPFORMAT *format;
1105 CFDataRef cfdata = NULL;
1107 check_clipboard_ownership(&hwnd_owner);
1108 window = macdrv_get_cocoa_window(GetAncestor(hwnd_owner, GA_ROOT), FALSE);
1109 TRACE("format_id %s data %p owner %d hwnd_owner %p window %p)\n", debugstr_format(format_id), data, owner, hwnd_owner, window);
1111 /* Find the "natural" format for this format_id (the one which isn't
1112 synthesized from another type). */
1113 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1114 if (format->format_id == format_id && !format->synthesized) break;
1116 if (&format->entry == &format_list && !(format = insert_clipboard_format(format_id, NULL)))
1118 WARN("Failed to register clipboard format %s\n", debugstr_format(format_id));
1122 /* Export the data to the Mac pasteboard. */
1125 if (!format->export_func || !(cfdata = format->export_func(data)))
1127 WARN("Failed to export %s data to type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1132 if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1133 TRACE("Set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1136 WARN("Failed to set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
1137 if (cfdata) CFRelease(cfdata);
1141 if (cfdata) CFRelease(cfdata);
1143 /* Find any other formats for this format_id (the exportable synthesized ones). */
1144 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
1146 if (format->format_id == format_id && format->synthesized && format->export_func)
1148 /* We have a synthesized format for this format ID. Add its type to the pasteboard. */
1149 TRACE("Synthesized from format %s: type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
1153 cfdata = format->export_func(data);
1156 WARN("Failed to export %s data to type %s\n", debugstr_format(format->format_id), debugstr_cf(format->type));
1163 if (macdrv_set_pasteboard_data(format->type, cfdata, window))
1164 TRACE(" ... set pasteboard data: %s\n", debugstr_cf(cfdata));
1166 WARN(" ... failed to set pasteboard data: %s\n", debugstr_cf(cfdata));
1168 if (cfdata) CFRelease(cfdata);
1174 /* FIXME: According to MSDN, the caller is entitled to lock and read from
1175 data until CloseClipboard is called. So, we should defer this cleanup. */
1176 if ((format_id >= CF_GDIOBJFIRST && format_id <= CF_GDIOBJLAST) ||
1177 format_id == CF_BITMAP ||
1178 format_id == CF_DIB ||
1179 format_id == CF_PALETTE)
1183 else if (format_id == CF_METAFILEPICT)
1185 DeleteMetaFile(((METAFILEPICT *)GlobalLock(data))->hMF);
1188 else if (format_id == CF_ENHMETAFILE)
1190 DeleteEnhMetaFile(data);
1192 else if (format_id < CF_PRIVATEFIRST || CF_PRIVATELAST < format_id)
1202 /**************************************************************************
1203 * MACDRV Private Clipboard Exports
1204 **************************************************************************/
1207 /**************************************************************************
1208 * macdrv_clipboard_process_attach
1210 void macdrv_clipboard_process_attach(void)
1214 /* Register built-in formats */
1215 for (i = 0; i < sizeof(builtin_format_ids)/sizeof(builtin_format_ids[0]); i++)
1217 WINE_CLIPFORMAT *format;
1219 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
1220 format->format_id = builtin_format_ids[i].id;
1221 format->type = CFRetain(builtin_format_ids[i].type);
1222 format->import_func = builtin_format_ids[i].import;
1223 format->export_func = builtin_format_ids[i].export;
1224 format->synthesized = builtin_format_ids[i].synthesized;
1225 list_add_tail(&format_list, &format->entry);
1230 /**************************************************************************
1231 * query_pasteboard_data
1233 BOOL query_pasteboard_data(HWND hwnd, CFStringRef type)
1236 CLIPBOARDINFO cbinfo;
1237 WINE_CLIPFORMAT* format;
1238 CFArrayRef types = NULL;
1241 TRACE("hwnd %p type %s\n", hwnd, debugstr_cf(type));
1243 if (get_clipboard_info(&cbinfo))
1244 hwnd = cbinfo.hwnd_owner;
1247 while ((format = format_for_type(format, type)))
1249 WINE_CLIPFORMAT* base_format;
1251 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
1253 if (!format->synthesized)
1255 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(format->format_id), hwnd);
1256 SendMessageW(hwnd, WM_RENDERFORMAT, format->format_id, 0);
1263 types = macdrv_copy_pasteboard_types();
1266 WARN("Failed to copy pasteboard types\n");
1270 range = CFRangeMake(0, CFArrayGetCount(types));
1273 /* The type maps to a synthesized format. Now look up what type that format maps to natively
1274 (not synthesized). For example, if type is "public.utf8-plain-text", then this format may
1275 have an ID of CF_TEXT. From CF_TEXT, we want to find "org.winehq.builtin.text" to see if
1276 that type is present in the pasteboard. If it is, then the app must have promised it and
1277 we can ask it to render it. (If it had put it on the clipboard immediately, then the
1278 pasteboard would also have data for "public.utf8-plain-text" and we wouldn't be here.) If
1279 "org.winehq.builtin.text" is not on the pasteboard, then one of the other text formats is
1280 presumably responsible for the promise that we're trying to satisfy, so we keep looking. */
1281 LIST_FOR_EACH_ENTRY(base_format, &format_list, WINE_CLIPFORMAT, entry)
1283 if (base_format->format_id == format->format_id && !base_format->synthesized &&
1284 CFArrayContainsValue(types, range, base_format->type))
1286 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(base_format->format_id), hwnd);
1287 SendMessageW(hwnd, WM_RENDERFORMAT, base_format->format_id, 0);
1295 if (types) CFRelease(types);