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:
parent
ec3cf77d65
commit
db412aaf60
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
131
server/window.c
131
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;
|
||||
|
|
Loading…
Reference in New Issue