1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/nonownedwnd.cpp
3 // Purpose: wxGTK implementation of wxNonOwnedWindow.
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
27 #include "wx/dcclient.h"
28 #include "wx/dcmemory.h"
29 #include "wx/nonownedwnd.h"
30 #include "wx/region.h"
33 #include "wx/gtk/private.h"
37 #include "wx/graphics.h"
39 // ----------------------------------------------------------------------------
40 // wxNonOwnedWindowShapeImpl: base class for region and path-based classes.
41 // ----------------------------------------------------------------------------
43 // This class provides behaviour common to both region and path-based
44 // implementations and defines SetShape() method and virtual dtor that can be
45 // called by wxNonOwnedWindow when it's realized leaving just the
46 // implementation of DoSetShape() to the derived classes.
47 class wxNonOwnedWindowShapeImpl
: public wxEvtHandler
50 wxNonOwnedWindowShapeImpl(wxWindow
* win
) : m_win(win
)
54 virtual ~wxNonOwnedWindowShapeImpl() { }
58 if ( m_win
->m_wxwindow
)
59 SetShapeIfNonNull(gtk_widget_get_window(m_win
->m_wxwindow
));
61 return SetShapeIfNonNull(gtk_widget_get_window(m_win
->m_widget
));
64 // Must be overridden to indicate if the data object must stay around or if
65 // it can be deleted once SetShape() was called.
66 virtual bool CanBeDeleted() const = 0;
69 wxWindow
* const m_win
;
72 // SetShape to the given GDK window by calling DoSetShape() if it's non-NULL.
73 bool SetShapeIfNonNull(GdkWindow
* window
)
75 return window
&& DoSetShape(window
);
78 // SetShape the shape to the given GDK window which can be either the window
79 // of m_widget or m_wxwindow of the wxWindow we're used with.
80 virtual bool DoSetShape(GdkWindow
* window
) = 0;
82 wxDECLARE_NO_COPY_CLASS(wxNonOwnedWindowShapeImpl
);
85 // Version not using any custom shape.
86 class wxNonOwnedWindowShapeImplNone
: public wxNonOwnedWindowShapeImpl
89 wxNonOwnedWindowShapeImplNone(wxWindow
* win
) :
90 wxNonOwnedWindowShapeImpl(win
)
94 virtual bool CanBeDeleted() const { return true; }
97 virtual bool DoSetShape(GdkWindow
* window
)
99 gdk_window_shape_combine_mask(window
, NULL
, 0, 0);
105 // Version using simple wxRegion.
106 class wxNonOwnedWindowShapeImplRegion
: public wxNonOwnedWindowShapeImpl
109 wxNonOwnedWindowShapeImplRegion(wxWindow
* win
, const wxRegion
& region
) :
110 wxNonOwnedWindowShapeImpl(win
),
115 virtual bool CanBeDeleted() const { return true; }
118 virtual bool DoSetShape(GdkWindow
* window
)
120 gdk_window_shape_combine_region(window
, m_region
.GetRegion(), 0, 0);
128 #if wxUSE_GRAPHICS_CONTEXT
130 // Version using more complex wxGraphicsPath.
131 class wxNonOwnedWindowShapeImplPath
: public wxNonOwnedWindowShapeImpl
134 wxNonOwnedWindowShapeImplPath(wxWindow
* win
, const wxGraphicsPath
& path
) :
135 wxNonOwnedWindowShapeImpl(win
),
137 m_mask(CreateShapeBitmap(path
), *wxBLACK
)
143 wxPaintEventHandler(wxNonOwnedWindowShapeImplPath::OnPaint
),
149 virtual ~wxNonOwnedWindowShapeImplPath()
154 wxPaintEventHandler(wxNonOwnedWindowShapeImplPath::OnPaint
),
160 // Currently we always return false from here, if drawing the border
161 // becomes optional, we could return true if we don't need to draw it.
162 virtual bool CanBeDeleted() const { return false; }
165 wxBitmap
CreateShapeBitmap(const wxGraphicsPath
& path
)
167 // Draw the path on a bitmap to get the mask we need.
169 // Notice that using monochrome bitmap here doesn't work because of an
170 // apparent wxGraphicsContext bug in wxGTK, so use a bitmap of screen
171 // depth even if this is wasteful.
172 wxBitmap
bmp(m_win
->GetSize());
176 dc
.SetBackground(*wxBLACK
);
179 wxScopedPtr
<wxGraphicsContext
> context(wxGraphicsContext::Create(dc
));
180 context
->SetBrush(*wxWHITE
);
181 context
->FillPath(path
);
186 virtual bool DoSetShape(GdkWindow
*window
)
188 GdkBitmap
* bitmap
= m_mask
.GetBitmap();
192 gdk_window_shape_combine_mask(window
, bitmap
, 0, 0);
197 // Draw a shaped window border.
198 void OnPaint(wxPaintEvent
& event
)
203 wxScopedPtr
<wxGraphicsContext
> context(wxGraphicsContext::Create(dc
));
204 context
->SetPen(wxPen(*wxLIGHT_GREY
, 2));
205 context
->StrokePath(m_path
);
208 wxGraphicsPath m_path
;
212 #endif // wxUSE_GRAPHICS_CONTEXT
214 // ============================================================================
215 // wxNonOwnedWindow implementation
216 // ============================================================================
218 wxNonOwnedWindow::~wxNonOwnedWindow()
223 void wxNonOwnedWindow::GTKHandleRealized()
225 wxNonOwnedWindowBase::GTKHandleRealized();
229 m_shapeImpl
->SetShape();
231 // We can destroy wxNonOwnedWindowShapeImplRegion immediately but need
232 // to keep wxNonOwnedWindowShapeImplPath around as it draws the border
234 if ( m_shapeImpl
->CanBeDeleted() )
242 bool wxNonOwnedWindow::DoClearShape()
246 // Nothing to do, we don't have any custom shape.
250 if ( gtk_widget_get_realized(m_widget
) )
252 // Reset the existing shape immediately.
253 wxNonOwnedWindowShapeImplNone
data(this);
256 //else: just do nothing, deleting m_shapeImpl is enough to ensure that we
257 // don't set the custom shape later when we're realized.
265 bool wxNonOwnedWindow::DoSetRegionShape(const wxRegion
& region
)
267 // In any case get rid of the old data.
271 if ( gtk_widget_get_realized(m_widget
) )
273 // We can avoid an unnecessary heap allocation and just set the shape
275 wxNonOwnedWindowShapeImplRegion
data(this, region
);
276 return data
.SetShape();
278 else // Create an object that will set shape when we're realized.
280 m_shapeImpl
= new wxNonOwnedWindowShapeImplRegion(this, region
);
282 // In general we don't know whether we are going to succeed or not, so
288 #if wxUSE_GRAPHICS_CONTEXT
290 bool wxNonOwnedWindow::DoSetPathShape(const wxGraphicsPath
& path
)
292 // The logic here is simpler than above because we always create
293 // wxNonOwnedWindowShapeImplPath on the heap as we must keep it around,
294 // even if we're already realized
297 m_shapeImpl
= new wxNonOwnedWindowShapeImplPath(this, path
);
299 if ( gtk_widget_get_realized(m_widget
) )
301 return m_shapeImpl
->SetShape();
303 //else: will be done later from GTKHandleRealized().
308 #endif // wxUSE_GRAPHICS_CONTEXT