]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/region.cpp
Applied #15375 to stop event-sending in generic wxSpinCtrl ctor (eco)
[wxWidgets.git] / src / gtk1 / region.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
e4db172a 2// Name: src/gtk1/region.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
9fe4c99c 5// Modified: VZ at 05.10.00: use AllocExclusive(), comparison fixed
f96aa4d9 6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
1e6feb95
VZ
10// ============================================================================
11// declarations
12// ============================================================================
13
1e6feb95
VZ
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
14f355c2
VS
18// For compilers that support precompilation, includes "wx.h".
19#include "wx/wxprec.h"
20
9e691f46 21#include "wx/region.h"
e4db172a
WS
22
23#ifndef WX_PRECOMP
24 #include "wx/log.h"
25#endif
26
3cbab641 27#include "wx/gtk1/private.h"
1e6feb95 28
57f2b902
VZ
29
30// ----------------------------------------------------------------------------
31// wxGdkRegion: creates a new region in ctor and destroys in dtor
32// ----------------------------------------------------------------------------
33
34class wxGdkRegion
35{
36public:
37 wxGdkRegion() { m_region = gdk_region_new(); }
38 ~wxGdkRegion() { gdk_region_destroy(m_region); }
39
40 operator GdkRegion *() const { return m_region; }
41
42private:
43 GdkRegion *m_region;
44};
45
57f2b902 46
1e6feb95
VZ
47// ----------------------------------------------------------------------------
48// wxRegionRefData: private class containing the information about the region
49// ----------------------------------------------------------------------------
c801d85f 50
8f884a0d 51class wxRegionRefData : public wxGDIRefData
c801d85f 52{
864e8bd0 53public:
48850fa7
RR
54 wxRegionRefData()
55 {
56 m_region = NULL;
57 }
57f2b902 58
48850fa7 59 wxRegionRefData(const wxRegionRefData& refData)
8f884a0d 60 : wxGDIRefData()
48850fa7 61 {
57f2b902 62 m_region = gdk_regions_union(wxGdkRegion(), refData.m_region);
48850fa7 63 }
57f2b902 64
d3c7fc99 65 virtual ~wxRegionRefData()
48850fa7
RR
66 {
67 if (m_region)
68 gdk_region_destroy( m_region );
69 }
5fc7ede9 70
c801d85f
KB
71 GdkRegion *m_region;
72};
73
1e6feb95
VZ
74// ----------------------------------------------------------------------------
75// macros
76// ----------------------------------------------------------------------------
77
78#define M_REGIONDATA ((wxRegionRefData *)m_refData)
79#define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData))
80
d84afea9
GD
81IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
82IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
1e6feb95 83
1e6feb95
VZ
84// ----------------------------------------------------------------------------
85// wxRegion construction
86// ----------------------------------------------------------------------------
c801d85f
KB
87
88#define M_REGIONDATA ((wxRegionRefData *)m_refData)
89
9fe4c99c 90void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
c801d85f 91{
bbe0af5b
RR
92 GdkRectangle rect;
93 rect.x = x;
94 rect.y = y;
95 rect.width = w;
96 rect.height = h;
57f2b902 97
48850fa7 98 m_refData = new wxRegionRefData();
57f2b902 99
57f2b902 100 M_REGIONDATA->m_region = gdk_region_union_with_rect( wxGdkRegion(), &rect );
ff7b1510 101}
c801d85f 102
b15ed747
RR
103wxRegion::wxRegion( GdkRegion *region )
104{
105 m_refData = new wxRegionRefData();
57f2b902 106 M_REGIONDATA->m_region = gdk_regions_union(wxGdkRegion(), region);
b15ed747
RR
107}
108
94a007ec 109wxRegion::wxRegion( size_t n, const wxPoint *points, wxPolygonFillMode fillStyle )
5549e9f7
VZ
110{
111 GdkPoint *gdkpoints = new GdkPoint[n];
112 for ( size_t i = 0 ; i < n ; i++ )
113 {
114 gdkpoints[i].x = points[i].x;
115 gdkpoints[i].y = points[i].y;
116 }
117
118 m_refData = new wxRegionRefData();
119
120 GdkRegion* reg = gdk_region_polygon
121 (
122 gdkpoints,
123 n,
124 fillStyle == wxWINDING_RULE ? GDK_WINDING_RULE
125 : GDK_EVEN_ODD_RULE
126 );
127
128 M_REGIONDATA->m_region = reg;
129
130 delete [] gdkpoints;
131}
132
1e6feb95 133wxRegion::~wxRegion()
c801d85f 134{
e0f0b197 135 // m_refData unrefed in ~wxObject
ff7b1510 136}
c801d85f 137
8f884a0d 138wxGDIRefData *wxRegion::CreateGDIRefData() const
e0f0b197
RR
139{
140 return new wxRegionRefData;
141}
142
8f884a0d 143wxGDIRefData *wxRegion::CloneGDIRefData(const wxGDIRefData *data) const
e0f0b197
RR
144{
145 return new wxRegionRefData(*(wxRegionRefData *)data);
146}
c89f5c02 147
9fe4c99c
VZ
148// ----------------------------------------------------------------------------
149// wxRegion comparison
150// ----------------------------------------------------------------------------
151
8a16d737 152bool wxRegion::DoIsEqual(const wxRegion& region) const
c801d85f 153{
1e6feb95
VZ
154 return gdk_region_equal(M_REGIONDATA->m_region,
155 M_REGIONDATA_OF(region)->m_region);
ff7b1510 156}
c801d85f 157
1e6feb95
VZ
158// ----------------------------------------------------------------------------
159// wxRegion operations
160// ----------------------------------------------------------------------------
161
bf57d1ad 162void wxRegion::Clear()
c801d85f 163{
bbe0af5b 164 UnRef();
ff7b1510 165}
c801d85f 166
8a16d737 167bool wxRegion::DoUnionWithRect(const wxRect& r)
c801d85f 168{
57351df0
VZ
169 // workaround for a strange GTK/X11 bug: taking union with an empty
170 // rectangle results in an empty region which is definitely not what we
171 // want
8a16d737 172 if ( r.IsEmpty() )
57351df0
VZ
173 return TRUE;
174
2b5f62a0 175 if ( !m_refData )
e1208c31 176 {
8a16d737 177 InitRect(r.x, r.y, r.width, r.height);
e1208c31
RR
178 }
179 else
180 {
9fe4c99c 181 AllocExclusive();
1e6feb95 182
2b5f62a0 183 GdkRectangle rect;
8a16d737
VZ
184 rect.x = r.x;
185 rect.y = r.y;
186 rect.width = r.width;
187 rect.height = r.height;
188
b61df4aa
VZ
189 GdkRegion *reg = gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
190 gdk_region_destroy( M_REGIONDATA->m_region );
191 M_REGIONDATA->m_region = reg;
e1208c31 192 }
1e6feb95 193
bbe0af5b 194 return TRUE;
ff7b1510 195}
c801d85f 196
8a16d737 197bool wxRegion::DoUnionWithRegion( const wxRegion& region )
c801d85f 198{
e1208c31
RR
199 if (region.IsNull())
200 return FALSE;
201
48850fa7
RR
202 if (!m_refData)
203 {
204 m_refData = new wxRegionRefData();
205 M_REGIONDATA->m_region = gdk_region_new();
206 }
207 else
208 {
209 AllocExclusive();
210 }
e1208c31 211
bbe0af5b
RR
212 GdkRegion *reg = gdk_regions_union( M_REGIONDATA->m_region, region.GetRegion() );
213 gdk_region_destroy( M_REGIONDATA->m_region );
214 M_REGIONDATA->m_region = reg;
5fc7ede9 215
bbe0af5b 216 return TRUE;
ff7b1510 217}
c801d85f 218
8a16d737 219bool wxRegion::DoIntersect( const wxRegion& region )
c801d85f 220{
a1b806b9 221 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
1e6feb95 222
e1208c31
RR
223 if (!m_refData)
224 {
2b5f62a0
VZ
225 // intersecting with invalid region doesn't make sense
226 return FALSE;
1e6feb95
VZ
227 }
228
2b5f62a0
VZ
229 AllocExclusive();
230
48850fa7
RR
231 GdkRegion *reg = gdk_regions_intersect( M_REGIONDATA->m_region, region.GetRegion() );
232 gdk_region_destroy( M_REGIONDATA->m_region );
233 M_REGIONDATA->m_region = reg;
9fe4c99c 234
bbe0af5b 235 return TRUE;
ff7b1510 236}
c801d85f 237
8a16d737 238bool wxRegion::DoSubtract( const wxRegion& region )
c801d85f 239{
a1b806b9 240 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
e1208c31
RR
241
242 if (!m_refData)
243 {
2b5f62a0
VZ
244 // subtracting from an invalid region doesn't make sense
245 return FALSE;
48850fa7 246 }
1e6feb95 247
2b5f62a0
VZ
248 AllocExclusive();
249
bbe0af5b
RR
250 GdkRegion *reg = gdk_regions_subtract( M_REGIONDATA->m_region, region.GetRegion() );
251 gdk_region_destroy( M_REGIONDATA->m_region );
252 M_REGIONDATA->m_region = reg;
1e6feb95 253
bbe0af5b 254 return TRUE;
ff7b1510 255}
c801d85f 256
8a16d737 257bool wxRegion::DoXor( const wxRegion& region )
c801d85f 258{
a1b806b9 259 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
e1208c31
RR
260
261 if (!m_refData)
262 {
2b5f62a0 263 return FALSE;
1e6feb95 264 }
e1208c31 265
2b5f62a0
VZ
266 AllocExclusive();
267
bbe0af5b
RR
268 GdkRegion *reg = gdk_regions_xor( M_REGIONDATA->m_region, region.GetRegion() );
269 gdk_region_destroy( M_REGIONDATA->m_region );
270 M_REGIONDATA->m_region = reg;
5fc7ede9 271
bbe0af5b 272 return TRUE;
ff7b1510 273}
c801d85f 274
8a16d737 275bool wxRegion::DoOffset( wxCoord x, wxCoord y )
2b5f62a0
VZ
276{
277 if (!m_refData)
278 return FALSE;
279
280 AllocExclusive();
281
282 gdk_region_offset( M_REGIONDATA->m_region, x, y );
283
284 return TRUE;
285}
286
1e6feb95
VZ
287// ----------------------------------------------------------------------------
288// wxRegion tests
289// ----------------------------------------------------------------------------
290
8a16d737 291bool wxRegion::DoGetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
c801d85f 292{
1e6feb95
VZ
293 if ( m_refData )
294 {
295 GdkRectangle rect;
296 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
297 x = rect.x;
298 y = rect.y;
299 w = rect.width;
300 h = rect.height;
8a16d737
VZ
301
302 return true;
1e6feb95
VZ
303 }
304 else
305 {
306 x = 0;
307 y = 0;
308 w = -1;
309 h = -1;
c801d85f 310
8a16d737
VZ
311 return false;
312 }
ff7b1510 313}
c801d85f 314
8a16d737 315bool wxRegion::IsEmpty() const
c801d85f 316{
e1208c31
RR
317 if (!m_refData)
318 return TRUE;
319
bbe0af5b 320 return gdk_region_empty( M_REGIONDATA->m_region );
ff7b1510 321}
c801d85f 322
8a16d737 323wxRegionContain wxRegion::DoContainsPoint( wxCoord x, wxCoord y ) const
c801d85f 324{
e1208c31
RR
325 if (!m_refData)
326 return wxOutRegion;
327
bbe0af5b
RR
328 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
329 return wxInRegion;
330 else
331 return wxOutRegion;
ff7b1510 332}
c801d85f 333
8a16d737 334wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
c801d85f 335{
e1208c31
RR
336 if (!m_refData)
337 return wxOutRegion;
338
bbe0af5b 339 GdkRectangle rect;
8a16d737
VZ
340 rect.x = r.x;
341 rect.y = r.y;
342 rect.width = r.width;
343 rect.height = r.height;
bbe0af5b
RR
344 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
345 switch (res)
346 {
347 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
348 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
349 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
350 }
351 return wxOutRegion;
ff7b1510 352}
c801d85f 353
bf57d1ad 354GdkRegion *wxRegion::GetRegion() const
c801d85f 355{
e1208c31 356 if (!m_refData)
d3b9f782 357 return NULL;
e1208c31 358
bbe0af5b 359 return M_REGIONDATA->m_region;
ff7b1510 360}
c801d85f 361
1e6feb95 362// ----------------------------------------------------------------------------
3d0c4d2e 363// wxRegionIterator
1e6feb95 364// ----------------------------------------------------------------------------
8429bec1 365
3d0c4d2e
RR
366// the following structures must match the private structures
367// in X11 region code ( xc/lib/X11/region.h )
368
369// this makes the Region type transparent
370// and we have access to the region rectangles
371
48850fa7
RR
372#include <gdk/gdkprivate.h>
373
3d0c4d2e
RR
374struct _XBox {
375 short x1, x2, y1, y2;
376};
1e6feb95 377
3d0c4d2e
RR
378struct _XRegion {
379 long size , numRects;
380 _XBox *rects, extents;
381};
382
48850fa7 383
8f884a0d 384class wxRIRefData : public wxGDIRefData
3d0c4d2e
RR
385{
386public:
3f0fb1d4
VZ
387 wxRIRefData() { Init(); }
388 virtual ~wxRIRefData();
3d0c4d2e 389
3f0fb1d4
VZ
390 void CreateRects( const wxRegion& r );
391
392 void Init() { m_rects = NULL; m_numRects = 0; }
3d0c4d2e
RR
393
394 wxRect *m_rects;
395 size_t m_numRects;
3d0c4d2e
RR
396};
397
398wxRIRefData::~wxRIRefData()
399{
64423153 400 delete [] m_rects;
3d0c4d2e
RR
401}
402
3d0c4d2e
RR
403void wxRIRefData::CreateRects( const wxRegion& region )
404{
64423153 405 delete [] m_rects;
48850fa7 406
3f0fb1d4 407 Init();
57f2b902 408
48850fa7 409 GdkRegion *gdkregion = region.GetRegion();
3f0fb1d4
VZ
410 if (!gdkregion)
411 return;
57f2b902 412
48850fa7
RR
413 Region r = ((GdkRegionPrivate *)gdkregion)->xregion;
414 if (r)
415 {
416 m_numRects = r->numRects;
417 if (m_numRects)
418 {
419 m_rects = new wxRect[m_numRects];
420 for (size_t i=0; i < m_numRects; ++i)
421 {
422 _XBox &xr = r->rects[i];
423 wxRect &wr = m_rects[i];
424 wr.x = xr.x1;
425 wr.y = xr.y1;
426 wr.width = xr.x2-xr.x1;
427 wr.height = xr.y2-xr.y1;
428 }
429 }
430 }
3d0c4d2e
RR
431}
432
3d0c4d2e
RR
433wxRegionIterator::wxRegionIterator()
434{
435 m_refData = new wxRIRefData();
436 Reset();
437}
438
439wxRegionIterator::wxRegionIterator( const wxRegion& region )
440{
441 m_refData = new wxRIRefData();
442 Reset(region);
443}
444
445void wxRegionIterator::Reset( const wxRegion& region )
446{
447 m_region = region;
448 ((wxRIRefData*)m_refData)->CreateRects(region);
449 Reset();
450}
451
452bool wxRegionIterator::HaveRects() const
453{
454 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
455}
456
2b5f62a0 457wxRegionIterator& wxRegionIterator::operator ++ ()
3d0c4d2e 458{
2b5f62a0
VZ
459 if (HaveRects())
460 ++m_current;
3d0c4d2e 461
2b5f62a0 462 return *this;
3d0c4d2e
RR
463}
464
2b5f62a0 465wxRegionIterator wxRegionIterator::operator ++ (int)
3d0c4d2e 466{
2b5f62a0
VZ
467 wxRegionIterator tmp = *this;
468 if (HaveRects())
469 ++m_current;
470
471 return tmp;
3d0c4d2e
RR
472}
473
474wxCoord wxRegionIterator::GetX() const
475{
9a83f860 476 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
2b5f62a0 477
3d0c4d2e
RR
478 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
479}
480
481wxCoord wxRegionIterator::GetY() const
482{
9a83f860 483 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
2b5f62a0 484
3d0c4d2e
RR
485 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
486}
487
488wxCoord wxRegionIterator::GetW() const
489{
9a83f860 490 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
2b5f62a0 491
3d0c4d2e
RR
492 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
493}
494
495wxCoord wxRegionIterator::GetH() const
496{
9a83f860 497 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
2b5f62a0 498
3d0c4d2e
RR
499 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
500}
501
1e6feb95
VZ
502wxRect wxRegionIterator::GetRect() const
503{
504 wxRect r;
3379ed37
VZ
505 if( HaveRects() )
506 r = ((wxRIRefData*)m_refData)->m_rects[m_current];
1e6feb95
VZ
507
508 return r;
509}