winemac: Implement setting of clipboard data with support for text formats.
This commit is contained in:
parent
764a8edb09
commit
bf824ed38c
|
@ -27,6 +27,7 @@
|
||||||
#include "macdrv.h"
|
#include "macdrv.h"
|
||||||
#include "winuser.h"
|
#include "winuser.h"
|
||||||
#include "wine/list.h"
|
#include "wine/list.h"
|
||||||
|
#include "wine/server.h"
|
||||||
#include "wine/unicode.h"
|
#include "wine/unicode.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,7 +38,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
|
||||||
* Types
|
* Types
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
HWND hwnd_owner;
|
||||||
|
UINT flags;
|
||||||
|
} CLIPBOARDINFO, *LPCLIPBOARDINFO;
|
||||||
|
|
||||||
typedef HANDLE (*DRVIMPORTFUNC)(CFDataRef data);
|
typedef HANDLE (*DRVIMPORTFUNC)(CFDataRef data);
|
||||||
|
typedef CFDataRef (*DRVEXPORTFUNC)(HANDLE data);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -45,6 +53,7 @@ typedef struct
|
||||||
UINT format_id;
|
UINT format_id;
|
||||||
CFStringRef type;
|
CFStringRef type;
|
||||||
DRVIMPORTFUNC import_func;
|
DRVIMPORTFUNC import_func;
|
||||||
|
DRVEXPORTFUNC export_func;
|
||||||
BOOL synthesized;
|
BOOL synthesized;
|
||||||
} WINE_CLIPFORMAT;
|
} WINE_CLIPFORMAT;
|
||||||
|
|
||||||
|
@ -69,6 +78,11 @@ static HANDLE import_utf8_to_oemtext(CFDataRef data);
|
||||||
static HANDLE import_utf8_to_text(CFDataRef data);
|
static HANDLE import_utf8_to_text(CFDataRef data);
|
||||||
static HANDLE import_utf8_to_unicodetext(CFDataRef data);
|
static HANDLE import_utf8_to_unicodetext(CFDataRef data);
|
||||||
|
|
||||||
|
static CFDataRef export_clipboard_data(HANDLE data);
|
||||||
|
static CFDataRef export_oemtext_to_utf8(HANDLE data);
|
||||||
|
static CFDataRef export_text_to_utf8(HANDLE data);
|
||||||
|
static CFDataRef export_unicodetext_to_utf8(HANDLE data);
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* Static Variables
|
* Static Variables
|
||||||
|
@ -123,24 +137,25 @@ static const struct
|
||||||
UINT id;
|
UINT id;
|
||||||
CFStringRef type;
|
CFStringRef type;
|
||||||
DRVIMPORTFUNC import;
|
DRVIMPORTFUNC import;
|
||||||
|
DRVEXPORTFUNC export;
|
||||||
BOOL synthesized;
|
BOOL synthesized;
|
||||||
} builtin_format_ids[] =
|
} builtin_format_ids[] =
|
||||||
{
|
{
|
||||||
{ CF_UNICODETEXT, CFSTR("org.winehq.builtin.unicodetext"), import_clipboard_data, FALSE },
|
{ CF_UNICODETEXT, CFSTR("org.winehq.builtin.unicodetext"), import_clipboard_data, export_clipboard_data, FALSE },
|
||||||
{ CF_TEXT, CFSTR("org.winehq.builtin.unicodetext"), import_unicodetext_to_text, TRUE },
|
{ CF_TEXT, CFSTR("org.winehq.builtin.unicodetext"), import_unicodetext_to_text, NULL, TRUE },
|
||||||
{ CF_OEMTEXT, CFSTR("org.winehq.builtin.unicodetext"), import_unicodetext_to_oemtext, TRUE },
|
{ CF_OEMTEXT, CFSTR("org.winehq.builtin.unicodetext"), import_unicodetext_to_oemtext, NULL, TRUE },
|
||||||
|
|
||||||
{ CF_TEXT, CFSTR("org.winehq.builtin.text"), import_clipboard_data, FALSE },
|
{ CF_TEXT, CFSTR("org.winehq.builtin.text"), import_clipboard_data, export_clipboard_data, FALSE },
|
||||||
{ CF_UNICODETEXT, CFSTR("org.winehq.builtin.text"), import_text_to_unicodetext, TRUE },
|
{ CF_UNICODETEXT, CFSTR("org.winehq.builtin.text"), import_text_to_unicodetext, NULL, TRUE },
|
||||||
{ CF_OEMTEXT, CFSTR("org.winehq.builtin.text"), import_text_to_oemtext, TRUE },
|
{ CF_OEMTEXT, CFSTR("org.winehq.builtin.text"), import_text_to_oemtext, NULL, TRUE },
|
||||||
|
|
||||||
{ CF_OEMTEXT, CFSTR("org.winehq.builtin.oemtext"), import_clipboard_data, FALSE },
|
{ CF_OEMTEXT, CFSTR("org.winehq.builtin.oemtext"), import_clipboard_data, export_clipboard_data, FALSE },
|
||||||
{ CF_UNICODETEXT, CFSTR("org.winehq.builtin.oemtext"), import_oemtext_to_unicodetext, TRUE },
|
{ CF_UNICODETEXT, CFSTR("org.winehq.builtin.oemtext"), import_oemtext_to_unicodetext, NULL, TRUE },
|
||||||
{ CF_TEXT, CFSTR("org.winehq.builtin.oemtext"), import_oemtext_to_text, TRUE },
|
{ CF_TEXT, CFSTR("org.winehq.builtin.oemtext"), import_oemtext_to_text, NULL, TRUE },
|
||||||
|
|
||||||
{ CF_UNICODETEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_unicodetext, TRUE },
|
{ CF_UNICODETEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_unicodetext, export_unicodetext_to_utf8, TRUE },
|
||||||
{ CF_TEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_text, TRUE },
|
{ CF_TEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_text, export_text_to_utf8, TRUE },
|
||||||
{ CF_OEMTEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_oemtext, TRUE },
|
{ CF_OEMTEXT, CFSTR("public.utf8-plain-text"), import_utf8_to_oemtext, export_oemtext_to_utf8, TRUE },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The prefix prepended to an external Mac pasteboard type to make a Win32 clipboard format name. org.winehq.mac-type. */
|
/* The prefix prepended to an external Mac pasteboard type to make a Win32 clipboard format name. org.winehq.mac-type. */
|
||||||
|
@ -215,6 +230,7 @@ static WINE_CLIPFORMAT *insert_clipboard_format(UINT id, CFStringRef type)
|
||||||
}
|
}
|
||||||
format->format_id = id;
|
format->format_id = id;
|
||||||
format->import_func = import_clipboard_data;
|
format->import_func = import_clipboard_data;
|
||||||
|
format->export_func = export_clipboard_data;
|
||||||
format->synthesized = FALSE;
|
format->synthesized = FALSE;
|
||||||
|
|
||||||
if (type)
|
if (type)
|
||||||
|
@ -586,11 +602,216 @@ static HANDLE import_utf8_to_unicodetext(CFDataRef data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* export_clipboard_data
|
||||||
|
*
|
||||||
|
* Generic export clipboard data routine.
|
||||||
|
*/
|
||||||
|
static CFDataRef export_clipboard_data(HANDLE data)
|
||||||
|
{
|
||||||
|
CFDataRef ret;
|
||||||
|
UINT len;
|
||||||
|
LPVOID src;
|
||||||
|
|
||||||
|
len = GlobalSize(data);
|
||||||
|
src = GlobalLock(data);
|
||||||
|
if (!src) return NULL;
|
||||||
|
|
||||||
|
ret = CFDataCreate(NULL, src, len);
|
||||||
|
GlobalUnlock(data);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* export_codepage_to_utf8
|
||||||
|
*
|
||||||
|
* Export string data in a specified codepage to UTF-8.
|
||||||
|
*/
|
||||||
|
static CFDataRef export_codepage_to_utf8(HANDLE data, UINT cp)
|
||||||
|
{
|
||||||
|
CFDataRef ret = NULL;
|
||||||
|
const char* str;
|
||||||
|
|
||||||
|
if ((str = GlobalLock(data)))
|
||||||
|
{
|
||||||
|
HANDLE unicode = convert_text(str, GlobalSize(data), cp, -1);
|
||||||
|
|
||||||
|
ret = export_unicodetext_to_utf8(unicode);
|
||||||
|
|
||||||
|
GlobalFree(unicode);
|
||||||
|
GlobalUnlock(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* export_oemtext_to_utf8
|
||||||
|
*
|
||||||
|
* Export CF_OEMTEXT to UTF-8.
|
||||||
|
*/
|
||||||
|
static CFDataRef export_oemtext_to_utf8(HANDLE data)
|
||||||
|
{
|
||||||
|
return export_codepage_to_utf8(data, CP_OEMCP);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* export_text_to_utf8
|
||||||
|
*
|
||||||
|
* Export CF_TEXT to UTF-8.
|
||||||
|
*/
|
||||||
|
static CFDataRef export_text_to_utf8(HANDLE data)
|
||||||
|
{
|
||||||
|
return export_codepage_to_utf8(data, CP_ACP);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* export_unicodetext_to_utf8
|
||||||
|
*
|
||||||
|
* Export CF_UNICODETEXT to UTF-8.
|
||||||
|
*/
|
||||||
|
static CFDataRef export_unicodetext_to_utf8(HANDLE data)
|
||||||
|
{
|
||||||
|
CFMutableDataRef ret;
|
||||||
|
LPVOID src;
|
||||||
|
INT dst_len;
|
||||||
|
|
||||||
|
src = GlobalLock(data);
|
||||||
|
if (!src) return NULL;
|
||||||
|
|
||||||
|
dst_len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
|
||||||
|
if (dst_len) dst_len--; /* Leave off null terminator. */
|
||||||
|
ret = CFDataCreateMutable(NULL, dst_len);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
LPSTR dst;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
CFDataSetLength(ret, dst_len);
|
||||||
|
dst = (LPSTR)CFDataGetMutableBytePtr(ret);
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_len, NULL, NULL);
|
||||||
|
|
||||||
|
/* Remove carriage returns */
|
||||||
|
for (i = 0, j = 0; i < dst_len; i++)
|
||||||
|
{
|
||||||
|
if (dst[i] == '\r' &&
|
||||||
|
(i + 1 >= dst_len || dst[i + 1] == '\n' || dst[i + 1] == '\0'))
|
||||||
|
continue;
|
||||||
|
dst[j++] = dst[i];
|
||||||
|
}
|
||||||
|
CFDataSetLength(ret, j);
|
||||||
|
}
|
||||||
|
GlobalUnlock(data);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* get_clipboard_info
|
||||||
|
*/
|
||||||
|
static BOOL get_clipboard_info(LPCLIPBOARDINFO cbinfo)
|
||||||
|
{
|
||||||
|
BOOL ret = FALSE;
|
||||||
|
|
||||||
|
SERVER_START_REQ(set_clipboard_info)
|
||||||
|
{
|
||||||
|
req->flags = 0;
|
||||||
|
|
||||||
|
if (wine_server_call_err(req))
|
||||||
|
{
|
||||||
|
ERR("Failed to get clipboard owner.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cbinfo->hwnd_owner = wine_server_ptr_handle(reply->old_owner);
|
||||||
|
cbinfo->flags = reply->flags;
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SERVER_END_REQ;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* release_ownership
|
||||||
|
*/
|
||||||
|
static BOOL release_ownership(void)
|
||||||
|
{
|
||||||
|
BOOL ret = FALSE;
|
||||||
|
|
||||||
|
SERVER_START_REQ(set_clipboard_info)
|
||||||
|
{
|
||||||
|
req->flags = SET_CB_RELOWNER | SET_CB_SEQNO;
|
||||||
|
|
||||||
|
if (wine_server_call_err(req))
|
||||||
|
ERR("Failed to set clipboard.\n");
|
||||||
|
else
|
||||||
|
ret = TRUE;
|
||||||
|
}
|
||||||
|
SERVER_END_REQ;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* check_clipboard_ownership
|
||||||
|
*/
|
||||||
|
static void check_clipboard_ownership(HWND *owner)
|
||||||
|
{
|
||||||
|
CLIPBOARDINFO cbinfo;
|
||||||
|
|
||||||
|
if (owner) *owner = NULL;
|
||||||
|
|
||||||
|
/* If Wine thinks we're the clipboard owner but Mac OS X thinks we're not
|
||||||
|
the pasteboard owner, update Wine. */
|
||||||
|
if (get_clipboard_info(&cbinfo) && (cbinfo.flags & CB_PROCESS))
|
||||||
|
{
|
||||||
|
if (!(cbinfo.flags & CB_OPEN) && !macdrv_is_pasteboard_owner())
|
||||||
|
{
|
||||||
|
TRACE("Lost clipboard ownership\n");
|
||||||
|
|
||||||
|
if (OpenClipboard(cbinfo.hwnd_owner))
|
||||||
|
{
|
||||||
|
/* Destroy private objects */
|
||||||
|
SendMessageW(cbinfo.hwnd_owner, WM_DESTROYCLIPBOARD, 0, 0);
|
||||||
|
|
||||||
|
/* Give up ownership of the windows clipboard */
|
||||||
|
release_ownership();
|
||||||
|
CloseClipboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (owner)
|
||||||
|
*owner = cbinfo.hwnd_owner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* Mac User Driver Clipboard Exports
|
* Mac User Driver Clipboard Exports
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* AcquireClipboard (MACDRV.@)
|
||||||
|
*/
|
||||||
|
int CDECL macdrv_AcquireClipboard(HWND hwnd)
|
||||||
|
{
|
||||||
|
TRACE("hwnd %p\n", hwnd);
|
||||||
|
check_clipboard_ownership(NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* CountClipboardFormats (MACDRV.@)
|
* CountClipboardFormats (MACDRV.@)
|
||||||
*/
|
*/
|
||||||
|
@ -603,6 +824,7 @@ INT CDECL macdrv_CountClipboardFormats(void)
|
||||||
INT ret = 0;
|
INT ret = 0;
|
||||||
|
|
||||||
TRACE("()\n");
|
TRACE("()\n");
|
||||||
|
check_clipboard_ownership(NULL);
|
||||||
|
|
||||||
seen_formats = CFSetCreateMutable(NULL, 0, NULL);
|
seen_formats = CFSetCreateMutable(NULL, 0, NULL);
|
||||||
if (!seen_formats)
|
if (!seen_formats)
|
||||||
|
@ -646,6 +868,28 @@ INT CDECL macdrv_CountClipboardFormats(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* EmptyClipboard (MACDRV.@)
|
||||||
|
*
|
||||||
|
* Empty cached clipboard data.
|
||||||
|
*/
|
||||||
|
void CDECL macdrv_EmptyClipboard(BOOL keepunowned)
|
||||||
|
{
|
||||||
|
TRACE("keepunowned %d\n", keepunowned);
|
||||||
|
macdrv_clear_pasteboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* EndClipboardUpdate (MACDRV.@)
|
||||||
|
*/
|
||||||
|
void CDECL macdrv_EndClipboardUpdate(void)
|
||||||
|
{
|
||||||
|
TRACE("()\n");
|
||||||
|
check_clipboard_ownership(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* EnumClipboardFormats (MACDRV.@)
|
* EnumClipboardFormats (MACDRV.@)
|
||||||
*/
|
*/
|
||||||
|
@ -657,6 +901,7 @@ UINT CDECL macdrv_EnumClipboardFormats(UINT prev_format)
|
||||||
UINT ret;
|
UINT ret;
|
||||||
|
|
||||||
TRACE("prev_format %s\n", debugstr_format(prev_format));
|
TRACE("prev_format %s\n", debugstr_format(prev_format));
|
||||||
|
check_clipboard_ownership(NULL);
|
||||||
|
|
||||||
types = macdrv_copy_pasteboard_types();
|
types = macdrv_copy_pasteboard_types();
|
||||||
if (!types)
|
if (!types)
|
||||||
|
@ -750,6 +995,7 @@ HANDLE CDECL macdrv_GetClipboardData(UINT desired_format)
|
||||||
HANDLE data = NULL;
|
HANDLE data = NULL;
|
||||||
|
|
||||||
TRACE("desired_format %s\n", debugstr_format(desired_format));
|
TRACE("desired_format %s\n", debugstr_format(desired_format));
|
||||||
|
check_clipboard_ownership(NULL);
|
||||||
|
|
||||||
types = macdrv_copy_pasteboard_types();
|
types = macdrv_copy_pasteboard_types();
|
||||||
if (!types)
|
if (!types)
|
||||||
|
@ -815,6 +1061,7 @@ BOOL CDECL macdrv_IsClipboardFormatAvailable(UINT desired_format)
|
||||||
BOOL found = FALSE;
|
BOOL found = FALSE;
|
||||||
|
|
||||||
TRACE("desired_format %s\n", debugstr_format(desired_format));
|
TRACE("desired_format %s\n", debugstr_format(desired_format));
|
||||||
|
check_clipboard_ownership(NULL);
|
||||||
|
|
||||||
types = macdrv_copy_pasteboard_types();
|
types = macdrv_copy_pasteboard_types();
|
||||||
if (!types)
|
if (!types)
|
||||||
|
@ -847,6 +1094,106 @@ BOOL CDECL macdrv_IsClipboardFormatAvailable(UINT desired_format)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* SetClipboardData (MACDRV.@)
|
||||||
|
*/
|
||||||
|
BOOL CDECL macdrv_SetClipboardData(UINT format_id, HANDLE data, BOOL owner)
|
||||||
|
{
|
||||||
|
HWND hwnd_owner;
|
||||||
|
macdrv_window window;
|
||||||
|
WINE_CLIPFORMAT *format;
|
||||||
|
CFDataRef cfdata;
|
||||||
|
|
||||||
|
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)
|
||||||
|
if (format->format_id == format_id && !format->synthesized) break;
|
||||||
|
|
||||||
|
if (&format->entry == &format_list && !(format = insert_clipboard_format(format_id, NULL)))
|
||||||
|
{
|
||||||
|
WARN("Failed to register clipboard format %s\n", debugstr_format(format_id));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Export the data to the Mac pasteboard. */
|
||||||
|
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))
|
||||||
|
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);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(cfdata);
|
||||||
|
|
||||||
|
/* Find any other formats for this format_id (the exportable synthesized ones). */
|
||||||
|
LIST_FOR_EACH_ENTRY(format, &format_list, WINE_CLIPFORMAT, entry)
|
||||||
|
{
|
||||||
|
if (format->format_id == format_id && format->synthesized && format->export_func)
|
||||||
|
{
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
WARN("Failed to export %s data to type %s\n", debugstr_format(format->format_id), debugstr_cf(format->type));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (macdrv_set_pasteboard_data(format->type, cfdata))
|
||||||
|
TRACE(" ... set pasteboard data: %s\n", debugstr_cf(cfdata));
|
||||||
|
else
|
||||||
|
WARN(" ... failed to set pasteboard data: %s\n", debugstr_cf(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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* MACDRV Private Clipboard Exports
|
* MACDRV Private Clipboard Exports
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
@ -868,6 +1215,7 @@ void macdrv_clipboard_process_attach(void)
|
||||||
format->format_id = builtin_format_ids[i].id;
|
format->format_id = builtin_format_ids[i].id;
|
||||||
format->type = CFRetain(builtin_format_ids[i].type);
|
format->type = CFRetain(builtin_format_ids[i].type);
|
||||||
format->import_func = builtin_format_ids[i].import;
|
format->import_func = builtin_format_ids[i].import;
|
||||||
|
format->export_func = builtin_format_ids[i].export;
|
||||||
format->synthesized = builtin_format_ids[i].synthesized;
|
format->synthesized = builtin_format_ids[i].synthesized;
|
||||||
list_add_tail(&format_list, &format->entry);
|
list_add_tail(&format_list, &format->entry);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,25 @@
|
||||||
#import "cocoa_app.h"
|
#import "cocoa_app.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int owned_change_count = -1;
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* macdrv_is_pasteboard_owner
|
||||||
|
*/
|
||||||
|
int macdrv_is_pasteboard_owner(void)
|
||||||
|
{
|
||||||
|
__block int ret;
|
||||||
|
|
||||||
|
OnMainThread(^{
|
||||||
|
NSPasteboard* pb = [NSPasteboard generalPasteboard];
|
||||||
|
ret = ([pb changeCount] == owned_change_count);
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* macdrv_copy_pasteboard_types
|
* macdrv_copy_pasteboard_types
|
||||||
*
|
*
|
||||||
|
@ -78,3 +97,61 @@ CFDataRef macdrv_copy_pasteboard_data(CFStringRef type)
|
||||||
|
|
||||||
return (CFDataRef)ret;
|
return (CFDataRef)ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* macdrv_clear_pasteboard
|
||||||
|
*
|
||||||
|
* Takes ownership of the Mac pasteboard and clears it of all data types.
|
||||||
|
*/
|
||||||
|
void macdrv_clear_pasteboard(void)
|
||||||
|
{
|
||||||
|
OnMainThreadAsync(^{
|
||||||
|
@try
|
||||||
|
{
|
||||||
|
NSPasteboard* pb = [NSPasteboard generalPasteboard];
|
||||||
|
owned_change_count = [pb declareTypes:[NSArray array] owner:nil];
|
||||||
|
}
|
||||||
|
@catch (id e)
|
||||||
|
{
|
||||||
|
ERR(@"Exception discarded while clearing pasteboard: %@\n", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* macdrv_set_pasteboard_data
|
||||||
|
*
|
||||||
|
* Sets the pasteboard data for a specified type. Replaces any data of
|
||||||
|
* that type already on the pasteboard.
|
||||||
|
*
|
||||||
|
* Returns 0 on error, non-zero on success.
|
||||||
|
*/
|
||||||
|
int macdrv_set_pasteboard_data(CFStringRef type, CFDataRef data)
|
||||||
|
{
|
||||||
|
__block int ret = 0;
|
||||||
|
|
||||||
|
OnMainThread(^{
|
||||||
|
@try
|
||||||
|
{
|
||||||
|
NSPasteboard* pb = [NSPasteboard generalPasteboard];
|
||||||
|
NSInteger change_count = [pb addTypes:[NSArray arrayWithObject:(NSString*)type]
|
||||||
|
owner:nil];
|
||||||
|
if (change_count)
|
||||||
|
{
|
||||||
|
owned_change_count = change_count;
|
||||||
|
if (data)
|
||||||
|
ret = [pb setData:(NSData*)data forType:(NSString*)type];
|
||||||
|
else
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@catch (id e)
|
||||||
|
{
|
||||||
|
ERR(@"Exception discarded while copying pasteboard types: %@\n", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -276,6 +276,9 @@ extern void macdrv_set_window_color_key(macdrv_window w, CGFloat keyRed, CGFloat
|
||||||
/* clipboard */
|
/* clipboard */
|
||||||
extern CFArrayRef macdrv_copy_pasteboard_types(void) DECLSPEC_HIDDEN;
|
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 void macdrv_clear_pasteboard(void) DECLSPEC_HIDDEN;
|
||||||
|
extern int macdrv_set_pasteboard_data(CFStringRef type, CFDataRef data) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
|
|
||||||
/* opengl */
|
/* opengl */
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
# USER driver
|
# USER driver
|
||||||
|
|
||||||
|
@ cdecl AcquireClipboard(long) macdrv_AcquireClipboard
|
||||||
@ cdecl ActivateKeyboardLayout(long long) macdrv_ActivateKeyboardLayout
|
@ cdecl ActivateKeyboardLayout(long long) macdrv_ActivateKeyboardLayout
|
||||||
@ cdecl Beep() macdrv_Beep
|
@ cdecl Beep() macdrv_Beep
|
||||||
@ cdecl ChangeDisplaySettingsEx(ptr ptr long long long) macdrv_ChangeDisplaySettingsEx
|
@ cdecl ChangeDisplaySettingsEx(ptr ptr long long long) macdrv_ChangeDisplaySettingsEx
|
||||||
|
@ -13,6 +14,8 @@
|
||||||
@ cdecl CreateWindow(long) macdrv_CreateWindow
|
@ cdecl CreateWindow(long) macdrv_CreateWindow
|
||||||
@ cdecl DestroyCursorIcon(long) macdrv_DestroyCursorIcon
|
@ cdecl DestroyCursorIcon(long) macdrv_DestroyCursorIcon
|
||||||
@ cdecl DestroyWindow(long) macdrv_DestroyWindow
|
@ cdecl DestroyWindow(long) macdrv_DestroyWindow
|
||||||
|
@ cdecl EmptyClipboard(long) macdrv_EmptyClipboard
|
||||||
|
@ cdecl EndClipboardUpdate() macdrv_EndClipboardUpdate
|
||||||
@ cdecl EnumClipboardFormats(long) macdrv_EnumClipboardFormats
|
@ cdecl EnumClipboardFormats(long) macdrv_EnumClipboardFormats
|
||||||
@ cdecl EnumDisplayMonitors(long ptr ptr long) macdrv_EnumDisplayMonitors
|
@ cdecl EnumDisplayMonitors(long ptr ptr long) macdrv_EnumDisplayMonitors
|
||||||
@ cdecl EnumDisplaySettingsEx(ptr long ptr long) macdrv_EnumDisplaySettingsEx
|
@ cdecl EnumDisplaySettingsEx(ptr long ptr long) macdrv_EnumDisplaySettingsEx
|
||||||
|
@ -26,6 +29,7 @@
|
||||||
@ cdecl MapVirtualKeyEx(long long long) macdrv_MapVirtualKeyEx
|
@ cdecl MapVirtualKeyEx(long long long) macdrv_MapVirtualKeyEx
|
||||||
@ cdecl MsgWaitForMultipleObjectsEx(long ptr long long long) macdrv_MsgWaitForMultipleObjectsEx
|
@ cdecl MsgWaitForMultipleObjectsEx(long ptr long long long) macdrv_MsgWaitForMultipleObjectsEx
|
||||||
@ cdecl ScrollDC(long long long ptr ptr long ptr) macdrv_ScrollDC
|
@ cdecl ScrollDC(long long long ptr ptr long ptr) macdrv_ScrollDC
|
||||||
|
@ cdecl SetClipboardData(long long long) macdrv_SetClipboardData
|
||||||
@ cdecl SetCursor(long) macdrv_SetCursor
|
@ cdecl SetCursor(long) macdrv_SetCursor
|
||||||
@ cdecl SetCursorPos(long long) macdrv_SetCursorPos
|
@ cdecl SetCursorPos(long long) macdrv_SetCursorPos
|
||||||
@ cdecl SetFocus(long) macdrv_SetFocus
|
@ cdecl SetFocus(long) macdrv_SetFocus
|
||||||
|
|
Loading…
Reference in New Issue