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 **************************************************************************/
47 } CLIPBOARDINFO
, *LPCLIPBOARDINFO
;
49 typedef HANDLE (*DRVIMPORTFUNC
)(CFDataRef data
);
50 typedef CFDataRef (*DRVEXPORTFUNC
)(HANDLE data
);
52 typedef struct _WINE_CLIPFORMAT
57 DRVIMPORTFUNC import_func
;
58 DRVEXPORTFUNC export_func
;
60 struct _WINE_CLIPFORMAT
*natural_format
;
64 /**************************************************************************
66 **************************************************************************/
69 /**************************************************************************
70 * Forward Function Declarations
71 **************************************************************************/
73 static HANDLE
import_clipboard_data(CFDataRef data
);
74 static HANDLE
import_bmp_to_bitmap(CFDataRef data
);
75 static HANDLE
import_bmp_to_dib(CFDataRef data
);
76 static HANDLE
import_enhmetafile(CFDataRef data
);
77 static HANDLE
import_metafilepict(CFDataRef data
);
78 static HANDLE
import_nsfilenames_to_hdrop(CFDataRef data
);
79 static HANDLE
import_utf8_to_text(CFDataRef data
);
80 static HANDLE
import_utf8_to_unicodetext(CFDataRef data
);
81 static HANDLE
import_utf16_to_unicodetext(CFDataRef data
);
83 static CFDataRef
export_clipboard_data(HANDLE data
);
84 static CFDataRef
export_bitmap_to_bmp(HANDLE data
);
85 static CFDataRef
export_dib_to_bmp(HANDLE data
);
86 static CFDataRef
export_enhmetafile(HANDLE data
);
87 static CFDataRef
export_hdrop_to_filenames(HANDLE data
);
88 static CFDataRef
export_metafilepict(HANDLE data
);
89 static CFDataRef
export_text_to_utf8(HANDLE data
);
90 static CFDataRef
export_unicodetext_to_utf8(HANDLE data
);
91 static CFDataRef
export_unicodetext_to_utf16(HANDLE data
);
94 /**************************************************************************
96 **************************************************************************/
98 /* Clipboard formats */
99 static struct list format_list
= LIST_INIT(format_list
);
101 /* There are two naming schemes involved and we want to have a mapping between
102 them. There are Win32 clipboard format names and there are Mac pasteboard
105 The Win32 standard clipboard formats don't have names, but they are associated
106 with Mac pasteboard types through the following tables, which are used to
107 initialize the format_list. Where possible, the standard clipboard formats
108 are mapped to predefined pasteboard type UTIs. Otherwise, we create Wine-
109 specific types of the form "org.winehq.builtin.<format>", where <format> is
110 the name of the symbolic constant for the format minus "CF_" and lowercased.
111 E.g. CF_BITMAP -> org.winehq.builtin.bitmap.
113 Win32 clipboard formats which originate in a Windows program may be registered
114 with an arbitrary name. We construct a Mac pasteboard type from these by
115 prepending "org.winehq.registered." to the registered name.
117 Likewise, Mac pasteboard types which originate in other apps may have
118 arbitrary type strings. We ignore these.
121 Win32 clipboard format names:
122 <none> standard clipboard format; maps via
123 format_list to either a predefined Mac UTI
124 or org.winehq.builtin.<format>.
125 <other> name registered within Win32 land; maps to
126 org.winehq.registered.<other>
127 Mac pasteboard type names:
128 org.winehq.builtin.<format ID> representation of Win32 standard clipboard
129 format for which there was no corresponding
130 predefined Mac UTI; maps via format_list
131 org.winehq.registered.<format name> representation of Win32 registered
132 clipboard format name; maps to <format name>
133 <other> Mac pasteboard type originating with system
134 or other apps; either maps via format_list
135 to a standard clipboard format or ignored
142 DRVIMPORTFUNC import
;
143 DRVEXPORTFUNC export
;
145 } builtin_format_ids
[] =
147 { CF_BITMAP
, CFSTR("org.winehq.builtin.bitmap"), import_bmp_to_bitmap
, export_bitmap_to_bmp
, FALSE
},
148 { CF_DIBV5
, CFSTR("org.winehq.builtin.dibv5"), import_clipboard_data
, export_clipboard_data
, FALSE
},
149 { CF_DIF
, CFSTR("org.winehq.builtin.dif"), import_clipboard_data
, export_clipboard_data
, FALSE
},
150 { CF_ENHMETAFILE
, CFSTR("org.winehq.builtin.enhmetafile"), import_enhmetafile
, export_enhmetafile
, FALSE
},
151 { CF_LOCALE
, CFSTR("org.winehq.builtin.locale"), import_clipboard_data
, export_clipboard_data
, FALSE
},
152 { CF_METAFILEPICT
, CFSTR("org.winehq.builtin.metafilepict"), import_metafilepict
, export_metafilepict
, FALSE
},
153 { CF_OEMTEXT
, CFSTR("org.winehq.builtin.oemtext"), import_clipboard_data
, export_clipboard_data
, FALSE
},
154 { CF_PALETTE
, CFSTR("org.winehq.builtin.palette"), import_clipboard_data
, export_clipboard_data
, FALSE
},
155 { CF_PENDATA
, CFSTR("org.winehq.builtin.pendata"), import_clipboard_data
, export_clipboard_data
, FALSE
},
156 { CF_RIFF
, CFSTR("org.winehq.builtin.riff"), import_clipboard_data
, export_clipboard_data
, FALSE
},
157 { CF_SYLK
, CFSTR("org.winehq.builtin.sylk"), import_clipboard_data
, export_clipboard_data
, FALSE
},
158 { CF_TEXT
, CFSTR("org.winehq.builtin.text"), import_clipboard_data
, export_clipboard_data
, FALSE
},
159 { CF_TIFF
, CFSTR("public.tiff"), import_clipboard_data
, export_clipboard_data
, FALSE
},
160 { CF_WAVE
, CFSTR("com.microsoft.waveform-audio"), import_clipboard_data
, export_clipboard_data
, FALSE
},
162 { CF_DIB
, CFSTR("org.winehq.builtin.dib"), import_clipboard_data
, export_clipboard_data
, FALSE
},
163 { CF_DIB
, CFSTR("com.microsoft.bmp"), import_bmp_to_dib
, export_dib_to_bmp
, TRUE
},
165 { CF_HDROP
, CFSTR("org.winehq.builtin.hdrop"), import_clipboard_data
, export_clipboard_data
, FALSE
},
166 { CF_HDROP
, CFSTR("NSFilenamesPboardType"), import_nsfilenames_to_hdrop
, export_hdrop_to_filenames
, TRUE
},
168 { CF_UNICODETEXT
, CFSTR("org.winehq.builtin.unicodetext"), import_clipboard_data
, export_clipboard_data
, FALSE
},
169 { CF_UNICODETEXT
, CFSTR("public.utf16-plain-text"), import_utf16_to_unicodetext
, export_unicodetext_to_utf16
,TRUE
},
170 { CF_UNICODETEXT
, CFSTR("public.utf8-plain-text"), import_utf8_to_unicodetext
, export_unicodetext_to_utf8
, TRUE
},
173 static const WCHAR wszRichTextFormat
[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
174 static const WCHAR wszGIF
[] = {'G','I','F',0};
175 static const WCHAR wszJFIF
[] = {'J','F','I','F',0};
176 static const WCHAR wszPNG
[] = {'P','N','G',0};
177 static const WCHAR wszHTMLFormat
[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
182 DRVIMPORTFUNC import
;
183 DRVEXPORTFUNC export
;
184 } builtin_format_names
[] =
186 { wszRichTextFormat
, CFSTR("public.rtf"), import_clipboard_data
, export_clipboard_data
},
187 { wszGIF
, CFSTR("com.compuserve.gif"), import_clipboard_data
, export_clipboard_data
},
188 { wszJFIF
, CFSTR("public.jpeg"), import_clipboard_data
, export_clipboard_data
},
189 { wszPNG
, CFSTR("public.png"), import_clipboard_data
, export_clipboard_data
},
190 { wszHTMLFormat
, CFSTR("public.html"), import_clipboard_data
, export_clipboard_data
},
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.");
198 /**************************************************************************
199 * Internal Clipboard implementation methods
200 **************************************************************************/
203 * format_list functions
206 /**************************************************************************
209 const char *debugstr_format(UINT id
)
213 if (GetClipboardFormatNameW(id
, buffer
, 256))
214 return wine_dbg_sprintf("0x%04x %s", id
, debugstr_w(buffer
));
218 #define BUILTIN(id) case id: return #id;
221 BUILTIN(CF_METAFILEPICT
)
231 BUILTIN(CF_UNICODETEXT
)
232 BUILTIN(CF_ENHMETAFILE
)
236 BUILTIN(CF_OWNERDISPLAY
)
238 BUILTIN(CF_DSPBITMAP
)
239 BUILTIN(CF_DSPMETAFILEPICT
)
240 BUILTIN(CF_DSPENHMETAFILE
)
242 default: return wine_dbg_sprintf("0x%04x", id
);
247 /**************************************************************************
248 * insert_clipboard_format
250 static WINE_CLIPFORMAT
*insert_clipboard_format(UINT id
, CFStringRef type
)
252 WINE_CLIPFORMAT
*format
;
254 format
= HeapAlloc(GetProcessHeap(), 0, sizeof(*format
));
258 WARN("No more memory for a new format!\n");
261 format
->format_id
= id
;
262 format
->import_func
= import_clipboard_data
;
263 format
->export_func
= export_clipboard_data
;
264 format
->synthesized
= FALSE
;
265 format
->natural_format
= NULL
;
268 format
->type
= CFStringCreateCopy(NULL
, type
);
273 if (!GetClipboardFormatNameW(format
->format_id
, buffer
, sizeof(buffer
) / sizeof(buffer
[0])))
275 WARN("failed to get name for format %s; error 0x%08x\n", debugstr_format(format
->format_id
), GetLastError());
276 HeapFree(GetProcessHeap(), 0, format
);
280 format
->type
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%S"),
281 registered_name_type_prefix
, buffer
);
284 list_add_tail(&format_list
, &format
->entry
);
286 TRACE("Registering format %s type %s\n", debugstr_format(format
->format_id
),
287 debugstr_cf(format
->type
));
293 /**************************************************************************
296 * Register a custom Mac clipboard format.
298 static WINE_CLIPFORMAT
* register_format(UINT id
, CFStringRef type
)
300 WINE_CLIPFORMAT
*format
;
302 /* walk format chain to see if it's already registered */
303 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
304 if (format
->format_id
== id
) return format
;
306 return insert_clipboard_format(id
, type
);
310 /**************************************************************************
313 static WINE_CLIPFORMAT
* format_for_type(WINE_CLIPFORMAT
*current
, CFStringRef type
)
315 struct list
*ptr
= current
? ¤t
->entry
: &format_list
;
316 WINE_CLIPFORMAT
*format
= NULL
;
318 TRACE("current %p/%s type %s\n", current
, debugstr_format(current
? current
->format_id
: 0), debugstr_cf(type
));
320 while ((ptr
= list_next(&format_list
, ptr
)))
322 format
= LIST_ENTRY(ptr
, WINE_CLIPFORMAT
, entry
);
323 if (CFEqual(format
->type
, type
))
330 if (CFStringHasPrefix(type
, CFSTR("org.winehq.builtin.")))
332 ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
335 else if (CFStringHasPrefix(type
, registered_name_type_prefix
))
338 int len
= CFStringGetLength(type
) - CFStringGetLength(registered_name_type_prefix
);
340 name
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
341 CFStringGetCharacters(type
, CFRangeMake(CFStringGetLength(registered_name_type_prefix
), len
),
345 format
= register_format(RegisterClipboardFormatW(name
), type
);
347 ERR("Failed to register format for type %s name %s\n", debugstr_cf(type
), debugstr_w(name
));
349 HeapFree(GetProcessHeap(), 0, name
);
354 TRACE(" -> %p/%s\n", format
, debugstr_format(format
? format
->format_id
: 0));
359 /**************************************************************************
360 * natural_format_for_format
362 * Find the "natural" format for this format_id (the one which isn't
363 * synthesized from another type).
365 static WINE_CLIPFORMAT
* natural_format_for_format(UINT format_id
)
367 WINE_CLIPFORMAT
*format
;
369 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
370 if (format
->format_id
== format_id
&& !format
->synthesized
) break;
372 if (&format
->entry
== &format_list
)
375 TRACE("%s -> %p/%s\n", debugstr_format(format_id
), format
, debugstr_cf(format
? format
->type
: NULL
));
380 /***********************************************************************
383 * Return the size of the bitmap info structure including color table.
385 static int bitmap_info_size(const BITMAPINFO
*info
, WORD coloruse
)
387 unsigned int colors
, size
, masks
= 0;
389 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
391 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
392 colors
= (core
->bcBitCount
<= 8) ? 1 << core
->bcBitCount
: 0;
393 return sizeof(BITMAPCOREHEADER
) + colors
*
394 ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBTRIPLE
) : sizeof(WORD
));
396 else /* assume BITMAPINFOHEADER */
398 colors
= MIN(info
->bmiHeader
.biClrUsed
, 256);
399 if (!colors
&& (info
->bmiHeader
.biBitCount
<= 8))
400 colors
= 1 << info
->bmiHeader
.biBitCount
;
401 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
) masks
= 3;
402 size
= max(info
->bmiHeader
.biSize
, sizeof(BITMAPINFOHEADER
) + masks
* sizeof(DWORD
));
403 return size
+ colors
* ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBQUAD
) : sizeof(WORD
));
408 /***********************************************************************
409 * create_dib_from_bitmap
411 * Allocates a packed DIB and copies the bitmap data into it.
413 static HGLOBAL
create_dib_from_bitmap(HBITMAP hBmp
)
419 LPBITMAPINFOHEADER pbmiHeader
;
420 unsigned int cDataSize
, cPackedSize
, OffsetBits
;
423 if (!GetObjectW(hBmp
, sizeof(bmp
), &bmp
)) return 0;
426 * A packed DIB contains a BITMAPINFO structure followed immediately by
427 * an optional color palette and the pixel data.
430 /* Calculate the size of the packed DIB */
431 cDataSize
= abs(bmp
.bmHeight
) * (((bmp
.bmWidth
* bmp
.bmBitsPixel
+ 31) / 8) & ~3);
432 cPackedSize
= sizeof(BITMAPINFOHEADER
)
433 + ((bmp
.bmBitsPixel
<= 8) ? (sizeof(RGBQUAD
) * (1 << bmp
.bmBitsPixel
)) : 0)
435 /* Get the offset to the bits */
436 OffsetBits
= cPackedSize
- cDataSize
;
438 /* Allocate the packed DIB */
439 TRACE("\tAllocating packed DIB of size %d\n", cPackedSize
);
440 hPackedDIB
= GlobalAlloc(GMEM_FIXED
, cPackedSize
);
443 WARN("Could not allocate packed DIB!\n");
447 /* A packed DIB starts with a BITMAPINFOHEADER */
448 pPackedDIB
= GlobalLock(hPackedDIB
);
449 pbmiHeader
= (LPBITMAPINFOHEADER
)pPackedDIB
;
451 /* Init the BITMAPINFOHEADER */
452 pbmiHeader
->biSize
= sizeof(BITMAPINFOHEADER
);
453 pbmiHeader
->biWidth
= bmp
.bmWidth
;
454 pbmiHeader
->biHeight
= bmp
.bmHeight
;
455 pbmiHeader
->biPlanes
= 1;
456 pbmiHeader
->biBitCount
= bmp
.bmBitsPixel
;
457 pbmiHeader
->biCompression
= BI_RGB
;
458 pbmiHeader
->biSizeImage
= 0;
459 pbmiHeader
->biXPelsPerMeter
= pbmiHeader
->biYPelsPerMeter
= 0;
460 pbmiHeader
->biClrUsed
= 0;
461 pbmiHeader
->biClrImportant
= 0;
463 /* Retrieve the DIB bits from the bitmap and fill in the
464 * DIB color table if present */
466 nLinesCopied
= GetDIBits(hdc
, /* Handle to device context */
467 hBmp
, /* Handle to bitmap */
468 0, /* First scan line to set in dest bitmap */
469 bmp
.bmHeight
, /* Number of scan lines to copy */
470 pPackedDIB
+ OffsetBits
, /* [out] Address of array for bitmap bits */
471 (LPBITMAPINFO
) pbmiHeader
, /* [out] Address of BITMAPINFO structure */
472 0); /* RGB or palette index */
473 GlobalUnlock(hPackedDIB
);
476 /* Cleanup if GetDIBits failed */
477 if (nLinesCopied
!= bmp
.bmHeight
)
479 TRACE("\tGetDIBits returned %d. Actual lines=%d\n", nLinesCopied
, bmp
.bmHeight
);
480 GlobalFree(hPackedDIB
);
487 /**************************************************************************
488 * create_bitmap_from_dib
490 * Given a packed DIB, creates a bitmap object from it.
492 static HANDLE
create_bitmap_from_dib(HANDLE dib
)
497 if (dib
&& (bmi
= GlobalLock(dib
)))
504 offset
= bitmap_info_size(bmi
, DIB_RGB_COLORS
);
506 ret
= CreateDIBitmap(hdc
, &bmi
->bmiHeader
, CBM_INIT
, (LPBYTE
)bmi
+ offset
,
507 bmi
, DIB_RGB_COLORS
);
510 ReleaseDC(NULL
, hdc
);
517 /**************************************************************************
518 * import_clipboard_data
520 * Generic import clipboard data routine.
522 static HANDLE
import_clipboard_data(CFDataRef data
)
524 HANDLE data_handle
= NULL
;
526 size_t len
= CFDataGetLength(data
);
531 /* Turn on the DDESHARE flag to enable shared 32 bit memory */
532 data_handle
= GlobalAlloc(GMEM_FIXED
, len
);
536 if ((p
= GlobalLock(data_handle
)))
538 memcpy(p
, CFDataGetBytePtr(data
), len
);
539 GlobalUnlock(data_handle
);
543 GlobalFree(data_handle
);
552 /**************************************************************************
553 * import_bmp_to_bitmap
555 * Import BMP data, converting to CF_BITMAP format.
557 static HANDLE
import_bmp_to_bitmap(CFDataRef data
)
560 HANDLE dib
= import_bmp_to_dib(data
);
562 ret
= create_bitmap_from_dib(dib
);
569 /**************************************************************************
572 * Import BMP data, converting to CF_DIB or CF_DIBV5 format. This just
573 * entails stripping the BMP file format header.
575 static HANDLE
import_bmp_to_dib(CFDataRef data
)
578 BITMAPFILEHEADER
*bfh
= (BITMAPFILEHEADER
*)CFDataGetBytePtr(data
);
579 CFIndex len
= CFDataGetLength(data
);
581 if (len
>= sizeof(*bfh
) + sizeof(BITMAPCOREHEADER
) &&
582 bfh
->bfType
== 0x4d42 /* "BM" */)
584 BITMAPINFO
*bmi
= (BITMAPINFO
*)(bfh
+ 1);
588 ret
= GlobalAlloc(GMEM_FIXED
, len
);
589 if (!ret
|| !(p
= GlobalLock(ret
)))
603 /**************************************************************************
606 * Import enhanced metafile data, converting it to CF_ENHMETAFILE.
608 static HANDLE
import_enhmetafile(CFDataRef data
)
611 CFIndex len
= CFDataGetLength(data
);
613 TRACE("data %s\n", debugstr_cf(data
));
616 ret
= SetEnhMetaFileBits(len
, (const BYTE
*)CFDataGetBytePtr(data
));
622 /**************************************************************************
623 * import_metafilepict
625 * Import metafile picture data, converting it to CF_METAFILEPICT.
627 static HANDLE
import_metafilepict(CFDataRef data
)
630 CFIndex len
= CFDataGetLength(data
);
633 TRACE("data %s\n", debugstr_cf(data
));
635 if (len
>= sizeof(*mfp
) && (ret
= GlobalAlloc(GMEM_FIXED
, sizeof(*mfp
))))
637 const BYTE
*bytes
= (const BYTE
*)CFDataGetBytePtr(data
);
639 mfp
= GlobalLock(ret
);
640 memcpy(mfp
, bytes
, sizeof(*mfp
));
641 mfp
->hMF
= SetMetaFileBitsEx(len
- sizeof(*mfp
), bytes
+ sizeof(*mfp
));
649 /**************************************************************************
650 * import_nsfilenames_to_hdrop
652 * Import NSFilenamesPboardType data, converting the property-list-
653 * serialized array of path strings to CF_HDROP.
655 static HANDLE
import_nsfilenames_to_hdrop(CFDataRef data
)
662 WCHAR
**paths
= NULL
;
663 DROPFILES
* dropfiles
;
666 TRACE("data %s\n", debugstr_cf(data
));
668 names
= (CFArrayRef
)CFPropertyListCreateWithData(NULL
, data
, kCFPropertyListImmutable
,
670 if (!names
|| CFGetTypeID(names
) != CFArrayGetTypeID())
672 WARN("failed to interpret data as a CFArray\n");
676 count
= CFArrayGetCount(names
);
679 for (i
= 0; i
< count
; i
++)
682 CFStringRef name
= (CFStringRef
)CFArrayGetValueAtIndex(names
, i
);
683 TRACE(" %s\n", debugstr_cf(name
));
684 if (CFGetTypeID(name
) != CFStringGetTypeID())
686 WARN("non-string in array\n");
690 this_len
= CFStringGetMaximumSizeOfFileSystemRepresentation(name
);
695 buffer
= HeapAlloc(GetProcessHeap(), 0, len
);
698 WARN("failed to allocate buffer for file-system representations\n");
702 paths
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, count
* sizeof(paths
[0]));
705 WARN("failed to allocate array of DOS paths\n");
709 for (i
= 0; i
< count
; i
++)
711 CFStringRef name
= (CFStringRef
)CFArrayGetValueAtIndex(names
, i
);
712 if (!CFStringGetFileSystemRepresentation(name
, buffer
, len
))
714 WARN("failed to get file-system representation for %s\n", debugstr_cf(name
));
717 paths
[i
] = wine_get_dos_file_name(buffer
);
720 WARN("failed to get DOS path for %s\n", debugstr_a(buffer
));
725 len
= 1; /* for the terminating null */
726 for (i
= 0; i
< count
; i
++)
727 len
+= strlenW(paths
[i
]) + 1;
729 hdrop
= GlobalAlloc(GMEM_FIXED
, sizeof(*dropfiles
) + len
* sizeof(WCHAR
));
730 if (!hdrop
|| !(dropfiles
= GlobalLock(hdrop
)))
732 WARN("failed to allocate HDROP\n");
738 dropfiles
->pFiles
= sizeof(*dropfiles
);
741 dropfiles
->fNC
= FALSE
;
742 dropfiles
->fWide
= TRUE
;
744 p
= (WCHAR
*)(dropfiles
+ 1);
745 for (i
= 0; i
< count
; i
++)
747 strcpyW(p
, paths
[i
]);
757 for (i
= 0; i
< count
; i
++)
758 HeapFree(GetProcessHeap(), 0, paths
[i
]);
759 HeapFree(GetProcessHeap(), 0, paths
);
761 HeapFree(GetProcessHeap(), 0, buffer
);
762 if (names
) CFRelease(names
);
767 /**************************************************************************
768 * import_utf8_to_text
770 * Import a UTF-8 string, converting the string to CF_TEXT.
772 static HANDLE
import_utf8_to_text(CFDataRef data
)
775 HANDLE unicode_handle
= import_utf8_to_unicodetext(data
);
776 LPWSTR unicode_string
= GlobalLock(unicode_handle
);
785 unicode_len
= GlobalSize(unicode_handle
) / sizeof(WCHAR
);
787 len
= WideCharToMultiByte(CP_ACP
, 0, unicode_string
, unicode_len
, NULL
, 0, NULL
, NULL
);
788 if (!unicode_len
|| unicode_string
[unicode_len
- 1]) len
+= 1;
789 handle
= GlobalAlloc(GMEM_FIXED
, len
);
791 if (handle
&& (p
= GlobalLock(handle
)))
793 WideCharToMultiByte(CP_ACP
, 0, unicode_string
, unicode_len
, p
, len
, NULL
, NULL
);
795 GlobalUnlock(handle
);
798 GlobalUnlock(unicode_handle
);
801 GlobalFree(unicode_handle
);
806 /**************************************************************************
807 * import_utf8_to_unicodetext
809 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
811 static HANDLE
import_utf8_to_unicodetext(CFDataRef data
)
814 unsigned long src_len
;
815 unsigned long new_lines
= 0;
818 HANDLE unicode_handle
= NULL
;
820 src
= CFDataGetBytePtr(data
);
821 src_len
= CFDataGetLength(data
);
822 for (i
= 0; i
< src_len
; i
++)
828 if ((dst
= HeapAlloc(GetProcessHeap(), 0, src_len
+ new_lines
+ 1)))
832 for (i
= 0, j
= 0; i
< src_len
; i
++)
841 count
= MultiByteToWideChar(CP_UTF8
, 0, dst
, -1, NULL
, 0);
842 unicode_handle
= GlobalAlloc(GMEM_FIXED
, count
* sizeof(WCHAR
));
846 WCHAR
*textW
= GlobalLock(unicode_handle
);
847 MultiByteToWideChar(CP_UTF8
, 0, dst
, -1, textW
, count
);
848 GlobalUnlock(unicode_handle
);
851 HeapFree(GetProcessHeap(), 0, dst
);
854 return unicode_handle
;
858 /**************************************************************************
859 * import_utf16_to_unicodetext
861 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
863 static HANDLE
import_utf16_to_unicodetext(CFDataRef data
)
866 unsigned long src_len
;
867 unsigned long new_lines
= 0;
870 HANDLE unicode_handle
;
872 src
= (const WCHAR
*)CFDataGetBytePtr(data
);
873 src_len
= CFDataGetLength(data
) / sizeof(WCHAR
);
874 for (i
= 0; i
< src_len
; i
++)
878 else if (src
[i
] == '\r' && (i
+ 1 >= src_len
|| src
[i
+ 1] != '\n'))
882 if ((unicode_handle
= GlobalAlloc(GMEM_FIXED
, (src_len
+ new_lines
+ 1) * sizeof(WCHAR
))))
884 dst
= GlobalLock(unicode_handle
);
886 for (i
= 0, j
= 0; i
< src_len
; i
++)
893 if (src
[i
] == '\r' && (i
+ 1 >= src_len
|| src
[i
+ 1] != '\n'))
898 GlobalUnlock(unicode_handle
);
901 return unicode_handle
;
905 /**************************************************************************
906 * export_clipboard_data
908 * Generic export clipboard data routine.
910 static CFDataRef
export_clipboard_data(HANDLE data
)
916 len
= GlobalSize(data
);
917 src
= GlobalLock(data
);
918 if (!src
) return NULL
;
920 ret
= CFDataCreate(NULL
, src
, len
);
927 /**************************************************************************
928 * export_bitmap_to_bmp
930 * Export CF_BITMAP to BMP file format.
932 static CFDataRef
export_bitmap_to_bmp(HANDLE data
)
934 CFDataRef ret
= NULL
;
937 dib
= create_dib_from_bitmap(data
);
940 ret
= export_dib_to_bmp(dib
);
948 /**************************************************************************
951 * Export CF_DIB or CF_DIBV5 to BMP file format. This just entails
952 * prepending a BMP file format header to the data.
954 static CFDataRef
export_dib_to_bmp(HANDLE data
)
956 CFMutableDataRef ret
= NULL
;
959 BITMAPFILEHEADER bfh
;
961 dibdata
= GlobalLock(data
);
965 len
= sizeof(bfh
) + GlobalSize(data
);
966 ret
= CFDataCreateMutable(NULL
, len
);
969 bfh
.bfType
= 0x4d42; /* "BM" */
973 bfh
.bfOffBits
= sizeof(bfh
) + bitmap_info_size((BITMAPINFO
*)dibdata
, DIB_RGB_COLORS
);
974 CFDataAppendBytes(ret
, (UInt8
*)&bfh
, sizeof(bfh
));
976 /* rest of bitmap is the same as the packed dib */
977 CFDataAppendBytes(ret
, (UInt8
*)dibdata
, len
- sizeof(bfh
));
986 /**************************************************************************
989 * Export an enhanced metafile to data.
991 static CFDataRef
export_enhmetafile(HANDLE data
)
993 CFMutableDataRef ret
= NULL
;
994 unsigned int size
= GetEnhMetaFileBits(data
, 0, NULL
);
996 TRACE("data %p\n", data
);
998 ret
= CFDataCreateMutable(NULL
, size
);
1001 CFDataSetLength(ret
, size
);
1002 GetEnhMetaFileBits(data
, size
, (BYTE
*)CFDataGetMutableBytePtr(ret
));
1005 TRACE(" -> %s\n", debugstr_cf(ret
));
1010 /**************************************************************************
1011 * export_hdrop_to_filenames
1013 * Export CF_HDROP to NSFilenamesPboardType data, which is a CFArray of
1014 * CFStrings (holding Unix paths) which is serialized as a property list.
1016 static CFDataRef
export_hdrop_to_filenames(HANDLE data
)
1018 CFDataRef ret
= NULL
;
1019 DROPFILES
*dropfiles
;
1020 CFMutableArrayRef filenames
= NULL
;
1022 WCHAR
*buffer
= NULL
;
1023 size_t buffer_len
= 0;
1025 TRACE("data %p\n", data
);
1027 if (!(dropfiles
= GlobalLock(data
)))
1029 WARN("failed to lock data %p\n", data
);
1033 filenames
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1036 WARN("failed to create filenames array\n");
1040 p
= (char*)dropfiles
+ dropfiles
->pFiles
;
1041 while (dropfiles
->fWide
? *(WCHAR
*)p
: *(char*)p
)
1044 CFStringRef filename
;
1046 TRACE(" %s\n", dropfiles
->fWide
? debugstr_w(p
) : debugstr_a(p
));
1048 if (dropfiles
->fWide
)
1049 unixname
= wine_get_unix_file_name(p
);
1052 int len
= MultiByteToWideChar(CP_ACP
, 0, p
, -1, NULL
, 0);
1055 if (len
> buffer_len
)
1057 HeapFree(GetProcessHeap(), 0, buffer
);
1058 buffer_len
= len
* 2;
1059 buffer
= HeapAlloc(GetProcessHeap(), 0, buffer_len
* sizeof(*buffer
));
1062 MultiByteToWideChar(CP_ACP
, 0, p
, -1, buffer
, buffer_len
);
1063 unixname
= wine_get_unix_file_name(buffer
);
1070 WARN("failed to convert DOS path to Unix: %s\n",
1071 dropfiles
->fWide
? debugstr_w(p
) : debugstr_a(p
));
1075 if (dropfiles
->fWide
)
1076 p
= (WCHAR
*)p
+ strlenW(p
) + 1;
1078 p
= (char*)p
+ strlen(p
) + 1;
1080 filename
= CFStringCreateWithFileSystemRepresentation(NULL
, unixname
);
1081 HeapFree(GetProcessHeap(), 0, unixname
);
1084 WARN("failed to create CFString from Unix path %s\n", debugstr_a(unixname
));
1088 CFArrayAppendValue(filenames
, filename
);
1089 CFRelease(filename
);
1092 ret
= CFPropertyListCreateData(NULL
, filenames
, kCFPropertyListXMLFormat_v1_0
, 0, NULL
);
1095 HeapFree(GetProcessHeap(), 0, buffer
);
1097 if (filenames
) CFRelease(filenames
);
1098 TRACE(" -> %s\n", debugstr_cf(ret
));
1103 /**************************************************************************
1104 * export_metafilepict
1106 * Export a metafile to data.
1108 static CFDataRef
export_metafilepict(HANDLE data
)
1110 CFMutableDataRef ret
= NULL
;
1111 METAFILEPICT
*mfp
= GlobalLock(data
);
1112 unsigned int size
= GetMetaFileBitsEx(mfp
->hMF
, 0, NULL
);
1114 TRACE("data %p\n", data
);
1116 ret
= CFDataCreateMutable(NULL
, sizeof(*mfp
) + size
);
1119 CFDataAppendBytes(ret
, (UInt8
*)mfp
, sizeof(*mfp
));
1120 CFDataIncreaseLength(ret
, size
);
1121 GetMetaFileBitsEx(mfp
->hMF
, size
, (BYTE
*)CFDataGetMutableBytePtr(ret
) + sizeof(*mfp
));
1125 TRACE(" -> %s\n", debugstr_cf(ret
));
1130 /**************************************************************************
1131 * export_text_to_utf8
1133 * Export CF_TEXT to UTF-8.
1135 static CFDataRef
export_text_to_utf8(HANDLE data
)
1137 CFDataRef ret
= NULL
;
1140 if ((str
= GlobalLock(data
)))
1142 int str_len
= GlobalSize(data
);
1148 wstr_len
= MultiByteToWideChar(CP_ACP
, 0, str
, str_len
, NULL
, 0);
1149 if (!str_len
|| str
[str_len
- 1]) wstr_len
+= 1;
1150 wstr
= HeapAlloc(GetProcessHeap(), 0, wstr_len
* sizeof(WCHAR
));
1151 MultiByteToWideChar(CP_ACP
, 0, str
, str_len
, wstr
, wstr_len
);
1152 wstr
[wstr_len
- 1] = 0;
1154 unicode
= GlobalAlloc(GMEM_FIXED
, wstr_len
* sizeof(WCHAR
));
1155 if (unicode
&& (p
= GlobalLock(unicode
)))
1157 memcpy(p
, wstr
, wstr_len
* sizeof(WCHAR
));
1158 GlobalUnlock(unicode
);
1161 ret
= export_unicodetext_to_utf8(unicode
);
1163 GlobalFree(unicode
);
1171 /**************************************************************************
1172 * export_unicodetext_to_utf8
1174 * Export CF_UNICODETEXT to UTF-8.
1176 static CFDataRef
export_unicodetext_to_utf8(HANDLE data
)
1178 CFMutableDataRef ret
;
1182 src
= GlobalLock(data
);
1183 if (!src
) return NULL
;
1185 dst_len
= WideCharToMultiByte(CP_UTF8
, 0, src
, -1, NULL
, 0, NULL
, NULL
);
1186 if (dst_len
) dst_len
--; /* Leave off null terminator. */
1187 ret
= CFDataCreateMutable(NULL
, dst_len
);
1193 CFDataSetLength(ret
, dst_len
);
1194 dst
= (LPSTR
)CFDataGetMutableBytePtr(ret
);
1195 WideCharToMultiByte(CP_UTF8
, 0, src
, -1, dst
, dst_len
, NULL
, NULL
);
1197 /* Remove carriage returns */
1198 for (i
= 0, j
= 0; i
< dst_len
; i
++)
1200 if (dst
[i
] == '\r' &&
1201 (i
+ 1 >= dst_len
|| dst
[i
+ 1] == '\n' || dst
[i
+ 1] == '\0'))
1205 CFDataSetLength(ret
, j
);
1213 /**************************************************************************
1214 * export_unicodetext_to_utf16
1216 * Export CF_UNICODETEXT to UTF-16.
1218 static CFDataRef
export_unicodetext_to_utf16(HANDLE data
)
1220 CFMutableDataRef ret
;
1224 src
= GlobalLock(data
);
1225 if (!src
) return NULL
;
1227 src_len
= GlobalSize(data
) / sizeof(WCHAR
);
1228 if (src_len
) src_len
--; /* Leave off null terminator. */
1229 ret
= CFDataCreateMutable(NULL
, src_len
* sizeof(WCHAR
));
1235 CFDataSetLength(ret
, src_len
* sizeof(WCHAR
));
1236 dst
= (LPWSTR
)CFDataGetMutableBytePtr(ret
);
1238 /* Remove carriage returns */
1239 for (i
= 0, j
= 0; i
< src_len
; i
++)
1241 if (src
[i
] == '\r' &&
1242 (i
+ 1 >= src_len
|| src
[i
+ 1] == '\n' || src
[i
+ 1] == '\0'))
1246 CFDataSetLength(ret
, j
* sizeof(WCHAR
));
1254 /**************************************************************************
1255 * get_clipboard_info
1257 static BOOL
get_clipboard_info(LPCLIPBOARDINFO cbinfo
)
1261 SERVER_START_REQ(set_clipboard_info
)
1265 if (wine_server_call_err(req
))
1267 ERR("Failed to get clipboard owner.\n");
1271 cbinfo
->hwnd_owner
= wine_server_ptr_handle(reply
->old_owner
);
1272 cbinfo
->flags
= reply
->flags
;
1283 /**************************************************************************
1286 static BOOL
release_ownership(void)
1290 SERVER_START_REQ(set_clipboard_info
)
1292 req
->flags
= SET_CB_RELOWNER
| SET_CB_SEQNO
;
1294 if (wine_server_call_err(req
))
1295 ERR("Failed to set clipboard.\n");
1305 /**************************************************************************
1306 * macdrv_get_pasteboard_data
1308 HANDLE
macdrv_get_pasteboard_data(CFTypeRef pasteboard
, UINT desired_format
)
1313 CFStringRef type
, best_type
;
1314 WINE_CLIPFORMAT
* best_format
= NULL
;
1317 TRACE("pasteboard %p, desired_format %s\n", pasteboard
, debugstr_format(desired_format
));
1319 types
= macdrv_copy_pasteboard_types(pasteboard
);
1322 WARN("Failed to copy pasteboard types\n");
1326 count
= CFArrayGetCount(types
);
1327 TRACE("got %ld types\n", count
);
1329 for (i
= 0; (!best_format
|| best_format
->synthesized
) && i
< count
; i
++)
1331 WINE_CLIPFORMAT
* format
;
1333 type
= CFArrayGetValueAtIndex(types
, i
);
1336 while ((!best_format
|| best_format
->synthesized
) && (format
= format_for_type(format
, type
)))
1338 TRACE("for type %s got format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
? format
->format_id
: 0));
1340 if (format
->format_id
== desired_format
)
1342 /* The best format is the matching one which is not synthesized. Failing that,
1343 the best format is the first matching synthesized format. */
1344 if (!format
->synthesized
|| !best_format
)
1347 best_format
= format
;
1355 CFDataRef pasteboard_data
= macdrv_copy_pasteboard_data(pasteboard
, best_type
);
1357 TRACE("got pasteboard data for type %s: %s\n", debugstr_cf(best_type
), debugstr_cf(pasteboard_data
));
1359 if (pasteboard_data
)
1361 data
= best_format
->import_func(pasteboard_data
);
1362 CFRelease(pasteboard_data
);
1367 TRACE(" -> %p\n", data
);
1372 /**************************************************************************
1373 * macdrv_pasteboard_has_format
1375 BOOL
macdrv_pasteboard_has_format(CFTypeRef pasteboard
, UINT desired_format
)
1382 TRACE("pasteboard %p, desired_format %s\n", pasteboard
, debugstr_format(desired_format
));
1384 types
= macdrv_copy_pasteboard_types(pasteboard
);
1387 WARN("Failed to copy pasteboard types\n");
1391 count
= CFArrayGetCount(types
);
1392 TRACE("got %d types\n", count
);
1394 for (i
= 0; !found
&& i
< count
; i
++)
1396 CFStringRef type
= CFArrayGetValueAtIndex(types
, i
);
1397 WINE_CLIPFORMAT
* format
;
1400 while (!found
&& (format
= format_for_type(format
, type
)))
1402 TRACE("for type %s got format %s\n", debugstr_cf(type
), debugstr_format(format
->format_id
));
1404 if (format
->format_id
== desired_format
)
1410 TRACE(" -> %d\n", found
);
1415 /**************************************************************************
1416 * macdrv_copy_pasteboard_formats
1418 CFArrayRef
macdrv_copy_pasteboard_formats(CFTypeRef pasteboard
)
1422 CFMutableArrayRef formats
;
1424 WINE_CLIPFORMAT
* format
;
1426 TRACE("pasteboard %p\n", pasteboard
);
1428 types
= macdrv_copy_pasteboard_types(pasteboard
);
1431 WARN("Failed to copy pasteboard types\n");
1435 count
= CFArrayGetCount(types
);
1436 TRACE("got %ld types\n", count
);
1444 formats
= CFArrayCreateMutable(NULL
, 0, NULL
);
1447 WARN("Failed to allocate formats array\n");
1452 for (i
= 0; i
< count
; i
++)
1454 CFStringRef type
= CFArrayGetValueAtIndex(types
, i
);
1458 while ((format
= format_for_type(format
, type
)))
1460 /* Suppose type is "public.utf8-plain-text". format->format_id will be each of
1461 CF_TEXT, CF_OEMTEXT, and CF_UNICODETEXT in turn. We want to look up the natural
1462 type for each of those IDs (e.g. CF_TEXT -> "org.winehq.builtin.text") and then see
1463 if that type is present in the pasteboard. If it is, then we don't want to add the
1464 format to the list yet because it would be out of order.
1466 For example, if a Mac app put "public.utf8-plain-text" and "public.tiff" on the
1467 pasteboard, then we want the Win32 clipboard formats to be CF_TEXT, CF_OEMTEXT, and
1468 CF_UNICODETEXT, and CF_TIFF, in that order. All of the text formats belong before
1469 CF_TIFF because the Mac app expressed that text was "better" than the TIFF. In
1470 this case, as soon as we encounter "public.utf8-plain-text" we should add all of
1471 the associated text format IDs.
1473 But if a Wine process put "org.winehq.builtin.unicodetext",
1474 "public.utf8-plain-text", "public.utf16-plain-text", and "public.tiff", then we
1475 want the clipboard formats to be CF_UNICODETEXT, CF_TIFF, CF_TEXT, and CF_OEMTEXT,
1476 in that order. The Windows program presumably added CF_UNICODETEXT and CF_TIFF.
1477 We're synthesizing CF_TEXT and CF_OEMTEXT from CF_UNICODETEXT but we want them to
1478 come after the non-synthesized CF_TIFF. In this case, we don't want to add the
1479 text formats upon encountering "public.utf8-plain-text",
1481 We tell the two cases apart by seeing that one of the natural types for the text
1482 formats (i.e. "org.winehq.builtin.unicodetext") is present on the pasteboard.
1483 "found" indicates that. */
1485 if (!format
->synthesized
)
1487 TRACE("for type %s got primary format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1488 CFArrayAppendValue(formats
, (void*)format
->format_id
);
1491 else if (!found
&& format
->natural_format
&&
1492 CFArrayContainsValue(types
, CFRangeMake(0, count
), format
->natural_format
->type
))
1494 TRACE("for type %s deferring synthesized formats because type %s is also present\n",
1495 debugstr_cf(type
), debugstr_cf(format
->natural_format
->type
));
1502 while ((format
= format_for_type(format
, type
)))
1504 /* Don't override a real value with a synthesized value. */
1505 if (!CFArrayContainsValue(formats
, CFRangeMake(0, CFArrayGetCount(formats
)), (void*)format
->format_id
))
1507 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1508 CFArrayAppendValue(formats
, (void*)format
->format_id
);
1514 /* Now go back through the types adding the synthesized formats that we deferred before. */
1515 for (i
= 0; i
< count
; i
++)
1517 CFStringRef type
= CFArrayGetValueAtIndex(types
, i
);
1520 while ((format
= format_for_type(format
, type
)))
1522 if (format
->synthesized
)
1524 /* Don't override a real value with a synthesized value. */
1525 if (!CFArrayContainsValue(formats
, CFRangeMake(0, CFArrayGetCount(formats
)), (void*)format
->format_id
))
1527 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1528 CFArrayAppendValue(formats
, (void*)format
->format_id
);
1536 TRACE(" -> %s\n", debugstr_cf(formats
));
1541 /**************************************************************************
1542 * check_clipboard_ownership
1544 static void check_clipboard_ownership(HWND
*owner
)
1546 CLIPBOARDINFO cbinfo
;
1548 if (owner
) *owner
= NULL
;
1550 /* If Wine thinks we're the clipboard owner but Mac OS X thinks we're not
1551 the pasteboard owner, update Wine. */
1552 if (get_clipboard_info(&cbinfo
) && (cbinfo
.flags
& CB_PROCESS
))
1554 if (!(cbinfo
.flags
& CB_OPEN
) && !macdrv_is_pasteboard_owner())
1556 TRACE("Lost clipboard ownership\n");
1558 if (OpenClipboard(cbinfo
.hwnd_owner
))
1560 /* Destroy private objects */
1561 SendMessageW(cbinfo
.hwnd_owner
, WM_DESTROYCLIPBOARD
, 0, 0);
1563 /* Give up ownership of the windows clipboard */
1564 release_ownership();
1569 *owner
= cbinfo
.hwnd_owner
;
1574 /**************************************************************************
1575 * Mac User Driver Clipboard Exports
1576 **************************************************************************/
1579 /**************************************************************************
1580 * CountClipboardFormats (MACDRV.@)
1582 INT CDECL
macdrv_CountClipboardFormats(void)
1584 CFMutableSetRef seen_formats
;
1591 check_clipboard_ownership(NULL
);
1593 seen_formats
= CFSetCreateMutable(NULL
, 0, NULL
);
1596 WARN("Failed to allocate set to track seen formats\n");
1600 types
= macdrv_copy_pasteboard_types(NULL
);
1603 WARN("Failed to copy pasteboard types\n");
1604 CFRelease(seen_formats
);
1608 count
= CFArrayGetCount(types
);
1609 TRACE("got %ld types\n", count
);
1611 for (i
= 0; i
< count
; i
++)
1613 CFStringRef type
= CFArrayGetValueAtIndex(types
, i
);
1614 WINE_CLIPFORMAT
* format
;
1617 while ((format
= format_for_type(format
, type
)))
1619 TRACE("for type %s got format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1621 if (!CFSetContainsValue(seen_formats
, (void*)format
->format_id
))
1624 CFSetAddValue(seen_formats
, (void*)format
->format_id
);
1630 CFRelease(seen_formats
);
1631 TRACE(" -> %d\n", ret
);
1636 /**************************************************************************
1637 * EmptyClipboard (MACDRV.@)
1639 * Empty cached clipboard data.
1641 void CDECL
macdrv_EmptyClipboard(void)
1644 check_clipboard_ownership(NULL
);
1645 macdrv_clear_pasteboard();
1649 /**************************************************************************
1650 * EndClipboardUpdate (MACDRV.@)
1652 void CDECL
macdrv_EndClipboardUpdate(void)
1655 check_clipboard_ownership(NULL
);
1659 /**************************************************************************
1660 * EnumClipboardFormats (MACDRV.@)
1662 UINT CDECL
macdrv_EnumClipboardFormats(UINT prev_format
)
1669 TRACE("prev_format %s\n", debugstr_format(prev_format
));
1670 check_clipboard_ownership(NULL
);
1672 formats
= macdrv_copy_pasteboard_formats(NULL
);
1675 count
= CFArrayGetCount(formats
);
1678 i
= CFArrayGetFirstIndexOfValue(formats
, CFRangeMake(0, count
), (void*)prev_format
);
1679 if (i
!= kCFNotFound
)
1685 if (i
!= kCFNotFound
&& i
< count
)
1686 ret
= (UINT
)CFArrayGetValueAtIndex(formats
, i
);
1691 TRACE(" -> %u\n", ret
);
1696 /**************************************************************************
1697 * GetClipboardData (MACDRV.@)
1699 HANDLE CDECL
macdrv_GetClipboardData(UINT desired_format
)
1701 check_clipboard_ownership(NULL
);
1703 return macdrv_get_pasteboard_data(NULL
, desired_format
);
1707 /**************************************************************************
1708 * IsClipboardFormatAvailable (MACDRV.@)
1710 BOOL CDECL
macdrv_IsClipboardFormatAvailable(UINT desired_format
)
1712 check_clipboard_ownership(NULL
);
1713 return macdrv_pasteboard_has_format(NULL
, desired_format
);
1717 /**************************************************************************
1718 * SetClipboardData (MACDRV.@)
1720 BOOL CDECL
macdrv_SetClipboardData(UINT format_id
, HANDLE data
, BOOL owner
)
1723 macdrv_window window
;
1724 WINE_CLIPFORMAT
*format
;
1725 CFDataRef cfdata
= NULL
;
1727 check_clipboard_ownership(&hwnd_owner
);
1728 window
= macdrv_get_cocoa_window(GetAncestor(hwnd_owner
, GA_ROOT
), FALSE
);
1729 TRACE("format_id %s data %p owner %d hwnd_owner %p window %p)\n", debugstr_format(format_id
), data
, owner
, hwnd_owner
, window
);
1731 format
= natural_format_for_format(format_id
);
1732 if (!format
&& !(format
= insert_clipboard_format(format_id
, NULL
)))
1734 WARN("Failed to register clipboard format %s\n", debugstr_format(format_id
));
1738 /* Export the data to the Mac pasteboard. */
1741 if (!format
->export_func
|| !(cfdata
= format
->export_func(data
)))
1743 WARN("Failed to export %s data to type %s\n", debugstr_format(format_id
), debugstr_cf(format
->type
));
1748 if (macdrv_set_pasteboard_data(format
->type
, cfdata
, window
))
1749 TRACE("Set pasteboard data for type %s: %s\n", debugstr_cf(format
->type
), debugstr_cf(cfdata
));
1752 WARN("Failed to set pasteboard data for type %s: %s\n", debugstr_cf(format
->type
), debugstr_cf(cfdata
));
1753 if (cfdata
) CFRelease(cfdata
);
1757 if (cfdata
) CFRelease(cfdata
);
1759 /* Find any other formats for this format_id (the exportable synthesized ones). */
1760 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
1762 if (format
->format_id
== format_id
&& format
->synthesized
&& format
->export_func
)
1764 /* We have a synthesized format for this format ID. Add its type to the pasteboard. */
1765 TRACE("Synthesized from format %s: type %s\n", debugstr_format(format_id
), debugstr_cf(format
->type
));
1769 cfdata
= format
->export_func(data
);
1772 WARN("Failed to export %s data to type %s\n", debugstr_format(format
->format_id
), debugstr_cf(format
->type
));
1779 if (macdrv_set_pasteboard_data(format
->type
, cfdata
, window
))
1780 TRACE(" ... set pasteboard data: %s\n", debugstr_cf(cfdata
));
1782 WARN(" ... failed to set pasteboard data: %s\n", debugstr_cf(cfdata
));
1784 if (cfdata
) CFRelease(cfdata
);
1790 /* FIXME: According to MSDN, the caller is entitled to lock and read from
1791 data until CloseClipboard is called. So, we should defer this cleanup. */
1792 if ((format_id
>= CF_GDIOBJFIRST
&& format_id
<= CF_GDIOBJLAST
) ||
1793 format_id
== CF_BITMAP
||
1794 format_id
== CF_DIB
||
1795 format_id
== CF_PALETTE
)
1799 else if (format_id
== CF_METAFILEPICT
)
1801 DeleteMetaFile(((METAFILEPICT
*)GlobalLock(data
))->hMF
);
1804 else if (format_id
== CF_ENHMETAFILE
)
1806 DeleteEnhMetaFile(data
);
1808 else if (format_id
< CF_PRIVATEFIRST
|| CF_PRIVATELAST
< format_id
)
1818 /**************************************************************************
1819 * MACDRV Private Clipboard Exports
1820 **************************************************************************/
1823 /**************************************************************************
1824 * macdrv_clipboard_process_attach
1826 void macdrv_clipboard_process_attach(void)
1829 WINE_CLIPFORMAT
*format
;
1831 /* Register built-in formats */
1832 for (i
= 0; i
< sizeof(builtin_format_ids
)/sizeof(builtin_format_ids
[0]); i
++)
1834 if (!(format
= HeapAlloc(GetProcessHeap(), 0, sizeof(*format
)))) break;
1835 format
->format_id
= builtin_format_ids
[i
].id
;
1836 format
->type
= CFRetain(builtin_format_ids
[i
].type
);
1837 format
->import_func
= builtin_format_ids
[i
].import
;
1838 format
->export_func
= builtin_format_ids
[i
].export
;
1839 format
->synthesized
= builtin_format_ids
[i
].synthesized
;
1840 format
->natural_format
= NULL
;
1841 list_add_tail(&format_list
, &format
->entry
);
1844 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
1846 if (format
->synthesized
)
1847 format
->natural_format
= natural_format_for_format(format
->format_id
);
1850 /* Register known mappings between Windows formats and Mac types */
1851 for (i
= 0; i
< sizeof(builtin_format_names
)/sizeof(builtin_format_names
[0]); i
++)
1853 if (!(format
= HeapAlloc(GetProcessHeap(), 0, sizeof(*format
)))) break;
1854 format
->format_id
= RegisterClipboardFormatW(builtin_format_names
[i
].name
);
1855 format
->type
= CFRetain(builtin_format_names
[i
].type
);
1856 format
->import_func
= builtin_format_names
[i
].import
;
1857 format
->export_func
= builtin_format_names
[i
].export
;
1858 format
->synthesized
= FALSE
;
1859 format
->natural_format
= NULL
;
1860 list_add_tail(&format_list
, &format
->entry
);
1865 /**************************************************************************
1866 * query_pasteboard_data
1868 BOOL
query_pasteboard_data(HWND hwnd
, CFStringRef type
)
1871 CLIPBOARDINFO cbinfo
;
1872 WINE_CLIPFORMAT
* format
;
1873 CFArrayRef types
= NULL
;
1876 TRACE("hwnd %p type %s\n", hwnd
, debugstr_cf(type
));
1878 if (get_clipboard_info(&cbinfo
))
1879 hwnd
= cbinfo
.hwnd_owner
;
1882 while ((format
= format_for_type(format
, type
)))
1884 TRACE("for type %s got format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1886 if (!format
->synthesized
)
1888 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(format
->format_id
), hwnd
);
1889 SendMessageW(hwnd
, WM_RENDERFORMAT
, format
->format_id
, 0);
1896 types
= macdrv_copy_pasteboard_types(NULL
);
1899 WARN("Failed to copy pasteboard types\n");
1903 range
= CFRangeMake(0, CFArrayGetCount(types
));
1906 /* The type maps to a synthesized format. Now look up what type that format maps to natively
1907 (not synthesized). For example, if type is "public.utf8-plain-text", then this format may
1908 have an ID of CF_TEXT. From CF_TEXT, we want to find "org.winehq.builtin.text" to see if
1909 that type is present in the pasteboard. If it is, then the app must have promised it and
1910 we can ask it to render it. (If it had put it on the clipboard immediately, then the
1911 pasteboard would also have data for "public.utf8-plain-text" and we wouldn't be here.) If
1912 "org.winehq.builtin.text" is not on the pasteboard, then one of the other text formats is
1913 presumably responsible for the promise that we're trying to satisfy, so we keep looking. */
1914 if (format
->natural_format
&& CFArrayContainsValue(types
, range
, format
->natural_format
->type
))
1916 TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(format
->format_id
), hwnd
);
1917 SendMessageW(hwnd
, WM_RENDERFORMAT
, format
->format_id
, 0);
1924 if (types
) CFRelease(types
);