From eea706948afc60579e97330ab7dbd0db5fc17815 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 30 Mar 2005 17:11:46 +0000 Subject: [PATCH] The update region passed in WM_NCPAINT and the clipping region passed to GetDCEx have to be in screen coordinates. --- dlls/user/painting.c | 63 ++++++++++++++++++++----------------------- dlls/user/tests/dce.c | 20 +++++++------- dlls/x11drv/dce.c | 4 +++ server/window.c | 52 ++++++++++++++++++++++++----------- windows/nonclient.c | 20 +++++--------- 5 files changed, 85 insertions(+), 74 deletions(-) diff --git a/dlls/user/painting.c b/dlls/user/painting.c index 3aef4c0b14b..d39036ac636 100644 --- a/dlls/user/painting.c +++ b/dlls/user/painting.c @@ -80,7 +80,7 @@ static void dump_rdw_flags(UINT flags) /*********************************************************************** * get_update_region * - * Return update region for a window. + * Return update region (in screen coordinates) for a window. */ static HRGN get_update_region( HWND hwnd, UINT *flags, HWND *child ) { @@ -172,7 +172,7 @@ static BOOL redraw_window_rects( HWND hwnd, UINT flags, const RECT *rects, UINT /*********************************************************************** * send_ncpaint * - * Send a WM_NCPAINT message if needed, and return the resulting update region. + * Send a WM_NCPAINT message if needed, and return the resulting update region (in screen coords). * Helper for erase_now and BeginPaint. */ static HRGN send_ncpaint( HWND hwnd, HWND *child, UINT *flags ) @@ -186,18 +186,11 @@ static HRGN send_ncpaint( HWND hwnd, HWND *child, UINT *flags ) { RECT client, update; INT type; - WND *win = WIN_GetPtr( hwnd ); - - if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP) - { - DeleteObject( whole_rgn ); - return 0; - } /* check if update rgn overlaps with nonclient area */ type = GetRgnBox( whole_rgn, &update ); - client = win->rectClient; - OffsetRect( &client, -win->rectWindow.left, -win->rectWindow.top ); + GetClientRect( hwnd, &client ); + MapWindowPoints( hwnd, 0, (POINT *)&client, 2 ); if ((*flags & UPDATE_NONCLIENT) || update.left < client.left || update.top < client.top || @@ -207,12 +200,15 @@ static HRGN send_ncpaint( HWND hwnd, HWND *child, UINT *flags ) CombineRgn( client_rgn, client_rgn, whole_rgn, RGN_AND ); /* check if update rgn contains complete nonclient area */ - if (type == SIMPLEREGION && update.left == 0 && update.top == 0 && - update.right == win->rectWindow.right - win->rectWindow.left && - update.bottom == win->rectWindow.bottom - win->rectWindow.top) + if (type == SIMPLEREGION) { - DeleteObject( whole_rgn ); - whole_rgn = (HRGN)1; + RECT window; + GetWindowRect( hwnd, &window ); + if (EqualRect( &window, &update )) + { + DeleteObject( whole_rgn ); + whole_rgn = (HRGN)1; + } } } else @@ -220,10 +216,6 @@ static HRGN send_ncpaint( HWND hwnd, HWND *child, UINT *flags ) client_rgn = whole_rgn; whole_rgn = 0; } - /* map client region to client coordinates */ - OffsetRgn( client_rgn, win->rectWindow.left - win->rectClient.left, - win->rectWindow.top - win->rectClient.top ); - WIN_ReleasePtr( win ); if (whole_rgn) /* NOTE: WM_NCPAINT allows wParam to be 1 */ { @@ -247,7 +239,9 @@ static BOOL send_erase( HWND hwnd, UINT flags, HRGN client_rgn, { BOOL need_erase = FALSE; HDC hdc; + RECT dummy; + if (!clip_rect) clip_rect = &dummy; if (hdc_ret || (flags & UPDATE_ERASE)) { UINT dcx_flags = DCX_INTERSECTRGN | DCX_USESTYLE; @@ -266,7 +260,7 @@ static BOOL send_erase( HWND hwnd, UINT flags, HRGN client_rgn, if (!hdc_ret) { if (need_erase && hwnd != GetDesktopWindow()) /* FIXME: mark it as needing erase again */ - RedrawWindow( hwnd, NULL, client_rgn, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN ); + RedrawWindow( hwnd, clip_rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN ); ReleaseDC( hwnd, hdc ); } } @@ -290,14 +284,13 @@ static void erase_now( HWND hwnd, UINT rdw_flags ) /* loop while we find a child to repaint */ for (;;) { - RECT rect; UINT flags = UPDATE_NONCLIENT | UPDATE_ERASE; if (rdw_flags & RDW_NOCHILDREN) flags |= UPDATE_NOCHILDREN; else if (rdw_flags & RDW_ALLCHILDREN) flags |= UPDATE_ALLCHILDREN; if (!(hrgn = send_ncpaint( hwnd, &child, &flags ))) break; - send_erase( child, flags, hrgn, &rect, NULL ); + send_erase( child, flags, hrgn, NULL, NULL ); DeleteObject( hrgn ); if (!flags) break; /* nothing more to do */ @@ -349,12 +342,11 @@ static void update_now( HWND hwnd, UINT rdw_flags ) { UINT erase_flags = UPDATE_NONCLIENT | UPDATE_ERASE | UPDATE_NOCHILDREN; HRGN hrgn; - RECT rect; TRACE( "%p not repainted properly, erasing\n", child ); if ((hrgn = send_ncpaint( child, NULL, &erase_flags ))) { - send_erase( child, erase_flags, hrgn, &rect, NULL ); + send_erase( child, erase_flags, hrgn, NULL, NULL ); DeleteObject( hrgn ); } prev = 0; @@ -529,10 +521,6 @@ BOOL WINAPI RedrawWindow( HWND hwnd, const RECT *rect, HRGN hrgn, UINT flags ) if (!hwnd) hwnd = GetDesktopWindow(); - /* check if the window or its parents are visible/not minimized */ - - if (!WIN_IsWindowDrawable( hwnd, !(flags & RDW_FRAME) )) return TRUE; - if (TRACE_ON(win)) { if (hrgn) @@ -638,8 +626,12 @@ INT WINAPI GetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase ) if ((update_rgn = send_ncpaint( hwnd, NULL, &flags ))) { - RECT rect; - send_erase( hwnd, flags, update_rgn, &rect, NULL ); + POINT offset; + send_erase( hwnd, flags, update_rgn, NULL, NULL ); + /* map region to client coordinates */ + offset.x = offset.y = 0; + ScreenToClient( hwnd, &offset ); + OffsetRgn( update_rgn, offset.x, offset.y ); retval = CombineRgn( hrgn, update_rgn, 0, RGN_COPY ); DeleteObject( update_rgn ); } @@ -653,7 +645,6 @@ INT WINAPI GetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase ) BOOL WINAPI GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase ) { HDC hdc; - RECT dummy; UINT flags = UPDATE_NOCHILDREN; HRGN update_rgn; @@ -661,9 +652,13 @@ BOOL WINAPI GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase ) if (!(update_rgn = send_ncpaint( hwnd, NULL, &flags ))) return FALSE; - if (rect) GetRgnBox( update_rgn, rect ); + if (rect) + { + if (GetRgnBox( update_rgn, rect ) != NULLREGION) + MapWindowPoints( 0, hwnd, (LPPOINT)rect, 2 ); + } - send_erase( hwnd, flags, update_rgn, &dummy, &hdc ); + send_erase( hwnd, flags, update_rgn, NULL, &hdc ); if (hdc) { if (rect) DPtoLP( hdc, (LPPOINT)rect, 2 ); diff --git a/dlls/user/tests/dce.c b/dlls/user/tests/dce.c index 5c42e3f1e11..9065c6c2d59 100644 --- a/dlls/user/tests/dce.c +++ b/dlls/user/tests/dce.c @@ -167,7 +167,7 @@ static void test_dc_visrgn(void) hdc = GetDCEx( hwnd_cache, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE ); SetRectEmpty( &rect ); GetClipBox( hdc, &rect ); - todo_wine ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, + ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom ); ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" ); ReleaseDC( hwnd_cache, hdc ); @@ -181,7 +181,7 @@ static void test_dc_visrgn(void) hdc = GetDCEx( hwnd_cache, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE | DCX_NORESETATTRS ); SetRectEmpty( &rect ); GetClipBox( hdc, &rect ); - todo_wine ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, + ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom ); ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" ); ReleaseDC( hwnd_cache, hdc ); @@ -201,19 +201,19 @@ static void test_dc_visrgn(void) hdc = GetDCEx( hwnd_owndc, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE ); SetRectEmpty( &rect ); GetClipBox( hdc, &rect ); - todo_wine ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, + ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom ); ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" ); ReleaseDC( hwnd_owndc, hdc ); ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" ); SetRectEmpty( &rect ); GetClipBox( hdc, &rect ); - todo_wine ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, + ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom ); hdc = GetDCEx( hwnd_owndc, 0, DCX_USESTYLE ); SetRectEmpty( &rect ); GetClipBox( hdc, &rect ); - todo_wine ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, + ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom ); ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" ); ReleaseDC( hwnd_owndc, hdc ); @@ -226,7 +226,7 @@ static void test_dc_visrgn(void) ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" ); SetRectEmpty( &rect ); GetClipBox( hdc, &rect ); - todo_wine ok( rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30, + ok( rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30, "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom ); ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" ); ReleaseDC( hwnd_owndc, hdc ); @@ -247,20 +247,20 @@ static void test_dc_visrgn(void) hdc = GetDCEx( hwnd_classdc, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE ); SetRectEmpty( &rect ); GetClipBox( hdc, &rect ); - todo_wine ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, + ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom ); ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" ); ReleaseDC( hwnd_classdc, hdc ); ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" ); SetRectEmpty( &rect ); GetClipBox( hdc, &rect ); - todo_wine ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, + ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom ); hdc = GetDCEx( hwnd_classdc, 0, DCX_USESTYLE ); SetRectEmpty( &rect ); GetClipBox( hdc, &rect ); - todo_wine ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, + ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20, "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom ); ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" ); ReleaseDC( hwnd_classdc, hdc ); @@ -273,7 +273,7 @@ static void test_dc_visrgn(void) ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" ); SetRectEmpty( &rect ); GetClipBox( hdc, &rect ); - todo_wine ok( rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30, + ok( rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30, "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom ); ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" ); diff --git a/dlls/x11drv/dce.c b/dlls/x11drv/dce.c index 600b11d9a8f..72f8ca77b77 100644 --- a/dlls/x11drv/dce.c +++ b/dlls/x11drv/dce.c @@ -224,6 +224,10 @@ static void set_drawable( struct dce *dce, BOOL update_visrgn ) CombineRgn( visRgn, visRgn, dce->clip_rgn, (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF ); + /* map region to DC coordinates */ + OffsetRgn( visRgn, -(escape.org.x + escape.drawable_org.x), + -(escape.org.y + escape.drawable_org.y) ); + SelectVisRgn16( HDC_16(dce->hdc), HRGN_16(visRgn) ); DeleteObject( visRgn ); } diff --git a/server/window.c b/server/window.c index ff8c3393448..26889faa980 100644 --- a/server/window.c +++ b/server/window.c @@ -633,6 +633,21 @@ static struct region *intersect_window_region( struct region *region, struct win } +/* map the region from window to screen coordinates */ +static inline void map_win_region_to_screen( struct window *win, struct region *region ) +{ + int x = win->window_rect.left; + int y = win->window_rect.top; + + for (win = win->parent; win; win = win->parent) + { + x += win->client_rect.left; + y += win->client_rect.top; + } + offset_region( region, x, y ); +} + + /* clip all children of a given window out of the visible region */ static struct region *clip_children( struct window *parent, struct window *last, struct region *region, int offset_x, int offset_y ) @@ -690,7 +705,7 @@ static inline struct window *get_top_clipping_window( struct window *win ) } -/* compute the visible region of a window */ +/* compute the visible region of a window, in window coordinates */ static struct region *get_visible_region( struct window *win, unsigned int flags ) { struct region *tmp, *region; @@ -709,39 +724,32 @@ static struct region *get_visible_region( struct window *win, unsigned int flags { set_region_client_rect( region, win->parent ); offset_region( region, -win->parent->client_rect.left, -win->parent->client_rect.top ); - offset_x = win->client_rect.left; - offset_y = win->client_rect.top; } else if (flags & DCX_WINDOW) { set_region_rect( region, &win->visible_rect ); if (win->win_region && !intersect_window_region( region, win )) goto error; - offset_x = win->window_rect.left; - offset_y = win->window_rect.top; } else { set_region_client_rect( region, win ); if (win->win_region && !intersect_window_region( region, win )) goto error; - offset_x = win->client_rect.left; - offset_y = win->client_rect.top; } - offset_region( region, -offset_x, -offset_y ); + offset_x = win->window_rect.left; + offset_y = win->window_rect.top; /* clip children */ if (flags & DCX_CLIPCHILDREN) { - if (!clip_children( win, NULL, region, - offset_x - win->client_rect.left, - offset_y - win->client_rect.top )) goto error; + if (!clip_children( win, NULL, region, win->client_rect.left, win->client_rect.top )) + goto error; } /* clip siblings of ancestors */ if (top && top != win && (tmp = create_empty_region()) != NULL) { - offset_region( region, offset_x, offset_y ); /* make it relative to parent */ while (win != top && win->parent) { if (win->style & WS_CLIPSIBLINGS) @@ -767,9 +775,9 @@ static struct region *get_visible_region( struct window *win, unsigned int flags } if (is_region_empty( region )) break; } - offset_region( region, -offset_x, -offset_y ); /* make it relative to target window again */ free_region( tmp ); } + offset_region( region, -offset_x, -offset_y ); /* make it relative to target window */ return region; error: @@ -1578,7 +1586,9 @@ DECL_HANDLER(get_visible_region) if ((region = get_visible_region( win, req->flags ))) { - rectangle_t *data = get_region_data_and_free( region, get_reply_max_size(), &reply->total_size ); + rectangle_t *data; + map_win_region_to_screen( win, region ); + data = get_region_data_and_free( region, get_reply_max_size(), &reply->total_size ); if (data) set_reply_data_ptr( data, reply->total_size ); } } @@ -1657,8 +1667,18 @@ DECL_HANDLER(get_update_region) if (win->update_region) { - if (!(data = get_region_data( win->update_region, get_reply_max_size(), - &reply->total_size ))) return; + /* convert update region to screen coordinates */ + struct region *region = create_empty_region(); + + if (!region) return; + if (!copy_region( region, win->update_region )) + { + free_region( region ); + return; + } + map_win_region_to_screen( win, region ); + if (!(data = get_region_data_and_free( region, get_reply_max_size(), + &reply->total_size ))) return; set_reply_data_ptr( data, reply->total_size ); } diff --git a/windows/nonclient.c b/windows/nonclient.c index 429d3b5a063..b1007cea761 100644 --- a/windows/nonclient.c +++ b/windows/nonclient.c @@ -953,7 +953,6 @@ static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint ) dwStyle = wndPtr->dwStyle; dwExStyle = wndPtr->dwExStyle; flags = wndPtr->flags; - rectClient = wndPtr->rectClient; rectWindow = wndPtr->rectWindow; WIN_ReleasePtr( wndPtr ); @@ -971,10 +970,10 @@ static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint ) Now, how is the "system" supposed to tell what happened? */ - hrgn = CreateRectRgn( rectClient.left - rectWindow.left, - rectClient.top - rectWindow.top, - rectClient.right - rectWindow.left, - rectClient.bottom - rectWindow.top ); + GetClientRect( hwnd, &rectClient ); + MapWindowPoints( hwnd, 0, (POINT *)&rectClient, 2 ); + hrgn = CreateRectRgnIndirect( &rectClient ); + if (clip > (HRGN)1) { CombineRgn( hrgn, clip, hrgn, RGN_DIFF ); @@ -990,14 +989,7 @@ static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint ) rect.top = rect.left = 0; rect.right = rectWindow.right - rectWindow.left; rect.bottom = rectWindow.bottom - rectWindow.top; - - if( clip > (HRGN)1 ) - GetRgnBox( clip, &rectClip ); - else - { - clip = 0; - rectClip = rect; - } + GetClipBox( hdc, &rectClip ); SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) ); @@ -1021,7 +1013,7 @@ static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint ) r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION); rect.top += GetSystemMetrics(SM_CYCAPTION); } - if( !clip || IntersectRect( &rfuzz, &r, &rectClip ) ) + if( IntersectRect( &rfuzz, &r, &rectClip ) ) NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active); }