]> git.saurik.com Git - wxWidgets.git/blame_incremental - 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
... / ...
CommitLineData
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
36class wxGdkRegion
37{
38public:
39 wxGdkRegion() { m_region = gdk_region_new(); }
40 ~wxGdkRegion() { gdk_region_destroy(m_region); }
41
42 operator GdkRegion *() const { return m_region; }
43
44private:
45 GdkRegion *m_region;
46};
47
48#endif // __WXGTK20__
49
50// ----------------------------------------------------------------------------
51// wxRegionRefData: private class containing the information about the region
52// ----------------------------------------------------------------------------
53
54class wxRegionRefData : public wxObjectRefData
55{
56public:
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
88IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
89IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
90
91// ----------------------------------------------------------------------------
92// wxRegion construction
93// ----------------------------------------------------------------------------
94
95#define M_REGIONDATA ((wxRegionRefData *)m_refData)
96
97void 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
114wxRegion::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
124wxRegion::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
148wxRegion::~wxRegion()
149{
150 // m_refData unrefed in ~wxObject
151}
152
153wxObjectRefData *wxRegion::CreateRefData() const
154{
155 return new wxRegionRefData;
156}
157
158wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
159{
160 return new wxRegionRefData(*(wxRegionRefData *)data);
161}
162
163// ----------------------------------------------------------------------------
164// wxRegion comparison
165// ----------------------------------------------------------------------------
166
167bool 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
182void wxRegion::Clear()
183{
184 UnRef();
185}
186
187bool 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
221bool wxRegion::Union( const wxRect& rect )
222{
223 return Union( rect.x, rect.y, rect.width, rect.height );
224}
225
226bool 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
252bool 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
259bool wxRegion::Intersect( const wxRect& rect )
260{
261 wxRegion reg( rect );
262
263 return Intersect( reg );
264}
265
266bool 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
290bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
291{
292 wxRegion reg( x, y, width, height );
293 return Subtract( reg );
294}
295
296bool wxRegion::Subtract( const wxRect& rect )
297{
298 wxRegion reg( rect );
299 return Subtract( reg );
300}
301
302bool 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
326bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
327{
328 wxRegion reg( x, y, width, height );
329 return Xor( reg );
330}
331
332bool wxRegion::Xor( const wxRect& rect )
333{
334 wxRegion reg( rect );
335 return Xor( reg );
336}
337
338bool 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
361bool 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
377void 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
397wxRect 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
404bool wxRegion::Empty() const
405{
406 if (!m_refData)
407 return TRUE;
408
409 return gdk_region_empty( M_REGIONDATA->m_region );
410}
411
412wxRegionContain 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
423wxRegionContain 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
443wxRegionContain wxRegion::Contains(const wxPoint& pt) const
444{
445 return Contains( pt.x, pt.y );
446}
447
448wxRegionContain wxRegion::Contains(const wxRect& rect) const
449{
450 return Contains( rect.x, rect.y, rect.width, rect.height );
451}
452
453GdkRegion *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
475struct _XBox {
476 short x1, x2, y1, y2;
477};
478
479struct _XRegion {
480 long size , numRects;
481 _XBox *rects, extents;
482};
483
484#endif // GTK+ 1.x
485
486class wxRIRefData: public wxObjectRefData
487{
488public:
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
500wxRIRefData::~wxRIRefData()
501{
502 delete [] m_rects;
503}
504
505void 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
557wxRegionIterator::wxRegionIterator()
558{
559 m_refData = new wxRIRefData();
560 Reset();
561}
562
563wxRegionIterator::wxRegionIterator( const wxRegion& region )
564{
565 m_refData = new wxRIRefData();
566 Reset(region);
567}
568
569void wxRegionIterator::Reset( const wxRegion& region )
570{
571 m_region = region;
572 ((wxRIRefData*)m_refData)->CreateRects(region);
573 Reset();
574}
575
576bool wxRegionIterator::HaveRects() const
577{
578 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
579}
580
581wxRegionIterator& wxRegionIterator::operator ++ ()
582{
583 if (HaveRects())
584 ++m_current;
585
586 return *this;
587}
588
589wxRegionIterator wxRegionIterator::operator ++ (int)
590{
591 wxRegionIterator tmp = *this;
592 if (HaveRects())
593 ++m_current;
594
595 return tmp;
596}
597
598wxCoord 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
605wxCoord 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
612wxCoord 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
619wxCoord 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
626wxRect 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