From: Paul Gofman Subject: Re: [PATCH] winex11.drv: Redraw window on Expose event if window surface has no region set. Message-Id: <1e1db422-09c4-3576-c4d6-94bccc6ceb11@gmail.com> Date: Fri, 3 Apr 2020 15:45:16 +0300 In-Reply-To: <20200403123457.20981-1-gofmanp@gmail.com> References: <20200403123457.20981-1-gofmanp@gmail.com> I am attaching a standalone test program which reliably shows a problem that the patch is solving in case I enable virtual desktop. Without virtual desktop the problem in this test is either visible or not depending on window manager used. The similar problem can also be reproduced with, e. g., destroying window instead of moving it. On 4/3/20 15:34, Paul Gofman wrote: > Otherwise the window (partially) obscured by the other window sometimes fails > to update when the obscuring window is moved or destroyed. > > Signed-off-by: Paul Gofman > --- > dlls/winex11.drv/bitblt.c | 5 +++++ > dlls/winex11.drv/event.c | 1 + > 2 files changed, 6 insertions(+) > > diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c > index b530ba7ba6..ac430ef4c0 100644 > --- a/dlls/winex11.drv/bitblt.c > +++ b/dlls/winex11.drv/bitblt.c > @@ -2106,6 +2106,11 @@ HRGN expose_surface( struct window_surface *window_surface, const RECT *rect ) > region = 0; > } > } > + else > + { > + region = (HRGN)1; > + } > + > window_surface->funcs->unlock( window_surface ); > return region; > } > diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c > index 10d71c2cb4..6424790a62 100644 > --- a/dlls/winex11.drv/event.c > +++ b/dlls/winex11.drv/event.c > @@ -941,6 +941,7 @@ static BOOL X11DRV_Expose( HWND hwnd, XEvent *xev ) > { > surface_region = expose_surface( data->surface, &rect ); > if (!surface_region) flags = 0; > + else if(surface_region == (HRGN)1) surface_region = NULL; > else OffsetRgn( surface_region, data->whole_rect.left - data->client_rect.left, > data->whole_rect.top - data->client_rect.top ); > #include #include static const char *dbgstr_wm(UINT msg) { #define WN(a) {a, #a} static const struct { UINT msg; const char *s; } msgs[] = { WN(WM_NULL), WN(WM_CREATE), WN(WM_DESTROY), WN(WM_MOVE), WN(WM_SIZE), WN(WM_ACTIVATE), WN(WM_SETFOCUS), WN(WM_KILLFOCUS), WN(WM_ENABLE), WN(WM_SETREDRAW), WN(WM_SETTEXT), WN(WM_GETTEXT), WN(WM_GETTEXTLENGTH), WN(WM_PAINT), WN(WM_CLOSE), WN(WM_QUERYENDSESSION), WN(WM_QUIT), WN(WM_QUERYOPEN), WN(WM_ERASEBKGND), WN(WM_SYSCOLORCHANGE), WN(WM_ENDSESSION), WN(WM_SHOWWINDOW), WN(WM_WININICHANGE), WN(WM_SETTINGCHANGE), WN(WM_DEVMODECHANGE), WN(WM_ACTIVATEAPP), WN(WM_FONTCHANGE), WN(WM_TIMECHANGE), WN(WM_CANCELMODE), WN(WM_SETCURSOR), WN(WM_MOUSEACTIVATE), WN(WM_CHILDACTIVATE), WN(WM_QUEUESYNC), WN(WM_GETMINMAXINFO), WN(WM_PAINTICON), WN(WM_ICONERASEBKGND), WN(WM_NEXTDLGCTL), WN(WM_SPOOLERSTATUS), WN(WM_DRAWITEM), WN(WM_MEASUREITEM), WN(WM_DELETEITEM), WN(WM_VKEYTOITEM), WN(WM_CHARTOITEM), WN(WM_SETFONT), WN(WM_GETFONT), WN(WM_SETHOTKEY), WN(WM_GETHOTKEY), WN(WM_QUERYDRAGICON), WN(WM_COMPAREITEM), WN(WM_COMPACTING), WN(WM_WINDOWPOSCHANGING), WN(WM_WINDOWPOSCHANGED), WN(WM_POWER), WN(WM_COPYDATA), WN(WM_CANCELJOURNAL), WN(WM_NOTIFY), WN(WM_INPUTLANGCHANGEREQUEST), WN(WM_INPUTLANGCHANGE), WN(WM_TCARD), WN(WM_HELP), WN(WM_USERCHANGED), WN(WM_NOTIFYFORMAT), WN(WM_CONTEXTMENU), WN(WM_STYLECHANGING), WN(WM_STYLECHANGED), WN(WM_DISPLAYCHANGE), WN(WM_GETICON), WN(WM_SETICON), WN(WM_NCCREATE), WN(WM_NCDESTROY), WN(WM_NCCALCSIZE), WN(WM_NCHITTEST), WN(WM_NCPAINT), WN(WM_NCACTIVATE), WN(WM_GETDLGCODE), WN(WM_NCMOUSEMOVE), WN(WM_NCLBUTTONDOWN), WN(WM_NCLBUTTONUP), WN(WM_NCLBUTTONDBLCLK), WN(WM_NCRBUTTONDOWN), WN(WM_NCRBUTTONUP), WN(WM_NCRBUTTONDBLCLK), WN(WM_NCMBUTTONDOWN), WN(WM_NCMBUTTONUP), WN(WM_NCMBUTTONDBLCLK), WN(WM_KEYFIRST), WN(WM_KEYDOWN), WN(WM_KEYUP), WN(WM_CHAR), WN(WM_DEADCHAR), WN(WM_SYSKEYDOWN), WN(WM_SYSKEYUP), WN(WM_SYSCHAR), WN(WM_SYSDEADCHAR), WN(WM_KEYLAST), WN(WM_IME_STARTCOMPOSITION), WN(WM_IME_ENDCOMPOSITION), WN(WM_IME_COMPOSITION), WN(WM_IME_KEYLAST), WN(WM_INITDIALOG), WN(WM_COMMAND), WN(WM_SYSCOMMAND), WN(WM_TIMER), WN(WM_HSCROLL), WN(WM_VSCROLL), WN(WM_INITMENU), WN(WM_INITMENUPOPUP), WN(WM_MENUSELECT), WN(WM_MENUCHAR), WN(WM_ENTERIDLE), WN(WM_CTLCOLORMSGBOX), WN(WM_CTLCOLOREDIT), WN(WM_CTLCOLORLISTBOX), WN(WM_CTLCOLORBTN), WN(WM_CTLCOLORDLG), WN(WM_CTLCOLORSCROLLBAR), WN(WM_CTLCOLORSTATIC), WN(WM_MOUSEFIRST), WN(WM_MOUSEMOVE), WN(WM_LBUTTONDOWN), WN(WM_LBUTTONUP), WN(WM_LBUTTONDBLCLK), WN(WM_RBUTTONDOWN), WN(WM_RBUTTONUP), WN(WM_RBUTTONDBLCLK), WN(WM_MBUTTONDOWN), WN(WM_MBUTTONUP), WN(WM_MBUTTONDBLCLK), WN(WM_MOUSEWHEEL), WN(WM_PARENTNOTIFY), WN(WM_ENTERMENULOOP), WN(WM_EXITMENULOOP), WN(WM_NEXTMENU), WN(WM_SIZING), WN(WM_CAPTURECHANGED), WN(WM_MOVING), WN(WM_POWERBROADCAST), WN(WM_DEVICECHANGE), WN(WM_MDICREATE), WN(WM_MDIDESTROY), WN(WM_MDIACTIVATE), WN(WM_MDIRESTORE), WN(WM_MDINEXT), WN(WM_MDIMAXIMIZE), WN(WM_MDITILE), WN(WM_MDICASCADE), WN(WM_MDIICONARRANGE), WN(WM_MDIGETACTIVE), WN(WM_MDISETMENU), WN(WM_ENTERSIZEMOVE), WN(WM_EXITSIZEMOVE), WN(WM_DROPFILES), WN(WM_MDIREFRESHMENU), WN(WM_IME_SETCONTEXT), WN(WM_IME_NOTIFY), WN(WM_IME_CONTROL), WN(WM_IME_COMPOSITIONFULL), WN(WM_IME_SELECT), WN(WM_IME_CHAR), WN(WM_IME_KEYDOWN), WN(WM_IME_KEYUP), WN(WM_MOUSEHOVER), WN(WM_NCMOUSELEAVE), WN(WM_MOUSELEAVE), WN(WM_CUT), WN(WM_COPY), WN(WM_PASTE), WN(WM_CLEAR), WN(WM_UNDO), WN(WM_RENDERFORMAT), WN(WM_RENDERALLFORMATS), WN(WM_DESTROYCLIPBOARD), WN(WM_DRAWCLIPBOARD), WN(WM_PAINTCLIPBOARD), WN(WM_VSCROLLCLIPBOARD), WN(WM_SIZECLIPBOARD), WN(WM_ASKCBFORMATNAME), WN(WM_CHANGECBCHAIN), WN(WM_HSCROLLCLIPBOARD), WN(WM_QUERYNEWPALETTE), WN(WM_PALETTEISCHANGING), WN(WM_PALETTECHANGED), WN(WM_HOTKEY), WN(WM_PRINT), WN(WM_PRINTCLIENT), WN(WM_HANDHELDFIRST), WN(WM_HANDHELDLAST), WN(WM_PENWINFIRST), WN(WM_PENWINLAST), WN(WM_DDE_FIRST), WN(WM_DDE_INITIATE), WN(WM_DDE_TERMINATE), WN(WM_DDE_ADVISE), WN(WM_DDE_UNADVISE), WN(WM_DDE_ACK), WN(WM_DDE_DATA), WN(WM_DDE_REQUEST), WN(WM_DDE_POKE), WN(WM_DDE_EXECUTE), WN(WM_DDE_LAST), WN(WM_USER), WN(WM_APP), }; #undef WN static char unknown_s[64]; unsigned int i; for (i = 0; i < sizeof(msgs) / sizeof(*msgs); ++i) if (msgs[i].msg == msg) return msgs[i].s; sprintf(unknown_s, "UNKNOWN(%#x)", msg); return unknown_s; } static LRESULT CALLBACK TestWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { printf("%s: hwnd %p, msg %s, wParam %p, lParam %p.\n", __func__, hwnd, dbgstr_wm(msg), (void *)wParam, (void *)lParam); fflush(stdout); switch (msg) { case WM_PAINT: { PAINTSTRUCT ps; HBRUSH b; HDC hdc; RECT r; GetClientRect(hwnd, &r); ps.fErase = 0; hdc = BeginPaint(hwnd, &ps); printf("WM_PAINT rect (%ld,%ld)-(%ld,%ld).\n", ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom); b = CreateSolidBrush(RGB(0xff, 0, 0)); FillRect(hdc, &r, b); DeleteObject(b); EndPaint(hwnd, &ps); return 0; } } return DefWindowProcA(hwnd, msg, wParam, lParam); } static LRESULT CALLBACK TestParentWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { RECT r; printf("%s: hwnd %p, msg %s, wParam %p, lParam %p.\n", __func__, hwnd, dbgstr_wm(msg), (void *)wParam, (void *)lParam); fflush(stdout); switch(msg) { case WM_DESTROY: PostQuitMessage(0); break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc; HBRUSH b; GetClientRect(hwnd, &r); hdc = BeginPaint(hwnd, &ps); printf("WM_PAINT rect (%ld,%ld)-(%ld,%ld).\n", ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom); b = CreateSolidBrush(RGB(0, 0xff, 0)); FillRect(hdc, &r, b); DeleteObject(b); EndPaint(hwnd, &ps); return 0; } } return DefWindowProcA(hwnd, msg, wParam, lParam); } static void process_queue(BOOL wait) { MSG msg; while (wait ? GetMessage(&msg, NULL, 0, 0) : PeekMessage(&msg, NULL, 0, 0, TRUE)) DispatchMessage(&msg); } static void test_1(void) { HWND hwnd, parent; WNDCLASSA clsA; memset(&clsA, 0, sizeof(clsA)); clsA.style = 0; clsA.lpfnWndProc = TestWindowProc; clsA.cbClsExtra = 0; clsA.cbWndExtra = 0; clsA.hInstance = GetModuleHandleA(NULL); clsA.hIcon = 0; clsA.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); clsA.hbrBackground = GetStockObject(WHITE_BRUSH); clsA.lpszMenuName = NULL; clsA.lpszClassName = "Test class"; RegisterClassA(&clsA); memset(&clsA, 0, sizeof(clsA)); clsA.style = 0; clsA.lpfnWndProc = TestParentWindowProc; clsA.cbClsExtra = 0; clsA.cbWndExtra = 0; clsA.hInstance = GetModuleHandleA(NULL); clsA.hIcon = 0; clsA.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); clsA.hbrBackground = GetStockObject(BLACK_BRUSH); clsA.lpszMenuName = NULL; clsA.lpszClassName = "Test parent class"; RegisterClassA(&clsA); parent = CreateWindowExA(0, "Test parent class", "Test owner window", WS_OVERLAPPED, 0, 0, 640, 480, NULL, NULL, GetModuleHandleA(NULL), NULL); hwnd = CreateWindowExA(0, "Test class", "Test window", WS_POPUP, 50, 50, 100, 100, parent, NULL, GetModuleHandleA(NULL), NULL); ShowWindow(parent, SW_SHOW); ShowWindow(hwnd, SW_SHOW); process_queue(FALSE); Sleep(1000); process_queue(FALSE); printf("Moving window.\n"); MoveWindow(hwnd, 150, 150, 120, 120, TRUE); process_queue(FALSE); Sleep(1000); printf("Hiding window.\n"); ShowWindow(hwnd, SW_HIDE); process_queue(FALSE); Sleep(1000); printf("Destroying window.\n"); DestroyWindow(hwnd); process_queue(FALSE); Sleep(1000); } int main(int argc, char *argv[]) { test_1(); return 0; }