The update region passed in WM_NCPAINT and the clipping region passed
[wine] / dlls / user / tests / dce.c
1 /*
2  * Unit tests for DCE support
3  *
4  * Copyright 2005 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #define NONAMELESSUNION
22 #define NONAMELESSSTRUCT
23
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33
34 #include "wine/test.h"
35
36 static HWND hwnd_cache, hwnd_owndc, hwnd_classdc, hwnd_classdc2;
37
38 /* test behavior of DC attributes with various GetDC/ReleaseDC combinations */
39 static void test_dc_attributes(void)
40 {
41     HDC hdc, old_hdc;
42     INT rop, def_rop;
43
44     /* test cache DC */
45
46     hdc = GetDC( hwnd_cache );
47     def_rop = GetROP2( hdc );
48
49     SetROP2( hdc, R2_WHITE );
50     rop = GetROP2( hdc );
51     ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
52
53     ReleaseDC( hwnd_cache, hdc );
54     hdc = GetDC( hwnd_cache );
55     rop = GetROP2( hdc );
56     ok( rop == def_rop, "wrong ROP2 %d after release\n", rop );
57     SetROP2( hdc, R2_WHITE );
58     ReleaseDC( hwnd_cache, hdc );
59
60     hdc = GetDCEx( hwnd_cache, 0, DCX_USESTYLE | DCX_NORESETATTRS );
61     rop = GetROP2( hdc );
62     /* Win9x seems to silently ignore DCX_NORESETATTRS */
63     ok( rop == def_rop || rop == R2_WHITE, "wrong ROP2 %d\n", rop );
64
65     SetROP2( hdc, R2_WHITE );
66     rop = GetROP2( hdc );
67     ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
68
69     ReleaseDC( hwnd_cache, hdc );
70     hdc = GetDCEx( hwnd_cache, 0, DCX_USESTYLE | DCX_NORESETATTRS );
71     rop = GetROP2( hdc );
72     ok( rop == def_rop || rop == R2_WHITE, "wrong ROP2 %d after release\n", rop );
73     ReleaseDC( hwnd_cache, hdc );
74
75     hdc = GetDCEx( hwnd_cache, 0, DCX_USESTYLE );
76     rop = GetROP2( hdc );
77     ok( rop == def_rop, "wrong ROP2 %d after release\n", rop );
78     ReleaseDC( hwnd_cache, hdc );
79
80     /* test own DC */
81
82     hdc = GetDC( hwnd_owndc );
83     SetROP2( hdc, R2_WHITE );
84     rop = GetROP2( hdc );
85     ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
86
87     old_hdc = hdc;
88     ReleaseDC( hwnd_owndc, hdc );
89     hdc = GetDC( hwnd_owndc );
90     ok( old_hdc == hdc, "didn't get same DC %p/%p\n", old_hdc, hdc );
91     rop = GetROP2( hdc );
92     ok( rop == R2_WHITE, "wrong ROP2 %d after release\n", rop );
93     ReleaseDC( hwnd_owndc, hdc );
94     rop = GetROP2( hdc );
95     ok( rop == R2_WHITE, "wrong ROP2 %d after second release\n", rop );
96
97     /* test class DC */
98
99     hdc = GetDC( hwnd_classdc );
100     SetROP2( hdc, R2_WHITE );
101     rop = GetROP2( hdc );
102     ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
103
104     old_hdc = hdc;
105     ReleaseDC( hwnd_classdc, hdc );
106     hdc = GetDC( hwnd_classdc );
107     ok( old_hdc == hdc, "didn't get same DC %p/%p\n", old_hdc, hdc );
108     rop = GetROP2( hdc );
109     ok( rop == R2_WHITE, "wrong ROP2 %d after release\n", rop );
110     ReleaseDC( hwnd_classdc, hdc );
111     rop = GetROP2( hdc );
112     ok( rop == R2_WHITE, "wrong ROP2 %d after second release\n", rop );
113
114     /* test class DC with 2 windows */
115
116     old_hdc = GetDC( hwnd_classdc );
117     SetROP2( old_hdc, R2_BLACK );
118     hdc = GetDC( hwnd_classdc2 );
119     ok( old_hdc == hdc, "didn't get same DC %p/%p\n", old_hdc, hdc );
120     rop = GetROP2( hdc );
121     ok( rop == R2_BLACK, "wrong ROP2 %d for other window\n", rop );
122     ReleaseDC( hwnd_classdc, old_hdc );
123     ReleaseDC( hwnd_classdc, hdc );
124     rop = GetROP2( hdc );
125     ok( rop == R2_BLACK, "wrong ROP2 %d after release\n", rop );
126 }
127
128
129 /* test behavior with various invalid parameters */
130 static void test_parameters(void)
131 {
132     HDC hdc;
133
134     hdc = GetDC( hwnd_cache );
135     ok( ReleaseDC( hwnd_owndc, hdc ), "ReleaseDC with wrong window should succeed\n" );
136
137     hdc = GetDC( hwnd_cache );
138     ok( !ReleaseDC( hwnd_cache, 0 ), "ReleaseDC with wrong HDC should fail\n" );
139     ok( ReleaseDC( hwnd_cache, hdc ), "correct ReleaseDC should succeed\n" );
140     ok( !ReleaseDC( hwnd_cache, hdc ), "second ReleaseDC should fail\n" );
141
142     hdc = GetDC( hwnd_owndc );
143     ok( ReleaseDC( hwnd_cache, hdc ), "ReleaseDC with wrong window should succeed\n" );
144     hdc = GetDC( hwnd_owndc );
145     ok( ReleaseDC( hwnd_owndc, hdc ), "correct ReleaseDC should succeed\n" );
146     ok( ReleaseDC( hwnd_owndc, hdc ), "second ReleaseDC should succeed\n" );
147
148     hdc = GetDC( hwnd_classdc );
149     ok( ReleaseDC( hwnd_cache, hdc ), "ReleaseDC with wrong window should succeed\n" );
150     hdc = GetDC( hwnd_classdc );
151     ok( ReleaseDC( hwnd_classdc, hdc ), "correct ReleaseDC should succeed\n" );
152     ok( ReleaseDC( hwnd_classdc, hdc ), "second ReleaseDC should succeed\n" );
153 }
154
155
156 static void test_dc_visrgn(void)
157 {
158     HDC old_hdc, hdc;
159     HRGN hrgn, hrgn2;
160     RECT rect;
161
162     /* cache DC */
163
164     SetRect( &rect, 10, 10, 20, 20 );
165     MapWindowPoints( hwnd_cache, 0, (POINT *)&rect, 2 );
166     hrgn = CreateRectRgnIndirect( &rect );
167     hdc = GetDCEx( hwnd_cache, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE );
168     SetRectEmpty( &rect );
169     GetClipBox( hdc, &rect );
170     ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
171         "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
172     ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
173     ReleaseDC( hwnd_cache, hdc );
174     ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
175
176     /* cache DC with NORESETATTRS */
177
178     SetRect( &rect, 10, 10, 20, 20 );
179     MapWindowPoints( hwnd_cache, 0, (POINT *)&rect, 2 );
180     hrgn = CreateRectRgnIndirect( &rect );
181     hdc = GetDCEx( hwnd_cache, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE | DCX_NORESETATTRS );
182     SetRectEmpty( &rect );
183     GetClipBox( hdc, &rect );
184     ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
185         "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
186     ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
187     ReleaseDC( hwnd_cache, hdc );
188     ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
189     hdc = GetDCEx( hwnd_cache, 0, DCX_USESTYLE | DCX_NORESETATTRS );
190     SetRectEmpty( &rect );
191     GetClipBox( hdc, &rect );
192     ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
193         "clip box sould have been reset %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
194     ReleaseDC( hwnd_cache, hdc );
195
196     /* window DC */
197
198     SetRect( &rect, 10, 10, 20, 20 );
199     MapWindowPoints( hwnd_owndc, 0, (POINT *)&rect, 2 );
200     hrgn = CreateRectRgnIndirect( &rect );
201     hdc = GetDCEx( hwnd_owndc, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE );
202     SetRectEmpty( &rect );
203     GetClipBox( hdc, &rect );
204     ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
205         "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
206     ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
207     ReleaseDC( hwnd_owndc, hdc );
208     ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
209     SetRectEmpty( &rect );
210     GetClipBox( hdc, &rect );
211     ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
212         "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
213     hdc = GetDCEx( hwnd_owndc, 0, DCX_USESTYLE );
214     SetRectEmpty( &rect );
215     GetClipBox( hdc, &rect );
216     ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
217         "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
218     ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
219     ReleaseDC( hwnd_owndc, hdc );
220     ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
221
222     SetRect( &rect, 20, 20, 30, 30 );
223     MapWindowPoints( hwnd_owndc, 0, (POINT *)&rect, 2 );
224     hrgn2 = CreateRectRgnIndirect( &rect );
225     hdc = GetDCEx( hwnd_owndc, hrgn2, DCX_INTERSECTRGN | DCX_USESTYLE );
226     ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
227     SetRectEmpty( &rect );
228     GetClipBox( hdc, &rect );
229     ok( rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30,
230         "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
231     ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
232     ReleaseDC( hwnd_owndc, hdc );
233     ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
234     hdc = GetDCEx( hwnd_owndc, 0, DCX_EXCLUDERGN | DCX_USESTYLE );
235     ok( GetRgnBox( hrgn2, &rect ) == ERROR, "region must no longer be valid\n" );
236     SetRectEmpty( &rect );
237     GetClipBox( hdc, &rect );
238     ok( !(rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30),
239         "clip box should have been reset %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
240     ReleaseDC( hwnd_owndc, hdc );
241
242     /* class DC */
243
244     SetRect( &rect, 10, 10, 20, 20 );
245     MapWindowPoints( hwnd_classdc, 0, (POINT *)&rect, 2 );
246     hrgn = CreateRectRgnIndirect( &rect );
247     hdc = GetDCEx( hwnd_classdc, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE );
248     SetRectEmpty( &rect );
249     GetClipBox( hdc, &rect );
250     ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
251         "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
252     ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
253     ReleaseDC( hwnd_classdc, hdc );
254     ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
255     SetRectEmpty( &rect );
256     GetClipBox( hdc, &rect );
257     ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
258         "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
259
260     hdc = GetDCEx( hwnd_classdc, 0, DCX_USESTYLE );
261     SetRectEmpty( &rect );
262     GetClipBox( hdc, &rect );
263     ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
264         "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
265     ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
266     ReleaseDC( hwnd_classdc, hdc );
267     ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
268
269     SetRect( &rect, 20, 20, 30, 30 );
270     MapWindowPoints( hwnd_classdc, 0, (POINT *)&rect, 2 );
271     hrgn2 = CreateRectRgnIndirect( &rect );
272     hdc = GetDCEx( hwnd_classdc, hrgn2, DCX_INTERSECTRGN | DCX_USESTYLE );
273     ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
274     SetRectEmpty( &rect );
275     GetClipBox( hdc, &rect );
276     ok( rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30,
277         "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
278     ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
279
280     old_hdc = hdc;
281     hdc = GetDCEx( hwnd_classdc2, 0, DCX_USESTYLE );
282     ok( old_hdc == hdc, "did not get the same hdc %p/%p\n", old_hdc, hdc );
283     ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
284     SetRectEmpty( &rect );
285     GetClipBox( hdc, &rect );
286     ok( !(rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30),
287         "clip box should have been reset %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
288     ReleaseDC( hwnd_classdc2, hdc );
289     ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
290     hdc = GetDCEx( hwnd_classdc2, 0, DCX_EXCLUDERGN | DCX_USESTYLE );
291     ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
292     ok( !(rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30),
293         "clip box must have been reset %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
294     ReleaseDC( hwnd_classdc2, hdc );
295 }
296
297
298 /* test various BeginPaint/EndPaint behaviors */
299 static void test_begin_paint(void)
300 {
301     HDC old_hdc, hdc;
302     RECT rect;
303     PAINTSTRUCT ps;
304
305     /* cache DC */
306
307     /* clear update region */
308     RedrawWindow( hwnd_cache, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
309     SetRect( &rect, 10, 10, 20, 20 );
310     RedrawWindow( hwnd_cache, &rect, 0, RDW_INVALIDATE );
311     hdc = BeginPaint( hwnd_cache, &ps );
312     SetRectEmpty( &rect );
313     GetClipBox( hdc, &rect );
314     ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
315         "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
316     EndPaint( hwnd_cache, &ps );
317
318     /* window DC */
319
320     RedrawWindow( hwnd_owndc, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
321     SetRect( &rect, 10, 10, 20, 20 );
322     RedrawWindow( hwnd_owndc, &rect, 0, RDW_INVALIDATE );
323     hdc = BeginPaint( hwnd_owndc, &ps );
324     SetRectEmpty( &rect );
325     GetClipBox( hdc, &rect );
326     ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
327         "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
328     ReleaseDC( hwnd_owndc, hdc );
329     SetRectEmpty( &rect );
330     GetClipBox( hdc, &rect );
331     ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
332         "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
333     ok( GetDC( hwnd_owndc ) == hdc, "got different hdc\n" );
334     SetRectEmpty( &rect );
335     GetClipBox( hdc, &rect );
336     ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
337         "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
338     EndPaint( hwnd_owndc, &ps );
339     SetRectEmpty( &rect );
340     GetClipBox( hdc, &rect );
341     ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
342         "clip box should have been reset %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
343
344     /* class DC */
345
346     RedrawWindow( hwnd_classdc, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
347     SetRect( &rect, 10, 10, 20, 20 );
348     RedrawWindow( hwnd_classdc, &rect, 0, RDW_INVALIDATE );
349     hdc = BeginPaint( hwnd_classdc, &ps );
350     SetRectEmpty( &rect );
351     GetClipBox( hdc, &rect );
352     ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
353         "invalid clip box %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
354
355     old_hdc = hdc;
356     hdc = GetDC( hwnd_classdc2 );
357     ok( old_hdc == hdc, "did not get the same hdc %p/%p\n", old_hdc, hdc );
358     SetRectEmpty( &rect );
359     GetClipBox( hdc, &rect );
360     ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
361         "clip box should have been reset %ld,%ld-%ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom );
362 }
363
364
365 START_TEST(dce)
366 {
367     WNDCLASSA cls;
368
369     cls.style = CS_DBLCLKS;
370     cls.lpfnWndProc = DefWindowProcA;
371     cls.cbClsExtra = 0;
372     cls.cbWndExtra = 0;
373     cls.hInstance = GetModuleHandleA(0);
374     cls.hIcon = 0;
375     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
376     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
377     cls.lpszMenuName = NULL;
378     cls.lpszClassName = "cache_class";
379     RegisterClassA(&cls);
380     cls.style = CS_DBLCLKS | CS_OWNDC;
381     cls.lpszClassName = "owndc_class";
382     RegisterClassA(&cls);
383     cls.style = CS_DBLCLKS | CS_CLASSDC;
384     cls.lpszClassName = "classdc_class";
385     RegisterClassA(&cls);
386
387     hwnd_cache = CreateWindowA("cache_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
388                                0, 0, 100, 100,
389                                0, 0, GetModuleHandleA(0), NULL );
390     hwnd_owndc = CreateWindowA("owndc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
391                                0, 200, 100, 100,
392                                0, 0, GetModuleHandleA(0), NULL );
393     hwnd_classdc = CreateWindowA("classdc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
394                                  200, 0, 100, 100,
395                                  0, 0, GetModuleHandleA(0), NULL );
396     hwnd_classdc2 = CreateWindowA("classdc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
397                                   200, 200, 100, 100,
398                                   0, 0, GetModuleHandleA(0), NULL );
399     test_dc_attributes();
400     test_parameters();
401     test_dc_visrgn();
402     test_begin_paint();
403 }