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