mirror of
https://github.com/reactos/wine.git
synced 2024-11-28 22:20:26 +00:00
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;
|
HWND hwnd_owner;
|
||||||
macdrv_window window;
|
macdrv_window window;
|
||||||
WINE_CLIPFORMAT *format;
|
WINE_CLIPFORMAT *format;
|
||||||
CFDataRef cfdata;
|
CFDataRef cfdata = NULL;
|
||||||
|
|
||||||
check_clipboard_ownership(&hwnd_owner);
|
check_clipboard_ownership(&hwnd_owner);
|
||||||
window = macdrv_get_cocoa_window(GetAncestor(hwnd_owner, GA_ROOT), FALSE);
|
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);
|
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
|
/* Find the "natural" format for this format_id (the one which isn't
|
||||||
synthesized from another type). */
|
synthesized from another type). */
|
||||||
LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
|
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. */
|
/* 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));
|
if (!format->export_func || !(cfdata = format->export_func(data)))
|
||||||
return FALSE;
|
{
|
||||||
|
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));
|
TRACE("Set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WARN("Failed to set pasteboard data for type %s: %s\n", debugstr_cf(format->type), debugstr_cf(cfdata));
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
CFRelease(cfdata);
|
if (cfdata) CFRelease(cfdata);
|
||||||
|
|
||||||
/* Find any other formats for this format_id (the exportable synthesized ones). */
|
/* Find any other formats for this format_id (the exportable synthesized ones). */
|
||||||
LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
|
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. */
|
/* 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));
|
TRACE("Synthesized from format %s: type %s\n", debugstr_format(format_id), debugstr_cf(format->type));
|
||||||
|
|
||||||
cfdata = format->export_func(data);
|
if (data)
|
||||||
if (!cfdata)
|
|
||||||
{
|
{
|
||||||
WARN("Failed to export %s data to type %s\n", debugstr_format(format->format_id), debugstr_cf(format->type));
|
cfdata = format->export_func(data);
|
||||||
continue;
|
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));
|
TRACE(" ... set pasteboard data: %s\n", debugstr_cf(cfdata));
|
||||||
else
|
else
|
||||||
WARN(" ... failed to set pasteboard data: %s\n", debugstr_cf(cfdata));
|
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
|
if (data)
|
||||||
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);
|
/* FIXME: According to MSDN, the caller is entitled to lock and read from
|
||||||
}
|
data until CloseClipboard is called. So, we should defer this cleanup. */
|
||||||
else if (format_id == CF_METAFILEPICT)
|
if ((format_id >= CF_GDIOBJFIRST && format_id <= CF_GDIOBJLAST) ||
|
||||||
{
|
format_id == CF_BITMAP ||
|
||||||
DeleteMetaFile(((METAFILEPICT *)GlobalLock(data))->hMF);
|
format_id == CF_DIB ||
|
||||||
GlobalFree(data);
|
format_id == CF_PALETTE)
|
||||||
}
|
{
|
||||||
else if (format_id == CF_ENHMETAFILE)
|
DeleteObject(data);
|
||||||
{
|
}
|
||||||
DeleteEnhMetaFile(data);
|
else if (format_id == CF_METAFILEPICT)
|
||||||
}
|
{
|
||||||
else if (format_id < CF_PRIVATEFIRST || CF_PRIVATELAST < format_id)
|
DeleteMetaFile(((METAFILEPICT *)GlobalLock(data))->hMF);
|
||||||
{
|
GlobalFree(data);
|
||||||
GlobalFree(data);
|
}
|
||||||
|
else if (format_id == CF_ENHMETAFILE)
|
||||||
|
{
|
||||||
|
DeleteEnhMetaFile(data);
|
||||||
|
}
|
||||||
|
else if (format_id < CF_PRIVATEFIRST || CF_PRIVATELAST < format_id)
|
||||||
|
{
|
||||||
|
GlobalFree(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -1220,3 +1225,74 @@ void macdrv_clipboard_process_attach(void)
|
|||||||
list_add_tail(&format_list, &format->entry);
|
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
|
* macdrv_set_pasteboard_data
|
||||||
*
|
*
|
||||||
* Sets the pasteboard data for a specified type. Replaces any data of
|
* 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.
|
* 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;
|
__block int ret = 0;
|
||||||
|
WineWindow* window = (WineWindow*)w;
|
||||||
|
|
||||||
OnMainThread(^{
|
OnMainThread(^{
|
||||||
@try
|
@try
|
||||||
{
|
{
|
||||||
NSPasteboard* pb = [NSPasteboard generalPasteboard];
|
NSPasteboard* pb = [NSPasteboard generalPasteboard];
|
||||||
NSInteger change_count = [pb addTypes:[NSArray arrayWithObject:(NSString*)type]
|
NSInteger change_count = [pb addTypes:[NSArray arrayWithObject:(NSString*)type]
|
||||||
owner:nil];
|
owner:window];
|
||||||
if (change_count)
|
if (change_count)
|
||||||
{
|
{
|
||||||
owned_change_count = change_count;
|
owned_change_count = change_count;
|
||||||
|
@ -455,6 +455,8 @@ void macdrv_release_query(macdrv_query *query)
|
|||||||
{
|
{
|
||||||
if (OSAtomicDecrement32Barrier(&query->refs) <= 0)
|
if (OSAtomicDecrement32Barrier(&query->refs) <= 0)
|
||||||
{
|
{
|
||||||
|
if (query->type == QUERY_PASTEBOARD_DATA && query->pasteboard_data.type)
|
||||||
|
CFRelease(query->pasteboard_data.type);
|
||||||
[(WineWindow*)query->window release];
|
[(WineWindow*)query->window release];
|
||||||
free(query);
|
free(query);
|
||||||
}
|
}
|
||||||
|
@ -1174,6 +1174,21 @@ static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers)
|
|||||||
ignore_windowMiniaturize = FALSE;
|
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
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@ -116,6 +116,10 @@ static void macdrv_query_event(HWND hwnd, macdrv_event *event)
|
|||||||
|
|
||||||
switch (query->type)
|
switch (query->type)
|
||||||
{
|
{
|
||||||
|
case QUERY_PASTEBOARD_DATA:
|
||||||
|
TRACE("QUERY_PASTEBOARD_DATA\n");
|
||||||
|
success = query_pasteboard_data(hwnd, query->pasteboard_data.type);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
FIXME("unrecognized query type %d\n", query->type);
|
FIXME("unrecognized query type %d\n", query->type);
|
||||||
break;
|
break;
|
||||||
|
@ -159,6 +159,7 @@ extern void macdrv_key_event(HWND hwnd, const macdrv_event *event) DECLSPEC_HIDD
|
|||||||
extern void macdrv_displays_changed(const macdrv_event *event) DECLSPEC_HIDDEN;
|
extern void macdrv_displays_changed(const macdrv_event *event) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
extern void macdrv_clipboard_process_attach(void) 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 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;
|
extern void sync_gl_view(struct macdrv_win_data *data) DECLSPEC_HIDDEN;
|
||||||
|
@ -208,6 +208,7 @@ typedef struct macdrv_event {
|
|||||||
} macdrv_event;
|
} macdrv_event;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
QUERY_PASTEBOARD_DATA,
|
||||||
NUM_QUERY_TYPES
|
NUM_QUERY_TYPES
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -217,6 +218,11 @@ typedef struct macdrv_query {
|
|||||||
macdrv_window window;
|
macdrv_window window;
|
||||||
int status;
|
int status;
|
||||||
int done;
|
int done;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
CFStringRef type;
|
||||||
|
} pasteboard_data;
|
||||||
|
};
|
||||||
} macdrv_query;
|
} macdrv_query;
|
||||||
|
|
||||||
static inline macdrv_event_mask event_mask_for_type(int type)
|
static inline macdrv_event_mask event_mask_for_type(int type)
|
||||||
@ -302,7 +308,7 @@ extern CFArrayRef macdrv_copy_pasteboard_types(void) DECLSPEC_HIDDEN;
|
|||||||
extern CFDataRef macdrv_copy_pasteboard_data(CFStringRef type) DECLSPEC_HIDDEN;
|
extern CFDataRef macdrv_copy_pasteboard_data(CFStringRef type) DECLSPEC_HIDDEN;
|
||||||
extern int macdrv_is_pasteboard_owner(void) DECLSPEC_HIDDEN;
|
extern int macdrv_is_pasteboard_owner(void) DECLSPEC_HIDDEN;
|
||||||
extern void macdrv_clear_pasteboard(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 */
|
/* opengl */
|
||||||
|
Loading…
Reference in New Issue
Block a user