From bddab0e7f8037e1eebebf4234ca883151389488b Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 1 Sep 2016 20:06:09 +0900 Subject: [PATCH] server: Add a release_clipboard request, and notify the owner and viewer on release. Signed-off-by: Alexandre Julliard --- dlls/user32/clipboard.c | 11 +++++++--- dlls/user32/tests/clipboard.c | 36 ++++++++++++++++++++++++++---- dlls/user32/win.c | 4 ++-- include/wine/server_protocol.h | 19 +++++++++++++++- server/clipboard.c | 40 ++++++++++++++++++++++++---------- server/protocol.def | 8 +++++++ server/request.h | 6 +++++ server/trace.c | 14 ++++++++++++ 8 files changed, 117 insertions(+), 21 deletions(-) diff --git a/dlls/user32/clipboard.c b/dlls/user32/clipboard.c index 67a27eec502..8e53a9f3002 100644 --- a/dlls/user32/clipboard.c +++ b/dlls/user32/clipboard.c @@ -83,13 +83,18 @@ static UINT get_clipboard_flags(void) */ void CLIPBOARD_ReleaseOwner( HWND hwnd ) { - SERVER_START_REQ( set_clipboard_info ) + HWND viewer = 0; + + SendMessageW( hwnd, WM_RENDERALLFORMATS, 0, 0 ); + + SERVER_START_REQ( release_clipboard ) { - req->flags = SET_CB_RELOWNER | SET_CB_SEQNO; req->owner = wine_server_user_handle( hwnd ); - wine_server_call( req ); + if (!wine_server_call( req )) viewer = wine_server_ptr_handle( reply->viewer ); } SERVER_END_REQ; + + if (viewer) SendNotifyMessageW( viewer, WM_DRAWCLIPBOARD, (WPARAM)GetClipboardOwner(), 0 ); } diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c index 56360e8fedf..7e0e41cb171 100644 --- a/dlls/user32/tests/clipboard.c +++ b/dlls/user32/tests/clipboard.c @@ -172,18 +172,43 @@ static void run_process( const char *args ) static WNDPROC old_proc; static LRESULT CALLBACK winproc_wrapper( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) { - static int destroyed; + static int wm_renderallformats; + static int wm_drawclipboard; + static int seqno; + DWORD msg_flags = InSendMessageEx( NULL ); - if (msg == WM_DESTROY) destroyed = TRUE; + if (!seqno) seqno = GetClipboardSequenceNumber(); trace( "%p msg %04x\n", hwnd, msg ); - if (!destroyed) + if (!wm_renderallformats) + { ok( GetClipboardOwner() == hwnd, "%04x: wrong owner %p/%p\n", msg, GetClipboardOwner(), hwnd ); - else todo_wine_if (msg == WM_DESTROY) + ok( seqno == GetClipboardSequenceNumber(), "%04x: seqno changed\n", msg ); + } + else + { ok( !GetClipboardOwner(), "%04x: wrong owner %p\n", msg, GetClipboardOwner() ); + ok( seqno + 1 == GetClipboardSequenceNumber(), "%04x: seqno unchanged\n", msg ); + } ok( GetClipboardViewer() == hwnd, "%04x: wrong viewer %p/%p\n", msg, GetClipboardViewer(), hwnd ); ok( GetOpenClipboardWindow() == hwnd, "%04x: wrong open win %p/%p\n", msg, GetOpenClipboardWindow(), hwnd ); + + switch (msg) + { + case WM_DESTROY: + ok( wm_renderallformats, "didn't receive WM_RENDERALLFORMATS before WM_DESTROY\n" ); + todo_wine ok( wm_drawclipboard, "didn't receive WM_DRAWCLIPBOARD before WM_DESTROY\n" ); + break; + case WM_DRAWCLIPBOARD: + ok( msg_flags == ISMEX_NOSEND, "WM_DRAWCLIPBOARD wrong flags %x\n", msg_flags ); + wm_drawclipboard++; + break; + case WM_RENDERALLFORMATS: + ok( msg_flags == ISMEX_NOSEND, "WM_RENDERALLFORMATS wrong flags %x\n", msg_flags ); + wm_renderallformats++; + break; + } return old_proc( hwnd, msg, wp, lp ); } @@ -271,10 +296,12 @@ static void test_ClipboardOwner(void) ok( ret, "OpenClipboard error %d\n", GetLastError()); ret = EmptyClipboard(); ok( ret, "EmptyClipboard error %d\n", GetLastError()); + SetClipboardData( CF_WAVE, 0 ); SetClipboardViewer( hWnd1 ); ok( GetClipboardOwner() == hWnd1, "wrong owner %p/%p\n", GetClipboardOwner(), hWnd1 ); ok( GetClipboardViewer() == hWnd1, "wrong viewer %p/%p\n", GetClipboardViewer(), hWnd1 ); ok( GetOpenClipboardWindow() == hWnd1, "wrong open win %p/%p\n", GetOpenClipboardWindow(), hWnd1 ); + ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" ); old_proc = (WNDPROC)SetWindowLongPtrA( hWnd1, GWLP_WNDPROC, (LONG_PTR)winproc_wrapper ); ret = DestroyWindow(hWnd1); @@ -285,6 +312,7 @@ static void test_ClipboardOwner(void) ok(!GetClipboardOwner() && GetLastError() == 0xdeadbeef, "clipboard should not be owned\n"); ok(!GetClipboardViewer() && GetLastError() == 0xdeadbeef, "viewer still exists\n"); ok(!GetOpenClipboardWindow() && GetLastError() == 0xdeadbeef, "clipboard should not be open\n"); + todo_wine ok( !IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE available\n" ); SetLastError( 0xdeadbeef ); ret = CloseClipboard(); diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 2a87e95b1af..b65fdd7f52a 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -1791,6 +1791,8 @@ static void WIN_SendDestroyMsg( HWND hwnd ) if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd ); } + if (hwnd == GetClipboardOwner()) CLIPBOARD_ReleaseOwner( hwnd ); + /* * Send the WM_DESTROY to the window. */ @@ -1901,8 +1903,6 @@ BOOL WINAPI DestroyWindow( HWND hwnd ) WIN_SendDestroyMsg( hwnd ); if (!IsWindow( hwnd )) return TRUE; - CLIPBOARD_ReleaseOwner( hwnd ); - /* Destroy the window storage */ WIN_DestroyWindow( hwnd ); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 786e00fc01a..e8b33b0f727 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -4527,6 +4527,20 @@ struct empty_clipboard_reply +struct release_clipboard_request +{ + struct request_header __header; + user_handle_t owner; +}; +struct release_clipboard_reply +{ + struct reply_header __header; + user_handle_t viewer; + char __pad_12[4]; +}; + + + struct get_clipboard_info_request { struct request_header __header; @@ -5715,6 +5729,7 @@ enum request REQ_close_clipboard, REQ_set_clipboard_info, REQ_empty_clipboard, + REQ_release_clipboard, REQ_get_clipboard_info, REQ_set_clipboard_viewer, REQ_add_clipboard_listener, @@ -6001,6 +6016,7 @@ union generic_request struct close_clipboard_request close_clipboard_request; struct set_clipboard_info_request set_clipboard_info_request; struct empty_clipboard_request empty_clipboard_request; + struct release_clipboard_request release_clipboard_request; struct get_clipboard_info_request get_clipboard_info_request; struct set_clipboard_viewer_request set_clipboard_viewer_request; struct add_clipboard_listener_request add_clipboard_listener_request; @@ -6285,6 +6301,7 @@ union generic_reply struct close_clipboard_reply close_clipboard_reply; struct set_clipboard_info_reply set_clipboard_info_reply; struct empty_clipboard_reply empty_clipboard_reply; + struct release_clipboard_reply release_clipboard_reply; struct get_clipboard_info_reply get_clipboard_info_reply; struct set_clipboard_viewer_reply set_clipboard_viewer_reply; struct add_clipboard_listener_reply add_clipboard_listener_reply; @@ -6348,6 +6365,6 @@ union generic_reply struct terminate_job_reply terminate_job_reply; }; -#define SERVER_PROTOCOL_VERSION 514 +#define SERVER_PROTOCOL_VERSION 515 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/clipboard.c b/server/clipboard.c index a9bbaec2e9d..21e6c9ec3b2 100644 --- a/server/clipboard.c +++ b/server/clipboard.c @@ -183,6 +183,15 @@ static user_handle_t close_clipboard( struct clipboard *clipboard ) return clipboard->viewer; } +/* release the clipboard owner, and return the viewer window that should be notified if any */ +static user_handle_t release_clipboard( struct clipboard *clipboard ) +{ + clipboard->owner_win = 0; + clipboard->owner_thread = NULL; + /* FIXME: free delay-rendered formats if any and notify listeners */ + return 0; +} + /* cleanup clipboard information upon window destruction */ void cleanup_clipboard_window( struct desktop *desktop, user_handle_t window ) { @@ -192,11 +201,7 @@ void cleanup_clipboard_window( struct desktop *desktop, user_handle_t window ) remove_listener( clipboard, window ); if (clipboard->viewer == window) clipboard->viewer = 0; - if (clipboard->owner_win == window) - { - clipboard->owner_win = 0; - clipboard->owner_thread = NULL; - } + if (clipboard->owner_win == window) release_clipboard( clipboard ); if (clipboard->open_win == window) { user_handle_t viewer = close_clipboard( clipboard ); @@ -215,11 +220,7 @@ void cleanup_clipboard_thread(struct thread *thread) if ((clipboard = winstation->clipboard)) { - if (thread == clipboard->owner_thread) - { - clipboard->owner_win = 0; - clipboard->owner_thread = NULL; - } + if (thread == clipboard->owner_thread) release_clipboard( clipboard ); if (thread == clipboard->open_thread) { user_handle_t viewer = close_clipboard( clipboard ); @@ -341,7 +342,24 @@ DECL_HANDLER(empty_clipboard) } -/* Get clipboard information */ +/* release ownership of the clipboard */ +DECL_HANDLER(release_clipboard) +{ + struct clipboard *clipboard = get_process_clipboard(); + user_handle_t owner; + + if (!clipboard) return; + + if (!(owner = get_valid_window_handle( req->owner ))) return; + + if (clipboard->owner_win == owner) + reply->viewer = release_clipboard( clipboard ); + else + set_error( STATUS_INVALID_OWNER ); +} + + +/* get clipboard information */ DECL_HANDLER(get_clipboard_info) { struct clipboard *clipboard = get_process_clipboard(); diff --git a/server/protocol.def b/server/protocol.def index 6b1a62e6390..86b209e2c88 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3200,6 +3200,14 @@ enum caret_state @END +/* Release ownership of the clipboard */ +@REQ(release_clipboard) + user_handle_t owner; /* clipboard owner to release */ +@REPLY + user_handle_t viewer; /* first clipboard viewer */ +@END + + /* Get clipboard information */ @REQ(get_clipboard_info) @REPLY diff --git a/server/request.h b/server/request.h index d735932c0ad..58aebbc845f 100644 --- a/server/request.h +++ b/server/request.h @@ -330,6 +330,7 @@ DECL_HANDLER(open_clipboard); DECL_HANDLER(close_clipboard); DECL_HANDLER(set_clipboard_info); DECL_HANDLER(empty_clipboard); +DECL_HANDLER(release_clipboard); DECL_HANDLER(get_clipboard_info); DECL_HANDLER(set_clipboard_viewer); DECL_HANDLER(add_clipboard_listener); @@ -615,6 +616,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_close_clipboard, (req_handler)req_set_clipboard_info, (req_handler)req_empty_clipboard, + (req_handler)req_release_clipboard, (req_handler)req_get_clipboard_info, (req_handler)req_set_clipboard_viewer, (req_handler)req_add_clipboard_listener, @@ -2041,6 +2043,10 @@ C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_reply, old_viewer) == 20 ); 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 release_clipboard_request, owner) == 12 ); +C_ASSERT( sizeof(struct release_clipboard_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct release_clipboard_reply, viewer) == 8 ); +C_ASSERT( sizeof(struct release_clipboard_reply) == 16 ); C_ASSERT( sizeof(struct get_clipboard_info_request) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_clipboard_info_reply, window) == 8 ); C_ASSERT( FIELD_OFFSET(struct get_clipboard_info_reply, owner) == 12 ); diff --git a/server/trace.c b/server/trace.c index c246f82518f..d99c4b20c5f 100644 --- a/server/trace.c +++ b/server/trace.c @@ -3774,6 +3774,16 @@ static void dump_empty_clipboard_request( const struct empty_clipboard_request * { } +static void dump_release_clipboard_request( const struct release_clipboard_request *req ) +{ + fprintf( stderr, " owner=%08x", req->owner ); +} + +static void dump_release_clipboard_reply( const struct release_clipboard_reply *req ) +{ + fprintf( stderr, " viewer=%08x", req->viewer ); +} + static void dump_get_clipboard_info_request( const struct get_clipboard_info_request *req ) { } @@ -4635,6 +4645,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_close_clipboard_request, (dump_func)dump_set_clipboard_info_request, (dump_func)dump_empty_clipboard_request, + (dump_func)dump_release_clipboard_request, (dump_func)dump_get_clipboard_info_request, (dump_func)dump_set_clipboard_viewer_request, (dump_func)dump_add_clipboard_listener_request, @@ -4917,6 +4928,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_close_clipboard_reply, (dump_func)dump_set_clipboard_info_reply, NULL, + (dump_func)dump_release_clipboard_reply, (dump_func)dump_get_clipboard_info_reply, (dump_func)dump_set_clipboard_viewer_reply, NULL, @@ -5199,6 +5211,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "close_clipboard", "set_clipboard_info", "empty_clipboard", + "release_clipboard", "get_clipboard_info", "set_clipboard_viewer", "add_clipboard_listener", @@ -5324,6 +5337,7 @@ static const struct { "INVALID_IMAGE_PROTECT", STATUS_INVALID_IMAGE_PROTECT }, { "INVALID_IMAGE_WIN_64", STATUS_INVALID_IMAGE_WIN_64 }, { "INVALID_LOCK_SEQUENCE", STATUS_INVALID_LOCK_SEQUENCE }, + { "INVALID_OWNER", STATUS_INVALID_OWNER }, { "INVALID_PARAMETER", STATUS_INVALID_PARAMETER }, { "INVALID_SECURITY_DESCR", STATUS_INVALID_SECURITY_DESCR }, { "IO_TIMEOUT", STATUS_IO_TIMEOUT },