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