nonownedwnd.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name: src/gtk/nonownedwnd.cpp
  3. // Purpose: wxGTK implementation of wxNonOwnedWindow.
  4. // Author: Vadim Zeitlin
  5. // Created: 2011-10-12
  6. // Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
  7. // Licence: wxWindows licence
  8. ///////////////////////////////////////////////////////////////////////////////
  9. // ============================================================================
  10. // declarations
  11. // ============================================================================
  12. // ----------------------------------------------------------------------------
  13. // headers
  14. // ----------------------------------------------------------------------------
  15. // for compilers that support precompilation, includes "wx.h".
  16. #include "wx/wxprec.h"
  17. #ifdef __BORLANDC__
  18. #pragma hdrstop
  19. #endif
  20. #ifndef WX_PRECOMP
  21. #include "wx/nonownedwnd.h"
  22. #include "wx/dcclient.h"
  23. #include "wx/dcmemory.h"
  24. #include "wx/region.h"
  25. #endif // WX_PRECOMP
  26. #include "wx/graphics.h"
  27. #include <gtk/gtk.h>
  28. #include "wx/gtk/private/gtk2-compat.h"
  29. // ----------------------------------------------------------------------------
  30. // wxNonOwnedWindowShapeImpl: base class for region and path-based classes.
  31. // ----------------------------------------------------------------------------
  32. // This class provides behaviour common to both region and path-based
  33. // implementations and defines SetShape() method and virtual dtor that can be
  34. // called by wxNonOwnedWindow when it's realized leaving just the
  35. // implementation of DoSetShape() to the derived classes.
  36. class wxNonOwnedWindowShapeImpl : public wxEvtHandler
  37. {
  38. public:
  39. wxNonOwnedWindowShapeImpl(wxWindow* win) : m_win(win)
  40. {
  41. }
  42. virtual ~wxNonOwnedWindowShapeImpl() { }
  43. bool SetShape()
  44. {
  45. if ( m_win->m_wxwindow )
  46. SetShapeIfNonNull(gtk_widget_get_window(m_win->m_wxwindow));
  47. return SetShapeIfNonNull(gtk_widget_get_window(m_win->m_widget));
  48. }
  49. // Must be overridden to indicate if the data object must stay around or if
  50. // it can be deleted once SetShape() was called.
  51. virtual bool CanBeDeleted() const = 0;
  52. protected:
  53. wxWindow* const m_win;
  54. private:
  55. // SetShape to the given GDK window by calling DoSetShape() if it's non-NULL.
  56. bool SetShapeIfNonNull(GdkWindow* window)
  57. {
  58. return window && DoSetShape(window);
  59. }
  60. // SetShape the shape to the given GDK window which can be either the window
  61. // of m_widget or m_wxwindow of the wxWindow we're used with.
  62. virtual bool DoSetShape(GdkWindow* window) = 0;
  63. wxDECLARE_NO_COPY_CLASS(wxNonOwnedWindowShapeImpl);
  64. };
  65. // Version not using any custom shape.
  66. class wxNonOwnedWindowShapeImplNone : public wxNonOwnedWindowShapeImpl
  67. {
  68. public:
  69. wxNonOwnedWindowShapeImplNone(wxWindow* win) :
  70. wxNonOwnedWindowShapeImpl(win)
  71. {
  72. }
  73. virtual bool CanBeDeleted() const { return true; }
  74. private:
  75. virtual bool DoSetShape(GdkWindow* window)
  76. {
  77. gdk_window_shape_combine_region(window, NULL, 0, 0);
  78. return true;
  79. }
  80. };
  81. // Version using simple wxRegion.
  82. class wxNonOwnedWindowShapeImplRegion : public wxNonOwnedWindowShapeImpl
  83. {
  84. public:
  85. wxNonOwnedWindowShapeImplRegion(wxWindow* win, const wxRegion& region) :
  86. wxNonOwnedWindowShapeImpl(win),
  87. m_region(region)
  88. {
  89. }
  90. virtual bool CanBeDeleted() const { return true; }
  91. private:
  92. virtual bool DoSetShape(GdkWindow* window)
  93. {
  94. gdk_window_shape_combine_region(window, m_region.GetRegion(), 0, 0);
  95. return true;
  96. }
  97. wxRegion m_region;
  98. };
  99. #if wxUSE_GRAPHICS_CONTEXT
  100. // Version using more complex wxGraphicsPath.
  101. class wxNonOwnedWindowShapeImplPath : public wxNonOwnedWindowShapeImpl
  102. {
  103. public:
  104. wxNonOwnedWindowShapeImplPath(wxWindow* win, const wxGraphicsPath& path) :
  105. wxNonOwnedWindowShapeImpl(win),
  106. m_path(path),
  107. m_mask(CreateShapeBitmap(path), *wxBLACK)
  108. {
  109. m_win->Connect
  110. (
  111. wxEVT_PAINT,
  112. wxPaintEventHandler(wxNonOwnedWindowShapeImplPath::OnPaint),
  113. NULL,
  114. this
  115. );
  116. }
  117. virtual ~wxNonOwnedWindowShapeImplPath()
  118. {
  119. m_win->Disconnect
  120. (
  121. wxEVT_PAINT,
  122. wxPaintEventHandler(wxNonOwnedWindowShapeImplPath::OnPaint),
  123. NULL,
  124. this
  125. );
  126. }
  127. // Currently we always return false from here, if drawing the border
  128. // becomes optional, we could return true if we don't need to draw it.
  129. virtual bool CanBeDeleted() const { return false; }
  130. private:
  131. wxBitmap CreateShapeBitmap(const wxGraphicsPath& path)
  132. {
  133. // Draw the path on a bitmap to get the mask we need.
  134. //
  135. // Notice that using monochrome bitmap here doesn't work because of an
  136. // apparent wxGraphicsContext bug in wxGTK, so use a bitmap of screen
  137. // depth even if this is wasteful.
  138. wxBitmap bmp(m_win->GetSize());
  139. wxMemoryDC dc(bmp);
  140. dc.SetBackground(*wxBLACK);
  141. dc.Clear();
  142. #ifdef __WXGTK3__
  143. wxGraphicsContext* context = dc.GetGraphicsContext();
  144. #else
  145. wxScopedPtr<wxGraphicsContext> context(wxGraphicsContext::Create(dc));
  146. #endif
  147. context->SetBrush(*wxWHITE);
  148. context->FillPath(path);
  149. return bmp;
  150. }
  151. virtual bool DoSetShape(GdkWindow *window)
  152. {
  153. if (!m_mask)
  154. return false;
  155. #ifdef __WXGTK3__
  156. cairo_region_t* region = gdk_cairo_region_create_from_surface(m_mask);
  157. gdk_window_shape_combine_region(window, region, 0, 0);
  158. cairo_region_destroy(region);
  159. #else
  160. gdk_window_shape_combine_mask(window, m_mask, 0, 0);
  161. #endif
  162. return true;
  163. }
  164. // Draw a shaped window border.
  165. void OnPaint(wxPaintEvent& event)
  166. {
  167. event.Skip();
  168. wxPaintDC dc(m_win);
  169. #ifdef __WXGTK3__
  170. wxGraphicsContext* context = dc.GetGraphicsContext();
  171. #else
  172. wxScopedPtr<wxGraphicsContext> context(wxGraphicsContext::Create(dc));
  173. #endif
  174. context->SetPen(wxPen(*wxLIGHT_GREY, 2));
  175. context->StrokePath(m_path);
  176. }
  177. wxGraphicsPath m_path;
  178. wxMask m_mask;
  179. };
  180. #endif // wxUSE_GRAPHICS_CONTEXT
  181. // ============================================================================
  182. // wxNonOwnedWindow implementation
  183. // ============================================================================
  184. wxNonOwnedWindow::~wxNonOwnedWindow()
  185. {
  186. delete m_shapeImpl;
  187. }
  188. void wxNonOwnedWindow::GTKHandleRealized()
  189. {
  190. wxNonOwnedWindowBase::GTKHandleRealized();
  191. if ( m_shapeImpl )
  192. {
  193. m_shapeImpl->SetShape();
  194. // We can destroy wxNonOwnedWindowShapeImplRegion immediately but need
  195. // to keep wxNonOwnedWindowShapeImplPath around as it draws the border
  196. // on every repaint.
  197. if ( m_shapeImpl->CanBeDeleted() )
  198. {
  199. delete m_shapeImpl;
  200. m_shapeImpl = NULL;
  201. }
  202. }
  203. }
  204. bool wxNonOwnedWindow::DoClearShape()
  205. {
  206. if ( !m_shapeImpl )
  207. {
  208. // Nothing to do, we don't have any custom shape.
  209. return true;
  210. }
  211. if ( gtk_widget_get_realized(m_widget) )
  212. {
  213. // Reset the existing shape immediately.
  214. wxNonOwnedWindowShapeImplNone data(this);
  215. data.SetShape();
  216. }
  217. //else: just do nothing, deleting m_shapeImpl is enough to ensure that we
  218. // don't set the custom shape later when we're realized.
  219. delete m_shapeImpl;
  220. m_shapeImpl = NULL;
  221. return true;
  222. }
  223. bool wxNonOwnedWindow::DoSetRegionShape(const wxRegion& region)
  224. {
  225. // In any case get rid of the old data.
  226. delete m_shapeImpl;
  227. m_shapeImpl = NULL;
  228. if ( gtk_widget_get_realized(m_widget) )
  229. {
  230. // We can avoid an unnecessary heap allocation and just set the shape
  231. // immediately.
  232. wxNonOwnedWindowShapeImplRegion data(this, region);
  233. return data.SetShape();
  234. }
  235. else // Create an object that will set shape when we're realized.
  236. {
  237. m_shapeImpl = new wxNonOwnedWindowShapeImplRegion(this, region);
  238. // In general we don't know whether we are going to succeed or not, so
  239. // be optimistic.
  240. return true;
  241. }
  242. }
  243. #if wxUSE_GRAPHICS_CONTEXT
  244. bool wxNonOwnedWindow::DoSetPathShape(const wxGraphicsPath& path)
  245. {
  246. // The logic here is simpler than above because we always create
  247. // wxNonOwnedWindowShapeImplPath on the heap as we must keep it around,
  248. // even if we're already realized
  249. delete m_shapeImpl;
  250. m_shapeImpl = new wxNonOwnedWindowShapeImplPath(this, path);
  251. if ( gtk_widget_get_realized(m_widget) )
  252. {
  253. return m_shapeImpl->SetShape();
  254. }
  255. //else: will be done later from GTKHandleRealized().
  256. return true;
  257. }
  258. #endif // wxUSE_GRAPHICS_CONTEXT