Merge in from trunk r67662 to r64801
[wxWidgets.git] / src / x11 / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // File: src/x11/region.cpp
3 // Purpose: Region class
4 // Author: Julian Smart, Robert Roebling
5 // Created: Fri Oct 24 10:46:34 MET 1997
6 // RCS-ID: $Id$
7 // Copyright: (c) 1997 Julian Smart, Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // for compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13
14 #include "wx/region.h"
15
16 #ifndef WX_PRECOMP
17 #include "wx/log.h"
18 #include "wx/gdicmn.h"
19 #endif
20
21 #ifdef __VMS__
22 #pragma message disable nosimpint
23 #endif
24 #include "wx/x11/private.h"
25 #include "X11/Xutil.h"
26 #ifdef __VMS__
27 #pragma message enable nosimpint
28 #endif
29
30 // ----------------------------------------------------------------------------
31 // wxRegionRefData: private class containing the information about the region
32 // ----------------------------------------------------------------------------
33
34 class wxRegionRefData : public wxGDIRefData
35 {
36 public:
37 wxRegionRefData()
38 {
39 m_region = NULL;
40 }
41
42 wxRegionRefData(const wxRegionRefData& refData)
43 {
44 m_region = XCreateRegion();
45 XUnionRegion( refData.m_region, m_region, m_region );
46 }
47
48 virtual ~wxRegionRefData()
49 {
50 if (m_region)
51 XDestroyRegion( m_region );
52 }
53
54 Region m_region;
55 };
56
57 // ----------------------------------------------------------------------------
58 // macros
59 // ----------------------------------------------------------------------------
60
61 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
62 #define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData))
63
64 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
65 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
66
67 // ----------------------------------------------------------------------------
68 // wxRegion construction
69 // ----------------------------------------------------------------------------
70
71 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
72
73 void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
74 {
75 XRectangle rect;
76 rect.x = (short)x;
77 rect.y = (short)y;
78 rect.width = (unsigned short)w;
79 rect.height = (unsigned short)h;
80
81 m_refData = new wxRegionRefData();
82
83 M_REGIONDATA->m_region = XCreateRegion();
84 XUnionRectWithRegion( &rect, M_REGIONDATA->m_region, M_REGIONDATA->m_region );
85 }
86
87 wxRegion::wxRegion( size_t WXUNUSED(n), const wxPoint *WXUNUSED(points), wxPolygonFillMode WXUNUSED(fillStyle) )
88 {
89 #if 0
90 XPoint *xpoints = new XPoint[n];
91 for ( size_t i = 0 ; i < n ; i++ )
92 {
93 xpoints[i].x = points[i].x;
94 xpoints[i].y = points[i].y;
95 }
96
97 m_refData = new wxRegionRefData();
98
99 Region* reg = gdk_region_polygon
100 (
101 gdkpoints,
102 n,
103 fillStyle == wxWINDING_RULE ? GDK_WINDING_RULE
104 : GDK_EVEN_ODD_RULE
105 );
106
107 M_REGIONDATA->m_region = reg;
108
109 delete [] xpoints;
110 #endif
111 }
112
113 wxRegion::~wxRegion()
114 {
115 // m_refData unrefed in ~wxObject
116 }
117
118 wxGDIRefData *wxRegion::CreateGDIRefData() const
119 {
120 return new wxRegionRefData;
121 }
122
123 wxGDIRefData *wxRegion::CloneGDIRefData(const wxGDIRefData *data) const
124 {
125 return new wxRegionRefData(*(wxRegionRefData *)data);
126 }
127
128 // ----------------------------------------------------------------------------
129 // wxRegion comparison
130 // ----------------------------------------------------------------------------
131
132 bool wxRegion::DoIsEqual(const wxRegion& region) const
133 {
134 return XEqualRegion( M_REGIONDATA->m_region,
135 M_REGIONDATA_OF(region)->m_region ) == True;
136 }
137
138 // ----------------------------------------------------------------------------
139 // wxRegion operations
140 // ----------------------------------------------------------------------------
141
142 void wxRegion::Clear()
143 {
144 UnRef();
145 }
146
147 bool wxRegion::DoUnionWithRect(const wxRect& r)
148 {
149 // work around for XUnionRectWithRegion() bug: taking a union with an empty
150 // rect results in an empty region (at least XFree 3.3.6 and 4.0 have this
151 // problem)
152 if ( r.IsEmpty() )
153 return true;
154
155 XRectangle rect;
156 rect.x = (short)r.x;
157 rect.y = (short)r.y;
158 rect.width = (unsigned short)r.width;
159 rect.height = (unsigned short)r.height;
160
161 if (!m_refData)
162 {
163 m_refData = new wxRegionRefData();
164 M_REGIONDATA->m_region = XCreateRegion();
165 }
166 else
167 {
168 AllocExclusive();
169 }
170
171 XUnionRectWithRegion( &rect, M_REGIONDATA->m_region, M_REGIONDATA->m_region );
172
173 return true;
174 }
175
176 bool wxRegion::DoUnionWithRegion( const wxRegion& region )
177 {
178 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
179
180 if (!m_refData)
181 {
182 m_refData = new wxRegionRefData();
183 M_REGIONDATA->m_region = XCreateRegion();
184 }
185 else
186 {
187 AllocExclusive();
188 }
189
190 XUnionRegion( M_REGIONDATA->m_region,
191 M_REGIONDATA_OF(region)->m_region,
192 M_REGIONDATA->m_region );
193
194 return true;
195 }
196
197 bool wxRegion::DoIntersect( const wxRegion& region )
198 {
199 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
200
201 if (!m_refData)
202 {
203 m_refData = new wxRegionRefData();
204 M_REGIONDATA->m_region = XCreateRegion();
205
206 // leave here
207 return true;
208 }
209 else
210 {
211 AllocExclusive();
212 }
213
214 XIntersectRegion( M_REGIONDATA->m_region,
215 M_REGIONDATA_OF(region)->m_region,
216 M_REGIONDATA->m_region );
217
218 return true;
219 }
220
221 bool wxRegion::DoSubtract( const wxRegion& region )
222 {
223 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
224
225 if (!m_refData)
226 {
227 m_refData = new wxRegionRefData();
228 M_REGIONDATA->m_region = XCreateRegion();
229 }
230 else
231 {
232 AllocExclusive();
233 }
234
235 XSubtractRegion( M_REGIONDATA->m_region,
236 M_REGIONDATA_OF(region)->m_region,
237 M_REGIONDATA->m_region );
238
239 return true;
240 }
241
242 bool wxRegion::DoXor( const wxRegion& region )
243 {
244 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
245
246 if (!m_refData)
247 {
248 m_refData = new wxRegionRefData();
249 M_REGIONDATA->m_region = XCreateRegion();
250 }
251 else
252 {
253 AllocExclusive();
254 }
255
256 XXorRegion( M_REGIONDATA->m_region,
257 M_REGIONDATA_OF(region)->m_region,
258 M_REGIONDATA->m_region );
259
260 return true;
261 }
262
263 // ----------------------------------------------------------------------------
264 // wxRegion tests
265 // ----------------------------------------------------------------------------
266
267 bool wxRegion::DoGetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
268 {
269 if (m_refData)
270 {
271 XRectangle rect;
272 XClipBox( M_REGIONDATA->m_region, &rect );
273 x = rect.x;
274 y = rect.y;
275 w = rect.width;
276 h = rect.height;
277
278 return true;
279 }
280 else
281 {
282 x = 0;
283 y = 0;
284 w = -1;
285 h = -1;
286
287 return false;
288 }
289 }
290
291 bool wxRegion::DoOffset( wxCoord x, wxCoord y )
292 {
293 if (!m_refData)
294 return false;
295
296 AllocExclusive();
297
298 XOffsetRegion( M_REGIONDATA->m_region, x, y );
299
300 return true;
301 }
302
303 bool wxRegion::IsEmpty() const
304 {
305 if (!m_refData)
306 return true;
307
308 return XEmptyRegion( M_REGIONDATA->m_region ) == True;
309 }
310
311 wxRegionContain wxRegion::DoContainsPoint( wxCoord x, wxCoord y ) const
312 {
313 if (!m_refData)
314 return wxOutRegion;
315
316 if (XPointInRegion( M_REGIONDATA->m_region, x, y ))
317 return wxInRegion;
318 else
319 return wxOutRegion;
320 }
321
322 wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
323 {
324 if (!m_refData)
325 return wxOutRegion;
326
327 int res = XRectInRegion(M_REGIONDATA->m_region, r.x, r.y, r.width, r.height);
328 switch (res)
329 {
330 case RectangleIn: return wxInRegion;
331 case RectangleOut: return wxOutRegion;
332 case RectanglePart: return wxPartRegion;
333 }
334 return wxOutRegion;
335 }
336
337 WXRegion *wxRegion::GetX11Region() const
338 {
339 if (!m_refData)
340 return NULL;
341
342 return (WXRegion*) M_REGIONDATA->m_region;
343 }
344
345 // ----------------------------------------------------------------------------
346 // wxRegionIterator
347 // ----------------------------------------------------------------------------
348
349 // the following structures must match the private structures
350 // in X11 region code ( xc/lib/X11/region.h )
351
352 // this makes the Region type transparent
353 // and we have access to the region rectangles
354
355 struct _XBox {
356 short x1, x2, y1, y2;
357 };
358
359 struct _XRegion {
360 long size , numRects;
361 _XBox *rects, extents;
362 };
363
364 class wxRIRefData: public wxGDIRefData
365 {
366 public:
367
368 wxRIRefData() : m_rects(0), m_numRects(0){}
369 virtual ~wxRIRefData();
370
371 wxRect *m_rects;
372 size_t m_numRects;
373
374 void CreateRects( const wxRegion& r );
375 };
376
377 wxRIRefData::~wxRIRefData()
378 {
379 delete [] m_rects;
380 }
381
382 void wxRIRefData::CreateRects( const wxRegion& region )
383 {
384 if (m_rects)
385 delete [] m_rects;
386
387 m_rects = 0;
388 m_numRects = 0;
389
390 if (region.IsEmpty()) return;
391
392 Region r = (Region) region.GetX11Region();
393 if (r)
394 {
395 #if wxUSE_NANOX
396 GR_RECT rect;
397 GrGetRegionBox(r, & rect);
398 m_numRects = 1;
399 m_rects = new wxRect[1];
400 m_rects[0].x = rect.x;
401 m_rects[0].y = rect.y;
402 m_rects[0].width = rect.width;
403 m_rects[0].height = rect.height;
404 #else
405 m_numRects = r->numRects;
406 if (m_numRects)
407 {
408 m_rects = new wxRect[m_numRects];
409 for (size_t i=0; i < m_numRects; ++i)
410 {
411 _XBox &xr = r->rects[i];
412 wxRect &wr = m_rects[i];
413 wr.x = xr.x1;
414 wr.y = xr.y1;
415 wr.width = xr.x2-xr.x1;
416 wr.height = xr.y2-xr.y1;
417 }
418 }
419 #endif
420 }
421 }
422
423 wxRegionIterator::wxRegionIterator()
424 {
425 m_refData = new wxRIRefData();
426 Reset();
427 }
428
429 wxRegionIterator::wxRegionIterator( const wxRegion& region )
430 {
431 m_refData = new wxRIRefData();
432 Reset(region);
433 }
434
435 void wxRegionIterator::Reset( const wxRegion& region )
436 {
437 m_region = region;
438 ((wxRIRefData*)m_refData)->CreateRects(region);
439 Reset();
440 }
441
442 bool wxRegionIterator::HaveRects() const
443 {
444 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
445 }
446
447 wxRegionIterator::operator bool () const
448 {
449 return HaveRects();
450 }
451
452 void wxRegionIterator::operator ++ ()
453 {
454 if (HaveRects()) ++m_current;
455 }
456
457 void wxRegionIterator::operator ++ (int)
458 {
459 if (HaveRects()) ++m_current;
460 }
461
462 wxCoord wxRegionIterator::GetX() const
463 {
464 if( !HaveRects() ) return 0;
465 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
466 }
467
468 wxCoord wxRegionIterator::GetY() const
469 {
470 if( !HaveRects() ) return 0;
471 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
472 }
473
474 wxCoord wxRegionIterator::GetW() const
475 {
476 if( !HaveRects() ) return -1;
477 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
478 }
479
480 wxCoord wxRegionIterator::GetH() const
481 {
482 if( !HaveRects() ) return -1;
483 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
484 }
485
486 wxRect wxRegionIterator::GetRect() const
487 {
488 wxRect r;
489 if( HaveRects() )
490 r = ((wxRIRefData*)m_refData)->m_rects[m_current];
491
492 return r;
493 }