2 * Window painting functions
4 * Copyright 1993, 1994, 1995, 2001 Alexandre Julliard
5 * Copyright 1999 Alex Korobka
11 #include "wine/winuser16.h"
12 #include "wine/server.h"
15 #include "debugtools.h"
17 DEFAULT_DEBUG_CHANNEL(win);
19 /***********************************************************************
22 * Add an increment (normally 1 or -1) to the current paint count of a window.
24 static void add_paint_count( HWND hwnd, int incr )
26 SERVER_START_REQ( inc_window_paint_count )
30 wine_server_call( req );
36 /***********************************************************************
39 * copy a region, doing the right thing if the source region is 0 or 1
41 static HRGN copy_rgn( HRGN hSrc )
45 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
46 CombineRgn( hrgn, hSrc, 0, RGN_COPY );
53 /***********************************************************************
56 * Return update regions for the whole window and for the client area.
58 static void get_update_regions( WND *win, HRGN *whole_rgn, HRGN *client_rgn )
60 if (win->hrgnUpdate > 1)
64 /* check if update rgn overlaps with nonclient area */
65 GetRgnBox( win->hrgnUpdate, &update );
66 client = win->rectClient;
67 OffsetRect( &client, -win->rectWindow.left, -win->rectWindow.top );
69 if (update.left < client.left || update.top < client.top ||
70 update.right > client.right || update.bottom > client.bottom)
72 *whole_rgn = copy_rgn( win->hrgnUpdate );
73 *client_rgn = CreateRectRgnIndirect( &client );
74 if (CombineRgn( *client_rgn, *client_rgn, win->hrgnUpdate, RGN_AND ) == NULLREGION)
76 DeleteObject( *client_rgn );
83 *client_rgn = copy_rgn( win->hrgnUpdate );
88 *client_rgn = *whole_rgn = win->hrgnUpdate; /* 0 or 1 */
93 /***********************************************************************
96 * Send a WM_NCPAINT message from inside BeginPaint().
97 * Returns update region cropped to client rectangle (and in client coords),
98 * and clears window update region and internal paint flag.
100 static HRGN begin_ncpaint( HWND hwnd )
102 HRGN whole_rgn, client_rgn;
103 WND *wnd = WIN_GetPtr( hwnd );
105 if (!wnd || wnd == WND_OTHER_PROCESS) return 0;
107 TRACE("hwnd %04x [%04x] ncf %i\n",
108 hwnd, wnd->hrgnUpdate, wnd->flags & WIN_NEEDS_NCPAINT);
110 get_update_regions( wnd, &whole_rgn, &client_rgn );
112 if (whole_rgn) /* NOTE: WM_NCPAINT allows wParam to be 1 */
114 WIN_ReleasePtr( wnd );
115 SendMessageA( hwnd, WM_NCPAINT, whole_rgn, 0 );
116 if (whole_rgn > 1) DeleteObject( whole_rgn );
117 /* make sure the window still exists before continuing */
118 if (!(wnd = WIN_GetPtr( hwnd )) || wnd == WND_OTHER_PROCESS)
120 if (client_rgn > 1) DeleteObject( client_rgn );
125 if (wnd->hrgnUpdate || (wnd->flags & WIN_INTERNAL_PAINT)) add_paint_count( hwnd, -1 );
126 if (wnd->hrgnUpdate > 1) DeleteObject( wnd->hrgnUpdate );
128 wnd->flags &= ~(WIN_INTERNAL_PAINT | WIN_NEEDS_NCPAINT | WIN_NEEDS_BEGINPAINT);
129 if (client_rgn > 1) OffsetRgn( client_rgn, wnd->rectWindow.left - wnd->rectClient.left,
130 wnd->rectWindow.top - wnd->rectClient.top );
131 WIN_ReleasePtr( wnd );
136 /***********************************************************************
137 * BeginPaint (USER32.@)
139 HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps )
144 RECT clipRect, clientRect;
148 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
151 FIXME( "window %x belongs to other thread\n", hwnd );
156 /* send WM_NCPAINT and retrieve update region */
157 hrgnUpdate = begin_ncpaint( hwnd );
158 if (!hrgnUpdate && !IsWindow( hwnd )) return 0;
162 bIcon = (IsIconic(hwnd) && GetClassLongA(hwnd, GCL_HICON));
164 dcx_flags = DCX_INTERSECTRGN | DCX_WINDOWPAINT | DCX_USESTYLE;
165 if (bIcon) dcx_flags |= DCX_WINDOW;
167 if (GetClassLongA( hwnd, GCL_STYLE ) & CS_PARENTDC)
169 /* Don't clip the output to the update region for CS_PARENTDC window */
170 if (hrgnUpdate > 1) DeleteObject( hrgnUpdate );
172 dcx_flags &= ~DCX_INTERSECTRGN;
176 if (!hrgnUpdate) /* empty region, clip everything */
178 hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
180 else if (hrgnUpdate == 1) /* whole client area, don't clip */
183 dcx_flags &= ~DCX_INTERSECTRGN;
186 lps->hdc = GetDCEx( hwnd, hrgnUpdate, dcx_flags );
187 /* ReleaseDC() in EndPaint() will delete the region */
191 WARN("GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd);
192 DeleteObject( hrgnUpdate );
196 /* It is possible that the clip box is bigger than the window itself,
197 if CS_PARENTDC flag is set. Windows never return a paint rect bigger
198 than the window itself, so we need to intersect the cliprect with
200 GetClientRect( hwnd, &clientRect );
202 GetClipBox( lps->hdc, &clipRect );
203 LPtoDP(lps->hdc, (LPPOINT)&clipRect, 2); /* GetClipBox returns LP */
205 IntersectRect(&lps->rcPaint, &clientRect, &clipRect);
206 DPtoLP(lps->hdc, (LPPOINT)&lps->rcPaint, 2); /* we must return LP */
208 TRACE("hdc = %x box = (%i,%i - %i,%i)\n",
209 lps->hdc, lps->rcPaint.left, lps->rcPaint.top, lps->rcPaint.right, lps->rcPaint.bottom );
211 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
212 lps->fErase = !(wndPtr->flags & WIN_NEEDS_ERASEBKGND);
213 wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
214 WIN_ReleasePtr( wndPtr );
217 lps->fErase = !SendMessageA( hwnd, bIcon ? WM_ICONERASEBKGND : WM_ERASEBKGND,
218 (WPARAM)lps->hdc, 0 );
223 /***********************************************************************
224 * EndPaint (USER32.@)
226 BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps )
228 ReleaseDC( hwnd, lps->hdc );