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