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