user32: Add synthesized clipboard formats on the server side.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
3044935b0e
commit
9ed8f5e83f
|
@ -52,10 +52,6 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
|
||||
|
||||
/*
|
||||
* Indicates if data has changed since open.
|
||||
*/
|
||||
static BOOL bCBHasChanged = FALSE;
|
||||
|
||||
/* get a debug string for a format id */
|
||||
static const char *debugstr_format( UINT id )
|
||||
|
@ -205,30 +201,6 @@ static HANDLE unmarshal_data( UINT format, void *data, data_size_t size )
|
|||
}
|
||||
|
||||
|
||||
/* formats that can be synthesized are: CF_TEXT, CF_OEMTEXT, CF_UNICODETEXT,
|
||||
CF_BITMAP, CF_DIB, CF_DIBV5, CF_ENHMETAFILE, CF_METAFILEPICT */
|
||||
|
||||
static UINT synthesized_formats[CF_MAX];
|
||||
|
||||
/* add a synthesized format to the list */
|
||||
static void add_synthesized_format( UINT format, UINT from )
|
||||
{
|
||||
assert( format < CF_MAX );
|
||||
SetClipboardData( format, 0 );
|
||||
synthesized_formats[format] = from;
|
||||
}
|
||||
|
||||
/* store the current locale in the CF_LOCALE format */
|
||||
static void set_clipboard_locale(void)
|
||||
{
|
||||
HANDLE data = GlobalAlloc( GMEM_FIXED, sizeof(LCID) );
|
||||
|
||||
if (!data) return;
|
||||
*(LCID *)data = GetUserDefaultLCID();
|
||||
SetClipboardData( CF_LOCALE, data );
|
||||
TRACE( "added CF_LOCALE\n" );
|
||||
}
|
||||
|
||||
/* get the clipboard locale stored in the CF_LOCALE format */
|
||||
static LCID get_clipboard_locale(void)
|
||||
{
|
||||
|
@ -258,71 +230,6 @@ static UINT get_format_codepage( LCID lcid, UINT format )
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* add synthesized text formats based on what is already in the clipboard */
|
||||
static void add_synthesized_text(void)
|
||||
{
|
||||
BOOL has_text = IsClipboardFormatAvailable( CF_TEXT );
|
||||
BOOL has_oemtext = IsClipboardFormatAvailable( CF_OEMTEXT );
|
||||
BOOL has_unicode = IsClipboardFormatAvailable( CF_UNICODETEXT );
|
||||
|
||||
if (!has_text && !has_oemtext && !has_unicode) return; /* no text, nothing to do */
|
||||
|
||||
if (!IsClipboardFormatAvailable( CF_LOCALE )) set_clipboard_locale();
|
||||
|
||||
if (has_unicode)
|
||||
{
|
||||
if (!has_text) add_synthesized_format( CF_TEXT, CF_UNICODETEXT );
|
||||
if (!has_oemtext) add_synthesized_format( CF_OEMTEXT, CF_UNICODETEXT );
|
||||
}
|
||||
else if (has_text)
|
||||
{
|
||||
if (!has_oemtext) add_synthesized_format( CF_OEMTEXT, CF_TEXT );
|
||||
if (!has_unicode) add_synthesized_format( CF_UNICODETEXT, CF_TEXT );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!has_text) add_synthesized_format( CF_TEXT, CF_OEMTEXT );
|
||||
if (!has_unicode) add_synthesized_format( CF_UNICODETEXT, CF_OEMTEXT );
|
||||
}
|
||||
}
|
||||
|
||||
/* add synthesized bitmap formats based on what is already in the clipboard */
|
||||
static void add_synthesized_bitmap(void)
|
||||
{
|
||||
BOOL has_dib = IsClipboardFormatAvailable( CF_DIB );
|
||||
BOOL has_dibv5 = IsClipboardFormatAvailable( CF_DIBV5 );
|
||||
BOOL has_bitmap = IsClipboardFormatAvailable( CF_BITMAP );
|
||||
|
||||
if (!has_bitmap && !has_dib && !has_dibv5) return; /* nothing to do */
|
||||
if (has_bitmap && has_dib && has_dibv5) return; /* nothing to synthesize */
|
||||
|
||||
if (has_bitmap)
|
||||
{
|
||||
if (!has_dib) add_synthesized_format( CF_DIB, CF_BITMAP );
|
||||
if (!has_dibv5) add_synthesized_format( CF_DIBV5, CF_BITMAP );
|
||||
}
|
||||
else if (has_dib)
|
||||
{
|
||||
if (!has_bitmap) add_synthesized_format( CF_BITMAP, CF_DIB );
|
||||
if (!has_dibv5) add_synthesized_format( CF_DIBV5, CF_DIB );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!has_bitmap) add_synthesized_format( CF_BITMAP, CF_DIBV5 );
|
||||
if (!has_dib) add_synthesized_format( CF_DIB, CF_DIBV5 );
|
||||
}
|
||||
}
|
||||
|
||||
/* add synthesized metafile formats based on what is already in the clipboard */
|
||||
static void add_synthesized_metafile(void)
|
||||
{
|
||||
BOOL has_mf = IsClipboardFormatAvailable( CF_METAFILEPICT );
|
||||
BOOL has_emf = IsClipboardFormatAvailable( CF_ENHMETAFILE );
|
||||
|
||||
if (!has_mf && has_emf) add_synthesized_format( CF_METAFILEPICT, CF_ENHMETAFILE );
|
||||
else if (!has_emf && has_mf) add_synthesized_format( CF_ENHMETAFILE, CF_METAFILEPICT );
|
||||
}
|
||||
|
||||
/* render synthesized ANSI text based on the contents of the 'from' format */
|
||||
static HANDLE render_synthesized_textA( HANDLE data, UINT format, UINT from )
|
||||
{
|
||||
|
@ -619,14 +526,7 @@ BOOL WINAPI OpenClipboard( HWND hwnd )
|
|||
SERVER_START_REQ( open_clipboard )
|
||||
{
|
||||
req->window = wine_server_user_handle( hwnd );
|
||||
if ((ret = !wine_server_call_err( req )))
|
||||
{
|
||||
if (!reply->owner)
|
||||
{
|
||||
bCBHasChanged = FALSE;
|
||||
memset( synthesized_formats, 0, sizeof(synthesized_formats) );
|
||||
}
|
||||
}
|
||||
ret = !wine_server_call_err( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
|
@ -642,15 +542,7 @@ BOOL WINAPI CloseClipboard(void)
|
|||
HWND viewer = 0, owner = 0;
|
||||
BOOL ret;
|
||||
|
||||
TRACE("() Changed=%d\n", bCBHasChanged);
|
||||
|
||||
if (bCBHasChanged)
|
||||
{
|
||||
memset( synthesized_formats, 0, sizeof(synthesized_formats) );
|
||||
add_synthesized_text();
|
||||
add_synthesized_bitmap();
|
||||
add_synthesized_metafile();
|
||||
}
|
||||
TRACE( "\n" );
|
||||
|
||||
SERVER_START_REQ( close_clipboard )
|
||||
{
|
||||
|
@ -662,12 +554,8 @@ BOOL WINAPI CloseClipboard(void)
|
|||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (!ret) return FALSE;
|
||||
|
||||
bCBHasChanged = FALSE;
|
||||
|
||||
if (viewer) SendNotifyMessageW( viewer, WM_DRAWCLIPBOARD, (WPARAM)owner, 0 );
|
||||
return TRUE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -690,11 +578,6 @@ BOOL WINAPI EmptyClipboard(void)
|
|||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (ret)
|
||||
{
|
||||
bCBHasChanged = TRUE;
|
||||
memset( synthesized_formats, 0, sizeof(synthesized_formats) );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -829,17 +712,14 @@ HANDLE WINAPI SetClipboardData( UINT format, HANDLE data )
|
|||
SERVER_START_REQ( set_clipboard_data )
|
||||
{
|
||||
req->format = format;
|
||||
req->lcid = GetUserDefaultLCID();
|
||||
wine_server_add_data( req, ptr, size );
|
||||
ret = !wine_server_call_err( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (ret)
|
||||
{
|
||||
bCBHasChanged = TRUE;
|
||||
if (format < CF_MAX) synthesized_formats[format] = 0;
|
||||
retval = data;
|
||||
}
|
||||
|
||||
done:
|
||||
if (ptr) GlobalUnlock( ptr );
|
||||
|
@ -949,14 +829,12 @@ BOOL WINAPI GetUpdatedClipboardFormats( UINT *formats, UINT size, UINT *out_size
|
|||
HANDLE WINAPI GetClipboardData( UINT format )
|
||||
{
|
||||
NTSTATUS status;
|
||||
UINT from;
|
||||
HWND owner;
|
||||
HANDLE data;
|
||||
UINT size = 1024;
|
||||
BOOL render = TRUE;
|
||||
|
||||
if (format < CF_MAX && synthesized_formats[format])
|
||||
return render_synthesized_format( format, synthesized_formats[format] );
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!(data = GlobalAlloc( GMEM_FIXED, size ))) return 0;
|
||||
|
@ -966,6 +844,7 @@ HANDLE WINAPI GetClipboardData( UINT format )
|
|||
req->format = format;
|
||||
wine_server_set_reply( req, data, size );
|
||||
status = wine_server_call( req );
|
||||
from = reply->from;
|
||||
size = reply->total;
|
||||
owner = wine_server_ptr_handle( reply->owner );
|
||||
}
|
||||
|
@ -995,6 +874,7 @@ HANDLE WINAPI GetClipboardData( UINT format )
|
|||
SendMessageW( owner, WM_RENDERFORMAT, format, 0 );
|
||||
continue;
|
||||
}
|
||||
if (from) return render_synthesized_format( format, from );
|
||||
}
|
||||
TRACE( "%s returning 0\n", debugstr_format( format ));
|
||||
return 0;
|
||||
|
@ -1024,11 +904,6 @@ INT WINAPI GetPriorityClipboardFormat(UINT *list, INT nCount)
|
|||
|
||||
/**************************************************************************
|
||||
* GetClipboardSequenceNumber (USER32.@)
|
||||
* Supported on Win2k/Win98
|
||||
* MSDN: Windows clipboard code keeps a serial number for the clipboard
|
||||
* for each window station. The number is incremented whenever the
|
||||
* contents change or are emptied.
|
||||
* If you do not have WINSTA_ACCESSCLIPBOARD then the function returns 0
|
||||
*/
|
||||
DWORD WINAPI GetClipboardSequenceNumber(VOID)
|
||||
{
|
||||
|
|
|
@ -4531,7 +4531,9 @@ struct set_clipboard_data_request
|
|||
{
|
||||
struct request_header __header;
|
||||
unsigned int format;
|
||||
unsigned int lcid;
|
||||
/* VARARG(data,bytes); */
|
||||
char __pad_20[4];
|
||||
};
|
||||
struct set_clipboard_data_reply
|
||||
{
|
||||
|
@ -4548,9 +4550,11 @@ struct get_clipboard_data_request
|
|||
struct get_clipboard_data_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
unsigned int from;
|
||||
user_handle_t owner;
|
||||
data_size_t total;
|
||||
/* VARARG(data,bytes); */
|
||||
char __pad_20[4];
|
||||
};
|
||||
|
||||
|
||||
|
@ -6434,6 +6438,6 @@ union generic_reply
|
|||
struct terminate_job_reply terminate_job_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 520
|
||||
#define SERVER_PROTOCOL_VERSION 521
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
|
@ -41,6 +41,7 @@ struct clip_format
|
|||
{
|
||||
struct list entry; /* entry in format list */
|
||||
unsigned int id; /* format id */
|
||||
unsigned int from; /* for synthesized data, format to generate it from */
|
||||
data_size_t size; /* size of the data block */
|
||||
void *data; /* data contents, or NULL for delay-rendered */
|
||||
};
|
||||
|
@ -53,10 +54,12 @@ struct clipboard
|
|||
struct thread *owner_thread; /* thread id that owns the clipboard */
|
||||
user_handle_t owner_win; /* window that owns the clipboard data */
|
||||
user_handle_t viewer; /* first window in clipboard viewer list */
|
||||
unsigned int lcid; /* locale id to use for synthesizing text formats */
|
||||
unsigned int seqno; /* clipboard change sequence number */
|
||||
unsigned int open_seqno; /* sequence number at open time */
|
||||
struct list formats; /* list of data formats */
|
||||
unsigned int format_count; /* count of data formats */
|
||||
unsigned int format_map; /* existence bitmap for formats < CF_MAX */
|
||||
unsigned int listen_size; /* size of listeners array */
|
||||
unsigned int listen_count; /* count of listeners */
|
||||
user_handle_t *listeners; /* array of listener windows */
|
||||
|
@ -88,6 +91,8 @@ static const struct object_ops clipboard_ops =
|
|||
};
|
||||
|
||||
|
||||
#define HAS_FORMAT(map,id) ((map) & (1 << (id))) /* only for formats < CF_MAX */
|
||||
|
||||
/* find a data format in the clipboard */
|
||||
static struct clip_format *get_format( struct clipboard *clipboard, unsigned int id )
|
||||
{
|
||||
|
@ -106,10 +111,12 @@ static struct clip_format *add_format( struct clipboard *clipboard, unsigned int
|
|||
|
||||
if (!(format = mem_alloc( sizeof(*format )))) return NULL;
|
||||
format->id = id;
|
||||
format->from = 0;
|
||||
format->size = 0;
|
||||
format->data = NULL;
|
||||
list_add_tail( &clipboard->formats, &format->entry );
|
||||
clipboard->format_count++;
|
||||
if (id < CF_MAX) clipboard->format_map |= 1 << id;
|
||||
return format;
|
||||
}
|
||||
|
||||
|
@ -125,6 +132,7 @@ static void free_clipboard_formats( struct clipboard *clipboard )
|
|||
free( format );
|
||||
}
|
||||
clipboard->format_count = 0;
|
||||
clipboard->format_map = 0;
|
||||
}
|
||||
|
||||
/* dump a clipboard object */
|
||||
|
@ -164,6 +172,7 @@ static struct clipboard *get_process_clipboard(void)
|
|||
clipboard->viewer = 0;
|
||||
clipboard->seqno = 0;
|
||||
clipboard->format_count = 0;
|
||||
clipboard->format_map = 0;
|
||||
clipboard->listen_size = 0;
|
||||
clipboard->listen_count = 0;
|
||||
clipboard->listeners = NULL;
|
||||
|
@ -175,6 +184,49 @@ static struct clipboard *get_process_clipboard(void)
|
|||
return clipboard;
|
||||
}
|
||||
|
||||
/* add synthesized formats upon clipboard close */
|
||||
static int synthesize_formats( struct clipboard *clipboard )
|
||||
{
|
||||
static const unsigned int formats[][3] =
|
||||
{
|
||||
{ CF_TEXT, CF_OEMTEXT, CF_UNICODETEXT },
|
||||
{ CF_OEMTEXT, CF_UNICODETEXT, CF_TEXT },
|
||||
{ CF_UNICODETEXT, CF_TEXT, CF_OEMTEXT },
|
||||
{ CF_METAFILEPICT, CF_ENHMETAFILE },
|
||||
{ CF_ENHMETAFILE, CF_METAFILEPICT },
|
||||
{ CF_BITMAP, CF_DIB, CF_DIBV5 },
|
||||
{ CF_DIB, CF_BITMAP, CF_DIBV5 },
|
||||
{ CF_DIBV5, CF_BITMAP, CF_DIB }
|
||||
};
|
||||
unsigned int i, from, total = 0, map = clipboard->format_map;
|
||||
struct clip_format *format;
|
||||
|
||||
if (!HAS_FORMAT( map, CF_LOCALE ) &&
|
||||
(HAS_FORMAT( map, CF_TEXT ) || HAS_FORMAT( map, CF_OEMTEXT ) || HAS_FORMAT( map, CF_UNICODETEXT )))
|
||||
{
|
||||
void *data = memdup( &clipboard->lcid, sizeof(clipboard->lcid) );
|
||||
if ((format = add_format( clipboard, CF_LOCALE )))
|
||||
{
|
||||
clipboard->seqno++;
|
||||
format->data = data;
|
||||
format->size = sizeof(clipboard->lcid);
|
||||
}
|
||||
else free( data );
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++)
|
||||
{
|
||||
if (HAS_FORMAT( map, formats[i][0] )) continue;
|
||||
if (HAS_FORMAT( map, formats[i][1] )) from = formats[i][1];
|
||||
else if (HAS_FORMAT( map, formats[i][2] )) from = formats[i][2];
|
||||
else continue;
|
||||
if (!(format = add_format( clipboard, formats[i][0] ))) continue;
|
||||
format->from = from;
|
||||
total++;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/* add a clipboard listener */
|
||||
static void add_listener( struct clipboard *clipboard, user_handle_t window )
|
||||
{
|
||||
|
@ -233,6 +285,7 @@ static user_handle_t close_clipboard( struct clipboard *clipboard )
|
|||
clipboard->open_win = 0;
|
||||
clipboard->open_thread = NULL;
|
||||
if (clipboard->seqno == clipboard->open_seqno) return 0; /* unchanged */
|
||||
if (synthesize_formats( clipboard )) clipboard->seqno++;
|
||||
return notify_listeners( clipboard );
|
||||
}
|
||||
|
||||
|
@ -248,8 +301,9 @@ static user_handle_t release_clipboard( struct clipboard *clipboard )
|
|||
/* free the delayed-rendered formats, since we no longer have an owner to render them */
|
||||
LIST_FOR_EACH_ENTRY_SAFE( format, next, &clipboard->formats, struct clip_format, entry )
|
||||
{
|
||||
if (format->data) continue;
|
||||
if (format->data || format->from) continue;
|
||||
list_remove( &format->entry );
|
||||
if (format->id < CF_MAX) clipboard->format_map &= ~(1 << format->id);
|
||||
clipboard->format_count--;
|
||||
free( format );
|
||||
changed = 1;
|
||||
|
@ -406,8 +460,12 @@ DECL_HANDLER(set_clipboard_data)
|
|||
}
|
||||
|
||||
clipboard->seqno++;
|
||||
format->from = 0;
|
||||
format->size = get_req_data_size();
|
||||
format->data = data;
|
||||
|
||||
if (req->format == CF_TEXT || req->format == CF_OEMTEXT || req->format == CF_UNICODETEXT)
|
||||
clipboard->lcid = req->lcid;
|
||||
}
|
||||
|
||||
|
||||
|
@ -429,8 +487,9 @@ DECL_HANDLER(get_clipboard_data)
|
|||
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
|
||||
return;
|
||||
}
|
||||
reply->from = format->from;
|
||||
reply->total = format->size;
|
||||
if (!format->data) reply->owner = clipboard->owner_win;
|
||||
if (!format->data && !format->from) reply->owner = clipboard->owner_win;
|
||||
if (format->size <= get_reply_max_size()) set_reply_data( format->data, format->size );
|
||||
else set_error( STATUS_BUFFER_OVERFLOW );
|
||||
}
|
||||
|
|
|
@ -3202,6 +3202,7 @@ enum caret_state
|
|||
/* Add a data format to the clipboard */
|
||||
@REQ(set_clipboard_data)
|
||||
unsigned int format; /* clipboard format of the data */
|
||||
unsigned int lcid; /* locale id to use for synthesizing text formats */
|
||||
VARARG(data,bytes); /* data contents */
|
||||
@END
|
||||
|
||||
|
@ -3210,6 +3211,7 @@ enum caret_state
|
|||
@REQ(get_clipboard_data)
|
||||
unsigned int format; /* clipboard format of the data */
|
||||
@REPLY
|
||||
unsigned int from; /* for synthesized data, format to generate it from */
|
||||
user_handle_t owner; /* clipboard owner for delayed-rendered formats */
|
||||
data_size_t total; /* total data size */
|
||||
VARARG(data,bytes); /* data contents */
|
||||
|
|
|
@ -2051,12 +2051,14 @@ C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_reply, seqno) == 24 );
|
|||
C_ASSERT( sizeof(struct set_clipboard_info_reply) == 32 );
|
||||
C_ASSERT( sizeof(struct empty_clipboard_request) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct set_clipboard_data_request, format) == 12 );
|
||||
C_ASSERT( sizeof(struct set_clipboard_data_request) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct set_clipboard_data_request, lcid) == 16 );
|
||||
C_ASSERT( sizeof(struct set_clipboard_data_request) == 24 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_clipboard_data_request, format) == 12 );
|
||||
C_ASSERT( sizeof(struct get_clipboard_data_request) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_clipboard_data_reply, owner) == 8 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_clipboard_data_reply, total) == 12 );
|
||||
C_ASSERT( sizeof(struct get_clipboard_data_reply) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_clipboard_data_reply, from) == 8 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_clipboard_data_reply, owner) == 12 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_clipboard_data_reply, total) == 16 );
|
||||
C_ASSERT( sizeof(struct get_clipboard_data_reply) == 24 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_clipboard_formats_request, format) == 12 );
|
||||
C_ASSERT( sizeof(struct get_clipboard_formats_request) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_clipboard_formats_reply, count) == 8 );
|
||||
|
|
|
@ -3776,6 +3776,7 @@ static void dump_empty_clipboard_request( const struct empty_clipboard_request *
|
|||
static void dump_set_clipboard_data_request( const struct set_clipboard_data_request *req )
|
||||
{
|
||||
fprintf( stderr, " format=%08x", req->format );
|
||||
fprintf( stderr, ", lcid=%08x", req->lcid );
|
||||
dump_varargs_bytes( ", data=", cur_size );
|
||||
}
|
||||
|
||||
|
@ -3786,7 +3787,8 @@ static void dump_get_clipboard_data_request( const struct get_clipboard_data_req
|
|||
|
||||
static void dump_get_clipboard_data_reply( const struct get_clipboard_data_reply *req )
|
||||
{
|
||||
fprintf( stderr, " owner=%08x", req->owner );
|
||||
fprintf( stderr, " from=%08x", req->from );
|
||||
fprintf( stderr, ", owner=%08x", req->owner );
|
||||
fprintf( stderr, ", total=%u", req->total );
|
||||
dump_varargs_bytes( ", data=", cur_size );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue