GetUpdateRect should return TRUE even if only the non-client area is
[wine/multimedia.git] / dlls / user / painting.c
blobe038c4f254cece280f3ca0b4f4c0559da6b85261
1 /*
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
22 #include "config.h"
23 #include "wine/port.h"
25 #include <stdarg.h>
26 #include <string.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "wine/winuser16.h"
32 #include "wine/server.h"
33 #include "win.h"
34 #include "dce.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(win);
39 /***********************************************************************
40 * add_paint_count
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 )
48 req->handle = hwnd;
49 req->incr = incr;
50 wine_server_call( req );
52 SERVER_END_REQ;
56 /***********************************************************************
57 * copy_rgn
59 * copy a region, doing the right thing if the source region is 0 or 1
61 static HRGN copy_rgn( HRGN hSrc )
63 if (hSrc > (HRGN)1)
65 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
66 CombineRgn( hrgn, hSrc, 0, RGN_COPY );
67 return hrgn;
69 return hSrc;
73 /***********************************************************************
74 * get_update_region
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 /***********************************************************************
88 * get_update_regions
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)
96 RECT client, update;
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 );
111 *client_rgn = 0;
114 else
116 *whole_rgn = 0;
117 *client_rgn = copy_rgn( win->hrgnUpdate );
120 else
122 *client_rgn = *whole_rgn = win->hrgnUpdate; /* 0 or 1 */
127 /***********************************************************************
128 * begin_ncpaint
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 );
155 return 0;
159 if (wnd->hrgnUpdate || (wnd->flags & WIN_INTERNAL_PAINT)) add_paint_count( hwnd, -1 );
160 if (wnd->hrgnUpdate > (HRGN)1) DeleteObject( wnd->hrgnUpdate );
161 wnd->hrgnUpdate = 0;
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 );
166 return client_rgn;
170 /***********************************************************************
171 * BeginPaint (USER32.@)
173 HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps )
175 INT dcx_flags;
176 BOOL bIcon;
177 HRGN hrgnUpdate;
178 RECT clipRect, clientRect;
179 HWND full_handle;
180 WND *wndPtr;
182 if (!lps) return 0;
184 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
186 if (IsWindow(hwnd))
187 FIXME( "window %p belongs to other thread\n", hwnd );
188 return 0;
190 hwnd = full_handle;
192 /* send WM_NCPAINT and retrieve update region */
193 hrgnUpdate = begin_ncpaint( hwnd );
194 if (!hrgnUpdate && !IsWindow( hwnd )) return 0;
196 HideCaret( hwnd );
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 );
207 hrgnUpdate = 0;
208 dcx_flags &= ~DCX_INTERSECTRGN;
210 else
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 */
218 hrgnUpdate = 0;
219 dcx_flags &= ~DCX_INTERSECTRGN;
222 lps->hdc = GetDCEx( hwnd, hrgnUpdate, dcx_flags );
223 /* ReleaseDC() in EndPaint() will delete the region */
225 if (!lps->hdc)
227 WARN("GetDCEx() failed in BeginPaint(), hwnd=%p\n", hwnd);
228 DeleteObject( hrgnUpdate );
229 return 0;
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
235 the window */
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 );
252 if (lps->fErase)
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,
258 lps->fErase);
260 return lps->hdc;
264 /***********************************************************************
265 * EndPaint (USER32.@)
267 BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps )
269 if (!lps) return FALSE;
271 ReleaseDC( hwnd, lps->hdc );
272 ShowCaret( hwnd );
273 return TRUE;
277 /***********************************************************************
278 * GetUpdateRgn (USER32.@)
280 INT WINAPI GetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
282 INT retval;
283 HRGN update_rgn;
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 );
290 return ERROR;
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 );
303 else retval = ERROR;
305 WIN_ReleasePtr( wndPtr );
307 if (erase) RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW | RDW_NOCHILDREN );
308 return retval;
312 /***********************************************************************
313 * GetUpdateRect (USER32.@)
315 BOOL WINAPI GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase )
317 WND *wndPtr;
318 BOOL ret = FALSE;
319 HRGN update_rgn = CreateRectRgn( 0, 0, 0, 0 );
321 if (GetUpdateRgn( hwnd, update_rgn, erase ) == ERROR)
323 DeleteObject( update_rgn );
324 return FALSE;
327 if (rect)
329 GetRgnBox( update_rgn, rect );
330 if (GetClassLongA(hwnd, GCL_STYLE) & CS_OWNDC)
332 HDC hdc = GetDCEx( hwnd, 0, DCX_USESTYLE );
333 if (hdc)
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 );
348 return ret;
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 );
360 if (ret != ERROR)
362 /* do ugly coordinate translations in dce.c */
364 ret = DCE_ExcludeRgn( hdc, hwnd, update_rgn );
365 DeleteObject( update_rgn );
367 return ret;