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:
parent
27a73216c0
commit
bddab0e7f8
|
@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 },
|
||||
|
|
Loading…
Reference in New Issue