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
32 #define WIN32_NO_STATUS
37 #include "wine/list.h"
38 #include "wine/server.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(clipboard
);
44 /**************************************************************************
46 **************************************************************************/
48 typedef void *(*DRVIMPORTFUNC
)(CFDataRef data
, size_t *ret_size
);
49 typedef CFDataRef (*DRVEXPORTFUNC
)(void *data
, size_t size
);
51 typedef struct _WINE_CLIPFORMAT
56 DRVIMPORTFUNC import_func
;
57 DRVEXPORTFUNC export_func
;
59 struct _WINE_CLIPFORMAT
*natural_format
;
63 /**************************************************************************
65 **************************************************************************/
67 #define CLIPBOARD_UPDATE_DELAY 2000 /* delay between checks of the Mac pasteboard */
70 /**************************************************************************
71 * Forward Function Declarations
72 **************************************************************************/
74 static void *import_clipboard_data(CFDataRef data
, size_t *ret_size
);
75 static void *import_bmp_to_dib(CFDataRef data
, size_t *ret_size
);
76 static void *import_html(CFDataRef data
, size_t *ret_size
);
77 static void *import_nsfilenames_to_hdrop(CFDataRef data
, size_t *ret_size
);
78 static void *import_utf8_to_unicodetext(CFDataRef data
, size_t *ret_size
);
79 static void *import_utf16_to_unicodetext(CFDataRef data
, size_t *ret_size
);
81 static CFDataRef
export_clipboard_data(void *data
, size_t size
);
82 static CFDataRef
export_dib_to_bmp(void *data
, size_t size
);
83 static CFDataRef
export_hdrop_to_filenames(void *data
, size_t size
);
84 static CFDataRef
export_html(void *data
, size_t size
);
85 static CFDataRef
export_unicodetext_to_utf8(void *data
, size_t size
);
86 static CFDataRef
export_unicodetext_to_utf16(void *data
, size_t size
);
89 /**************************************************************************
91 **************************************************************************/
93 static const WCHAR clipboard_classname
[] =
94 {'_','_','w','i','n','e','_','c','l','i','p','b','o','a','r','d','_','m','a','n','a','g','e','r',0};
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_DIBV5
, CFSTR("org.winehq.builtin.dibv5"), import_clipboard_data
, export_clipboard_data
, FALSE
},
146 { CF_DIF
, CFSTR("org.winehq.builtin.dif"), import_clipboard_data
, export_clipboard_data
, FALSE
},
147 { CF_ENHMETAFILE
, CFSTR("org.winehq.builtin.enhmetafile"), import_clipboard_data
, export_clipboard_data
, FALSE
},
148 { CF_LOCALE
, CFSTR("org.winehq.builtin.locale"), import_clipboard_data
, export_clipboard_data
, FALSE
},
149 { CF_OEMTEXT
, CFSTR("org.winehq.builtin.oemtext"), import_clipboard_data
, export_clipboard_data
, FALSE
},
150 { CF_PALETTE
, CFSTR("org.winehq.builtin.palette"), import_clipboard_data
, export_clipboard_data
, FALSE
},
151 { CF_PENDATA
, CFSTR("org.winehq.builtin.pendata"), import_clipboard_data
, export_clipboard_data
, FALSE
},
152 { CF_RIFF
, CFSTR("org.winehq.builtin.riff"), import_clipboard_data
, export_clipboard_data
, FALSE
},
153 { CF_SYLK
, CFSTR("org.winehq.builtin.sylk"), import_clipboard_data
, export_clipboard_data
, FALSE
},
154 { CF_TEXT
, CFSTR("org.winehq.builtin.text"), import_clipboard_data
, export_clipboard_data
, FALSE
},
155 { CF_TIFF
, CFSTR("public.tiff"), import_clipboard_data
, export_clipboard_data
, FALSE
},
156 { CF_WAVE
, CFSTR("com.microsoft.waveform-audio"), import_clipboard_data
, export_clipboard_data
, FALSE
},
158 { CF_DIB
, CFSTR("org.winehq.builtin.dib"), import_clipboard_data
, export_clipboard_data
, FALSE
},
159 { CF_DIB
, CFSTR("com.microsoft.bmp"), import_bmp_to_dib
, export_dib_to_bmp
, TRUE
},
161 { CF_HDROP
, CFSTR("org.winehq.builtin.hdrop"), import_clipboard_data
, export_clipboard_data
, FALSE
},
162 { CF_HDROP
, CFSTR("NSFilenamesPboardType"), import_nsfilenames_to_hdrop
, export_hdrop_to_filenames
, TRUE
},
164 { CF_UNICODETEXT
, CFSTR("org.winehq.builtin.unicodetext"), import_clipboard_data
, export_clipboard_data
, FALSE
},
165 { CF_UNICODETEXT
, CFSTR("public.utf16-plain-text"), import_utf16_to_unicodetext
, export_unicodetext_to_utf16
,TRUE
},
166 { CF_UNICODETEXT
, CFSTR("public.utf8-plain-text"), import_utf8_to_unicodetext
, export_unicodetext_to_utf8
, TRUE
},
169 static const WCHAR wszRichTextFormat
[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
170 static const WCHAR wszGIF
[] = {'G','I','F',0};
171 static const WCHAR wszJFIF
[] = {'J','F','I','F',0};
172 static const WCHAR wszPNG
[] = {'P','N','G',0};
173 static const WCHAR wszHTMLFormat
[] = {'H','T','M','L',' ','F','o','r','m','a','t',0};
178 DRVIMPORTFUNC import
;
179 DRVEXPORTFUNC export
;
181 } builtin_format_names
[] =
183 { wszRichTextFormat
, CFSTR("public.rtf"), import_clipboard_data
, export_clipboard_data
},
184 { wszGIF
, CFSTR("com.compuserve.gif"), import_clipboard_data
, export_clipboard_data
},
185 { wszJFIF
, CFSTR("public.jpeg"), import_clipboard_data
, export_clipboard_data
},
186 { wszPNG
, CFSTR("public.png"), import_clipboard_data
, export_clipboard_data
},
187 { wszHTMLFormat
, NULL
, import_clipboard_data
, export_clipboard_data
},
188 { wszHTMLFormat
, CFSTR("public.html"), import_html
, export_html
, TRUE
},
189 { CFSTR_INETURLW
, CFSTR("public.url"), import_utf8_to_unicodetext
, export_unicodetext_to_utf8
},
192 /* The prefix prepended to a Win32 clipboard format name to make a Mac pasteboard type. */
193 static const CFStringRef registered_name_type_prefix
= CFSTR("org.winehq.registered.");
195 static unsigned int clipboard_thread_id
;
196 static HWND clipboard_hwnd
;
197 static BOOL is_clipboard_owner
;
198 static macdrv_window clipboard_cocoa_window
;
199 static unsigned int last_clipboard_update
;
200 static unsigned int last_get_seqno
;
201 static WINE_CLIPFORMAT
**current_mac_formats
;
202 static unsigned int nb_current_mac_formats
;
205 /**************************************************************************
206 * Internal Clipboard implementation methods
207 **************************************************************************/
210 * format_list functions
213 /**************************************************************************
216 static const char *debugstr_format(UINT id
)
220 if (NtUserGetClipboardFormatName(id
, buffer
, 256))
221 return wine_dbg_sprintf("0x%04x %s", id
, debugstr_w(buffer
));
225 #define BUILTIN(id) case id: return #id;
228 BUILTIN(CF_METAFILEPICT
)
238 BUILTIN(CF_UNICODETEXT
)
239 BUILTIN(CF_ENHMETAFILE
)
243 BUILTIN(CF_OWNERDISPLAY
)
245 BUILTIN(CF_DSPBITMAP
)
246 BUILTIN(CF_DSPMETAFILEPICT
)
247 BUILTIN(CF_DSPENHMETAFILE
)
249 default: return wine_dbg_sprintf("0x%04x", id
);
254 static CFTypeRef
pasteboard_from_handle(UINT64 handle
)
256 return (CFTypeRef
)(UINT_PTR
)handle
;
260 /**************************************************************************
261 * insert_clipboard_format
263 static WINE_CLIPFORMAT
*insert_clipboard_format(UINT id
, CFStringRef type
)
265 WINE_CLIPFORMAT
*format
;
267 format
= malloc(sizeof(*format
));
271 WARN("No more memory for a new format!\n");
274 format
->format_id
= id
;
275 format
->import_func
= import_clipboard_data
;
276 format
->export_func
= export_clipboard_data
;
277 format
->synthesized
= FALSE
;
278 format
->natural_format
= NULL
;
281 format
->type
= CFStringCreateCopy(NULL
, type
);
286 if (!NtUserGetClipboardFormatName(format
->format_id
, buffer
, ARRAY_SIZE(buffer
)))
288 WARN("failed to get name for format %s; error 0x%08x\n", debugstr_format(format
->format_id
),
289 (unsigned int)RtlGetLastWin32Error());
294 format
->type
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%S"),
295 registered_name_type_prefix
, (const WCHAR
*)buffer
);
298 list_add_tail(&format_list
, &format
->entry
);
300 TRACE("Registering format %s type %s\n", debugstr_format(format
->format_id
),
301 debugstr_cf(format
->type
));
307 /**************************************************************************
310 * Register a custom Mac clipboard format.
312 static WINE_CLIPFORMAT
* register_format(UINT id
, CFStringRef type
)
314 WINE_CLIPFORMAT
*format
;
316 /* walk format chain to see if it's already registered */
317 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
318 if (format
->format_id
== id
) return format
;
320 return insert_clipboard_format(id
, type
);
324 /**************************************************************************
325 * natural_format_for_format
327 * Find the "natural" format for this format_id (the one which isn't
328 * synthesized from another type).
330 static WINE_CLIPFORMAT
* natural_format_for_format(UINT format_id
)
332 WINE_CLIPFORMAT
*format
;
334 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
335 if (format
->format_id
== format_id
&& !format
->synthesized
) break;
337 if (&format
->entry
== &format_list
)
340 TRACE("%s -> %p/%s\n", debugstr_format(format_id
), format
, debugstr_cf(format
? format
->type
: NULL
));
345 static ATOM
register_clipboard_format(const WCHAR
*name
)
348 if (NtAddAtom(name
, lstrlenW(name
) * sizeof(WCHAR
), &atom
)) return 0;
353 /**************************************************************************
354 * register_builtin_formats
356 static void register_builtin_formats(void)
359 WINE_CLIPFORMAT
*format
;
361 /* Register built-in formats */
362 for (i
= 0; i
< ARRAY_SIZE(builtin_format_ids
); i
++)
364 if (!(format
= malloc(sizeof(*format
)))) break;
365 format
->format_id
= builtin_format_ids
[i
].id
;
366 format
->type
= CFRetain(builtin_format_ids
[i
].type
);
367 format
->import_func
= builtin_format_ids
[i
].import
;
368 format
->export_func
= builtin_format_ids
[i
].export
;
369 format
->synthesized
= builtin_format_ids
[i
].synthesized
;
370 format
->natural_format
= NULL
;
371 list_add_tail(&format_list
, &format
->entry
);
374 /* Register known mappings between Windows formats and Mac types */
375 for (i
= 0; i
< ARRAY_SIZE(builtin_format_names
); i
++)
377 if (!(format
= malloc(sizeof(*format
)))) break;
378 format
->format_id
= register_clipboard_format(builtin_format_names
[i
].name
);
379 format
->import_func
= builtin_format_names
[i
].import
;
380 format
->export_func
= builtin_format_names
[i
].export
;
381 format
->synthesized
= builtin_format_names
[i
].synthesized
;
382 format
->natural_format
= NULL
;
384 if (builtin_format_names
[i
].type
)
385 format
->type
= CFRetain(builtin_format_names
[i
].type
);
388 format
->type
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%S"),
389 registered_name_type_prefix
, builtin_format_names
[i
].name
);
392 list_add_tail(&format_list
, &format
->entry
);
395 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
397 if (format
->synthesized
)
398 format
->natural_format
= natural_format_for_format(format
->format_id
);
403 /**************************************************************************
406 static WINE_CLIPFORMAT
* format_for_type(CFStringRef type
)
408 WINE_CLIPFORMAT
*format
;
410 TRACE("type %s\n", debugstr_cf(type
));
412 if (list_empty(&format_list
)) register_builtin_formats();
414 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
416 if (CFEqual(format
->type
, type
))
421 if (CFStringHasPrefix(type
, CFSTR("org.winehq.builtin.")))
423 ERR("Shouldn't happen. Built-in type %s should have matched something in format list.\n",
426 else if (CFStringHasPrefix(type
, registered_name_type_prefix
))
429 int len
= CFStringGetLength(type
) - CFStringGetLength(registered_name_type_prefix
);
431 name
= malloc((len
+ 1) * sizeof(WCHAR
));
432 CFStringGetCharacters(type
, CFRangeMake(CFStringGetLength(registered_name_type_prefix
), len
),
436 format
= register_format(register_clipboard_format(name
), type
);
438 ERR("Failed to register format for type %s name %s\n", debugstr_cf(type
), debugstr_w(name
));
444 TRACE(" -> %p/%s\n", format
, debugstr_format(format
? format
->format_id
: 0));
449 /***********************************************************************
452 * Return the size of the bitmap info structure including color table.
454 static int bitmap_info_size(const BITMAPINFO
*info
, WORD coloruse
)
456 unsigned int colors
, size
, masks
= 0;
458 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
460 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
461 colors
= (core
->bcBitCount
<= 8) ? 1 << core
->bcBitCount
: 0;
462 return sizeof(BITMAPCOREHEADER
) + colors
*
463 ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBTRIPLE
) : sizeof(WORD
));
465 else /* assume BITMAPINFOHEADER */
467 colors
= min(info
->bmiHeader
.biClrUsed
, 256);
468 if (!colors
&& (info
->bmiHeader
.biBitCount
<= 8))
469 colors
= 1 << info
->bmiHeader
.biBitCount
;
470 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
) masks
= 3;
471 size
= max(info
->bmiHeader
.biSize
, sizeof(BITMAPINFOHEADER
) + masks
* sizeof(DWORD
));
472 return size
+ colors
* ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBQUAD
) : sizeof(WORD
));
477 /**************************************************************************
478 * get_html_description_field
480 * Find the value of a field in an HTML Format description.
482 static const char* get_html_description_field(const char* data
, const char* keyword
)
484 const char* pos
= data
;
486 while (pos
&& *pos
&& *pos
!= '<')
488 if (memcmp(pos
, keyword
, strlen(keyword
)) == 0)
489 return pos
+ strlen(keyword
);
491 pos
= strchr(pos
, '\n');
499 /**************************************************************************
500 * import_clipboard_data
502 * Generic import clipboard data routine.
504 static void *import_clipboard_data(CFDataRef data
, size_t *ret_size
)
508 size_t len
= CFDataGetLength(data
);
509 if (len
&& (ret
= malloc(len
)))
511 memcpy(ret
, CFDataGetBytePtr(data
), len
);
519 /**************************************************************************
522 * Import BMP data, converting to CF_DIB or CF_DIBV5 format. This just
523 * entails stripping the BMP file format header.
525 static void *import_bmp_to_dib(CFDataRef data
, size_t *ret_size
)
527 BITMAPFILEHEADER
*bfh
= (BITMAPFILEHEADER
*)CFDataGetBytePtr(data
);
528 CFIndex len
= CFDataGetLength(data
);
531 if (len
>= sizeof(*bfh
) + sizeof(BITMAPCOREHEADER
) &&
532 bfh
->bfType
== 0x4d42 /* "BM" */)
534 BITMAPINFO
*bmi
= (BITMAPINFO
*)(bfh
+ 1);
537 if ((ret
= malloc(len
)))
539 memcpy(ret
, bmi
, len
);
548 /**************************************************************************
553 static void *import_html(CFDataRef data
, size_t *ret_size
)
555 static const char header
[] =
557 "StartHTML:0000000100\n"
559 "StartFragment:%010lu\n"
560 "EndFragment:%010lu\n"
561 "<!--StartFragment-->";
562 static const char trailer
[] = "\n<!--EndFragment-->";
565 size_t size
= CFDataGetLength(data
);
567 len
= strlen(header
) + 12; /* 3 * 4 extra chars for %010lu */
568 total
= len
+ size
+ sizeof(trailer
);
569 if ((ret
= malloc(total
)))
572 p
+= snprintf(p
, total
, header
, total
- 1, len
, len
+ size
+ 1 /* include the final \n in the data */);
573 CFDataGetBytes(data
, CFRangeMake(0, size
), (UInt8
*)p
);
574 strcpy(p
+ size
, trailer
);
576 TRACE("returning %s\n", debugstr_a(ret
));
582 static CPTABLEINFO
*get_ansi_cp(void)
584 USHORT utf8_hdr
[2] = { 0, CP_UTF8
};
585 static CPTABLEINFO cp
;
588 if (NtCurrentTeb()->Peb
->AnsiCodePageData
)
589 RtlInitCodePageTable(NtCurrentTeb()->Peb
->AnsiCodePageData
, &cp
);
591 RtlInitCodePageTable(utf8_hdr
, &cp
);
597 /* based on wine_get_dos_file_name */
598 static WCHAR
*get_dos_file_name(const char *path
)
600 ULONG len
= strlen(path
) + 9; /* \??\unix prefix */
603 if (!(ret
= malloc(len
* sizeof(WCHAR
)))) return NULL
;
604 if (wine_unix_to_nt_file_name(path
, ret
, &len
))
612 /* get rid of the \??\ prefix */
613 memmove(ret
, ret
+ 4, (len
- 4) * sizeof(WCHAR
));
620 /***********************************************************************
623 * Simplified version of RtlDosPathNameToNtPathName_U.
625 static BOOL
get_nt_pathname(const WCHAR
*name
, UNICODE_STRING
*nt_name
)
627 static const WCHAR ntprefixW
[] = {'\\','?','?','\\'};
628 static const WCHAR uncprefixW
[] = {'U','N','C','\\'};
629 size_t len
= lstrlenW(name
);
632 nt_name
->MaximumLength
= (len
+ 8) * sizeof(WCHAR
);
633 if (!(ptr
= malloc(nt_name
->MaximumLength
))) return FALSE
;
634 nt_name
->Buffer
= ptr
;
636 memcpy(ptr
, ntprefixW
, sizeof(ntprefixW
));
637 ptr
+= ARRAYSIZE(ntprefixW
);
638 if (name
[0] == '\\' && name
[1] == '\\')
640 if ((name
[2] == '.' || name
[2] == '?') && name
[3] == '\\')
647 memcpy(ptr
, uncprefixW
, sizeof(uncprefixW
));
648 ptr
+= ARRAYSIZE(uncprefixW
);
653 memcpy(ptr
, name
, (len
+ 1) * sizeof(WCHAR
));
655 nt_name
->Length
= (ptr
- nt_name
->Buffer
) * sizeof(WCHAR
);
660 /* based on wine_get_unix_file_name */
661 static char *get_unix_file_name(const WCHAR
*dosW
)
663 UNICODE_STRING nt_name
;
664 OBJECT_ATTRIBUTES attr
;
669 if (!get_nt_pathname(dosW
, &nt_name
)) return NULL
;
670 InitializeObjectAttributes(&attr
, &nt_name
, 0, 0, NULL
);
673 if (!(buffer
= malloc(size
)))
675 free(nt_name
.Buffer
);
678 status
= wine_nt_to_unix_file_name(&attr
, buffer
, &size
, FILE_OPEN_IF
);
679 if (status
!= STATUS_BUFFER_TOO_SMALL
) break;
682 free(nt_name
.Buffer
);
692 /**************************************************************************
693 * import_nsfilenames_to_hdrop
695 * Import NSFilenamesPboardType data, converting the property-list-
696 * serialized array of path strings to CF_HDROP.
698 static void *import_nsfilenames_to_hdrop(CFDataRef data
, size_t *ret_size
)
704 WCHAR
**paths
= NULL
;
705 DROPFILES
*dropfiles
= NULL
;
708 TRACE("data %s\n", debugstr_cf(data
));
710 names
= (CFArrayRef
)CFPropertyListCreateWithData(NULL
, data
, kCFPropertyListImmutable
,
712 if (!names
|| CFGetTypeID(names
) != CFArrayGetTypeID())
714 WARN("failed to interpret data as a CFArray\n");
718 count
= CFArrayGetCount(names
);
721 for (i
= 0; i
< count
; i
++)
724 CFStringRef name
= (CFStringRef
)CFArrayGetValueAtIndex(names
, i
);
725 TRACE(" %s\n", debugstr_cf(name
));
726 if (CFGetTypeID(name
) != CFStringGetTypeID())
728 WARN("non-string in array\n");
732 this_len
= CFStringGetMaximumSizeOfFileSystemRepresentation(name
);
737 buffer
= malloc(len
);
740 WARN("failed to allocate buffer for file-system representations\n");
744 paths
= calloc(count
, sizeof(paths
[0]));
747 WARN("failed to allocate array of DOS paths\n");
751 for (i
= 0; i
< count
; i
++)
753 CFStringRef name
= (CFStringRef
)CFArrayGetValueAtIndex(names
, i
);
754 if (!CFStringGetFileSystemRepresentation(name
, buffer
, len
))
756 WARN("failed to get file-system representation for %s\n", debugstr_cf(name
));
759 paths
[i
] = get_dos_file_name(buffer
);
762 WARN("failed to get DOS path for %s\n", debugstr_a(buffer
));
767 len
= 1; /* for the terminating null */
768 for (i
= 0; i
< count
; i
++)
769 len
+= wcslen(paths
[i
]) + 1;
771 *ret_size
= sizeof(*dropfiles
) + len
* sizeof(WCHAR
);
772 if (!(dropfiles
= malloc(*ret_size
)))
774 WARN("failed to allocate HDROP\n");
778 dropfiles
->pFiles
= sizeof(*dropfiles
);
781 dropfiles
->fNC
= FALSE
;
782 dropfiles
->fWide
= TRUE
;
784 p
= (WCHAR
*)(dropfiles
+ 1);
785 for (i
= 0; i
< count
; i
++)
795 for (i
= 0; i
< count
; i
++) free(paths
[i
]);
799 if (names
) CFRelease(names
);
804 /**************************************************************************
805 * import_utf8_to_unicodetext
807 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
809 static void *import_utf8_to_unicodetext(CFDataRef data
, size_t *ret_size
)
812 unsigned long src_len
;
813 unsigned long new_lines
= 0;
818 src
= CFDataGetBytePtr(data
);
819 src_len
= CFDataGetLength(data
);
820 for (i
= 0; i
< src_len
; i
++)
826 if ((dst
= malloc(src_len
+ new_lines
+ 1)))
828 for (i
= 0, j
= 0; i
< src_len
; i
++)
837 if ((ret
= malloc(j
* sizeof(WCHAR
))))
840 RtlUTF8ToUnicodeN(ret
, j
* sizeof(WCHAR
), &dst_size
, dst
, j
);
841 *ret_size
= dst_size
;
851 /**************************************************************************
852 * import_utf16_to_unicodetext
854 * Import a UTF-8 string, converting the string to CF_UNICODETEXT.
856 static void *import_utf16_to_unicodetext(CFDataRef data
, size_t *ret_size
)
859 unsigned long src_len
;
860 unsigned long new_lines
= 0;
864 src
= (const WCHAR
*)CFDataGetBytePtr(data
);
865 src_len
= CFDataGetLength(data
) / sizeof(WCHAR
);
866 for (i
= 0; i
< src_len
; i
++)
870 else if (src
[i
] == '\r' && (i
+ 1 >= src_len
|| src
[i
+ 1] != '\n'))
874 *ret_size
= (src_len
+ new_lines
+ 1) * sizeof(WCHAR
);
875 if ((dst
= malloc(*ret_size
)))
877 for (i
= 0, j
= 0; i
< src_len
; i
++)
884 if (src
[i
] == '\r' && (i
+ 1 >= src_len
|| src
[i
+ 1] != '\n'))
894 /**************************************************************************
895 * export_clipboard_data
897 * Generic export clipboard data routine.
899 static CFDataRef
export_clipboard_data(void *data
, size_t size
)
901 return CFDataCreate(NULL
, data
, size
);
905 /**************************************************************************
908 * Export CF_DIB or CF_DIBV5 to BMP file format. This just entails
909 * prepending a BMP file format header to the data.
911 static CFDataRef
export_dib_to_bmp(void *data
, size_t size
)
913 CFMutableDataRef ret
= NULL
;
915 BITMAPFILEHEADER bfh
;
917 len
= sizeof(bfh
) + size
;
918 ret
= CFDataCreateMutable(NULL
, len
);
921 bfh
.bfType
= 0x4d42; /* "BM" */
925 bfh
.bfOffBits
= sizeof(bfh
) + bitmap_info_size(data
, DIB_RGB_COLORS
);
926 CFDataAppendBytes(ret
, (UInt8
*)&bfh
, sizeof(bfh
));
928 /* rest of bitmap is the same as the packed dib */
929 CFDataAppendBytes(ret
, data
, size
);
936 /**************************************************************************
937 * export_hdrop_to_filenames
939 * Export CF_HDROP to NSFilenamesPboardType data, which is a CFArray of
940 * CFStrings (holding Unix paths) which is serialized as a property list.
942 static CFDataRef
export_hdrop_to_filenames(void *data
, size_t size
)
944 CFDataRef ret
= NULL
;
945 DROPFILES
*dropfiles
= data
;
946 CFMutableArrayRef filenames
= NULL
;
948 WCHAR
*buffer
= NULL
;
949 size_t buffer_len
= 0;
951 TRACE("data %p\n", data
);
953 filenames
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
956 WARN("failed to create filenames array\n");
960 p
= (char*)dropfiles
+ dropfiles
->pFiles
;
961 while (dropfiles
->fWide
? *(WCHAR
*)p
: *(char*)p
)
964 CFStringRef filename
;
966 TRACE(" %s\n", dropfiles
->fWide
? debugstr_w(p
) : debugstr_a(p
));
968 if (dropfiles
->fWide
)
969 unixname
= get_unix_file_name(p
);
972 CPTABLEINFO
*cp
= get_ansi_cp();
973 DWORD len
= strlen(p
) + 1;
975 if (len
* 3 > buffer_len
)
978 buffer_len
= len
* 3;
979 buffer
= malloc(buffer_len
* sizeof(*buffer
));
982 if (cp
->CodePage
== CP_UTF8
)
983 RtlUTF8ToUnicodeN(buffer
, buffer_len
* sizeof(WCHAR
), &len
, p
, len
);
985 RtlCustomCPToUnicodeN(cp
, buffer
, buffer_len
* sizeof(WCHAR
), &len
, p
, len
);
987 unixname
= get_unix_file_name(buffer
);
991 WARN("failed to convert DOS path to Unix: %s\n",
992 dropfiles
->fWide
? debugstr_w(p
) : debugstr_a(p
));
996 if (dropfiles
->fWide
)
997 p
= (WCHAR
*)p
+ wcslen(p
) + 1;
999 p
= (char*)p
+ strlen(p
) + 1;
1001 filename
= CFStringCreateWithFileSystemRepresentation(NULL
, unixname
);
1004 WARN("failed to create CFString from Unix path %s\n", debugstr_a(unixname
));
1010 CFArrayAppendValue(filenames
, filename
);
1011 CFRelease(filename
);
1014 ret
= CFPropertyListCreateData(NULL
, filenames
, kCFPropertyListXMLFormat_v1_0
, 0, NULL
);
1018 if (filenames
) CFRelease(filenames
);
1019 TRACE(" -> %s\n", debugstr_cf(ret
));
1024 /**************************************************************************
1027 * Export HTML Format to public.html data.
1029 * FIXME: We should attempt to add an <a base> tag and convert windows paths.
1031 static CFDataRef
export_html(void *data
, size_t size
)
1033 const char *field_value
;
1034 int fragmentstart
, fragmentend
;
1036 /* read the important fields */
1037 field_value
= get_html_description_field(data
, "StartFragment:");
1040 ERR("Couldn't find StartFragment value\n");
1043 fragmentstart
= atoi(field_value
);
1045 field_value
= get_html_description_field(data
, "EndFragment:");
1048 ERR("Couldn't find EndFragment value\n");
1051 fragmentend
= atoi(field_value
);
1053 /* export only the fragment */
1054 return CFDataCreate(NULL
, &((const UInt8
*)data
)[fragmentstart
], fragmentend
- fragmentstart
);
1058 /**************************************************************************
1059 * export_unicodetext_to_utf8
1061 * Export CF_UNICODETEXT to UTF-8.
1063 static CFDataRef
export_unicodetext_to_utf8(void *data
, size_t size
)
1065 CFMutableDataRef ret
;
1069 /* Leave off null terminator. */
1070 if (size
>= sizeof(WCHAR
) && !src
[size
/ sizeof(WCHAR
) - 1]) size
-= sizeof(WCHAR
);
1071 RtlUnicodeToUTF8N(NULL
, 0, &dst_len
, src
, size
);
1072 ret
= CFDataCreateMutable(NULL
, dst_len
);
1078 CFDataSetLength(ret
, dst_len
);
1079 dst
= (LPSTR
)CFDataGetMutableBytePtr(ret
);
1080 RtlUnicodeToUTF8N(dst
, dst_len
, &dst_len
, src
, size
);
1082 /* Remove carriage returns */
1083 for (i
= 0, j
= 0; i
< dst_len
; i
++)
1085 if (dst
[i
] == '\r' &&
1086 (i
+ 1 >= dst_len
|| dst
[i
+ 1] == '\n' || dst
[i
+ 1] == '\0'))
1090 CFDataSetLength(ret
, j
);
1097 /**************************************************************************
1098 * export_unicodetext_to_utf16
1100 * Export CF_UNICODETEXT to UTF-16.
1102 static CFDataRef
export_unicodetext_to_utf16(void *data
, size_t size
)
1104 CFMutableDataRef ret
;
1105 const WCHAR
*src
= data
;
1108 src_len
= size
/ sizeof(WCHAR
);
1109 if (src_len
) src_len
--; /* Leave off null terminator. */
1110 ret
= CFDataCreateMutable(NULL
, src_len
* sizeof(WCHAR
));
1116 CFDataSetLength(ret
, src_len
* sizeof(WCHAR
));
1117 dst
= (LPWSTR
)CFDataGetMutableBytePtr(ret
);
1119 /* Remove carriage returns */
1120 for (i
= 0, j
= 0; i
< src_len
; i
++)
1122 if (src
[i
] == '\r' &&
1123 (i
+ 1 >= src_len
|| src
[i
+ 1] == '\n' || src
[i
+ 1] == '\0'))
1127 CFDataSetLength(ret
, j
* sizeof(WCHAR
));
1134 /**************************************************************************
1135 * macdrv_dnd_get_data
1137 NTSTATUS
macdrv_dnd_get_data(void *arg
)
1139 struct dnd_get_data_params
*params
= arg
;
1140 CFTypeRef pasteboard
= pasteboard_from_handle(params
->handle
);
1144 CFStringRef type
, best_type
;
1145 WINE_CLIPFORMAT
* best_format
= NULL
;
1146 unsigned int status
= STATUS_SUCCESS
;
1148 TRACE("pasteboard %p, desired_format %s\n", pasteboard
, debugstr_format(params
->format
));
1150 types
= macdrv_copy_pasteboard_types(pasteboard
);
1153 WARN("Failed to copy pasteboard types\n");
1154 return STATUS_NO_MEMORY
;
1157 count
= CFArrayGetCount(types
);
1158 TRACE("got %ld types\n", count
);
1160 for (i
= 0; (!best_format
|| best_format
->synthesized
) && i
< count
; i
++)
1162 WINE_CLIPFORMAT
* format
;
1164 type
= CFArrayGetValueAtIndex(types
, i
);
1166 if ((format
= format_for_type(type
)))
1168 TRACE("for type %s got format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1170 if (format
->format_id
== params
->format
)
1172 /* The best format is the matching one which is not synthesized. Failing that,
1173 the best format is the first matching synthesized format. */
1174 if (!format
->synthesized
|| !best_format
)
1177 best_format
= format
;
1185 CFDataRef pasteboard_data
= macdrv_copy_pasteboard_data(pasteboard
, best_type
);
1187 TRACE("got pasteboard data for type %s: %s\n", debugstr_cf(best_type
), debugstr_cf(pasteboard_data
));
1189 if (pasteboard_data
)
1192 void *import
= best_format
->import_func(pasteboard_data
, &size
);
1195 if (size
> params
->size
) status
= STATUS_BUFFER_OVERFLOW
;
1196 else memcpy(params
->data
, import
, size
);
1197 params
->size
= size
;
1200 CFRelease(pasteboard_data
);
1205 TRACE(" -> %#x\n", status
);
1210 /**************************************************************************
1211 * macdrv_pasteboard_has_format
1213 NTSTATUS
macdrv_dnd_have_format(void *arg
)
1215 struct dnd_have_format_params
*params
= arg
;
1216 CFTypeRef pasteboard
= pasteboard_from_handle(params
->handle
);
1222 TRACE("pasteboard %p, desired_format %s\n", pasteboard
, debugstr_format(params
->format
));
1224 types
= macdrv_copy_pasteboard_types(pasteboard
);
1227 WARN("Failed to copy pasteboard types\n");
1231 count
= CFArrayGetCount(types
);
1232 TRACE("got %d types\n", count
);
1234 for (i
= 0; i
< count
; i
++)
1236 CFStringRef type
= CFArrayGetValueAtIndex(types
, i
);
1237 WINE_CLIPFORMAT
* format
= format_for_type(type
);
1241 TRACE("for type %s got format %s\n", debugstr_cf(type
), debugstr_format(format
->format_id
));
1243 if (format
->format_id
== params
->format
)
1252 TRACE(" -> %d\n", found
);
1257 /**************************************************************************
1258 * get_formats_for_pasteboard_types
1260 static WINE_CLIPFORMAT
** get_formats_for_pasteboard_types(CFArrayRef types
, UINT
*num_formats
)
1263 CFMutableSetRef seen_formats
;
1264 WINE_CLIPFORMAT
** formats
;
1267 count
= CFArrayGetCount(types
);
1268 TRACE("got %ld types\n", count
);
1273 seen_formats
= CFSetCreateMutable(NULL
, count
, NULL
);
1276 WARN("Failed to allocate seen formats set\n");
1280 formats
= malloc(count
* sizeof(*formats
));
1283 WARN("Failed to allocate formats array\n");
1284 CFRelease(seen_formats
);
1289 for (i
= 0; i
< count
; i
++)
1291 CFStringRef type
= CFArrayGetValueAtIndex(types
, i
);
1292 WINE_CLIPFORMAT
* format
= format_for_type(type
);
1296 TRACE("ignoring type %s\n", debugstr_cf(type
));
1300 if (!format
->synthesized
)
1302 TRACE("for type %s got format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1303 CFSetAddValue(seen_formats
, ULongToPtr(format
->format_id
));
1304 formats
[pos
++] = format
;
1306 else if (format
->natural_format
&&
1307 CFArrayContainsValue(types
, CFRangeMake(0, count
), format
->natural_format
->type
))
1309 TRACE("for type %s deferring synthesized formats because type %s is also present\n",
1310 debugstr_cf(type
), debugstr_cf(format
->natural_format
->type
));
1312 else if (CFSetContainsValue(seen_formats
, ULongToPtr(format
->format_id
)))
1314 TRACE("for type %s got duplicate synthesized format %p/%s; skipping\n", debugstr_cf(type
), format
,
1315 debugstr_format(format
->format_id
));
1319 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1320 CFSetAddValue(seen_formats
, ULongToPtr(format
->format_id
));
1321 formats
[pos
++] = format
;
1325 /* Now go back through the types adding the synthesized formats that we deferred before. */
1326 for (i
= 0; i
< count
; i
++)
1328 CFStringRef type
= CFArrayGetValueAtIndex(types
, i
);
1329 WINE_CLIPFORMAT
* format
= format_for_type(type
);
1331 if (!format
) continue;
1332 if (!format
->synthesized
) continue;
1334 /* Don't duplicate a real value with a synthesized value. */
1335 if (CFSetContainsValue(seen_formats
, ULongToPtr(format
->format_id
))) continue;
1337 TRACE("for type %s got synthesized format %p/%s\n", debugstr_cf(type
), format
, debugstr_format(format
->format_id
));
1338 CFSetAddValue(seen_formats
, ULongToPtr(format
->format_id
));
1339 formats
[pos
++] = format
;
1342 CFRelease(seen_formats
);
1355 /**************************************************************************
1356 * get_formats_for_pasteboard
1358 static WINE_CLIPFORMAT
** get_formats_for_pasteboard(CFTypeRef pasteboard
, UINT
*num_formats
)
1361 WINE_CLIPFORMAT
** formats
;
1363 TRACE("pasteboard %s\n", debugstr_cf(pasteboard
));
1365 types
= macdrv_copy_pasteboard_types(pasteboard
);
1368 WARN("Failed to copy pasteboard types\n");
1372 formats
= get_formats_for_pasteboard_types(types
, num_formats
);
1378 /**************************************************************************
1379 * macdrv_dnd_get_formats
1381 NTSTATUS
macdrv_dnd_get_formats(void *arg
)
1383 struct dnd_get_formats_params
*params
= arg
;
1384 CFTypeRef pasteboard
= pasteboard_from_handle(params
->handle
);
1385 WINE_CLIPFORMAT
** formats
;
1388 formats
= get_formats_for_pasteboard(pasteboard
, &count
);
1391 count
= min(count
, ARRAYSIZE(params
->formats
));
1393 for (i
= 0; i
< count
; i
++)
1394 params
->formats
[i
] = formats
[i
]->format_id
;
1400 /**************************************************************************
1401 * register_win32_formats
1403 * Register Win32 clipboard formats the first time we encounter them.
1405 static void register_win32_formats(const UINT
*ids
, UINT size
)
1409 if (list_empty(&format_list
)) register_builtin_formats();
1411 for (i
= 0; i
< size
; i
++)
1412 register_format(ids
[i
], NULL
);
1416 /***********************************************************************
1417 * get_clipboard_formats
1419 * Return a list of all formats currently available on the Win32 clipboard.
1420 * Helper for set_mac_pasteboard_types_from_win32_clipboard.
1422 static UINT
*get_clipboard_formats(UINT
*size
)
1429 if (!(ids
= malloc(*size
* sizeof(*ids
)))) return NULL
;
1430 if (NtUserGetUpdatedClipboardFormats(ids
, *size
, size
)) break;
1432 if (RtlGetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER
) return NULL
;
1434 register_win32_formats(ids
, *size
);
1439 /**************************************************************************
1440 * set_mac_pasteboard_types_from_win32_clipboard
1442 static void set_mac_pasteboard_types_from_win32_clipboard(void)
1444 WINE_CLIPFORMAT
*format
;
1445 UINT count
, i
, *formats
;
1447 if (!(formats
= get_clipboard_formats(&count
))) return;
1449 macdrv_clear_pasteboard(clipboard_cocoa_window
);
1451 for (i
= 0; i
< count
; i
++)
1453 LIST_FOR_EACH_ENTRY(format
, &format_list
, WINE_CLIPFORMAT
, entry
)
1455 if (format
->format_id
!= formats
[i
]) continue;
1456 TRACE("%s -> %s\n", debugstr_format(format
->format_id
), debugstr_cf(format
->type
));
1457 macdrv_set_pasteboard_data(format
->type
, NULL
, clipboard_cocoa_window
);
1466 /**************************************************************************
1467 * set_win32_clipboard_formats_from_mac_pasteboard
1469 static void set_win32_clipboard_formats_from_mac_pasteboard(CFArrayRef types
)
1471 WINE_CLIPFORMAT
** formats
;
1474 formats
= get_formats_for_pasteboard_types(types
, &count
);
1478 for (i
= 0; i
< count
; i
++)
1480 struct set_clipboard_params params
= { 0 };
1481 TRACE("adding format %s\n", debugstr_format(formats
[i
]->format_id
));
1482 NtUserSetClipboardData(formats
[i
]->format_id
, 0, ¶ms
);
1485 free(current_mac_formats
);
1486 current_mac_formats
= formats
;
1487 nb_current_mac_formats
= count
;
1491 /**************************************************************************
1494 static void render_format(UINT id
)
1498 for (i
= 0; i
< nb_current_mac_formats
; i
++)
1500 CFDataRef pasteboard_data
;
1502 if (current_mac_formats
[i
]->format_id
!= id
) continue;
1504 pasteboard_data
= macdrv_copy_pasteboard_data(NULL
, current_mac_formats
[i
]->type
);
1505 if (pasteboard_data
)
1507 struct set_clipboard_params params
= { 0 };
1508 params
.data
= current_mac_formats
[i
]->import_func(pasteboard_data
, ¶ms
.size
);
1509 CFRelease(pasteboard_data
);
1510 if (!params
.data
) continue;
1511 NtUserSetClipboardData(id
, 0, ¶ms
);
1519 /**************************************************************************
1520 * grab_win32_clipboard
1522 * Grab the Win32 clipboard when a Mac app has taken ownership of the
1523 * pasteboard, and fill it with the pasteboard data types.
1525 static void grab_win32_clipboard(void)
1527 static CFArrayRef last_types
;
1530 types
= macdrv_copy_pasteboard_types(NULL
);
1533 WARN("Failed to copy pasteboard types\n");
1537 if (!macdrv_has_pasteboard_changed() && last_types
&& CFEqual(types
, last_types
))
1543 if (last_types
) CFRelease(last_types
);
1544 last_types
= types
; /* takes ownership */
1546 if (!NtUserOpenClipboard(clipboard_hwnd
, 0)) return;
1547 NtUserEmptyClipboard();
1548 is_clipboard_owner
= TRUE
;
1549 last_clipboard_update
= NtGetTickCount();
1550 set_win32_clipboard_formats_from_mac_pasteboard(types
);
1551 NtUserCloseClipboard();
1552 NtUserSetTimer(clipboard_hwnd
, 1, CLIPBOARD_UPDATE_DELAY
, NULL
, TIMERV_DEFAULT_COALESCING
);
1556 /**************************************************************************
1559 * Periodically update the clipboard while the clipboard is owned by a
1562 static void update_clipboard(void)
1564 static BOOL updating
;
1566 TRACE("is_clipboard_owner %d last_clipboard_update %u now %u\n",
1567 is_clipboard_owner
, last_clipboard_update
, (unsigned int)NtGetTickCount());
1569 if (updating
) return;
1572 if (is_clipboard_owner
)
1574 if (NtGetTickCount() - last_clipboard_update
> CLIPBOARD_UPDATE_DELAY
)
1575 grab_win32_clipboard();
1577 else if (!macdrv_is_pasteboard_owner(clipboard_cocoa_window
))
1578 grab_win32_clipboard();
1584 static BOOL
init_clipboard(HWND hwnd
)
1586 struct macdrv_window_features wf
;
1588 memset(&wf
, 0, sizeof(wf
));
1589 clipboard_cocoa_window
= macdrv_create_cocoa_window(&wf
, CGRectMake(100, 100, 100, 100), hwnd
,
1590 macdrv_init_thread_data()->queue
);
1591 if (!clipboard_cocoa_window
)
1593 ERR("failed to create clipboard Cocoa window\n");
1597 clipboard_hwnd
= hwnd
;
1598 clipboard_thread_id
= GetCurrentThreadId();
1599 NtUserAddClipboardFormatListener(clipboard_hwnd
);
1600 register_builtin_formats();
1601 grab_win32_clipboard();
1603 TRACE("clipboard thread %04x running\n", clipboard_thread_id
);
1608 /**************************************************************************
1609 * macdrv_ClipboardWindowProc
1611 * Window procedure for the clipboard manager.
1613 LRESULT
macdrv_ClipboardWindowProc(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1618 return init_clipboard(hwnd
);
1619 case WM_CLIPBOARDUPDATE
:
1620 if (is_clipboard_owner
) break; /* ignore our own changes */
1621 if ((LONG
)(NtUserGetClipboardSequenceNumber() - last_get_seqno
) <= 0) break;
1622 set_mac_pasteboard_types_from_win32_clipboard();
1624 case WM_RENDERFORMAT
:
1628 if (!is_clipboard_owner
) break;
1629 grab_win32_clipboard();
1631 case WM_DESTROYCLIPBOARD
:
1632 TRACE("WM_DESTROYCLIPBOARD: lost ownership\n");
1633 is_clipboard_owner
= FALSE
;
1634 NtUserKillTimer(hwnd
, 1);
1640 return NtUserMessageCall(hwnd
, msg
, wp
, lp
, NULL
, NtUserDefWindowProc
, FALSE
);
1644 /**************************************************************************
1645 * Mac User Driver Clipboard Exports
1646 **************************************************************************/
1649 /**************************************************************************
1650 * macdrv_UpdateClipboard
1652 void macdrv_UpdateClipboard(void)
1654 static ULONG last_update
;
1655 static HWND clipboard_manager
;
1659 if (GetCurrentThreadId() == clipboard_thread_id
) return;
1663 now
= NtGetTickCount();
1664 if (last_update
&& (int)(now
- last_update
) <= CLIPBOARD_UPDATE_DELAY
) return;
1666 if (!NtUserIsWindow(clipboard_manager
))
1668 UNICODE_STRING str
= RTL_CONSTANT_STRING(clipboard_classname
);
1669 clipboard_manager
= NtUserFindWindowEx(NULL
, NULL
, &str
, NULL
, 0);
1670 if (!clipboard_manager
)
1672 ERR("clipboard manager not found\n");
1677 send_message_timeout(clipboard_manager
, WM_USER
, 0, 0,
1678 SMTO_ABORTIFHUNG
, 5000, &ret
);
1683 /**************************************************************************
1684 * MACDRV Private Clipboard Exports
1685 **************************************************************************/
1688 /**************************************************************************
1689 * query_pasteboard_data
1691 BOOL
query_pasteboard_data(HWND hwnd
, CFStringRef type
)
1693 struct get_clipboard_params params
= { .data_only
= TRUE
, .size
= 1024 };
1694 WINE_CLIPFORMAT
*format
;
1697 TRACE("win %p/%p type %s\n", hwnd
, clipboard_cocoa_window
, debugstr_cf(type
));
1699 format
= format_for_type(type
);
1700 if (!format
) return FALSE
;
1702 if (!NtUserOpenClipboard(clipboard_hwnd
, 0))
1704 ERR("failed to open clipboard for %s\n", debugstr_cf(type
));
1710 if (!(params
.data
= malloc(params
.size
))) break;
1711 if (NtUserGetClipboardData(format
->format_id
, ¶ms
))
1715 TRACE("exporting %s\n", debugstr_format(format
->format_id
));
1717 if ((data
= format
->export_func(params
.data
, params
.size
)))
1719 ret
= macdrv_set_pasteboard_data(format
->type
, data
, clipboard_cocoa_window
);
1726 if (!params
.data_size
) break;
1727 params
.size
= params
.data_size
;
1728 params
.data_size
= 0;
1731 last_get_seqno
= NtUserGetClipboardSequenceNumber();
1733 NtUserCloseClipboard();
1739 /**************************************************************************
1740 * macdrv_lost_pasteboard_ownership
1742 * Handler for the LOST_PASTEBOARD_OWNERSHIP event.
1744 void macdrv_lost_pasteboard_ownership(HWND hwnd
)
1746 TRACE("win %p\n", hwnd
);
1747 if (!macdrv_is_pasteboard_owner(clipboard_cocoa_window
))
1748 grab_win32_clipboard();
1752 /**************************************************************************
1753 * macdrv_dnd_release
1755 NTSTATUS
macdrv_dnd_release(void *arg
)
1757 UINT64 handle
= *(UINT64
*)arg
;
1758 CFRelease(pasteboard_from_handle(handle
));
1763 /**************************************************************************
1766 NTSTATUS
macdrv_dnd_retain(void *arg
)
1768 UINT64 handle
= *(UINT64
*)arg
;
1769 CFRetain(pasteboard_from_handle(handle
));