"Ann and Jason Edmeades" us@the-edmeades.demon.co.uk writes:
Index: painting.c
RCS file: /home/wine/wine/dlls/user/painting.c,v retrieving revision 1.29 diff -u -r1.29 painting.c --- painting.c 13 May 2005 14:03:06 -0000 1.29 +++ painting.c 20 May 2005 20:26:24 -0000 @@ -344,7 +344,7 @@ if ((hrgn = send_ncpaint( child, NULL, &erase_flags ))) send_erase( child, erase_flags, hrgn, NULL, NULL );
prev = 0;
break;
The problem is that this will cause children to be skipped too. What you really need is to repaint every window only once, but still recurse for children. Unfortunately that's a bit tricky to do with a stateless interface...
if ((hrgn = send_ncpaint( child, NULL, &erase_flags ))) send_erase( child, erase_flags, hrgn, NULL, NULL );
prev = 0;
break;
The problem is that this will cause children to be skipped too. What you really need is to repaint every window only once, but still recurse for children. Unfortunately that's a bit tricky to do with a stateless interface...
Now you tell me :-)
What about instead of the send_ncpaind/send_erase when child==prev (assuming this to be the more 'unusual' case and not the norm) I build a list of the hwnds and validate their update region. When the loop completes, for each hwnd left in the list I do the send_ncpaint/send_erase processing?
Without removing the update region there's no way to step further in the list, if I understand the problem correctly?
Jason
"Ann and Jason Edmeades" us@the-edmeades.demon.co.uk writes:
What about instead of the send_ncpaind/send_erase when child==prev (assuming this to be the more 'unusual' case and not the norm) I build a list of the hwnds and validate their update region. When the loop completes, for each hwnd left in the list I do the send_ncpaint/send_erase processing?
Without removing the update region there's no way to step further in the list, if I understand the problem correctly?
Yes, but that's what needs to be fixed, we need to make progress even if the update region is not validated. We will then get a WM_PAINT in the main message loop, which I believe is what we want.
Alexandre Julliard julliard@winehq.org writes:
"Ann and Jason Edmeades" us@the-edmeades.demon.co.uk writes:
What about instead of the send_ncpaind/send_erase when child==prev (assuming this to be the more 'unusual' case and not the norm) I build a list of the hwnds and validate their update region. When the loop completes, for each hwnd left in the list I do the send_ncpaint/send_erase processing?
Without removing the update region there's no way to step further in the list, if I understand the problem correctly?
Yes, but that's what needs to be fixed, we need to make progress even if the update region is not validated. We will then get a WM_PAINT in the main message loop, which I believe is what we want.
Try something like this:
Index: dlls/user/painting.c =================================================================== RCS file: /opt/cvs-commit/wine/dlls/user/painting.c,v retrieving revision 1.29 diff -u -p -r1.29 painting.c --- dlls/user/painting.c 13 May 2005 14:03:06 -0000 1.29 +++ dlls/user/painting.c 26 May 2005 19:56:42 -0000 @@ -99,8 +99,9 @@ static HRGN get_update_region( HWND hwnd
SERVER_START_REQ( get_update_region ) { - req->window = hwnd; - req->flags = *flags; + req->window = hwnd; + req->from_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,
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; @@ -319,7 +321,7 @@ static void erase_now( HWND hwnd, UINT r */ 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 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; } } Index: server/protocol.def =================================================================== RCS file: /opt/cvs-commit/wine/server/protocol.def,v retrieving revision 1.138 diff -u -p -r1.138 protocol.def --- server/protocol.def 24 May 2005 12:32:18 -0000 1.138 +++ server/protocol.def 26 May 2005 19:57:30 -0000 @@ -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) */ Index: server/window.c =================================================================== RCS file: /opt/cvs-commit/wine/server/window.c,v retrieving revision 1.54 diff -u -p -r1.54 window.c --- server/window.c 26 May 2005 12:28:07 -0000 1.54 +++ server/window.c 26 May 2005 19:57:46 -0000 @@ -1046,33 +1046,72 @@ static unsigned int get_update_flags( st
/* 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; + if ((ret = get_child_update_flags( ptr, NULL, flags, child ))) break; + } + return ret; +}
- /* 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))) +/* 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; + + /* check window itself (only if not restarting from a child) */ + + if (!from_child) + { + if ((ret = get_update_flags( win, flags ))) { - if ((ret = get_child_update_flags( ptr, flags, child ))) break; + *child = win; + return ret; } + from_child = win; } - return ret; + + /* now check children */ + + if (flags & UPDATE_NOCHILDREN) return 0; + if ((ret = get_child_update_flags( from_child, NULL, flags, child ))) return ret; + + /* then check siblings and parent siblings */ + + while (from_child->parent && from_child != win) + { + if ((ret = get_child_update_flags( from_child->parent, from_child, flags, child ))) + return ret; + from_child = from_child->parent; + } + return 0; }
@@ -1667,11 +1706,28 @@ 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 (req->from_child) + { + struct window *ptr; + + 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) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + } + if ((flags & UPDATE_NONCLIENT) && !(flags & (UPDATE_PAINT|UPDATE_INTERNALPAINT))) { /* non-client painting must be delayed if one of the parents is going to @@ -1685,17 +1741,7 @@ DECL_HANDLER(get_update_region) } }
- 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 ); - } - } - + reply->flags = get_window_update_flags( win, from_child, flags, &win ); reply->child = win->handle;
if (flags & UPDATE_NOREGION) return;
Without removing the update region there's no way to step further in the list, if I understand the problem correctly?
Yes, but that's what needs to be fixed, we need to make progress even if the update region is not validated. We will then get a WM_PAINT in the main message loop, which I believe is what we want.
Try something like this:
(For reference you need to run tools/make_requests after applying the patch for compilation to work...)
Yes, that works fine for both the test case I sent (want me to submit standalond?), and UT2003. Its much simpler than what I had planned, because I wasn't going to change the server protocol!
Thanks for taking the time to look at this
Jason
On Thu, 26 May 2005 22:06:30 +0200, Alexandre Julliard wrote:
Alexandre Julliard julliard@winehq.org writes:
"Ann and Jason Edmeades" us@the-edmeades.demon.co.uk writes:
What about instead of the send_ncpaind/send_erase when child==prev (assuming this to be the more 'unusual' case and not the norm) I build a list of the hwnds and validate their update region. When the loop completes, for each hwnd left in the list I do the send_ncpaint/send_erase processing?
Without removing the update region there's no way to step further in the list, if I understand the problem correctly?
Yes, but that's what needs to be fixed, we need to make progress even if the update region is not validated. We will then get a WM_PAINT in the main message loop, which I believe is what we want.
Try something like this:
[snip patch]
Thanks for that! I just thought I'd mention that this also fixes problems with Transport Tycoon Deluxe, another game that had a blank window and put wine in an infinite loop since the changes from 2004-12-07. With this patch it works again, so it'd be great if this could make it into CVS soon.
Thanks again!