dinput: Create generic joystick Acquire/Unacquire.
[wine] / dlls / gdi32 / clipping.c
1 /*
2  * DC clipping functions
3  *
4  * Copyright 1993 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "gdi_private.h"
27 #include "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(clipping);
30
31
32 /***********************************************************************
33  *           get_clip_region
34  *
35  * Return the total clip region (if any).
36  */
37 static inline HRGN get_clip_region( DC * dc )
38 {
39     if (dc->hMetaClipRgn) return dc->hMetaClipRgn;
40     if (dc->hMetaRgn) return dc->hMetaRgn;
41     return dc->hClipRgn;
42 }
43
44
45 /***********************************************************************
46  *           CLIPPING_UpdateGCRegion
47  *
48  * Update the GC clip region when the ClipRgn or VisRgn have changed.
49  */
50 void CLIPPING_UpdateGCRegion( DC * dc )
51 {
52     HRGN clip_rgn;
53
54     if (!dc->hVisRgn)
55     {
56         ERR("hVisRgn is zero. Please report this.\n" );
57         exit(1);
58     }
59
60     /* update the intersection of meta and clip regions */
61     if (dc->hMetaRgn && dc->hClipRgn)
62     {
63         if (!dc->hMetaClipRgn) dc->hMetaClipRgn = CreateRectRgn( 0, 0, 0, 0 );
64         CombineRgn( dc->hMetaClipRgn, dc->hClipRgn, dc->hMetaRgn, RGN_AND );
65         clip_rgn = dc->hMetaClipRgn;
66     }
67     else  /* only one is set, no need for an intersection */
68     {
69         if (dc->hMetaClipRgn) DeleteObject( dc->hMetaClipRgn );
70         dc->hMetaClipRgn = 0;
71         clip_rgn = dc->hMetaRgn ? dc->hMetaRgn : dc->hClipRgn;
72     }
73
74     if (dc->funcs->pSetDeviceClipping)
75         dc->funcs->pSetDeviceClipping( dc->physDev, dc->hVisRgn, clip_rgn );
76 }
77
78 /***********************************************************************
79  *           create_default_clip_region
80  *
81  * Create a default clipping region when none already exists.
82  */
83 static inline void create_default_clip_region( DC * dc )
84 {
85     UINT width, height;
86
87     if (dc->header.type == OBJ_MEMDC)
88     {
89         BITMAP bitmap;
90
91         GetObjectW( dc->hBitmap, sizeof(bitmap), &bitmap );
92         width = bitmap.bmWidth;
93         height = bitmap.bmHeight;
94     }
95     else
96     {
97         width = GetDeviceCaps( dc->hSelf, DESKTOPHORZRES );
98         height = GetDeviceCaps( dc->hSelf, DESKTOPVERTRES );
99     }
100     dc->hClipRgn = CreateRectRgn( 0, 0, width, height );
101 }
102
103
104 /***********************************************************************
105  *           SelectClipRgn    (GDI32.@)
106  */
107 INT WINAPI SelectClipRgn( HDC hdc, HRGN hrgn )
108 {
109     return ExtSelectClipRgn( hdc, hrgn, RGN_COPY );
110 }
111
112
113 /******************************************************************************
114  *              ExtSelectClipRgn        [GDI32.@]
115  */
116 INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode )
117 {
118     INT retval;
119     RECT rect;
120     DC * dc = get_dc_ptr( hdc );
121     if (!dc) return ERROR;
122
123     TRACE("%p %p %d\n", hdc, hrgn, fnMode );
124
125     update_dc( dc );
126     if (dc->funcs->pExtSelectClipRgn)
127     {
128         retval = dc->funcs->pExtSelectClipRgn( dc->physDev, hrgn, fnMode );
129         release_dc_ptr( dc );
130         return retval;
131     }
132
133     if (!hrgn)
134     {
135         if (fnMode == RGN_COPY)
136         {
137             if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
138             dc->hClipRgn = 0;
139         }
140         else
141         {
142             FIXME("Unimplemented: hrgn NULL in mode: %d\n", fnMode);
143             release_dc_ptr( dc );
144             return ERROR;
145         }
146     }
147     else
148     {
149         if (!dc->hClipRgn)
150             create_default_clip_region( dc );
151
152         if(fnMode == RGN_COPY)
153             CombineRgn( dc->hClipRgn, hrgn, 0, fnMode );
154         else
155             CombineRgn( dc->hClipRgn, dc->hClipRgn, hrgn, fnMode);
156     }
157
158     CLIPPING_UpdateGCRegion( dc );
159     release_dc_ptr( dc );
160
161     return GetClipBox(hdc, &rect);
162 }
163
164 /***********************************************************************
165  *           SelectVisRgn   (GDI32.@)
166  *
167  * Note: not exported on Windows, only the 16-bit version is exported.
168  */
169 INT WINAPI SelectVisRgn( HDC hdc, HRGN hrgn )
170 {
171     int retval;
172     DC * dc;
173
174     if (!hrgn) return ERROR;
175     if (!(dc = get_dc_ptr( hdc ))) return ERROR;
176
177     TRACE("%p %p\n", hdc, hrgn );
178
179     dc->dirty = 0;
180
181     retval = CombineRgn( dc->hVisRgn, hrgn, 0, RGN_COPY );
182     CLIPPING_UpdateGCRegion( dc );
183     release_dc_ptr( dc );
184     return retval;
185 }
186
187
188 /***********************************************************************
189  *           OffsetClipRgn    (GDI32.@)
190  */
191 INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y )
192 {
193     INT ret = SIMPLEREGION;
194     DC *dc = get_dc_ptr( hdc );
195     if (!dc) return ERROR;
196
197     TRACE("%p %d,%d\n", hdc, x, y );
198
199     update_dc( dc );
200     if(dc->funcs->pOffsetClipRgn)
201     {
202         ret = dc->funcs->pOffsetClipRgn( dc->physDev, x, y );
203         /* FIXME: ret is just a success flag, we should return a proper value */
204     }
205     else if (dc->hClipRgn) {
206         ret = OffsetRgn( dc->hClipRgn, MulDiv( x, dc->vportExtX, dc->wndExtX ),
207                          MulDiv( y, dc->vportExtY, dc->wndExtY ) );
208         CLIPPING_UpdateGCRegion( dc );
209     }
210     release_dc_ptr( dc );
211     return ret;
212 }
213
214
215 /***********************************************************************
216  *           ExcludeClipRect    (GDI32.@)
217  */
218 INT WINAPI ExcludeClipRect( HDC hdc, INT left, INT top,
219                                 INT right, INT bottom )
220 {
221     HRGN newRgn;
222     INT ret;
223     DC *dc = get_dc_ptr( hdc );
224     if (!dc) return ERROR;
225
226     TRACE("%p %dx%d,%dx%d\n", hdc, left, top, right, bottom );
227
228     update_dc( dc );
229     if(dc->funcs->pExcludeClipRect)
230     {
231         ret = dc->funcs->pExcludeClipRect( dc->physDev, left, top, right, bottom );
232         /* FIXME: ret is just a success flag, we should return a proper value */
233     }
234     else
235     {
236         POINT pt[2];
237
238         pt[0].x = left;
239         pt[0].y = top;
240         pt[1].x = right;
241         pt[1].y = bottom;
242         LPtoDP( hdc, pt, 2 );
243         if (!(newRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
244         else
245         {
246             if (!dc->hClipRgn)
247                 create_default_clip_region( dc );
248             ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, newRgn, RGN_DIFF );
249             DeleteObject( newRgn );
250         }
251         if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
252     }
253     release_dc_ptr( dc );
254     return ret;
255 }
256
257
258 /***********************************************************************
259  *           IntersectClipRect    (GDI32.@)
260  */
261 INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top, INT right, INT bottom )
262 {
263     INT ret;
264     DC *dc = get_dc_ptr( hdc );
265     if (!dc) return ERROR;
266
267     TRACE("%p %d,%d - %d,%d\n", hdc, left, top, right, bottom );
268
269     update_dc( dc );
270     if(dc->funcs->pIntersectClipRect)
271     {
272         ret = dc->funcs->pIntersectClipRect( dc->physDev, left, top, right, bottom );
273         /* FIXME: ret is just a success flag, we should return a proper value */
274     }
275     else
276     {
277         POINT pt[2];
278
279         pt[0].x = left;
280         pt[0].y = top;
281         pt[1].x = right;
282         pt[1].y = bottom;
283
284         LPtoDP( hdc, pt, 2 );
285
286         if (!dc->hClipRgn)
287         {
288             dc->hClipRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y );
289             ret = SIMPLEREGION;
290         }
291         else
292         {
293             HRGN newRgn;
294
295             if (!(newRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
296             else
297             {
298                 ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, newRgn, RGN_AND );
299                 DeleteObject( newRgn );
300             }
301         }
302         if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
303     }
304     release_dc_ptr( dc );
305     return ret;
306 }
307
308
309 /***********************************************************************
310  *           PtVisible    (GDI32.@)
311  */
312 BOOL WINAPI PtVisible( HDC hdc, INT x, INT y )
313 {
314     POINT pt;
315     BOOL ret;
316     HRGN clip;
317     DC *dc = get_dc_ptr( hdc );
318
319     TRACE("%p %d,%d\n", hdc, x, y );
320     if (!dc) return FALSE;
321
322     pt.x = x;
323     pt.y = y;
324     LPtoDP( hdc, &pt, 1 );
325     update_dc( dc );
326     ret = PtInRegion( dc->hVisRgn, pt.x, pt.y );
327     if (ret && (clip = get_clip_region(dc))) ret = PtInRegion( clip, pt.x, pt.y );
328     release_dc_ptr( dc );
329     return ret;
330 }
331
332
333 /***********************************************************************
334  *           RectVisible    (GDI32.@)
335  */
336 BOOL WINAPI RectVisible( HDC hdc, const RECT* rect )
337 {
338     RECT tmpRect;
339     BOOL ret;
340     HRGN clip;
341     DC *dc = get_dc_ptr( hdc );
342     if (!dc) return FALSE;
343     TRACE("%p %d,%dx%d,%d\n", hdc, rect->left, rect->top, rect->right, rect->bottom );
344
345     tmpRect = *rect;
346     LPtoDP( hdc, (POINT *)&tmpRect, 2 );
347
348     update_dc( dc );
349     if ((clip = get_clip_region(dc)))
350     {
351         HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
352         CombineRgn( hrgn, dc->hVisRgn, clip, RGN_AND );
353         ret = RectInRegion( hrgn, &tmpRect );
354         DeleteObject( hrgn );
355     }
356     else ret = RectInRegion( dc->hVisRgn, &tmpRect );
357     release_dc_ptr( dc );
358     return ret;
359 }
360
361
362 /***********************************************************************
363  *           GetClipBox    (GDI32.@)
364  */
365 INT WINAPI GetClipBox( HDC hdc, LPRECT rect )
366 {
367     INT ret;
368     HRGN clip;
369     DC *dc = get_dc_ptr( hdc );
370     if (!dc) return ERROR;
371
372     update_dc( dc );
373     if ((clip = get_clip_region(dc)))
374     {
375         HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
376         CombineRgn( hrgn, dc->hVisRgn, clip, RGN_AND );
377         ret = GetRgnBox( hrgn, rect );
378         DeleteObject( hrgn );
379     }
380     else ret = GetRgnBox( dc->hVisRgn, rect );
381     DPtoLP( hdc, (LPPOINT)rect, 2 );
382     release_dc_ptr( dc );
383     return ret;
384 }
385
386
387 /***********************************************************************
388  *           GetClipRgn  (GDI32.@)
389  */
390 INT WINAPI GetClipRgn( HDC hdc, HRGN hRgn )
391 {
392     INT ret = -1;
393     DC * dc;
394     if (hRgn && (dc = get_dc_ptr( hdc )))
395     {
396       if( dc->hClipRgn )
397       {
398           if( CombineRgn(hRgn, dc->hClipRgn, 0, RGN_COPY) != ERROR ) ret = 1;
399       }
400       else ret = 0;
401       release_dc_ptr( dc );
402     }
403     return ret;
404 }
405
406
407 /***********************************************************************
408  *           GetMetaRgn    (GDI32.@)
409  */
410 INT WINAPI GetMetaRgn( HDC hdc, HRGN hRgn )
411 {
412     INT ret = 0;
413     DC * dc = get_dc_ptr( hdc );
414
415     if (dc)
416     {
417         if (dc->hMetaRgn && CombineRgn( hRgn, dc->hMetaRgn, 0, RGN_COPY ) != ERROR)
418             ret = 1;
419         release_dc_ptr( dc );
420     }
421     return ret;
422 }
423
424
425 /***********************************************************************
426  * GetRandomRgn [GDI32.@]
427  *
428  * NOTES
429  *     This function is documented in MSDN online for the case of
430  *     iCode == SYSRGN (4).
431  *
432  *     For iCode == 1 it should return the clip region
433  *                  2 "    "       "   the meta region
434  *                  3 "    "       "   the intersection of the clip with
435  *                                     the meta region (== 'Rao' region).
436  *
437  *     See http://www.codeproject.com/gdi/cliprgnguide.asp
438  */
439 INT WINAPI GetRandomRgn(HDC hDC, HRGN hRgn, INT iCode)
440 {
441     HRGN rgn;
442     DC *dc = get_dc_ptr( hDC );
443
444     if (!dc) return -1;
445
446     switch (iCode)
447     {
448     case 1:
449         rgn = dc->hClipRgn;
450         break;
451     case 2:
452         rgn = dc->hMetaRgn;
453         break;
454     case 3:
455         rgn = dc->hMetaClipRgn;
456         if(!rgn) rgn = dc->hClipRgn;
457         if(!rgn) rgn = dc->hMetaRgn;
458         break;
459     case SYSRGN: /* == 4 */
460         update_dc( dc );
461         rgn = dc->hVisRgn;
462         break;
463     default:
464         WARN("Unknown code %d\n", iCode);
465         release_dc_ptr( dc );
466         return -1;
467     }
468     if (rgn) CombineRgn( hRgn, rgn, 0, RGN_COPY );
469     release_dc_ptr( dc );
470
471     /* On Windows NT/2000, the SYSRGN returned is in screen coordinates */
472     if (iCode == SYSRGN && !(GetVersion() & 0x80000000))
473     {
474         POINT org;
475         GetDCOrgEx( hDC, &org );
476         OffsetRgn( hRgn, org.x, org.y );
477     }
478     return (rgn != 0);
479 }
480
481
482 /***********************************************************************
483  *           SetMetaRgn    (GDI32.@)
484  */
485 INT WINAPI SetMetaRgn( HDC hdc )
486 {
487     INT ret;
488     RECT dummy;
489     DC *dc = get_dc_ptr( hdc );
490
491     if (!dc) return ERROR;
492
493     if (dc->hMetaClipRgn)
494     {
495         /* the intersection becomes the new meta region */
496         DeleteObject( dc->hMetaRgn );
497         DeleteObject( dc->hClipRgn );
498         dc->hMetaRgn = dc->hMetaClipRgn;
499         dc->hClipRgn = 0;
500         dc->hMetaClipRgn = 0;
501     }
502     else if (dc->hClipRgn)
503     {
504         dc->hMetaRgn = dc->hClipRgn;
505         dc->hClipRgn = 0;
506     }
507     /* else nothing to do */
508
509     /* Note: no need to call CLIPPING_UpdateGCRegion, the overall clip region hasn't changed */
510
511     ret = GetRgnBox( dc->hMetaRgn, &dummy );
512     release_dc_ptr( dc );
513     return ret;
514 }