From db412aaf60f999b76927d613ce221c69954fe40e Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 31 May 2005 13:37:16 +0000 Subject: [PATCH] Added a from_child parameter to the get_update_region request to allow restarting the search from a given child, in order to avoid looping forever on windows that don't repaint correctly. --- dlls/user/painting.c | 31 +++----- include/wine/server_protocol.h | 3 +- server/protocol.def | 1 + server/trace.c | 1 + server/window.c | 131 +++++++++++++++++++++++++-------- 5 files changed, 113 insertions(+), 54 deletions(-) diff --git a/dlls/user/painting.c b/dlls/user/painting.c index 927f886cebd..0169ada50e0 100644 --- a/dlls/user/painting.c +++ b/dlls/user/painting.c @@ -99,8 +99,9 @@ static HRGN get_update_region( HWND hwnd, UINT *flags, HWND *child ) SERVER_START_REQ( get_update_region ) { - req->window = hwnd; - req->flags = *flags; + req->window = hwnd; + req->from_child = child ? *child : 0; + req->flags = *flags; wine_server_set_reply( req, data->Buffer, size ); if (!(status = wine_server_call( req ))) { @@ -135,8 +136,9 @@ static BOOL get_update_flags( HWND hwnd, HWND *child, UINT *flags ) SERVER_START_REQ( get_update_region ) { - req->window = hwnd; - req->flags = *flags | UPDATE_NOREGION; + req->window = hwnd; + req->from_child = child ? *child : 0; + req->flags = *flags | UPDATE_NOREGION; if ((ret = !wine_server_call_err( req ))) { if (child) *child = reply->child; @@ -279,7 +281,7 @@ static BOOL send_erase( HWND hwnd, UINT flags, HRGN client_rgn, */ static void erase_now( HWND hwnd, UINT rdw_flags ) { - HWND child; + HWND child = 0; HRGN hrgn; /* loop while we find a child to repaint */ @@ -319,7 +321,7 @@ static void erase_now( HWND hwnd, UINT rdw_flags ) */ static void update_now( HWND hwnd, UINT rdw_flags ) { - HWND prev = 0, child; + HWND child = 0; /* desktop window never gets WM_PAINT, only WM_ERASEBKGND */ if (hwnd == GetDesktopWindow()) erase_now( hwnd, rdw_flags | RDW_NOCHILDREN ); @@ -335,22 +337,7 @@ static void update_now( HWND hwnd, UINT rdw_flags ) if (!get_update_flags( hwnd, &child, &flags )) break; if (!flags) break; /* nothing more to do */ - if (child == prev) /* same window again, didn't get repainted properly */ - { - UINT erase_flags = UPDATE_NONCLIENT | UPDATE_ERASE | UPDATE_NOCHILDREN; - HRGN hrgn; - - TRACE( "%p not repainted properly, erasing\n", child ); - if ((hrgn = send_ncpaint( child, NULL, &erase_flags ))) - send_erase( child, erase_flags, hrgn, NULL, NULL ); - - prev = 0; - } - else - { - prev = child; - SendMessageW( child, WM_PAINT, 0, 0 ); - } + SendMessageW( child, WM_PAINT, 0, 0 ); if (rdw_flags & RDW_NOCHILDREN) break; } } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index ddad0006897..9bd32744ab6 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2770,6 +2770,7 @@ struct get_update_region_request { struct request_header __header; user_handle_t window; + user_handle_t from_child; unsigned int flags; }; struct get_update_region_reply @@ -3997,6 +3998,6 @@ union generic_reply struct set_mailslot_info_reply set_mailslot_info_reply; }; -#define SERVER_PROTOCOL_VERSION 176 +#define SERVER_PROTOCOL_VERSION 177 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index bbf2213ed3b..b8281749fe3 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1953,6 +1953,7 @@ enum message_type /* Get the window update region */ @REQ(get_update_region) user_handle_t window; /* handle to the window */ + user_handle_t from_child; /* child to start searching from */ unsigned int flags; /* update flags (see below) */ @REPLY user_handle_t child; /* child to repaint (or window itself) */ diff --git a/server/trace.c b/server/trace.c index 87b4cfff2cf..d5fb96a988d 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2440,6 +2440,7 @@ static void dump_set_window_region_request( const struct set_window_region_reque static void dump_get_update_region_request( const struct get_update_region_request *req ) { fprintf( stderr, " window=%p,", req->window ); + fprintf( stderr, " from_child=%p,", req->from_child ); fprintf( stderr, " flags=%08x", req->flags ); } diff --git a/server/window.c b/server/window.c index f1133bae2e5..20775f27454 100644 --- a/server/window.c +++ b/server/window.c @@ -1046,35 +1046,110 @@ static unsigned int get_update_flags( struct window *win, unsigned int flags ) /* iterate through the children of the given window until we find one with some update flags */ -static unsigned int get_child_update_flags( struct window *win, unsigned int flags, - struct window **child ) +static unsigned int get_child_update_flags( struct window *win, struct window *from_child, + unsigned int flags, struct window **child ) { struct window *ptr; unsigned int ret = 0; + /* first make sure we want to iterate children at all */ + + if (win->style & WS_MINIMIZE) return 0; + + /* note: the WS_CLIPCHILDREN test is the opposite of the invalidation case, + * here we only want to repaint children of windows that clip them, others + * need to wait for WM_PAINT to be done in the parent first. + */ + if (!(flags & UPDATE_ALLCHILDREN) && !(win->style & WS_CLIPCHILDREN)) return 0; + LIST_FOR_EACH_ENTRY( ptr, &win->children, struct window, entry ) { + if (from_child) /* skip all children until from_child is found */ + { + if (ptr == from_child) from_child = NULL; + continue; + } if (!(ptr->style & WS_VISIBLE)) continue; if ((ret = get_update_flags( ptr, flags )) != 0) { *child = ptr; break; } - if (ptr->style & WS_MINIMIZE) continue; - - /* Note: the WS_CLIPCHILDREN test is the opposite of the invalidation case, - * here we only want to repaint children of windows that clip them, others - * need to wait for WM_PAINT to be done in the parent first. - */ - if (!(flags & UPDATE_NOCHILDREN) && - ((flags & UPDATE_ALLCHILDREN) || (ptr->style & WS_CLIPCHILDREN))) - { - if ((ret = get_child_update_flags( ptr, flags, child ))) break; - } + if ((ret = get_child_update_flags( ptr, NULL, flags, child ))) break; } return ret; } +/* iterate through children and siblings of the given window until we find one with some update flags */ +static unsigned int get_window_update_flags( struct window *win, struct window *from_child, + unsigned int flags, struct window **child ) +{ + unsigned int ret; + struct window *ptr, *from_sibling = NULL; + + /* if some parent is not visible start from the next sibling */ + + if (!is_visible( win )) return 0; + for (ptr = from_child; ptr && ptr != top_window; ptr = ptr->parent) + { + if (!(ptr->style & WS_VISIBLE) || (ptr->style & WS_MINIMIZE)) from_sibling = ptr; + if (ptr == win) break; + } + + /* non-client painting must be delayed if one of the parents is going to + * be repainted and doesn't clip children */ + + if ((flags & UPDATE_NONCLIENT) && !(flags & (UPDATE_PAINT|UPDATE_INTERNALPAINT))) + { + for (ptr = win->parent; ptr && ptr != top_window; ptr = ptr->parent) + { + if (!(ptr->style & WS_CLIPCHILDREN) && win_needs_repaint( ptr )) + return 0; + } + if (from_child && !(flags & UPDATE_ALLCHILDREN)) + { + for (ptr = from_sibling ? from_sibling : from_child; + ptr && ptr != top_window; ptr = ptr->parent) + { + if (!(ptr->style & WS_CLIPCHILDREN) && win_needs_repaint( ptr )) from_sibling = ptr; + if (ptr == win) break; + } + } + } + + + /* check window itself (only if not restarting from a child) */ + + if (!from_child) + { + if ((ret = get_update_flags( win, flags ))) + { + *child = win; + return ret; + } + from_child = win; + } + + /* now check children */ + + if (flags & UPDATE_NOCHILDREN) return 0; + if (!from_sibling) + { + if ((ret = get_child_update_flags( from_child, NULL, flags, child ))) return ret; + from_sibling = from_child; + } + + /* then check siblings and parent siblings */ + + while (from_sibling->parent && from_sibling != win) + { + if ((ret = get_child_update_flags( from_sibling->parent, from_sibling, flags, child ))) + return ret; + from_sibling = from_sibling->parent; + } + return 0; +} + /* expose a region of a window, looking for the top most parent that needs to be exposed */ /* the region is in window coordinates */ @@ -1667,35 +1742,29 @@ DECL_HANDLER(get_update_region) { rectangle_t *data; unsigned int flags = req->flags; + struct window *from_child = NULL; struct window *win = get_window( req->window ); reply->flags = 0; - if (!win || !is_visible( win )) return; + if (!win) return; - if ((flags & UPDATE_NONCLIENT) && !(flags & (UPDATE_PAINT|UPDATE_INTERNALPAINT))) + if (req->from_child) { - /* non-client painting must be delayed if one of the parents is going to - * be repainted and doesn't clip children */ struct window *ptr; - for (ptr = win->parent; ptr && ptr != top_window; ptr = ptr->parent) + if (!(from_child = get_window( req->from_child ))) return; + + /* make sure from_child is a child of win */ + ptr = from_child; + while (ptr && ptr != win) ptr = ptr->parent; + if (!ptr) { - if (!(ptr->style & WS_CLIPCHILDREN) && win_needs_repaint( ptr )) - return; - } - } - - if (!(reply->flags = get_update_flags( win, flags ))) - { - /* if window doesn't need any repaint, check the children */ - if (!(flags & UPDATE_NOCHILDREN) && - ((flags & UPDATE_ALLCHILDREN) || (win->style & WS_CLIPCHILDREN)) && - !(win->style & WS_MINIMIZE)) - { - reply->flags = get_child_update_flags( win, flags, &win ); + set_error( STATUS_INVALID_PARAMETER ); + return; } } + reply->flags = get_window_update_flags( win, from_child, flags, &win ); reply->child = win->handle; if (flags & UPDATE_NOREGION) return;