diff --git a/dlls/user32/clipboard.c b/dlls/user32/clipboard.c index c4209899515..3282fa08f4c 100644 --- a/dlls/user32/clipboard.c +++ b/dlls/user32/clipboard.c @@ -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) { diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index d96bdb6d9c9..01ba97a724a 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -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 */ diff --git a/server/clipboard.c b/server/clipboard.c index 50975cece37..dcae0158816 100644 --- a/server/clipboard.c +++ b/server/clipboard.c @@ -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 ); } diff --git a/server/protocol.def b/server/protocol.def index 922e829bc97..f9840583534 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -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 */ diff --git a/server/request.h b/server/request.h index 1800df96d1e..3c6e2981334 100644 --- a/server/request.h +++ b/server/request.h @@ -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 ); diff --git a/server/trace.c b/server/trace.c index 2ecff74a192..ddc6cc7223a 100644 --- a/server/trace.c +++ b/server/trace.c @@ -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 ); }