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 <gtk/gtk.h>
19 #include <gdk/gdkx.h>
20 #include "wx/gtk/private/gtk2-compat.h"
21
22 #if WXWIN_COMPATIBILITY_2_8
23
24 //-----------------------------------------------------------------------------
25 // "realize" from m_wxwindow: used to create m_glContext implicitly
26 //-----------------------------------------------------------------------------
27
28 extern "C" {
29 static void
gtk_glwindow_realized_callback(GtkWidget * WXUNUSED (widget),wxGLCanvas * win)30 gtk_glwindow_realized_callback( GtkWidget *WXUNUSED(widget), wxGLCanvas *win )
31 {
32 win->GTKInitImplicitContext();
33 }
34 }
35
36 #endif // WXWIN_COMPATIBILITY_2_8
37
38 //-----------------------------------------------------------------------------
39 // "map" from m_wxwindow
40 //-----------------------------------------------------------------------------
41
42 #ifndef __WXGTK3__
43 extern "C" {
44 static void
gtk_glwindow_map_callback(GtkWidget * WXUNUSED (widget),wxGLCanvas * win)45 gtk_glwindow_map_callback( GtkWidget * WXUNUSED(widget), wxGLCanvas *win )
46 {
47 wxPaintEvent event( win->GetId() );
48 event.SetEventObject( win );
49 win->HandleWindowEvent( event );
50
51 win->m_exposed = false;
52 win->GetUpdateRegion().Clear();
53 }
54 }
55 #endif
56
57 //-----------------------------------------------------------------------------
58 // "expose_event" of m_wxwindow
59 //-----------------------------------------------------------------------------
60
61 extern "C" {
62 #ifdef __WXGTK3__
draw(GtkWidget *,cairo_t * cr,wxGLCanvas * win)63 static gboolean draw(GtkWidget*, cairo_t* cr, wxGLCanvas* win)
64 {
65 win->m_exposed = true;
66 if (win->m_cairoPaintContext == NULL)
67 {
68 win->m_cairoPaintContext = cr;
69 cairo_reference(cr);
70 }
71 double x1, y1, x2, y2;
72 cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
73 win->GetUpdateRegion().Union(int(x1), int(y1), int(x2 - x1), int(y2 - y1));
74 return false;
75 }
76 #else
77 static gboolean
78 gtk_glwindow_expose_callback( GtkWidget *WXUNUSED(widget), GdkEventExpose *gdk_event, wxGLCanvas *win )
79 {
80 win->m_exposed = true;
81
82 win->GetUpdateRegion().Union( gdk_event->area.x,
83 gdk_event->area.y,
84 gdk_event->area.width,
85 gdk_event->area.height );
86 return false;
87 }
88 #endif
89 }
90
91 //-----------------------------------------------------------------------------
92 // "size_allocate" of m_wxwindow
93 //-----------------------------------------------------------------------------
94
95 extern "C" {
96 static void
gtk_glcanvas_size_callback(GtkWidget * WXUNUSED (widget),GtkAllocation * WXUNUSED (alloc),wxGLCanvas * win)97 gtk_glcanvas_size_callback(GtkWidget *WXUNUSED(widget),
98 GtkAllocation * WXUNUSED(alloc),
99 wxGLCanvas *win)
100 {
101 wxSizeEvent event( wxSize(win->m_width,win->m_height), win->GetId() );
102 event.SetEventObject( win );
103 win->HandleWindowEvent( event );
104 }
105 }
106
107 //-----------------------------------------------------------------------------
108 // emission hook for "parent-set"
109 //-----------------------------------------------------------------------------
110
111 extern "C" {
112 static gboolean
parent_set_hook(GSignalInvocationHint *,guint,const GValue * param_values,void * data)113 parent_set_hook(GSignalInvocationHint*, guint, const GValue* param_values, void* data)
114 {
115 wxGLCanvas* win = (wxGLCanvas*)data;
116 if (g_value_peek_pointer(¶m_values[0]) == win->m_wxwindow)
117 {
118 const XVisualInfo* xvi = win->GetXVisualInfo();
119 GdkVisual* visual = gtk_widget_get_visual(win->m_wxwindow);
120 if (GDK_VISUAL_XVISUAL(visual)->visualid != xvi->visualid)
121 {
122 GdkScreen* screen = gtk_widget_get_screen(win->m_wxwindow);
123 visual = gdk_x11_screen_lookup_visual(screen, xvi->visualid);
124 #ifdef __WXGTK3__
125 gtk_widget_set_visual(win->m_wxwindow, visual);
126 #else
127 GdkColormap* colormap = gdk_colormap_new(visual, false);
128 gtk_widget_set_colormap(win->m_wxwindow, colormap);
129 g_object_unref(colormap);
130 #endif
131 }
132 // remove hook
133 return false;
134 }
135 return true;
136 }
137 }
138
139 //---------------------------------------------------------------------------
140 // wxGlCanvas
141 //---------------------------------------------------------------------------
142
IMPLEMENT_CLASS(wxGLCanvas,wxWindow)143 IMPLEMENT_CLASS(wxGLCanvas, wxWindow)
144
145 wxGLCanvas::wxGLCanvas(wxWindow *parent,
146 wxWindowID id,
147 const int *attribList,
148 const wxPoint& pos,
149 const wxSize& size,
150 long style,
151 const wxString& name,
152 const wxPalette& palette)
153 #if WXWIN_COMPATIBILITY_2_8
154 : m_createImplicitContext(false)
155 #endif
156 {
157 Create(parent, id, pos, size, style, name, attribList, palette);
158 }
159
160 #if WXWIN_COMPATIBILITY_2_8
161
wxGLCanvas(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name,const int * attribList,const wxPalette & palette)162 wxGLCanvas::wxGLCanvas(wxWindow *parent,
163 wxWindowID id,
164 const wxPoint& pos,
165 const wxSize& size,
166 long style,
167 const wxString& name,
168 const int *attribList,
169 const wxPalette& palette)
170 : m_createImplicitContext(true)
171 {
172 m_sharedContext = NULL;
173 m_sharedContextOf = NULL;
174
175 Create(parent, id, pos, size, style, name, attribList, palette);
176 }
177
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)178 wxGLCanvas::wxGLCanvas(wxWindow *parent,
179 const wxGLContext *shared,
180 wxWindowID id,
181 const wxPoint& pos,
182 const wxSize& size,
183 long style,
184 const wxString& name,
185 const int *attribList,
186 const wxPalette& palette)
187 : m_createImplicitContext(true)
188 {
189 m_sharedContext = const_cast<wxGLContext *>(shared);
190
191 Create(parent, id, pos, size, style, name, attribList, palette);
192 }
193
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)194 wxGLCanvas::wxGLCanvas(wxWindow *parent,
195 const wxGLCanvas *shared,
196 wxWindowID id,
197 const wxPoint& pos, const wxSize& size,
198 long style, const wxString& name,
199 const int *attribList,
200 const wxPalette& palette )
201 : m_createImplicitContext(true)
202 {
203 m_sharedContext = NULL;
204 m_sharedContextOf = const_cast<wxGLCanvas *>(shared);
205
206 Create(parent, id, pos, size, style, name, attribList, palette);
207 }
208
209 #endif // WXWIN_COMPATIBILITY_2_8
210
IsAvailable()211 static bool IsAvailable()
212 {
213 #ifdef GDK_WINDOWING_X11
214 if ( !GDK_IS_X11_DISPLAY(gdk_display_get_default()) )
215 #endif
216 {
217 wxSafeShowMessage(_("Fatal Error"), _("wxGLCanvas is only supported on X11 currently. You may be able to\nwork around this by setting environment variable GDK_BACKEND=x11 before starting\nyour program."));
218 return false;
219 }
220
221 return true;
222 }
223
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name,const int * attribList,const wxPalette & palette)224 bool wxGLCanvas::Create(wxWindow *parent,
225 wxWindowID id,
226 const wxPoint& pos,
227 const wxSize& size,
228 long style,
229 const wxString& name,
230 const int *attribList,
231 const wxPalette& palette)
232 {
233 if ( !IsAvailable() )
234 return false;
235
236 #if wxUSE_PALETTE
237 wxASSERT_MSG( !palette.IsOk(), wxT("palettes not supported") );
238 #endif // wxUSE_PALETTE
239 wxUnusedVar(palette); // Unused when wxDEBUG_LEVEL==0
240
241 m_exposed = false;
242 m_noExpose = true;
243 m_nativeSizeEvent = true;
244 #ifdef __WXGTK3__
245 m_cairoPaintContext = NULL;
246 m_backgroundStyle = wxBG_STYLE_PAINT;
247 #endif
248
249 if ( !InitVisual(attribList) )
250 return false;
251
252 // watch for the "parent-set" signal on m_wxwindow so we can set colormap
253 // before m_wxwindow is realized (which will occur before
254 // wxWindow::Create() returns if parent is already visible)
255 unsigned sig_id = g_signal_lookup("parent-set", GTK_TYPE_WIDGET);
256 g_signal_add_emission_hook(sig_id, 0, parent_set_hook, this, NULL);
257
258 wxWindow::Create( parent, id, pos, size, style, name );
259
260 gtk_widget_set_double_buffered(m_wxwindow, false);
261
262 #if WXWIN_COMPATIBILITY_2_8
263 g_signal_connect(m_wxwindow, "realize", G_CALLBACK(gtk_glwindow_realized_callback), this);
264 #endif // WXWIN_COMPATIBILITY_2_8
265 #ifdef __WXGTK3__
266 g_signal_connect(m_wxwindow, "draw", G_CALLBACK(draw), this);
267 #else
268 g_signal_connect(m_wxwindow, "map", G_CALLBACK(gtk_glwindow_map_callback), this);
269 g_signal_connect(m_wxwindow, "expose_event", G_CALLBACK(gtk_glwindow_expose_callback), this);
270 #endif
271 g_signal_connect(m_widget, "size_allocate", G_CALLBACK(gtk_glcanvas_size_callback), this);
272
273 #if WXWIN_COMPATIBILITY_2_8
274 // if our parent window is already visible, we had been realized before we
275 // connected to the "realize" signal and hence our m_glContext hasn't been
276 // initialized yet and we have to do it now
277 if (gtk_widget_get_realized(m_wxwindow))
278 gtk_glwindow_realized_callback( m_wxwindow, this );
279 #endif // WXWIN_COMPATIBILITY_2_8
280
281 #ifndef __WXGTK3__
282 if (gtk_widget_get_mapped(m_wxwindow))
283 gtk_glwindow_map_callback( m_wxwindow, this );
284 #endif
285
286 return true;
287 }
288
SetBackgroundStyle(wxBackgroundStyle)289 bool wxGLCanvas::SetBackgroundStyle(wxBackgroundStyle /* style */)
290 {
291 return false;
292 }
293
GetXWindow() const294 Window wxGLCanvas::GetXWindow() const
295 {
296 GdkWindow* window = GTKGetDrawingWindow();
297 return window ? GDK_WINDOW_XID(window) : 0;
298 }
299
OnInternalIdle()300 void wxGLCanvas::OnInternalIdle()
301 {
302 if (m_exposed)
303 {
304 #ifdef __WXGTK3__
305 GTKSendPaintEvents(m_cairoPaintContext);
306 cairo_destroy(m_cairoPaintContext);
307 m_cairoPaintContext = NULL;
308 #else
309 wxPaintEvent event( GetId() );
310 event.SetEventObject( this );
311 HandleWindowEvent( event );
312 #endif
313
314 m_exposed = false;
315 GetUpdateRegion().Clear();
316 }
317
318 wxWindow::OnInternalIdle();
319 }
320
321 #if WXWIN_COMPATIBILITY_2_8
322
GTKInitImplicitContext()323 void wxGLCanvas::GTKInitImplicitContext()
324 {
325 if ( !m_glContext && m_createImplicitContext )
326 {
327 wxGLContext *share = m_sharedContext;
328 if ( !share && m_sharedContextOf )
329 share = m_sharedContextOf->m_glContext;
330
331 m_glContext = new wxGLContext(this, share);
332 }
333 }
334
335 #endif // WXWIN_COMPATIBILITY_2_8
336
337 #endif // wxUSE_GLCANVAS
338