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/unicode.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
36 /**************************************************************************
38 **************************************************************************/
40 typedef HANDLE (*DRVIMPORTFUNC)(CFDataRef data);
47 DRVIMPORTFUNC import_func;
52 /**************************************************************************
54 **************************************************************************/
57 /**************************************************************************
58 * Forward Function Declarations
59 **************************************************************************/
61 static HANDLE import_clipboard_data(CFDataRef data);
62 static HANDLE import_oemtext_to_text(CFDataRef data);
63 static HANDLE import_oemtext_to_unicodetext(CFDataRef data);
64 static HANDLE import_text_to_oemtext(CFDataRef data);
65 static HANDLE import_text_to_unicodetext(CFDataRef data);
66 static HANDLE import_unicodetext_to_oemtext(CFDataRef data);
67 static HANDLE import_unicodetext_to_text(CFDataRef data);
68 static HANDLE import_utf8_to_oemtext(CFDataRef data);
69 static HANDLE import_utf8_to_text(CFDataRef data);
70 static HANDLE import_utf8_to_unicodetext(CFDataRef data);
73 /**************************************************************************
75 **************************************************************************/
77 /* Clipboard formats */
78 static struct list format_list = LIST_INIT(format_list);
80 /* There are two naming schemes involved and we want to have a mapping between
81 them. There are Win32 clipboard format names and there are Mac pasteboard
84 The Win32 standard clipboard formats don't have names, but they are associated
85 with Mac pasteboard types through the following tables, which are used to
86 initialize the format_list. Where possible, the standard clipboard formats
87 are mapped to predefined pasteboard type UTIs. Otherwise, we create Wine-
88 specific types of the form "org.winehq.builtin.<format>", where <format> is
89 the name of the symbolic constant for the format minus "CF_" and lowercased.
90 E.g. CF_BITMAP -> org.winehq.builtin.bitmap.
92 Win32 clipboard formats which originate in a Windows program may be registered
93 with an arbitrary name. We construct a Mac pasteboard type from these by
94 prepending "org.winehq.registered." to the registered name.
96 Likewise, Mac pasteboard types which originate in other apps may have
97 arbitrary type strings. We construct a Win32 clipboard format name from
98 these by prepending "org.winehq.mac-type." to the Mac pasteboard type.
101 Win32 clipboard format names:
102 <none> standard clipboard format; maps via
103 format_list to either a predefined Mac UTI
104 or org.winehq.builtin.<format>.
105 org.winehq.mac-type.<Mac type> representation of Mac type in Win32 land;
107 <other> name registered within Win32 land; maps to
108 org.winehq.registered.<other>
109 Mac pasteboard type names:
110 org.winehq.builtin.<format ID> representation of Win32 standard clipboard
111 format for which there was no corresponding
112 predefined Mac UTI; maps via format_list
113 org.winehq.registered.<format name> representation of Win32 registered
114 clipboard format name; maps to <format name>
115 <other> Mac pasteboard type originating with system
116 or other apps; either maps via format_list
117 to a standard clipboard format or maps to
118 org.winehq.mac-type.<other>
125 DRVIMPORTFUNC import;
127 } builtin_format_ids[] =
129 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.unicodetext"), import_clipboard_data, FALSE },
130 { CF_TEXT, CFSTR("org.winehq.builtin.unicodetext"), import_unicodetext_to_text, TRUE },
131 { CF_OEMTEXT, CFSTR("org.winehq.builtin.unicodetext"), import_unicodetext_to_oemtext, TRUE },
133 { CF_TEXT, CFSTR("org.winehq.builtin.text"), import_clipboard_data, FALSE },
134 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.text"), import_text_to_unicodetext, TRUE },
135 { CF_OEMTEXT, CFSTR("org.winehq.builtin.text"), import_text_to_oemtext, TRUE },
137 { CF_OEMTEXT, CFSTR("org.winehq.builtin.oemtext"), import_clipboard_data, FALSE },
138 { CF_UNICODETEXT, CFSTR("org.winehq.builtin.oemtext"), import_oemtext_to_unicodetext, TRUE },
139 { CF_TEXT, CFSTR("org.winehq.builtin.oemtext"), import_oemtext_to_text, TRUE },
141 { CF_UNICODETEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_unicodetext, TRUE },
142 { CF_TEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_text, TRUE },
143 { CF_OEMTEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_oemtext, TRUE },
146 /* The prefix prepended to an external Mac pasteboard type to make a Win32 clipboard format name. org.winehq.mac-type. */
147 static const WCHAR mac_type_name_prefix[] = {'o','r','g','.','w','i','n','e','h','q','.','m','a','c','-','t','y','p','e','.',0};
149 /* The prefix prepended to a Win32 clipboard format name to make a Mac pasteboard type. */
150 static const CFStringRef registered_name_type_prefix = CFSTR("org.winehq.registered.");
153 /**************************************************************************
154 * Internal Clipboard implementation methods
155 **************************************************************************/
158 * format_list functions
161 /**************************************************************************
164 static const char *debugstr_format(UINT id)
168 if (GetClipboardFormatNameW(id, buffer, 256))
169 return wine_dbg_sprintf("0x%04x %s", id, debugstr_w(buffer));
173 #define BUILTIN(id) case id: return #id;
176 BUILTIN(CF_METAFILEPICT)
186 BUILTIN(CF_UNICODETEXT)
187 BUILTIN(CF_ENHMETAFILE)
191 BUILTIN(CF_OWNERDISPLAY)
193 BUILTIN(CF_DSPBITMAP)
194 BUILTIN(CF_DSPMETAFILEPICT)
195 BUILTIN(CF_DSPENHMETAFILE)
197 default: return wine_dbg_sprintf("0x%04x", id);
202 /**************************************************************************
203 * insert_clipboard_format
205 static WINE_CLIPFORMAT *insert_clipboard_format(UINT id, CFStringRef type)
207 WINE_CLIPFORMAT *format;
209 format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format));
213 WARN("No more memory for a new format!\n");
216 format->format_id = id;
217 format->import_func = import_clipboard_data;
218 format->synthesized = FALSE;
221 format->type = CFStringCreateCopy(NULL, type);
226 GetClipboardFormatNameW(format->format_id, buffer, 256);
227 if (!strncmpW(buffer, mac_type_name_prefix, strlenW(mac_type_name_prefix)))
229 const WCHAR *p = buffer + strlenW(mac_type_name_prefix);
230 format->type = CFStringCreateWithCharacters(NULL, (UniChar*)p, strlenW(p));
234 format->type = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%S"),
235 registered_name_type_prefix, buffer);
239 list_add_tail(&format_list, &format->entry);
241 TRACE("Registering format %s type %s\n", debugstr_format(format->format_id),
242 debugstr_cf(format->type));
248 /**************************************************************************
251 * Register a custom Mac clipboard format.
253 static WINE_CLIPFORMAT* register_format(UINT id, CFStringRef type)
255 WINE_CLIPFORMAT *format;
257 /* walk format chain to see if it's already registered */
258 LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
259 if (format->format_id == id) return format;
261 return insert_clipboard_format(id, type);
265 /**************************************************************************
268 static WINE_CLIPFORMAT* format_for_type(WINE_CLIPFORMAT *current, CFStringRef type)
270 struct list *ptr = current ? ¤t->entry : &format_list;
271 WINE_CLIPFORMAT *format = NULL;
273 TRACE("current %p/%s type %s\n", current, debugstr_format(current ? current->format_id : 0), debugstr_cf(type));
275 while ((ptr = list_next(&format_list, ptr)))
277 format = LIST_ENTRY(ptr, WINE_CLIPFORMAT, entry);
278 if (CFEqual(format->type, type))
280 TRACE(" -> %p/%s\n", format, debugstr_format(format->format_id));
289 if (CFStringHasPrefix(type, CFSTR("org.winehq.builtin.")))
291 ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
295 else if (CFStringHasPrefix(type, registered_name_type_prefix))
297 int len = CFStringGetLength(type) - CFStringGetLength(registered_name_type_prefix);
298 name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
299 CFStringGetCharacters(type, CFRangeMake(CFStringGetLength(registered_name_type_prefix), len),
305 int len = strlenW(mac_type_name_prefix) + CFStringGetLength(type);
306 name = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
307 memcpy(name, mac_type_name_prefix, sizeof(mac_type_name_prefix));
308 CFStringGetCharacters(type, CFRangeMake(0, CFStringGetLength(type)),
309 (UniChar*)name + strlenW(mac_type_name_prefix));
313 format = register_format(RegisterClipboardFormatW(name), type);
315 ERR("Failed to register format for type %s name %s\n", debugstr_cf(type), debugstr_w(name));
317 HeapFree(GetProcessHeap(), 0, name);
320 TRACE(" -> %p/%s\n", format, debugstr_format(format ? format->format_id : 0));
325 /**************************************************************************
328 * Convert string data between code pages or to/from wide characters. The
329 * special value of (UINT)-1 for a code page indicates to use wide
332 static HANDLE convert_text(const void *src, int src_len, UINT src_cp, UINT dest_cp)
340 if (src_cp == (UINT)-1)
343 wstr_len = src_len / sizeof(WCHAR);
349 wstr_len = MultiByteToWideChar(src_cp, 0, src, src_len, NULL, 0);
350 if (!src_len || ((const char*)src)[src_len - 1]) wstr_len += 1;
351 temp = HeapAlloc(GetProcessHeap(), 0, wstr_len * sizeof(WCHAR));
352 MultiByteToWideChar(src_cp, 0, src, src_len, temp, wstr_len);
353 temp[wstr_len - 1] = 0;
357 if (dest_cp == (UINT)-1)
359 handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, wstr_len * sizeof(WCHAR));
360 if (handle && (p = GlobalLock(handle)))
362 memcpy(p, wstr, wstr_len * sizeof(WCHAR));
363 GlobalUnlock(handle);
371 len = WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, NULL, 0, NULL, NULL);
372 if (!wstr_len || wstr[wstr_len - 1]) len += 1;
373 handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
375 if (handle && (p = GlobalLock(handle)))
377 WideCharToMultiByte(dest_cp, 0, wstr, wstr_len, p, len, NULL, NULL);
379 GlobalUnlock(handle);
388 /**************************************************************************
389 * convert_unicodetext_to_codepage
391 static HANDLE convert_unicodetext_to_codepage(HANDLE unicode_handle, UINT cp)
393 LPWSTR unicode_string = GlobalLock(unicode_handle);
398 ret = convert_text(unicode_string, GlobalSize(unicode_handle), -1, cp);
399 GlobalUnlock(unicode_handle);
406 /**************************************************************************
407 * import_clipboard_data
409 * Generic import clipboard data routine.
411 static HANDLE import_clipboard_data(CFDataRef data)
413 HANDLE data_handle = NULL;
415 size_t len = CFDataGetLength(data);
420 /* Turn on the DDESHARE flag to enable shared 32 bit memory */
421 data_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
425 if ((p = GlobalLock(data_handle)))
427 memcpy(p, CFDataGetBytePtr(data), len);
428 GlobalUnlock(data_handle);
432 GlobalFree(data_handle);
441 /**************************************************************************
442 * import_oemtext_to_text
444 * Import CF_OEMTEXT data, converting the string to CF_TEXT.
446 static HANDLE import_oemtext_to_text(CFDataRef data)
448 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, CP_ACP);
452 /**************************************************************************
453 * import_oemtext_to_unicodetext
455 * Import CF_OEMTEXT data, converting the string to CF_UNICODETEXT.
457 static HANDLE import_oemtext_to_unicodetext(CFDataRef data)
459 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_OEMCP, -1);
463 /**************************************************************************
464 * import_text_to_oemtext
466 * Import CF_TEXT data, converting the string to CF_OEMTEXT.
468 static HANDLE import_text_to_oemtext(CFDataRef data)
470 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, CP_OEMCP);
474 /**************************************************************************
475 * import_text_to_unicodetext
477 * Import CF_TEXT data, converting the string to CF_UNICODETEXT.
479 static HANDLE import_text_to_unicodetext(CFDataRef data)
481 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), CP_ACP, -1);
485 /**************************************************************************
486 * import_unicodetext_to_oemtext
488 * Import a CF_UNICODETEXT string, converting the string to CF_OEMTEXT.
490 static HANDLE import_unicodetext_to_oemtext(CFDataRef data)
492 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_OEMCP);
496 /**************************************************************************
497 * import_unicodetext_to_text
499 * Import a CF_UNICODETEXT string, converting the string to CF_TEXT.
501 static HANDLE import_unicodetext_to_text(CFDataRef data)
503 return convert_text(CFDataGetBytePtr(data), CFDataGetLength(data), -1, CP_ACP);
507 /**************************************************************************
508 * import_utf8_to_oemtext
510 * Import a UTF-8 string, converting the string to CF_OEMTEXT.
512 static HANDLE import_utf8_to_oemtext(CFDataRef data)
514 HANDLE unicode_handle = import_utf8_to_unicodetext(data);
515 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_OEMCP);
517 GlobalFree(unicode_handle);
522 /**************************************************************************
523 * import_utf8_to_text
525 * Import a UTF-8 string, converting the string to CF_TEXT.
527 static HANDLE import_utf8_to_text(CFDataRef data)
529 HANDLE unicode_handle = import_utf8_to_unicodetext(data);
530 HANDLE ret = convert_unicodetext_to_codepage(unicode_handle, CP_ACP);
532 GlobalFree(unicode_handle);
537 /**************************************************************************
538 * import_utf8_to_unicodetext
540 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
542 static HANDLE import_utf8_to_unicodetext(CFDataRef data)
545 unsigned long data_len;
546 unsigned long new_lines = 0;
549 HANDLE unicode_handle = NULL;
551 src = CFDataGetBytePtr(data);
552 data_len = CFDataGetLength(data);
553 for (i = 0; i < data_len; i++)
559 if ((dst = HeapAlloc(GetProcessHeap(), 0, data_len + new_lines + 1)))
563 for (i = 0, j = 0; i < data_len; i++)
572 count = MultiByteToWideChar(CP_UTF8, 0, dst, -1, NULL, 0);
573 unicode_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, count * sizeof(WCHAR));
577 WCHAR *textW = GlobalLock(unicode_handle);
578 MultiByteToWideChar(CP_UTF8, 0, dst, -1, textW, count);
579 GlobalUnlock(unicode_handle);
582 HeapFree(GetProcessHeap(), 0, dst);
585 return unicode_handle;
589 /**************************************************************************
590 * Mac User Driver Clipboard Exports
591 **************************************************************************/
594 /**************************************************************************
595 * CountClipboardFormats (MACDRV.@)
597 INT CDECL macdrv_CountClipboardFormats(void)
599 CFMutableSetRef seen_formats;
607 seen_formats = CFSetCreateMutable(NULL, 0, NULL);
610 WARN("Failed to allocate set to track seen formats\n");
614 types = macdrv_copy_pasteboard_types();
617 WARN("Failed to copy pasteboard types\n");
618 CFRelease(seen_formats);
622 count = CFArrayGetCount(types);
623 TRACE("got %ld types\n", count);
625 for (i = 0; i < count; i++)
627 CFStringRef type = CFArrayGetValueAtIndex(types, i);
628 WINE_CLIPFORMAT* format;
631 while ((format = format_for_type(format, type)))
633 TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
635 if (!CFSetContainsValue(seen_formats, (void*)format->format_id))
638 CFSetAddValue(seen_formats, (void*)format->format_id);
643 CFRelease(seen_formats);
644 TRACE(" -> %d\n", ret);
649 /**************************************************************************
650 * IsClipboardFormatAvailable (MACDRV.@)
652 BOOL CDECL macdrv_IsClipboardFormatAvailable(UINT desired_format)
659 TRACE("desired_format %s\n", debugstr_format(desired_format));
661 types = macdrv_copy_pasteboard_types();
664 WARN("Failed to copy pasteboard types\n");
668 count = CFArrayGetCount(types);
669 TRACE("got %d types\n", count);
671 for (i = 0; !found && i < count; i++)
673 CFStringRef type = CFArrayGetValueAtIndex(types, i);
674 WINE_CLIPFORMAT* format;
677 while (!found && (format = format_for_type(format, type)))
679 TRACE("for type %s got format %s\n", debugstr_cf(type), debugstr_format(format->format_id));
681 if (format->format_id == desired_format)
687 TRACE(" -> %d\n", found);
692 /**************************************************************************
693 * MACDRV Private Clipboard Exports
694 **************************************************************************/
697 /**************************************************************************
698 * macdrv_clipboard_process_attach
700 void macdrv_clipboard_process_attach(void)
704 /* Register built-in formats */
705 for (i = 0; i < sizeof(builtin_format_ids)/sizeof(builtin_format_ids[0]); i++)
707 WINE_CLIPFORMAT *format;
709 if (!(format = HeapAlloc(GetProcessHeap(), 0, sizeof(*format)))) break;
710 format->format_id = builtin_format_ids[i].id;
711 format->type = CFRetain(builtin_format_ids[i].type);
712 format->import_func = builtin_format_ids[i].import;
713 format->synthesized = builtin_format_ids[i].synthesized;
714 list_add_tail(&format_list, &format->entry);