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