Move __stdcall/__cdecl to the right place.
[wine] / dlls / user / painting.c
1 /*
2  * Window painting functions
3  *
4  * Copyright 1993, 1994, 1995, 2001 Alexandre Julliard
5  * Copyright 1999 Alex Korobka
6  */
7 #include <string.h>
8
9 #include "windef.h"
10 #include "wingdi.h"
11 #include "wine/winuser16.h"
12 #include "wine/server.h"
13 #include "win.h"
14 #include "dce.h"
15 #include "debugtools.h"
16
17 DEFAULT_DEBUG_CHANNEL(win);
18
19 /***********************************************************************
20  *           add_paint_count
21  *
22  * Add an increment (normally 1 or -1) to the current paint count of a window.
23  */
24 static void add_paint_count( HWND hwnd, int incr )
25 {
26     SERVER_START_REQ( inc_window_paint_count )
27     {
28         req->handle = hwnd;
29         req->incr   = incr;
30         wine_server_call( req );
31     }
32     SERVER_END_REQ;
33 }
34
35
36 /***********************************************************************
37  *           copy_rgn
38  *
39  * copy a region, doing the right thing if the source region is 0 or 1
40  */
41 static HRGN copy_rgn( HRGN hSrc )
42 {
43     if (hSrc > 1)
44     {
45         HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
46         CombineRgn( hrgn, hSrc, 0, RGN_COPY );
47         return hrgn;
48     }
49     return hSrc;
50 }
51
52
53 /***********************************************************************
54  *           get_update_regions
55  *
56  * Return update regions for the whole window and for the client area.
57  */
58 static void get_update_regions( WND *win, HRGN *whole_rgn, HRGN *client_rgn )
59 {
60     if (win->hrgnUpdate > 1)
61     {
62         RECT client, update;
63
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 );
68
69         if (update.left < client.left || update.top < client.top ||
70             update.right > client.right || update.bottom > client.bottom)
71         {
72             *whole_rgn = copy_rgn( win->hrgnUpdate );
73             *client_rgn = CreateRectRgnIndirect( &client );
74             if (CombineRgn( *client_rgn, *client_rgn, win->hrgnUpdate, RGN_AND ) == NULLREGION)
75             {
76                 DeleteObject( *client_rgn );
77                 *client_rgn = 0;
78             }
79         }
80         else
81         {
82             *whole_rgn = 0;
83             *client_rgn = copy_rgn( win->hrgnUpdate );
84         }
85     }
86     else
87     {
88         *client_rgn = *whole_rgn = win->hrgnUpdate;  /* 0 or 1 */
89     }
90 }
91
92
93 /***********************************************************************
94  *           begin_ncpaint
95  *
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.
99  */
100 static HRGN begin_ncpaint( HWND hwnd )
101 {
102     HRGN whole_rgn, client_rgn;
103     WND *wnd = WIN_GetPtr( hwnd );
104
105     if (!wnd || wnd == WND_OTHER_PROCESS) return 0;
106
107     TRACE("hwnd %04x [%04x] ncf %i\n",
108           hwnd, wnd->hrgnUpdate, wnd->flags & WIN_NEEDS_NCPAINT);
109
110     get_update_regions( wnd, &whole_rgn, &client_rgn );
111
112     if (whole_rgn) /* NOTE: WM_NCPAINT allows wParam to be 1 */
113     {
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)
119         {
120             if (client_rgn > 1) DeleteObject( client_rgn );
121             return 0;
122         }
123     }
124
125     if (wnd->hrgnUpdate || (wnd->flags & WIN_INTERNAL_PAINT)) add_paint_count( hwnd, -1 );
126     if (wnd->hrgnUpdate > 1) DeleteObject( wnd->hrgnUpdate );
127     wnd->hrgnUpdate = 0;
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 );
132     return client_rgn;
133 }
134
135
136 /***********************************************************************
137  *              BeginPaint (USER32.@)
138  */
139 HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps )
140 {
141     INT dcx_flags;
142     BOOL bIcon;
143     HRGN hrgnUpdate;
144     RECT clipRect, clientRect;
145     HWND full_handle;
146     WND *wndPtr;
147
148     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
149     {
150         if (IsWindow(hwnd))
151             FIXME( "window %x belongs to other thread\n", hwnd );
152         return 0;
153     }
154     hwnd = full_handle;
155
156     /* send WM_NCPAINT and retrieve update region */
157     hrgnUpdate = begin_ncpaint( hwnd );
158     if (!hrgnUpdate && !IsWindow( hwnd )) return 0;
159
160     HideCaret( hwnd );
161
162     bIcon = (IsIconic(hwnd) && GetClassLongA(hwnd, GCL_HICON));
163
164     dcx_flags = DCX_INTERSECTRGN | DCX_WINDOWPAINT | DCX_USESTYLE;
165     if (bIcon) dcx_flags |= DCX_WINDOW;
166
167     if (GetClassLongA( hwnd, GCL_STYLE ) & CS_PARENTDC)
168     {
169         /* Don't clip the output to the update region for CS_PARENTDC window */
170         if (hrgnUpdate > 1) DeleteObject( hrgnUpdate );
171         hrgnUpdate = 0;
172         dcx_flags &= ~DCX_INTERSECTRGN;
173     }
174     else
175     {
176         if (!hrgnUpdate)  /* empty region, clip everything */
177         {
178             hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
179         }
180         else if (hrgnUpdate == 1)  /* whole client area, don't clip */
181         {
182             hrgnUpdate = 0;
183             dcx_flags &= ~DCX_INTERSECTRGN;
184         }
185     }
186     lps->hdc = GetDCEx( hwnd, hrgnUpdate, dcx_flags );
187     /* ReleaseDC() in EndPaint() will delete the region */
188
189     if (!lps->hdc)
190     {
191         WARN("GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd);
192         DeleteObject( hrgnUpdate );
193         return 0;
194     }
195
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
199        the window  */
200     GetClientRect( hwnd, &clientRect );
201
202     GetClipBox( lps->hdc, &clipRect );
203     LPtoDP(lps->hdc, (LPPOINT)&clipRect, 2);      /* GetClipBox returns LP */
204
205     IntersectRect(&lps->rcPaint, &clientRect, &clipRect);
206     DPtoLP(lps->hdc, (LPPOINT)&lps->rcPaint, 2);  /* we must return LP */
207
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 );
210
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 );
215
216     if (!lps->fErase)
217         lps->fErase = !SendMessageA( hwnd, bIcon ? WM_ICONERASEBKGND : WM_ERASEBKGND,
218                                      (WPARAM)lps->hdc, 0 );
219     return lps->hdc;
220 }
221
222
223 /***********************************************************************
224  *              EndPaint (USER32.@)
225  */
226 BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps )
227 {
228     ReleaseDC( hwnd, lps->hdc );
229     ShowCaret( hwnd );
230     return TRUE;
231 }