X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/7266b6723573ce6317577226cb1e5d32826e24e8..55e18dbe2faca047b2008734782d52a6eb140115:/src/x11/region.cpp?ds=sidebyside diff --git a/src/x11/region.cpp b/src/x11/region.cpp index 180ca79e2c..b1575a3f0d 100644 --- a/src/x11/region.cpp +++ b/src/x11/region.cpp @@ -1,10 +1,10 @@ ///////////////////////////////////////////////////////////////////////////// // File: region.cpp // Purpose: Region class -// Author: Markus Holzem/Julian Smart +// Author: Julian Smart, Robert Roebling // Created: Fri Oct 24 10:46:34 MET 1997 -// RCS-ID: $Id$ -// Copyright: (c) 1997 Markus Holzem/Julian Smart +// RCS-ID: $Id$ +// Copyright: (c) 1997 Julian Smart, Robert Roebling // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -14,7 +14,7 @@ #include "wx/region.h" #include "wx/gdicmn.h" -#include "wx/window.h" +#include "wx/log.h" #ifdef __VMS__ #pragma message disable nosimpint @@ -25,514 +25,534 @@ #pragma message enable nosimpint #endif - - IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject) - IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject) - // ---------------------------------------------------------------------------- -// list types +// wxRegionRefData: private class containing the information about the region // ---------------------------------------------------------------------------- -#include "wx/listimpl.cpp" - -WX_DEFINE_LIST(wxRectList); - -//----------------------------------------------------------------------------- -// wxRegionRefData implementation -//----------------------------------------------------------------------------- - -class WXDLLEXPORT wxRegionRefData : public wxGDIRefData { +class wxRegionRefData : public wxObjectRefData +{ public: wxRegionRefData() { - m_region = XCreateRegion(); - m_usingRects = FALSE; - m_rects = (wxRect*) NULL; - m_rectCount = 0; + m_region = NULL; } - - wxRegionRefData(const wxRegionRefData& data) + + wxRegionRefData(const wxRegionRefData& refData) { m_region = XCreateRegion(); - m_rects = (wxRect*) NULL; - m_rectCount = 0; - XUnionRegion(m_region, data.m_region, m_region); - - SetRects(data.m_rectCount, data.m_rects); + XUnionRegion( refData.m_region, m_region, m_region ); } - + ~wxRegionRefData() { - XDestroyRegion(m_region); - DeleteRects(); + if (m_region) + XDestroyRegion( m_region ); } - wxRect* GetRects() { return m_rects; }; - void SetRects(const wxRectList& rectList); - void SetRects(int count, const wxRect* rects); - bool UsingRects() const { return m_usingRects; } - int GetRectCount() const { return m_rectCount; } + Region m_region; +}; + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- - void DeleteRects(); +#define M_REGIONDATA ((wxRegionRefData *)m_refData) +#define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData)) - Region m_region; - wxRect* m_rects; - int m_rectCount; - bool m_usingRects; // TRUE if we're using the above. -}; +IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject); +IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject); + +// ---------------------------------------------------------------------------- +// wxRegion construction +// ---------------------------------------------------------------------------- + +#define M_REGIONDATA ((wxRegionRefData *)m_refData) + +void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h) +{ + XRectangle rect; + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + + m_refData = new wxRegionRefData(); + + M_REGIONDATA->m_region = XCreateRegion(); + XUnionRectWithRegion( &rect, M_REGIONDATA->m_region, M_REGIONDATA->m_region ); +} -void wxRegionRefData::SetRects(const wxRectList& rectList) +wxRegion::wxRegion( size_t n, const wxPoint *points, int fillStyle ) { - DeleteRects(); - m_usingRects = (rectList.Number() > 0); - if (m_usingRects) +#if 0 + XPoint *xpoints = new XPoint[n]; + for ( size_t i = 0 ; i < n ; i++ ) { - m_rectCount = rectList.Number(); - m_rects = new wxRect[m_rectCount]; + xpoints[i].x = points[i].x; + xpoints[i].y = points[i].y; } - wxRectList::Node* node = rectList.GetFirst(); - int i = 0; - while (node) { - wxRect* rect = node->GetData(); - m_rects[i] = * rect; - node = node->GetNext(); - i ++; - } + m_refData = new wxRegionRefData(); + + Region* reg = gdk_region_polygon + ( + gdkpoints, + n, + fillStyle == wxWINDING_RULE ? GDK_WINDING_RULE + : GDK_EVEN_ODD_RULE + ); + + M_REGIONDATA->m_region = reg; + + delete [] xpoints; +#endif } -void wxRegionRefData::SetRects(int count, const wxRect* rects) +wxRegion::~wxRegion() { - DeleteRects(); - m_usingRects = (count > 0); - if (m_usingRects) - { - m_rectCount = count; - m_rects = new wxRect[m_rectCount]; - int i; - for (i = 0; i < m_rectCount; i++) - m_rects[i] = rects[i]; - } + // m_refData unrefed in ~wxObject } -void wxRegionRefData::DeleteRects() +wxObjectRefData *wxRegion::CreateRefData() const { - if (m_rects) - { - delete[] m_rects; - m_rects = (wxRect*) NULL; - } - m_rectCount = 0; - m_usingRects = FALSE; - } + return new wxRegionRefData; +} -#define M_REGION (((wxRegionRefData*)m_refData)->m_region) +wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const +{ + return new wxRegionRefData(*(wxRegionRefData *)data); +} -//----------------------------------------------------------------------------- -// wxRegion -//----------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// wxRegion comparison +// ---------------------------------------------------------------------------- -/*! - * Create an empty region. - */ -wxRegion::wxRegion() +bool wxRegion::operator==( const wxRegion& region ) { + if (m_refData == region.m_refData) return TRUE; + + if (!m_refData || !region.m_refData) return FALSE; + + // compare the regions themselves, not the pointers to ref data! + return XEqualRegion( M_REGIONDATA->m_region, + M_REGIONDATA_OF(region)->m_region ); } -wxRegion::wxRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h) -{ - m_refData = new wxRegionRefData; +// ---------------------------------------------------------------------------- +// wxRegion operations +// ---------------------------------------------------------------------------- - XRectangle rect; - rect.x = x; - rect.y = y; - rect.width = w; - rect.height = h; - XUnionRectWithRegion(&rect, M_REGION, M_REGION); +void wxRegion::Clear() +{ + UnRef(); } -wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight) +bool wxRegion::Union( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { - m_refData = new wxRegionRefData; + // work around for XUnionRectWithRegion() bug: taking a union with an empty + // rect results in an empty region (at least XFree 3.3.6 and 4.0 have this + // problem) + if ( !width || !height ) + return TRUE; XRectangle rect; - rect.x = topLeft.x; - rect.y = topLeft.y; - rect.width = bottomRight.x - topLeft.x; - rect.height = bottomRight.y - topLeft.y; - XUnionRectWithRegion(&rect, M_REGION, M_REGION); -} + rect.x = x; + rect.y = y; + rect.width = width; + rect.height = height; + + if (!m_refData) + { + m_refData = new wxRegionRefData(); + M_REGIONDATA->m_region = XCreateRegion(); + XUnionRectWithRegion( &rect, M_REGIONDATA->m_region, M_REGIONDATA->m_region ); + } + else + { + AllocExclusive(); -wxRegion::wxRegion(const wxRect& rect) -{ - m_refData = new wxRegionRefData; + XUnionRectWithRegion( &rect, M_REGIONDATA->m_region, M_REGIONDATA->m_region ); + } - XRectangle rect1; - rect1.x = rect.x; - rect1.y = rect.y; - rect1.width = rect.width; - rect1.height = rect.height; - XUnionRectWithRegion(&rect1, M_REGION, M_REGION); + return TRUE; } -/*! - * Destroy the region. - */ -wxRegion::~wxRegion() +bool wxRegion::Union( const wxRect& rect ) { - // m_refData unrefed in ~wxObject + return Union( rect.x, rect.y, rect.width, rect.height ); } -// Get the internal region handle -WXRegion wxRegion::GetXRegion() const +bool wxRegion::Union( const wxRegion& region ) { - wxASSERT( m_refData !=NULL ); + if (region.IsNull()) + return FALSE; - return (WXRegion) ((wxRegionRefData*)m_refData)->m_region; + if (!m_refData) + { + m_refData = new wxRegionRefData(); + M_REGIONDATA->m_region = XCreateRegion(); + } + else + { + AllocExclusive(); + } + + XUnionRegion( M_REGIONDATA->m_region, + M_REGIONDATA_OF(region)->m_region, + M_REGIONDATA->m_region ); + + return TRUE; } -//----------------------------------------------------------------------------- -//# Modify region -//----------------------------------------------------------------------------- +bool wxRegion::Intersect( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) +{ + wxRegion reg( x, y, width, height ); -//! Clear current region -void wxRegion::Clear() + return Intersect( reg ); +} + +bool wxRegion::Intersect( const wxRect& rect ) { - UnRef(); + wxRegion reg( rect ); + + return Intersect( reg ); } -//! Combine rectangle (x, y, w, h) with this. -bool wxRegion::Combine(wxCoord x, wxCoord y, wxCoord width, wxCoord height, wxRegionOp op) +bool wxRegion::Intersect( const wxRegion& region ) { - // Don't change shared data - if (!m_refData) { + if (region.IsNull()) + return FALSE; + + if (!m_refData) + { m_refData = new wxRegionRefData(); - } else if (m_refData->GetRefCount() > 1) { - wxRegionRefData* ref = (wxRegionRefData*)m_refData; - UnRef(); - m_refData = new wxRegionRefData(*ref); + M_REGIONDATA->m_region = XCreateRegion(); + + // leave here + return TRUE; + } + else + { + AllocExclusive(); } - // If ref count is 1, that means it's 'ours' anyway so no action. - Region rectRegion = XCreateRegion(); + XIntersectRegion( M_REGIONDATA->m_region, + M_REGIONDATA_OF(region)->m_region, + M_REGIONDATA->m_region ); - XRectangle rect; - rect.x = x; - rect.y = y; - rect.width = width; - rect.height = height; - XUnionRectWithRegion(&rect, rectRegion, rectRegion); + return TRUE; +} - switch (op) - { - case wxRGN_AND: - XIntersectRegion(M_REGION, rectRegion, M_REGION); - break ; - case wxRGN_OR: - XUnionRegion(M_REGION, rectRegion, M_REGION); - break ; - case wxRGN_XOR: - // TODO - break ; - case wxRGN_DIFF: - // TODO - break ; - case wxRGN_COPY: // Don't have to do this one - default: - // TODO - break ; - } +bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) +{ + wxRegion reg( x, y, width, height ); + return Subtract( reg ); +} - return FALSE; +bool wxRegion::Subtract( const wxRect& rect ) +{ + wxRegion reg( rect ); + return Subtract( reg ); } -//! Union /e region with this. -bool wxRegion::Combine(const wxRegion& region, wxRegionOp op) +bool wxRegion::Subtract( const wxRegion& region ) { - if (region.Empty()) + if (region.IsNull()) return FALSE; - // Don't change shared data - if (!m_refData) { + if (!m_refData) + { m_refData = new wxRegionRefData(); - } else if (m_refData->GetRefCount() > 1) { - wxRegionRefData* ref = (wxRegionRefData*)m_refData; - UnRef(); - m_refData = new wxRegionRefData(*ref); + M_REGIONDATA->m_region = XCreateRegion(); } - - switch (op) + else { - case wxRGN_AND: - XIntersectRegion(M_REGION, ((wxRegionRefData*)region.m_refData)->m_region, - M_REGION); - break ; - case wxRGN_OR: - XUnionRegion(M_REGION, ((wxRegionRefData*)region.m_refData)->m_region, - M_REGION); - break ; - case wxRGN_XOR: - // TODO - break ; - case wxRGN_DIFF: - // TODO - break ; - case wxRGN_COPY: // Don't have to do this one - default: - // TODO - break ; + AllocExclusive(); } - return FALSE; + XSubtractRegion( M_REGIONDATA->m_region, + M_REGIONDATA_OF(region)->m_region, + M_REGIONDATA->m_region ); + + return TRUE; } -bool wxRegion::Combine(const wxRect& rect, wxRegionOp op) +bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { - return Combine(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), op); + wxRegion reg( x, y, width, height ); + return Xor( reg ); } -//----------------------------------------------------------------------------- -//# Information on region -//----------------------------------------------------------------------------- +bool wxRegion::Xor( const wxRect& rect ) +{ + wxRegion reg( rect ); + return Xor( reg ); +} + +bool wxRegion::Xor( const wxRegion& region ) +{ + if (region.IsNull()) + return FALSE; + + if (!m_refData) + { + m_refData = new wxRegionRefData(); + M_REGIONDATA->m_region = XCreateRegion(); + } + else + { + AllocExclusive(); + } + + XXorRegion( M_REGIONDATA->m_region, + M_REGIONDATA_OF(region)->m_region, + M_REGIONDATA->m_region ); + + return TRUE; +} + +// ---------------------------------------------------------------------------- +// wxRegion tests +// ---------------------------------------------------------------------------- -// Outer bounds of region -void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const +void wxRegion::GetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const { - if (m_refData) { + if (m_refData) + { XRectangle rect; - XClipBox(M_REGION, &rect); + XClipBox( M_REGIONDATA->m_region, &rect ); x = rect.x; y = rect.y; w = rect.width; h = rect.height; - } else { - x = y = w = h = 0; + } + else + { + x = 0; + y = 0; + w = -1; + h = -1; } } wxRect wxRegion::GetBox() const { wxCoord x, y, w, h; - GetBox(x, y, w, h); - return wxRect(x, y, w, h); + GetBox( x, y, w, h ); + return wxRect( x, y, w, h ); } -// Is region empty? -bool wxRegion::Empty() const +bool wxRegion::Offset( wxCoord x, wxCoord y ) { - return m_refData ? XEmptyRegion(M_REGION) : TRUE; -} + if (!m_refData) + return FALSE; + + AllocExclusive(); -//----------------------------------------------------------------------------- -//# Tests -//----------------------------------------------------------------------------- + XOffsetRegion( M_REGIONDATA->m_region, x, y ); -// Does the region contain the point (x,y)? -wxRegionContain wxRegion::Contains(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y)) const + return TRUE; +} + +bool wxRegion::Empty() const { if (!m_refData) - return wxOutRegion; + return TRUE; - // TODO. Return wxInRegion if within region. - if (0) - return wxInRegion; - return wxOutRegion; + return XEmptyRegion( M_REGIONDATA->m_region ); } -// Does the region contain the point pt? -wxRegionContain wxRegion::Contains(const wxPoint& pt) const +wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y ) const { if (!m_refData) return wxOutRegion; - return XPointInRegion(M_REGION, pt.x, pt.y) ? wxInRegion : wxOutRegion; + if (XPointInRegion( M_REGIONDATA->m_region, x, y )) + return wxInRegion; + else + return wxOutRegion; } -// Does the region contain the rectangle (x, y, w, h)? -wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y, wxCoord w, wxCoord h) const +wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) const { if (!m_refData) return wxOutRegion; - switch (XRectInRegion(M_REGION, x, y, w, h)) { - case RectangleIn: return wxInRegion; + int res = XRectInRegion( M_REGIONDATA->m_region, x, y, w, h ); + switch (res) + { + case RectangleIn: return wxInRegion; + case RectangleOut: return wxOutRegion; case RectanglePart: return wxPartRegion; } return wxOutRegion; } -// Does the region contain the rectangle rect -wxRegionContain wxRegion::Contains(const wxRect& rect) const +wxRegionContain wxRegion::Contains(const wxPoint& pt) const { - if (!m_refData) - return wxOutRegion; - - wxCoord x, y, w, h; - x = rect.x; - y = rect.y; - w = rect.GetWidth(); - h = rect.GetHeight(); - return Contains(x, y, w, h); + return Contains( pt.x, pt.y ); } -bool wxRegion::UsingRects() const +wxRegionContain wxRegion::Contains(const wxRect& rect) const { - return ((wxRegionRefData*)m_refData)->UsingRects(); + return Contains( rect.x, rect.y, rect.width, rect.height ); } -/* -wxRectList& wxRegion::GetRectList() +WXRegion *wxRegion::GetX11Region() const { - return ((wxRegionRefData*)m_refData)->GetRectList(); -} -*/ + if (!m_refData) + return (WXRegion*) NULL; -wxRect* wxRegion::GetRects() -{ - return ((wxRegionRefData*)m_refData)->GetRects(); + return (WXRegion*) M_REGIONDATA->m_region; } -int wxRegion::GetRectCount() const -{ - return ((wxRegionRefData*)m_refData)->GetRectCount(); -} +// ---------------------------------------------------------------------------- +// wxRegionIterator +// ---------------------------------------------------------------------------- -void wxRegion::SetRects(const wxRectList& rectList) -{ - ((wxRegionRefData*)m_refData)->SetRects(rectList); -} +// the following structures must match the private structures +// in X11 region code ( xc/lib/X11/region.h ) + +// this makes the Region type transparent +// and we have access to the region rectangles + +struct _XBox { + short x1, x2, y1, y2; +}; + +struct _XRegion { + long size , numRects; + _XBox *rects, extents; +}; -void wxRegion::SetRects(int count, const wxRect* rects) +class wxRIRefData: public wxObjectRefData { - ((wxRegionRefData*)m_refData)->SetRects(count, rects); -} +public: + + wxRIRefData() : m_rects(0), m_numRects(0){} + ~wxRIRefData(); -/////////////////////////////////////////////////////////////////////////////// -// // -// wxRegionIterator // -// // -/////////////////////////////////////////////////////////////////////////////// + wxRect *m_rects; + size_t m_numRects; -/*! - * Initialize empty iterator - */ -wxRegionIterator::wxRegionIterator() : m_current(0), m_numRects(0), m_rects(NULL) + void CreateRects( const wxRegion& r ); +}; + +wxRIRefData::~wxRIRefData() { + delete [] m_rects; } -wxRegionIterator::~wxRegionIterator() +void wxRIRefData::CreateRects( const wxRegion& region ) { if (m_rects) - delete[] m_rects; + delete [] m_rects; + + m_rects = 0; + m_numRects = 0; + + if (region.IsEmpty()) return; + + Region r = (Region) region.GetX11Region(); + if (r) + { +#if wxUSE_NANOX + GR_RECT rect; + GrGetRegionBox(r, & rect); + m_numRects = 1; + m_rects = new wxRect[1]; + m_rects[0].x = rect.x; + m_rects[0].y = rect.y; + m_rects[0].width = rect.width; + m_rects[0].height = rect.height; +#else + m_numRects = r->numRects; + if (m_numRects) + { + m_rects = new wxRect[m_numRects]; + for (size_t i=0; i < m_numRects; ++i) + { + _XBox &xr = r->rects[i]; + wxRect &wr = m_rects[i]; + wr.x = xr.x1; + wr.y = xr.y1; + wr.width = xr.x2-xr.x1; + wr.height = xr.y2-xr.y1; + } + } +#endif + } } -/*! - * Initialize iterator for region - */ -wxRegionIterator::wxRegionIterator(const wxRegion& region) +wxRegionIterator::wxRegionIterator() { - m_rects = NULL; + m_refData = new wxRIRefData(); + Reset(); +} +wxRegionIterator::wxRegionIterator( const wxRegion& region ) +{ + m_refData = new wxRIRefData(); Reset(region); } -/*! - * Reset iterator for a new /e region. - */ -void wxRegionIterator::Reset(const wxRegion& region) +void wxRegionIterator::Reset( const wxRegion& region ) { - m_current = 0; m_region = region; + ((wxRIRefData*)m_refData)->CreateRects(region); + Reset(); +} - if (m_rects) - delete[] m_rects; - - m_rects = NULL; - - if (m_region.Empty()) - m_numRects = 0; - else - { - // Create m_rects and fill with rectangles for this region. - // Since we can't find the rectangles in a region, we cheat - // by retrieving the rectangles explicitly set in wxPaintDC::wxPaintDC - // (dcclient.cpp). - if (m_region.UsingRects()) - { - wxRect* rects = m_region.GetRects(); - int count = m_region.GetRectCount(); - m_numRects = count; - m_rects = new wxRect[m_numRects]; +bool wxRegionIterator::HaveRects() const +{ + return m_current < ((wxRIRefData*)m_refData)->m_numRects; +} - for (size_t i = 0; i < m_numRects; i++) - m_rects[i] = rects[i]; - - /* - int i = 0; - wxRectList::Node* node = rectList.GetFirst(); - while (node) { - wxRect* rect = node->GetData(); - m_rects[i] = * rect; - node = node->GetNext(); - i ++; - } - */ - } - else - { - // For now, fudge by getting the whole bounding box. - m_rects = new wxRect[1]; - m_numRects = 1; - m_rects[0] = m_region.GetBox(); - } - } +wxRegionIterator::operator bool () const +{ + return HaveRects(); } -/*! - * Increment iterator. The rectangle returned is the one after the - * incrementation. - */ void wxRegionIterator::operator ++ () { - if (m_current < m_numRects) - ++m_current; + if (HaveRects()) ++m_current; } -/*! - * Increment iterator. The rectangle returned is the one before the - * incrementation. - */ void wxRegionIterator::operator ++ (int) { - if (m_current < m_numRects) - ++m_current; + if (HaveRects()) ++m_current; } wxCoord wxRegionIterator::GetX() const { - if (m_current < m_numRects) - return m_rects[m_current].x; - return 0; + if( !HaveRects() ) return 0; + return ((wxRIRefData*)m_refData)->m_rects[m_current].x; } wxCoord wxRegionIterator::GetY() const { - if (m_current < m_numRects) - return m_rects[m_current].y; - return 0; + if( !HaveRects() ) return 0; + return ((wxRIRefData*)m_refData)->m_rects[m_current].y; } wxCoord wxRegionIterator::GetW() const { - if (m_current < m_numRects) - return m_rects[m_current].width ; - return 0; + if( !HaveRects() ) return -1; + return ((wxRIRefData*)m_refData)->m_rects[m_current].width; } wxCoord wxRegionIterator::GetH() const { - if (m_current < m_numRects) - return m_rects[m_current].height; - return 0; + if( !HaveRects() ) return -1; + return ((wxRIRefData*)m_refData)->m_rects[m_current].height; +} + +wxRect wxRegionIterator::GetRect() const +{ + wxRect r; + if( HaveRects() ) + r = ((wxRIRefData*)m_refData)->m_rects[m_current]; + + return r; }