2 * Window painting functions
4 * Copyright 1993, 1994, 1995, 2001 Alexandre Julliard
5 * Copyright 1999 Alex Korobka
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "wine/port.h"
31 #include "wine/winuser16.h"
32 #include "wine/server.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(win
);
39 /***********************************************************************
42 * Add an increment (normally 1 or -1) to the current paint count of a window.
44 static void add_paint_count( HWND hwnd
, int incr
)
46 SERVER_START_REQ( inc_window_paint_count
)
50 wine_server_call( req
);
56 /***********************************************************************
59 * copy a region, doing the right thing if the source region is 0 or 1
61 static HRGN
copy_rgn( HRGN hSrc
)
65 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
66 CombineRgn( hrgn
, hSrc
, 0, RGN_COPY
);
73 /***********************************************************************
76 * Return update region for a window.
78 static HRGN
get_update_region( WND
*win
)
80 if (!win
->hrgnUpdate
) return CreateRectRgn( 0, 0, 0, 0 );
81 if (win
->hrgnUpdate
> (HRGN
)1) return copy_rgn( win
->hrgnUpdate
);
82 return CreateRectRgn( 0, 0, win
->rectWindow
.right
- win
->rectWindow
.left
,
83 win
->rectWindow
.bottom
- win
->rectWindow
.top
);
87 /***********************************************************************
90 * Return update regions for the whole window and for the client area.
92 static void get_update_regions( WND
*win
, HRGN
*whole_rgn
, HRGN
*client_rgn
)
94 if (win
->hrgnUpdate
> (HRGN
)1)
98 /* check if update rgn overlaps with nonclient area */
99 GetRgnBox( win
->hrgnUpdate
, &update
);
100 client
= win
->rectClient
;
101 OffsetRect( &client
, -win
->rectWindow
.left
, -win
->rectWindow
.top
);
103 if (update
.left
< client
.left
|| update
.top
< client
.top
||
104 update
.right
> client
.right
|| update
.bottom
> client
.bottom
)
106 *whole_rgn
= copy_rgn( win
->hrgnUpdate
);
107 *client_rgn
= CreateRectRgnIndirect( &client
);
108 if (CombineRgn( *client_rgn
, *client_rgn
, win
->hrgnUpdate
, RGN_AND
) == NULLREGION
)
110 DeleteObject( *client_rgn
);
117 *client_rgn
= copy_rgn( win
->hrgnUpdate
);
122 *client_rgn
= *whole_rgn
= win
->hrgnUpdate
; /* 0 or 1 */
127 /***********************************************************************
130 * Send a WM_NCPAINT message from inside BeginPaint().
131 * Returns update region cropped to client rectangle (and in client coords),
132 * and clears window update region and internal paint flag.
134 static HRGN
begin_ncpaint( HWND hwnd
)
136 HRGN whole_rgn
, client_rgn
;
137 WND
*wnd
= WIN_GetPtr( hwnd
);
139 if (!wnd
|| wnd
== WND_OTHER_PROCESS
) return 0;
141 TRACE("hwnd %p [%p] ncf %i\n",
142 hwnd
, wnd
->hrgnUpdate
, wnd
->flags
& WIN_NEEDS_NCPAINT
);
144 get_update_regions( wnd
, &whole_rgn
, &client_rgn
);
146 if (whole_rgn
) /* NOTE: WM_NCPAINT allows wParam to be 1 */
148 WIN_ReleasePtr( wnd
);
149 SendMessageA( hwnd
, WM_NCPAINT
, (WPARAM
)whole_rgn
, 0 );
150 if (whole_rgn
> (HRGN
)1) DeleteObject( whole_rgn
);
151 /* make sure the window still exists before continuing */
152 if (!(wnd
= WIN_GetPtr( hwnd
)) || wnd
== WND_OTHER_PROCESS
)
154 if (client_rgn
> (HRGN
)1) DeleteObject( client_rgn
);
159 if (wnd
->hrgnUpdate
|| (wnd
->flags
& WIN_INTERNAL_PAINT
)) add_paint_count( hwnd
, -1 );
160 if (wnd
->hrgnUpdate
> (HRGN
)1) DeleteObject( wnd
->hrgnUpdate
);
162 wnd
->flags
&= ~(WIN_INTERNAL_PAINT
| WIN_NEEDS_NCPAINT
| WIN_NEEDS_BEGINPAINT
);
163 if (client_rgn
> (HRGN
)1) OffsetRgn( client_rgn
, wnd
->rectWindow
.left
- wnd
->rectClient
.left
,
164 wnd
->rectWindow
.top
- wnd
->rectClient
.top
);
165 WIN_ReleasePtr( wnd
);
170 /***********************************************************************
171 * BeginPaint (USER32.@)
173 HDC WINAPI
BeginPaint( HWND hwnd
, PAINTSTRUCT
*lps
)
178 RECT clipRect
, clientRect
;
184 if (!(full_handle
= WIN_IsCurrentThread( hwnd
)))
187 FIXME( "window %p belongs to other thread\n", hwnd
);
192 /* send WM_NCPAINT and retrieve update region */
193 hrgnUpdate
= begin_ncpaint( hwnd
);
194 if (!hrgnUpdate
&& !IsWindow( hwnd
)) return 0;
198 bIcon
= (IsIconic(hwnd
) && GetClassLongA(hwnd
, GCL_HICON
));
200 dcx_flags
= DCX_INTERSECTRGN
| DCX_WINDOWPAINT
| DCX_USESTYLE
;
201 if (bIcon
) dcx_flags
|= DCX_WINDOW
;
203 if (GetClassLongA( hwnd
, GCL_STYLE
) & CS_PARENTDC
)
205 /* Don't clip the output to the update region for CS_PARENTDC window */
206 if (hrgnUpdate
> (HRGN
)1) DeleteObject( hrgnUpdate
);
208 dcx_flags
&= ~DCX_INTERSECTRGN
;
212 if (!hrgnUpdate
) /* empty region, clip everything */
214 hrgnUpdate
= CreateRectRgn( 0, 0, 0, 0 );
216 else if (hrgnUpdate
== (HRGN
)1) /* whole client area, don't clip */
219 dcx_flags
&= ~DCX_INTERSECTRGN
;
222 lps
->hdc
= GetDCEx( hwnd
, hrgnUpdate
, dcx_flags
);
223 /* ReleaseDC() in EndPaint() will delete the region */
227 WARN("GetDCEx() failed in BeginPaint(), hwnd=%p\n", hwnd
);
228 DeleteObject( hrgnUpdate
);
232 /* It is possible that the clip box is bigger than the window itself,
233 if CS_PARENTDC flag is set. Windows never return a paint rect bigger
234 than the window itself, so we need to intersect the cliprect with
236 GetClientRect( hwnd
, &clientRect
);
238 GetClipBox( lps
->hdc
, &clipRect
);
239 LPtoDP(lps
->hdc
, (LPPOINT
)&clipRect
, 2); /* GetClipBox returns LP */
241 IntersectRect(&lps
->rcPaint
, &clientRect
, &clipRect
);
242 DPtoLP(lps
->hdc
, (LPPOINT
)&lps
->rcPaint
, 2); /* we must return LP */
244 TRACE("hdc = %p box = (%ld,%ld - %ld,%ld)\n",
245 lps
->hdc
, lps
->rcPaint
.left
, lps
->rcPaint
.top
, lps
->rcPaint
.right
, lps
->rcPaint
.bottom
);
247 if (!(wndPtr
= WIN_GetPtr( hwnd
)) || wndPtr
== WND_OTHER_PROCESS
) return 0;
248 lps
->fErase
= (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
) != 0;
249 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
250 WIN_ReleasePtr( wndPtr
);
253 lps
->fErase
= !SendMessageA( hwnd
, bIcon
? WM_ICONERASEBKGND
: WM_ERASEBKGND
,
254 (WPARAM
)lps
->hdc
, 0 );
256 TRACE("hdc = %p box = (%ld,%ld - %ld,%ld), fErase = %d\n",
257 lps
->hdc
, lps
->rcPaint
.left
, lps
->rcPaint
.top
, lps
->rcPaint
.right
, lps
->rcPaint
.bottom
,
264 /***********************************************************************
265 * EndPaint (USER32.@)
267 BOOL WINAPI
EndPaint( HWND hwnd
, const PAINTSTRUCT
*lps
)
269 if (!lps
) return FALSE
;
271 ReleaseDC( hwnd
, lps
->hdc
);
277 /***********************************************************************
278 * GetUpdateRgn (USER32.@)
280 INT WINAPI
GetUpdateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
284 WND
*wndPtr
= WIN_GetPtr( hwnd
);
286 if (!wndPtr
) return ERROR
;
287 if (wndPtr
== WND_OTHER_PROCESS
)
289 FIXME( "not supported on other process window %p\n", hwnd
);
293 if ((update_rgn
= get_update_region( wndPtr
)))
295 /* map coordinates and clip to client area */
296 OffsetRgn( update_rgn
, wndPtr
->rectWindow
.left
- wndPtr
->rectClient
.left
,
297 wndPtr
->rectWindow
.top
- wndPtr
->rectClient
.top
);
298 SetRectRgn( hrgn
, 0, 0, wndPtr
->rectClient
.right
- wndPtr
->rectClient
.left
,
299 wndPtr
->rectClient
.bottom
- wndPtr
->rectClient
.top
);
300 retval
= CombineRgn( hrgn
, hrgn
, update_rgn
, RGN_AND
);
301 DeleteObject( update_rgn
);
305 WIN_ReleasePtr( wndPtr
);
307 if (erase
) RedrawWindow( hwnd
, NULL
, 0, RDW_ERASENOW
| RDW_NOCHILDREN
);
312 /***********************************************************************
313 * GetUpdateRect (USER32.@)
315 BOOL WINAPI
GetUpdateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
319 HRGN update_rgn
= CreateRectRgn( 0, 0, 0, 0 );
321 if (GetUpdateRgn( hwnd
, update_rgn
, erase
) == ERROR
)
323 DeleteObject( update_rgn
);
329 GetRgnBox( update_rgn
, rect
);
330 if (GetClassLongA(hwnd
, GCL_STYLE
) & CS_OWNDC
)
332 HDC hdc
= GetDCEx( hwnd
, 0, DCX_USESTYLE
);
335 if (GetMapMode(hdc
) != MM_TEXT
) DPtoLP(hdc
, (LPPOINT
)rect
, 2);
336 ReleaseDC( hwnd
, hdc
);
340 DeleteObject( update_rgn
);
342 wndPtr
= WIN_GetPtr( hwnd
);
343 if (wndPtr
&& wndPtr
!= WND_OTHER_PROCESS
)
345 ret
= (wndPtr
->hrgnUpdate
!= 0);
346 WIN_ReleasePtr( wndPtr
);
352 /***********************************************************************
353 * ExcludeUpdateRgn (USER32.@)
355 INT WINAPI
ExcludeUpdateRgn( HDC hdc
, HWND hwnd
)
357 HRGN update_rgn
= CreateRectRgn( 0, 0, 0, 0 );
358 INT ret
= GetUpdateRgn( hwnd
, update_rgn
, FALSE
);
362 /* do ugly coordinate translations in dce.c */
364 ret
= DCE_ExcludeRgn( hdc
, hwnd
, update_rgn
);
365 DeleteObject( update_rgn
);