diff --git a/dlls/user32/clipboard.c b/dlls/user32/clipboard.c index 83229d3873a..67a27eec502 100644 --- a/dlls/user32/clipboard.c +++ b/dlls/user32/clipboard.c @@ -185,8 +185,8 @@ BOOL WINAPI CloseClipboard(void) { if (owner) USER_Driver->pEndClipboardUpdate(); bCBHasChanged = FALSE; - if (viewer) SendNotifyMessageW(viewer, WM_DRAWCLIPBOARD, (WPARAM) GetClipboardOwner(), 0); } + if (viewer) SendNotifyMessageW( viewer, WM_DRAWCLIPBOARD, (WPARAM)GetClipboardOwner(), 0 ); return TRUE; } diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c index 67609c11681..56360e8fedf 100644 --- a/dlls/user32/tests/clipboard.c +++ b/dlls/user32/tests/clipboard.c @@ -513,33 +513,45 @@ static void test_synthesized(void) static CRITICAL_SECTION clipboard_cs; static HWND next_wnd; +static UINT wm_drawclipboard; +static UINT wm_clipboardupdate; +static UINT wm_destroyclipboard; +static UINT nb_formats; +static BOOL cross_thread; + static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { - static UINT wm_drawclipboard; - static UINT wm_clipboardupdate; - static UINT wm_destroyclipboard; - static UINT nb_formats; LRESULT ret; + DWORD msg_flags = InSendMessageEx( NULL ); switch(msg) { case WM_DRAWCLIPBOARD: + ok( msg_flags == (cross_thread ? ISMEX_NOTIFY : ISMEX_NOSEND), + "WM_DRAWCLIPBOARD wrong flags %x\n", msg_flags ); EnterCriticalSection(&clipboard_cs); wm_drawclipboard++; LeaveCriticalSection(&clipboard_cs); break; case WM_CHANGECBCHAIN: + ok( msg_flags == (cross_thread ? ISMEX_SEND : ISMEX_NOSEND), + "WM_CHANGECBCHAIN wrong flags %x\n", msg_flags ); if (next_wnd == (HWND)wp) next_wnd = (HWND)lp; else if (next_wnd) SendMessageA(next_wnd, msg, wp, lp); break; case WM_DESTROYCLIPBOARD: + ok( msg_flags == (cross_thread ? ISMEX_SEND : ISMEX_NOSEND), + "WM_DESTROYCLIPBOARD wrong flags %x\n", msg_flags ); wm_destroyclipboard++; ok( GetClipboardOwner() == hwnd, "WM_DESTROYCLIPBOARD owner %p\n", GetClipboardOwner() ); nb_formats = CountClipboardFormats(); break; case WM_CLIPBOARDUPDATE: + ok( msg_flags == ISMEX_NOSEND, "WM_CLIPBOARDUPDATE wrong flags %x\n", msg_flags ); + EnterCriticalSection(&clipboard_cs); wm_clipboardupdate++; + LeaveCriticalSection(&clipboard_cs); break; case WM_USER: ChangeClipboardChain(hwnd, next_wnd); @@ -568,9 +580,13 @@ static DWORD WINAPI clipboard_thread(void *param) { HWND ret, win = param; BOOL r; + MSG msg; HANDLE handle; UINT count, formats, old_seq = 0, seq; + cross_thread = (GetWindowThreadProcessId( win, NULL ) != GetCurrentThreadId()); + trace( "%s-threaded test\n", cross_thread ? "multi" : "single" ); + if (pGetClipboardSequenceNumber) old_seq = pGetClipboardSequenceNumber(); EnterCriticalSection(&clipboard_cs); @@ -615,8 +631,14 @@ static DWORD WINAPI clipboard_thread(void *param) seq = pGetClipboardSequenceNumber(); ok( seq == old_seq, "sequence changed\n" ); } + if (!cross_thread) + { + ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER + 1, 0, 0 ); - ok( count, "WM_DRAWCLIPBOARD received\n" ); + ok( count == 1, "WM_DRAWCLIPBOARD not received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); ok( !count, "WM_CLIPBOARDUPDATE received\n" ); @@ -633,6 +655,12 @@ static DWORD WINAPI clipboard_thread(void *param) seq = pGetClipboardSequenceNumber(); ok( seq == old_seq, "sequence changed\n" ); } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); @@ -647,6 +675,12 @@ static DWORD WINAPI clipboard_thread(void *param) ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); @@ -663,6 +697,12 @@ static DWORD WINAPI clipboard_thread(void *param) ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); @@ -681,6 +721,12 @@ static DWORD WINAPI clipboard_thread(void *param) todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); @@ -694,6 +740,12 @@ static DWORD WINAPI clipboard_thread(void *param) todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); @@ -707,6 +759,12 @@ static DWORD WINAPI clipboard_thread(void *param) todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); @@ -723,10 +781,16 @@ static DWORD WINAPI clipboard_thread(void *param) ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); - ok( count, "WM_DRAWCLIPBOARD not received\n" ); + ok( count == 1, "WM_DRAWCLIPBOARD not received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); - todo_wine ok( count || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); + ok( count == 1 || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); r = OpenClipboard(win); ok(r, "OpenClipboard failed: %d\n", GetLastError()); @@ -736,6 +800,11 @@ static DWORD WINAPI clipboard_thread(void *param) seq = pGetClipboardSequenceNumber(); ok( seq == old_seq, "sequence changed\n" ); } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); @@ -748,6 +817,12 @@ static DWORD WINAPI clipboard_thread(void *param) todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); @@ -762,10 +837,16 @@ static DWORD WINAPI clipboard_thread(void *param) todo_wine ok( seq == old_seq, "sequence changed\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); - ok( count, "WM_DRAWCLIPBOARD not received\n" ); + ok( count == 1, "WM_DRAWCLIPBOARD not received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); - todo_wine ok( count || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); + ok( count == 1 || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); r = OpenClipboard(win); ok(r, "OpenClipboard failed: %d\n", GetLastError()); @@ -777,6 +858,12 @@ static DWORD WINAPI clipboard_thread(void *param) seq = pGetClipboardSequenceNumber(); ok( seq == old_seq, "sequence changed\n" ); } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); @@ -792,12 +879,18 @@ static DWORD WINAPI clipboard_thread(void *param) r = CloseClipboard(); ok(r, "CloseClipboard failed: %d\n", GetLastError()); + if (!cross_thread) + { + ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); - ok( count, "WM_DRAWCLIPBOARD not received\n" ); + ok( count == 1, "WM_DRAWCLIPBOARD not received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); - todo_wine ok( count || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); + ok( count == 1 || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); count = SendMessageA( win, WM_USER+3, 0, 0 ); - ok( count, "WM_DESTROYCLIPBOARD not received\n" ); + ok( count == 1, "WM_DESTROYCLIPBOARD not received\n" ); count = SendMessageA( win, WM_USER+4, 0, 0 ); ok( count == formats, "wrong format count %u on WM_DESTROYCLIPBOARD\n", count ); @@ -810,6 +903,14 @@ static DWORD WINAPI clipboard_thread(void *param) ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } + count = SendMessageA( win, WM_USER+1, 0, 0 ); + ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); ok( !count, "WM_CLIPBOARDUPDATE received\n" ); count = SendMessageA( win, WM_USER+3, 0, 0 ); @@ -826,10 +927,16 @@ static DWORD WINAPI clipboard_thread(void *param) todo_wine ok( seq == old_seq, "sequence changed\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); - ok( count, "WM_DRAWCLIPBOARD not received\n" ); + ok( count == 1, "WM_DRAWCLIPBOARD not received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); - todo_wine ok( count || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); + ok( count == 1 || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); run_process( "grab_clipboard 0" ); @@ -839,10 +946,19 @@ static DWORD WINAPI clipboard_thread(void *param) ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + /* in this case we get a cross-thread WM_DRAWCLIPBOARD */ + cross_thread = TRUE; + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + cross_thread = FALSE; + } count = SendMessageA( win, WM_USER+1, 0, 0 ); - todo_wine ok( count, "WM_DRAWCLIPBOARD not received\n" ); + ok( count == 1, "WM_DRAWCLIPBOARD not received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); - todo_wine ok( count || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); + ok( count == 1 || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); r = OpenClipboard(0); ok(r, "OpenClipboard failed: %d\n", GetLastError()); @@ -853,6 +969,12 @@ static DWORD WINAPI clipboard_thread(void *param) todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); @@ -869,10 +991,16 @@ static DWORD WINAPI clipboard_thread(void *param) todo_wine ok( seq == old_seq, "sequence changed\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); - ok( count, "WM_DRAWCLIPBOARD not received\n" ); + ok( count == 1, "WM_DRAWCLIPBOARD not received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); - todo_wine ok( count || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); + ok( count == 1 || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); run_process( "grab_clipboard 1" ); @@ -882,10 +1010,19 @@ static DWORD WINAPI clipboard_thread(void *param) ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + /* in this case we get a cross-thread WM_DRAWCLIPBOARD */ + cross_thread = TRUE; + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + cross_thread = FALSE; + } count = SendMessageA( win, WM_USER+1, 0, 0 ); - todo_wine ok( count, "WM_DRAWCLIPBOARD not received\n" ); + ok( count == 1, "WM_DRAWCLIPBOARD not received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); - todo_wine ok( count || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); + ok( count == 1 || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); r = OpenClipboard(0); ok(r, "OpenClipboard failed: %d\n", GetLastError()); @@ -896,6 +1033,12 @@ static DWORD WINAPI clipboard_thread(void *param) todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( !wm_drawclipboard, "WM_DRAWCLIPBOARD received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); ok( !count, "WM_DRAWCLIPBOARD received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); @@ -912,10 +1055,16 @@ static DWORD WINAPI clipboard_thread(void *param) todo_wine ok( seq == old_seq, "sequence changed\n" ); old_seq = seq; } + if (!cross_thread) + { + ok( wm_drawclipboard == 1, "WM_DRAWCLIPBOARD not received\n" ); + ok( !wm_clipboardupdate, "WM_CLIPBOARDUPDATE received\n" ); + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + } count = SendMessageA( win, WM_USER+1, 0, 0 ); - ok( count, "WM_DRAWCLIPBOARD not received\n" ); + ok( count == 1, "WM_DRAWCLIPBOARD not received\n" ); count = SendMessageA( win, WM_USER+2, 0, 0 ); - todo_wine ok( count || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); + ok( count == 1 || broken(!pAddClipboardFormatListener), "WM_CLIPBOARDUPDATE not received\n" ); r = PostMessageA(win, WM_USER, 0, 0); ok(r, "PostMessage failed: %d\n", GetLastError()); @@ -958,7 +1107,9 @@ static void test_messages(void) thread = CreateThread(NULL, 0, clipboard_thread, (void*)win, 0, &tid); ok(thread != NULL, "CreateThread failed: %d\n", GetLastError()); - while(GetMessageA(&msg, NULL, 0, 0)) { + while(GetMessageA(&msg, NULL, 0, 0)) + { + ok( msg.message != WM_DRAWCLIPBOARD, "WM_DRAWCLIPBOARD was posted\n" ); TranslateMessage(&msg); DispatchMessageA(&msg); } @@ -966,6 +1117,16 @@ static void test_messages(void) ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(thread); + DestroyWindow( win ); + + /* same tests again but inside a single thread */ + + win = CreateWindowA( "clipboard_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 ); + ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() ); + + clipboard_thread( win ); + DestroyWindow( win ); + UnregisterClassA("clipboard_test", GetModuleHandleA(NULL)); DeleteCriticalSection(&clipboard_cs); } diff --git a/server/clipboard.c b/server/clipboard.c index 8396ec35cbc..f640b50a6ad 100644 --- a/server/clipboard.c +++ b/server/clipboard.c @@ -45,6 +45,7 @@ struct clipboard user_handle_t owner_win; /* window that owns the clipboard data */ user_handle_t viewer; /* first window in clipboard viewer list */ unsigned int seqno; /* clipboard change sequence number */ + unsigned int open_seqno; /* sequence number at open time */ timeout_t seqno_timestamp; /* time stamp of last seqno increment */ unsigned int listen_size; /* size of listeners array */ unsigned int listen_count; /* count of listeners */ @@ -167,6 +168,21 @@ static int remove_listener( struct clipboard *clipboard, user_handle_t window ) return 0; } +/* close the clipboard, and return the viewer window that should be notified if any */ +static user_handle_t close_clipboard( struct clipboard *clipboard ) +{ + unsigned int i; + + clipboard->open_win = 0; + clipboard->open_thread = NULL; + + if (clipboard->seqno == clipboard->open_seqno) return 0; /* unchanged */ + + for (i = 0; i < clipboard->listen_count; i++) + post_message( clipboard->listeners[i], WM_CLIPBOARDUPDATE, 0, 0 ); + return clipboard->viewer; +} + /* cleanup clipboard information upon window destruction */ void cleanup_clipboard_window( struct desktop *desktop, user_handle_t window ) { @@ -174,18 +190,18 @@ void cleanup_clipboard_window( struct desktop *desktop, user_handle_t window ) if (!clipboard) return; - if (clipboard->open_win == window) - { - clipboard->open_win = 0; - clipboard->open_thread = NULL; - } + 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->viewer == window) clipboard->viewer = 0; - remove_listener( clipboard, window ); + if (clipboard->open_win == window) + { + user_handle_t viewer = close_clipboard( clipboard ); + if (viewer) send_notify_message( viewer, WM_DRAWCLIPBOARD, clipboard->owner_win, 0 ); + } } /* Called when thread terminates to allow release of clipboard */ @@ -199,16 +215,16 @@ void cleanup_clipboard_thread(struct thread *thread) if ((clipboard = winstation->clipboard)) { - if (thread == clipboard->open_thread) - { - clipboard->open_win = 0; - clipboard->open_thread = NULL; - } if (thread == clipboard->owner_thread) { clipboard->owner_win = 0; clipboard->owner_thread = NULL; } + if (thread == clipboard->open_thread) + { + user_handle_t viewer = close_clipboard( clipboard ); + if (viewer) send_notify_message( viewer, WM_DRAWCLIPBOARD, clipboard->owner_win, 0 ); + } } release_object( winstation ); } @@ -256,6 +272,8 @@ DECL_HANDLER(open_clipboard) set_error( STATUS_INVALID_LOCK_SEQUENCE ); return; } + + if (!clipboard->open_thread) clipboard->open_seqno = clipboard->seqno; /* first open */ clipboard->open_win = win; clipboard->open_thread = current; @@ -276,10 +294,8 @@ DECL_HANDLER(close_clipboard) return; } if (req->changed) clipboard->seqno++; - clipboard->open_thread = NULL; - clipboard->open_win = 0; - reply->viewer = clipboard->viewer; + reply->viewer = close_clipboard( clipboard ); reply->owner = (clipboard->owner_thread && clipboard->owner_thread->process == current->process); } diff --git a/server/queue.c b/server/queue.c index f82060fe9d6..387c652a317 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2112,6 +2112,33 @@ void post_message( user_handle_t win, unsigned int message, lparam_t wparam, lpa release_object( thread ); } +/* send a notify message to a window */ +void send_notify_message( user_handle_t win, unsigned int message, lparam_t wparam, lparam_t lparam ) +{ + struct message *msg; + struct thread *thread = get_window_thread( win ); + + if (!thread) return; + + if (thread->queue && (msg = mem_alloc( sizeof(*msg) ))) + { + msg->type = MSG_NOTIFY; + msg->win = get_user_full_handle( win ); + msg->msg = message; + msg->wparam = wparam; + msg->lparam = lparam; + msg->result = NULL; + msg->data = NULL; + msg->data_size = 0; + + get_message_defaults( thread->queue, &msg->x, &msg->y, &msg->time ); + + list_add_tail( &thread->queue->msg_list[SEND_MESSAGE], &msg->entry ); + set_queue_bits( thread->queue, QS_SENDMESSAGE ); + } + release_object( thread ); +} + /* post a win event */ void post_win_event( struct thread *thread, unsigned int event, user_handle_t win, unsigned int object_id, diff --git a/server/user.h b/server/user.h index 2f706747b65..ad62b7d7873 100644 --- a/server/user.h +++ b/server/user.h @@ -112,6 +112,8 @@ extern int attach_thread_input( struct thread *thread_from, struct thread *threa extern void detach_thread_input( struct thread *thread_from ); extern void post_message( user_handle_t win, unsigned int message, lparam_t wparam, lparam_t lparam ); +extern void send_notify_message( user_handle_t win, unsigned int message, + lparam_t wparam, lparam_t lparam ); extern void post_win_event( struct thread *thread, unsigned int event, user_handle_t win, unsigned int object_id, unsigned int child_id, client_ptr_t proc,