]> git.saurik.com Git - wxWidgets.git/blame - 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
c801d85f 1/////////////////////////////////////////////////////////////////////////////
5fc7ede9 2// Name: gtk/region.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
9fe4c99c 5// Modified: VZ at 05.10.00: use AllocExclusive(), comparison fixed
f96aa4d9
RR
6// Id: $Id$
7// Copyright: (c) 1998 Robert Roebling
65571936 8// Licence: wxWindows licence
c801d85f
KB
9/////////////////////////////////////////////////////////////////////////////
10
1e6feb95
VZ
11// ============================================================================
12// declarations
13// ============================================================================
14
14f355c2 15#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
1e6feb95 16 #pragma implementation "region.h"
c801d85f
KB
17#endif
18
1e6feb95
VZ
19// ----------------------------------------------------------------------------
20// headers
21// ----------------------------------------------------------------------------
22
14f355c2
VS
23// For compilers that support precompilation, includes "wx.h".
24#include "wx/wxprec.h"
25
9e691f46 26#include "wx/region.h"
e1bf3ad3 27#include "wx/log.h"
9e691f46 28#include "wx/gtk/private.h"
1e6feb95 29
57f2b902
VZ
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
1e6feb95
VZ
50// ----------------------------------------------------------------------------
51// wxRegionRefData: private class containing the information about the region
52// ----------------------------------------------------------------------------
c801d85f 53
1e6feb95 54class wxRegionRefData : public wxObjectRefData
c801d85f 55{
864e8bd0 56public:
48850fa7
RR
57 wxRegionRefData()
58 {
59 m_region = NULL;
60 }
57f2b902 61
48850fa7 62 wxRegionRefData(const wxRegionRefData& refData)
d84afea9 63 : wxObjectRefData()
48850fa7
RR
64 {
65#ifdef __WXGTK20__
66 m_region = gdk_region_copy(refData.m_region);
67#else
57f2b902 68 m_region = gdk_regions_union(wxGdkRegion(), refData.m_region);
48850fa7
RR
69#endif
70 }
57f2b902 71
48850fa7
RR
72 ~wxRegionRefData()
73 {
74 if (m_region)
75 gdk_region_destroy( m_region );
76 }
5fc7ede9 77
c801d85f
KB
78 GdkRegion *m_region;
79};
80
1e6feb95
VZ
81// ----------------------------------------------------------------------------
82// macros
83// ----------------------------------------------------------------------------
84
85#define M_REGIONDATA ((wxRegionRefData *)m_refData)
86#define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData))
87
d84afea9
GD
88IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
89IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
1e6feb95 90
1e6feb95
VZ
91// ----------------------------------------------------------------------------
92// wxRegion construction
93// ----------------------------------------------------------------------------
c801d85f
KB
94
95#define M_REGIONDATA ((wxRegionRefData *)m_refData)
96
9fe4c99c 97void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
c801d85f 98{
bbe0af5b
RR
99 GdkRectangle rect;
100 rect.x = x;
101 rect.y = y;
102 rect.width = w;
103 rect.height = h;
57f2b902 104
48850fa7 105 m_refData = new wxRegionRefData();
57f2b902 106
b7c2d6ff 107#ifdef __WXGTK20__
9e691f46 108 M_REGIONDATA->m_region = gdk_region_rectangle( &rect );
b7c2d6ff 109#else
57f2b902 110 M_REGIONDATA->m_region = gdk_region_union_with_rect( wxGdkRegion(), &rect );
b7c2d6ff 111#endif
ff7b1510 112}
c801d85f 113
b15ed747
RR
114wxRegion::wxRegion( GdkRegion *region )
115{
116 m_refData = new wxRegionRefData();
57f2b902 117#ifdef __WXGTK20__
b15ed747 118 M_REGIONDATA->m_region = gdk_region_copy( region );
57f2b902
VZ
119#else
120 M_REGIONDATA->m_region = gdk_regions_union(wxGdkRegion(), region);
121#endif
b15ed747
RR
122}
123
5549e9f7
VZ
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
1e6feb95 148wxRegion::~wxRegion()
c801d85f 149{
e0f0b197 150 // m_refData unrefed in ~wxObject
ff7b1510 151}
c801d85f 152
e0f0b197
RR
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}
c89f5c02 162
9fe4c99c
VZ
163// ----------------------------------------------------------------------------
164// wxRegion comparison
165// ----------------------------------------------------------------------------
166
1e6feb95 167bool wxRegion::operator==( const wxRegion& region )
c801d85f 168{
c89f5c02
RR
169 if (m_refData == region.m_refData) return TRUE;
170
171 if (!m_refData || !region.m_refData) return FALSE;
57f2b902 172
9fe4c99c 173 // compare the regions themselves, not the pointers to ref data!
1e6feb95
VZ
174 return gdk_region_equal(M_REGIONDATA->m_region,
175 M_REGIONDATA_OF(region)->m_region);
ff7b1510 176}
c801d85f 177
1e6feb95
VZ
178// ----------------------------------------------------------------------------
179// wxRegion operations
180// ----------------------------------------------------------------------------
181
bf57d1ad 182void wxRegion::Clear()
c801d85f 183{
bbe0af5b 184 UnRef();
ff7b1510 185}
c801d85f 186
5fc7ede9 187bool wxRegion::Union( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 188{
57351df0
VZ
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
2b5f62a0 195 if ( !m_refData )
e1208c31 196 {
2b5f62a0 197 InitRect(x, y, width, height);
e1208c31
RR
198 }
199 else
200 {
9fe4c99c 201 AllocExclusive();
1e6feb95 202
2b5f62a0
VZ
203 GdkRectangle rect;
204 rect.x = x;
205 rect.y = y;
206 rect.width = width;
207 rect.height = height;
208
b7c2d6ff
OK
209#ifdef __WXGTK20__
210 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
211#else
e1208c31
RR
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;
b7c2d6ff 215#endif
e1208c31 216 }
1e6feb95 217
bbe0af5b 218 return TRUE;
ff7b1510 219}
c801d85f
KB
220
221bool wxRegion::Union( const wxRect& rect )
222{
e1208c31 223 return Union( rect.x, rect.y, rect.width, rect.height );
ff7b1510 224}
c801d85f
KB
225
226bool wxRegion::Union( const wxRegion& region )
227{
e1208c31
RR
228 if (region.IsNull())
229 return FALSE;
230
48850fa7
RR
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 }
e1208c31 240
b7c2d6ff
OK
241#ifdef __WXGTK20__
242 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
243#else
bbe0af5b
RR
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;
b7c2d6ff 247#endif
5fc7ede9 248
bbe0af5b 249 return TRUE;
ff7b1510 250}
c801d85f 251
5fc7ede9 252bool wxRegion::Intersect( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 253{
bbe0af5b 254 wxRegion reg( x, y, width, height );
1e6feb95
VZ
255
256 return Intersect( reg );
ff7b1510 257}
c801d85f
KB
258
259bool wxRegion::Intersect( const wxRect& rect )
260{
bbe0af5b 261 wxRegion reg( rect );
57f2b902 262
1e6feb95 263 return Intersect( reg );
ff7b1510 264}
c801d85f 265
1e6feb95 266bool wxRegion::Intersect( const wxRegion& region )
c801d85f 267{
1e6feb95
VZ
268 if (region.IsNull())
269 return FALSE;
270
e1208c31
RR
271 if (!m_refData)
272 {
2b5f62a0
VZ
273 // intersecting with invalid region doesn't make sense
274 return FALSE;
1e6feb95
VZ
275 }
276
2b5f62a0
VZ
277 AllocExclusive();
278
48850fa7
RR
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
9fe4c99c 286
bbe0af5b 287 return TRUE;
ff7b1510 288}
c801d85f 289
1e6feb95 290bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 291{
1e6feb95
VZ
292 wxRegion reg( x, y, width, height );
293 return Subtract( reg );
294}
e1208c31 295
1e6feb95
VZ
296bool wxRegion::Subtract( const wxRect& rect )
297{
bbe0af5b 298 wxRegion reg( rect );
1e6feb95 299 return Subtract( reg );
ff7b1510 300}
c801d85f
KB
301
302bool wxRegion::Subtract( const wxRegion& region )
303{
e1208c31
RR
304 if (region.IsNull())
305 return FALSE;
306
307 if (!m_refData)
308 {
2b5f62a0
VZ
309 // subtracting from an invalid region doesn't make sense
310 return FALSE;
48850fa7 311 }
1e6feb95 312
2b5f62a0
VZ
313 AllocExclusive();
314
b7c2d6ff
OK
315#ifdef __WXGTK20__
316 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
317#else
bbe0af5b
RR
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;
b7c2d6ff 321#endif
1e6feb95 322
bbe0af5b 323 return TRUE;
ff7b1510 324}
c801d85f 325
5fc7ede9 326bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 327{
bbe0af5b 328 wxRegion reg( x, y, width, height );
1e6feb95 329 return Xor( reg );
ff7b1510 330}
c801d85f
KB
331
332bool wxRegion::Xor( const wxRect& rect )
333{
bbe0af5b 334 wxRegion reg( rect );
1e6feb95 335 return Xor( reg );
ff7b1510 336}
c801d85f
KB
337
338bool wxRegion::Xor( const wxRegion& region )
339{
e1208c31 340 if (region.IsNull())
05a11043 341 return FALSE;
e1208c31
RR
342
343 if (!m_refData)
344 {
2b5f62a0 345 return FALSE;
1e6feb95 346 }
e1208c31 347
2b5f62a0
VZ
348 AllocExclusive();
349
b7c2d6ff
OK
350#ifdef __WXGTK20__
351 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
352#else
bbe0af5b
RR
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;
b7c2d6ff 356#endif
5fc7ede9 357
bbe0af5b 358 return TRUE;
ff7b1510 359}
c801d85f 360
2b5f62a0
VZ
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
1e6feb95
VZ
373// ----------------------------------------------------------------------------
374// wxRegion tests
375// ----------------------------------------------------------------------------
376
e1208c31 377void wxRegion::GetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
c801d85f 378{
1e6feb95
VZ
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 }
ff7b1510 395}
c801d85f 396
bf57d1ad 397wxRect wxRegion::GetBox() const
c801d85f 398{
1e6feb95 399 wxCoord x, y, w, h;
bbe0af5b
RR
400 GetBox( x, y, w, h );
401 return wxRect( x, y, w, h );
ff7b1510 402}
c801d85f 403
bf57d1ad 404bool wxRegion::Empty() const
c801d85f 405{
e1208c31
RR
406 if (!m_refData)
407 return TRUE;
408
bbe0af5b 409 return gdk_region_empty( M_REGIONDATA->m_region );
ff7b1510 410}
c801d85f 411
5fc7ede9 412wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y ) const
c801d85f 413{
e1208c31
RR
414 if (!m_refData)
415 return wxOutRegion;
416
bbe0af5b
RR
417 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
418 return wxInRegion;
419 else
420 return wxOutRegion;
ff7b1510 421}
c801d85f 422
5fc7ede9 423wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) const
c801d85f 424{
e1208c31
RR
425 if (!m_refData)
426 return wxOutRegion;
427
bbe0af5b
RR
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;
ff7b1510 441}
c801d85f 442
8429bec1
RR
443wxRegionContain wxRegion::Contains(const wxPoint& pt) const
444{
bbe0af5b 445 return Contains( pt.x, pt.y );
8429bec1
RR
446}
447
448wxRegionContain wxRegion::Contains(const wxRect& rect) const
449{
bbe0af5b 450 return Contains( rect.x, rect.y, rect.width, rect.height );
8429bec1
RR
451}
452
bf57d1ad 453GdkRegion *wxRegion::GetRegion() const
c801d85f 454{
e1208c31
RR
455 if (!m_refData)
456 return (GdkRegion*) NULL;
457
bbe0af5b 458 return M_REGIONDATA->m_region;
ff7b1510 459}
c801d85f 460
1e6feb95 461// ----------------------------------------------------------------------------
3d0c4d2e 462// wxRegionIterator
1e6feb95 463// ----------------------------------------------------------------------------
8429bec1 464
48850fa7 465#ifndef __WXGTK20__
3d0c4d2e
RR
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
48850fa7
RR
473#include <gdk/gdkprivate.h>
474
3d0c4d2e
RR
475struct _XBox {
476 short x1, x2, y1, y2;
477};
1e6feb95 478
3d0c4d2e
RR
479struct _XRegion {
480 long size , numRects;
481 _XBox *rects, extents;
482};
483
2b5f62a0 484#endif // GTK+ 1.x
48850fa7 485
3d0c4d2e
RR
486class wxRIRefData: public wxObjectRefData
487{
488public:
3f0fb1d4
VZ
489 wxRIRefData() { Init(); }
490 virtual ~wxRIRefData();
3d0c4d2e 491
3f0fb1d4
VZ
492 void CreateRects( const wxRegion& r );
493
494 void Init() { m_rects = NULL; m_numRects = 0; }
3d0c4d2e
RR
495
496 wxRect *m_rects;
497 size_t m_numRects;
3d0c4d2e
RR
498};
499
500wxRIRefData::~wxRIRefData()
501{
64423153 502 delete [] m_rects;
3d0c4d2e
RR
503}
504
3d0c4d2e
RR
505void wxRIRefData::CreateRects( const wxRegion& region )
506{
64423153 507 delete [] m_rects;
48850fa7 508
3f0fb1d4 509 Init();
57f2b902 510
48850fa7 511 GdkRegion *gdkregion = region.GetRegion();
3f0fb1d4
VZ
512 if (!gdkregion)
513 return;
57f2b902 514
48850fa7 515#ifdef __WXGTK20__
9e691f46 516 GdkRectangle *gdkrects = NULL;
48850fa7 517 gint numRects = 0;
9e691f46 518 gdk_region_get_rectangles( gdkregion, &gdkrects, &numRects );
57f2b902 519
48850fa7
RR
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)
3d0c4d2e 525 {
48850fa7
RR
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;
3d0c4d2e 532 }
3d0c4d2e 533 }
9e691f46
VZ
534 g_free( gdkrects );
535#else // GTK+ 1.x
48850fa7
RR
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 }
9e691f46 554#endif // GTK+ 2.0/1.x
3d0c4d2e
RR
555}
556
3d0c4d2e
RR
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
2b5f62a0 581wxRegionIterator& wxRegionIterator::operator ++ ()
3d0c4d2e 582{
2b5f62a0
VZ
583 if (HaveRects())
584 ++m_current;
3d0c4d2e 585
2b5f62a0 586 return *this;
3d0c4d2e
RR
587}
588
2b5f62a0 589wxRegionIterator wxRegionIterator::operator ++ (int)
3d0c4d2e 590{
2b5f62a0
VZ
591 wxRegionIterator tmp = *this;
592 if (HaveRects())
593 ++m_current;
594
595 return tmp;
3d0c4d2e
RR
596}
597
598wxCoord wxRegionIterator::GetX() const
599{
2b5f62a0
VZ
600 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
601
3d0c4d2e
RR
602 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
603}
604
605wxCoord wxRegionIterator::GetY() const
606{
2b5f62a0
VZ
607 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
608
3d0c4d2e
RR
609 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
610}
611
612wxCoord wxRegionIterator::GetW() const
613{
2b5f62a0
VZ
614 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
615
3d0c4d2e
RR
616 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
617}
618
619wxCoord wxRegionIterator::GetH() const
620{
2b5f62a0
VZ
621 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
622
3d0c4d2e
RR
623 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
624}
625
1e6feb95
VZ
626wxRect wxRegionIterator::GetRect() const
627{
628 wxRect r;
3379ed37
VZ
629 if( HaveRects() )
630 r = ((wxRIRefData*)m_refData)->m_rects[m_current];
1e6feb95
VZ
631
632 return r;
633}
634