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