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