From: Vadim Zeitlin Date: Tue, 18 Oct 2011 21:56:52 +0000 (+0000) Subject: Added wxNonOwnedWindow::SetShape(wxGraphicsPath). X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/46ea442ca27e8b77d617481175bc7010bd602eb8 Added wxNonOwnedWindow::SetShape(wxGraphicsPath). TODO: Document. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@69462 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/frame.h b/include/wx/frame.h index e39c17f22e..efa94287cb 100644 --- a/include/wx/frame.h +++ b/include/wx/frame.h @@ -39,7 +39,6 @@ class WXDLLIMPEXP_FWD_CORE wxToolBar; #define wxFRAME_NO_TASKBAR 0x0002 // No taskbar button (MSW only) #define wxFRAME_TOOL_WINDOW 0x0004 // No taskbar button, no system menu #define wxFRAME_FLOAT_ON_PARENT 0x0008 // Always above its parent -#define wxFRAME_SHAPED 0x0010 // Create a window that is able to be shaped // ---------------------------------------------------------------------------- // wxFrame is a top-level window with optional menubar, statusbar and toolbar diff --git a/include/wx/gtk/nonownedwnd.h b/include/wx/gtk/nonownedwnd.h index a722e27606..bad674cca2 100644 --- a/include/wx/gtk/nonownedwnd.h +++ b/include/wx/gtk/nonownedwnd.h @@ -11,6 +11,8 @@ #ifndef _WX_GTK_NONOWNEDWND_H_ #define _WX_GTK_NONOWNEDWND_H_ +class wxNonOwnedWindowShapeImpl; + // ---------------------------------------------------------------------------- // wxNonOwnedWindow contains code common to wx{Popup,TopLevel}Window in wxGTK. // ---------------------------------------------------------------------------- @@ -18,16 +20,23 @@ class WXDLLIMPEXP_CORE wxNonOwnedWindow : public wxNonOwnedWindowBase { public: - wxNonOwnedWindow() { } - - virtual bool SetShape(const wxRegion& region); + wxNonOwnedWindow() { m_shapeImpl = NULL; } + virtual ~wxNonOwnedWindow(); // Overridden to actually set the shape when the window becomes realized. virtual void GTKHandleRealized(); +protected: + virtual bool DoClearShape(); + virtual bool DoSetRegionShape(const wxRegion& region); +#if wxUSE_GRAPHICS_CONTEXT + virtual bool DoSetPathShape(const wxGraphicsPath& path); +#endif // wxUSE_GRAPHICS_CONTEXT + + private: - // If valid, defines the custom shape of the window. - wxRegion m_shape; + // If non-NULL, contains information about custom window shape. + wxNonOwnedWindowShapeImpl* m_shapeImpl; wxDECLARE_NO_COPY_CLASS(wxNonOwnedWindow); }; diff --git a/include/wx/msw/nonownedwnd.h b/include/wx/msw/nonownedwnd.h index 3eddd78ff9..260c81ceb3 100644 --- a/include/wx/msw/nonownedwnd.h +++ b/include/wx/msw/nonownedwnd.h @@ -11,6 +11,8 @@ #ifndef _WX_MSW_NONOWNEDWND_H_ #define _WX_MSW_NONOWNEDWND_H_ +class wxNonOwnedWindowShapeImpl; + // ---------------------------------------------------------------------------- // wxNonOwnedWindow // ---------------------------------------------------------------------------- @@ -18,7 +20,20 @@ class WXDLLIMPEXP_CORE wxNonOwnedWindow : public wxNonOwnedWindowBase { public: - virtual bool SetShape(const wxRegion& region); + wxNonOwnedWindow(); + virtual ~wxNonOwnedWindow(); + +protected: + virtual bool DoClearShape(); + virtual bool DoSetRegionShape(const wxRegion& region); +#if wxUSE_GRAPHICS_CONTEXT + virtual bool DoSetPathShape(const wxGraphicsPath& path); + +private: + wxNonOwnedWindowShapeImpl* m_shapeImpl; +#endif // wxUSE_GRAPHICS_CONTEXT + + wxDECLARE_NO_COPY_CLASS(wxNonOwnedWindow); }; #endif // _WX_MSW_NONOWNEDWND_H_ diff --git a/include/wx/nonownedwnd.h b/include/wx/nonownedwnd.h index 58f288065f..ae0c04f5c6 100644 --- a/include/wx/nonownedwnd.h +++ b/include/wx/nonownedwnd.h @@ -14,6 +14,11 @@ #include "wx/window.h" +// Styles that can be used with any wxNonOwnedWindow: +#define wxFRAME_SHAPED 0x0010 // Create a window that is able to be shaped + +class WXDLLIMPEXP_FWD_CORE wxGraphicsPath; + // ---------------------------------------------------------------------------- // wxNonOwnedWindow: a window that is not a child window of another one. // ---------------------------------------------------------------------------- @@ -24,8 +29,52 @@ public: // Set the shape of the window to the given region. // Returns true if the platform supports this feature (and the // operation is successful.) - virtual bool SetShape(const wxRegion& WXUNUSED(region)) { return false; } + bool SetShape(const wxRegion& region) + { + // This style is in fact only needed by wxOSX/Carbon so once we don't + // use this port any more, we could get rid of this requirement, but + // for now you must specify wxFRAME_SHAPED for SetShape() to work on + // all platforms. + wxCHECK_MSG + ( + HasFlag(wxFRAME_SHAPED), false, + wxS("Shaped windows must be created with the wxFRAME_SHAPED style.") + ); + + return region.IsEmpty() ? DoClearShape() : DoSetRegionShape(region); + } + +#if wxUSE_GRAPHICS_CONTEXT + // Set the shape using the specified path. + bool SetShape(const wxGraphicsPath& path) + { + wxCHECK_MSG + ( + HasFlag(wxFRAME_SHAPED), false, + wxS("Shaped windows must be created with the wxFRAME_SHAPED style.") + ); + return DoSetPathShape(path); + } +#endif // wxUSE_GRAPHICS_CONTEXT + +protected: + virtual bool DoClearShape() + { + return false; + } + + virtual bool DoSetRegionShape(const wxRegion& WXUNUSED(region)) + { + return false; + } + +#if wxUSE_GRAPHICS_CONTEXT + virtual bool DoSetPathShape(const wxGraphicsPath& WXUNUSED(path)) + { + return false; + } +#endif // wxUSE_GRAPHICS_CONTEXT }; #if defined(__WXDFB__) diff --git a/include/wx/osx/nonownedwnd.h b/include/wx/osx/nonownedwnd.h index 60ea912021..4ae95d3099 100644 --- a/include/wx/osx/nonownedwnd.h +++ b/include/wx/osx/nonownedwnd.h @@ -14,6 +14,8 @@ #include "wx/window.h" +#include "wx/graphics.h" + #if wxUSE_SYSTEM_OPTIONS #define wxMAC_WINDOW_PLAIN_TRANSITION wxT("mac.window-plain-transition") #endif @@ -82,6 +84,10 @@ public: virtual bool SetShape(const wxRegion& region); const wxRegion& GetShape() const { return m_shape; } +#if wxUSE_GRAPHICS_CONTEXT + const wxGraphicsPath& GetShapePath() { return m_shapePath; } +#endif // wxUSE_GRAPHICS_CONTEXT + // activation hooks only necessary for MDI Implementation static void MacDelayedDeactivation(long timestamp); virtual void MacActivate( long timestamp , bool inIsActivating ) ; @@ -125,6 +131,12 @@ protected: wxShowEffect effect, unsigned timeout); + virtual bool DoClearShape(); + virtual bool DoSetRegionShape(const wxRegion& region); +#if wxUSE_GRAPHICS_CONTEXT + virtual bool DoSetPathShape(const wxGraphicsPath& path); +#endif // wxUSE_GRAPHICS_CONTEXT + virtual void WillBeDestroyed(); wxNonOwnedWindowImpl* m_nowpeer ; @@ -135,6 +147,9 @@ protected: private : wxRegion m_shape; +#if wxUSE_GRAPHICS_CONTEXT + wxGraphicsPath m_shapePath; +#endif // wxUSE_GRAPHICS_CONTEXT }; // list of all frames and modeless dialogs diff --git a/src/gtk/nonownedwnd.cpp b/src/gtk/nonownedwnd.cpp index b07cdd1afb..862ac8b32b 100644 --- a/src/gtk/nonownedwnd.cpp +++ b/src/gtk/nonownedwnd.cpp @@ -24,7 +24,6 @@ #endif #ifndef WX_PRECOMP - #include "wx/frame.h" // Just for wxFRAME_SHAPED. #include "wx/nonownedwnd.h" #include "wx/region.h" #endif // WX_PRECOMP @@ -33,61 +32,275 @@ #include -namespace +#include "wx/graphics.h" + +// ---------------------------------------------------------------------------- +// wxNonOwnedWindowShapeImpl: base class for region and path-based classes. +// ---------------------------------------------------------------------------- + +// This class provides behaviour common to both region and path-based +// implementations and defines SetShape() method and virtual dtor that can be +// called by wxNonOwnedWindow when it's realized leaving just the +// implementation of DoSetShape() to the derived classes. +class wxNonOwnedWindowShapeImpl : public wxEvtHandler { +public: + wxNonOwnedWindowShapeImpl(wxWindow* win) : m_win(win) + { + } + + virtual ~wxNonOwnedWindowShapeImpl() { } + + bool SetShape() + { + if ( m_win->m_wxwindow ) + SetShapeIfNonNull(gtk_widget_get_window(m_win->m_wxwindow)); + + return SetShapeIfNonNull(gtk_widget_get_window(m_win->m_widget)); + } + + // Must be overridden to indicate if the data object must stay around or if + // it can be deleted once SetShape() was called. + virtual bool CanBeDeleted() const = 0; + +protected: + wxWindow* const m_win; -// helper -bool do_shape_combine_region(GdkWindow* window, const wxRegion& region) +private: + // SetShape to the given GDK window by calling DoSetShape() if it's non-NULL. + bool SetShapeIfNonNull(GdkWindow* window) + { + return window && DoSetShape(window); + } + + // SetShape the shape to the given GDK window which can be either the window + // of m_widget or m_wxwindow of the wxWindow we're used with. + virtual bool DoSetShape(GdkWindow* window) = 0; + + wxDECLARE_NO_COPY_CLASS(wxNonOwnedWindowShapeImpl); +}; + +// Version not using any custom shape. +class wxNonOwnedWindowShapeImplNone : public wxNonOwnedWindowShapeImpl { - if (window) +public: + wxNonOwnedWindowShapeImplNone(wxWindow* win) : + wxNonOwnedWindowShapeImpl(win) { - if (region.IsEmpty()) - { - gdk_window_shape_combine_mask(window, NULL, 0, 0); - } - else - { - gdk_window_shape_combine_region(window, region.GetRegion(), 0, 0); - return true; - } } - return false; -} -} // anonymous namespace + virtual bool CanBeDeleted() const { return true; } +private: + virtual bool DoSetShape(GdkWindow* window) + { + gdk_window_shape_combine_mask(window, NULL, 0, 0); + + return true; + } +}; + +// Version using simple wxRegion. +class wxNonOwnedWindowShapeImplRegion : public wxNonOwnedWindowShapeImpl +{ +public: + wxNonOwnedWindowShapeImplRegion(wxWindow* win, const wxRegion& region) : + wxNonOwnedWindowShapeImpl(win), + m_region(region) + { + } + + virtual bool CanBeDeleted() const { return true; } + +private: + virtual bool DoSetShape(GdkWindow* window) + { + gdk_window_shape_combine_region(window, m_region.GetRegion(), 0, 0); + + return true; + } + + wxRegion m_region; +}; + +#if wxUSE_GRAPHICS_CONTEXT + +// Version using more complex wxGraphicsPath. +class wxNonOwnedWindowShapeImplPath : public wxNonOwnedWindowShapeImpl +{ +public: + wxNonOwnedWindowShapeImplPath(wxWindow* win, const wxGraphicsPath& path) : + wxNonOwnedWindowShapeImpl(win), + m_path(path), + m_mask(CreateShapeBitmap(path), *wxBLACK) + { + + m_win->Connect + ( + wxEVT_PAINT, + wxPaintEventHandler(wxNonOwnedWindowShapeImplPath::OnPaint), + NULL, + this + ); + } + + virtual ~wxNonOwnedWindowShapeImplPath() + { + m_win->Disconnect + ( + wxEVT_PAINT, + wxPaintEventHandler(wxNonOwnedWindowShapeImplPath::OnPaint), + NULL, + this + ); + } + + // Currently we always return false from here, if drawing the border + // becomes optional, we could return true if we don't need to draw it. + virtual bool CanBeDeleted() const { return false; } + +private: + wxBitmap CreateShapeBitmap(const wxGraphicsPath& path) + { + // Draw the path on a bitmap to get the mask we need. + // + // Notice that using monochrome bitmap here doesn't work because of an + // apparent wxGraphicsContext bug in wxGTK, so use a bitmap of screen + // depth even if this is wasteful. + wxBitmap bmp(m_win->GetSize()); + + wxMemoryDC dc(bmp); + + dc.SetBackground(*wxBLACK); + dc.Clear(); + + wxScopedPtr context(wxGraphicsContext::Create(dc)); + context->SetBrush(*wxWHITE); + context->FillPath(path); + + return bmp; + } + + virtual bool DoSetShape(GdkWindow *window) + { + GdkBitmap* bitmap = m_mask.GetBitmap(); + if ( !bitmap ) + return false; + + gdk_window_shape_combine_mask(window, bitmap, 0, 0); + + return true; + } + + // Draw a shaped window border. + void OnPaint(wxPaintEvent& event) + { + event.Skip(); + + wxPaintDC dc(m_win); + wxScopedPtr context(wxGraphicsContext::Create(dc)); + context->SetPen(wxPen(*wxLIGHT_GREY, 2)); + context->StrokePath(m_path); + } + + wxGraphicsPath m_path; + wxMask m_mask; +}; + +#endif // wxUSE_GRAPHICS_CONTEXT // ============================================================================ // wxNonOwnedWindow implementation // ============================================================================ +wxNonOwnedWindow::~wxNonOwnedWindow() +{ + delete m_shapeImpl; +} + void wxNonOwnedWindow::GTKHandleRealized() { wxNonOwnedWindowBase::GTKHandleRealized(); - if (HasFlag(wxFRAME_SHAPED)) - SetShape(m_shape); + if ( m_shapeImpl ) + { + m_shapeImpl->SetShape(); + + // We can destroy wxNonOwnedWindowShapeImplRegion immediately but need + // to keep wxNonOwnedWindowShapeImplPath around as it draws the border + // on every repaint. + if ( m_shapeImpl->CanBeDeleted() ) + { + delete m_shapeImpl; + m_shapeImpl = NULL; + } + } } -bool wxNonOwnedWindow::SetShape(const wxRegion& region) +bool wxNonOwnedWindow::DoClearShape() { - wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), false, - wxT("Shaped windows must be created with the wxFRAME_SHAPED style.")); + if ( !m_shapeImpl ) + { + // Nothing to do, we don't have any custom shape. + return true; + } if ( gtk_widget_get_realized(m_widget) ) { - if ( m_wxwindow ) - do_shape_combine_region(gtk_widget_get_window(m_wxwindow), region); + // Reset the existing shape immediately. + wxNonOwnedWindowShapeImplNone data(this); + data.SetShape(); + } + //else: just do nothing, deleting m_shapeImpl is enough to ensure that we + // don't set the custom shape later when we're realized. - return do_shape_combine_region(gtk_widget_get_window(m_widget), region); + delete m_shapeImpl; + m_shapeImpl = NULL; + + return true; +} + +bool wxNonOwnedWindow::DoSetRegionShape(const wxRegion& region) +{ + // In any case get rid of the old data. + delete m_shapeImpl; + m_shapeImpl = NULL; + + if ( gtk_widget_get_realized(m_widget) ) + { + // We can avoid an unnecessary heap allocation and just set the shape + // immediately. + wxNonOwnedWindowShapeImplRegion data(this, region); + return data.SetShape(); } - else // not realized yet + else // Create an object that will set shape when we're realized. { - // store the shape to set, it will be really set once we're realized - m_shape = region; + m_shapeImpl = new wxNonOwnedWindowShapeImplRegion(this, region); - // we don't know if we're going to succeed or fail, be optimistic by - // default + // In general we don't know whether we are going to succeed or not, so + // be optimistic. return true; } } + +#if wxUSE_GRAPHICS_CONTEXT + +bool wxNonOwnedWindow::DoSetPathShape(const wxGraphicsPath& path) +{ + // The logic here is simpler than above because we always create + // wxNonOwnedWindowShapeImplPath on the heap as we must keep it around, + // even if we're already realized + + delete m_shapeImpl; + m_shapeImpl = new wxNonOwnedWindowShapeImplPath(this, path); + + if ( gtk_widget_get_realized(m_widget) ) + { + return m_shapeImpl->SetShape(); + } + //else: will be done later from GTKHandleRealized(). + + return true; +} + +#endif // wxUSE_GRAPHICS_CONTEXT diff --git a/src/msw/nonownedwnd.cpp b/src/msw/nonownedwnd.cpp index 66e4c69668..e656ada141 100644 --- a/src/msw/nonownedwnd.cpp +++ b/src/msw/nonownedwnd.cpp @@ -34,27 +34,27 @@ #include "wx/nonownedwnd.h" +#include "wx/msw/wrapgdip.h" +#include "wx/graphics.h" +#include "wx/scopedptr.h" + // ============================================================================ // wxNonOwnedWindow implementation // ============================================================================ -bool wxNonOwnedWindow::SetShape(const wxRegion& region) +bool wxNonOwnedWindow::DoClearShape() { - wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), false, - wxT("Shaped windows must be created with the wxFRAME_SHAPED style.")); - - // The empty region signifies that the shape should be removed from the - // window. - if ( region.IsEmpty() ) + if (::SetWindowRgn(GetHwnd(), NULL, TRUE) == 0) { - if (::SetWindowRgn(GetHwnd(), NULL, TRUE) == 0) - { - wxLogLastError(wxT("SetWindowRgn")); - return false; - } - return true; + wxLogLastError(wxT("SetWindowRgn")); + return false; } + return true; +} + +bool wxNonOwnedWindow::DoSetRegionShape(const wxRegion& region) +{ // Windows takes ownership of the region, so // we'll have to make a copy of the region to give to it. DWORD noBytes = ::GetRegionData(GetHrgnOf(region), 0, NULL); @@ -77,4 +77,104 @@ bool wxNonOwnedWindow::SetShape(const wxRegion& region) return true; } +#if wxUSE_GRAPHICS_CONTEXT + +#include "wx/msw/wrapgdip.h" + +// This class contains data used only when SetPath(wxGraphicsPath) is called. +// +// Notice that it derives from wxEvtHandler solely to allow Connect()-ing its +// OnPaint() method to the window, we could get rid of this inheritance once +// Bind() can be used in wx sources. +class wxNonOwnedWindowShapeImpl : public wxEvtHandler +{ +public: + wxNonOwnedWindowShapeImpl(wxNonOwnedWindow* win, const wxGraphicsPath& path) : + m_win(win), + m_path(path) + { + // Create the region corresponding to this path and set it as windows + // shape. + wxScopedPtr context(wxGraphicsContext::Create(win)); + Region gr(static_cast(m_path.GetNativePath())); + win->SetShape( + wxRegion( + gr.GetHRGN(static_cast(context->GetNativeContext())) + ) + ); + + + // Connect to the paint event to draw the border. + // + // TODO: Do this only optionally? + m_win->Connect + ( + wxEVT_PAINT, + wxPaintEventHandler(wxNonOwnedWindowShapeImpl::OnPaint), + NULL, + this + ); + } + + virtual ~wxNonOwnedWindowShapeImpl() + { + m_win->Disconnect + ( + wxEVT_PAINT, + wxPaintEventHandler(wxNonOwnedWindowShapeImpl::OnPaint), + NULL, + this + ); + } + +private: + void OnPaint(wxPaintEvent& event) + { + event.Skip(); + + wxPaintDC dc(m_win); + wxScopedPtr context(wxGraphicsContext::Create(dc)); + context->SetPen(wxPen(*wxLIGHT_GREY, 2)); + context->StrokePath(m_path); + } + + wxNonOwnedWindow* const m_win; + wxGraphicsPath m_path; + + wxDECLARE_NO_COPY_CLASS(wxNonOwnedWindowShapeImpl); +}; + +wxNonOwnedWindow::wxNonOwnedWindow() +{ + m_shapeImpl = NULL; +} + +wxNonOwnedWindow::~wxNonOwnedWindow() +{ + delete m_shapeImpl; +} + +bool wxNonOwnedWindow::DoSetPathShape(const wxGraphicsPath& path) +{ + delete m_shapeImpl; + m_shapeImpl = new wxNonOwnedWindowShapeImpl(this, path); + + return true; +} + +#else // !wxUSE_GRAPHICS_CONTEXT + +// Trivial ctor and dtor as we don't have anything to do when wxGraphicsContext +// is not used but still define them here to avoid adding even more #if checks +// to the header, it it doesn't do any harm even though it's not needed. +wxNonOwnedWindow::wxNonOwnedWindow() +{ +} + +wxNonOwnedWindow::~wxNonOwnedWindow() +{ +} + +#endif // wxUSE_GRAPHICS_CONTEXT/!wxUSE_GRAPHICS_CONTEXT + #endif // !__WXWINCE__ diff --git a/src/osx/cocoa/window.mm b/src/osx/cocoa/window.mm index 378755f89e..f19ebfb231 100644 --- a/src/osx/cocoa/window.mm +++ b/src/osx/cocoa/window.mm @@ -1288,6 +1288,19 @@ void wxWidgetCocoaImpl::drawRect(void* rect, WXWidget slf, void *WXUNUSED(_cmd)) dc.SetDeviceClippingRegion(clearRgn); dc.Clear(); } + +#if wxUSE_GRAPHICS_CONTEXT + // If the window shape is defined by a path, stroke the path to show + // the window border. + const wxGraphicsPath& path = tlwParent->GetShapePath(); + if ( !path.IsNull() ) + { + CGContextSetLineWidth(context, 1); + CGContextSetStrokeColorWithColor(context, wxLIGHT_GREY->GetCGColor()); + CGContextAddPath(context, (CGPathRef) path.GetNativePath()); + CGContextStrokePath(context); + } +#endif // wxUSE_GRAPHICS_CONTEXT } wxpeer->MacPaintChildrenBorders(); diff --git a/src/osx/nonownedwnd_osx.cpp b/src/osx/nonownedwnd_osx.cpp index 70cd61b5c4..89ad08c4f3 100644 --- a/src/osx/nonownedwnd_osx.cpp +++ b/src/osx/nonownedwnd_osx.cpp @@ -497,25 +497,49 @@ WXWindow wxNonOwnedWindow::GetWXWindow() const // Shape implementation // --------------------------------------------------------------------------- - -bool wxNonOwnedWindow::SetShape(const wxRegion& region) +bool wxNonOwnedWindow::DoClearShape() { - wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), false, - wxT("Shaped windows must be created with the wxFRAME_SHAPED style.")); + m_shape.Clear(); + + wxSize sz = GetClientSize(); + wxRegion region(0, 0, sz.x, sz.y); + + return m_nowpeer->SetShape(region); +} +bool wxNonOwnedWindow::DoSetRegionShape(const wxRegion& region) +{ m_shape = region; - // The empty region signifies that the shape - // should be removed from the window. - if ( region.IsEmpty() ) + return m_nowpeer->SetShape(region); +} + +#if wxUSE_GRAPHICS_CONTEXT + +#include "wx/scopedptr.h" + +bool wxNonOwnedWindow::DoSetPathShape(const wxGraphicsPath& path) +{ + m_shapePath = path; + + // Convert the path to wxRegion by rendering the path on a window-sized + // bitmap, creating a mask from it and finally creating the region from + // this mask. + wxBitmap bmp(GetSize()); + { - wxSize sz = GetClientSize(); - wxRegion rgn(0, 0, sz.x, sz.y); - if ( rgn.IsEmpty() ) - return false ; - else - return SetShape(rgn); + wxMemoryDC dc(bmp); + dc.SetBackground(*wxBLACK); + dc.Clear(); + + wxScopedPtr context(wxGraphicsContext::Create(dc)); + context->SetBrush(*wxWHITE); + context->FillPath(m_shapePath); } - return m_nowpeer->SetShape(region); + bmp.SetMask(new wxMask(bmp, *wxBLACK)); + + return DoSetRegionShape(wxRegion(bmp)); } + +#endif // wxUSE_GRAPHICS_CONTEXT