Protect BeginPaint and EndPaint from lps being NULL.
[wine/multimedia.git] / dlls / user / painting.c
blob1faada0097df30daa664426a2da776eae7f12330
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
21 #include <string.h>
23 #include "windef.h"
24 #include "wingdi.h"
25 #include "wine/winuser16.h"
26 #include "wine/server.h"
27 #include "win.h"
28 #include "dce.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(win);
33 /***********************************************************************
34 * add_paint_count
36 * Add an increment (normally 1 or -1) to the current paint count of a window.
38 static void add_paint_count( HWND hwnd, int incr )
40 SERVER_START_REQ( inc_window_paint_count )
42 req->handle = hwnd;
43 req->incr = incr;
44 wine_server_call( req );
46 SERVER_END_REQ;
50 /***********************************************************************
51 * copy_rgn
53 * copy a region, doing the right thing if the source region is 0 or 1
55 static HRGN copy_rgn( HRGN hSrc )
57 if (hSrc > (HRGN)1)
59 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
60 CombineRgn( hrgn, hSrc, 0, RGN_COPY );
61 return hrgn;
63 return hSrc;
67 /***********************************************************************
68 * get_update_regions
70 * Return update regions for the whole window and for the client area.
72 static void get_update_regions( WND *win, HRGN *whole_rgn, HRGN *client_rgn )
74 if (win->hrgnUpdate > (HRGN)1)
76 RECT client, update;
78 /* check if update rgn overlaps with nonclient area */
79 GetRgnBox( win->hrgnUpdate, &update );
80 client = win->rectClient;
81 OffsetRect( &client, -win->rectWindow.left, -win->rectWindow.top );
83 if (update.left < client.left || update.top < client.top ||
84 update.right > client.right || update.bottom > client.bottom)
86 *whole_rgn = copy_rgn( win->hrgnUpdate );
87 *client_rgn = CreateRectRgnIndirect( &client );
88 if (CombineRgn( *client_rgn, *client_rgn, win->hrgnUpdate, RGN_AND ) == NULLREGION)
90 DeleteObject( *client_rgn );
91 *client_rgn = 0;
94 else
96 *whole_rgn = 0;
97 *client_rgn = copy_rgn( win->hrgnUpdate );
100 else
102 *client_rgn = *whole_rgn = win->hrgnUpdate; /* 0 or 1 */
107 /***********************************************************************
108 * begin_ncpaint
110 * Send a WM_NCPAINT message from inside BeginPaint().
111 * Returns update region cropped to client rectangle (and in client coords),
112 * and clears window update region and internal paint flag.
114 static HRGN begin_ncpaint( HWND hwnd )
116 HRGN whole_rgn, client_rgn;
117 WND *wnd = WIN_GetPtr( hwnd );
119 if (!wnd || wnd == WND_OTHER_PROCESS) return 0;
121 TRACE("hwnd %p [%p] ncf %i\n",
122 hwnd, wnd->hrgnUpdate, wnd->flags & WIN_NEEDS_NCPAINT);
124 get_update_regions( wnd, &whole_rgn, &client_rgn );
126 if (whole_rgn) /* NOTE: WM_NCPAINT allows wParam to be 1 */
128 WIN_ReleasePtr( wnd );
129 SendMessageA( hwnd, WM_NCPAINT, (WPARAM)whole_rgn, 0 );
130 if (whole_rgn > (HRGN)1) DeleteObject( whole_rgn );
131 /* make sure the window still exists before continuing */
132 if (!(wnd = WIN_GetPtr( hwnd )) || wnd == WND_OTHER_PROCESS)
134 if (client_rgn > (HRGN)1) DeleteObject( client_rgn );
135 return 0;
139 if (wnd->hrgnUpdate || (wnd->flags & WIN_INTERNAL_PAINT)) add_paint_count( hwnd, -1 );
140 if (wnd->hrgnUpdate > (HRGN)1) DeleteObject( wnd->hrgnUpdate );
141 wnd->hrgnUpdate = 0;
142 wnd->flags &= ~(WIN_INTERNAL_PAINT | WIN_NEEDS_NCPAINT | WIN_NEEDS_BEGINPAINT);
143 if (client_rgn > (HRGN)1) OffsetRgn( client_rgn, wnd->rectWindow.left - wnd->rectClient.left,
144 wnd->rectWindow.top - wnd->rectClient.top );
145 WIN_ReleasePtr( wnd );
146 return client_rgn;
150 /***********************************************************************
151 * BeginPaint (USER32.@)
153 HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps )
155 INT dcx_flags;
156 BOOL bIcon;
157 HRGN hrgnUpdate;
158 RECT clipRect, clientRect;
159 HWND full_handle;
160 WND *wndPtr;
162 if (!lps) return 0;
164 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
166 if (IsWindow(hwnd))
167 FIXME( "window %p belongs to other thread\n", hwnd );
168 return 0;
170 hwnd = full_handle;
172 /* send WM_NCPAINT and retrieve update region */
173 hrgnUpdate = begin_ncpaint( hwnd );
174 if (!hrgnUpdate && !IsWindow( hwnd )) return 0;
176 HideCaret( hwnd );
178 bIcon = (IsIconic(hwnd) && GetClassLongA(hwnd, GCL_HICON));
180 dcx_flags = DCX_INTERSECTRGN | DCX_WINDOWPAINT | DCX_USESTYLE;
181 if (bIcon) dcx_flags |= DCX_WINDOW;
183 if (GetClassLongA( hwnd, GCL_STYLE ) & CS_PARENTDC)
185 /* Don't clip the output to the update region for CS_PARENTDC window */
186 if (hrgnUpdate > (HRGN)1) DeleteObject( hrgnUpdate );
187 hrgnUpdate = 0;
188 dcx_flags &= ~DCX_INTERSECTRGN;
190 else
192 if (!hrgnUpdate) /* empty region, clip everything */
194 hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
196 else if (hrgnUpdate == (HRGN)1) /* whole client area, don't clip */
198 hrgnUpdate = 0;
199 dcx_flags &= ~DCX_INTERSECTRGN;
202 lps->hdc = GetDCEx( hwnd, hrgnUpdate, dcx_flags );
203 /* ReleaseDC() in EndPaint() will delete the region */
205 if (!lps->hdc)
207 WARN("GetDCEx() failed in BeginPaint(), hwnd=%p\n", hwnd);
208 DeleteObject( hrgnUpdate );
209 return 0;
212 /* It is possible that the clip box is bigger than the window itself,
213 if CS_PARENTDC flag is set. Windows never return a paint rect bigger
214 than the window itself, so we need to intersect the cliprect with
215 the window */
216 GetClientRect( hwnd, &clientRect );
218 GetClipBox( lps->hdc, &clipRect );
219 LPtoDP(lps->hdc, (LPPOINT)&clipRect, 2); /* GetClipBox returns LP */
221 IntersectRect(&lps->rcPaint, &clientRect, &clipRect);
222 DPtoLP(lps->hdc, (LPPOINT)&lps->rcPaint, 2); /* we must return LP */
224 TRACE("hdc = %p box = (%ld,%ld - %ld,%ld)\n",
225 lps->hdc, lps->rcPaint.left, lps->rcPaint.top, lps->rcPaint.right, lps->rcPaint.bottom );
227 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
228 lps->fErase = !(wndPtr->flags & WIN_NEEDS_ERASEBKGND);
229 wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
230 WIN_ReleasePtr( wndPtr );
232 if (!lps->fErase)
233 lps->fErase = !SendMessageA( hwnd, bIcon ? WM_ICONERASEBKGND : WM_ERASEBKGND,
234 (WPARAM)lps->hdc, 0 );
235 return lps->hdc;
239 /***********************************************************************
240 * EndPaint (USER32.@)
242 BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps )
244 if (!lps) return FALSE;
246 ReleaseDC( hwnd, lps->hdc );
247 ShowCaret( hwnd );
248 return TRUE;