]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/region.cpp
Fixed a crash when GetMonthControl returns NULL
[wxWidgets.git] / src / gtk / region.cpp
... / ...
CommitLineData
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
33class wxRegionRefData : public wxObjectRefData
34{
35public:
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
70IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
71IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
72
73// ----------------------------------------------------------------------------
74// wxRegion construction
75// ----------------------------------------------------------------------------
76
77#define M_REGIONDATA ((wxRegionRefData *)m_refData)
78
79void 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
98wxRegion::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
122wxRegion::~wxRegion()
123{
124 // m_refData unrefed in ~wxObject
125}
126
127wxObjectRefData *wxRegion::CreateRefData() const
128{
129 return new wxRegionRefData;
130}
131
132wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
133{
134 return new wxRegionRefData(*(wxRegionRefData *)data);
135}
136
137// ----------------------------------------------------------------------------
138// wxRegion comparison
139// ----------------------------------------------------------------------------
140
141bool 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
156void wxRegion::Clear()
157{
158 UnRef();
159}
160
161bool 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
196bool wxRegion::Union( const wxRect& rect )
197{
198 return Union( rect.x, rect.y, rect.width, rect.height );
199}
200
201bool 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
227bool 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
234bool wxRegion::Intersect( const wxRect& rect )
235{
236 wxRegion reg( rect );
237
238 return Intersect( reg );
239}
240
241bool 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
270bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
271{
272 wxRegion reg( x, y, width, height );
273 return Subtract( reg );
274}
275
276bool wxRegion::Subtract( const wxRect& rect )
277{
278 wxRegion reg( rect );
279 return Subtract( reg );
280}
281
282bool 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
308bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
309{
310 wxRegion reg( x, y, width, height );
311 return Xor( reg );
312}
313
314bool wxRegion::Xor( const wxRect& rect )
315{
316 wxRegion reg( rect );
317 return Xor( reg );
318}
319
320bool 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
350void 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
370wxRect 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
377bool 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
389bool wxRegion::Empty() const
390{
391 if (!m_refData)
392 return TRUE;
393
394 return gdk_region_empty( M_REGIONDATA->m_region );
395}
396
397wxRegionContain 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
408wxRegionContain 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
428wxRegionContain wxRegion::Contains(const wxPoint& pt) const
429{
430 return Contains( pt.x, pt.y );
431}
432
433wxRegionContain wxRegion::Contains(const wxRect& rect) const
434{
435 return Contains( rect.x, rect.y, rect.width, rect.height );
436}
437
438GdkRegion *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
460struct _XBox {
461 short x1, x2, y1, y2;
462};
463
464struct _XRegion {
465 long size , numRects;
466 _XBox *rects, extents;
467};
468
469#endif
470
471class wxRIRefData: public wxObjectRefData
472{
473public:
474 wxRIRefData() { Init(); }
475 virtual ~wxRIRefData();
476
477 void CreateRects( const wxRegion& r );
478
479 void Init() { m_rects = NULL; m_numRects = 0; }
480
481 wxRect *m_rects;
482 size_t m_numRects;
483};
484
485wxRIRefData::~wxRIRefData()
486{
487 delete [] m_rects;
488}
489
490void wxRIRefData::CreateRects( const wxRegion& region )
491{
492 delete [] m_rects;
493
494 Init();
495
496 GdkRegion *gdkregion = region.GetRegion();
497 if (!gdkregion)
498 return;
499
500#ifdef __WXGTK20__
501 GdkRectangle *gdkrects = NULL;
502 gint numRects = 0;
503 gdk_region_get_rectangles( gdkregion, &gdkrects, &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_free( gdkrects );
520#else // GTK+ 1.x
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 // GTK+ 2.0/1.x
540}
541
542wxRegionIterator::wxRegionIterator()
543{
544 m_refData = new wxRIRefData();
545 Reset();
546}
547
548wxRegionIterator::wxRegionIterator( const wxRegion& region )
549{
550 m_refData = new wxRIRefData();
551 Reset(region);
552}
553
554void wxRegionIterator::Reset( const wxRegion& region )
555{
556 m_region = region;
557 ((wxRIRefData*)m_refData)->CreateRects(region);
558 Reset();
559}
560
561bool wxRegionIterator::HaveRects() const
562{
563 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
564}
565
566wxRegionIterator::operator bool () const
567{
568 return HaveRects();
569}
570
571void wxRegionIterator::operator ++ ()
572{
573 if (HaveRects()) ++m_current;
574}
575
576void wxRegionIterator::operator ++ (int)
577{
578 if (HaveRects()) ++m_current;
579}
580
581wxCoord wxRegionIterator::GetX() const
582{
583 if( !HaveRects() ) return 0;
584 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
585}
586
587wxCoord wxRegionIterator::GetY() const
588{
589 if( !HaveRects() ) return 0;
590 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
591}
592
593wxCoord wxRegionIterator::GetW() const
594{
595 if( !HaveRects() ) return -1;
596 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
597}
598
599wxCoord wxRegionIterator::GetH() const
600{
601 if( !HaveRects() ) return -1;
602 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
603}
604
605wxRect 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