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
31 #include "wine/list.h"
32 #include "wine/server.h"
33 #include "wine/unicode.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(clipboard
);
39 /**************************************************************************
41 **************************************************************************/
43 typedef HANDLE (*DRVIMPORTFUNC
)(CFDataRef data
);
44 typedef CFDataRef (*DRVEXPORTFUNC
)(HANDLE data
);
46 typedef struct _WINE_CLIPFORMAT
51 DRVIMPORTFUNC import_func
;
52 DRVEXPORTFUNC export_func
;
54 struct _WINE_CLIPFORMAT
*natural_format
;
58 /**************************************************************************
60 **************************************************************************/
63 /**************************************************************************
64 * Forward Function Declarations
65 **************************************************************************/
67 static HANDLE
import_clipboard_data(CFDataRef data
);
68 static HANDLE
import_bmp_to_bitmap(CFDataRef data
);
69 static HANDLE
import_bmp_to_dib(CFDataRef data
);
70 static HANDLE
import_enhmetafile(CFDataRef data
);
71 static HANDLE
import_metafilepict(CFDataRef data
);
72 static HANDLE
import_nsfilenames_to_hdrop(CFDataRef data
);
73 static HANDLE
import_utf8_to_text(CFDataRef data
);
74 static HANDLE
import_utf8_to_unicodetext(CFDataRef data
);
75 static HANDLE
import_utf16_to_unicodetext(CFDataRef data
);
77 static CFDataRef
export_clipboard_data(HANDLE data
);
78 static CFDataRef
export_bitmap_to_bmp(HANDLE data
);
79 static CFDataRef
export_dib_to_bmp(HANDLE data
);
80 static CFDataRef
export_enhmetafile(HANDLE data
);
81 static CFDataRef
export_hdrop_to_filenames(HANDLE data
);
82 static CFDataRef
export_metafilepict(HANDLE data
);
83 static CFDataRef
export_text_to_utf8(HANDLE data
);
84 static CFDataRef
export_unicodetext_to_utf8(HANDLE data
);
85 static CFDataRef
export_unicodetext_to_utf16(HANDLE data
);
88 /**************************************************************************
90 **************************************************************************/
92 /* Clipboard formats */
93 static struct list format_list
= LIST_INIT(format_list
);
95 /* There are two naming schemes involved and we want to have a mapping between
96 them. There are Win32 clipboard format names and there are Mac pasteboard
99 The Win32 standard clipboard formats don't have names, but they are associated
100 with Mac pasteboard types through the following tables, which are used to
101 initialize the format_list. Where possible, the standard clipboard formats
102 are mapped to predefined pasteboard type UTIs. Otherwise, we create Wine-
103 specific types of the form "org.winehq.builtin.<format>", where <format> is
104 the name of the symbolic constant for the format minus "CF_" and lowercased.
105 E.g. CF_BITMAP -> org.winehq.builtin.bitmap.
107 Win32 clipboard formats which originate in a Windows program may be registered
108 with an arbitrary name. We construct a Mac pasteboard type from these by
109 prepending "org.winehq.registered." to the registered name.
111 Likewise, Mac pasteboard types which originate in other apps may have
112 arbitrary type strings. We ignore these.
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 <other> name registered within Win32 land; maps to
120 org.winehq.registered.<other>
121 Mac pasteboard type names:
122 org.winehq.builtin.<format ID> representation of Win32 standard clipboard
123 format for which there was no corresponding
124 predefined Mac UTI; maps via format_list
125 org.winehq.registered.<format name> representation of Win32 registered
126 clipboard format name; maps to <format name>
127 <other> Mac pasteboard type originating with system
128 or other apps; either maps via format_list
129 to a standard clipboard format or ignored
136 DRVIMPORTFUNC import
;
137 DRVEXPORTFUNC export
;
139 } builtin_format_ids
[] =
141 { CF_BITMAP
, CFSTR("org.winehq.builtin.bitmap"), import_bmp_to_bitmap
, export_bitmap_to_bmp
, FALSE
},
142 { CF_DIBV5
, CFSTR("org.winehq.builtin.dibv5"), import_clipboard_data
, export_clipboard_data
, FALSE
},
143 { CF_DIF
, CFSTR("org.winehq.builtin.dif"), import_clipboard_data
, export_clipboard_data
, FALSE
},
144 { CF_ENHMETAFILE
, CFSTR("org.winehq.builtin.enhmetafile"), import_enhmetafile
, export_enhmetafile
, FALSE
},
145 { CF_LOCALE
, CFSTR("org.winehq.builtin.locale"), import_clipboard_data
, export_clipboard_data
, FALSE
},
146 { CF_METAFILEPICT
, CFSTR("org.winehq.builtin.metafilepict"), import_metafilepict
, export_metafilepict
, FALSE
},
147 { CF_OEMTEXT
, CFSTR("org.winehq.builtin.oemtext"), import_clipboard_data
, export_clipboard_data
, FALSE
},
148 { CF_PALETTE
, CFSTR("org.winehq.builtin.palette"), import_clipboard_data
, export_clipboard_data
, FALSE
},
149 { CF_PENDATA
, CFSTR("org.winehq.builtin.pendata"), import_clipboard_data
, export_clipboard_data
, FALSE
},
150 { CF_RIFF
, CFSTR("org.winehq.builtin.riff"), import_clipboard_data
, export_clipboard_data
, FALSE
},
151 { CF_SYLK
, CFSTR("org.winehq.builtin.sylk"), import_clipboard_data
, export_clipboard_data
, FALSE
},
152 { CF_TEXT
, CFSTR("org.winehq.builtin.text"), import_clipboard_data
, export_clipboard_data
, FALSE
},
153 { CF_TIFF
, CFSTR("public.tiff"), import_clipboard_data
, export_clipboard_data
, FALSE
},
154 { CF_WAVE
, CFSTR("com.microsoft.waveform-audio"), import_clipboard_data
, export_clipboard_data
, FALSE
},
156 { CF_DIB
, CFSTR("org.winehq.builtin.dib"), import_clipboard_data
, export_clipboard_data
, FALSE
},
157 { CF_DIB
, CFSTR("com.microsoft.bmp"), import_bmp_to_dib
, export_dib_to_bmp
, TRUE
},
159 { CF_HDROP
, CFSTR("org.winehq.builtin.hdrop"), import_clipboard_data
, export_clipboard_data
, FALSE
},
160 { CF_HDROP
, CFSTR("NSFilenamesPboardType"), import_nsfilenames_to_hdrop
, export_hdrop_to_filenames
, TRUE
},
162 { CF_UNICODETEXT
, CFSTR("org.winehq.builtin.unicodetext"), import_clipboard_data
, export_clipboard_data
, FALSE
},
163 { CF_UNICODETEXT
, CFSTR("public.utf16-plain-text"), import_utf16_to_unicodetext
, export_unicodetext_to_utf16
,TRUE
},
164 { CF_UNICODETEXT
, CFSTR("public.utf8-plain-text"), import_utf8_to_unicodetext
, export_unicodetext_to_utf8
, TRUE
},
167 static const WCHAR wszRichTextFormat
[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
168 static const WCHAR wszGIF
[] = {'G','I','F',0};
169 static const WCHAR wszJFIF
[] = {'J','F','I','F',0};
170 static const WCHAR wszPNG
[] = {'P','N','G',0};
171 static const WCHAR wszHTMLFormat
[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
176 DRVIMPORTFUNC import
;
177 DRVEXPORTFUNC export
;
178 } builtin_format_names
[] =
180 { wszRichTextFormat
, CFSTR("public.rtf"), import_clipboard_data
, export_clipboard_data
},
181 { wszGIF
, CFSTR("com.compuserve.gif"), import_clipboard_data
, export_clipboard_data
},
182 { wszJFIF
, CFSTR("public.jpeg"), import_clipboard_data
, export_clipboard_data
},
183 { wszPNG
, CFSTR("public.png"), import_clipboard_data
, export_clipboard_data
},
184 { wszHTMLFormat
, CFSTR("public.html"), import_clipboard_data
, export_clipboard_data
},
185 { CFSTR_SHELLURLW
, CFSTR("public.url"), import_utf8_to_text
, export_text_to_utf8
},
188 /* The prefix prepended to a Win32 clipboard format name to make a Mac pasteboard type. */
189 static const CFStringRef registered_name_type_prefix
= CFSTR("org.winehq.registered.");
191 static DWORD clipboard_thread_id
;
192 static HWND clipboard_hwnd
;
193 static BOOL is_clipboard_owner
;
194 static macdrv_window clipboard_cocoa_window
;
195 static ULONG64 last_clipboard_update
;
196 static WINE_CLIPFORMAT
**current_mac_formats
;
197 static unsigned int nb_current_mac_formats
;
200 /**************************************************************************
201 * Internal Clipboard implementation methods
202 **************************************************************************/
205 * format_list functions
208 /**************************************************************************
211 const char *debugstr_format(UINT id
)
215 if (GetClipboardFormatNameW(id
, buffer
, 256))
216 return wine_dbg_sprintf("0x%04x %s", id
, debugstr_w(buffer
));
220 #define BUILTIN(id) case id: return #id;
223 BUILTIN(CF_METAFILEPICT
)
233 BUILTIN(CF_UNICODETEXT
)
234 BUILTIN(CF_ENHMETAFILE
)
238 BUILTIN(CF_OWNERDISPLAY
)
240 BUILTIN(CF_DSPBITMAP
)
241 BUILTIN(CF_DSPMETAFILEPICT
)
242 BUILTIN(CF_DSPENHMETAFILE
)
244 default: return wine_dbg_sprintf("0x%04x", id
);
249 /**************************************************************************
250 * insert_clipboard_format
252 static WINE_CLIPFORMAT
*insert_clipboard_format(UINT id
, CFStringRef type
)
254 WINE_CLIPFORMAT
*format
;
256 format
= HeapAlloc(GetProcessHeap(), 0, sizeof(*format
));
260 WARN("No more memory for a new format!\n");
263 format
->format_id
= id
;
264 format
->import_func
= import_clipboard_data
;
265 format
->export_func
= export_clipboard_data
;
266 format
->synthesized
= FALSE
;
267 format
->natural_format
= NULL
;
270 format
->type
= CFStringCreateCopy(NULL
, type
);
275 if (!GetClipboardFormatNameW(format
->format_id
, buffer
, sizeof(buffer
) / sizeof(buffer
[0])))
277 WARN("failed to get name for format %s; error 0x%08x\n", debugstr_format(format
->format_id
), GetLastError());
278 HeapFree(GetProcessHeap(), 0, format
);
282 format
->type
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%S"),
283 registered_name_type_prefix
, buffer
);
286 list_add_tail(&format_list
, &format
->entry
);
288 TRACE("Registering format %s type %s\n", debugstr_format(format
->format_id
),
289 debugstr_cf(format
->type
));
295 /**************************************************************************
298 * Register a custom Mac clipboard format.
300 static WINE_CLIPFORMAT
* register_format(UINT id
, CFStringRef type
)
302 WINE_CLIPFORMAT
*format
;
304 /* walk format chain to see if it's already registered */
305 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
306 if (format
->format_id
== id
) return format
;
308 return insert_clipboard_format(id
, type
);
312 /**************************************************************************
313 * natural_format_for_format
315 * Find the "natural" format for this format_id (the one which isn't
316 * synthesized from another type).
318 static WINE_CLIPFORMAT
* natural_format_for_format(UINT format_id
)
320 WINE_CLIPFORMAT
*format
;
322 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
323 if (format
->format_id
== format_id
&& !format
->synthesized
) break;
325 if (&format
->entry
== &format_list
)
328 TRACE("%s -> %p/%s\n", debugstr_format(format_id
), format
, debugstr_cf(format
? format
->type
: NULL
));
333 /**************************************************************************
334 * register_builtin_formats
336 static void register_builtin_formats(void)
339 WINE_CLIPFORMAT
*format
;
341 /* Register built-in formats */
342 for (i
= 0; i
< sizeof(builtin_format_ids
)/sizeof(builtin_format_ids
[0]); i
++)
344 if (!(format
= HeapAlloc(GetProcessHeap(), 0, sizeof(*format
)))) break;
345 format
->format_id
= builtin_format_ids
[i
].id
;
346 format
->type
= CFRetain(builtin_format_ids
[i
].type
);
347 format
->import_func
= builtin_format_ids
[i
].import
;
348 format
->export_func
= builtin_format_ids
[i
].export
;
349 format
->synthesized
= builtin_format_ids
[i
].synthesized
;
350 format
->natural_format
= NULL
;
351 list_add_tail(&format_list
, &format
->entry
);
354 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
356 if (format
->synthesized
)
357 format
->natural_format
= natural_format_for_format(format
->format_id
);
360 /* Register known mappings between Windows formats and Mac types */
361 for (i
= 0; i
< sizeof(builtin_format_names
)/sizeof(builtin_format_names
[0]); i
++)
363 if (!(format
= HeapAlloc(GetProcessHeap(), 0, sizeof(*format
)))) break;
364 format
->format_id
= RegisterClipboardFormatW(builtin_format_names
[i
].name
);
365 format
->type
= CFRetain(builtin_format_names
[i
].type
);
366 format
->import_func
= builtin_format_names
[i
].import
;
367 format
->export_func
= builtin_format_names
[i
].export
;
368 format
->synthesized
= FALSE
;
369 format
->natural_format
= NULL
;
370 list_add_tail(&format_list
, &format
->entry
);
375 /**************************************************************************
378 static WINE_CLIPFORMAT
* format_for_type(CFStringRef type
)
380 WINE_CLIPFORMAT
*format
;
382 TRACE("type %s\n", debugstr_cf(type
));
384 if (list_empty(&format_list
)) register_builtin_formats();
386 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
388 if (CFEqual(format
->type
, type
))
393 if (CFStringHasPrefix(type
, CFSTR("org.winehq.builtin.")))
395 ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
398 else if (CFStringHasPrefix(type
, registered_name_type_prefix
))
401 int len
= CFStringGetLength(type
) - CFStringGetLength(registered_name_type_prefix
);
403 name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
404 CFStringGetCharacters(type
, CFRangeMake(CFStringGetLength(registered_name_type_prefix
), len
),
408 format
= register_format(RegisterClipboardFormatW(name
), type
);
410 ERR("Failed to register format for type %s name %s\n", debugstr_cf(type
), debugstr_w(name
));
412 HeapFree(GetProcessHeap(), 0, name
);
416 TRACE(" -> %p/%s\n", format
, debugstr_format(format
? format
->format_id
: 0));
421 /***********************************************************************
424 * Return the size of the bitmap info structure including color table.
426 static int bitmap_info_size(const BITMAPINFO
*info
, WORD coloruse
)
428 unsigned int colors
, size
, masks
= 0;
430 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
432 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
433 colors
= (core
->bcBitCount
<= 8) ? 1 << core
->bcBitCount
: 0;
434 return sizeof(BITMAPCOREHEADER
) + colors
*
435 ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBTRIPLE
) : sizeof(WORD
));
437 else /* assume BITMAPINFOHEADER */
439 colors
= MIN(info
->bmiHeader
.biClrUsed
, 256);
440 if (!colors
&& (info
->bmiHeader
.biBitCount
<= 8))
441 colors
= 1 << info
->bmiHeader
.biBitCount
;
442 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
) masks
= 3;
443 size
= max(info
->bmiHeader
.biSize
, sizeof(BITMAPINFOHEADER
) + masks
* sizeof(DWORD
));
444 return size
+ colors
* ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBQUAD
) : sizeof(WORD
));
449 /***********************************************************************
450 * create_dib_from_bitmap
452 * Allocates a packed DIB and copies the bitmap data into it.
454 static HGLOBAL
create_dib_from_bitmap(HBITMAP bitmap
)
457 BITMAPINFOHEADER header
;
462 memset(&header
, 0, sizeof(header
));
463 header
.biSize
= sizeof(header
);
464 if (!GetDIBits(hdc
, bitmap
, 0, 0, NULL
, (BITMAPINFO
*)&header
, DIB_RGB_COLORS
)) goto done
;
466 header_size
= bitmap_info_size((BITMAPINFO
*)&header
, DIB_RGB_COLORS
);
467 if (!(ret
= GlobalAlloc(GMEM_FIXED
, header_size
+ header
.biSizeImage
))) goto done
;
468 bmi
= (BITMAPINFO
*)ret
;
469 memset(bmi
, 0, header_size
);
470 memcpy(bmi
, &header
, header
.biSize
);
471 GetDIBits(hdc
, bitmap
, 0, abs(header
.biHeight
), (char *)bmi
+ header_size
, bmi
, DIB_RGB_COLORS
);
479 /**************************************************************************
480 * create_bitmap_from_dib
482 * Given a packed DIB, creates a bitmap object from it.
484 static HANDLE
create_bitmap_from_dib(HANDLE dib
)
489 if (dib
&& (bmi
= GlobalLock(dib
)))
496 offset
= bitmap_info_size(bmi
, DIB_RGB_COLORS
);
498 ret
= CreateDIBitmap(hdc
, &bmi
->bmiHeader
, CBM_INIT
, (LPBYTE
)bmi
+ offset
,
499 bmi
, DIB_RGB_COLORS
);
502 ReleaseDC(NULL
, hdc
);
509 /**************************************************************************
510 * import_clipboard_data
512 * Generic import clipboard data routine.
514 static HANDLE
import_clipboard_data(CFDataRef data
)
516 HANDLE data_handle
= NULL
;
518 size_t len
= CFDataGetLength(data
);
523 /* Turn on the DDESHARE flag to enable shared 32 bit memory */
524 data_handle
= GlobalAlloc(GMEM_FIXED
, len
);
528 if ((p
= GlobalLock(data_handle
)))
530 memcpy(p
, CFDataGetBytePtr(data
), len
);
531 GlobalUnlock(data_handle
);
535 GlobalFree(data_handle
);
544 /**************************************************************************
545 * import_bmp_to_bitmap
547 * Import BMP data, converting to CF_BITMAP format.
549 static HANDLE
import_bmp_to_bitmap(CFDataRef data
)
552 HANDLE dib
= import_bmp_to_dib(data
);
554 ret
= create_bitmap_from_dib(dib
);
561 /**************************************************************************
564 * Import BMP data, converting to CF_DIB or CF_DIBV5 format. This just
565 * entails stripping the BMP file format header.
567 static HANDLE
import_bmp_to_dib(CFDataRef data
)
570 BITMAPFILEHEADER
*bfh
= (BITMAPFILEHEADER
*)CFDataGetBytePtr(data
);
571 CFIndex len
= CFDataGetLength(data
);
573 if (len
>= sizeof(*bfh
) + sizeof(BITMAPCOREHEADER
) &&
574 bfh
->bfType
== 0x4d42 /* "BM" */)
576 BITMAPINFO
*bmi
= (BITMAPINFO
*)(bfh
+ 1);
580 ret
= GlobalAlloc(GMEM_FIXED
, len
);
581 if (!ret
|| !(p
= GlobalLock(ret
)))
595 /**************************************************************************
598 * Import enhanced metafile data, converting it to CF_ENHMETAFILE.
600 static HANDLE
import_enhmetafile(CFDataRef data
)
603 CFIndex len
= CFDataGetLength(data
);
605 TRACE("data %s\n", debugstr_cf(data
));
608 ret
= SetEnhMetaFileBits(len
, (const BYTE
*)CFDataGetBytePtr(data
));
614 /**************************************************************************
615 * import_metafilepict
617 * Import metafile picture data, converting it to CF_METAFILEPICT.
619 static HANDLE
import_metafilepict(CFDataRef data
)
622 CFIndex len
= CFDataGetLength(data
);
625 TRACE("data %s\n", debugstr_cf(data
));
627 if (len
>= sizeof(*mfp
) && (ret
= GlobalAlloc(GMEM_FIXED
, sizeof(*mfp
))))
629 const BYTE
*bytes
= (const BYTE
*)CFDataGetBytePtr(data
);
631 mfp
= GlobalLock(ret
);
632 memcpy(mfp
, bytes
, sizeof(*mfp
));
633 mfp
->hMF
= SetMetaFileBitsEx(len
- sizeof(*mfp
), bytes
+ sizeof(*mfp
));
641 /**************************************************************************
642 * import_nsfilenames_to_hdrop
644 * Import NSFilenamesPboardType data, converting the property-list-
645 * serialized array of path strings to CF_HDROP.
647 static HANDLE
import_nsfilenames_to_hdrop(CFDataRef data
)
654 WCHAR
**paths
= NULL
;
655 DROPFILES
* dropfiles
;
658 TRACE("data %s\n", debugstr_cf(data
));
660 names
= (CFArrayRef
)CFPropertyListCreateWithData(NULL
, data
, kCFPropertyListImmutable
,
662 if (!names
|| CFGetTypeID(names
) != CFArrayGetTypeID())
664 WARN("failed to interpret data as a CFArray\n");
668 count
= CFArrayGetCount(names
);
671 for (i
= 0; i
< count
; i
++)
674 CFStringRef name
= (CFStringRef
)CFArrayGetValueAtIndex(names
, i
);
675 TRACE(" %s\n", debugstr_cf(name
));
676 if (CFGetTypeID(name
) != CFStringGetTypeID())
678 WARN("non-string in array\n");
682 this_len
= CFStringGetMaximumSizeOfFileSystemRepresentation(name
);
687 buffer
= HeapAlloc(GetProcessHeap(), 0, len
);
690 WARN("failed to allocate buffer for file-system representations\n");
694 paths
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, count
* sizeof(paths
[0]));
697 WARN("failed to allocate array of DOS paths\n");
701 for (i
= 0; i
< count
; i
++)
703 CFStringRef name
= (CFStringRef
)CFArrayGetValueAtIndex(names
, i
);
704 if (!CFStringGetFileSystemRepresentation(name
, buffer
, len
))
706 WARN("failed to get file-system representation for %s\n", debugstr_cf(name
));
709 paths
[i
] = wine_get_dos_file_name(buffer
);
712 WARN("failed to get DOS path for %s\n", debugstr_a(buffer
));
717 len
= 1; /* for the terminating null */
718 for (i
= 0; i
< count
; i
++)
719 len
+= strlenW(paths
[i
]) + 1;
721 hdrop
= GlobalAlloc(GMEM_FIXED
, sizeof(*dropfiles
) + len
* sizeof(WCHAR
));
722 if (!hdrop
|| !(dropfiles
= GlobalLock(hdrop
)))
724 WARN("failed to allocate HDROP\n");
730 dropfiles
->pFiles
= sizeof(*dropfiles
);
733 dropfiles
->fNC
= FALSE
;
734 dropfiles
->fWide
= TRUE
;
736 p
= (WCHAR
*)(dropfiles
+ 1);
737 for (i
= 0; i
< count
; i
++)
739 strcpyW(p
, paths
[i
]);
749 for (i
= 0; i
< count
; i
++)
750 HeapFree(GetProcessHeap(), 0, paths
[i
]);
751 HeapFree(GetProcessHeap(), 0, paths
);
753 HeapFree(GetProcessHeap(), 0, buffer
);
754 if (names
) CFRelease(names
);
759 /**************************************************************************
760 * import_utf8_to_text
762 * Import a UTF-8 string, converting the string to CF_TEXT.
764 static HANDLE
import_utf8_to_text(CFDataRef data
)
767 HANDLE unicode_handle
= import_utf8_to_unicodetext(data
);
768 LPWSTR unicode_string
= GlobalLock(unicode_handle
);
777 unicode_len
= GlobalSize(unicode_handle
) / sizeof(WCHAR
);
779 len
= WideCharToMultiByte(CP_ACP
, 0, unicode_string
, unicode_len
, NULL
, 0, NULL
, NULL
);
780 if (!unicode_len
|| unicode_string
[unicode_len
- 1]) len
+= 1;
781 handle
= GlobalAlloc(GMEM_FIXED
, len
);
783 if (handle
&& (p
= GlobalLock(handle
)))
785 WideCharToMultiByte(CP_ACP
, 0, unicode_string
, unicode_len
, p
, len
, NULL
, NULL
);
787 GlobalUnlock(handle
);
790 GlobalUnlock(unicode_handle
);
793 GlobalFree(unicode_handle
);
798 /**************************************************************************
799 * import_utf8_to_unicodetext
801 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
803 static HANDLE
import_utf8_to_unicodetext(CFDataRef data
)
806 unsigned long src_len
;
807 unsigned long new_lines
= 0;
810 HANDLE unicode_handle
= NULL
;
812 src
= CFDataGetBytePtr(data
);
813 src_len
= CFDataGetLength(data
);
814 for (i
= 0; i
< src_len
; i
++)
820 if ((dst
= HeapAlloc(GetProcessHeap(), 0, src_len
+ new_lines
+ 1)))
824 for (i
= 0, j
= 0; i
< src_len
; i
++)
833 count
= MultiByteToWideChar(CP_UTF8
, 0, dst
, -1, NULL
, 0);
834 unicode_handle
= GlobalAlloc(GMEM_FIXED
, count
* sizeof(WCHAR
));
838 WCHAR
*textW
= GlobalLock(unicode_handle
);
839 MultiByteToWideChar(CP_UTF8
, 0, dst
, -1, textW
, count
);
840 GlobalUnlock(unicode_handle
);
843 HeapFree(GetProcessHeap(), 0, dst
);
846 return unicode_handle
;
850 /**************************************************************************
851 * import_utf16_to_unicodetext
853 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
855 static HANDLE
import_utf16_to_unicodetext(CFDataRef data
)
858 unsigned long src_len
;
859 unsigned long new_lines
= 0;
862 HANDLE unicode_handle
;
864 src
= (const WCHAR
*)CFDataGetBytePtr(data
);
865 src_len
= CFDataGetLength(data
) / sizeof(WCHAR
);
866 for (i
= 0; i
< src_len
; i
++)
870 else if (src
[i
] == '\r' && (i
+ 1 >= src_len
|| src
[i
+ 1] != '\n'))
874 if ((unicode_handle
= GlobalAlloc(GMEM_FIXED
, (src_len
+ new_lines
+ 1) * sizeof(WCHAR
))))
876 dst
= GlobalLock(unicode_handle
);
878 for (i
= 0, j
= 0; i
< src_len
; i
++)
885 if (src
[i
] == '\r' && (i
+ 1 >= src_len
|| src
[i
+ 1] != '\n'))
890 GlobalUnlock(unicode_handle
);
893 return unicode_handle
;
897 /**************************************************************************
898 * export_clipboard_data
900 * Generic export clipboard data routine.
902 static CFDataRef
export_clipboard_data(HANDLE data
)
908 len
= GlobalSize(data
);
909 src
= GlobalLock(data
);
910 if (!src
) return NULL
;
912 ret
= CFDataCreate(NULL
, src
, len
);
919 /**************************************************************************
920 * export_bitmap_to_bmp
922 * Export CF_BITMAP to BMP file format.
924 static CFDataRef
export_bitmap_to_bmp(HANDLE data
)
926 CFDataRef ret
= NULL
;
929 dib
= create_dib_from_bitmap(data
);
932 ret
= export_dib_to_bmp(dib
);
940 /**************************************************************************
943 * Export CF_DIB or CF_DIBV5 to BMP file format. This just entails
944 * prepending a BMP file format header to the data.
946 static CFDataRef
export_dib_to_bmp(HANDLE data
)
948 CFMutableDataRef ret
= NULL
;
951 BITMAPFILEHEADER bfh
;
953 dibdata
= GlobalLock(data
);
957 len
= sizeof(bfh
) + GlobalSize(data
);
958 ret
= CFDataCreateMutable(NULL
, len
);
961 bfh
.bfType
= 0x4d42; /* "BM" */
965 bfh
.bfOffBits
= sizeof(bfh
) + bitmap_info_size((BITMAPINFO
*)dibdata
, DIB_RGB_COLORS
);
966 CFDataAppendBytes(ret
, (UInt8
*)&bfh
, sizeof(bfh
));
968 /* rest of bitmap is the same as the packed dib */
969 CFDataAppendBytes(ret
, (UInt8
*)dibdata
, len
- sizeof(bfh
));
978 /**************************************************************************
981 * Export an enhanced metafile to data.
983 static CFDataRef
export_enhmetafile(HANDLE data
)
985 CFMutableDataRef ret
= NULL
;
986 unsigned int size
= GetEnhMetaFileBits(data
, 0, NULL
);
988 TRACE("data %p\n", data
);
990 ret
= CFDataCreateMutable(NULL
, size
);
993 CFDataSetLength(ret
, size
);
994 GetEnhMetaFileBits(data
, size
, (BYTE
*)CFDataGetMutableBytePtr(ret
));
997 TRACE(" -> %s\n", debugstr_cf(ret
));
1002 /**************************************************************************
1003 * export_hdrop_to_filenames
1005 * Export CF_HDROP to NSFilenamesPboardType data, which is a CFArray of
1006 * CFStrings (holding Unix paths) which is serialized as a property list.
1008 static CFDataRef
export_hdrop_to_filenames(HANDLE data
)
1010 CFDataRef ret
= NULL
;
1011 DROPFILES
*dropfiles
;
1012 CFMutableArrayRef filenames
= NULL
;
1014 WCHAR
*buffer
= NULL
;
1015 size_t buffer_len
= 0;
1017 TRACE("data %p\n", data
);
1019 if (!(dropfiles
= GlobalLock(data
)))
1021 WARN("failed to lock data %p\n", data
);
1025 filenames
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1028 WARN("failed to create filenames array\n");
1032 p
= (char*)dropfiles
+ dropfiles
->pFiles
;
1033 while (dropfiles
->fWide
? *(WCHAR
*)p
: *(char*)p
)
1036 CFStringRef filename
;
1038 TRACE(" %s\n", dropfiles
->fWide
? debugstr_w(p
) : debugstr_a(p
));
1040 if (dropfiles
->fWide
)
1041 unixname
= wine_get_unix_file_name(p
);
1044 int len
= MultiByteToWideChar(CP_ACP
, 0, p
, -1, NULL
, 0);
1047 if (len
> buffer_len
)
1049 HeapFree(GetProcessHeap(), 0, buffer
);
1050 buffer_len
= len
* 2;
1051 buffer
= HeapAlloc(GetProcessHeap(), 0, buffer_len
* sizeof(*buffer
));
1054 MultiByteToWideChar(CP_ACP
, 0, p
, -1, buffer
, buffer_len
);
1055 unixname
= wine_get_unix_file_name(buffer
);
1062 WARN("failed to convert DOS path to Unix: %s\n",
1063 dropfiles
->fWide
? debugstr_w(p
) : debugstr_a(p
));
1067 if (dropfiles
->fWide
)
1068 p
= (WCHAR
*)p
+ strlenW(p
) + 1;
1070 p
= (char*)p
+ strlen(p
) + 1;
1072 filename
= CFStringCreateWithFileSystemRepresentation(NULL
, unixname
);
1073 HeapFree(GetProcessHeap(), 0, unixname
);
1076 WARN("failed to create CFString from Unix path %s\n", debugstr_a(unixname
));
1080 CFArrayAppendValue(filenames
, filename
);
1081 CFRelease(filename
);
1084 ret
= CFPropertyListCreateData(NULL
, filenames
, kCFPropertyListXMLFormat_v1_0
, 0, NULL
);
1087 HeapFree(GetProcessHeap(), 0, buffer
);
1089 if (filenames
) CFRelease(filenames
);
1090 TRACE(" -> %s\n", debugstr_cf(ret
));
1095 /**************************************************************************
1096 * export_metafilepict
1098 * Export a metafile to data.
1100 static CFDataRef
export_metafilepict(HANDLE data
)
1102 CFMutableDataRef ret
= NULL
;
1103 METAFILEPICT
*mfp
= GlobalLock(data
);
1104 unsigned int size
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
1106 TRACE("data %p\n", data
);
1108 ret
= CFDataCreateMutable(NULL
, sizeof(*mfp
) + size
);
1111 CFDataAppendBytes(ret
, (UInt8
*)mfp
, sizeof(*mfp
));
1112 CFDataIncreaseLength(ret
, size
);
1113 GetMetaFileBitsEx(mfp
->hMF
, size
, (BYTE
*)CFDataGetMutableBytePtr(ret
) + sizeof(*mfp
));
1117 TRACE(" -> %s\n", debugstr_cf(ret
));
1122 /**************************************************************************
1123 * export_text_to_utf8
1125 * Export CF_TEXT to UTF-8.
1127 static CFDataRef
export_text_to_utf8(HANDLE data
)
1129 CFDataRef ret
= NULL
;
1132 if ((str
= GlobalLock(data
)))
1134 int str_len
= GlobalSize(data
);
1140 wstr_len
= MultiByteToWideChar(CP_ACP
, 0, str
, str_len
, NULL
, 0);
1141 if (!str_len
|| str
[str_len
- 1]) wstr_len
+= 1;
1142 wstr
= HeapAlloc(GetProcessHeap(), 0, wstr_len
* sizeof(WCHAR
));
1143 MultiByteToWideChar(CP_ACP
, 0, str
, str_len
, wstr
, wstr_len
);
1144 wstr
[wstr_len
- 1] = 0;
1146 unicode
= GlobalAlloc(GMEM_FIXED
, wstr_len
* sizeof(WCHAR
));
1147 if (unicode
&& (p
= GlobalLock(unicode
)))
1149 memcpy(p
, wstr
, wstr_len
* sizeof(WCHAR
));
1150 GlobalUnlock(unicode
);
1153 ret
= export_unicodetext_to_utf8(unicode
);
1155 GlobalFree(unicode
);
1163 /**************************************************************************
1164 * export_unicodetext_to_utf8
1166 * Export CF_UNICODETEXT to UTF-8.
1168 static CFDataRef
export_unicodetext_to_utf8(HANDLE data
)
1170 CFMutableDataRef ret
;
1174 src
= GlobalLock(data
);
1175 if (!src
) return NULL
;
1177 dst_len
= WideCharToMultiByte(CP_UTF8
, 0, src
, -1, NULL
, 0, NULL
, NULL
);
1178 if (dst_len
) dst_len
--; /* Leave off null terminator. */
1179 ret
= CFDataCreateMutable(NULL
, dst_len
);
1185 CFDataSetLength(ret
, dst_len
);
1186 dst
= (LPSTR
)CFDataGetMutableBytePtr(ret
);
1187 WideCharToMultiByte(CP_UTF8
, 0, src
, -1, dst
, dst_len
, NULL
, NULL
);
1189 /* Remove carriage returns */
1190 for (i
= 0, j
= 0; i
< dst_len
; i
++)
1192 if (dst
[i
] == '\r' &&
1193 (i
+ 1 >= dst_len
|| dst
[i
+ 1] == '\n' || dst
[i
+ 1] == '\0'))
1197 CFDataSetLength(ret
, j
);
1205 /**************************************************************************
1206 * export_unicodetext_to_utf16
1208 * Export CF_UNICODETEXT to UTF-16.
1210 static CFDataRef
export_unicodetext_to_utf16(HANDLE data
)
1212 CFMutableDataRef ret
;
1216 src
= GlobalLock(data
);
1217 if (!src
) return NULL
;
1219 src_len
= GlobalSize(data
) / sizeof(WCHAR
);
1220 if (src_len
) src_len
--; /* Leave off null terminator. */
1221 ret
= CFDataCreateMutable(NULL
, src_len
* sizeof(WCHAR
));
1227 CFDataSetLength(ret
, src_len
* sizeof(WCHAR
));
1228 dst
= (LPWSTR
)CFDataGetMutableBytePtr(ret
);
1230 /* Remove carriage returns */
1231 for (i
= 0, j
= 0; i
< src_len
; i
++)
1233 if (src
[i
] == '\r' &&
1234 (i
+ 1 >= src_len
|| src
[i
+ 1] == '\n' || src
[i
+ 1] == '\0'))
1238 CFDataSetLength(ret
, j
* sizeof(WCHAR
));
1246 /**************************************************************************
1247 * macdrv_get_pasteboard_data
1249 HANDLE
macdrv_get_pasteboard_data(CFTypeRef pasteboard
, UINT desired_format
)
1254 CFStringRef type
, best_type
;
1255 WINE_CLIPFORMAT
* best_format
= NULL
;
1258 TRACE("pasteboard %p, desired_format %s\n", pasteboard
, debugstr_format(desired_format
));
1260 types
= macdrv_copy_pasteboard_types(pasteboard
);
1263 WARN("Failed to copy pasteboard types\n");
1267 count
= CFArrayGetCount(types
);
1268 TRACE("got %ld types\n", count
);
1270 for (i
= 0; (!best_format
|| best_format
->synthesized
) && i
< count
; i
++)
1272 WINE_CLIPFORMAT
* format
;
1274 type
= CFArrayGetValueAtIndex(types
, i
);
1276 if ((format
= format_for_type(type
)))
1278 TRACE("for type %s got format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1280 if (format
->format_id
== desired_format
)
1282 /* The best format is the matching one which is not synthesized. Failing that,
1283 the best format is the first matching synthesized format. */
1284 if (!format
->synthesized
|| !best_format
)
1287 best_format
= format
;
1295 CFDataRef pasteboard_data
= macdrv_copy_pasteboard_data(pasteboard
, best_type
);
1297 TRACE("got pasteboard data for type %s: %s\n", debugstr_cf(best_type
), debugstr_cf(pasteboard_data
));
1299 if (pasteboard_data
)
1301 data
= best_format
->import_func(pasteboard_data
);
1302 CFRelease(pasteboard_data
);
1307 TRACE(" -> %p\n", data
);
1312 /**************************************************************************
1313 * macdrv_pasteboard_has_format
1315 BOOL
macdrv_pasteboard_has_format(CFTypeRef pasteboard
, UINT desired_format
)
1322 TRACE("pasteboard %p, desired_format %s\n", pasteboard
, debugstr_format(desired_format
));
1324 types
= macdrv_copy_pasteboard_types(pasteboard
);
1327 WARN("Failed to copy pasteboard types\n");
1331 count
= CFArrayGetCount(types
);
1332 TRACE("got %d types\n", count
);
1334 for (i
= 0; i
< count
; i
++)
1336 CFStringRef type
= CFArrayGetValueAtIndex(types
, i
);
1337 WINE_CLIPFORMAT
* format
= format_for_type(type
);
1341 TRACE("for type %s got format %s\n", debugstr_cf(type
), debugstr_format(format
->format_id
));
1343 if (format
->format_id
== desired_format
)
1352 TRACE(" -> %d\n", found
);
1357 /**************************************************************************
1358 * get_formats_for_pasteboard
1360 static WINE_CLIPFORMAT
** get_formats_for_pasteboard(CFTypeRef pasteboard
, UINT
*num_formats
)
1364 CFMutableSetRef seen_formats
;
1365 WINE_CLIPFORMAT
** formats
;
1368 TRACE("pasteboard %s\n", debugstr_cf(pasteboard
));
1370 types
= macdrv_copy_pasteboard_types(pasteboard
);
1373 WARN("Failed to copy pasteboard types\n");
1377 count
= CFArrayGetCount(types
);
1378 TRACE("got %ld types\n", count
);
1386 seen_formats
= CFSetCreateMutable(NULL
, count
, NULL
);
1389 WARN("Failed to allocate seen formats set\n");
1394 formats
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(*formats
));
1397 WARN("Failed to allocate formats array\n");
1399 CFRelease(seen_formats
);
1404 for (i
= 0; i
< count
; i
++)
1406 CFStringRef type
= CFArrayGetValueAtIndex(types
, i
);
1407 WINE_CLIPFORMAT
* format
= format_for_type(type
);
1411 TRACE("ignoring type %s\n", debugstr_cf(type
));
1415 if (!format
->synthesized
)
1417 TRACE("for type %s got format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1418 CFSetAddValue(seen_formats
, (void*)format
->format_id
);
1419 formats
[pos
++] = format
;
1421 else if (format
->natural_format
&&
1422 CFArrayContainsValue(types
, CFRangeMake(0, count
), format
->natural_format
->type
))
1424 TRACE("for type %s deferring synthesized formats because type %s is also present\n",
1425 debugstr_cf(type
), debugstr_cf(format
->natural_format
->type
));
1427 else if (CFSetContainsValue(seen_formats
, (void*)format
->format_id
))
1429 TRACE("for type %s got duplicate synthesized format %p/%s; skipping\n", debugstr_cf(type
), format
,
1430 debugstr_format(format
->format_id
));
1434 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1435 CFSetAddValue(seen_formats
, (void*)format
->format_id
);
1436 formats
[pos
++] = format
;
1440 /* Now go back through the types adding the synthesized formats that we deferred before. */
1441 for (i
= 0; i
< count
; i
++)
1443 CFStringRef type
= CFArrayGetValueAtIndex(types
, i
);
1444 WINE_CLIPFORMAT
* format
= format_for_type(type
);
1446 if (!format
) continue;
1447 if (!format
->synthesized
) continue;
1449 /* Don't duplicate a real value with a synthesized value. */
1450 if (CFSetContainsValue(seen_formats
, (void*)format
->format_id
)) continue;
1452 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1453 CFSetAddValue(seen_formats
, (void*)format
->format_id
);
1454 formats
[pos
++] = format
;
1458 CFRelease(seen_formats
);
1462 HeapFree(GetProcessHeap(), 0, formats
);
1471 /**************************************************************************
1472 * macdrv_get_pasteboard_formats
1474 UINT
* macdrv_get_pasteboard_formats(CFTypeRef pasteboard
, UINT
* num_formats
)
1476 WINE_CLIPFORMAT
** formats
;
1480 formats
= get_formats_for_pasteboard(pasteboard
, &count
);
1484 format_ids
= HeapAlloc(GetProcessHeap(), 0, count
);
1487 WARN("Failed to allocate formats IDs array\n");
1488 HeapFree(GetProcessHeap(), 0, formats
);
1492 for (i
= 0; i
< count
; i
++)
1493 format_ids
[i
] = formats
[i
]->format_id
;
1495 HeapFree(GetProcessHeap(), 0, formats
);
1497 *num_formats
= count
;
1502 /**************************************************************************
1503 * register_win32_formats
1505 * Register Win32 clipboard formats the first time we encounter them.
1507 static void register_win32_formats(const UINT
*ids
, UINT size
)
1511 if (list_empty(&format_list
)) register_builtin_formats();
1513 for (i
= 0; i
< size
; i
++)
1514 register_format(ids
[i
], NULL
);
1518 /***********************************************************************
1519 * get_clipboard_formats
1521 * Return a list of all formats currently available on the Win32 clipboard.
1522 * Helper for set_mac_pasteboard_types_from_win32_clipboard.
1524 static UINT
*get_clipboard_formats(UINT
*size
)
1531 if (!(ids
= HeapAlloc(GetProcessHeap(), 0, *size
* sizeof(*ids
)))) return NULL
;
1532 if (GetUpdatedClipboardFormats(ids
, *size
, size
)) break;
1533 HeapFree(GetProcessHeap(), 0, ids
);
1534 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return NULL
;
1536 register_win32_formats(ids
, *size
);
1541 /**************************************************************************
1542 * set_mac_pasteboard_types_from_win32_clipboard
1544 static void set_mac_pasteboard_types_from_win32_clipboard(void)
1546 WINE_CLIPFORMAT
*format
;
1547 UINT count
, i
, *formats
;
1549 if (!(formats
= get_clipboard_formats(&count
))) return;
1551 macdrv_clear_pasteboard();
1553 for (i
= 0; i
< count
; i
++)
1555 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
1557 if (format
->format_id
!= formats
[i
]) continue;
1558 TRACE("%s -> %s\n", debugstr_format(format
->format_id
), debugstr_cf(format
->type
));
1559 macdrv_set_pasteboard_data(format
->type
, NULL
, clipboard_cocoa_window
);
1563 HeapFree(GetProcessHeap(), 0, formats
);
1568 /**************************************************************************
1569 * set_win32_clipboard_formats_from_mac_pasteboard
1571 static void set_win32_clipboard_formats_from_mac_pasteboard(void)
1573 WINE_CLIPFORMAT
** formats
;
1576 formats
= get_formats_for_pasteboard(NULL
, &count
);
1580 for (i
= 0; i
< count
; i
++)
1582 TRACE("adding format %s\n", debugstr_format(formats
[i
]->format_id
));
1583 SetClipboardData(formats
[i
]->format_id
, 0);
1586 HeapFree(GetProcessHeap(), 0, current_mac_formats
);
1587 current_mac_formats
= formats
;
1588 nb_current_mac_formats
= count
;
1592 /**************************************************************************
1595 static void render_format(UINT id
)
1599 for (i
= 0; i
< nb_current_mac_formats
; i
++)
1601 CFDataRef pasteboard_data
;
1603 if (current_mac_formats
[i
]->format_id
!= id
) continue;
1605 pasteboard_data
= macdrv_copy_pasteboard_data(NULL
, current_mac_formats
[i
]->type
);
1606 if (pasteboard_data
)
1608 HANDLE handle
= current_mac_formats
[i
]->import_func(pasteboard_data
);
1609 CFRelease(pasteboard_data
);
1610 if (handle
) SetClipboardData(id
, handle
);
1617 /**************************************************************************
1618 * grab_win32_clipboard
1620 * Grab the Win32 clipboard when a Mac app has taken ownership of the
1621 * pasteboard, and fill it with the pasteboard data types.
1623 static BOOL
grab_win32_clipboard(void)
1625 if (!OpenClipboard(clipboard_hwnd
)) return FALSE
;
1627 is_clipboard_owner
= TRUE
;
1628 last_clipboard_update
= GetTickCount64();
1629 set_win32_clipboard_formats_from_mac_pasteboard();
1635 /**************************************************************************
1638 * Window procedure for the clipboard manager.
1640 static LRESULT CALLBACK
clipboard_wndproc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1646 case WM_CLIPBOARDUPDATE
:
1647 if (is_clipboard_owner
) break; /* ignore our own changes */
1648 set_mac_pasteboard_types_from_win32_clipboard();
1650 case WM_RENDERFORMAT
:
1653 case WM_DESTROYCLIPBOARD
:
1654 TRACE("WM_DESTROYCLIPBOARD: lost ownership\n");
1655 is_clipboard_owner
= FALSE
;
1658 return DefWindowProcW(hwnd
, msg
, wp
, lp
);
1662 /**************************************************************************
1663 * wait_clipboard_mutex
1665 * Make sure that there's only one clipboard thread per window station.
1667 static BOOL
wait_clipboard_mutex(void)
1669 static const WCHAR prefix
[] = {'_','_','w','i','n','e','_','c','l','i','p','b','o','a','r','d','_'};
1670 WCHAR buffer
[MAX_PATH
+ sizeof(prefix
) / sizeof(WCHAR
)];
1673 memcpy(buffer
, prefix
, sizeof(prefix
));
1674 if (!GetUserObjectInformationW(GetProcessWindowStation(), UOI_NAME
,
1675 buffer
+ sizeof(prefix
) / sizeof(WCHAR
),
1676 sizeof(buffer
) - sizeof(prefix
), NULL
))
1678 ERR("failed to get winstation name\n");
1681 mutex
= CreateMutexW(NULL
, TRUE
, buffer
);
1682 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1684 TRACE("waiting for mutex %s\n", debugstr_w(buffer
));
1685 WaitForSingleObject(mutex
, INFINITE
);
1691 /**************************************************************************
1694 * Thread running inside the desktop process to manage the clipboard
1696 static DWORD WINAPI
clipboard_thread(void *arg
)
1698 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};
1700 struct macdrv_window_features wf
;
1703 if (!wait_clipboard_mutex()) return 0;
1705 memset(&class, 0, sizeof(class));
1706 class.lpfnWndProc
= clipboard_wndproc
;
1707 class.lpszClassName
= clipboard_classname
;
1709 if (!RegisterClassW(&class) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS
)
1711 ERR("could not register clipboard window class err %u\n", GetLastError());
1714 if (!(clipboard_hwnd
= CreateWindowW(clipboard_classname
, NULL
, 0, 0, 0, 0, 0,
1715 HWND_MESSAGE
, 0, 0, NULL
)))
1717 ERR("failed to create clipboard window err %u\n", GetLastError());
1721 memset(&wf
, 0, sizeof(wf
));
1722 clipboard_cocoa_window
= macdrv_create_cocoa_window(&wf
, CGRectMake(100, 100, 100, 100), clipboard_hwnd
,
1723 macdrv_init_thread_data()->queue
);
1724 if (!clipboard_cocoa_window
)
1726 ERR("failed to create clipboard Cocoa window\n");
1730 clipboard_thread_id
= GetCurrentThreadId();
1731 AddClipboardFormatListener(clipboard_hwnd
);
1732 register_builtin_formats();
1733 grab_win32_clipboard();
1735 TRACE("clipboard thread %04x running\n", GetCurrentThreadId());
1736 while (GetMessageW(&msg
, NULL
, 0, 0))
1737 DispatchMessageW(&msg
);
1740 macdrv_destroy_cocoa_window(clipboard_cocoa_window
);
1741 DestroyWindow(clipboard_hwnd
);
1746 /**************************************************************************
1747 * Mac User Driver Clipboard Exports
1748 **************************************************************************/
1751 /**************************************************************************
1752 * MACDRV Private Clipboard Exports
1753 **************************************************************************/
1756 /**************************************************************************
1757 * query_pasteboard_data
1759 BOOL
query_pasteboard_data(HWND hwnd
, CFStringRef type
)
1761 WINE_CLIPFORMAT
*format
;
1765 TRACE("win %p/%p type %s\n", hwnd
, clipboard_cocoa_window
, debugstr_cf(type
));
1767 format
= format_for_type(type
);
1768 if (!format
) return FALSE
;
1770 if (!OpenClipboard(clipboard_hwnd
))
1772 ERR("failed to open clipboard for %s\n", debugstr_cf(type
));
1776 if ((handle
= GetClipboardData(format
->format_id
)))
1780 TRACE("exporting %s %p\n", debugstr_format(format
->format_id
), handle
);
1782 if ((data
= format
->export_func(handle
)))
1784 ret
= macdrv_set_pasteboard_data(format
->type
, data
, clipboard_cocoa_window
);
1795 /**************************************************************************
1796 * macdrv_init_clipboard
1798 void macdrv_init_clipboard(void)
1801 HANDLE handle
= CreateThread(NULL
, 0, clipboard_thread
, NULL
, 0, &id
);
1803 if (handle
) CloseHandle(handle
);
1804 else ERR("failed to create clipboard thread\n");