1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk/glcanvas.cpp
3 // Purpose:     wxGLCanvas, for using OpenGL/Mesa with wxWidgets and GTK
4 // Author:      Robert Roebling
5 // Modified by:
6 // Created:     17/08/98
7 // Copyright:   (c) Robert Roebling
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13 
14 #if wxUSE_GLCANVAS
15 
16 #include "wx/glcanvas.h"
17 
18 #include "wx/gtk/private/wrapgtk.h"
19 #ifdef GDK_WINDOWING_WAYLAND
20 #include <gdk/gdkwayland.h>
21 #endif
22 #ifdef GDK_WINDOWING_X11
23 #include <gdk/gdkx.h>
24 #endif
25 
26 #ifdef __WXGTK3__
27 extern "C" {
draw(GtkWidget * widget,cairo_t * cr,wxGLCanvas * win)28 static gboolean draw(GtkWidget* widget, cairo_t* cr, wxGLCanvas* win)
29 {
30     GtkAllocation a;
31     gtk_widget_get_allocation(widget, &a);
32     if (a.width > win->m_size.x || a.height > win->m_size.y)
33     {
34         // GLX buffers are apparently not reliably updated to the new size
35         // before the paint event occurs, resulting in newly exposed window
36         // areas sometimes not being painted at the end of a drag resize.
37         gdk_display_sync(gtk_widget_get_display(widget));
38     }
39     win->m_size.Set(a.width, a.height);
40 
41     win->GTKSendPaintEvents(cr);
42     return false;
43 }
44 }
45 #endif // __WXGTK3__
46 
47 //-----------------------------------------------------------------------------
48 // emission hook for "parent-set"
49 //-----------------------------------------------------------------------------
50 
51 #if !wxUSE_GLCANVAS_EGL
52 extern "C" {
53 static gboolean
parent_set_hook(GSignalInvocationHint *,guint,const GValue * param_values,void * data)54 parent_set_hook(GSignalInvocationHint*, guint, const GValue* param_values, void* data)
55 {
56     wxGLCanvas* win = (wxGLCanvas*)data;
57     if (g_value_peek_pointer(&param_values[0]) == win->m_wxwindow)
58     {
59         const XVisualInfo* xvi = static_cast<XVisualInfo*>(win->GetXVisualInfo());
60         GdkVisual* visual = gtk_widget_get_visual(win->m_wxwindow);
61         if (GDK_VISUAL_XVISUAL(visual)->visualid != xvi->visualid)
62         {
63             GdkScreen* screen = gtk_widget_get_screen(win->m_wxwindow);
64             visual = gdk_x11_screen_lookup_visual(screen, xvi->visualid);
65 #ifdef __WXGTK3__
66             gtk_widget_set_visual(win->m_wxwindow, visual);
67 #else
68             GdkColormap* colormap = gdk_colormap_new(visual, false);
69             gtk_widget_set_colormap(win->m_wxwindow, colormap);
70             g_object_unref(colormap);
71 #endif
72         }
73         // remove hook
74         return false;
75     }
76     return true;
77 }
78 }
79 #endif
80 
81 //---------------------------------------------------------------------------
82 // wxGlCanvas
83 //---------------------------------------------------------------------------
84 
85 wxIMPLEMENT_CLASS(wxGLCanvas, wxWindow);
86 
wxGLCanvas(wxWindow * parent,const wxGLAttributes & dispAttrs,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name,const wxPalette & palette)87 wxGLCanvas::wxGLCanvas(wxWindow *parent,
88                        const wxGLAttributes& dispAttrs,
89                        wxWindowID id,
90                        const wxPoint& pos,
91                        const wxSize& size,
92                        long style,
93                        const wxString& name,
94                        const wxPalette& palette)
95 #if WXWIN_COMPATIBILITY_2_8
96     : m_createImplicitContext(false)
97 #endif
98 {
99     Create(parent, dispAttrs, id, pos, size, style, name, palette);
100 }
101 
wxGLCanvas(wxWindow * parent,wxWindowID id,const int * attribList,const wxPoint & pos,const wxSize & size,long style,const wxString & name,const wxPalette & palette)102 wxGLCanvas::wxGLCanvas(wxWindow *parent,
103                        wxWindowID id,
104                        const int *attribList,
105                        const wxPoint& pos,
106                        const wxSize& size,
107                        long style,
108                        const wxString& name,
109                        const wxPalette& palette)
110 #if WXWIN_COMPATIBILITY_2_8
111     : m_createImplicitContext(false)
112 #endif
113 {
114     Create(parent, id, pos, size, style, name, attribList, palette);
115 }
116 
117 #if WXWIN_COMPATIBILITY_2_8
118 
wxGLCanvas(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name,const int * attribList,const wxPalette & palette)119 wxGLCanvas::wxGLCanvas(wxWindow *parent,
120                        wxWindowID id,
121                        const wxPoint& pos,
122                        const wxSize& size,
123                        long style,
124                        const wxString& name,
125                        const int *attribList,
126                        const wxPalette& palette)
127     : m_createImplicitContext(true)
128 {
129     m_sharedContext = NULL;
130     m_sharedContextOf = NULL;
131 
132     Create(parent, id, pos, size, style, name, attribList, palette);
133 }
134 
wxGLCanvas(wxWindow * parent,const wxGLContext * shared,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name,const int * attribList,const wxPalette & palette)135 wxGLCanvas::wxGLCanvas(wxWindow *parent,
136                        const wxGLContext *shared,
137                        wxWindowID id,
138                        const wxPoint& pos,
139                        const wxSize& size,
140                        long style,
141                        const wxString& name,
142                        const int *attribList,
143                        const wxPalette& palette)
144     : m_createImplicitContext(true)
145 {
146     m_sharedContext = const_cast<wxGLContext *>(shared);
147 
148     Create(parent, id, pos, size, style, name, attribList, palette);
149 }
150 
wxGLCanvas(wxWindow * parent,const wxGLCanvas * shared,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name,const int * attribList,const wxPalette & palette)151 wxGLCanvas::wxGLCanvas(wxWindow *parent,
152                        const wxGLCanvas *shared,
153                        wxWindowID id,
154                        const wxPoint& pos, const wxSize& size,
155                        long style, const wxString& name,
156                        const int *attribList,
157                        const wxPalette& palette )
158     : m_createImplicitContext(true)
159 {
160     m_sharedContext = NULL;
161     m_sharedContextOf = const_cast<wxGLCanvas *>(shared);
162 
163     Create(parent, id, pos, size, style, name, attribList, palette);
164 }
165 
166 #endif // WXWIN_COMPATIBILITY_2_8
167 
IsAvailable()168 static bool IsAvailable()
169 {
170 #if defined(__WXGTK3__) && (defined(GDK_WINDOWING_WAYLAND) || defined(GDK_WINDOWING_X11))
171     GdkDisplay* display = gdk_display_get_default();
172     const char* displayTypeName = g_type_name(G_TYPE_FROM_INSTANCE(display));
173 #endif
174 
175 #ifdef GDK_WINDOWING_WAYLAND
176     if (strcmp("GdkWaylandDisplay", displayTypeName) == 0)
177     {
178 #if wxUSE_GLCANVAS_EGL
179         return true;
180 #else
181         wxSafeShowMessage(_("Fatal Error"), _("This program wasn't compiled with EGL support required under Wayland, either\ninstall EGL libraries and rebuild or run it under X11 backend by setting\nenvironment variable GDK_BACKEND=x11 before starting your program."));
182         return false;
183 #endif // wxUSE_GLCANVAS_EGL
184     }
185 #endif // GDK_WINDOWING_WAYLAND
186 
187 #ifdef GDK_WINDOWING_X11
188 #ifdef __WXGTK3__
189     if (strcmp("GdkX11Display", displayTypeName) == 0)
190 #endif
191     {
192         return true;
193     }
194 #endif
195 
196     wxSafeShowMessage(_("Fatal Error"), _("wxGLCanvas is only supported on Wayland and X11 currently.  You may be able to\nwork around this by setting environment variable GDK_BACKEND=x11 before\nstarting your program."));
197     return false;
198 }
199 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name,const int * attribList,const wxPalette & palette)200 bool wxGLCanvas::Create(wxWindow *parent,
201                         wxWindowID id,
202                         const wxPoint& pos,
203                         const wxSize& size,
204                         long style,
205                         const wxString& name,
206                         const int *attribList,
207                         const wxPalette& palette)
208 {
209     if ( !IsAvailable() )
210         return false;
211 
212     // Separate 'GLXFBConfig/XVisual' attributes.
213     // Also store context attributes for wxGLContext ctor
214     wxGLAttributes dispAttrs;
215     if ( ! ParseAttribList(attribList, dispAttrs, &m_GLCTXAttrs) )
216         return false;
217 
218     return Create(parent, dispAttrs, id, pos, size, style, name, palette);
219 }
220 
Create(wxWindow * parent,const wxGLAttributes & dispAttrs,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name,const wxPalette & palette)221 bool wxGLCanvas::Create(wxWindow *parent,
222                         const wxGLAttributes& dispAttrs,
223                         wxWindowID id,
224                         const wxPoint& pos,
225                         const wxSize& size,
226                         long style,
227                         const wxString& name,
228                         const wxPalette& palette)
229 {
230     if ( !IsAvailable() )
231         return false;
232 
233 #if wxUSE_PALETTE
234     wxASSERT_MSG( !palette.IsOk(), wxT("palettes not supported") );
235 #endif // wxUSE_PALETTE
236     wxUnusedVar(palette); // Unused when wxDEBUG_LEVEL==0
237 
238     m_nativeSizeEvent = true;
239 #ifdef __WXGTK3__
240     m_noExpose = true;
241     m_backgroundStyle = wxBG_STYLE_PAINT;
242 #endif
243 
244     if ( !InitVisual(dispAttrs) )
245         return false;
246 
247     // watch for the "parent-set" signal on m_wxwindow so we can set colormap
248     // before m_wxwindow is realized (which will occur before
249     // wxWindow::Create() returns if parent is already visible)
250 #if !wxUSE_GLCANVAS_EGL
251     unsigned sig_id = g_signal_lookup("parent-set", GTK_TYPE_WIDGET);
252     g_signal_add_emission_hook(sig_id, 0, parent_set_hook, this, NULL);
253 #endif
254 
255     wxWindow::Create( parent, id, pos, size, style, name );
256 #ifdef __WXGTK3__
257     g_signal_connect(m_wxwindow, "draw", G_CALLBACK(draw), this);
258 #endif
259 
260     gtk_widget_set_double_buffered(m_wxwindow, false);
261 
262     return true;
263 }
264 
SetBackgroundStyle(wxBackgroundStyle)265 bool wxGLCanvas::SetBackgroundStyle(wxBackgroundStyle /* style */)
266 {
267     return false;
268 }
269 
GetXWindow() const270 unsigned long wxGLCanvas::GetXWindow() const
271 {
272 #if defined(GDK_WINDOWING_X11)
273     GdkWindow* window = GTKGetDrawingWindow();
274     return window ? GDK_WINDOW_XID(window) : 0;
275 #else
276     return 0;
277 #endif
278 }
279 
GTKHandleRealized()280 void wxGLCanvas::GTKHandleRealized()
281 {
282     BaseType::GTKHandleRealized();
283 
284 #if WXWIN_COMPATIBILITY_2_8
285     GTKInitImplicitContext();
286 #endif
287 #if wxUSE_GLCANVAS_EGL
288     CreateSurface();
289 #endif
290     SendSizeEvent();
291 }
292 
293 #if WXWIN_COMPATIBILITY_2_8
294 
GTKInitImplicitContext()295 void wxGLCanvas::GTKInitImplicitContext()
296 {
297     if ( !m_glContext && m_createImplicitContext )
298     {
299         wxGLContext *share = m_sharedContext;
300         if ( !share && m_sharedContextOf )
301             share = m_sharedContextOf->m_glContext;
302 
303         m_glContext = new wxGLContext(this, share);
304     }
305 }
306 
307 #endif // WXWIN_COMPATIBILITY_2_8
308 
309 #endif // wxUSE_GLCANVAS
310