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