diff --git a/dlls/user32/painting.c b/dlls/user32/painting.c index 22dd6c27ec..9ba4a7a863 100644 --- a/dlls/user32/painting.c +++ b/dlls/user32/painting.c @@ -243,7 +243,7 @@ static HRGN send_ncpaint( HWND hwnd, HWND *child, UINT *flags ) static BOOL send_erase( HWND hwnd, UINT flags, HRGN client_rgn, RECT *clip_rect, HDC *hdc_ret ) { - BOOL need_erase = FALSE; + BOOL need_erase = (flags & UPDATE_DELAYED_ERASE) != 0; HDC hdc = 0; RECT dummy; @@ -263,12 +263,7 @@ static BOOL send_erase( HWND hwnd, UINT flags, HRGN client_rgn, if (type != NULLREGION) need_erase = !SendMessageW( hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0 ); } - if (!hdc_ret) - { - if (need_erase && hwnd != GetDesktopWindow()) /* FIXME: mark it as needing erase again */ - RedrawWindow( hwnd, clip_rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN ); - USER_Driver->pReleaseDC( hwnd, hdc, TRUE ); - } + if (!hdc_ret) USER_Driver->pReleaseDC( hwnd, hdc, TRUE ); } if (hdc_ret) *hdc_ret = hdc; @@ -287,6 +282,7 @@ void erase_now( HWND hwnd, UINT rdw_flags ) { HWND child = 0; HRGN hrgn; + BOOL need_erase = FALSE; /* loop while we find a child to repaint */ for (;;) @@ -295,12 +291,13 @@ void erase_now( HWND hwnd, UINT rdw_flags ) if (rdw_flags & RDW_NOCHILDREN) flags |= UPDATE_NOCHILDREN; else if (rdw_flags & RDW_ALLCHILDREN) flags |= UPDATE_ALLCHILDREN; + if (need_erase) flags |= UPDATE_DELAYED_ERASE; if (!(hrgn = send_ncpaint( hwnd, &child, &flags ))) break; - send_erase( child, flags, hrgn, NULL, NULL ); + need_erase = send_erase( child, flags, hrgn, NULL, NULL ); if (!flags) break; /* nothing more to do */ - if (rdw_flags & RDW_NOCHILDREN) break; + if ((rdw_flags & RDW_NOCHILDREN) && !need_erase) break; } } @@ -736,7 +733,11 @@ INT WINAPI GetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase ) POINT offset; retval = CombineRgn( hrgn, update_rgn, 0, RGN_COPY ); - send_erase( hwnd, flags, update_rgn, NULL, NULL ); + if (send_erase( hwnd, flags, update_rgn, NULL, NULL )) + { + flags = UPDATE_DELAYED_ERASE; + get_update_flags( hwnd, NULL, &flags ); + } /* map region to client coordinates */ offset.x = offset.y = 0; ScreenToClient( hwnd, &offset ); @@ -753,6 +754,7 @@ BOOL WINAPI GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase ) { UINT flags = UPDATE_NOCHILDREN; HRGN update_rgn; + BOOL need_erase; if (erase) flags |= UPDATE_NONCLIENT | UPDATE_ERASE; @@ -768,10 +770,11 @@ BOOL WINAPI GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase ) ReleaseDC( hwnd, hdc ); } } - send_erase( hwnd, flags, update_rgn, NULL, NULL ); + need_erase = send_erase( hwnd, flags, update_rgn, NULL, NULL ); /* check if we still have an update region */ flags = UPDATE_PAINT | UPDATE_NOCHILDREN; + if (need_erase) flags |= UPDATE_DELAYED_ERASE; return (get_update_flags( hwnd, NULL, &flags ) && (flags & UPDATE_PAINT)); } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index e0f7f8b06c..71d0709429 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -3073,6 +3073,7 @@ struct get_update_region_reply #define UPDATE_ALLCHILDREN 0x10 #define UPDATE_NOCHILDREN 0x20 #define UPDATE_NOREGION 0x40 +#define UPDATE_DELAYED_ERASE 0x80 @@ -4730,6 +4731,6 @@ union generic_reply struct make_process_system_reply make_process_system_reply; }; -#define SERVER_PROTOCOL_VERSION 309 +#define SERVER_PROTOCOL_VERSION 310 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index 6e13cb267f..aaf6c2ec83 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2256,6 +2256,7 @@ enum message_type #define UPDATE_ALLCHILDREN 0x10 /* force repaint of all children */ #define UPDATE_NOCHILDREN 0x20 /* don't try to repaint any children */ #define UPDATE_NOREGION 0x40 /* don't return a region, only the flags */ +#define UPDATE_DELAYED_ERASE 0x80 /* still needs erase after BeginPaint */ /* Update the z order of a window so that a given rectangle is fully visible */ diff --git a/server/window.c b/server/window.c index 8971dc6c97..14d646852e 100644 --- a/server/window.c +++ b/server/window.c @@ -88,9 +88,10 @@ struct window char extra_bytes[1]; /* extra bytes storage */ }; -#define PAINT_INTERNAL 0x01 /* internal WM_PAINT pending */ -#define PAINT_ERASE 0x02 /* needs WM_ERASEBKGND */ -#define PAINT_NONCLIENT 0x04 /* needs WM_NCPAINT */ +#define PAINT_INTERNAL 0x01 /* internal WM_PAINT pending */ +#define PAINT_ERASE 0x02 /* needs WM_ERASEBKGND */ +#define PAINT_NONCLIENT 0x04 /* needs WM_NCPAINT */ +#define PAINT_DELAYED_ERASE 0x08 /* still needs erase after WM_ERASEBKGND */ /* growable array of user handles */ struct user_handle_array @@ -978,7 +979,7 @@ static void set_update_region( struct window *win, struct region *region ) inc_window_paint_count( win, -1 ); free_region( win->update_region ); } - win->paint_flags &= ~(PAINT_ERASE | PAINT_NONCLIENT); + win->paint_flags &= ~(PAINT_ERASE | PAINT_DELAYED_ERASE | PAINT_NONCLIENT); win->update_region = NULL; if (region) free_region( region ); } @@ -1122,7 +1123,7 @@ static void redraw_window( struct window *win, struct region *region, int frame, set_update_region( win, tmp ); } if (flags & RDW_NOFRAME) validate_non_client( win ); - if (flags & RDW_NOERASE) win->paint_flags &= ~PAINT_ERASE; + if (flags & RDW_NOERASE) win->paint_flags &= ~(PAINT_ERASE | PAINT_DELAYED_ERASE); } } @@ -1178,11 +1179,19 @@ static unsigned int get_update_flags( struct window *win, unsigned int flags ) } if (flags & UPDATE_PAINT) { - if (win->update_region) ret |= UPDATE_PAINT; + if (win->update_region) + { + if (win->paint_flags & PAINT_DELAYED_ERASE) ret |= UPDATE_DELAYED_ERASE; + ret |= UPDATE_PAINT; + } } if (flags & UPDATE_INTERNALPAINT) { - if (win->paint_flags & PAINT_INTERNAL) ret |= UPDATE_INTERNALPAINT; + if (win->paint_flags & PAINT_INTERNAL) + { + ret |= UPDATE_INTERNALPAINT; + if (win->paint_flags & PAINT_DELAYED_ERASE) ret |= UPDATE_DELAYED_ERASE; + } } return ret; } @@ -1943,6 +1952,12 @@ DECL_HANDLER(get_update_region) } } + if (flags & UPDATE_DELAYED_ERASE) /* this means that the previous call didn't erase */ + { + if (from_child) from_child->paint_flags |= PAINT_DELAYED_ERASE; + else win->paint_flags |= PAINT_DELAYED_ERASE; + } + reply->flags = get_window_update_flags( win, from_child, flags, &win ); reply->child = win->handle; @@ -1975,7 +1990,7 @@ DECL_HANDLER(get_update_region) if (reply->flags & UPDATE_NONCLIENT) validate_non_client( win ); if (reply->flags & UPDATE_ERASE) { - win->paint_flags &= ~PAINT_ERASE; + win->paint_flags &= ~(PAINT_ERASE | PAINT_DELAYED_ERASE); /* desktop window only gets erased, not repainted */ if (is_desktop_window(win)) validate_whole_window( win ); }