diff --git a/dlls/user32/clipboard.c b/dlls/user32/clipboard.c index ae6b88768d3..dec738afa75 100644 --- a/dlls/user32/clipboard.c +++ b/dlls/user32/clipboard.c @@ -70,30 +70,6 @@ typedef struct static BOOL bCBHasChanged = FALSE; -/************************************************************************** - * CLIPBOARD_SetClipboardOwner - * - * Set the global wineserver clipboard owner. The current process will - * be the owner and will get the render notifications. - */ -static BOOL CLIPBOARD_SetClipboardOwner(HWND hWnd) -{ - BOOL bRet; - - TRACE(" hWnd(%p)\n", hWnd); - - SERVER_START_REQ( set_clipboard_info ) - { - req->flags = SET_CB_OWNER; - req->owner = wine_server_user_handle( hWnd ); - bRet = !wine_server_call_err( req ); - } - SERVER_END_REQ; - - return bRet; -} - - /************************************************************************** * CLIPBOARD_GetClipboardInfo */ @@ -256,39 +232,25 @@ BOOL WINAPI CloseClipboard(void) */ BOOL WINAPI EmptyClipboard(void) { - CLIPBOARDINFO cbinfo; + BOOL ret; + HWND owner = GetClipboardOwner(); TRACE("()\n"); - if (!CLIPBOARD_GetClipboardInfo(&cbinfo) || - ~cbinfo.flags & CB_OPEN) + if (owner) SendMessageTimeoutW( owner, WM_DESTROYCLIPBOARD, 0, 0, SMTO_ABORTIFHUNG, 5000, NULL ); + + SERVER_START_REQ( empty_clipboard ) { - WARN("Clipboard not opened by calling task!\n"); - SetLastError(ERROR_CLIPBOARD_NOT_OPEN); - return FALSE; + ret = !wine_server_call_err( req ); } + SERVER_END_REQ; - /* Destroy private objects */ - if (cbinfo.hWndOwner) - SendMessageW(cbinfo.hWndOwner, WM_DESTROYCLIPBOARD, 0, 0); - - /* Tell the driver to acquire the selection. The current owner - * will be signaled to delete its own cache. */ - - /* Assign ownership of the clipboard to the current client. We do - * this before acquiring the selection so that when we do acquire the - * selection and the selection loser gets notified, it can check if - * it has lost the Wine clipboard ownership. If it did then it knows - * that a WM_DESTROYCLIPBOARD has already been sent. Otherwise it - * lost the selection to a X app and it should send the - * WM_DESTROYCLIPBOARD itself. */ - CLIPBOARD_SetClipboardOwner(cbinfo.hWndOpen); - - USER_Driver->pEmptyClipboard(); - - bCBHasChanged = TRUE; - - return TRUE; + if (ret) + { + USER_Driver->pEmptyClipboard(); + bCBHasChanged = TRUE; + } + return ret; } diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c index 05deed64964..b9add86e892 100644 --- a/dlls/user32/tests/clipboard.c +++ b/dlls/user32/tests/clipboard.c @@ -408,7 +408,7 @@ static DWORD WINAPI clipboard_thread(void *param) if (pGetClipboardSequenceNumber) { seq = pGetClipboardSequenceNumber(); - todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); + ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } count = SendMessageA( win, WM_USER+1, 0, 0 ); @@ -424,7 +424,7 @@ static DWORD WINAPI clipboard_thread(void *param) if (pGetClipboardSequenceNumber) { seq = pGetClipboardSequenceNumber(); - todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); + ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } count = SendMessageA( win, WM_USER+1, 0, 0 ); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index d296369e52a..febaee54a2f 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -4381,7 +4381,6 @@ struct set_clipboard_info_reply }; #define SET_CB_OPEN 0x001 -#define SET_CB_OWNER 0x002 #define SET_CB_VIEWER 0x004 #define SET_CB_SEQNO 0x008 #define SET_CB_RELOWNER 0x010 @@ -4392,6 +4391,18 @@ struct set_clipboard_info_reply +struct empty_clipboard_request +{ + struct request_header __header; + char __pad_12[4]; +}; +struct empty_clipboard_reply +{ + struct reply_header __header; +}; + + + struct open_token_request { struct request_header __header; @@ -5462,6 +5473,7 @@ enum request REQ_destroy_class, REQ_set_class_info, REQ_set_clipboard_info, + REQ_empty_clipboard, REQ_open_token, REQ_set_global_windows, REQ_adjust_token_privileges, @@ -5734,6 +5746,7 @@ union generic_request struct destroy_class_request destroy_class_request; struct set_class_info_request set_class_info_request; struct set_clipboard_info_request set_clipboard_info_request; + struct empty_clipboard_request empty_clipboard_request; struct open_token_request open_token_request; struct set_global_windows_request set_global_windows_request; struct adjust_token_privileges_request adjust_token_privileges_request; @@ -6004,6 +6017,7 @@ union generic_reply struct destroy_class_reply destroy_class_reply; struct set_class_info_reply set_class_info_reply; struct set_clipboard_info_reply set_clipboard_info_reply; + struct empty_clipboard_reply empty_clipboard_reply; struct open_token_reply open_token_reply; struct set_global_windows_reply set_global_windows_reply; struct adjust_token_privileges_reply adjust_token_privileges_reply; @@ -6059,6 +6073,6 @@ union generic_reply struct terminate_job_reply terminate_job_reply; }; -#define SERVER_PROTOCOL_VERSION 475 +#define SERVER_PROTOCOL_VERSION 476 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/clipboard.c b/server/clipboard.c index 87dde50d617..2f56c72f676 100644 --- a/server/clipboard.c +++ b/server/clipboard.c @@ -160,18 +160,6 @@ static int close_clipboard( struct clipboard *clipboard ) return 1; } -static int set_clipboard_owner( struct clipboard *clipboard, user_handle_t win ) -{ - if (clipboard->open_thread && clipboard->open_thread->process != current->process) - { - set_error(STATUS_WAS_LOCKED); - return 0; - } - clipboard->owner_win = get_user_full_handle( win ); - clipboard->owner_thread = current; - return 1; -} - static int release_clipboard_owner( struct clipboard *clipboard, user_handle_t win ) { if ((clipboard->open_thread && clipboard->open_thread->process != current->process) || @@ -216,11 +204,7 @@ DECL_HANDLER(set_clipboard_info) if (!close_clipboard( clipboard )) return; } - if (req->flags & SET_CB_OWNER) - { - if (!set_clipboard_owner( clipboard, req->owner )) return; - } - else if (req->flags & SET_CB_RELOWNER) + if (req->flags & SET_CB_RELOWNER) { if (!release_clipboard_owner( clipboard, req->owner )) return; } @@ -236,3 +220,21 @@ DECL_HANDLER(set_clipboard_info) if (clipboard->owner_thread && clipboard->owner_thread->process == current->process) reply->flags |= CB_PROCESS; } + + +/* empty the clipboard and grab ownership */ +DECL_HANDLER(empty_clipboard) +{ + struct clipboard *clipboard = get_process_clipboard(); + + if (!clipboard) return; + + if (clipboard->open_thread != current) + { + set_win32_error( ERROR_CLIPBOARD_NOT_OPEN ); + return; + } + clipboard->owner_win = clipboard->open_win; + clipboard->owner_thread = clipboard->open_thread; + clipboard->seqno++; +} diff --git a/server/protocol.def b/server/protocol.def index 54db246ff01..9e5e416341e 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3087,7 +3087,6 @@ enum coords_relative @END #define SET_CB_OPEN 0x001 -#define SET_CB_OWNER 0x002 #define SET_CB_VIEWER 0x004 #define SET_CB_SEQNO 0x008 #define SET_CB_RELOWNER 0x010 @@ -3097,6 +3096,11 @@ enum coords_relative #define CB_PROCESS 0x100 +/* Empty the clipboard and grab ownership */ +@REQ(empty_clipboard) +@END + + /* Open a security token */ @REQ(open_token) obj_handle_t handle; /* handle to the thread or process */ diff --git a/server/request.h b/server/request.h index ad161878213..1dfd10ec73a 100644 --- a/server/request.h +++ b/server/request.h @@ -318,6 +318,7 @@ DECL_HANDLER(create_class); DECL_HANDLER(destroy_class); DECL_HANDLER(set_class_info); DECL_HANDLER(set_clipboard_info); +DECL_HANDLER(empty_clipboard); DECL_HANDLER(open_token); DECL_HANDLER(set_global_windows); DECL_HANDLER(adjust_token_privileges); @@ -589,6 +590,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_destroy_class, (req_handler)req_set_class_info, (req_handler)req_set_clipboard_info, + (req_handler)req_empty_clipboard, (req_handler)req_open_token, (req_handler)req_set_global_windows, (req_handler)req_adjust_token_privileges, @@ -1989,6 +1991,7 @@ C_ASSERT( FIELD_OFFSET(struct set_clipboard_info_reply, old_owner) == 16 ); 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 open_token_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct open_token_request, access) == 16 ); C_ASSERT( FIELD_OFFSET(struct open_token_request, attributes) == 20 ); diff --git a/server/trace.c b/server/trace.c index 95c040aa499..73abd1ba266 100644 --- a/server/trace.c +++ b/server/trace.c @@ -3639,6 +3639,10 @@ static void dump_set_clipboard_info_reply( const struct set_clipboard_info_reply fprintf( stderr, ", seqno=%08x", req->seqno ); } +static void dump_empty_clipboard_request( const struct empty_clipboard_request *req ) +{ +} + static void dump_open_token_request( const struct open_token_request *req ) { fprintf( stderr, " handle=%04x", req->handle ); @@ -4434,6 +4438,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_destroy_class_request, (dump_func)dump_set_class_info_request, (dump_func)dump_set_clipboard_info_request, + (dump_func)dump_empty_clipboard_request, (dump_func)dump_open_token_request, (dump_func)dump_set_global_windows_request, (dump_func)dump_adjust_token_privileges_request, @@ -4702,6 +4707,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_destroy_class_reply, (dump_func)dump_set_class_info_reply, (dump_func)dump_set_clipboard_info_reply, + NULL, (dump_func)dump_open_token_reply, (dump_func)dump_set_global_windows_reply, (dump_func)dump_adjust_token_privileges_reply, @@ -4970,6 +4976,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "destroy_class", "set_class_info", "set_clipboard_info", + "empty_clipboard", "open_token", "set_global_windows", "adjust_token_privileges",