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(¶m_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