Anything wrong with this patch? I'm guessing its the Sleep(). Any
other way to force X server to put expose events in the queue, if any?
This is for bug #9875.
Clinton Stimpson
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c
index 49fe766..0d369c8 100644
--- a/dlls/user32/tests/win.c
+++ b/dlls/user32/tests/win.c
@@ -4324,6 +4324,123 @@ static void test_GetUpdateRect(void)
DestroyWindow(hgrandparent);
}
+/* Would like to call XSync() instead of waiting.
+ * But we need to wait for the X server to catch up
+ * so expose events will be in the queue when we want them */
+static int WaitForXServerTime = 500;
+
+static DWORD WINAPI Async_GetUpdateRect_Thread(void* data)
+{
+ HWND win2;
+ win2 = CreateWindowA("static", "win2", WS_VISIBLE, 10,10,50,50, NULL, NULL,
+0, NULL);
+ UpdateWindow(win2);
+ DestroyWindow(win2);
+ return 0;
+}
+
+static LRESULT CALLBACK Async_GetUpdateRect_WndProc(
+ HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if(msg == WM_PAINT)
+ {
+ PAINTSTRUCT ps;
+ RECT updateRect;
+ HANDLE thread;
+ DWORD threadId;
+ HWND* child;
+ BeginPaint(hwnd, &ps);
+ TextOutA(ps.hdc, 0, 0, "Hello World", 11);
+
+ /* on another thread, create window that comes and goes,
+ * while in the middle of painting this window */
+ thread = CreateThread(NULL, 0, Async_GetUpdateRect_Thread, NULL, 0, &threadId);
+ WaitForSingleObject(thread, INFINITE);
+ CloseHandle(thread);
+
+ child = (HWND*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ UpdateWindow(*child);
+ ValidateRect(hwnd, NULL);
+ EndPaint(hwnd, &ps);
+
+ Sleep(WaitForXServerTime);
+ MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_PAINT, 0 );
+
+ /* pending expose events should not be processed in
+ * RedrawWindow() while painting this window */
+ /* but they should be processed in GetUpdateRect so we should get
+ * something here */
+ GetUpdateRect(hwnd, &updateRect, FALSE);
+todo_wine {
+ ok(!IsRectEmpty(&updateRect), "Update Rect is not supposed to be empty.\n");
+}
+ return 1;
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+static void test_Async_GetUpdateRect(void)
+{
+ /* check if the window system gives expose events (X11 on Mac doesn't) */
+ HWND win1, win2, child;
+ RECT rect1, rect2;
+ win1 = CreateWindowA("static", "win1", WS_VISIBLE|WS_OVERLAPPEDWINDOW,
+ 0,0,200,200, NULL, NULL, 0, NULL);
+ UpdateWindow(win1);
+ win2 = CreateWindowA("static", "win2", WS_VISIBLE|WS_OVERLAPPEDWINDOW,
+ 10,10,100,100, NULL, NULL, 0, NULL);
+ UpdateWindow(win2);
+ DestroyWindow(win2);
+ Sleep(WaitForXServerTime);
+ /* GetUpdateRect should process expose events, if any */
+ GetUpdateRect(win1, &rect1, FALSE);
+ MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_PAINT, 0 );
+ GetUpdateRect(win1, &rect2, FALSE);
+ DestroyWindow(win1);
+ if(!IsRectEmpty(&rect1) || !IsRectEmpty(&rect2))
+ {
+ /* if we get here, window system does give expose events */
+ ATOM atom;
+ WNDCLASSA cls;
+ HANDLE thread;
+ DWORD threadId;
+
+todo_wine {
+ ok(IsRectEmpty(&rect1) == IsRectEmpty(&rect2), "rects should be equal\n");
+}
+
+ memset(&cls, 0, sizeof(WNDCLASSA));
+ cls.lpfnWndProc = Async_GetUpdateRect_WndProc;
+ cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+ cls.lpszClassName = "AsyncGetUpdateRectClass";
+ atom = RegisterClassA(&cls);
+
+ /* verify that RedrawWindow will deal with newly exposed area */
+ win1 = CreateWindowA("static", "win1", WS_VISIBLE|WS_OVERLAPPEDWINDOW,
+ 0,0,200,200, NULL, NULL, 0, NULL);
+ UpdateWindow(win1);
+ /* on another thread, create window that comes and goes */
+ thread = CreateThread(NULL, 0, Async_GetUpdateRect_Thread, NULL, 0, &threadId);
+ WaitForSingleObject(thread, INFINITE);
+ CloseHandle(thread);
+ Sleep(WaitForXServerTime);
+ UpdateWindow(win1);
+ GetUpdateRect(win1, &rect1, FALSE);
+ ok(IsRectEmpty(&rect1), "rect should be empty\n");
+ DestroyWindow(win1);
+
+ /* check when/how exposed regions are handled in the middle of painting */
+ win1 = CreateWindowA("AsyncGetUpdateRectClass", "win1", WS_VISIBLE,
+ 0,0,200,200, NULL, NULL, 0, NULL);
+ child = CreateWindowA("static", "child", WS_VISIBLE|WS_CHILD,
+ 10, 10, 20, 20, win1, NULL, 0, NULL);
+ SetWindowLongPtr(win1, GWLP_USERDATA, (LONG_PTR)&child);
+ UpdateWindow(win1);
+ DestroyWindow(win1);
+ }
+
+}
+
START_TEST(win)
{
pGetAncestor = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetAncestor" );
@@ -4403,6 +4520,7 @@ START_TEST(win)
test_ShowWindow();
test_gettext();
test_GetUpdateRect();
+ test_Async_GetUpdateRect();
/* add the tests above this line */
UnhookWindowsHookEx(hhook);