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