]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/region.cpp
follow up parent chain to properly support modal dialog parents, see #15383
[wxWidgets.git] / src / gtk1 / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk1/region.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Modified: VZ at 05.10.00: use AllocExclusive(), comparison fixed
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // ============================================================================
11 // declarations
12 // ============================================================================
13
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20
21 #include "wx/region.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/log.h"
25 #endif
26
27 #include "wx/gtk1/private.h"
28
29
30 // ----------------------------------------------------------------------------
31 // wxGdkRegion: creates a new region in ctor and destroys in dtor
32 // ----------------------------------------------------------------------------
33
34 class wxGdkRegion
35 {
36 public:
37 wxGdkRegion() { m_region = gdk_region_new(); }
38 ~wxGdkRegion() { gdk_region_destroy(m_region); }
39
40 operator GdkRegion *() const { return m_region; }
41
42 private:
43 GdkRegion *m_region;
44 };
45
46
47 // ----------------------------------------------------------------------------
48 // wxRegionRefData: private class containing the information about the region
49 // ----------------------------------------------------------------------------
50
51 class wxRegionRefData : public wxGDIRefData
52 {
53 public:
54 wxRegionRefData()
55 {
56 m_region = NULL;
57 }
58
59 wxRegionRefData(const wxRegionRefData& refData)
60 : wxGDIRefData()
61 {
62 m_region = gdk_regions_union(wxGdkRegion(), refData.m_region);
63 }
64
65 virtual ~wxRegionRefData()
66 {
67 if (m_region)
68 gdk_region_destroy( m_region );
69 }
70
71 GdkRegion *m_region;
72 };
73
74 // ----------------------------------------------------------------------------
75 // macros
76 // ----------------------------------------------------------------------------
77
78 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
79 #define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData))
80
81 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
82 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
83
84 // ----------------------------------------------------------------------------
85 // wxRegion construction
86 // ----------------------------------------------------------------------------
87
88 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
89
90 void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
91 {
92 GdkRectangle rect;
93 rect.x = x;
94 rect.y = y;
95 rect.width = w;
96 rect.height = h;
97
98 m_refData = new wxRegionRefData();
99
100 M_REGIONDATA->m_region = gdk_region_union_with_rect( wxGdkRegion(), &rect );
101 }
102
103 wxRegion::wxRegion( GdkRegion *region )
104 {
105 m_refData = new wxRegionRefData();
106 M_REGIONDATA->m_region = gdk_regions_union(wxGdkRegion(), region);
107 }
108
109 wxRegion::wxRegion( size_t n, const wxPoint *points, wxPolygonFillMode fillStyle )
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
133 wxRegion::~wxRegion()
134 {
135 // m_refData unrefed in ~wxObject
136 }
137
138 wxGDIRefData *wxRegion::CreateGDIRefData() const
139 {
140 return new wxRegionRefData;
141 }
142
143 wxGDIRefData *wxRegion::CloneGDIRefData(const wxGDIRefData *data) const
144 {
145 return new wxRegionRefData(*(wxRegionRefData *)data);
146 }
147
148 // ----------------------------------------------------------------------------
149 // wxRegion comparison
150 // ----------------------------------------------------------------------------
151
152 bool wxRegion::DoIsEqual(const wxRegion& region) const
153 {
154 return gdk_region_equal(M_REGIONDATA->m_region,
155 M_REGIONDATA_OF(region)->m_region);
156 }
157
158 // ----------------------------------------------------------------------------
159 // wxRegion operations
160 // ----------------------------------------------------------------------------
161
162 void wxRegion::Clear()
163 {
164 UnRef();
165 }
166
167 bool wxRegion::DoUnionWithRect(const wxRect& r)
168 {
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
172 if ( r.IsEmpty() )
173 return TRUE;
174
175 if ( !m_refData )
176 {
177 InitRect(r.x, r.y, r.width, r.height);
178 }
179 else
180 {
181 AllocExclusive();
182
183 GdkRectangle rect;
184 rect.x = r.x;
185 rect.y = r.y;
186 rect.width = r.width;
187 rect.height = r.height;
188
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;
192 }
193
194 return TRUE;
195 }
196
197 bool wxRegion::DoUnionWithRegion( const wxRegion& region )
198 {
199 if (region.IsNull())
200 return FALSE;
201
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 }
211
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;
215
216 return TRUE;
217 }
218
219 bool wxRegion::DoIntersect( const wxRegion& region )
220 {
221 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
222
223 if (!m_refData)
224 {
225 // intersecting with invalid region doesn't make sense
226 return FALSE;
227 }
228
229 AllocExclusive();
230
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;
234
235 return TRUE;
236 }
237
238 bool wxRegion::DoSubtract( const wxRegion& region )
239 {
240 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
241
242 if (!m_refData)
243 {
244 // subtracting from an invalid region doesn't make sense
245 return FALSE;
246 }
247
248 AllocExclusive();
249
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;
253
254 return TRUE;
255 }
256
257 bool wxRegion::DoXor( const wxRegion& region )
258 {
259 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
260
261 if (!m_refData)
262 {
263 return FALSE;
264 }
265
266 AllocExclusive();
267
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;
271
272 return TRUE;
273 }
274
275 bool wxRegion::DoOffset( wxCoord x, wxCoord y )
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
287 // ----------------------------------------------------------------------------
288 // wxRegion tests
289 // ----------------------------------------------------------------------------
290
291 bool wxRegion::DoGetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
292 {
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;
301
302 return true;
303 }
304 else
305 {
306 x = 0;
307 y = 0;
308 w = -1;
309 h = -1;
310
311 return false;
312 }
313 }
314
315 bool wxRegion::IsEmpty() const
316 {
317 if (!m_refData)
318 return TRUE;
319
320 return gdk_region_empty( M_REGIONDATA->m_region );
321 }
322
323 wxRegionContain wxRegion::DoContainsPoint( wxCoord x, wxCoord y ) const
324 {
325 if (!m_refData)
326 return wxOutRegion;
327
328 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
329 return wxInRegion;
330 else
331 return wxOutRegion;
332 }
333
334 wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
335 {
336 if (!m_refData)
337 return wxOutRegion;
338
339 GdkRectangle rect;
340 rect.x = r.x;
341 rect.y = r.y;
342 rect.width = r.width;
343 rect.height = r.height;
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;
352 }
353
354 GdkRegion *wxRegion::GetRegion() const
355 {
356 if (!m_refData)
357 return NULL;
358
359 return M_REGIONDATA->m_region;
360 }
361
362 // ----------------------------------------------------------------------------
363 // wxRegionIterator
364 // ----------------------------------------------------------------------------
365
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
372 #include <gdk/gdkprivate.h>
373
374 struct _XBox {
375 short x1, x2, y1, y2;
376 };
377
378 struct _XRegion {
379 long size , numRects;
380 _XBox *rects, extents;
381 };
382
383
384 class wxRIRefData : public wxGDIRefData
385 {
386 public:
387 wxRIRefData() { Init(); }
388 virtual ~wxRIRefData();
389
390 void CreateRects( const wxRegion& r );
391
392 void Init() { m_rects = NULL; m_numRects = 0; }
393
394 wxRect *m_rects;
395 size_t m_numRects;
396 };
397
398 wxRIRefData::~wxRIRefData()
399 {
400 delete [] m_rects;
401 }
402
403 void wxRIRefData::CreateRects( const wxRegion& region )
404 {
405 delete [] m_rects;
406
407 Init();
408
409 GdkRegion *gdkregion = region.GetRegion();
410 if (!gdkregion)
411 return;
412
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 }
431 }
432
433 wxRegionIterator::wxRegionIterator()
434 {
435 m_refData = new wxRIRefData();
436 Reset();
437 }
438
439 wxRegionIterator::wxRegionIterator( const wxRegion& region )
440 {
441 m_refData = new wxRIRefData();
442 Reset(region);
443 }
444
445 void wxRegionIterator::Reset( const wxRegion& region )
446 {
447 m_region = region;
448 ((wxRIRefData*)m_refData)->CreateRects(region);
449 Reset();
450 }
451
452 bool wxRegionIterator::HaveRects() const
453 {
454 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
455 }
456
457 wxRegionIterator& wxRegionIterator::operator ++ ()
458 {
459 if (HaveRects())
460 ++m_current;
461
462 return *this;
463 }
464
465 wxRegionIterator wxRegionIterator::operator ++ (int)
466 {
467 wxRegionIterator tmp = *this;
468 if (HaveRects())
469 ++m_current;
470
471 return tmp;
472 }
473
474 wxCoord wxRegionIterator::GetX() const
475 {
476 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
477
478 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
479 }
480
481 wxCoord wxRegionIterator::GetY() const
482 {
483 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
484
485 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
486 }
487
488 wxCoord wxRegionIterator::GetW() const
489 {
490 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
491
492 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
493 }
494
495 wxCoord wxRegionIterator::GetH() const
496 {
497 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
498
499 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
500 }
501
502 wxRect wxRegionIterator::GetRect() const
503 {
504 wxRect r;
505 if( HaveRects() )
506 r = ((wxRIRefData*)m_refData)->m_rects[m_current];
507
508 return r;
509 }