Make IDirectMusicScriptImpl_IDirectMusicScript_CallRoutine return S_OK
[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  * 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.
11  *
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.
16  *
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
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdarg.h>
26 #include <string.h>
27
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"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(win);
38
39 /***********************************************************************
40  *           add_paint_count
41  *
42  * Add an increment (normally 1 or -1) to the current paint count of a window.
43  */
44 static void add_paint_count( HWND hwnd, int incr )
45 {
46     SERVER_START_REQ( inc_window_paint_count )
47     {
48         req->handle = hwnd;
49         req->incr   = incr;
50         wine_server_call( req );
51     }
52     SERVER_END_REQ;
53 }
54
55
56 /***********************************************************************
57  *           copy_rgn
58  *
59  * copy a region, doing the right thing if the source region is 0 or 1
60  */
61 static HRGN copy_rgn( HRGN hSrc )
62 {
63     if (hSrc > (HRGN)1)
64     {
65         HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
66         CombineRgn( hrgn, hSrc, 0, RGN_COPY );
67         return hrgn;
68     }
69     return hSrc;
70 }
71
72
73 /***********************************************************************
74  *           get_update_regions
75  *
76  * Return update regions for the whole window and for the client area.
77  */
78 static void get_update_regions( WND *win, HRGN *whole_rgn, HRGN *client_rgn )
79 {
80     if (win->hrgnUpdate > (HRGN)1)
81     {
82         RECT client, update;
83
84         /* check if update rgn overlaps with nonclient area */
85         GetRgnBox( win->hrgnUpdate, &update );
86         client = win->rectClient;
87         OffsetRect( &client, -win->rectWindow.left, -win->rectWindow.top );
88
89         if (update.left < client.left || update.top < client.top ||
90             update.right > client.right || update.bottom > client.bottom)
91         {
92             *whole_rgn = copy_rgn( win->hrgnUpdate );
93             *client_rgn = CreateRectRgnIndirect( &client );
94             if (CombineRgn( *client_rgn, *client_rgn, win->hrgnUpdate, RGN_AND ) == NULLREGION)
95             {
96                 DeleteObject( *client_rgn );
97                 *client_rgn = 0;
98             }
99         }
100         else
101         {
102             *whole_rgn = 0;
103             *client_rgn = copy_rgn( win->hrgnUpdate );
104         }
105     }
106     else
107     {
108         *client_rgn = *whole_rgn = win->hrgnUpdate;  /* 0 or 1 */
109     }
110 }
111
112
113 /***********************************************************************
114  *           begin_ncpaint
115  *
116  * Send a WM_NCPAINT message from inside BeginPaint().
117  * Returns update region cropped to client rectangle (and in client coords),
118  * and clears window update region and internal paint flag.
119  */
120 static HRGN begin_ncpaint( HWND hwnd )
121 {
122     HRGN whole_rgn, client_rgn;
123     WND *wnd = WIN_GetPtr( hwnd );
124
125     if (!wnd || wnd == WND_OTHER_PROCESS) return 0;
126
127     TRACE("hwnd %p [%p] ncf %i\n",
128           hwnd, wnd->hrgnUpdate, wnd->flags & WIN_NEEDS_NCPAINT);
129
130     get_update_regions( wnd, &whole_rgn, &client_rgn );
131
132     if (whole_rgn) /* NOTE: WM_NCPAINT allows wParam to be 1 */
133     {
134         WIN_ReleasePtr( wnd );
135         SendMessageA( hwnd, WM_NCPAINT, (WPARAM)whole_rgn, 0 );
136         if (whole_rgn > (HRGN)1) DeleteObject( whole_rgn );
137         /* make sure the window still exists before continuing */
138         if (!(wnd = WIN_GetPtr( hwnd )) || wnd == WND_OTHER_PROCESS)
139         {
140             if (client_rgn > (HRGN)1) DeleteObject( client_rgn );
141             return 0;
142         }
143     }
144
145     if (wnd->hrgnUpdate || (wnd->flags & WIN_INTERNAL_PAINT)) add_paint_count( hwnd, -1 );
146     if (wnd->hrgnUpdate > (HRGN)1) DeleteObject( wnd->hrgnUpdate );
147     wnd->hrgnUpdate = 0;
148     wnd->flags &= ~(WIN_INTERNAL_PAINT | WIN_NEEDS_NCPAINT | WIN_NEEDS_BEGINPAINT);
149     if (client_rgn > (HRGN)1) OffsetRgn( client_rgn, wnd->rectWindow.left - wnd->rectClient.left,
150                                          wnd->rectWindow.top - wnd->rectClient.top );
151     WIN_ReleasePtr( wnd );
152     return client_rgn;
153 }
154
155
156 /***********************************************************************
157  *              BeginPaint (USER32.@)
158  */
159 HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps )
160 {
161     INT dcx_flags;
162     BOOL bIcon;
163     HRGN hrgnUpdate;
164     RECT clipRect, clientRect;
165     HWND full_handle;
166     WND *wndPtr;
167
168     if (!lps) return 0;
169
170     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
171     {
172         if (IsWindow(hwnd))
173             FIXME( "window %p belongs to other thread\n", hwnd );
174         return 0;
175     }
176     hwnd = full_handle;
177
178     /* send WM_NCPAINT and retrieve update region */
179     hrgnUpdate = begin_ncpaint( hwnd );
180     if (!hrgnUpdate && !IsWindow( hwnd )) return 0;
181
182     HideCaret( hwnd );
183
184     bIcon = (IsIconic(hwnd) && GetClassLongA(hwnd, GCL_HICON));
185
186     dcx_flags = DCX_INTERSECTRGN | DCX_WINDOWPAINT | DCX_USESTYLE;
187     if (bIcon) dcx_flags |= DCX_WINDOW;
188
189     if (GetClassLongA( hwnd, GCL_STYLE ) & CS_PARENTDC)
190     {
191         /* Don't clip the output to the update region for CS_PARENTDC window */
192         if (hrgnUpdate > (HRGN)1) DeleteObject( hrgnUpdate );
193         hrgnUpdate = 0;
194         dcx_flags &= ~DCX_INTERSECTRGN;
195     }
196     else
197     {
198         if (!hrgnUpdate)  /* empty region, clip everything */
199         {
200             hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
201         }
202         else if (hrgnUpdate == (HRGN)1)  /* whole client area, don't clip */
203         {
204             hrgnUpdate = 0;
205             dcx_flags &= ~DCX_INTERSECTRGN;
206         }
207     }
208     lps->hdc = GetDCEx( hwnd, hrgnUpdate, dcx_flags );
209     /* ReleaseDC() in EndPaint() will delete the region */
210
211     if (!lps->hdc)
212     {
213         WARN("GetDCEx() failed in BeginPaint(), hwnd=%p\n", hwnd);
214         DeleteObject( hrgnUpdate );
215         return 0;
216     }
217
218     /* It is possible that the clip box is bigger than the window itself,
219        if CS_PARENTDC flag is set. Windows never return a paint rect bigger
220        than the window itself, so we need to intersect the cliprect with
221        the window  */
222     GetClientRect( hwnd, &clientRect );
223
224     GetClipBox( lps->hdc, &clipRect );
225     LPtoDP(lps->hdc, (LPPOINT)&clipRect, 2);      /* GetClipBox returns LP */
226
227     IntersectRect(&lps->rcPaint, &clientRect, &clipRect);
228     DPtoLP(lps->hdc, (LPPOINT)&lps->rcPaint, 2);  /* we must return LP */
229
230     TRACE("hdc = %p box = (%ld,%ld - %ld,%ld)\n",
231           lps->hdc, lps->rcPaint.left, lps->rcPaint.top, lps->rcPaint.right, lps->rcPaint.bottom );
232
233     if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
234     lps->fErase = (wndPtr->flags & WIN_NEEDS_ERASEBKGND) != 0;
235     wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
236     WIN_ReleasePtr( wndPtr );
237
238     if (lps->fErase)
239         lps->fErase = !SendMessageA( hwnd, bIcon ? WM_ICONERASEBKGND : WM_ERASEBKGND,
240                                      (WPARAM)lps->hdc, 0 );
241
242     TRACE("hdc = %p box = (%ld,%ld - %ld,%ld), fErase = %d\n",
243           lps->hdc, lps->rcPaint.left, lps->rcPaint.top, lps->rcPaint.right, lps->rcPaint.bottom,
244           lps->fErase);
245
246     return lps->hdc;
247 }
248
249
250 /***********************************************************************
251  *              EndPaint (USER32.@)
252  */
253 BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps )
254 {
255     if (!lps) return FALSE;
256
257     ReleaseDC( hwnd, lps->hdc );
258     ShowCaret( hwnd );
259     return TRUE;
260 }