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