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