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