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 **************************************************************************/
62 #define CLIPBOARD_UPDATE_DELAY 2000 /* delay between checks of the Mac pasteboard */
65 /**************************************************************************
66 * Forward Function Declarations
67 **************************************************************************/
69 static HANDLE
import_clipboard_data(CFDataRef data
);
70 static HANDLE
import_bmp_to_bitmap(CFDataRef data
);
71 static HANDLE
import_bmp_to_dib(CFDataRef data
);
72 static HANDLE
import_enhmetafile(CFDataRef data
);
73 static HANDLE
import_html(CFDataRef data
);
74 static HANDLE
import_metafilepict(CFDataRef data
);
75 static HANDLE
import_nsfilenames_to_hdrop(CFDataRef data
);
76 static HANDLE
import_utf8_to_text(CFDataRef data
);
77 static HANDLE
import_utf8_to_unicodetext(CFDataRef data
);
78 static HANDLE
import_utf16_to_unicodetext(CFDataRef data
);
80 static CFDataRef
export_clipboard_data(HANDLE data
);
81 static CFDataRef
export_bitmap_to_bmp(HANDLE data
);
82 static CFDataRef
export_dib_to_bmp(HANDLE data
);
83 static CFDataRef
export_enhmetafile(HANDLE data
);
84 static CFDataRef
export_hdrop_to_filenames(HANDLE data
);
85 static CFDataRef
export_html(HANDLE data
);
86 static CFDataRef
export_metafilepict(HANDLE data
);
87 static CFDataRef
export_text_to_utf8(HANDLE data
);
88 static CFDataRef
export_unicodetext_to_utf8(HANDLE data
);
89 static CFDataRef
export_unicodetext_to_utf16(HANDLE data
);
92 /**************************************************************************
94 **************************************************************************/
96 /* Clipboard formats */
97 static struct list format_list
= LIST_INIT(format_list
);
99 /* There are two naming schemes involved and we want to have a mapping between
100 them. There are Win32 clipboard format names and there are Mac pasteboard
103 The Win32 standard clipboard formats don't have names, but they are associated
104 with Mac pasteboard types through the following tables, which are used to
105 initialize the format_list. Where possible, the standard clipboard formats
106 are mapped to predefined pasteboard type UTIs. Otherwise, we create Wine-
107 specific types of the form "org.winehq.builtin.<format>", where <format> is
108 the name of the symbolic constant for the format minus "CF_" and lowercased.
109 E.g. CF_BITMAP -> org.winehq.builtin.bitmap.
111 Win32 clipboard formats which originate in a Windows program may be registered
112 with an arbitrary name. We construct a Mac pasteboard type from these by
113 prepending "org.winehq.registered." to the registered name.
115 Likewise, Mac pasteboard types which originate in other apps may have
116 arbitrary type strings. We ignore these.
119 Win32 clipboard format names:
120 <none> standard clipboard format; maps via
121 format_list to either a predefined Mac UTI
122 or org.winehq.builtin.<format>.
123 <other> name registered within Win32 land; maps to
124 org.winehq.registered.<other>
125 Mac pasteboard type names:
126 org.winehq.builtin.<format ID> representation of Win32 standard clipboard
127 format for which there was no corresponding
128 predefined Mac UTI; maps via format_list
129 org.winehq.registered.<format name> representation of Win32 registered
130 clipboard format name; maps to <format name>
131 <other> Mac pasteboard type originating with system
132 or other apps; either maps via format_list
133 to a standard clipboard format or ignored
140 DRVIMPORTFUNC import
;
141 DRVEXPORTFUNC export
;
143 } builtin_format_ids
[] =
145 { CF_BITMAP
, CFSTR("org.winehq.builtin.bitmap"), import_bmp_to_bitmap
, export_bitmap_to_bmp
, FALSE
},
146 { CF_DIBV5
, CFSTR("org.winehq.builtin.dibv5"), import_clipboard_data
, export_clipboard_data
, FALSE
},
147 { CF_DIF
, CFSTR("org.winehq.builtin.dif"), import_clipboard_data
, export_clipboard_data
, FALSE
},
148 { CF_ENHMETAFILE
, CFSTR("org.winehq.builtin.enhmetafile"), import_enhmetafile
, export_enhmetafile
, FALSE
},
149 { CF_LOCALE
, CFSTR("org.winehq.builtin.locale"), import_clipboard_data
, export_clipboard_data
, FALSE
},
150 { CF_METAFILEPICT
, CFSTR("org.winehq.builtin.metafilepict"), import_metafilepict
, export_metafilepict
, FALSE
},
151 { CF_OEMTEXT
, CFSTR("org.winehq.builtin.oemtext"), import_clipboard_data
, export_clipboard_data
, FALSE
},
152 { CF_PALETTE
, CFSTR("org.winehq.builtin.palette"), import_clipboard_data
, export_clipboard_data
, FALSE
},
153 { CF_PENDATA
, CFSTR("org.winehq.builtin.pendata"), import_clipboard_data
, export_clipboard_data
, FALSE
},
154 { CF_RIFF
, CFSTR("org.winehq.builtin.riff"), import_clipboard_data
, export_clipboard_data
, FALSE
},
155 { CF_SYLK
, CFSTR("org.winehq.builtin.sylk"), import_clipboard_data
, export_clipboard_data
, FALSE
},
156 { CF_TEXT
, CFSTR("org.winehq.builtin.text"), import_clipboard_data
, export_clipboard_data
, FALSE
},
157 { CF_TIFF
, CFSTR("public.tiff"), import_clipboard_data
, export_clipboard_data
, FALSE
},
158 { CF_WAVE
, CFSTR("com.microsoft.waveform-audio"), import_clipboard_data
, export_clipboard_data
, FALSE
},
160 { CF_DIB
, CFSTR("org.winehq.builtin.dib"), import_clipboard_data
, export_clipboard_data
, FALSE
},
161 { CF_DIB
, CFSTR("com.microsoft.bmp"), import_bmp_to_dib
, export_dib_to_bmp
, TRUE
},
163 { CF_HDROP
, CFSTR("org.winehq.builtin.hdrop"), import_clipboard_data
, export_clipboard_data
, FALSE
},
164 { CF_HDROP
, CFSTR("NSFilenamesPboardType"), import_nsfilenames_to_hdrop
, export_hdrop_to_filenames
, TRUE
},
166 { CF_UNICODETEXT
, CFSTR("org.winehq.builtin.unicodetext"), import_clipboard_data
, export_clipboard_data
, FALSE
},
167 { CF_UNICODETEXT
, CFSTR("public.utf16-plain-text"), import_utf16_to_unicodetext
, export_unicodetext_to_utf16
,TRUE
},
168 { CF_UNICODETEXT
, CFSTR("public.utf8-plain-text"), import_utf8_to_unicodetext
, export_unicodetext_to_utf8
, TRUE
},
171 static const WCHAR wszRichTextFormat
[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
172 static const WCHAR wszGIF
[] = {'G','I','F',0};
173 static const WCHAR wszJFIF
[] = {'J','F','I','F',0};
174 static const WCHAR wszPNG
[] = {'P','N','G',0};
175 static const WCHAR wszHTMLFormat
[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
180 DRVIMPORTFUNC import
;
181 DRVEXPORTFUNC export
;
183 } builtin_format_names
[] =
185 { wszRichTextFormat
, CFSTR("public.rtf"), import_clipboard_data
, export_clipboard_data
},
186 { wszGIF
, CFSTR("com.compuserve.gif"), import_clipboard_data
, export_clipboard_data
},
187 { wszJFIF
, CFSTR("public.jpeg"), import_clipboard_data
, export_clipboard_data
},
188 { wszPNG
, CFSTR("public.png"), import_clipboard_data
, export_clipboard_data
},
189 { wszHTMLFormat
, NULL
, import_clipboard_data
, export_clipboard_data
},
190 { wszHTMLFormat
, CFSTR("public.html"), import_html
, export_html
, TRUE
},
191 { CFSTR_SHELLURLW
, CFSTR("public.url"), import_utf8_to_text
, export_text_to_utf8
},
194 /* The prefix prepended to a Win32 clipboard format name to make a Mac pasteboard type. */
195 static const CFStringRef registered_name_type_prefix
= CFSTR("org.winehq.registered.");
197 static DWORD clipboard_thread_id
;
198 static HWND clipboard_hwnd
;
199 static BOOL is_clipboard_owner
;
200 static macdrv_window clipboard_cocoa_window
;
201 static ULONG64 last_clipboard_update
;
202 static DWORD last_get_seqno
;
203 static WINE_CLIPFORMAT
**current_mac_formats
;
204 static unsigned int nb_current_mac_formats
;
205 static WCHAR clipboard_pipe_name
[256];
208 /**************************************************************************
209 * Internal Clipboard implementation methods
210 **************************************************************************/
213 * format_list functions
216 /**************************************************************************
219 const char *debugstr_format(UINT id
)
223 if (GetClipboardFormatNameW(id
, buffer
, 256))
224 return wine_dbg_sprintf("0x%04x %s", id
, debugstr_w(buffer
));
228 #define BUILTIN(id) case id: return #id;
231 BUILTIN(CF_METAFILEPICT
)
241 BUILTIN(CF_UNICODETEXT
)
242 BUILTIN(CF_ENHMETAFILE
)
246 BUILTIN(CF_OWNERDISPLAY
)
248 BUILTIN(CF_DSPBITMAP
)
249 BUILTIN(CF_DSPMETAFILEPICT
)
250 BUILTIN(CF_DSPENHMETAFILE
)
252 default: return wine_dbg_sprintf("0x%04x", id
);
257 /**************************************************************************
258 * insert_clipboard_format
260 static WINE_CLIPFORMAT
*insert_clipboard_format(UINT id
, CFStringRef type
)
262 WINE_CLIPFORMAT
*format
;
264 format
= HeapAlloc(GetProcessHeap(), 0, sizeof(*format
));
268 WARN("No more memory for a new format!\n");
271 format
->format_id
= id
;
272 format
->import_func
= import_clipboard_data
;
273 format
->export_func
= export_clipboard_data
;
274 format
->synthesized
= FALSE
;
275 format
->natural_format
= NULL
;
278 format
->type
= CFStringCreateCopy(NULL
, type
);
283 if (!GetClipboardFormatNameW(format
->format_id
, buffer
, ARRAY_SIZE(buffer
)))
285 WARN("failed to get name for format %s; error 0x%08x\n", debugstr_format(format
->format_id
), GetLastError());
286 HeapFree(GetProcessHeap(), 0, format
);
290 format
->type
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%S"),
291 registered_name_type_prefix
, buffer
);
294 list_add_tail(&format_list
, &format
->entry
);
296 TRACE("Registering format %s type %s\n", debugstr_format(format
->format_id
),
297 debugstr_cf(format
->type
));
303 /**************************************************************************
306 * Register a custom Mac clipboard format.
308 static WINE_CLIPFORMAT
* register_format(UINT id
, CFStringRef type
)
310 WINE_CLIPFORMAT
*format
;
312 /* walk format chain to see if it's already registered */
313 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
314 if (format
->format_id
== id
) return format
;
316 return insert_clipboard_format(id
, type
);
320 /**************************************************************************
321 * natural_format_for_format
323 * Find the "natural" format for this format_id (the one which isn't
324 * synthesized from another type).
326 static WINE_CLIPFORMAT
* natural_format_for_format(UINT format_id
)
328 WINE_CLIPFORMAT
*format
;
330 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
331 if (format
->format_id
== format_id
&& !format
->synthesized
) break;
333 if (&format
->entry
== &format_list
)
336 TRACE("%s -> %p/%s\n", debugstr_format(format_id
), format
, debugstr_cf(format
? format
->type
: NULL
));
341 /**************************************************************************
342 * register_builtin_formats
344 static void register_builtin_formats(void)
347 WINE_CLIPFORMAT
*format
;
349 /* Register built-in formats */
350 for (i
= 0; i
< ARRAY_SIZE(builtin_format_ids
); i
++)
352 if (!(format
= HeapAlloc(GetProcessHeap(), 0, sizeof(*format
)))) break;
353 format
->format_id
= builtin_format_ids
[i
].id
;
354 format
->type
= CFRetain(builtin_format_ids
[i
].type
);
355 format
->import_func
= builtin_format_ids
[i
].import
;
356 format
->export_func
= builtin_format_ids
[i
].export
;
357 format
->synthesized
= builtin_format_ids
[i
].synthesized
;
358 format
->natural_format
= NULL
;
359 list_add_tail(&format_list
, &format
->entry
);
362 /* Register known mappings between Windows formats and Mac types */
363 for (i
= 0; i
< ARRAY_SIZE(builtin_format_names
); i
++)
365 if (!(format
= HeapAlloc(GetProcessHeap(), 0, sizeof(*format
)))) break;
366 format
->format_id
= RegisterClipboardFormatW(builtin_format_names
[i
].name
);
367 format
->import_func
= builtin_format_names
[i
].import
;
368 format
->export_func
= builtin_format_names
[i
].export
;
369 format
->synthesized
= builtin_format_names
[i
].synthesized
;
370 format
->natural_format
= NULL
;
372 if (builtin_format_names
[i
].type
)
373 format
->type
= CFRetain(builtin_format_names
[i
].type
);
376 format
->type
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%S"),
377 registered_name_type_prefix
, builtin_format_names
[i
].name
);
380 list_add_tail(&format_list
, &format
->entry
);
383 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
385 if (format
->synthesized
)
386 format
->natural_format
= natural_format_for_format(format
->format_id
);
391 /**************************************************************************
394 static WINE_CLIPFORMAT
* format_for_type(CFStringRef type
)
396 WINE_CLIPFORMAT
*format
;
398 TRACE("type %s\n", debugstr_cf(type
));
400 if (list_empty(&format_list
)) register_builtin_formats();
402 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
404 if (CFEqual(format
->type
, type
))
409 if (CFStringHasPrefix(type
, CFSTR("org.winehq.builtin.")))
411 ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
414 else if (CFStringHasPrefix(type
, registered_name_type_prefix
))
417 int len
= CFStringGetLength(type
) - CFStringGetLength(registered_name_type_prefix
);
419 name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
420 CFStringGetCharacters(type
, CFRangeMake(CFStringGetLength(registered_name_type_prefix
), len
),
424 format
= register_format(RegisterClipboardFormatW(name
), type
);
426 ERR("Failed to register format for type %s name %s\n", debugstr_cf(type
), debugstr_w(name
));
428 HeapFree(GetProcessHeap(), 0, name
);
432 TRACE(" -> %p/%s\n", format
, debugstr_format(format
? format
->format_id
: 0));
437 /***********************************************************************
440 * Return the size of the bitmap info structure including color table.
442 static int bitmap_info_size(const BITMAPINFO
*info
, WORD coloruse
)
444 unsigned int colors
, size
, masks
= 0;
446 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
448 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
449 colors
= (core
->bcBitCount
<= 8) ? 1 << core
->bcBitCount
: 0;
450 return sizeof(BITMAPCOREHEADER
) + colors
*
451 ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBTRIPLE
) : sizeof(WORD
));
453 else /* assume BITMAPINFOHEADER */
455 colors
= min(info
->bmiHeader
.biClrUsed
, 256);
456 if (!colors
&& (info
->bmiHeader
.biBitCount
<= 8))
457 colors
= 1 << info
->bmiHeader
.biBitCount
;
458 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
) masks
= 3;
459 size
= max(info
->bmiHeader
.biSize
, sizeof(BITMAPINFOHEADER
) + masks
* sizeof(DWORD
));
460 return size
+ colors
* ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBQUAD
) : sizeof(WORD
));
465 /***********************************************************************
466 * create_dib_from_bitmap
468 * Allocates a packed DIB and copies the bitmap data into it.
470 static HGLOBAL
create_dib_from_bitmap(HBITMAP bitmap
)
473 BITMAPINFOHEADER header
;
478 memset(&header
, 0, sizeof(header
));
479 header
.biSize
= sizeof(header
);
480 if (!GetDIBits(hdc
, bitmap
, 0, 0, NULL
, (BITMAPINFO
*)&header
, DIB_RGB_COLORS
)) goto done
;
482 header_size
= bitmap_info_size((BITMAPINFO
*)&header
, DIB_RGB_COLORS
);
483 if (!(ret
= GlobalAlloc(GMEM_FIXED
, header_size
+ header
.biSizeImage
))) goto done
;
484 bmi
= (BITMAPINFO
*)ret
;
485 memset(bmi
, 0, header_size
);
486 memcpy(bmi
, &header
, header
.biSize
);
487 GetDIBits(hdc
, bitmap
, 0, abs(header
.biHeight
), (char *)bmi
+ header_size
, bmi
, DIB_RGB_COLORS
);
495 /**************************************************************************
496 * create_bitmap_from_dib
498 * Given a packed DIB, creates a bitmap object from it.
500 static HANDLE
create_bitmap_from_dib(HANDLE dib
)
505 if (dib
&& (bmi
= GlobalLock(dib
)))
512 offset
= bitmap_info_size(bmi
, DIB_RGB_COLORS
);
514 ret
= CreateDIBitmap(hdc
, &bmi
->bmiHeader
, CBM_INIT
, (LPBYTE
)bmi
+ offset
,
515 bmi
, DIB_RGB_COLORS
);
518 ReleaseDC(NULL
, hdc
);
525 /**************************************************************************
526 * get_html_description_field
528 * Find the value of a field in an HTML Format description.
530 static const char* get_html_description_field(const char* data
, const char* keyword
)
532 const char* pos
= data
;
534 while (pos
&& *pos
&& *pos
!= '<')
536 if (memcmp(pos
, keyword
, strlen(keyword
)) == 0)
537 return pos
+ strlen(keyword
);
539 pos
= strchr(pos
, '\n');
547 /**************************************************************************
548 * import_clipboard_data
550 * Generic import clipboard data routine.
552 static HANDLE
import_clipboard_data(CFDataRef data
)
554 HANDLE data_handle
= NULL
;
556 size_t len
= CFDataGetLength(data
);
561 /* Turn on the DDESHARE flag to enable shared 32 bit memory */
562 data_handle
= GlobalAlloc(GMEM_FIXED
, len
);
566 if ((p
= GlobalLock(data_handle
)))
568 memcpy(p
, CFDataGetBytePtr(data
), len
);
569 GlobalUnlock(data_handle
);
573 GlobalFree(data_handle
);
582 /**************************************************************************
583 * import_bmp_to_bitmap
585 * Import BMP data, converting to CF_BITMAP format.
587 static HANDLE
import_bmp_to_bitmap(CFDataRef data
)
590 HANDLE dib
= import_bmp_to_dib(data
);
592 ret
= create_bitmap_from_dib(dib
);
599 /**************************************************************************
602 * Import BMP data, converting to CF_DIB or CF_DIBV5 format. This just
603 * entails stripping the BMP file format header.
605 static HANDLE
import_bmp_to_dib(CFDataRef data
)
608 BITMAPFILEHEADER
*bfh
= (BITMAPFILEHEADER
*)CFDataGetBytePtr(data
);
609 CFIndex len
= CFDataGetLength(data
);
611 if (len
>= sizeof(*bfh
) + sizeof(BITMAPCOREHEADER
) &&
612 bfh
->bfType
== 0x4d42 /* "BM" */)
614 BITMAPINFO
*bmi
= (BITMAPINFO
*)(bfh
+ 1);
618 ret
= GlobalAlloc(GMEM_FIXED
, len
);
619 if (!ret
|| !(p
= GlobalLock(ret
)))
633 /**************************************************************************
636 * Import enhanced metafile data, converting it to CF_ENHMETAFILE.
638 static HANDLE
import_enhmetafile(CFDataRef data
)
641 CFIndex len
= CFDataGetLength(data
);
643 TRACE("data %s\n", debugstr_cf(data
));
646 ret
= SetEnhMetaFileBits(len
, (const BYTE
*)CFDataGetBytePtr(data
));
652 /**************************************************************************
657 static HANDLE
import_html(CFDataRef data
)
659 static const char header
[] =
661 "StartHTML:0000000100\n"
663 "StartFragment:%010lu\n"
664 "EndFragment:%010lu\n"
665 "<!--StartFragment-->";
666 static const char trailer
[] = "\n<!--EndFragment-->";
669 size_t size
= CFDataGetLength(data
);
671 len
= strlen(header
) + 12; /* 3 * 4 extra chars for %010lu */
672 total
= len
+ size
+ sizeof(trailer
);
673 if ((ret
= GlobalAlloc(GMEM_FIXED
, total
)))
676 p
+= sprintf(p
, header
, total
- 1, len
, len
+ size
+ 1 /* include the final \n in the data */);
677 CFDataGetBytes(data
, CFRangeMake(0, size
), (UInt8
*)p
);
678 strcpy(p
+ size
, trailer
);
679 TRACE("returning %s\n", debugstr_a(ret
));
685 /**************************************************************************
686 * import_metafilepict
688 * Import metafile picture data, converting it to CF_METAFILEPICT.
690 static HANDLE
import_metafilepict(CFDataRef data
)
693 CFIndex len
= CFDataGetLength(data
);
696 TRACE("data %s\n", debugstr_cf(data
));
698 if (len
>= sizeof(*mfp
) && (ret
= GlobalAlloc(GMEM_FIXED
, sizeof(*mfp
))))
700 const BYTE
*bytes
= (const BYTE
*)CFDataGetBytePtr(data
);
702 mfp
= GlobalLock(ret
);
703 memcpy(mfp
, bytes
, sizeof(*mfp
));
704 mfp
->hMF
= SetMetaFileBitsEx(len
- sizeof(*mfp
), bytes
+ sizeof(*mfp
));
712 /**************************************************************************
713 * import_nsfilenames_to_hdrop
715 * Import NSFilenamesPboardType data, converting the property-list-
716 * serialized array of path strings to CF_HDROP.
718 static HANDLE
import_nsfilenames_to_hdrop(CFDataRef data
)
725 WCHAR
**paths
= NULL
;
726 DROPFILES
* dropfiles
;
729 TRACE("data %s\n", debugstr_cf(data
));
731 names
= (CFArrayRef
)CFPropertyListCreateWithData(NULL
, data
, kCFPropertyListImmutable
,
733 if (!names
|| CFGetTypeID(names
) != CFArrayGetTypeID())
735 WARN("failed to interpret data as a CFArray\n");
739 count
= CFArrayGetCount(names
);
742 for (i
= 0; i
< count
; i
++)
745 CFStringRef name
= (CFStringRef
)CFArrayGetValueAtIndex(names
, i
);
746 TRACE(" %s\n", debugstr_cf(name
));
747 if (CFGetTypeID(name
) != CFStringGetTypeID())
749 WARN("non-string in array\n");
753 this_len
= CFStringGetMaximumSizeOfFileSystemRepresentation(name
);
758 buffer
= HeapAlloc(GetProcessHeap(), 0, len
);
761 WARN("failed to allocate buffer for file-system representations\n");
765 paths
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, count
* sizeof(paths
[0]));
768 WARN("failed to allocate array of DOS paths\n");
772 for (i
= 0; i
< count
; i
++)
774 CFStringRef name
= (CFStringRef
)CFArrayGetValueAtIndex(names
, i
);
775 if (!CFStringGetFileSystemRepresentation(name
, buffer
, len
))
777 WARN("failed to get file-system representation for %s\n", debugstr_cf(name
));
780 paths
[i
] = wine_get_dos_file_name(buffer
);
783 WARN("failed to get DOS path for %s\n", debugstr_a(buffer
));
788 len
= 1; /* for the terminating null */
789 for (i
= 0; i
< count
; i
++)
790 len
+= strlenW(paths
[i
]) + 1;
792 hdrop
= GlobalAlloc(GMEM_FIXED
, sizeof(*dropfiles
) + len
* sizeof(WCHAR
));
793 if (!hdrop
|| !(dropfiles
= GlobalLock(hdrop
)))
795 WARN("failed to allocate HDROP\n");
801 dropfiles
->pFiles
= sizeof(*dropfiles
);
804 dropfiles
->fNC
= FALSE
;
805 dropfiles
->fWide
= TRUE
;
807 p
= (WCHAR
*)(dropfiles
+ 1);
808 for (i
= 0; i
< count
; i
++)
810 strcpyW(p
, paths
[i
]);
820 for (i
= 0; i
< count
; i
++)
821 HeapFree(GetProcessHeap(), 0, paths
[i
]);
822 HeapFree(GetProcessHeap(), 0, paths
);
824 HeapFree(GetProcessHeap(), 0, buffer
);
825 if (names
) CFRelease(names
);
830 /**************************************************************************
831 * import_utf8_to_text
833 * Import a UTF-8 string, converting the string to CF_TEXT.
835 static HANDLE
import_utf8_to_text(CFDataRef data
)
838 HANDLE unicode_handle
= import_utf8_to_unicodetext(data
);
839 LPWSTR unicode_string
= GlobalLock(unicode_handle
);
848 unicode_len
= GlobalSize(unicode_handle
) / sizeof(WCHAR
);
850 len
= WideCharToMultiByte(CP_ACP
, 0, unicode_string
, unicode_len
, NULL
, 0, NULL
, NULL
);
851 if (!unicode_len
|| unicode_string
[unicode_len
- 1]) len
+= 1;
852 handle
= GlobalAlloc(GMEM_FIXED
, len
);
854 if (handle
&& (p
= GlobalLock(handle
)))
856 WideCharToMultiByte(CP_ACP
, 0, unicode_string
, unicode_len
, p
, len
, NULL
, NULL
);
858 GlobalUnlock(handle
);
861 GlobalUnlock(unicode_handle
);
864 GlobalFree(unicode_handle
);
869 /**************************************************************************
870 * import_utf8_to_unicodetext
872 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
874 static HANDLE
import_utf8_to_unicodetext(CFDataRef data
)
877 unsigned long src_len
;
878 unsigned long new_lines
= 0;
881 HANDLE unicode_handle
= NULL
;
883 src
= CFDataGetBytePtr(data
);
884 src_len
= CFDataGetLength(data
);
885 for (i
= 0; i
< src_len
; i
++)
891 if ((dst
= HeapAlloc(GetProcessHeap(), 0, src_len
+ new_lines
+ 1)))
895 for (i
= 0, j
= 0; i
< src_len
; i
++)
904 count
= MultiByteToWideChar(CP_UTF8
, 0, dst
, -1, NULL
, 0);
905 unicode_handle
= GlobalAlloc(GMEM_FIXED
, count
* sizeof(WCHAR
));
909 WCHAR
*textW
= GlobalLock(unicode_handle
);
910 MultiByteToWideChar(CP_UTF8
, 0, dst
, -1, textW
, count
);
911 GlobalUnlock(unicode_handle
);
914 HeapFree(GetProcessHeap(), 0, dst
);
917 return unicode_handle
;
921 /**************************************************************************
922 * import_utf16_to_unicodetext
924 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
926 static HANDLE
import_utf16_to_unicodetext(CFDataRef data
)
929 unsigned long src_len
;
930 unsigned long new_lines
= 0;
933 HANDLE unicode_handle
;
935 src
= (const WCHAR
*)CFDataGetBytePtr(data
);
936 src_len
= CFDataGetLength(data
) / sizeof(WCHAR
);
937 for (i
= 0; i
< src_len
; i
++)
941 else if (src
[i
] == '\r' && (i
+ 1 >= src_len
|| src
[i
+ 1] != '\n'))
945 if ((unicode_handle
= GlobalAlloc(GMEM_FIXED
, (src_len
+ new_lines
+ 1) * sizeof(WCHAR
))))
947 dst
= GlobalLock(unicode_handle
);
949 for (i
= 0, j
= 0; i
< src_len
; i
++)
956 if (src
[i
] == '\r' && (i
+ 1 >= src_len
|| src
[i
+ 1] != '\n'))
961 GlobalUnlock(unicode_handle
);
964 return unicode_handle
;
968 /**************************************************************************
969 * export_clipboard_data
971 * Generic export clipboard data routine.
973 static CFDataRef
export_clipboard_data(HANDLE data
)
979 len
= GlobalSize(data
);
980 src
= GlobalLock(data
);
981 if (!src
) return NULL
;
983 ret
= CFDataCreate(NULL
, src
, len
);
990 /**************************************************************************
991 * export_bitmap_to_bmp
993 * Export CF_BITMAP to BMP file format.
995 static CFDataRef
export_bitmap_to_bmp(HANDLE data
)
997 CFDataRef ret
= NULL
;
1000 dib
= create_dib_from_bitmap(data
);
1003 ret
= export_dib_to_bmp(dib
);
1011 /**************************************************************************
1014 * Export CF_DIB or CF_DIBV5 to BMP file format. This just entails
1015 * prepending a BMP file format header to the data.
1017 static CFDataRef
export_dib_to_bmp(HANDLE data
)
1019 CFMutableDataRef ret
= NULL
;
1022 BITMAPFILEHEADER bfh
;
1024 dibdata
= GlobalLock(data
);
1028 len
= sizeof(bfh
) + GlobalSize(data
);
1029 ret
= CFDataCreateMutable(NULL
, len
);
1032 bfh
.bfType
= 0x4d42; /* "BM" */
1034 bfh
.bfReserved1
= 0;
1035 bfh
.bfReserved2
= 0;
1036 bfh
.bfOffBits
= sizeof(bfh
) + bitmap_info_size((BITMAPINFO
*)dibdata
, DIB_RGB_COLORS
);
1037 CFDataAppendBytes(ret
, (UInt8
*)&bfh
, sizeof(bfh
));
1039 /* rest of bitmap is the same as the packed dib */
1040 CFDataAppendBytes(ret
, (UInt8
*)dibdata
, len
- sizeof(bfh
));
1049 /**************************************************************************
1050 * export_enhmetafile
1052 * Export an enhanced metafile to data.
1054 static CFDataRef
export_enhmetafile(HANDLE data
)
1056 CFMutableDataRef ret
= NULL
;
1057 unsigned int size
= GetEnhMetaFileBits(data
, 0, NULL
);
1059 TRACE("data %p\n", data
);
1061 ret
= CFDataCreateMutable(NULL
, size
);
1064 CFDataSetLength(ret
, size
);
1065 GetEnhMetaFileBits(data
, size
, (BYTE
*)CFDataGetMutableBytePtr(ret
));
1068 TRACE(" -> %s\n", debugstr_cf(ret
));
1073 /**************************************************************************
1074 * export_hdrop_to_filenames
1076 * Export CF_HDROP to NSFilenamesPboardType data, which is a CFArray of
1077 * CFStrings (holding Unix paths) which is serialized as a property list.
1079 static CFDataRef
export_hdrop_to_filenames(HANDLE data
)
1081 CFDataRef ret
= NULL
;
1082 DROPFILES
*dropfiles
;
1083 CFMutableArrayRef filenames
= NULL
;
1085 WCHAR
*buffer
= NULL
;
1086 size_t buffer_len
= 0;
1088 TRACE("data %p\n", data
);
1090 if (!(dropfiles
= GlobalLock(data
)))
1092 WARN("failed to lock data %p\n", data
);
1096 filenames
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1099 WARN("failed to create filenames array\n");
1103 p
= (char*)dropfiles
+ dropfiles
->pFiles
;
1104 while (dropfiles
->fWide
? *(WCHAR
*)p
: *(char*)p
)
1107 CFStringRef filename
;
1109 TRACE(" %s\n", dropfiles
->fWide
? debugstr_w(p
) : debugstr_a(p
));
1111 if (dropfiles
->fWide
)
1112 unixname
= wine_get_unix_file_name(p
);
1115 int len
= MultiByteToWideChar(CP_ACP
, 0, p
, -1, NULL
, 0);
1118 if (len
> buffer_len
)
1120 HeapFree(GetProcessHeap(), 0, buffer
);
1121 buffer_len
= len
* 2;
1122 buffer
= HeapAlloc(GetProcessHeap(), 0, buffer_len
* sizeof(*buffer
));
1125 MultiByteToWideChar(CP_ACP
, 0, p
, -1, buffer
, buffer_len
);
1126 unixname
= wine_get_unix_file_name(buffer
);
1133 WARN("failed to convert DOS path to Unix: %s\n",
1134 dropfiles
->fWide
? debugstr_w(p
) : debugstr_a(p
));
1138 if (dropfiles
->fWide
)
1139 p
= (WCHAR
*)p
+ strlenW(p
) + 1;
1141 p
= (char*)p
+ strlen(p
) + 1;
1143 filename
= CFStringCreateWithFileSystemRepresentation(NULL
, unixname
);
1144 HeapFree(GetProcessHeap(), 0, unixname
);
1147 WARN("failed to create CFString from Unix path %s\n", debugstr_a(unixname
));
1151 CFArrayAppendValue(filenames
, filename
);
1152 CFRelease(filename
);
1155 ret
= CFPropertyListCreateData(NULL
, filenames
, kCFPropertyListXMLFormat_v1_0
, 0, NULL
);
1158 HeapFree(GetProcessHeap(), 0, buffer
);
1160 if (filenames
) CFRelease(filenames
);
1161 TRACE(" -> %s\n", debugstr_cf(ret
));
1166 /**************************************************************************
1169 * Export HTML Format to public.html data.
1171 * FIXME: We should attempt to add an <a base> tag and convert windows paths.
1173 static CFDataRef
export_html(HANDLE handle
)
1176 const char *data
, *field_value
;
1177 int fragmentstart
, fragmentend
;
1179 data
= GlobalLock(handle
);
1181 /* read the important fields */
1182 field_value
= get_html_description_field(data
, "StartFragment:");
1185 ERR("Couldn't find StartFragment value\n");
1188 fragmentstart
= atoi(field_value
);
1190 field_value
= get_html_description_field(data
, "EndFragment:");
1193 ERR("Couldn't find EndFragment value\n");
1196 fragmentend
= atoi(field_value
);
1198 /* export only the fragment */
1199 ret
= CFDataCreate(NULL
, (const UInt8
*)&data
[fragmentstart
], fragmentend
- fragmentstart
);
1200 GlobalUnlock(handle
);
1204 GlobalUnlock(handle
);
1209 /**************************************************************************
1210 * export_metafilepict
1212 * Export a metafile to data.
1214 static CFDataRef
export_metafilepict(HANDLE data
)
1216 CFMutableDataRef ret
= NULL
;
1217 METAFILEPICT
*mfp
= GlobalLock(data
);
1218 unsigned int size
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
1220 TRACE("data %p\n", data
);
1222 ret
= CFDataCreateMutable(NULL
, sizeof(*mfp
) + size
);
1225 CFDataAppendBytes(ret
, (UInt8
*)mfp
, sizeof(*mfp
));
1226 CFDataIncreaseLength(ret
, size
);
1227 GetMetaFileBitsEx(mfp
->hMF
, size
, (BYTE
*)CFDataGetMutableBytePtr(ret
) + sizeof(*mfp
));
1231 TRACE(" -> %s\n", debugstr_cf(ret
));
1236 /**************************************************************************
1237 * export_text_to_utf8
1239 * Export CF_TEXT to UTF-8.
1241 static CFDataRef
export_text_to_utf8(HANDLE data
)
1243 CFDataRef ret
= NULL
;
1246 if ((str
= GlobalLock(data
)))
1248 int str_len
= GlobalSize(data
);
1254 wstr_len
= MultiByteToWideChar(CP_ACP
, 0, str
, str_len
, NULL
, 0);
1255 if (!str_len
|| str
[str_len
- 1]) wstr_len
+= 1;
1256 wstr
= HeapAlloc(GetProcessHeap(), 0, wstr_len
* sizeof(WCHAR
));
1257 MultiByteToWideChar(CP_ACP
, 0, str
, str_len
, wstr
, wstr_len
);
1258 wstr
[wstr_len
- 1] = 0;
1260 unicode
= GlobalAlloc(GMEM_FIXED
, wstr_len
* sizeof(WCHAR
));
1261 if (unicode
&& (p
= GlobalLock(unicode
)))
1263 memcpy(p
, wstr
, wstr_len
* sizeof(WCHAR
));
1264 GlobalUnlock(unicode
);
1267 ret
= export_unicodetext_to_utf8(unicode
);
1269 GlobalFree(unicode
);
1277 /**************************************************************************
1278 * export_unicodetext_to_utf8
1280 * Export CF_UNICODETEXT to UTF-8.
1282 static CFDataRef
export_unicodetext_to_utf8(HANDLE data
)
1284 CFMutableDataRef ret
;
1288 src
= GlobalLock(data
);
1289 if (!src
) return NULL
;
1291 dst_len
= WideCharToMultiByte(CP_UTF8
, 0, src
, -1, NULL
, 0, NULL
, NULL
);
1292 if (dst_len
) dst_len
--; /* Leave off null terminator. */
1293 ret
= CFDataCreateMutable(NULL
, dst_len
);
1299 CFDataSetLength(ret
, dst_len
);
1300 dst
= (LPSTR
)CFDataGetMutableBytePtr(ret
);
1301 WideCharToMultiByte(CP_UTF8
, 0, src
, -1, dst
, dst_len
, NULL
, NULL
);
1303 /* Remove carriage returns */
1304 for (i
= 0, j
= 0; i
< dst_len
; i
++)
1306 if (dst
[i
] == '\r' &&
1307 (i
+ 1 >= dst_len
|| dst
[i
+ 1] == '\n' || dst
[i
+ 1] == '\0'))
1311 CFDataSetLength(ret
, j
);
1319 /**************************************************************************
1320 * export_unicodetext_to_utf16
1322 * Export CF_UNICODETEXT to UTF-16.
1324 static CFDataRef
export_unicodetext_to_utf16(HANDLE data
)
1326 CFMutableDataRef ret
;
1330 src
= GlobalLock(data
);
1331 if (!src
) return NULL
;
1333 src_len
= GlobalSize(data
) / sizeof(WCHAR
);
1334 if (src_len
) src_len
--; /* Leave off null terminator. */
1335 ret
= CFDataCreateMutable(NULL
, src_len
* sizeof(WCHAR
));
1341 CFDataSetLength(ret
, src_len
* sizeof(WCHAR
));
1342 dst
= (LPWSTR
)CFDataGetMutableBytePtr(ret
);
1344 /* Remove carriage returns */
1345 for (i
= 0, j
= 0; i
< src_len
; i
++)
1347 if (src
[i
] == '\r' &&
1348 (i
+ 1 >= src_len
|| src
[i
+ 1] == '\n' || src
[i
+ 1] == '\0'))
1352 CFDataSetLength(ret
, j
* sizeof(WCHAR
));
1360 /**************************************************************************
1361 * macdrv_get_pasteboard_data
1363 HANDLE
macdrv_get_pasteboard_data(CFTypeRef pasteboard
, UINT desired_format
)
1368 CFStringRef type
, best_type
;
1369 WINE_CLIPFORMAT
* best_format
= NULL
;
1372 TRACE("pasteboard %p, desired_format %s\n", pasteboard
, debugstr_format(desired_format
));
1374 types
= macdrv_copy_pasteboard_types(pasteboard
);
1377 WARN("Failed to copy pasteboard types\n");
1381 count
= CFArrayGetCount(types
);
1382 TRACE("got %ld types\n", count
);
1384 for (i
= 0; (!best_format
|| best_format
->synthesized
) && i
< count
; i
++)
1386 WINE_CLIPFORMAT
* format
;
1388 type
= CFArrayGetValueAtIndex(types
, i
);
1390 if ((format
= format_for_type(type
)))
1392 TRACE("for type %s got format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1394 if (format
->format_id
== desired_format
)
1396 /* The best format is the matching one which is not synthesized. Failing that,
1397 the best format is the first matching synthesized format. */
1398 if (!format
->synthesized
|| !best_format
)
1401 best_format
= format
;
1409 CFDataRef pasteboard_data
= macdrv_copy_pasteboard_data(pasteboard
, best_type
);
1411 TRACE("got pasteboard data for type %s: %s\n", debugstr_cf(best_type
), debugstr_cf(pasteboard_data
));
1413 if (pasteboard_data
)
1415 data
= best_format
->import_func(pasteboard_data
);
1416 CFRelease(pasteboard_data
);
1421 TRACE(" -> %p\n", data
);
1426 /**************************************************************************
1427 * macdrv_pasteboard_has_format
1429 BOOL
macdrv_pasteboard_has_format(CFTypeRef pasteboard
, UINT desired_format
)
1436 TRACE("pasteboard %p, desired_format %s\n", pasteboard
, debugstr_format(desired_format
));
1438 types
= macdrv_copy_pasteboard_types(pasteboard
);
1441 WARN("Failed to copy pasteboard types\n");
1445 count
= CFArrayGetCount(types
);
1446 TRACE("got %d types\n", count
);
1448 for (i
= 0; i
< count
; i
++)
1450 CFStringRef type
= CFArrayGetValueAtIndex(types
, i
);
1451 WINE_CLIPFORMAT
* format
= format_for_type(type
);
1455 TRACE("for type %s got format %s\n", debugstr_cf(type
), debugstr_format(format
->format_id
));
1457 if (format
->format_id
== desired_format
)
1466 TRACE(" -> %d\n", found
);
1471 /**************************************************************************
1472 * get_formats_for_pasteboard_types
1474 static WINE_CLIPFORMAT
** get_formats_for_pasteboard_types(CFArrayRef types
, UINT
*num_formats
)
1477 CFMutableSetRef seen_formats
;
1478 WINE_CLIPFORMAT
** formats
;
1481 count
= CFArrayGetCount(types
);
1482 TRACE("got %ld types\n", count
);
1487 seen_formats
= CFSetCreateMutable(NULL
, count
, NULL
);
1490 WARN("Failed to allocate seen formats set\n");
1494 formats
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(*formats
));
1497 WARN("Failed to allocate formats array\n");
1498 CFRelease(seen_formats
);
1503 for (i
= 0; i
< count
; i
++)
1505 CFStringRef type
= CFArrayGetValueAtIndex(types
, i
);
1506 WINE_CLIPFORMAT
* format
= format_for_type(type
);
1510 TRACE("ignoring type %s\n", debugstr_cf(type
));
1514 if (!format
->synthesized
)
1516 TRACE("for type %s got format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1517 CFSetAddValue(seen_formats
, (void*)format
->format_id
);
1518 formats
[pos
++] = format
;
1520 else if (format
->natural_format
&&
1521 CFArrayContainsValue(types
, CFRangeMake(0, count
), format
->natural_format
->type
))
1523 TRACE("for type %s deferring synthesized formats because type %s is also present\n",
1524 debugstr_cf(type
), debugstr_cf(format
->natural_format
->type
));
1526 else if (CFSetContainsValue(seen_formats
, (void*)format
->format_id
))
1528 TRACE("for type %s got duplicate synthesized format %p/%s; skipping\n", debugstr_cf(type
), format
,
1529 debugstr_format(format
->format_id
));
1533 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1534 CFSetAddValue(seen_formats
, (void*)format
->format_id
);
1535 formats
[pos
++] = format
;
1539 /* Now go back through the types adding the synthesized formats that we deferred before. */
1540 for (i
= 0; i
< count
; i
++)
1542 CFStringRef type
= CFArrayGetValueAtIndex(types
, i
);
1543 WINE_CLIPFORMAT
* format
= format_for_type(type
);
1545 if (!format
) continue;
1546 if (!format
->synthesized
) continue;
1548 /* Don't duplicate a real value with a synthesized value. */
1549 if (CFSetContainsValue(seen_formats
, (void*)format
->format_id
)) continue;
1551 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1552 CFSetAddValue(seen_formats
, (void*)format
->format_id
);
1553 formats
[pos
++] = format
;
1556 CFRelease(seen_formats
);
1560 HeapFree(GetProcessHeap(), 0, formats
);
1569 /**************************************************************************
1570 * get_formats_for_pasteboard
1572 static WINE_CLIPFORMAT
** get_formats_for_pasteboard(CFTypeRef pasteboard
, UINT
*num_formats
)
1575 WINE_CLIPFORMAT
** formats
;
1577 TRACE("pasteboard %s\n", debugstr_cf(pasteboard
));
1579 types
= macdrv_copy_pasteboard_types(pasteboard
);
1582 WARN("Failed to copy pasteboard types\n");
1586 formats
= get_formats_for_pasteboard_types(types
, num_formats
);
1592 /**************************************************************************
1593 * macdrv_get_pasteboard_formats
1595 UINT
* macdrv_get_pasteboard_formats(CFTypeRef pasteboard
, UINT
* num_formats
)
1597 WINE_CLIPFORMAT
** formats
;
1601 formats
= get_formats_for_pasteboard(pasteboard
, &count
);
1605 format_ids
= HeapAlloc(GetProcessHeap(), 0, count
);
1608 WARN("Failed to allocate formats IDs array\n");
1609 HeapFree(GetProcessHeap(), 0, formats
);
1613 for (i
= 0; i
< count
; i
++)
1614 format_ids
[i
] = formats
[i
]->format_id
;
1616 HeapFree(GetProcessHeap(), 0, formats
);
1618 *num_formats
= count
;
1623 /**************************************************************************
1624 * register_win32_formats
1626 * Register Win32 clipboard formats the first time we encounter them.
1628 static void register_win32_formats(const UINT
*ids
, UINT size
)
1632 if (list_empty(&format_list
)) register_builtin_formats();
1634 for (i
= 0; i
< size
; i
++)
1635 register_format(ids
[i
], NULL
);
1639 /***********************************************************************
1640 * get_clipboard_formats
1642 * Return a list of all formats currently available on the Win32 clipboard.
1643 * Helper for set_mac_pasteboard_types_from_win32_clipboard.
1645 static UINT
*get_clipboard_formats(UINT
*size
)
1652 if (!(ids
= HeapAlloc(GetProcessHeap(), 0, *size
* sizeof(*ids
)))) return NULL
;
1653 if (GetUpdatedClipboardFormats(ids
, *size
, size
)) break;
1654 HeapFree(GetProcessHeap(), 0, ids
);
1655 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return NULL
;
1657 register_win32_formats(ids
, *size
);
1662 /**************************************************************************
1663 * set_mac_pasteboard_types_from_win32_clipboard
1665 static void set_mac_pasteboard_types_from_win32_clipboard(void)
1667 WINE_CLIPFORMAT
*format
;
1668 UINT count
, i
, *formats
;
1670 if (!(formats
= get_clipboard_formats(&count
))) return;
1672 macdrv_clear_pasteboard(clipboard_cocoa_window
);
1674 for (i
= 0; i
< count
; i
++)
1676 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
1678 if (format
->format_id
!= formats
[i
]) continue;
1679 TRACE("%s -> %s\n", debugstr_format(format
->format_id
), debugstr_cf(format
->type
));
1680 macdrv_set_pasteboard_data(format
->type
, NULL
, clipboard_cocoa_window
);
1684 HeapFree(GetProcessHeap(), 0, formats
);
1689 /**************************************************************************
1690 * set_win32_clipboard_formats_from_mac_pasteboard
1692 static void set_win32_clipboard_formats_from_mac_pasteboard(CFArrayRef types
)
1694 WINE_CLIPFORMAT
** formats
;
1697 formats
= get_formats_for_pasteboard_types(types
, &count
);
1701 for (i
= 0; i
< count
; i
++)
1703 TRACE("adding format %s\n", debugstr_format(formats
[i
]->format_id
));
1704 SetClipboardData(formats
[i
]->format_id
, 0);
1707 HeapFree(GetProcessHeap(), 0, current_mac_formats
);
1708 current_mac_formats
= formats
;
1709 nb_current_mac_formats
= count
;
1713 /**************************************************************************
1716 static void render_format(UINT id
)
1720 for (i
= 0; i
< nb_current_mac_formats
; i
++)
1722 CFDataRef pasteboard_data
;
1724 if (current_mac_formats
[i
]->format_id
!= id
) continue;
1726 pasteboard_data
= macdrv_copy_pasteboard_data(NULL
, current_mac_formats
[i
]->type
);
1727 if (pasteboard_data
)
1729 HANDLE handle
= current_mac_formats
[i
]->import_func(pasteboard_data
);
1730 CFRelease(pasteboard_data
);
1731 if (handle
) SetClipboardData(id
, handle
);
1738 /**************************************************************************
1739 * grab_win32_clipboard
1741 * Grab the Win32 clipboard when a Mac app has taken ownership of the
1742 * pasteboard, and fill it with the pasteboard data types.
1744 static void grab_win32_clipboard(void)
1746 static CFArrayRef last_types
;
1749 types
= macdrv_copy_pasteboard_types(NULL
);
1752 WARN("Failed to copy pasteboard types\n");
1756 if (!macdrv_has_pasteboard_changed() && last_types
&& CFEqual(types
, last_types
))
1762 if (last_types
) CFRelease(last_types
);
1763 last_types
= types
; /* takes ownership */
1765 if (!OpenClipboard(clipboard_hwnd
)) return;
1767 is_clipboard_owner
= TRUE
;
1768 last_clipboard_update
= GetTickCount64();
1769 set_win32_clipboard_formats_from_mac_pasteboard(types
);
1771 SetTimer(clipboard_hwnd
, 1, CLIPBOARD_UPDATE_DELAY
, NULL
);
1775 /**************************************************************************
1778 * Periodically update the clipboard while the clipboard is owned by a
1781 static void update_clipboard(void)
1783 static BOOL updating
;
1785 TRACE("is_clipboard_owner %d last_clipboard_update %llu now %llu\n",
1786 is_clipboard_owner
, last_clipboard_update
, GetTickCount64());
1788 if (updating
) return;
1791 if (is_clipboard_owner
)
1793 if (GetTickCount64() - last_clipboard_update
> CLIPBOARD_UPDATE_DELAY
)
1794 grab_win32_clipboard();
1796 else if (!macdrv_is_pasteboard_owner(clipboard_cocoa_window
))
1797 grab_win32_clipboard();
1803 /**************************************************************************
1806 * Window procedure for the clipboard manager.
1808 static LRESULT CALLBACK
clipboard_wndproc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1814 case WM_CLIPBOARDUPDATE
:
1815 if (is_clipboard_owner
) break; /* ignore our own changes */
1816 if ((LONG
)(GetClipboardSequenceNumber() - last_get_seqno
) <= 0) break;
1817 set_mac_pasteboard_types_from_win32_clipboard();
1819 case WM_RENDERFORMAT
:
1823 if (!is_clipboard_owner
) break;
1824 grab_win32_clipboard();
1826 case WM_DESTROYCLIPBOARD
:
1827 TRACE("WM_DESTROYCLIPBOARD: lost ownership\n");
1828 is_clipboard_owner
= FALSE
;
1832 return DefWindowProcW(hwnd
, msg
, wp
, lp
);
1836 /**************************************************************************
1837 * wait_clipboard_mutex
1839 * Make sure that there's only one clipboard thread per window station.
1841 static BOOL
wait_clipboard_mutex(void)
1843 static const WCHAR prefix
[] = {'_','_','w','i','n','e','_','c','l','i','p','b','o','a','r','d','_'};
1844 WCHAR buffer
[MAX_PATH
+ ARRAY_SIZE(prefix
)];
1847 memcpy(buffer
, prefix
, sizeof(prefix
));
1848 if (!GetUserObjectInformationW(GetProcessWindowStation(), UOI_NAME
,
1849 buffer
+ ARRAY_SIZE(prefix
),
1850 sizeof(buffer
) - sizeof(prefix
), NULL
))
1852 ERR("failed to get winstation name\n");
1855 mutex
= CreateMutexW(NULL
, TRUE
, buffer
);
1856 if (GetLastError() == ERROR_ALREADY_EXISTS
)
1858 TRACE("waiting for mutex %s\n", debugstr_w(buffer
));
1859 WaitForSingleObject(mutex
, INFINITE
);
1865 /**************************************************************************
1868 * Init-once helper for get_pipe_name.
1870 static BOOL CALLBACK
init_pipe_name(INIT_ONCE
* once
, void* param
, void** context
)
1872 static const WCHAR prefix
[] = {'\\','\\','.','\\','p','i','p','e','\\','_','_','w','i','n','e','_','c','l','i','p','b','o','a','r','d','_'};
1874 memcpy(clipboard_pipe_name
, prefix
, sizeof(prefix
));
1875 if (!GetUserObjectInformationW(GetProcessWindowStation(), UOI_NAME
,
1876 clipboard_pipe_name
+ ARRAY_SIZE(prefix
),
1877 sizeof(clipboard_pipe_name
) - sizeof(prefix
), NULL
))
1879 ERR("failed to get winstation name\n");
1887 /**************************************************************************
1890 * Get the name of the pipe used to communicate with the per-window-station
1891 * clipboard manager thread.
1893 static const WCHAR
* get_pipe_name(void)
1895 static INIT_ONCE once
= INIT_ONCE_STATIC_INIT
;
1896 InitOnceExecuteOnce(&once
, init_pipe_name
, NULL
, NULL
);
1897 return clipboard_pipe_name
[0] ? clipboard_pipe_name
: NULL
;
1901 /**************************************************************************
1904 * Thread running inside the desktop process to manage the clipboard
1906 static DWORD WINAPI
clipboard_thread(void *arg
)
1908 static const WCHAR clipboard_classname
[] = {'_','_','w','i','n','e','_','c','l','i','p','b','o','a','r','d','_','m','a','n','a','g','e','r',0};
1910 struct macdrv_window_features wf
;
1911 const WCHAR
* pipe_name
;
1913 HANDLE event
= NULL
;
1914 OVERLAPPED overlapped
;
1915 BOOL need_connect
= TRUE
, pending
= FALSE
;
1918 if (!wait_clipboard_mutex()) return 0;
1920 memset(&class, 0, sizeof(class));
1921 class.lpfnWndProc
= clipboard_wndproc
;
1922 class.lpszClassName
= clipboard_classname
;
1924 if (!RegisterClassW(&class) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS
)
1926 ERR("could not register clipboard window class err %u\n", GetLastError());
1929 if (!(clipboard_hwnd
= CreateWindowW(clipboard_classname
, NULL
, 0, 0, 0, 0, 0,
1930 HWND_MESSAGE
, 0, 0, NULL
)))
1932 ERR("failed to create clipboard window err %u\n", GetLastError());
1936 memset(&wf
, 0, sizeof(wf
));
1937 clipboard_cocoa_window
= macdrv_create_cocoa_window(&wf
, CGRectMake(100, 100, 100, 100), clipboard_hwnd
,
1938 macdrv_init_thread_data()->queue
);
1939 if (!clipboard_cocoa_window
)
1941 ERR("failed to create clipboard Cocoa window\n");
1945 pipe_name
= get_pipe_name();
1948 ERR("failed to get pipe name\n");
1952 pipe
= CreateNamedPipeW(pipe_name
, PIPE_ACCESS_OUTBOUND
| FILE_FLAG_OVERLAPPED
,
1953 PIPE_TYPE_BYTE
, PIPE_UNLIMITED_INSTANCES
, 1, 1, 0, NULL
);
1956 ERR("failed to create named pipe: %u\n", GetLastError());
1960 event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
1963 ERR("failed to create event: %d\n", GetLastError());
1967 clipboard_thread_id
= GetCurrentThreadId();
1968 AddClipboardFormatListener(clipboard_hwnd
);
1969 register_builtin_formats();
1970 grab_win32_clipboard();
1972 TRACE("clipboard thread %04x running\n", GetCurrentThreadId());
1980 memset(&overlapped
, 0, sizeof(overlapped
));
1981 overlapped
.hEvent
= event
;
1982 if (ConnectNamedPipe(pipe
, &overlapped
))
1984 ERR("asynchronous ConnectNamedPipe unexpectedly returned true: %d\n", GetLastError());
1989 result
= GetLastError();
1992 case ERROR_PIPE_CONNECTED
:
1995 need_connect
= FALSE
;
1997 case ERROR_IO_PENDING
:
1998 need_connect
= FALSE
;
2002 ERR("failed to initiate pipe connection: %d\n", result
);
2008 result
= MsgWaitForMultipleObjectsEx(1, &event
, INFINITE
, QS_ALLINPUT
, MWMO_ALERTABLE
| MWMO_INPUTAVAILABLE
);
2015 if (pending
&& !GetOverlappedResult(pipe
, &overlapped
, &written
, FALSE
))
2016 ERR("failed to connect pipe: %d\n", GetLastError());
2019 DisconnectNamedPipe(pipe
);
2020 need_connect
= TRUE
;
2023 case WAIT_OBJECT_0
+ 1:
2024 while (PeekMessageW(&msg
, NULL
, 0, 0, PM_REMOVE
))
2026 if (msg
.message
== WM_QUIT
)
2028 DispatchMessageW(&msg
);
2031 case WAIT_IO_COMPLETION
:
2034 ERR("failed to wait for connection or input: %d\n", GetLastError());
2040 if (event
) CloseHandle(event
);
2041 if (pipe
) CloseHandle(pipe
);
2042 macdrv_destroy_cocoa_window(clipboard_cocoa_window
);
2043 DestroyWindow(clipboard_hwnd
);
2048 /**************************************************************************
2049 * Mac User Driver Clipboard Exports
2050 **************************************************************************/
2053 /**************************************************************************
2054 * macdrv_UpdateClipboard
2056 void CDECL
macdrv_UpdateClipboard(void)
2058 static ULONG last_update
;
2060 const WCHAR
* pipe_name
;
2064 OVERLAPPED overlapped
= { 0 };
2065 BOOL canceled
= FALSE
;
2067 if (GetCurrentThreadId() == clipboard_thread_id
) return;
2071 now
= GetTickCount();
2072 if ((int)(now
- last_update
) <= CLIPBOARD_UPDATE_DELAY
) return;
2075 if (!(pipe_name
= get_pipe_name())) return;
2076 pipe
= CreateFileW(pipe_name
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, NULL
,
2077 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_OVERLAPPED
, NULL
);
2078 if (pipe
== INVALID_HANDLE_VALUE
)
2080 WARN("failed to open pipe to clipboard manager: %d\n", GetLastError());
2084 overlapped
.hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
2085 if (!overlapped
.hEvent
)
2087 ERR("failed to create event: %d\n", GetLastError());
2091 /* We expect the read to fail because the server just closes our connection. This
2092 is just waiting for that close to happen. */
2093 if (ReadFile(pipe
, &dummy
, sizeof(dummy
), NULL
, &overlapped
))
2095 WARN("asynchronous ReadFile unexpectedly returned true: %d\n", GetLastError());
2100 DWORD error
= GetLastError();
2101 if (error
== ERROR_PIPE_NOT_CONNECTED
|| error
== ERROR_BROKEN_PIPE
)
2103 /* The server accepted, handled, and closed our connection before we
2104 attempted the read, which is fine. */
2107 else if (error
!= ERROR_IO_PENDING
)
2109 ERR("failed to initiate read from pipe: %d\n", error
);
2117 DWORD result
, timeout
;
2123 now
= GetTickCount();
2124 timeout
= end
- now
;
2125 if ((int)timeout
< 0)
2129 result
= MsgWaitForMultipleObjectsEx(1, &overlapped
.hEvent
, timeout
, QS_SENDMESSAGE
, MWMO_ALERTABLE
);
2134 if (GetOverlappedResult(pipe
, &overlapped
, &count
, FALSE
))
2135 WARN("unexpectedly succeeded in reading from pipe\n");
2138 result
= GetLastError();
2139 if (result
!= ERROR_BROKEN_PIPE
&& result
!= ERROR_OPERATION_ABORTED
&&
2140 result
!= ERROR_HANDLES_CLOSED
)
2141 WARN("failed to read from pipe: %d\n", result
);
2146 case WAIT_OBJECT_0
+ 1:
2149 while (PeekMessageW(&msg
, NULL
, 0, 0, PM_REMOVE
| PM_QS_SENDMESSAGE
))
2150 DispatchMessageW(&msg
);
2153 case WAIT_IO_COMPLETION
:
2156 WARN("timed out waiting for read\n");
2157 CancelIoEx(pipe
, &overlapped
);
2163 ERR("failed to wait for cancel: %d\n", GetLastError());
2167 ERR("failed to wait for read: %d\n", GetLastError());
2168 CancelIoEx(pipe
, &overlapped
);
2175 if (overlapped
.hEvent
) CloseHandle(overlapped
.hEvent
);
2180 /**************************************************************************
2181 * MACDRV Private Clipboard Exports
2182 **************************************************************************/
2185 /**************************************************************************
2186 * query_pasteboard_data
2188 BOOL
query_pasteboard_data(HWND hwnd
, CFStringRef type
)
2190 WINE_CLIPFORMAT
*format
;
2194 TRACE("win %p/%p type %s\n", hwnd
, clipboard_cocoa_window
, debugstr_cf(type
));
2196 format
= format_for_type(type
);
2197 if (!format
) return FALSE
;
2199 if (!OpenClipboard(clipboard_hwnd
))
2201 ERR("failed to open clipboard for %s\n", debugstr_cf(type
));
2205 if ((handle
= GetClipboardData(format
->format_id
)))
2209 TRACE("exporting %s %p\n", debugstr_format(format
->format_id
), handle
);
2211 if ((data
= format
->export_func(handle
)))
2213 ret
= macdrv_set_pasteboard_data(format
->type
, data
, clipboard_cocoa_window
);
2218 last_get_seqno
= GetClipboardSequenceNumber();
2226 /**************************************************************************
2227 * macdrv_lost_pasteboard_ownership
2229 * Handler for the LOST_PASTEBOARD_OWNERSHIP event.
2231 void macdrv_lost_pasteboard_ownership(HWND hwnd
)
2233 TRACE("win %p\n", hwnd
);
2234 if (!macdrv_is_pasteboard_owner(clipboard_cocoa_window
))
2235 grab_win32_clipboard();
2239 /**************************************************************************
2240 * macdrv_init_clipboard
2242 void macdrv_init_clipboard(void)
2245 HANDLE handle
= CreateThread(NULL
, 0, clipboard_thread
, NULL
, 0, &id
);
2247 if (handle
) CloseHandle(handle
);
2248 else ERR("failed to create clipboard thread\n");