More GTK+ 1.3.1 fixes
[wxWidgets.git] / src / gtk1 / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/region.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "region.h"
12 #endif
13
14 #include "wx/region.h"
15
16 #include <gdk/gdk.h>
17 #include <gtk/gtk.h>
18
19 // Unfortunately the new way of implementing the region iterator
20 // doesn't work with GTK+ 2.0 or above (can't access a Region in
21 // GdkPrivateRegion)
22 #ifdef __WXGTK20__
23 #define OLDCODE 1
24 #else
25 #define OLDCODE 0
26 #endif
27
28 //-----------------------------------------------------------------------------
29 // wxRegion
30 //-----------------------------------------------------------------------------
31
32 class wxRegionRefData: public wxObjectRefData
33 {
34 public:
35 wxRegionRefData();
36 ~wxRegionRefData();
37
38 GdkRegion *m_region;
39 #if OLDCODE
40 wxList m_rects;
41 #endif
42 };
43
44 wxRegionRefData::wxRegionRefData()
45 {
46 m_region = (GdkRegion *) NULL;
47 }
48
49 wxRegionRefData::~wxRegionRefData()
50 {
51 if (m_region) gdk_region_destroy( m_region );
52
53 #if OLDCODE
54 wxNode *node = m_rects.First();
55 while (node)
56 {
57 wxRect *r = (wxRect*)node->Data();
58 delete r;
59 node = node->Next();
60 }
61 #endif
62 }
63
64 //-----------------------------------------------------------------------------
65
66 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
67
68 IMPLEMENT_DYNAMIC_CLASS(wxRegion,wxGDIObject);
69
70 wxRegion::wxRegion( wxCoord x, wxCoord y, wxCoord w, wxCoord h )
71 {
72 m_refData = new wxRegionRefData();
73 GdkRegion *reg = gdk_region_new();
74 GdkRectangle rect;
75 rect.x = x;
76 rect.y = y;
77 rect.width = w;
78 rect.height = h;
79 #ifdef __WXGTK20__
80 gdk_region_union_with_rect( reg, &rect );
81 M_REGIONDATA->m_region = reg;
82 #else
83 M_REGIONDATA->m_region = gdk_region_union_with_rect( reg, &rect );
84 gdk_region_destroy( reg );
85 #endif
86 #if OLDCODE
87 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(x,y,w,h) );
88 #endif
89 }
90
91 wxRegion::wxRegion( const wxPoint& topLeft, const wxPoint& bottomRight )
92 {
93 m_refData = new wxRegionRefData();
94 GdkRegion *reg = gdk_region_new();
95 GdkRectangle rect;
96 rect.x = topLeft.x;
97 rect.y = topLeft.y;
98 rect.width = bottomRight.x - rect.x;
99 rect.height = bottomRight.y - rect.y;
100 #ifdef __WXGTK20__
101 gdk_region_union_with_rect( reg, &rect );
102 M_REGIONDATA->m_region = reg;
103 #else
104 M_REGIONDATA->m_region = gdk_region_union_with_rect( reg, &rect );
105 gdk_region_destroy( reg );
106 #endif
107 #if OLDCODE
108 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(topLeft,bottomRight) );
109 #endif
110 }
111
112 wxRegion::wxRegion( const wxRect& rect )
113 {
114 m_refData = new wxRegionRefData();
115 GdkRegion *reg = gdk_region_new();
116 GdkRectangle g_rect;
117 g_rect.x = rect.x;
118 g_rect.y = rect.y;
119 g_rect.width = rect.width;
120 g_rect.height = rect.height;
121 #ifdef __WXGTK20__
122 gdk_region_union_with_rect( reg, &g_rect );
123 M_REGIONDATA->m_region = reg;
124 #else
125 M_REGIONDATA->m_region = gdk_region_union_with_rect( reg, &g_rect );
126 gdk_region_destroy( reg );
127 #endif
128 #if OLDCODE
129 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(rect.x,rect.y,rect.width,rect.height) );
130 #endif
131 }
132
133 wxRegion::wxRegion()
134 {
135 }
136
137 wxRegion::~wxRegion()
138 {
139 }
140
141 bool wxRegion::operator == ( const wxRegion& region )
142 {
143 return m_refData == region.m_refData;
144 }
145
146 bool wxRegion::operator != ( const wxRegion& region )
147 {
148 return m_refData != region.m_refData;
149 }
150
151 void wxRegion::Clear()
152 {
153 UnRef();
154 }
155
156 bool wxRegion::Union( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
157 {
158 GdkRectangle rect;
159 rect.x = x;
160 rect.y = y;
161 rect.width = width;
162 rect.height = height;
163 if (!m_refData)
164 {
165 m_refData = new wxRegionRefData();
166 GdkRegion *reg = gdk_region_new();
167 #ifdef __WXGTK20__
168 gdk_region_union_with_rect( reg, &rect );
169 M_REGIONDATA->m_region = reg;
170 #else
171 M_REGIONDATA->m_region = gdk_region_union_with_rect( reg, &rect );
172 gdk_region_destroy( reg );
173 #endif
174 }
175 else
176 {
177 #ifdef __WXGTK20__
178 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
179 #else
180 GdkRegion *reg = gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
181 gdk_region_destroy( M_REGIONDATA->m_region );
182 M_REGIONDATA->m_region = reg;
183 #endif
184 }
185
186 #if OLDCODE
187 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(x,y,width,height) );
188 #endif
189
190 return TRUE;
191 }
192
193 bool wxRegion::Union( const wxRect& rect )
194 {
195 return Union( rect.x, rect.y, rect.width, rect.height );
196 }
197
198 bool wxRegion::Union( const wxRegion& region )
199 {
200 if (region.IsNull())
201 return FALSE;
202
203 if (!m_refData)
204 {
205 m_refData = new wxRegionRefData();
206 M_REGIONDATA->m_region = gdk_region_new();
207 }
208
209 #ifdef __WXGTK20__
210 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
211 #else
212 GdkRegion *reg = gdk_regions_union( M_REGIONDATA->m_region, region.GetRegion() );
213 gdk_region_destroy( M_REGIONDATA->m_region );
214 M_REGIONDATA->m_region = reg;
215 #endif
216
217 #if OLDCODE
218 wxNode *node = region.GetRectList()->First();
219 while (node)
220 {
221 wxRect *r = (wxRect*)node->Data();
222 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(r->x,r->y,r->width,r->height) );
223 node = node->Next();
224 }
225 #endif
226
227 return TRUE;
228 }
229
230 bool wxRegion::Intersect( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
231 {
232 if (!m_refData)
233 {
234 m_refData = new wxRegionRefData();
235 M_REGIONDATA->m_region = gdk_region_new();
236 }
237
238 wxRegion reg( x, y, width, height );
239 Intersect( reg );
240 return TRUE;
241 }
242
243 bool wxRegion::Intersect( const wxRect& rect )
244 {
245 if (!m_refData)
246 {
247 m_refData = new wxRegionRefData();
248 M_REGIONDATA->m_region = gdk_region_new();
249 }
250
251 wxRegion reg( rect );
252 Intersect( reg );
253 return TRUE;
254 }
255
256 bool wxRegion::Intersect( const wxRegion& region )
257 {
258 if (region.IsNull())
259 return FALSE;
260
261 if (!m_refData)
262 {
263 m_refData = new wxRegionRefData();
264 M_REGIONDATA->m_region = gdk_region_new();
265 return TRUE;
266 }
267
268 #ifdef __WXGTK20__
269 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
270 #else
271 GdkRegion *reg = gdk_regions_intersect( M_REGIONDATA->m_region, region.GetRegion() );
272 gdk_region_destroy( M_REGIONDATA->m_region );
273 M_REGIONDATA->m_region = reg;
274 #endif
275 return TRUE;
276 }
277
278 bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
279 {
280 if (!m_refData)
281 {
282 m_refData = new wxRegionRefData();
283 M_REGIONDATA->m_region = gdk_region_new();
284 }
285
286 wxRegion reg( x, y, width, height );
287 Subtract( reg );
288 return TRUE;
289 }
290
291 bool wxRegion::Subtract( const wxRect& rect )
292 {
293 if (!m_refData)
294 {
295 m_refData = new wxRegionRefData();
296 M_REGIONDATA->m_region = gdk_region_new();
297 }
298
299 wxRegion reg( rect );
300 Subtract( reg );
301 return TRUE;
302 }
303
304 bool wxRegion::Subtract( const wxRegion& region )
305 {
306 if (region.IsNull())
307 return FALSE;
308
309 if (!m_refData)
310 {
311 m_refData = new wxRegionRefData();
312 M_REGIONDATA->m_region = gdk_region_new();
313 }
314
315 #ifdef __WXGTK20__
316 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
317 #else
318 GdkRegion *reg = gdk_regions_subtract( M_REGIONDATA->m_region, region.GetRegion() );
319 gdk_region_destroy( M_REGIONDATA->m_region );
320 M_REGIONDATA->m_region = reg;
321 #endif
322 return TRUE;
323 }
324
325 bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
326 {
327 if (!m_refData)
328 {
329 m_refData = new wxRegionRefData();
330 M_REGIONDATA->m_region = gdk_region_new();
331 }
332
333 wxRegion reg( x, y, width, height );
334 Xor( reg );
335 return TRUE;
336 }
337
338 bool wxRegion::Xor( const wxRect& rect )
339 {
340 if (!m_refData)
341 {
342 m_refData = new wxRegionRefData();
343 M_REGIONDATA->m_region = gdk_region_new();
344 }
345
346 wxRegion reg( rect );
347 Xor( reg );
348 return TRUE;
349 }
350
351 bool wxRegion::Xor( const wxRegion& region )
352 {
353 if (region.IsNull())
354 return FALSE;
355
356 if (!m_refData)
357 {
358 m_refData = new wxRegionRefData();
359 M_REGIONDATA->m_region = gdk_region_new();
360 }
361
362 #ifdef __WXGTK20__
363 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
364 #else
365 GdkRegion *reg = gdk_regions_xor( M_REGIONDATA->m_region, region.GetRegion() );
366 gdk_region_destroy( M_REGIONDATA->m_region );
367 M_REGIONDATA->m_region = reg;
368 #endif
369
370 #if OLDCODE
371 wxNode *node = region.GetRectList()->First();
372 while (node)
373 {
374 wxRect *r = (wxRect*)node->Data();
375 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(r->x,r->y,r->width,r->height) );
376 node = node->Next();
377 }
378 #endif
379
380 return TRUE;
381 }
382
383 void wxRegion::GetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
384 {
385 x = 0;
386 y = 0;
387 w = -1;
388 h = -1;
389 if (!m_refData)
390 return;
391
392 GdkRectangle rect;
393 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
394 x = rect.x;
395 y = rect.y;
396 w = rect.width;
397 h = rect.height;
398 }
399
400 wxRect wxRegion::GetBox() const
401 {
402 wxCoord x = 0;
403 wxCoord y = 0;
404 wxCoord w = -1;
405 wxCoord h = -1;
406 GetBox( x, y, w, h );
407 return wxRect( x, y, w, h );
408 }
409
410 bool wxRegion::Empty() const
411 {
412 if (!m_refData)
413 return TRUE;
414
415 return gdk_region_empty( M_REGIONDATA->m_region );
416 }
417
418 wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y ) const
419 {
420 if (!m_refData)
421 return wxOutRegion;
422
423 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
424 return wxInRegion;
425 else
426 return wxOutRegion;
427 }
428
429 wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) const
430 {
431 if (!m_refData)
432 return wxOutRegion;
433
434 GdkRectangle rect;
435 rect.x = x;
436 rect.y = y;
437 rect.width = w;
438 rect.height = h;
439 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
440 switch (res)
441 {
442 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
443 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
444 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
445 }
446 return wxOutRegion;
447 }
448
449 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
450 {
451 return Contains( pt.x, pt.y );
452 }
453
454 wxRegionContain wxRegion::Contains(const wxRect& rect) const
455 {
456 return Contains( rect.x, rect.y, rect.width, rect.height );
457 }
458
459 GdkRegion *wxRegion::GetRegion() const
460 {
461 if (!m_refData)
462 return (GdkRegion*) NULL;
463
464 return M_REGIONDATA->m_region;
465 }
466
467 wxList *wxRegion::GetRectList() const
468 {
469 #if OLDCODE
470 if (!m_refData)
471 return (wxList*) NULL;
472
473 return &(M_REGIONDATA->m_rects);
474 #else
475 return (wxList*) NULL;
476 #endif
477 }
478
479 //-----------------------------------------------------------------------------
480 // wxRegionIterator
481 //-----------------------------------------------------------------------------
482
483 #if OLDCODE
484
485 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject);
486
487 wxRegionIterator::wxRegionIterator()
488 {
489 Reset();
490 }
491
492 wxRegionIterator::wxRegionIterator( const wxRegion& region )
493 {
494 Reset(region);
495 }
496
497 void wxRegionIterator::Reset( const wxRegion& region )
498 {
499 m_region = region;
500 Reset();
501 }
502
503 wxRegionIterator::operator bool () const
504 {
505 return m_region.GetRectList() && m_current < (size_t)m_region.GetRectList()->Number();
506 }
507
508 bool wxRegionIterator::HaveRects() const
509 {
510 return m_region.GetRectList() && m_current < (size_t)m_region.GetRectList()->Number();
511 }
512
513 void wxRegionIterator::operator ++ ()
514 {
515 if (HaveRects()) ++m_current;
516 }
517
518 void wxRegionIterator::operator ++ (int)
519 {
520 if (HaveRects()) ++m_current;
521 }
522
523 wxCoord wxRegionIterator::GetX() const
524 {
525 wxNode *node = m_region.GetRectList()->Nth( m_current );
526 if (!node) return 0;
527 wxRect *r = (wxRect*)node->Data();
528 return r->x;
529 }
530
531 wxCoord wxRegionIterator::GetY() const
532 {
533 wxNode *node = m_region.GetRectList()->Nth( m_current );
534 if (!node) return 0;
535 wxRect *r = (wxRect*)node->Data();
536 return r->y;
537 }
538
539 wxCoord wxRegionIterator::GetW() const
540 {
541 wxNode *node = m_region.GetRectList()->Nth( m_current );
542 if (!node) return 0;
543 wxRect *r = (wxRect*)node->Data();
544 return r->width;
545 }
546
547 wxCoord wxRegionIterator::GetH() const
548 {
549 wxNode *node = m_region.GetRectList()->Nth( m_current );
550 if (!node) return 0;
551 wxRect *r = (wxRect*)node->Data();
552 return r->height;
553 }
554
555 #else
556
557 // the following structures must match the private structures
558 // in X11 region code ( xc/lib/X11/region.h )
559
560 // this makes the Region type transparent
561 // and we have access to the region rectangles
562
563 struct _XBox {
564 short x1, x2, y1, y2;
565 };
566
567 struct _XRegion {
568 long size , numRects;
569 _XBox *rects, extents;
570 };
571
572 class wxRIRefData: public wxObjectRefData
573 {
574 public:
575
576 wxRIRefData() : m_rects(0), m_numRects(0){}
577 ~wxRIRefData();
578
579 wxRect *m_rects;
580 size_t m_numRects;
581
582 void CreateRects( const wxRegion& r );
583 };
584
585 wxRIRefData::~wxRIRefData()
586 {
587 delete m_rects;
588 }
589
590 #include <gdk/gdkprivate.h>
591
592 void wxRIRefData::CreateRects( const wxRegion& region )
593 {
594 if( m_rects )
595 delete m_rects;
596 m_rects = 0;
597 m_numRects= 0;
598 GdkRegion *gdkregion= region.GetRegion();
599 if( gdkregion ){
600 Region r= ((GdkRegionPrivate *)gdkregion)->xregion;
601 if( r ){
602 m_numRects= r->numRects;
603 if( m_numRects )
604 {
605 m_rects= new wxRect[m_numRects];
606 for( size_t i=0; i<m_numRects; ++i )
607 {
608 _XBox &xr= r->rects[i];
609 wxRect&wr= m_rects[i];
610 wr.x = xr.x1;
611 wr.y = xr.y1;
612 wr.width = xr.x2-xr.x1;
613 wr.height= xr.y2-xr.y1;
614 }
615 }
616 }
617 }
618 }
619
620 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject);
621
622 wxRegionIterator::wxRegionIterator()
623 {
624 m_refData = new wxRIRefData();
625 Reset();
626 }
627
628 wxRegionIterator::wxRegionIterator( const wxRegion& region )
629 {
630 m_refData = new wxRIRefData();
631 Reset(region);
632 }
633
634 void wxRegionIterator::Reset( const wxRegion& region )
635 {
636 m_region = region;
637 ((wxRIRefData*)m_refData)->CreateRects(region);
638 Reset();
639 }
640
641 bool wxRegionIterator::HaveRects() const
642 {
643 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
644 }
645
646 wxRegionIterator::operator bool () const
647 {
648 return HaveRects();
649 }
650
651 void wxRegionIterator::operator ++ ()
652 {
653 if (HaveRects()) ++m_current;
654 }
655
656 void wxRegionIterator::operator ++ (int)
657 {
658 if (HaveRects()) ++m_current;
659 }
660
661 wxCoord wxRegionIterator::GetX() const
662 {
663 if( !HaveRects() ) return 0;
664 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
665 }
666
667 wxCoord wxRegionIterator::GetY() const
668 {
669 if( !HaveRects() ) return 0;
670 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
671 }
672
673 wxCoord wxRegionIterator::GetW() const
674 {
675 if( !HaveRects() ) return -1;
676 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
677 }
678
679 wxCoord wxRegionIterator::GetH() const
680 {
681 if( !HaveRects() ) return -1;
682 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
683 }
684
685 #endif
686