The update region passed in WM_NCPAINT and the clipping region passed

to GetDCEx have to be in screen coordinates.
This commit is contained in:
Alexandre Julliard 2005-03-30 17:11:46 +00:00
parent 6b10c324c5
commit eea706948a
5 changed files with 85 additions and 74 deletions

View File

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

View File

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

View File

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

View File

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

View File

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