1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/nonownedwnd.cpp
3 // Purpose: wxGTK implementation of wxNonOwnedWindow.
4 // Author: Vadim Zeitlin
6 // Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
18 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
26 #include "wx/nonownedwnd.h"
27 #include "wx/dcclient.h"
28 #include "wx/dcmemory.h"
29 #include "wx/region.h"
32 #include "wx/graphics.h"
35 #include "wx/gtk/private/gtk2-compat.h"
37 // ----------------------------------------------------------------------------
38 // wxNonOwnedWindowShapeImpl: base class for region and path-based classes.
39 // ----------------------------------------------------------------------------
41 // This class provides behaviour common to both region and path-based
42 // implementations and defines SetShape() method and virtual dtor that can be
43 // called by wxNonOwnedWindow when it's realized leaving just the
44 // implementation of DoSetShape() to the derived classes.
45 class wxNonOwnedWindowShapeImpl
: public wxEvtHandler
48 wxNonOwnedWindowShapeImpl(wxWindow
* win
) : m_win(win
)
52 virtual ~wxNonOwnedWindowShapeImpl() { }
56 if ( m_win
->m_wxwindow
)
57 SetShapeIfNonNull(gtk_widget_get_window(m_win
->m_wxwindow
));
59 return SetShapeIfNonNull(gtk_widget_get_window(m_win
->m_widget
));
62 // Must be overridden to indicate if the data object must stay around or if
63 // it can be deleted once SetShape() was called.
64 virtual bool CanBeDeleted() const = 0;
67 wxWindow
* const m_win
;
70 // SetShape to the given GDK window by calling DoSetShape() if it's non-NULL.
71 bool SetShapeIfNonNull(GdkWindow
* window
)
73 return window
&& DoSetShape(window
);
76 // SetShape the shape to the given GDK window which can be either the window
77 // of m_widget or m_wxwindow of the wxWindow we're used with.
78 virtual bool DoSetShape(GdkWindow
* window
) = 0;
80 wxDECLARE_NO_COPY_CLASS(wxNonOwnedWindowShapeImpl
);
83 // Version not using any custom shape.
84 class wxNonOwnedWindowShapeImplNone
: public wxNonOwnedWindowShapeImpl
87 wxNonOwnedWindowShapeImplNone(wxWindow
* win
) :
88 wxNonOwnedWindowShapeImpl(win
)
92 virtual bool CanBeDeleted() const { return true; }
95 virtual bool DoSetShape(GdkWindow
* window
)
97 gdk_window_shape_combine_region(window
, NULL
, 0, 0);
103 // Version using simple wxRegion.
104 class wxNonOwnedWindowShapeImplRegion
: public wxNonOwnedWindowShapeImpl
107 wxNonOwnedWindowShapeImplRegion(wxWindow
* win
, const wxRegion
& region
) :
108 wxNonOwnedWindowShapeImpl(win
),
113 virtual bool CanBeDeleted() const { return true; }
116 virtual bool DoSetShape(GdkWindow
* window
)
118 gdk_window_shape_combine_region(window
, m_region
.GetRegion(), 0, 0);
126 #if wxUSE_GRAPHICS_CONTEXT
128 // Version using more complex wxGraphicsPath.
129 class wxNonOwnedWindowShapeImplPath
: public wxNonOwnedWindowShapeImpl
132 wxNonOwnedWindowShapeImplPath(wxWindow
* win
, const wxGraphicsPath
& path
) :
133 wxNonOwnedWindowShapeImpl(win
),
135 m_mask(CreateShapeBitmap(path
), *wxBLACK
)
141 wxPaintEventHandler(wxNonOwnedWindowShapeImplPath::OnPaint
),
147 virtual ~wxNonOwnedWindowShapeImplPath()
152 wxPaintEventHandler(wxNonOwnedWindowShapeImplPath::OnPaint
),
158 // Currently we always return false from here, if drawing the border
159 // becomes optional, we could return true if we don't need to draw it.
160 virtual bool CanBeDeleted() const { return false; }
163 wxBitmap
CreateShapeBitmap(const wxGraphicsPath
& path
)
165 // Draw the path on a bitmap to get the mask we need.
167 // Notice that using monochrome bitmap here doesn't work because of an
168 // apparent wxGraphicsContext bug in wxGTK, so use a bitmap of screen
169 // depth even if this is wasteful.
170 wxBitmap
bmp(m_win
->GetSize());
174 dc
.SetBackground(*wxBLACK
);
178 wxGraphicsContext
* context
= dc
.GetGraphicsContext();
180 wxScopedPtr
<wxGraphicsContext
> context(wxGraphicsContext::Create(dc
));
182 context
->SetBrush(*wxWHITE
);
183 context
->FillPath(path
);
188 virtual bool DoSetShape(GdkWindow
*window
)
194 cairo_region_t
* region
= gdk_cairo_region_create_from_surface(m_mask
);
195 gdk_window_shape_combine_region(window
, region
, 0, 0);
196 cairo_region_destroy(region
);
198 gdk_window_shape_combine_mask(window
, m_mask
, 0, 0);
204 // Draw a shaped window border.
205 void OnPaint(wxPaintEvent
& event
)
211 wxGraphicsContext
* context
= dc
.GetGraphicsContext();
213 wxScopedPtr
<wxGraphicsContext
> context(wxGraphicsContext::Create(dc
));
215 context
->SetPen(wxPen(*wxLIGHT_GREY
, 2));
216 context
->StrokePath(m_path
);
219 wxGraphicsPath m_path
;
223 #endif // wxUSE_GRAPHICS_CONTEXT
225 // ============================================================================
226 // wxNonOwnedWindow implementation
227 // ============================================================================
229 wxNonOwnedWindow::~wxNonOwnedWindow()
234 void wxNonOwnedWindow::GTKHandleRealized()
236 wxNonOwnedWindowBase::GTKHandleRealized();
240 m_shapeImpl
->SetShape();
242 // We can destroy wxNonOwnedWindowShapeImplRegion immediately but need
243 // to keep wxNonOwnedWindowShapeImplPath around as it draws the border
245 if ( m_shapeImpl
->CanBeDeleted() )
253 bool wxNonOwnedWindow::DoClearShape()
257 // Nothing to do, we don't have any custom shape.
261 if ( gtk_widget_get_realized(m_widget
) )
263 // Reset the existing shape immediately.
264 wxNonOwnedWindowShapeImplNone
data(this);
267 //else: just do nothing, deleting m_shapeImpl is enough to ensure that we
268 // don't set the custom shape later when we're realized.
276 bool wxNonOwnedWindow::DoSetRegionShape(const wxRegion
& region
)
278 // In any case get rid of the old data.
282 if ( gtk_widget_get_realized(m_widget
) )
284 // We can avoid an unnecessary heap allocation and just set the shape
286 wxNonOwnedWindowShapeImplRegion
data(this, region
);
287 return data
.SetShape();
289 else // Create an object that will set shape when we're realized.
291 m_shapeImpl
= new wxNonOwnedWindowShapeImplRegion(this, region
);
293 // In general we don't know whether we are going to succeed or not, so
299 #if wxUSE_GRAPHICS_CONTEXT
301 bool wxNonOwnedWindow::DoSetPathShape(const wxGraphicsPath
& path
)
303 // The logic here is simpler than above because we always create
304 // wxNonOwnedWindowShapeImplPath on the heap as we must keep it around,
305 // even if we're already realized
308 m_shapeImpl
= new wxNonOwnedWindowShapeImplPath(this, path
);
310 if ( gtk_widget_get_realized(m_widget
) )
312 return m_shapeImpl
->SetShape();
314 //else: will be done later from GTKHandleRealized().
319 #endif // wxUSE_GRAPHICS_CONTEXT