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.
This commit is contained in:
Alexandre Julliard 2005-05-31 13:37:16 +00:00
parent ec3cf77d65
commit db412aaf60
5 changed files with 113 additions and 54 deletions

View File

@ -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;
}
}

View File

@ -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 */

View File

@ -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) */

View File

@ -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 );
}

View File

@ -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;