compilation fixes - wxGTK compiles but not links
[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 wxList& list = *GetRectList();
355 wxNode *node = list.First();
356 while (node)
357 {
358 wxRect *r = (wxRect*)node->Data();
359
360 wxRegion regCopy = region;
361 if ( regCopy.IntersectRegionOnly(*r) )
362 {
363 // replace the node with the intersection
364 *r = regCopy.GetBox();
365 }
366 else
367 {
368 // TODO remove the rect from the list
369 r->width = 0;
370 r->height = 0;
371 }
372
373 node = node->Next();
374 }
375
376 return TRUE;
377 }
378
379 bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
380 {
381 wxRegion reg( x, y, width, height );
382 return Subtract( reg );
383 }
384
385 bool wxRegion::Subtract( const wxRect& rect )
386 {
387 wxRegion reg( rect );
388 return Subtract( reg );
389 }
390
391 bool wxRegion::Subtract( const wxRegion& region )
392 {
393 if (region.IsNull())
394 return FALSE;
395
396 if (!m_refData)
397 {
398 m_refData = new wxRegionRefData();
399 M_REGIONDATA->m_region = gdk_region_new();
400 }
401
402 Unshare();
403
404 #ifdef __WXGTK20__
405 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
406 #else
407 GdkRegion *reg = gdk_regions_subtract( M_REGIONDATA->m_region, region.GetRegion() );
408 gdk_region_destroy( M_REGIONDATA->m_region );
409 M_REGIONDATA->m_region = reg;
410 #endif
411
412 return TRUE;
413 }
414
415 bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
416 {
417 wxRegion reg( x, y, width, height );
418 return Xor( reg );
419 }
420
421 bool wxRegion::Xor( const wxRect& rect )
422 {
423 wxRegion reg( rect );
424 return Xor( reg );
425 }
426
427 bool wxRegion::Xor( const wxRegion& region )
428 {
429 if (region.IsNull())
430 return FALSE;
431
432 if (!m_refData)
433 {
434 m_refData = new wxRegionRefData();
435 M_REGIONDATA->m_region = gdk_region_new();
436 }
437 else
438 {
439 Unshare();
440 }
441
442 #ifdef __WXGTK20__
443 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
444 #else
445 GdkRegion *reg = gdk_regions_xor( M_REGIONDATA->m_region, region.GetRegion() );
446 gdk_region_destroy( M_REGIONDATA->m_region );
447 M_REGIONDATA->m_region = reg;
448 #endif
449
450 #if OLDCODE
451 wxNode *node = region.GetRectList()->First();
452 while (node)
453 {
454 wxRect *r = (wxRect*)node->Data();
455 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(r->x,r->y,r->width,r->height) );
456 node = node->Next();
457 }
458 #endif
459
460 return TRUE;
461 }
462
463 // ----------------------------------------------------------------------------
464 // wxRegion tests
465 // ----------------------------------------------------------------------------
466
467 void wxRegion::GetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
468 {
469 if ( m_refData )
470 {
471 GdkRectangle rect;
472 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
473 x = rect.x;
474 y = rect.y;
475 w = rect.width;
476 h = rect.height;
477 }
478 else
479 {
480 x = 0;
481 y = 0;
482 w = -1;
483 h = -1;
484 }
485 }
486
487 wxRect wxRegion::GetBox() const
488 {
489 wxCoord x, y, w, h;
490 GetBox( x, y, w, h );
491 return wxRect( x, y, w, h );
492 }
493
494 bool wxRegion::Empty() const
495 {
496 if (!m_refData)
497 return TRUE;
498
499 return gdk_region_empty( M_REGIONDATA->m_region );
500 }
501
502 wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y ) const
503 {
504 if (!m_refData)
505 return wxOutRegion;
506
507 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
508 return wxInRegion;
509 else
510 return wxOutRegion;
511 }
512
513 wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) const
514 {
515 if (!m_refData)
516 return wxOutRegion;
517
518 GdkRectangle rect;
519 rect.x = x;
520 rect.y = y;
521 rect.width = w;
522 rect.height = h;
523 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
524 switch (res)
525 {
526 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
527 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
528 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
529 }
530 return wxOutRegion;
531 }
532
533 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
534 {
535 return Contains( pt.x, pt.y );
536 }
537
538 wxRegionContain wxRegion::Contains(const wxRect& rect) const
539 {
540 return Contains( rect.x, rect.y, rect.width, rect.height );
541 }
542
543 GdkRegion *wxRegion::GetRegion() const
544 {
545 if (!m_refData)
546 return (GdkRegion*) NULL;
547
548 return M_REGIONDATA->m_region;
549 }
550
551 wxList *wxRegion::GetRectList() const
552 {
553 #if OLDCODE
554 if (!m_refData)
555 return (wxList*) NULL;
556
557 return &(M_REGIONDATA->m_rects);
558 #else
559 return (wxList*) NULL;
560 #endif
561 }
562
563 // ----------------------------------------------------------------------------
564 // wxRegionIterator
565 // ----------------------------------------------------------------------------
566
567 #if OLDCODE
568
569 wxRegionIterator::wxRegionIterator()
570 {
571 Reset();
572 }
573
574 wxRegionIterator::wxRegionIterator( const wxRegion& region )
575 {
576 Reset(region);
577 }
578
579 void wxRegionIterator::Reset( const wxRegion& region )
580 {
581 m_region = region;
582 Reset();
583 }
584
585 wxRegionIterator::operator bool () const
586 {
587 return m_region.GetRectList() && m_current < (size_t)m_region.GetRectList()->Number();
588 }
589
590 bool wxRegionIterator::HaveRects() const
591 {
592 return m_region.GetRectList() && m_current < (size_t)m_region.GetRectList()->Number();
593 }
594
595 void wxRegionIterator::operator ++ ()
596 {
597 if (HaveRects()) ++m_current;
598 }
599
600 void wxRegionIterator::operator ++ (int)
601 {
602 if (HaveRects()) ++m_current;
603 }
604
605 wxCoord wxRegionIterator::GetX() const
606 {
607 wxNode *node = m_region.GetRectList()->Nth( m_current );
608 if (!node) return 0;
609 wxRect *r = (wxRect*)node->Data();
610 return r->x;
611 }
612
613 wxCoord wxRegionIterator::GetY() const
614 {
615 wxNode *node = m_region.GetRectList()->Nth( m_current );
616 if (!node) return 0;
617 wxRect *r = (wxRect*)node->Data();
618 return r->y;
619 }
620
621 wxCoord wxRegionIterator::GetW() const
622 {
623 wxNode *node = m_region.GetRectList()->Nth( m_current );
624 if (!node) return 0;
625 wxRect *r = (wxRect*)node->Data();
626 return r->width;
627 }
628
629 wxCoord wxRegionIterator::GetH() const
630 {
631 wxNode *node = m_region.GetRectList()->Nth( m_current );
632 if (!node) return 0;
633 wxRect *r = (wxRect*)node->Data();
634 return r->height;
635 }
636
637 #else
638
639 // the following structures must match the private structures
640 // in X11 region code ( xc/lib/X11/region.h )
641
642 // this makes the Region type transparent
643 // and we have access to the region rectangles
644
645 struct _XBox {
646 short x1, x2, y1, y2;
647 };
648
649 struct _XRegion {
650 long size , numRects;
651 _XBox *rects, extents;
652 };
653
654 class wxRIRefData: public wxObjectRefData
655 {
656 public:
657
658 wxRIRefData() : m_rects(0), m_numRects(0){}
659 ~wxRIRefData();
660
661 wxRect *m_rects;
662 size_t m_numRects;
663
664 void CreateRects( const wxRegion& r );
665 };
666
667 wxRIRefData::~wxRIRefData()
668 {
669 delete m_rects;
670 }
671
672 #include <gdk/gdkprivate.h>
673
674 void wxRIRefData::CreateRects( const wxRegion& region )
675 {
676 if( m_rects )
677 delete m_rects;
678 m_rects = 0;
679 m_numRects= 0;
680 GdkRegion *gdkregion= region.GetRegion();
681 if( gdkregion ){
682 Region r= ((GdkRegionPrivate *)gdkregion)->xregion;
683 if( r ){
684 m_numRects= r->numRects;
685 if( m_numRects )
686 {
687 m_rects= new wxRect[m_numRects];
688 for( size_t i=0; i<m_numRects; ++i )
689 {
690 _XBox &xr= r->rects[i];
691 wxRect&wr= m_rects[i];
692 wr.x = xr.x1;
693 wr.y = xr.y1;
694 wr.width = xr.x2-xr.x1;
695 wr.height= xr.y2-xr.y1;
696 }
697 }
698 }
699 }
700 }
701
702 wxRegionIterator::wxRegionIterator()
703 {
704 m_refData = new wxRIRefData();
705 Reset();
706 }
707
708 wxRegionIterator::wxRegionIterator( const wxRegion& region )
709 {
710 m_refData = new wxRIRefData();
711 Reset(region);
712 }
713
714 void wxRegionIterator::Reset( const wxRegion& region )
715 {
716 m_region = region;
717 ((wxRIRefData*)m_refData)->CreateRects(region);
718 Reset();
719 }
720
721 bool wxRegionIterator::HaveRects() const
722 {
723 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
724 }
725
726 wxRegionIterator::operator bool () const
727 {
728 return HaveRects();
729 }
730
731 void wxRegionIterator::operator ++ ()
732 {
733 if (HaveRects()) ++m_current;
734 }
735
736 void wxRegionIterator::operator ++ (int)
737 {
738 if (HaveRects()) ++m_current;
739 }
740
741 wxCoord wxRegionIterator::GetX() const
742 {
743 if( !HaveRects() ) return 0;
744 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
745 }
746
747 wxCoord wxRegionIterator::GetY() const
748 {
749 if( !HaveRects() ) return 0;
750 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
751 }
752
753 wxCoord wxRegionIterator::GetW() const
754 {
755 if( !HaveRects() ) return -1;
756 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
757 }
758
759 wxCoord wxRegionIterator::GetH() const
760 {
761 if( !HaveRects() ) return -1;
762 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
763 }
764
765 wxRect wxRegionIterator::GetRect() const
766 {
767 wxRect r;
768 wxNode *node = m_region.GetRectList()->Nth( m_current );
769
770 if (node)
771 r = *((wxRect*)node->Data());
772
773 return r;
774 }
775
776 #endif
777