]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/region.cpp
Fix mem leak.
[wxWidgets.git] / src / gtk / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/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 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifndef WX_PRECOMP
23 #include "wx/log.h"
24 #endif
25
26 #include "wx/region.h"
27 #include "wx/gtk/private.h"
28
29
30 // ----------------------------------------------------------------------------
31 // wxRegionRefData: private class containing the information about the region
32 // ----------------------------------------------------------------------------
33
34 class wxRegionRefData : public wxObjectRefData
35 {
36 public:
37 wxRegionRefData()
38 {
39 m_region = NULL;
40 }
41
42 wxRegionRefData(const wxRegionRefData& refData)
43 : wxObjectRefData()
44 {
45 m_region = gdk_region_copy(refData.m_region);
46 }
47
48 ~wxRegionRefData()
49 {
50 if (m_region)
51 gdk_region_destroy( m_region );
52 }
53
54 GdkRegion *m_region;
55 };
56
57 // ----------------------------------------------------------------------------
58 // macros
59 // ----------------------------------------------------------------------------
60
61 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
62 #define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData))
63
64 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
65 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
66
67 // ----------------------------------------------------------------------------
68 // wxRegion construction
69 // ----------------------------------------------------------------------------
70
71 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
72
73 void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
74 {
75 GdkRectangle rect;
76 rect.x = x;
77 rect.y = y;
78 rect.width = w;
79 rect.height = h;
80
81 m_refData = new wxRegionRefData();
82
83 M_REGIONDATA->m_region = gdk_region_rectangle( &rect );
84 }
85
86 wxRegion::wxRegion( GdkRegion *region )
87 {
88 m_refData = new wxRegionRefData();
89 M_REGIONDATA->m_region = gdk_region_copy( region );
90 }
91
92 wxRegion::wxRegion( size_t n, const wxPoint *points, int fillStyle )
93 {
94 GdkPoint *gdkpoints = new GdkPoint[n];
95 for ( size_t i = 0 ; i < n ; i++ )
96 {
97 gdkpoints[i].x = points[i].x;
98 gdkpoints[i].y = points[i].y;
99 }
100
101 m_refData = new wxRegionRefData();
102
103 GdkRegion* reg = gdk_region_polygon
104 (
105 gdkpoints,
106 n,
107 fillStyle == wxWINDING_RULE ? GDK_WINDING_RULE
108 : GDK_EVEN_ODD_RULE
109 );
110
111 M_REGIONDATA->m_region = reg;
112
113 delete [] gdkpoints;
114 }
115
116 wxRegion::~wxRegion()
117 {
118 // m_refData unrefed in ~wxObject
119 }
120
121 wxObjectRefData *wxRegion::CreateRefData() const
122 {
123 return new wxRegionRefData;
124 }
125
126 wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
127 {
128 return new wxRegionRefData(*(wxRegionRefData *)data);
129 }
130
131 // ----------------------------------------------------------------------------
132 // wxRegion comparison
133 // ----------------------------------------------------------------------------
134
135 bool wxRegion::operator==( const wxRegion& region ) const
136 {
137 if (m_refData == region.m_refData) return TRUE;
138
139 if (!m_refData || !region.m_refData) return FALSE;
140
141 // compare the regions themselves, not the pointers to ref data!
142 return gdk_region_equal(M_REGIONDATA->m_region,
143 M_REGIONDATA_OF(region)->m_region);
144 }
145
146 // ----------------------------------------------------------------------------
147 // wxRegion operations
148 // ----------------------------------------------------------------------------
149
150 void wxRegion::Clear()
151 {
152 UnRef();
153 }
154
155 bool wxRegion::Union( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
156 {
157 // workaround for a strange GTK/X11 bug: taking union with an empty
158 // rectangle results in an empty region which is definitely not what we
159 // want
160 if ( !width || !height )
161 return TRUE;
162
163 if ( !m_refData )
164 {
165 InitRect(x, y, width, height);
166 }
167 else
168 {
169 AllocExclusive();
170
171 GdkRectangle rect;
172 rect.x = x;
173 rect.y = y;
174 rect.width = width;
175 rect.height = height;
176
177 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
178 }
179
180 return TRUE;
181 }
182
183 bool wxRegion::Union( const wxRect& rect )
184 {
185 return Union( rect.x, rect.y, rect.width, rect.height );
186 }
187
188 bool wxRegion::Union( const wxRegion& region )
189 {
190 if (region.IsNull())
191 return FALSE;
192
193 if (!m_refData)
194 {
195 m_refData = new wxRegionRefData();
196 M_REGIONDATA->m_region = gdk_region_new();
197 }
198 else
199 {
200 AllocExclusive();
201 }
202
203 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
204
205 return TRUE;
206 }
207
208 bool wxRegion::Intersect( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
209 {
210 wxRegion reg( x, y, width, height );
211
212 return Intersect( reg );
213 }
214
215 bool wxRegion::Intersect( const wxRect& rect )
216 {
217 wxRegion reg( rect );
218
219 return Intersect( reg );
220 }
221
222 bool wxRegion::Intersect( const wxRegion& region )
223 {
224 if (region.IsNull())
225 return FALSE;
226
227 if (!m_refData)
228 {
229 // intersecting with invalid region doesn't make sense
230 return FALSE;
231 }
232
233 AllocExclusive();
234
235 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
236
237 return TRUE;
238 }
239
240 bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
241 {
242 wxRegion reg( x, y, width, height );
243 return Subtract( reg );
244 }
245
246 bool wxRegion::Subtract( const wxRect& rect )
247 {
248 wxRegion reg( rect );
249 return Subtract( reg );
250 }
251
252 bool wxRegion::Subtract( const wxRegion& region )
253 {
254 if (region.IsNull())
255 return FALSE;
256
257 if (!m_refData)
258 {
259 // subtracting from an invalid region doesn't make sense
260 return FALSE;
261 }
262
263 AllocExclusive();
264
265 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
266
267 return TRUE;
268 }
269
270 bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
271 {
272 wxRegion reg( x, y, width, height );
273 return Xor( reg );
274 }
275
276 bool wxRegion::Xor( const wxRect& rect )
277 {
278 wxRegion reg( rect );
279 return Xor( reg );
280 }
281
282 bool wxRegion::Xor( const wxRegion& region )
283 {
284 if (region.IsNull())
285 return FALSE;
286
287 if (!m_refData)
288 {
289 return FALSE;
290 }
291
292 AllocExclusive();
293
294 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
295
296 return TRUE;
297 }
298
299 bool wxRegion::Offset( wxCoord x, wxCoord y )
300 {
301 if (!m_refData)
302 return FALSE;
303
304 AllocExclusive();
305
306 gdk_region_offset( M_REGIONDATA->m_region, x, y );
307
308 return TRUE;
309 }
310
311 // ----------------------------------------------------------------------------
312 // wxRegion tests
313 // ----------------------------------------------------------------------------
314
315 void wxRegion::GetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
316 {
317 if ( m_refData )
318 {
319 GdkRectangle rect;
320 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
321 x = rect.x;
322 y = rect.y;
323 w = rect.width;
324 h = rect.height;
325 }
326 else
327 {
328 x = 0;
329 y = 0;
330 w = -1;
331 h = -1;
332 }
333 }
334
335 wxRect wxRegion::GetBox() const
336 {
337 wxCoord x, y, w, h;
338 GetBox( x, y, w, h );
339 return wxRect( x, y, w, h );
340 }
341
342 bool wxRegion::Empty() const
343 {
344 if (!m_refData)
345 return TRUE;
346
347 return gdk_region_empty( M_REGIONDATA->m_region );
348 }
349
350 wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y ) const
351 {
352 if (!m_refData)
353 return wxOutRegion;
354
355 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
356 return wxInRegion;
357 else
358 return wxOutRegion;
359 }
360
361 wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) const
362 {
363 if (!m_refData)
364 return wxOutRegion;
365
366 GdkRectangle rect;
367 rect.x = x;
368 rect.y = y;
369 rect.width = w;
370 rect.height = h;
371 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
372 switch (res)
373 {
374 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
375 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
376 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
377 }
378 return wxOutRegion;
379 }
380
381 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
382 {
383 return Contains( pt.x, pt.y );
384 }
385
386 wxRegionContain wxRegion::Contains(const wxRect& rect) const
387 {
388 return Contains( rect.x, rect.y, rect.width, rect.height );
389 }
390
391 GdkRegion *wxRegion::GetRegion() const
392 {
393 if (!m_refData)
394 return (GdkRegion*) NULL;
395
396 return M_REGIONDATA->m_region;
397 }
398
399 // ----------------------------------------------------------------------------
400 // wxRegionIterator
401 // ----------------------------------------------------------------------------
402
403 class wxRIRefData: public wxObjectRefData
404 {
405 public:
406 wxRIRefData() { Init(); }
407 virtual ~wxRIRefData();
408
409 void CreateRects( const wxRegion& r );
410
411 void Init() { m_rects = NULL; m_numRects = 0; }
412
413 wxRect *m_rects;
414 size_t m_numRects;
415 };
416
417 wxRIRefData::~wxRIRefData()
418 {
419 delete [] m_rects;
420 }
421
422 void wxRIRefData::CreateRects( const wxRegion& region )
423 {
424 delete [] m_rects;
425
426 Init();
427
428 GdkRegion *gdkregion = region.GetRegion();
429 if (!gdkregion)
430 return;
431
432 GdkRectangle *gdkrects = NULL;
433 gint numRects = 0;
434 gdk_region_get_rectangles( gdkregion, &gdkrects, &numRects );
435
436 m_numRects = numRects;
437 if (numRects)
438 {
439 m_rects = new wxRect[m_numRects];
440 for (size_t i=0; i < m_numRects; ++i)
441 {
442 GdkRectangle &gr = gdkrects[i];
443 wxRect &wr = m_rects[i];
444 wr.x = gr.x;
445 wr.y = gr.y;
446 wr.width = gr.width;
447 wr.height = gr.height;
448 }
449 }
450 g_free( gdkrects );
451 }
452
453 wxRegionIterator::wxRegionIterator()
454 {
455 m_refData = new wxRIRefData();
456 Reset();
457 }
458
459 wxRegionIterator::wxRegionIterator( const wxRegion& region )
460 {
461 m_refData = new wxRIRefData();
462 Reset(region);
463 }
464
465 void wxRegionIterator::Reset( const wxRegion& region )
466 {
467 m_region = region;
468 ((wxRIRefData*)m_refData)->CreateRects(region);
469 Reset();
470 }
471
472 bool wxRegionIterator::HaveRects() const
473 {
474 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
475 }
476
477 wxRegionIterator& wxRegionIterator::operator ++ ()
478 {
479 if (HaveRects())
480 ++m_current;
481
482 return *this;
483 }
484
485 wxRegionIterator wxRegionIterator::operator ++ (int)
486 {
487 wxRegionIterator tmp = *this;
488 if (HaveRects())
489 ++m_current;
490
491 return tmp;
492 }
493
494 wxCoord wxRegionIterator::GetX() const
495 {
496 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
497
498 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
499 }
500
501 wxCoord wxRegionIterator::GetY() const
502 {
503 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
504
505 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
506 }
507
508 wxCoord wxRegionIterator::GetW() const
509 {
510 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
511
512 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
513 }
514
515 wxCoord wxRegionIterator::GetH() const
516 {
517 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
518
519 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
520 }
521
522 wxRect wxRegionIterator::GetRect() const
523 {
524 wxRect r;
525 if( HaveRects() )
526 r = ((wxRIRefData*)m_refData)->m_rects[m_current];
527
528 return r;
529 }