X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/83df96d63a52ebb08b9e32549dc255354b4a18d0..0a9c5e3564ed35162bb8cab5af62a98405364fb8:/src/x11/region.cpp diff --git a/src/x11/region.cpp b/src/x11/region.cpp index fb3b1e3db2..2abcca5e45 100644 --- a/src/x11/region.cpp +++ b/src/x11/region.cpp @@ -1,536 +1,493 @@ ///////////////////////////////////////////////////////////////////////////// -// File: region.cpp +// File: src/x11/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 ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "region.h" -#endif +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" #include "wx/region.h" -#include "wx/gdicmn.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/gdicmn.h" +#endif #ifdef __VMS__ #pragma message disable nosimpint #endif -#include +#include "wx/x11/private.h" +#include "X11/Xutil.h" #ifdef __VMS__ #pragma message enable nosimpint #endif -// #include "wx/motif/private.h" - - 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 wxGDIRefData +{ 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() + virtual ~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; +}; - void DeleteRects(); +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- - Region m_region; - wxRect* m_rects; - int m_rectCount; - bool m_usingRects; // TRUE if we're using the above. -}; +#define M_REGIONDATA ((wxRegionRefData *)m_refData) +#define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData)) + +IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject) +IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject) + +// ---------------------------------------------------------------------------- +// wxRegion construction +// ---------------------------------------------------------------------------- + +#define M_REGIONDATA ((wxRegionRefData *)m_refData) -void wxRegionRefData::SetRects(const wxRectList& rectList) +void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h) { - DeleteRects(); - m_usingRects = (rectList.Number() > 0); - if (m_usingRects) - { - m_rectCount = rectList.Number(); - m_rects = new wxRect[m_rectCount]; - } + XRectangle rect; + rect.x = (short)x; + rect.y = (short)y; + rect.width = (unsigned short)w; + rect.height = (unsigned short)h; - 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(); + + M_REGIONDATA->m_region = XCreateRegion(); + XUnionRectWithRegion( &rect, M_REGIONDATA->m_region, M_REGIONDATA->m_region ); } -void wxRegionRefData::SetRects(int count, const wxRect* rects) +wxRegion::wxRegion( size_t WXUNUSED(n), const wxPoint *WXUNUSED(points), wxPolygonFillMode WXUNUSED(fillStyle) ) { - DeleteRects(); - m_usingRects = (count > 0); - if (m_usingRects) +#if 0 + XPoint *xpoints = new XPoint[n]; + for ( size_t i = 0 ; i < n ; i++ ) { - m_rectCount = count; - m_rects = new wxRect[m_rectCount]; - int i; - for (i = 0; i < m_rectCount; i++) - m_rects[i] = rects[i]; + xpoints[i].x = points[i].x; + xpoints[i].y = points[i].y; } -} -void wxRegionRefData::DeleteRects() -{ - if (m_rects) - { - delete[] m_rects; - m_rects = (wxRect*) NULL; - } - m_rectCount = 0; - m_usingRects = FALSE; - } + m_refData = new wxRegionRefData(); -#define M_REGION (((wxRegionRefData*)m_refData)->m_region) + Region* reg = gdk_region_polygon + ( + gdkpoints, + n, + fillStyle == wxWINDING_RULE ? GDK_WINDING_RULE + : GDK_EVEN_ODD_RULE + ); -//----------------------------------------------------------------------------- -// wxRegion -//----------------------------------------------------------------------------- + M_REGIONDATA->m_region = reg; -/*! - * Create an empty region. - */ -wxRegion::wxRegion() -{ + delete [] xpoints; +#endif } -wxRegion::wxRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h) +wxRegion::~wxRegion() { - m_refData = new wxRegionRefData; - - XRectangle rect; - rect.x = x; - rect.y = y; - rect.width = w; - rect.height = h; - XUnionRectWithRegion(&rect, M_REGION, M_REGION); + // m_refData unrefed in ~wxObject } -wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight) +wxGDIRefData *wxRegion::CreateGDIRefData() const { - m_refData = new wxRegionRefData; - - 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); + return new wxRegionRefData; } -wxRegion::wxRegion(const wxRect& rect) +wxGDIRefData *wxRegion::CloneGDIRefData(const wxGDIRefData *data) const { - m_refData = new wxRegionRefData; - - 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 new wxRegionRefData(*(wxRegionRefData *)data); } -/*! - * Destroy the region. - */ -wxRegion::~wxRegion() -{ - // m_refData unrefed in ~wxObject -} +// ---------------------------------------------------------------------------- +// wxRegion comparison +// ---------------------------------------------------------------------------- -// Get the internal region handle -WXRegion wxRegion::GetXRegion() const +bool wxRegion::DoIsEqual(const wxRegion& region) const { - wxASSERT( m_refData !=NULL ); - - return (WXRegion) ((wxRegionRefData*)m_refData)->m_region; + return XEqualRegion( M_REGIONDATA->m_region, + M_REGIONDATA_OF(region)->m_region ) == True; } -//----------------------------------------------------------------------------- -//# Modify region -//----------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// wxRegion operations +// ---------------------------------------------------------------------------- -//! Clear current region void wxRegion::Clear() { UnRef(); } -//! Combine rectangle (x, y, w, h) with this. -bool wxRegion::Combine(wxCoord x, wxCoord y, wxCoord width, wxCoord height, wxRegionOp op) +bool wxRegion::DoUnionWithRect(const wxRect& r) { - // Don't change shared data - if (!m_refData) { + // 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 ( r.IsEmpty() ) + return true; + + XRectangle rect; + rect.x = (short)r.x; + rect.y = (short)r.y; + rect.width = (unsigned short)r.width; + rect.height = (unsigned short)r.height; + + 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(); + } + else + { + AllocExclusive(); } - // If ref count is 1, that means it's 'ours' anyway so no action. - Region rectRegion = XCreateRegion(); + XUnionRectWithRegion( &rect, M_REGIONDATA->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; +} + +bool wxRegion::DoUnionWithRegion( const wxRegion& region ) +{ + wxCHECK_MSG( region.Ok(), false, wxT("invalid region") ); - switch (op) + if (!m_refData) + { + m_refData = new wxRegionRefData(); + M_REGIONDATA->m_region = XCreateRegion(); + } + else { - 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 ; + AllocExclusive(); } - return FALSE; + XUnionRegion( M_REGIONDATA->m_region, + M_REGIONDATA_OF(region)->m_region, + M_REGIONDATA->m_region ); + + return true; } -//! Union /e region with this. -bool wxRegion::Combine(const wxRegion& region, wxRegionOp op) +bool wxRegion::DoIntersect( const wxRegion& region ) { - if (region.Empty()) - return FALSE; + wxCHECK_MSG( region.Ok(), false, wxT("invalid region") ); - // 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(); + + // leave here + return true; + } + else + { + AllocExclusive(); } - switch (op) + XIntersectRegion( M_REGIONDATA->m_region, + M_REGIONDATA_OF(region)->m_region, + M_REGIONDATA->m_region ); + + return true; +} + +bool wxRegion::DoSubtract( const wxRegion& region ) +{ + wxCHECK_MSG( region.Ok(), false, wxT("invalid region") ); + + if (!m_refData) + { + m_refData = new wxRegionRefData(); + M_REGIONDATA->m_region = XCreateRegion(); + } + 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::DoXor( const wxRegion& region ) { - return Combine(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), op); + wxCHECK_MSG( region.Ok(), false, wxT("invalid region") ); + + 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; } -//----------------------------------------------------------------------------- -//# Information on region -//----------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// wxRegion tests +// ---------------------------------------------------------------------------- -// Outer bounds of region -void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const +bool wxRegion::DoGetBox( 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; + + return true; } -} + 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); + return false; + } } -// Is region empty? -bool wxRegion::Empty() const +bool wxRegion::DoOffset( 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::IsEmpty() 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 ) == True; } -// Does the region contain the point pt? -wxRegionContain wxRegion::Contains(const wxPoint& pt) const +wxRegionContain wxRegion::DoContainsPoint( 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::DoContainsRect(const wxRect& r) 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, r.x, r.y, r.width, r.height); + 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 +WXRegion *wxRegion::GetX11Region() const { if (!m_refData) - return wxOutRegion; + return NULL; - wxCoord x, y, w, h; - x = rect.x; - y = rect.y; - w = rect.GetWidth(); - h = rect.GetHeight(); - return Contains(x, y, w, h); + return (WXRegion*) M_REGIONDATA->m_region; } -bool wxRegion::UsingRects() const -{ - return ((wxRegionRefData*)m_refData)->UsingRects(); -} +// ---------------------------------------------------------------------------- +// wxRegionIterator +// ---------------------------------------------------------------------------- -/* -wxRectList& wxRegion::GetRectList() -{ - return ((wxRegionRefData*)m_refData)->GetRectList(); -} -*/ +// the following structures must match the private structures +// in X11 region code ( xc/lib/X11/region.h ) -wxRect* wxRegion::GetRects() -{ - return ((wxRegionRefData*)m_refData)->GetRects(); -} +// this makes the Region type transparent +// and we have access to the region rectangles -int wxRegion::GetRectCount() const -{ - return ((wxRegionRefData*)m_refData)->GetRectCount(); -} +struct _XBox { + short x1, x2, y1, y2; +}; -void wxRegion::SetRects(const wxRectList& rectList) -{ - ((wxRegionRefData*)m_refData)->SetRects(rectList); -} +struct _XRegion { + long size , numRects; + _XBox *rects, extents; +}; -void wxRegion::SetRects(int count, const wxRect* rects) +class wxRIRefData: public wxGDIRefData { - ((wxRegionRefData*)m_refData)->SetRects(count, rects); -} +public: + + wxRIRefData() : m_rects(0), m_numRects(0){} + virtual ~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; +}