winemac: Add support for delay-rendered (a.k.a. promised) clipboard data.
This commit is contained in:
parent
69e631e04e
commit
449e2655c2
|
@ -1102,18 +1102,12 @@ BOOL CDECL macdrv_SetClipboardData(UINT format_id, HANDLE data, BOOL owner)
|
|||
HWND hwnd_owner;
|
||||
macdrv_window window;
|
||||
WINE_CLIPFORMAT *format;
|
||||
CFDataRef cfdata;
|
||||
CFDataRef cfdata = NULL;
|
||||
|
||||
check_clipboard_ownership(&hwnd_owner);
|
||||
window = macdrv_get_cocoa_window(GetAncestor(hwnd_owner, GA_ROOT), FALSE);
|
||||
TRACE("format_id %s data %p owner %d hwnd_owner %p window %p)\n", debugstr_format(format_id), data, owner, hwnd_owner, window);
|
||||
|
||||
if (!data)
|
||||
{
|
||||
FIXME("delayed rendering (promising) is not implemented yet\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Find the "natural" format for this format_id (the one which isn't
|
||||
synthesized from another type). */
|
||||
LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
|
||||
|
@ -1126,22 +1120,25 @@ BOOL CDECL macdrv_SetClipboardData(UINT format_id, HANDLE data, BOOL owner)
|
|||
}
|
||||
|
||||
/* Export the data to the Mac pasteboard. */
|
||||
if (!format->export_func || !(cfdata = format->export_func(data)))
|
||||
if (data)
|
||||
{
|
||||
WARN("Failed to export %s data to type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
|
||||
return FALSE;
|
||||
if (!format->export_func || !(cfdata = format->export_func(data)))
|
||||
{
|
||||
WARN("Failed to export %s data to type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (macdrv_set_pasteboard_data(format->type, cfdata))
|
||||
if (macdrv_set_pasteboard_data(format->type, cfdata, window))
|
||||
TRACE("Set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
|
||||
else
|
||||
{
|
||||
WARN("Failed to set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
|
||||
CFRelease(cfdata);
|
||||
if (cfdata) CFRelease(cfdata);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CFRelease(cfdata);
|
||||
if (cfdata) CFRelease(cfdata);
|
||||
|
||||
/* Find any other formats for this format_id (the exportable synthesized ones). */
|
||||
LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
|
||||
|
@ -1151,43 +1148,51 @@ BOOL CDECL macdrv_SetClipboardData(UINT format_id, HANDLE data, BOOL owner)
|
|||
/* We have a synthesized format for this format ID. Add its type to the pasteboard. */
|
||||
TRACE("Synthesized from format %s: type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
|
||||
|
||||
cfdata = format->export_func(data);
|
||||
if (!cfdata)
|
||||
if (data)
|
||||
{
|
||||
WARN("Failed to export %s data to type %s\n", debugstr_format(format->format_id), debugstr_cf(format->type));
|
||||
continue;
|
||||
cfdata = format->export_func(data);
|
||||
if (!cfdata)
|
||||
{
|
||||
WARN("Failed to export %s data to type %s\n", debugstr_format(format->format_id), debugstr_cf(format->type));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
cfdata = NULL;
|
||||
|
||||
if (macdrv_set_pasteboard_data(format->type, cfdata))
|
||||
if (macdrv_set_pasteboard_data(format->type, cfdata, window))
|
||||
TRACE(" ... set pasteboard data: %s\n", debugstr_cf(cfdata));
|
||||
else
|
||||
WARN(" ... failed to set pasteboard data: %s\n", debugstr_cf(cfdata));
|
||||
|
||||
CFRelease(cfdata);
|
||||
if (cfdata) CFRelease(cfdata);
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: According to MSDN, the caller is entitled to lock and read from
|
||||
data until CloseClipboard is called. So, we should defer this cleanup. */
|
||||
if ((format_id >= CF_GDIOBJFIRST && format_id <= CF_GDIOBJLAST) ||
|
||||
format_id == CF_BITMAP ||
|
||||
format_id == CF_DIB ||
|
||||
format_id == CF_PALETTE)
|
||||
if (data)
|
||||
{
|
||||
DeleteObject(data);
|
||||
}
|
||||
else if (format_id == CF_METAFILEPICT)
|
||||
{
|
||||
DeleteMetaFile(((METAFILEPICT *)GlobalLock(data))->hMF);
|
||||
GlobalFree(data);
|
||||
}
|
||||
else if (format_id == CF_ENHMETAFILE)
|
||||
{
|
||||
DeleteEnhMetaFile(data);
|
||||
}
|
||||
else if (format_id < CF_PRIVATEFIRST || CF_PRIVATELAST < format_id)
|
||||
{
|
||||
GlobalFree(data);
|
||||
/* FIXME: According to MSDN, the caller is entitled to lock and read from
|
||||
data until CloseClipboard is called. So, we should defer this cleanup. */
|
||||
if ((format_id >= CF_GDIOBJFIRST && format_id <= CF_GDIOBJLAST) ||
|
||||
format_id == CF_BITMAP ||
|
||||
format_id == CF_DIB ||
|
||||
format_id == CF_PALETTE)
|
||||
{
|
||||
DeleteObject(data);
|
||||
}
|
||||
else if (format_id == CF_METAFILEPICT)
|
||||
{
|
||||
DeleteMetaFile(((METAFILEPICT *)GlobalLock(data))->hMF);
|
||||
GlobalFree(data);
|
||||
}
|
||||
else if (format_id == CF_ENHMETAFILE)
|
||||
{
|
||||
DeleteEnhMetaFile(data);
|
||||
}
|
||||
else if (format_id < CF_PRIVATEFIRST || CF_PRIVATELAST < format_id)
|
||||
{
|
||||
GlobalFree(data);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
@ -1220,3 +1225,74 @@ void macdrv_clipboard_process_attach(void)
|
|||
list_add_tail(&format_list, &format->entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* query_pasteboard_data
|
||||
*/
|
||||
BOOL query_pasteboard_data(HWND hwnd, CFStringRef type)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
CLIPBOARDINFO cbinfo;
|
||||
WINE_CLIPFORMAT* format;
|
||||
CFArrayRef types = NULL;
|
||||
CFRange range;
|
||||
|
||||
TRACE("hwnd %p type %s\n", hwnd, debugstr_cf(type));
|
||||
|
||||
if (get_clipboard_info(&cbinfo))
|
||||
hwnd = cbinfo.hwnd_owner;
|
||||
|
||||
format = NULL;
|
||||
while ((format = format_for_type(format, type)))
|
||||
{
|
||||
WINE_CLIPFORMAT* base_format;
|
||||
|
||||
TRACE("for type %s got format %p/%s\n", debugstr_cf(type), format, debugstr_format(format->format_id));
|
||||
|
||||
if (!format->synthesized)
|
||||
{
|
||||
TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(format->format_id), hwnd);
|
||||
SendMessageW(hwnd, WM_RENDERFORMAT, format->format_id, 0);
|
||||
ret = TRUE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!types)
|
||||
{
|
||||
types = macdrv_copy_pasteboard_types();
|
||||
if (!types)
|
||||
{
|
||||
WARN("Failed to copy pasteboard types\n");
|
||||
break;
|
||||
}
|
||||
|
||||
range = CFRangeMake(0, CFArrayGetCount(types));
|
||||
}
|
||||
|
||||
/* The type maps to a synthesized format. Now look up what type that format maps to natively
|
||||
(not synthesized). For example, if type is "public.utf8-plain-text", then this format may
|
||||
have an ID of CF_TEXT. From CF_TEXT, we want to find "org.winehq.builtin.text" to see if
|
||||
that type is present in the pasteboard. If it is, then the app must have promised it and
|
||||
we can ask it to render it. (If it had put it on the clipboard immediately, then the
|
||||
pasteboard would also have data for "public.utf8-plain-text" and we wouldn't be here.) If
|
||||
"org.winehq.builtin.text" is not on the pasteboard, then one of the other text formats is
|
||||
presumably responsible for the promise that we're trying to satisfy, so we keep looking. */
|
||||
LIST_FOR_EACH_ENTRY(base_format, &format_list, WINE_CLIPFORMAT, entry)
|
||||
{
|
||||
if (base_format->format_id == format->format_id && !base_format->synthesized &&
|
||||
CFArrayContainsValue(types, range, base_format->type))
|
||||
{
|
||||
TRACE("Sending WM_RENDERFORMAT message for format %s to hwnd %p\n", debugstr_format(base_format->format_id), hwnd);
|
||||
SendMessageW(hwnd, WM_RENDERFORMAT, base_format->format_id, 0);
|
||||
ret = TRUE;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (types) CFRelease(types);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -125,20 +125,22 @@ void macdrv_clear_pasteboard(void)
|
|||
* macdrv_set_pasteboard_data
|
||||
*
|
||||
* Sets the pasteboard data for a specified type. Replaces any data of
|
||||
* that type already on the pasteboard.
|
||||
* that type already on the pasteboard. If data is NULL, promises the
|
||||
* type.
|
||||
*
|
||||
* Returns 0 on error, non-zero on success.
|
||||
*/
|
||||
int macdrv_set_pasteboard_data(CFStringRef type, CFDataRef data)
|
||||
int macdrv_set_pasteboard_data(CFStringRef type, CFDataRef data, macdrv_window w)
|
||||
{
|
||||
__block int ret = 0;
|
||||
WineWindow* window = (WineWindow*)w;
|
||||
|
||||
OnMainThread(^{
|
||||
@try
|
||||
{
|
||||
NSPasteboard* pb = [NSPasteboard generalPasteboard];
|
||||
NSInteger change_count = [pb addTypes:[NSArray arrayWithObject:(NSString*)type]
|
||||
owner:nil];
|
||||
owner:window];
|
||||
if (change_count)
|
||||
{
|
||||
owned_change_count = change_count;
|
||||
|
|
|
@ -455,6 +455,8 @@ void macdrv_release_query(macdrv_query *query)
|
|||
{
|
||||
if (OSAtomicDecrement32Barrier(&query->refs) <= 0)
|
||||
{
|
||||
if (query->type == QUERY_PASTEBOARD_DATA && query->pasteboard_data.type)
|
||||
CFRelease(query->pasteboard_data.type);
|
||||
[(WineWindow*)query->window release];
|
||||
free(query);
|
||||
}
|
||||
|
|
|
@ -1174,6 +1174,21 @@ - (void)windowWillMiniaturize:(NSNotification *)notification
|
|||
ignore_windowMiniaturize = FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ---------- NSPasteboardOwner methods ----------
|
||||
*/
|
||||
- (void) pasteboard:(NSPasteboard *)sender provideDataForType:(NSString *)type
|
||||
{
|
||||
macdrv_query* query = macdrv_create_query();
|
||||
query->type = QUERY_PASTEBOARD_DATA;
|
||||
query->window = (macdrv_window)[self retain];
|
||||
query->pasteboard_data.type = (CFStringRef)[type copy];
|
||||
|
||||
[self.queue query:query timeout:3];
|
||||
macdrv_release_query(query);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
|
|
@ -116,6 +116,10 @@ static void macdrv_query_event(HWND hwnd, macdrv_event *event)
|
|||
|
||||
switch (query->type)
|
||||
{
|
||||
case QUERY_PASTEBOARD_DATA:
|
||||
TRACE("QUERY_PASTEBOARD_DATA\n");
|
||||
success = query_pasteboard_data(hwnd, query->pasteboard_data.type);
|
||||
break;
|
||||
default:
|
||||
FIXME("unrecognized query type %d\n", query->type);
|
||||
break;
|
||||
|
|
|
@ -159,6 +159,7 @@ static inline RECT rect_from_cgrect(CGRect cgrect)
|
|||
extern void macdrv_displays_changed(const macdrv_event *event) DECLSPEC_HIDDEN;
|
||||
|
||||
extern void macdrv_clipboard_process_attach(void) DECLSPEC_HIDDEN;
|
||||
extern BOOL query_pasteboard_data(HWND hwnd, CFStringRef type) DECLSPEC_HIDDEN;
|
||||
|
||||
extern struct opengl_funcs *macdrv_wine_get_wgl_driver(PHYSDEV dev, UINT version) DECLSPEC_HIDDEN;
|
||||
extern void sync_gl_view(struct macdrv_win_data *data) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -208,6 +208,7 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display,
|
|||
} macdrv_event;
|
||||
|
||||
enum {
|
||||
QUERY_PASTEBOARD_DATA,
|
||||
NUM_QUERY_TYPES
|
||||
};
|
||||
|
||||
|
@ -217,6 +218,11 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display,
|
|||
macdrv_window window;
|
||||
int status;
|
||||
int done;
|
||||
union {
|
||||
struct {
|
||||
CFStringRef type;
|
||||
} pasteboard_data;
|
||||
};
|
||||
} macdrv_query;
|
||||
|
||||
static inline macdrv_event_mask event_mask_for_type(int type)
|
||||
|
@ -302,7 +308,7 @@ extern void macdrv_set_window_color_key(macdrv_window w, CGFloat keyRed, CGFloat
|
|||
extern CFDataRef macdrv_copy_pasteboard_data(CFStringRef type) DECLSPEC_HIDDEN;
|
||||
extern int macdrv_is_pasteboard_owner(void) DECLSPEC_HIDDEN;
|
||||
extern void macdrv_clear_pasteboard(void) DECLSPEC_HIDDEN;
|
||||
extern int macdrv_set_pasteboard_data(CFStringRef type, CFDataRef data) DECLSPEC_HIDDEN;
|
||||
extern int macdrv_set_pasteboard_data(CFStringRef type, CFDataRef data, macdrv_window w) DECLSPEC_HIDDEN;
|
||||
|
||||
|
||||
/* opengl */
|
||||
|
|
Loading…
Reference in New Issue