server: Notify all listeners when the contents of the clipboard have changed.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2016-08-30 16:33:04 +09:00
parent 7594afeb6c
commit c6f12bd9cc
5 changed files with 245 additions and 39 deletions

View File

@ -185,8 +185,8 @@ BOOL WINAPI CloseClipboard(void)
{ {
if (owner) USER_Driver->pEndClipboardUpdate(); if (owner) USER_Driver->pEndClipboardUpdate();
bCBHasChanged = FALSE; bCBHasChanged = FALSE;
if (viewer) SendNotifyMessageW(viewer, WM_DRAWCLIPBOARD, (WPARAM) GetClipboardOwner(), 0);
} }
if (viewer) SendNotifyMessageW( viewer, WM_DRAWCLIPBOARD, (WPARAM)GetClipboardOwner(), 0 );
return TRUE; return TRUE;
} }

View File

@ -513,33 +513,45 @@ static void test_synthesized(void)
static CRITICAL_SECTION clipboard_cs; static CRITICAL_SECTION clipboard_cs;
static HWND next_wnd; static HWND next_wnd;
static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
static UINT wm_drawclipboard; static UINT wm_drawclipboard;
static UINT wm_clipboardupdate; static UINT wm_clipboardupdate;
static UINT wm_destroyclipboard; static UINT wm_destroyclipboard;
static UINT nb_formats; static UINT nb_formats;
static BOOL cross_thread;
static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
LRESULT ret; LRESULT ret;
DWORD msg_flags = InSendMessageEx( NULL );
switch(msg) { switch(msg) {
case WM_DRAWCLIPBOARD: case WM_DRAWCLIPBOARD:
ok( msg_flags == (cross_thread ? ISMEX_NOTIFY : ISMEX_NOSEND),
"WM_DRAWCLIPBOARD wrong flags %x\n", msg_flags );
EnterCriticalSection(&clipboard_cs); EnterCriticalSection(&clipboard_cs);
wm_drawclipboard++; wm_drawclipboard++;
LeaveCriticalSection(&clipboard_cs); LeaveCriticalSection(&clipboard_cs);
break; break;
case WM_CHANGECBCHAIN: 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) if (next_wnd == (HWND)wp)
next_wnd = (HWND)lp; next_wnd = (HWND)lp;
else if (next_wnd) else if (next_wnd)
SendMessageA(next_wnd, msg, wp, lp); SendMessageA(next_wnd, msg, wp, lp);
break; break;
case WM_DESTROYCLIPBOARD: case WM_DESTROYCLIPBOARD:
ok( msg_flags == (cross_thread ? ISMEX_SEND : ISMEX_NOSEND),
"WM_DESTROYCLIPBOARD wrong flags %x\n", msg_flags );
wm_destroyclipboard++; wm_destroyclipboard++;
ok( GetClipboardOwner() == hwnd, "WM_DESTROYCLIPBOARD owner %p\n", GetClipboardOwner() ); ok( GetClipboardOwner() == hwnd, "WM_DESTROYCLIPBOARD owner %p\n", GetClipboardOwner() );
nb_formats = CountClipboardFormats(); nb_formats = CountClipboardFormats();
break; break;
case WM_CLIPBOARDUPDATE: case WM_CLIPBOARDUPDATE:
ok( msg_flags == ISMEX_NOSEND, "WM_CLIPBOARDUPDATE wrong flags %x\n", msg_flags );
EnterCriticalSection(&clipboard_cs);
wm_clipboardupdate++; wm_clipboardupdate++;
LeaveCriticalSection(&clipboard_cs);
break; break;
case WM_USER: case WM_USER:
ChangeClipboardChain(hwnd, next_wnd); ChangeClipboardChain(hwnd, next_wnd);
@ -568,9 +580,13 @@ static DWORD WINAPI clipboard_thread(void *param)
{ {
HWND ret, win = param; HWND ret, win = param;
BOOL r; BOOL r;
MSG msg;
HANDLE handle; HANDLE handle;
UINT count, formats, old_seq = 0, seq; 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(); if (pGetClipboardSequenceNumber) old_seq = pGetClipboardSequenceNumber();
EnterCriticalSection(&clipboard_cs); EnterCriticalSection(&clipboard_cs);
@ -615,8 +631,14 @@ static DWORD WINAPI clipboard_thread(void *param)
seq = pGetClipboardSequenceNumber(); seq = pGetClipboardSequenceNumber();
ok( seq == old_seq, "sequence changed\n" ); 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 ); 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 ); count = SendMessageA( win, WM_USER+2, 0, 0 );
ok( !count, "WM_CLIPBOARDUPDATE received\n" ); ok( !count, "WM_CLIPBOARDUPDATE received\n" );
@ -633,6 +655,12 @@ static DWORD WINAPI clipboard_thread(void *param)
seq = pGetClipboardSequenceNumber(); seq = pGetClipboardSequenceNumber();
ok( seq == old_seq, "sequence changed\n" ); 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 ); count = SendMessageA( win, WM_USER+1, 0, 0 );
ok( !count, "WM_DRAWCLIPBOARD received\n" ); ok( !count, "WM_DRAWCLIPBOARD received\n" );
count = SendMessageA( win, WM_USER+2, 0, 0 ); 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" ); ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" );
old_seq = seq; 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 ); count = SendMessageA( win, WM_USER+1, 0, 0 );
ok( !count, "WM_DRAWCLIPBOARD received\n" ); ok( !count, "WM_DRAWCLIPBOARD received\n" );
count = SendMessageA( win, WM_USER+2, 0, 0 ); 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" ); ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" );
old_seq = seq; 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 ); count = SendMessageA( win, WM_USER+1, 0, 0 );
ok( !count, "WM_DRAWCLIPBOARD received\n" ); ok( !count, "WM_DRAWCLIPBOARD received\n" );
count = SendMessageA( win, WM_USER+2, 0, 0 ); 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" ); todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" );
old_seq = seq; 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 ); count = SendMessageA( win, WM_USER+1, 0, 0 );
ok( !count, "WM_DRAWCLIPBOARD received\n" ); ok( !count, "WM_DRAWCLIPBOARD received\n" );
count = SendMessageA( win, WM_USER+2, 0, 0 ); 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" ); todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" );
old_seq = seq; 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 ); count = SendMessageA( win, WM_USER+1, 0, 0 );
ok( !count, "WM_DRAWCLIPBOARD received\n" ); ok( !count, "WM_DRAWCLIPBOARD received\n" );
count = SendMessageA( win, WM_USER+2, 0, 0 ); 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" ); todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" );
old_seq = seq; 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 ); count = SendMessageA( win, WM_USER+1, 0, 0 );
ok( !count, "WM_DRAWCLIPBOARD received\n" ); ok( !count, "WM_DRAWCLIPBOARD received\n" );
count = SendMessageA( win, WM_USER+2, 0, 0 ); 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" ); ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" );
old_seq = seq; 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 ); 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 ); 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); r = OpenClipboard(win);
ok(r, "OpenClipboard failed: %d\n", GetLastError()); ok(r, "OpenClipboard failed: %d\n", GetLastError());
@ -736,6 +800,11 @@ static DWORD WINAPI clipboard_thread(void *param)
seq = pGetClipboardSequenceNumber(); seq = pGetClipboardSequenceNumber();
ok( seq == old_seq, "sequence changed\n" ); 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 ); count = SendMessageA( win, WM_USER+1, 0, 0 );
ok( !count, "WM_DRAWCLIPBOARD received\n" ); ok( !count, "WM_DRAWCLIPBOARD received\n" );
count = SendMessageA( win, WM_USER+2, 0, 0 ); 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" ); todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" );
old_seq = seq; 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 ); count = SendMessageA( win, WM_USER+1, 0, 0 );
ok( !count, "WM_DRAWCLIPBOARD received\n" ); ok( !count, "WM_DRAWCLIPBOARD received\n" );
count = SendMessageA( win, WM_USER+2, 0, 0 ); 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" ); todo_wine ok( seq == old_seq, "sequence changed\n" );
old_seq = seq; 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 ); 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 ); 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); r = OpenClipboard(win);
ok(r, "OpenClipboard failed: %d\n", GetLastError()); ok(r, "OpenClipboard failed: %d\n", GetLastError());
@ -777,6 +858,12 @@ static DWORD WINAPI clipboard_thread(void *param)
seq = pGetClipboardSequenceNumber(); seq = pGetClipboardSequenceNumber();
ok( seq == old_seq, "sequence changed\n" ); 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 ); count = SendMessageA( win, WM_USER+1, 0, 0 );
ok( !count, "WM_DRAWCLIPBOARD received\n" ); ok( !count, "WM_DRAWCLIPBOARD received\n" );
count = SendMessageA( win, WM_USER+2, 0, 0 ); count = SendMessageA( win, WM_USER+2, 0, 0 );
@ -792,12 +879,18 @@ static DWORD WINAPI clipboard_thread(void *param)
r = CloseClipboard(); r = CloseClipboard();
ok(r, "CloseClipboard failed: %d\n", GetLastError()); 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 ); 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 ); 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 ); 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 ); count = SendMessageA( win, WM_USER+4, 0, 0 );
ok( count == formats, "wrong format count %u on WM_DESTROYCLIPBOARD\n", count ); 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" ); ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" );
old_seq = seq; 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 ); count = SendMessageA( win, WM_USER+2, 0, 0 );
ok( !count, "WM_CLIPBOARDUPDATE received\n" ); ok( !count, "WM_CLIPBOARDUPDATE received\n" );
count = SendMessageA( win, WM_USER+3, 0, 0 ); 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" ); todo_wine ok( seq == old_seq, "sequence changed\n" );
old_seq = seq; 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 ); 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 ); 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" ); 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" ); ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" );
old_seq = seq; 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 ); 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 ); 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); r = OpenClipboard(0);
ok(r, "OpenClipboard failed: %d\n", GetLastError()); 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" ); todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" );
old_seq = seq; 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 ); count = SendMessageA( win, WM_USER+1, 0, 0 );
ok( !count, "WM_DRAWCLIPBOARD received\n" ); ok( !count, "WM_DRAWCLIPBOARD received\n" );
count = SendMessageA( win, WM_USER+2, 0, 0 ); 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" ); todo_wine ok( seq == old_seq, "sequence changed\n" );
old_seq = seq; 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 ); 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 ); 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" ); 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" ); ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" );
old_seq = seq; 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 ); 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 ); 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); r = OpenClipboard(0);
ok(r, "OpenClipboard failed: %d\n", GetLastError()); 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" ); todo_wine ok( (int)(seq - old_seq) > 0, "sequence unchanged\n" );
old_seq = seq; 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 ); count = SendMessageA( win, WM_USER+1, 0, 0 );
ok( !count, "WM_DRAWCLIPBOARD received\n" ); ok( !count, "WM_DRAWCLIPBOARD received\n" );
count = SendMessageA( win, WM_USER+2, 0, 0 ); 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" ); todo_wine ok( seq == old_seq, "sequence changed\n" );
old_seq = seq; 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 ); 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 ); 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); r = PostMessageA(win, WM_USER, 0, 0);
ok(r, "PostMessage failed: %d\n", GetLastError()); 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); thread = CreateThread(NULL, 0, clipboard_thread, (void*)win, 0, &tid);
ok(thread != NULL, "CreateThread failed: %d\n", GetLastError()); 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); TranslateMessage(&msg);
DispatchMessageA(&msg); DispatchMessageA(&msg);
} }
@ -966,6 +1117,16 @@ static void test_messages(void)
ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
CloseHandle(thread); 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)); UnregisterClassA("clipboard_test", GetModuleHandleA(NULL));
DeleteCriticalSection(&clipboard_cs); DeleteCriticalSection(&clipboard_cs);
} }

View File

@ -45,6 +45,7 @@ struct clipboard
user_handle_t owner_win; /* window that owns the clipboard data */ user_handle_t owner_win; /* window that owns the clipboard data */
user_handle_t viewer; /* first window in clipboard viewer list */ user_handle_t viewer; /* first window in clipboard viewer list */
unsigned int seqno; /* clipboard change sequence number */ 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 */ timeout_t seqno_timestamp; /* time stamp of last seqno increment */
unsigned int listen_size; /* size of listeners array */ unsigned int listen_size; /* size of listeners array */
unsigned int listen_count; /* count of listeners */ unsigned int listen_count; /* count of listeners */
@ -167,6 +168,21 @@ static int remove_listener( struct clipboard *clipboard, user_handle_t window )
return 0; 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 */ /* 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 )
{ {
@ -174,18 +190,18 @@ void cleanup_clipboard_window( struct desktop *desktop, user_handle_t window )
if (!clipboard) return; if (!clipboard) return;
if (clipboard->open_win == window) remove_listener( clipboard, window );
{ if (clipboard->viewer == window) clipboard->viewer = 0;
clipboard->open_win = 0;
clipboard->open_thread = NULL;
}
if (clipboard->owner_win == window) if (clipboard->owner_win == window)
{ {
clipboard->owner_win = 0; clipboard->owner_win = 0;
clipboard->owner_thread = NULL; clipboard->owner_thread = NULL;
} }
if (clipboard->viewer == window) clipboard->viewer = 0; if (clipboard->open_win == window)
remove_listener( clipboard, 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 */ /* 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 ((clipboard = winstation->clipboard))
{ {
if (thread == clipboard->open_thread)
{
clipboard->open_win = 0;
clipboard->open_thread = NULL;
}
if (thread == clipboard->owner_thread) if (thread == clipboard->owner_thread)
{ {
clipboard->owner_win = 0; clipboard->owner_win = 0;
clipboard->owner_thread = NULL; 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 ); release_object( winstation );
} }
@ -256,6 +272,8 @@ DECL_HANDLER(open_clipboard)
set_error( STATUS_INVALID_LOCK_SEQUENCE ); set_error( STATUS_INVALID_LOCK_SEQUENCE );
return; return;
} }
if (!clipboard->open_thread) clipboard->open_seqno = clipboard->seqno; /* first open */
clipboard->open_win = win; clipboard->open_win = win;
clipboard->open_thread = current; clipboard->open_thread = current;
@ -276,10 +294,8 @@ DECL_HANDLER(close_clipboard)
return; return;
} }
if (req->changed) clipboard->seqno++; 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); reply->owner = (clipboard->owner_thread && clipboard->owner_thread->process == current->process);
} }

View File

@ -2112,6 +2112,33 @@ void post_message( user_handle_t win, unsigned int message, lparam_t wparam, lpa
release_object( thread ); 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 */ /* post a win event */
void post_win_event( struct thread *thread, unsigned int event, void post_win_event( struct thread *thread, unsigned int event,
user_handle_t win, unsigned int object_id, user_handle_t win, unsigned int object_id,

View File

@ -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 detach_thread_input( struct thread *thread_from );
extern void post_message( user_handle_t win, unsigned int message, extern void post_message( user_handle_t win, unsigned int message,
lparam_t wparam, lparam_t lparam ); 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, extern void post_win_event( struct thread *thread, unsigned int event,
user_handle_t win, unsigned int object_id, user_handle_t win, unsigned int object_id,
unsigned int child_id, client_ptr_t proc, unsigned int child_id, client_ptr_t proc,