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/nonownedwnd.h"
28 #include "wx/dcclient.h"
29 #include "wx/dcmemory.h"
30 #include "wx/region.h"
33 #include "wx/graphics.h"
36 #include "wx/gtk/private/gtk2-compat.h"
38 // ----------------------------------------------------------------------------
39 // wxNonOwnedWindowShapeImpl: base class for region and path-based classes.
40 // ----------------------------------------------------------------------------
42 // This class provides behaviour common to both region and path-based
43 // implementations and defines SetShape() method and virtual dtor that can be
44 // called by wxNonOwnedWindow when it's realized leaving just the
45 // implementation of DoSetShape() to the derived classes.
46 class wxNonOwnedWindowShapeImpl
: public wxEvtHandler
49 wxNonOwnedWindowShapeImpl(wxWindow
* win
) : m_win(win
)
53 virtual ~wxNonOwnedWindowShapeImpl() { }
57 if ( m_win
->m_wxwindow
)
58 SetShapeIfNonNull(gtk_widget_get_window(m_win
->m_wxwindow
));
60 return SetShapeIfNonNull(gtk_widget_get_window(m_win
->m_widget
));
63 // Must be overridden to indicate if the data object must stay around or if
64 // it can be deleted once SetShape() was called.
65 virtual bool CanBeDeleted() const = 0;
68 wxWindow
* const m_win
;
71 // SetShape to the given GDK window by calling DoSetShape() if it's non-NULL.
72 bool SetShapeIfNonNull(GdkWindow
* window
)
74 return window
&& DoSetShape(window
);
77 // SetShape the shape to the given GDK window which can be either the window
78 // of m_widget or m_wxwindow of the wxWindow we're used with.
79 virtual bool DoSetShape(GdkWindow
* window
) = 0;
81 wxDECLARE_NO_COPY_CLASS(wxNonOwnedWindowShapeImpl
);
84 // Version not using any custom shape.
85 class wxNonOwnedWindowShapeImplNone
: public wxNonOwnedWindowShapeImpl
88 wxNonOwnedWindowShapeImplNone(wxWindow
* win
) :
89 wxNonOwnedWindowShapeImpl(win
)
93 virtual bool CanBeDeleted() const { return true; }
96 virtual bool DoSetShape(GdkWindow
* window
)
98 gdk_window_shape_combine_region(window
, NULL
, 0, 0);
104 // Version using simple wxRegion.
105 class wxNonOwnedWindowShapeImplRegion
: public wxNonOwnedWindowShapeImpl
108 wxNonOwnedWindowShapeImplRegion(wxWindow
* win
, const wxRegion
& region
) :
109 wxNonOwnedWindowShapeImpl(win
),
114 virtual bool CanBeDeleted() const { return true; }
117 virtual bool DoSetShape(GdkWindow
* window
)
119 gdk_window_shape_combine_region(window
, m_region
.GetRegion(), 0, 0);
127 #if wxUSE_GRAPHICS_CONTEXT
129 // Version using more complex wxGraphicsPath.
130 class wxNonOwnedWindowShapeImplPath
: public wxNonOwnedWindowShapeImpl
133 wxNonOwnedWindowShapeImplPath(wxWindow
* win
, const wxGraphicsPath
& path
) :
134 wxNonOwnedWindowShapeImpl(win
),
136 m_mask(CreateShapeBitmap(path
), *wxBLACK
)
142 wxPaintEventHandler(wxNonOwnedWindowShapeImplPath::OnPaint
),
148 virtual ~wxNonOwnedWindowShapeImplPath()
153 wxPaintEventHandler(wxNonOwnedWindowShapeImplPath::OnPaint
),
159 // Currently we always return false from here, if drawing the border
160 // becomes optional, we could return true if we don't need to draw it.
161 virtual bool CanBeDeleted() const { return false; }
164 wxBitmap
CreateShapeBitmap(const wxGraphicsPath
& path
)
166 // Draw the path on a bitmap to get the mask we need.
168 // Notice that using monochrome bitmap here doesn't work because of an
169 // apparent wxGraphicsContext bug in wxGTK, so use a bitmap of screen
170 // depth even if this is wasteful.
171 wxBitmap
bmp(m_win
->GetSize());
175 dc
.SetBackground(*wxBLACK
);
179 wxGraphicsContext
* context
= dc
.GetGraphicsContext();
181 wxScopedPtr
<wxGraphicsContext
> context(wxGraphicsContext::Create(dc
));
183 context
->SetBrush(*wxWHITE
);
184 context
->FillPath(path
);
189 virtual bool DoSetShape(GdkWindow
*window
)
195 cairo_region_t
* region
= gdk_cairo_region_create_from_surface(m_mask
);
196 gdk_window_shape_combine_region(window
, region
, 0, 0);
197 cairo_region_destroy(region
);
199 gdk_window_shape_combine_mask(window
, m_mask
, 0, 0);
205 // Draw a shaped window border.
206 void OnPaint(wxPaintEvent
& event
)
212 wxGraphicsContext
* context
= dc
.GetGraphicsContext();
214 wxScopedPtr
<wxGraphicsContext
> context(wxGraphicsContext::Create(dc
));
216 context
->SetPen(wxPen(*wxLIGHT_GREY
, 2));
217 context
->StrokePath(m_path
);
220 wxGraphicsPath m_path
;
224 #endif // wxUSE_GRAPHICS_CONTEXT
226 // ============================================================================
227 // wxNonOwnedWindow implementation
228 // ============================================================================
230 wxNonOwnedWindow::~wxNonOwnedWindow()
235 void wxNonOwnedWindow::GTKHandleRealized()
237 wxNonOwnedWindowBase::GTKHandleRealized();
241 m_shapeImpl
->SetShape();
243 // We can destroy wxNonOwnedWindowShapeImplRegion immediately but need
244 // to keep wxNonOwnedWindowShapeImplPath around as it draws the border
246 if ( m_shapeImpl
->CanBeDeleted() )
254 bool wxNonOwnedWindow::DoClearShape()
258 // Nothing to do, we don't have any custom shape.
262 if ( gtk_widget_get_realized(m_widget
) )
264 // Reset the existing shape immediately.
265 wxNonOwnedWindowShapeImplNone
data(this);
268 //else: just do nothing, deleting m_shapeImpl is enough to ensure that we
269 // don't set the custom shape later when we're realized.
277 bool wxNonOwnedWindow::DoSetRegionShape(const wxRegion
& region
)
279 // In any case get rid of the old data.
283 if ( gtk_widget_get_realized(m_widget
) )
285 // We can avoid an unnecessary heap allocation and just set the shape
287 wxNonOwnedWindowShapeImplRegion
data(this, region
);
288 return data
.SetShape();
290 else // Create an object that will set shape when we're realized.
292 m_shapeImpl
= new wxNonOwnedWindowShapeImplRegion(this, region
);
294 // In general we don't know whether we are going to succeed or not, so
300 #if wxUSE_GRAPHICS_CONTEXT
302 bool wxNonOwnedWindow::DoSetPathShape(const wxGraphicsPath
& path
)
304 // The logic here is simpler than above because we always create
305 // wxNonOwnedWindowShapeImplPath on the heap as we must keep it around,
306 // even if we're already realized
309 m_shapeImpl
= new wxNonOwnedWindowShapeImplPath(this, path
);
311 if ( gtk_widget_get_realized(m_widget
) )
313 return m_shapeImpl
->SetShape();
315 //else: will be done later from GTKHandleRealized().
320 #endif // wxUSE_GRAPHICS_CONTEXT