server: Add a release_clipboard request, and notify the owner and viewer on release.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2016-09-01 20:06:09 +09:00
parent 27a73216c0
commit bddab0e7f8
8 changed files with 117 additions and 21 deletions

View File

@ -83,13 +83,18 @@ static UINT get_clipboard_flags(void)
*/ */
void CLIPBOARD_ReleaseOwner( HWND hwnd ) 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 ); 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; SERVER_END_REQ;
if (viewer) SendNotifyMessageW( viewer, WM_DRAWCLIPBOARD, (WPARAM)GetClipboardOwner(), 0 );
} }

View File

@ -172,18 +172,43 @@ static void run_process( const char *args )
static WNDPROC old_proc; static WNDPROC old_proc;
static LRESULT CALLBACK winproc_wrapper( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) 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 ); trace( "%p msg %04x\n", hwnd, msg );
if (!destroyed) if (!wm_renderallformats)
{
ok( GetClipboardOwner() == hwnd, "%04x: wrong owner %p/%p\n", msg, GetClipboardOwner(), hwnd ); 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( !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( GetClipboardViewer() == hwnd, "%04x: wrong viewer %p/%p\n", msg, GetClipboardViewer(), hwnd );
ok( GetOpenClipboardWindow() == hwnd, "%04x: wrong open win %p/%p\n", ok( GetOpenClipboardWindow() == hwnd, "%04x: wrong open win %p/%p\n",
msg, GetOpenClipboardWindow(), hwnd ); 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 ); return old_proc( hwnd, msg, wp, lp );
} }
@ -271,10 +296,12 @@ static void test_ClipboardOwner(void)
ok( ret, "OpenClipboard error %d\n", GetLastError()); ok( ret, "OpenClipboard error %d\n", GetLastError());
ret = EmptyClipboard(); ret = EmptyClipboard();
ok( ret, "EmptyClipboard error %d\n", GetLastError()); ok( ret, "EmptyClipboard error %d\n", GetLastError());
SetClipboardData( CF_WAVE, 0 );
SetClipboardViewer( hWnd1 ); SetClipboardViewer( hWnd1 );
ok( GetClipboardOwner() == hWnd1, "wrong owner %p/%p\n", GetClipboardOwner(), hWnd1 ); ok( GetClipboardOwner() == hWnd1, "wrong owner %p/%p\n", GetClipboardOwner(), hWnd1 );
ok( GetClipboardViewer() == hWnd1, "wrong viewer %p/%p\n", GetClipboardViewer(), hWnd1 ); ok( GetClipboardViewer() == hWnd1, "wrong viewer %p/%p\n", GetClipboardViewer(), hWnd1 );
ok( GetOpenClipboardWindow() == hWnd1, "wrong open win %p/%p\n", GetOpenClipboardWindow(), 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 ); old_proc = (WNDPROC)SetWindowLongPtrA( hWnd1, GWLP_WNDPROC, (LONG_PTR)winproc_wrapper );
ret = DestroyWindow(hWnd1); ret = DestroyWindow(hWnd1);
@ -285,6 +312,7 @@ static void test_ClipboardOwner(void)
ok(!GetClipboardOwner() && GetLastError() == 0xdeadbeef, "clipboard should not be owned\n"); ok(!GetClipboardOwner() && GetLastError() == 0xdeadbeef, "clipboard should not be owned\n");
ok(!GetClipboardViewer() && GetLastError() == 0xdeadbeef, "viewer still exists\n"); ok(!GetClipboardViewer() && GetLastError() == 0xdeadbeef, "viewer still exists\n");
ok(!GetOpenClipboardWindow() && GetLastError() == 0xdeadbeef, "clipboard should not be open\n"); ok(!GetOpenClipboardWindow() && GetLastError() == 0xdeadbeef, "clipboard should not be open\n");
todo_wine ok( !IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE available\n" );
SetLastError( 0xdeadbeef ); SetLastError( 0xdeadbeef );
ret = CloseClipboard(); ret = CloseClipboard();

View File

@ -1791,6 +1791,8 @@ static void WIN_SendDestroyMsg( HWND hwnd )
if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd ); if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
} }
if (hwnd == GetClipboardOwner()) CLIPBOARD_ReleaseOwner( hwnd );
/* /*
* Send the WM_DESTROY to the window. * Send the WM_DESTROY to the window.
*/ */
@ -1901,8 +1903,6 @@ BOOL WINAPI DestroyWindow( HWND hwnd )
WIN_SendDestroyMsg( hwnd ); WIN_SendDestroyMsg( hwnd );
if (!IsWindow( hwnd )) return TRUE; if (!IsWindow( hwnd )) return TRUE;
CLIPBOARD_ReleaseOwner( hwnd );
/* Destroy the window storage */ /* Destroy the window storage */
WIN_DestroyWindow( hwnd ); WIN_DestroyWindow( hwnd );

View File

@ -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 get_clipboard_info_request
{ {
struct request_header __header; struct request_header __header;
@ -5715,6 +5729,7 @@ enum request
REQ_close_clipboard, REQ_close_clipboard,
REQ_set_clipboard_info, REQ_set_clipboard_info,
REQ_empty_clipboard, REQ_empty_clipboard,
REQ_release_clipboard,
REQ_get_clipboard_info, REQ_get_clipboard_info,
REQ_set_clipboard_viewer, REQ_set_clipboard_viewer,
REQ_add_clipboard_listener, REQ_add_clipboard_listener,
@ -6001,6 +6016,7 @@ union generic_request
struct close_clipboard_request close_clipboard_request; struct close_clipboard_request close_clipboard_request;
struct set_clipboard_info_request set_clipboard_info_request; struct set_clipboard_info_request set_clipboard_info_request;
struct empty_clipboard_request empty_clipboard_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 get_clipboard_info_request get_clipboard_info_request;
struct set_clipboard_viewer_request set_clipboard_viewer_request; struct set_clipboard_viewer_request set_clipboard_viewer_request;
struct add_clipboard_listener_request add_clipboard_listener_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 close_clipboard_reply close_clipboard_reply;
struct set_clipboard_info_reply set_clipboard_info_reply; struct set_clipboard_info_reply set_clipboard_info_reply;
struct empty_clipboard_reply empty_clipboard_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 get_clipboard_info_reply get_clipboard_info_reply;
struct set_clipboard_viewer_reply set_clipboard_viewer_reply; struct set_clipboard_viewer_reply set_clipboard_viewer_reply;
struct add_clipboard_listener_reply add_clipboard_listener_reply; struct add_clipboard_listener_reply add_clipboard_listener_reply;
@ -6348,6 +6365,6 @@ union generic_reply
struct terminate_job_reply terminate_job_reply; struct terminate_job_reply terminate_job_reply;
}; };
#define SERVER_PROTOCOL_VERSION 514 #define SERVER_PROTOCOL_VERSION 515
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -183,6 +183,15 @@ static user_handle_t close_clipboard( struct clipboard *clipboard )
return clipboard->viewer; 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 */ /* cleanup clipboard information upon window destruction */
void cleanup_clipboard_window( struct desktop *desktop, user_handle_t window ) 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 ); remove_listener( clipboard, window );
if (clipboard->viewer == window) clipboard->viewer = 0; if (clipboard->viewer == window) clipboard->viewer = 0;
if (clipboard->owner_win == window) if (clipboard->owner_win == window) release_clipboard( clipboard );
{
clipboard->owner_win = 0;
clipboard->owner_thread = NULL;
}
if (clipboard->open_win == window) if (clipboard->open_win == window)
{ {
user_handle_t viewer = close_clipboard( clipboard ); user_handle_t viewer = close_clipboard( clipboard );
@ -215,11 +220,7 @@ void cleanup_clipboard_thread(struct thread *thread)
if ((clipboard = winstation->clipboard)) if ((clipboard = winstation->clipboard))
{ {
if (thread == clipboard->owner_thread) if (thread == clipboard->owner_thread) release_clipboard( clipboard );
{
clipboard->owner_win = 0;
clipboard->owner_thread = NULL;
}
if (thread == clipboard->open_thread) if (thread == clipboard->open_thread)
{ {
user_handle_t viewer = close_clipboard( clipboard ); 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) DECL_HANDLER(get_clipboard_info)
{ {
struct clipboard *clipboard = get_process_clipboard(); struct clipboard *clipboard = get_process_clipboard();

View File

@ -3200,6 +3200,14 @@ enum caret_state
@END @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 */ /* Get clipboard information */
@REQ(get_clipboard_info) @REQ(get_clipboard_info)
@REPLY @REPLY

View File

@ -330,6 +330,7 @@ DECL_HANDLER(open_clipboard);
DECL_HANDLER(close_clipboard); DECL_HANDLER(close_clipboard);
DECL_HANDLER(set_clipboard_info); DECL_HANDLER(set_clipboard_info);
DECL_HANDLER(empty_clipboard); DECL_HANDLER(empty_clipboard);
DECL_HANDLER(release_clipboard);
DECL_HANDLER(get_clipboard_info); DECL_HANDLER(get_clipboard_info);
DECL_HANDLER(set_clipboard_viewer); DECL_HANDLER(set_clipboard_viewer);
DECL_HANDLER(add_clipboard_listener); 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_close_clipboard,
(req_handler)req_set_clipboard_info, (req_handler)req_set_clipboard_info,
(req_handler)req_empty_clipboard, (req_handler)req_empty_clipboard,
(req_handler)req_release_clipboard,
(req_handler)req_get_clipboard_info, (req_handler)req_get_clipboard_info,
(req_handler)req_set_clipboard_viewer, (req_handler)req_set_clipboard_viewer,
(req_handler)req_add_clipboard_listener, (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( FIELD_OFFSET(struct set_clipboard_info_reply, seqno) == 24 );
C_ASSERT( sizeof(struct set_clipboard_info_reply) == 32 ); C_ASSERT( sizeof(struct set_clipboard_info_reply) == 32 );
C_ASSERT( sizeof(struct empty_clipboard_request) == 16 ); 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( 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, window) == 8 );
C_ASSERT( FIELD_OFFSET(struct get_clipboard_info_reply, owner) == 12 ); C_ASSERT( FIELD_OFFSET(struct get_clipboard_info_reply, owner) == 12 );

View File

@ -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 ) 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_close_clipboard_request,
(dump_func)dump_set_clipboard_info_request, (dump_func)dump_set_clipboard_info_request,
(dump_func)dump_empty_clipboard_request, (dump_func)dump_empty_clipboard_request,
(dump_func)dump_release_clipboard_request,
(dump_func)dump_get_clipboard_info_request, (dump_func)dump_get_clipboard_info_request,
(dump_func)dump_set_clipboard_viewer_request, (dump_func)dump_set_clipboard_viewer_request,
(dump_func)dump_add_clipboard_listener_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_close_clipboard_reply,
(dump_func)dump_set_clipboard_info_reply, (dump_func)dump_set_clipboard_info_reply,
NULL, NULL,
(dump_func)dump_release_clipboard_reply,
(dump_func)dump_get_clipboard_info_reply, (dump_func)dump_get_clipboard_info_reply,
(dump_func)dump_set_clipboard_viewer_reply, (dump_func)dump_set_clipboard_viewer_reply,
NULL, NULL,
@ -5199,6 +5211,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"close_clipboard", "close_clipboard",
"set_clipboard_info", "set_clipboard_info",
"empty_clipboard", "empty_clipboard",
"release_clipboard",
"get_clipboard_info", "get_clipboard_info",
"set_clipboard_viewer", "set_clipboard_viewer",
"add_clipboard_listener", "add_clipboard_listener",
@ -5324,6 +5337,7 @@ static const struct
{ "INVALID_IMAGE_PROTECT", STATUS_INVALID_IMAGE_PROTECT }, { "INVALID_IMAGE_PROTECT", STATUS_INVALID_IMAGE_PROTECT },
{ "INVALID_IMAGE_WIN_64", STATUS_INVALID_IMAGE_WIN_64 }, { "INVALID_IMAGE_WIN_64", STATUS_INVALID_IMAGE_WIN_64 },
{ "INVALID_LOCK_SEQUENCE", STATUS_INVALID_LOCK_SEQUENCE }, { "INVALID_LOCK_SEQUENCE", STATUS_INVALID_LOCK_SEQUENCE },
{ "INVALID_OWNER", STATUS_INVALID_OWNER },
{ "INVALID_PARAMETER", STATUS_INVALID_PARAMETER }, { "INVALID_PARAMETER", STATUS_INVALID_PARAMETER },
{ "INVALID_SECURITY_DESCR", STATUS_INVALID_SECURITY_DESCR }, { "INVALID_SECURITY_DESCR", STATUS_INVALID_SECURITY_DESCR },
{ "IO_TIMEOUT", STATUS_IO_TIMEOUT }, { "IO_TIMEOUT", STATUS_IO_TIMEOUT },