]> git.saurik.com Git - wxWidgets.git/commitdiff
Added wxNonOwnedWindow::SetShape(wxGraphicsPath).
authorVadim Zeitlin <vadim@wxwidgets.org>
Tue, 18 Oct 2011 21:56:52 +0000 (21:56 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Tue, 18 Oct 2011 21:56:52 +0000 (21:56 +0000)
TODO: Document.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@69462 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/frame.h
include/wx/gtk/nonownedwnd.h
include/wx/msw/nonownedwnd.h
include/wx/nonownedwnd.h
include/wx/osx/nonownedwnd.h
src/gtk/nonownedwnd.cpp
src/msw/nonownedwnd.cpp
src/osx/cocoa/window.mm
src/osx/nonownedwnd_osx.cpp

index e39c17f22e3fd531e041860fd0830537c7a07cf3..efa94287cb1cf7b94e7a19d0e516a8823d41f9d6 100644 (file)
@@ -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_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
 
 // ----------------------------------------------------------------------------
 // wxFrame is a top-level window with optional menubar, statusbar and toolbar
index a722e276063d48108614ca3611cbbdfc35b1bc01..bad674cca20039300889f09cc6fdf06d712f0c31 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef _WX_GTK_NONOWNEDWND_H_
 #define _WX_GTK_NONOWNEDWND_H_
 
 #ifndef _WX_GTK_NONOWNEDWND_H_
 #define _WX_GTK_NONOWNEDWND_H_
 
+class wxNonOwnedWindowShapeImpl;
+
 // ----------------------------------------------------------------------------
 // wxNonOwnedWindow contains code common to wx{Popup,TopLevel}Window in wxGTK.
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // wxNonOwnedWindow contains code common to wx{Popup,TopLevel}Window in wxGTK.
 // ----------------------------------------------------------------------------
 class WXDLLIMPEXP_CORE wxNonOwnedWindow : public wxNonOwnedWindowBase
 {
 public:
 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();
 
 
     // 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:
 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);
 };
 
     wxDECLARE_NO_COPY_CLASS(wxNonOwnedWindow);
 };
index 3eddd78ff9839f61e88c029d6bc0bf94635697db..260c81ceb312cad0594b0dc1deae811fd9c027aa 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef _WX_MSW_NONOWNEDWND_H_
 #define _WX_MSW_NONOWNEDWND_H_
 
 #ifndef _WX_MSW_NONOWNEDWND_H_
 #define _WX_MSW_NONOWNEDWND_H_
 
+class wxNonOwnedWindowShapeImpl;
+
 // ----------------------------------------------------------------------------
 // wxNonOwnedWindow
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // wxNonOwnedWindow
 // ----------------------------------------------------------------------------
 class WXDLLIMPEXP_CORE wxNonOwnedWindow : public wxNonOwnedWindowBase
 {
 public:
 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_
 };
 
 #endif // _WX_MSW_NONOWNEDWND_H_
index 58f288065fac2e43fb7b5f463cdd4804b4f05052..ae0c04f5c6b8eb537979400db1729ab47b436416 100644 (file)
 
 #include "wx/window.h"
 
 
 #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.
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // 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.)
     // 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__)
 };
 
 #if defined(__WXDFB__)
index 60ea9120215be6b6fac8582be613849ebb692816..4ae95d3099d0049d2132fada0aaf3f3763c60c65 100644 (file)
@@ -14,6 +14,8 @@
 
 #include "wx/window.h"
 
 
 #include "wx/window.h"
 
+#include "wx/graphics.h"
+
 #if wxUSE_SYSTEM_OPTIONS
     #define wxMAC_WINDOW_PLAIN_TRANSITION wxT("mac.window-plain-transition")
 #endif
 #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; }
 
     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 ) ;
     // 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);
 
                                    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 ;
     virtual void WillBeDestroyed();
 
     wxNonOwnedWindowImpl* m_nowpeer ;
@@ -135,6 +147,9 @@ protected:
 
 private :
     wxRegion m_shape;
 
 private :
     wxRegion m_shape;
+#if wxUSE_GRAPHICS_CONTEXT
+    wxGraphicsPath m_shapePath;
+#endif // wxUSE_GRAPHICS_CONTEXT
 };
 
 // list of all frames and modeless dialogs
 };
 
 // list of all frames and modeless dialogs
index b07cdd1afb7887d88c1b5a647aee49f88797b3e3..862ac8b32bb5bbd5f39fa66db883d8943b0b2fe4 100644 (file)
@@ -24,7 +24,6 @@
 #endif
 
 #ifndef WX_PRECOMP
 #endif
 
 #ifndef WX_PRECOMP
-    #include "wx/frame.h"           // Just for wxFRAME_SHAPED.
     #include "wx/nonownedwnd.h"
     #include "wx/region.h"
 #endif // WX_PRECOMP
     #include "wx/nonownedwnd.h"
     #include "wx/region.h"
 #endif // WX_PRECOMP
 
 #include <gdk/gdk.h>
 
 
 #include <gdk/gdk.h>
 
-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<wxGraphicsContext> 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<wxGraphicsContext> 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 implementation
 // ============================================================================
 
+wxNonOwnedWindow::~wxNonOwnedWindow()
+{
+    delete m_shapeImpl;
+}
+
 void wxNonOwnedWindow::GTKHandleRealized()
 {
     wxNonOwnedWindowBase::GTKHandleRealized();
 
 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 ( 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;
     }
 }
         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
index 66e4c696685110820951b7972d2a9bba8d62ba35..e656ada141b3d26aae326c622ce8ca45747f98a4 100644 (file)
 
 #include "wx/nonownedwnd.h"
 
 
 #include "wx/nonownedwnd.h"
 
+#include "wx/msw/wrapgdip.h"
+#include "wx/graphics.h"
+#include "wx/scopedptr.h"
+
 // ============================================================================
 // wxNonOwnedWindow implementation
 // ============================================================================
 
 // ============================================================================
 // 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);
     // 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;
 }
 
     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<wxGraphicsContext> context(wxGraphicsContext::Create(win));
+        Region gr(static_cast<GraphicsPath*>(m_path.GetNativePath()));
+        win->SetShape(
+            wxRegion(
+                gr.GetHRGN(static_cast<Graphics*>(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<wxGraphicsContext> 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__
 #endif // !__WXWINCE__
index 378755f89e8c8169c914849e82a2e1998e81c59e..f19ebfb231f52c9a8759d35773c0d5b791c75aed 100644 (file)
@@ -1288,6 +1288,19 @@ void wxWidgetCocoaImpl::drawRect(void* rect, WXWidget slf, void *WXUNUSED(_cmd))
             dc.SetDeviceClippingRegion(clearRgn);
             dc.Clear();
         }
             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();
     }
 
     wxpeer->MacPaintChildrenBorders();
index 70cd61b5c4c9a8d92bdd9adb74e0a41e274b7c7c..89ad08c4f3041f55904477ecda29d064d8ad5c78 100644 (file)
@@ -497,25 +497,49 @@ WXWindow wxNonOwnedWindow::GetWXWindow() const
 // Shape implementation
 // ---------------------------------------------------------------------------
 
 // 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;
 
     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<wxGraphicsContext> 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