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