#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
#ifndef _WX_GTK_NONOWNEDWND_H_
#define _WX_GTK_NONOWNEDWND_H_
+class wxNonOwnedWindowShapeImpl;
+
// ----------------------------------------------------------------------------
// wxNonOwnedWindow contains code common to wx{Popup,TopLevel}Window in wxGTK.
// ----------------------------------------------------------------------------
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);
};
#ifndef _WX_MSW_NONOWNEDWND_H_
#define _WX_MSW_NONOWNEDWND_H_
+class wxNonOwnedWindowShapeImpl;
+
// ----------------------------------------------------------------------------
// wxNonOwnedWindow
// ----------------------------------------------------------------------------
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_
#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.
// ----------------------------------------------------------------------------
// 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__)
#include "wx/window.h"
+#include "wx/graphics.h"
+
#if wxUSE_SYSTEM_OPTIONS
#define wxMAC_WINDOW_PLAIN_TRANSITION wxT("mac.window-plain-transition")
#endif
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 ) ;
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 ;
private :
wxRegion m_shape;
+#if wxUSE_GRAPHICS_CONTEXT
+ wxGraphicsPath m_shapePath;
+#endif // wxUSE_GRAPHICS_CONTEXT
};
// list of all frames and modeless dialogs
#endif
#ifndef WX_PRECOMP
- #include "wx/frame.h" // Just for wxFRAME_SHAPED.
#include "wx/nonownedwnd.h"
#include "wx/region.h"
#endif // WX_PRECOMP
#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::~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
#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);
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__
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();
// 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<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