1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk1/glcanvas.cpp
3 // Purpose: wxGLCanvas, for using OpenGL/Mesa with wxWidgets and GTK
4 // Author: Robert Roebling
8 // Copyright: (c) Robert Roebling
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
17 #include "wx/glcanvas.h"
22 #include "wx/colour.h"
23 #include "wx/module.h"
33 #include "wx/gtk1/win_gtk.h"
34 #include "wx/gtk1/private.h"
36 //---------------------------------------------------------------------------
38 //---------------------------------------------------------------------------
40 XVisualInfo
*g_vi
= (XVisualInfo
*) NULL
;
42 //-----------------------------------------------------------------------------
44 //-----------------------------------------------------------------------------
46 extern void wxapp_install_idle_handler();
49 // ----------------------------------------------------------------------------
51 // ----------------------------------------------------------------------------
53 // wrapper around glXMakeContextCurrent/glXMakeCurrent depending on GLX
55 static void wxMakeContextCurrent(GLXDrawable drawable
, GLXContext context
)
57 if (wxGLCanvas::GetGLXVersion() >= 13)
58 glXMakeContextCurrent( GDK_DISPLAY(), drawable
, drawable
, context
);
59 else // GLX <= 1.2 doesn't have glXMakeContextCurrent()
60 glXMakeCurrent( GDK_DISPLAY(), drawable
, context
);
63 //---------------------------------------------------------------------------
65 //---------------------------------------------------------------------------
67 IMPLEMENT_CLASS(wxGLContext
,wxObject
)
69 wxGLContext::wxGLContext(wxWindow
* win
, const wxGLContext
* other
)
71 wxGLCanvas
*gc
= (wxGLCanvas
*) win
;
73 if (wxGLCanvas::GetGLXVersion() >= 13)
75 GLXFBConfig
*fbc
= gc
->m_fbc
;
76 wxCHECK_RET( fbc
, _T("invalid GLXFBConfig for OpenGl") );
77 m_glContext
= glXCreateNewContext( GDK_DISPLAY(), fbc
[0], GLX_RGBA_TYPE
,
78 other
? other
->m_glContext
: None
,
83 XVisualInfo
*vi
= (XVisualInfo
*) gc
->m_vi
;
84 wxCHECK_RET( vi
, _T("invalid visual for OpenGl") );
85 m_glContext
= glXCreateContext( GDK_DISPLAY(), vi
,
86 other
? other
->m_glContext
: None
,
90 wxASSERT_MSG( m_glContext
, _T("Couldn't create OpenGl context") );
93 wxGLContext::~wxGLContext()
98 if ( m_glContext
== glXGetCurrentContext() )
99 wxMakeContextCurrent(None
, NULL
);
101 glXDestroyContext( GDK_DISPLAY(), m_glContext
);
104 void wxGLContext::SetCurrent(const wxGLCanvas
& win
) const
109 GdkWindow
*window
= GTK_PIZZA(win
.m_wxwindow
)->bin_window
;
110 wxCHECK_RET( window
, _T("window must be shown") );
112 wxMakeContextCurrent(GDK_WINDOW_XWINDOW(window
), m_glContext
);
116 #if WXWIN_COMPATIBILITY_2_8
118 //-----------------------------------------------------------------------------
119 // "realize" from m_wxwindow: used to create m_glContext implicitly
120 //-----------------------------------------------------------------------------
124 gtk_glwindow_realized_callback( GtkWidget
*WXUNUSED(widget
), wxGLCanvas
*win
)
126 win
->GTKInitImplicitContext();
132 #endif // WXWIN_COMPATIBILITY_2_8
134 //-----------------------------------------------------------------------------
135 // "map" from m_wxwindow
136 //-----------------------------------------------------------------------------
140 gtk_glwindow_map_callback( GtkWidget
* WXUNUSED(widget
), wxGLCanvas
*win
)
142 wxPaintEvent
event( win
->GetId() );
143 event
.SetEventObject( win
);
144 win
->GetEventHandler()->ProcessEvent( event
);
146 win
->GetUpdateRegion().Clear();
152 //-----------------------------------------------------------------------------
153 // "expose_event" of m_wxwindow
154 //-----------------------------------------------------------------------------
158 gtk_glwindow_expose_callback( GtkWidget
*WXUNUSED(widget
), GdkEventExpose
*gdk_event
, wxGLCanvas
*win
)
161 wxapp_install_idle_handler();
163 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
165 gdk_event
->area
.width
,
166 gdk_event
->area
.height
);
170 //-----------------------------------------------------------------------------
171 // "draw" of m_wxwindow
172 //-----------------------------------------------------------------------------
176 gtk_glwindow_draw_callback( GtkWidget
*WXUNUSED(widget
), GdkRectangle
*rect
, wxGLCanvas
*win
)
179 wxapp_install_idle_handler();
181 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
,
182 rect
->width
, rect
->height
);
186 //-----------------------------------------------------------------------------
187 // "size_allocate" of m_wxwindow
188 //-----------------------------------------------------------------------------
192 gtk_glcanvas_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxGLCanvas
*win
)
195 wxapp_install_idle_handler();
200 wxSizeEvent
event( wxSize(win
->m_width
,win
->m_height
), win
->GetId() );
201 event
.SetEventObject( win
);
202 win
->GetEventHandler()->ProcessEvent( event
);
206 //---------------------------------------------------------------------------
208 //---------------------------------------------------------------------------
210 IMPLEMENT_CLASS(wxGLCanvas
, wxWindow
)
212 wxGLCanvas::wxGLCanvas(wxWindow
*parent
,
214 const int *attribList
,
218 const wxString
& name
,
219 const wxPalette
& palette
)
220 #if WXWIN_COMPATIBILITY_2_8
221 : m_createImplicitContext(false)
224 Create(parent
, id
, pos
, size
, style
, name
, attribList
, palette
);
227 #if WXWIN_COMPATIBILITY_2_8
229 wxGLCanvas::wxGLCanvas(wxWindow
*parent
,
234 const wxString
& name
,
235 const int *attribList
,
236 const wxPalette
& palette
)
237 : m_createImplicitContext(true)
239 Create(parent
, id
, pos
, size
, style
, name
, attribList
, palette
);
242 wxGLCanvas::wxGLCanvas(wxWindow
*parent
,
243 const wxGLContext
*shared
,
248 const wxString
& name
,
249 const int *attribList
,
250 const wxPalette
& palette
)
251 : m_createImplicitContext(true)
253 m_sharedContext
= wx_const_cast(wxGLContext
*, shared
);
255 Create(parent
, id
, pos
, size
, style
, name
, attribList
, palette
);
258 wxGLCanvas::wxGLCanvas(wxWindow
*parent
,
259 const wxGLCanvas
*shared
,
261 const wxPoint
& pos
, const wxSize
& size
,
262 long style
, const wxString
& name
,
263 const int *attribList
,
264 const wxPalette
& palette
)
265 : m_createImplicitContext(true)
267 m_sharedContextOf
= wx_const_cast(wxGLCanvas
*, shared
);
269 Create(parent
, id
, pos
, size
, style
, name
, attribList
, palette
);
272 #endif // WXWIN_COMPATIBILITY_2_8
274 bool wxGLCanvas::Create(wxWindow
*parent
,
279 const wxString
& name
,
280 const int *attribList
,
281 const wxPalette
& palette
)
284 m_nativeSizeEvent
= true;
288 if (wxGLCanvas::GetGLXVersion() >= 13)
290 // GLX >= 1.3 uses a GLXFBConfig
291 GLXFBConfig
* fbc
= NULL
;
292 if (wxTheApp
->m_glFBCInfo
!= NULL
)
294 fbc
= (GLXFBConfig
*) wxTheApp
->m_glFBCInfo
;
295 m_canFreeFBC
= false; // owned by wxTheApp - don't free upon destruction
299 fbc
= (GLXFBConfig
*) wxGLCanvas::ChooseGLFBC(attribList
);
302 m_fbc
= fbc
; // save for later use
303 wxCHECK_MSG( m_fbc
, false, _T("required FBConfig couldn't be found") );
306 XVisualInfo
*vi
= NULL
;
307 if (wxTheApp
->m_glVisualInfo
!= NULL
)
309 vi
= (XVisualInfo
*)wxTheApp
->m_glVisualInfo
;
310 m_canFreeVi
= false; // owned by wxTheApp - don't free upon destruction
314 if (wxGLCanvas::GetGLXVersion() >= 13)
316 vi
= glXGetVisualFromFBConfig(GDK_DISPLAY(), m_fbc
[0]);
319 vi
= (XVisualInfo
*) ChooseGLVisual(attribList
);
324 m_vi
= vi
; // save for later use
326 wxCHECK_MSG( m_vi
, false, _T("required visual couldn't be found") );
328 GdkColormap
*colormap
;
330 visual
= gdkx_visual_get( vi
->visualid
);
331 colormap
= gdk_colormap_new( visual
, TRUE
);
333 gtk_widget_push_colormap( colormap
);
334 gtk_widget_push_visual( visual
);
336 wxWindow::Create( parent
, id
, pos
, size
, style
, name
);
337 m_glWidget
= m_wxwindow
;
339 gtk_pizza_set_clear( GTK_PIZZA(m_wxwindow
), FALSE
);
341 #if WXWIN_COMPATIBILITY_2_8
342 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
343 GTK_SIGNAL_FUNC(gtk_glwindow_realized_callback
), (gpointer
) this);
344 #endif // WXWIN_COMPATIBILITY_2_8
346 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "map",
347 GTK_SIGNAL_FUNC(gtk_glwindow_map_callback
), (gpointer
) this);
349 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
350 GTK_SIGNAL_FUNC(gtk_glwindow_expose_callback
), (gpointer
) this);
352 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
353 GTK_SIGNAL_FUNC(gtk_glwindow_draw_callback
), (gpointer
) this);
355 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_allocate",
356 GTK_SIGNAL_FUNC(gtk_glcanvas_size_callback
), (gpointer
) this);
358 gtk_widget_pop_visual();
360 gtk_widget_pop_colormap();
362 #if WXWIN_COMPATIBILITY_2_8
363 // if our parent window is already visible, we had been realized before we
364 // connected to the "realize" signal and hence our m_glContext hasn't been
365 // initialized yet and we have to do it now
366 if (GTK_WIDGET_REALIZED(m_wxwindow
))
367 gtk_glwindow_realized_callback( m_wxwindow
, this );
368 #endif // WXWIN_COMPATIBILITY_2_8
370 if (GTK_WIDGET_MAPPED(m_wxwindow
))
371 gtk_glwindow_map_callback( m_wxwindow
, this );
376 wxGLCanvas::~wxGLCanvas()
378 GLXFBConfig
* fbc
= (GLXFBConfig
*) m_fbc
;
379 if (fbc
&& m_canFreeFBC
)
382 XVisualInfo
*vi
= (XVisualInfo
*) m_vi
;
383 if (vi
&& m_canFreeVi
)
387 void* wxGLCanvas::ChooseGLVisual(const int *attribList
)
390 GetGLAttribListFromWX( attribList
, data
);
392 Display
*dpy
= GDK_DISPLAY();
394 return glXChooseVisual( dpy
, DefaultScreen(dpy
), data
);
397 void* wxGLCanvas::ChooseGLFBC(const int *attribList
)
400 GetGLAttribListFromWX( attribList
, data
);
403 return glXChooseFBConfig( GDK_DISPLAY(), DefaultScreen(GDK_DISPLAY()),
409 wxGLCanvas::GetGLAttribListFromWX(const int *wx_attribList
, int *gl_attribList
)
411 if ( !wx_attribList
)
413 if (wxGLCanvas::GetGLXVersion() >= 13)
415 // leave GLX >= 1.3 choose the default attributes
416 gl_attribList
[0] = 0;
421 // default settings if attriblist = 0
422 gl_attribList
[i
++] = GLX_RGBA
;
423 gl_attribList
[i
++] = GLX_DOUBLEBUFFER
;
424 gl_attribList
[i
++] = GLX_DEPTH_SIZE
; gl_attribList
[i
++] = 1;
425 gl_attribList
[i
++] = GLX_RED_SIZE
; gl_attribList
[i
++] = 1;
426 gl_attribList
[i
++] = GLX_GREEN_SIZE
; gl_attribList
[i
++] = 1;
427 gl_attribList
[i
++] = GLX_BLUE_SIZE
; gl_attribList
[i
++] = 1;
428 gl_attribList
[i
++] = GLX_ALPHA_SIZE
; gl_attribList
[i
++] = 0;
429 gl_attribList
[i
++] = None
;
432 else // have non-default attributes
435 while( (wx_attribList
[arg
]!=0) && (p
<510) )
437 switch( wx_attribList
[arg
++] )
440 if (wxGLCanvas::GetGLXVersion() <= 12)
442 // for GLX >= 1.3, GLX_RGBA is useless (setting this flags will crash on most opengl implm)
443 gl_attribList
[p
++] = GLX_RGBA
;
446 case WX_GL_BUFFER_SIZE
:
447 gl_attribList
[p
++] = GLX_BUFFER_SIZE
;
448 gl_attribList
[p
++] = wx_attribList
[arg
++];
451 gl_attribList
[p
++] = GLX_LEVEL
;
452 gl_attribList
[p
++] = wx_attribList
[arg
++];
454 case WX_GL_DOUBLEBUFFER
:
455 gl_attribList
[p
++] = GLX_DOUBLEBUFFER
;
456 gl_attribList
[p
++] = 1;
459 gl_attribList
[p
++] = GLX_STEREO
;
461 case WX_GL_AUX_BUFFERS
:
462 gl_attribList
[p
++] = GLX_AUX_BUFFERS
;
463 gl_attribList
[p
++] = wx_attribList
[arg
++];
466 gl_attribList
[p
++] = GLX_RED_SIZE
;
467 gl_attribList
[p
++] = wx_attribList
[arg
++];
469 case WX_GL_MIN_GREEN
:
470 gl_attribList
[p
++] = GLX_GREEN_SIZE
;
471 gl_attribList
[p
++] = wx_attribList
[arg
++];
474 gl_attribList
[p
++] = GLX_BLUE_SIZE
;
475 gl_attribList
[p
++] = wx_attribList
[arg
++];
477 case WX_GL_MIN_ALPHA
:
478 gl_attribList
[p
++] = GLX_ALPHA_SIZE
;
479 gl_attribList
[p
++] = wx_attribList
[arg
++];
481 case WX_GL_DEPTH_SIZE
:
482 gl_attribList
[p
++] = GLX_DEPTH_SIZE
;
483 gl_attribList
[p
++] = wx_attribList
[arg
++];
485 case WX_GL_STENCIL_SIZE
:
486 gl_attribList
[p
++] = GLX_STENCIL_SIZE
;
487 gl_attribList
[p
++] = wx_attribList
[arg
++];
489 case WX_GL_MIN_ACCUM_RED
:
490 gl_attribList
[p
++] = GLX_ACCUM_RED_SIZE
;
491 gl_attribList
[p
++] = wx_attribList
[arg
++];
493 case WX_GL_MIN_ACCUM_GREEN
:
494 gl_attribList
[p
++] = GLX_ACCUM_GREEN_SIZE
;
495 gl_attribList
[p
++] = wx_attribList
[arg
++];
497 case WX_GL_MIN_ACCUM_BLUE
:
498 gl_attribList
[p
++] = GLX_ACCUM_BLUE_SIZE
;
499 gl_attribList
[p
++] = wx_attribList
[arg
++];
501 case WX_GL_MIN_ACCUM_ALPHA
:
502 gl_attribList
[p
++] = GLX_ACCUM_ALPHA_SIZE
;
503 gl_attribList
[p
++] = wx_attribList
[arg
++];
510 gl_attribList
[p
] = 0;
515 int wxGLCanvas::GetGLXVersion()
517 static int s_glxVersion
= 0;
518 if ( s_glxVersion
== 0 )
520 // check the GLX version
521 int glxMajorVer
, glxMinorVer
;
522 bool ok
= glXQueryVersion(GDK_DISPLAY(), &glxMajorVer
, &glxMinorVer
);
523 wxASSERT_MSG( ok
, _T("GLX version not found") );
525 s_glxVersion
= 10; // 1.0 by default
527 s_glxVersion
= glxMajorVer
*10 + glxMinorVer
;
533 void wxGLCanvas::SwapBuffers()
535 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
536 glXSwapBuffers( GDK_DISPLAY(), GDK_WINDOW_XWINDOW( window
) );
539 void wxGLCanvas::OnInternalIdle()
541 if (!m_updateRegion
.IsEmpty())
543 wxPaintEvent
event( GetId() );
544 event
.SetEventObject( this );
545 GetEventHandler()->ProcessEvent( event
);
547 GetUpdateRegion().Clear();
550 wxWindow::OnInternalIdle();
553 #if WXWIN_COMPATIBILITY_2_8
555 void wxGLCanvas::GTKInitImplicitContext()
557 if ( !m_glContext
&& m_createImplicitContext
)
559 wxGLContext
*share
= m_sharedContext
;
560 if ( !share
&& m_sharedContextOf
)
561 share
= m_sharedContextOf
->m_glContext
;
563 m_glContext
= new wxGLContext(this, share
);
567 #endif // WXWIN_COMPATIBILITY_2_8
569 //---------------------------------------------------------------------------
571 //---------------------------------------------------------------------------
573 bool wxGLApp::InitGLVisual(const int *attribList
)
575 if ( wxGLCanvas::GetGLXVersion() >= 13 )
579 m_glFBCInfo
= wxGLCanvas::ChooseGLFBC(attribList
);
585 XFree(m_glVisualInfo
);
586 m_glVisualInfo
= glXGetVisualFromFBConfig(GDK_DISPLAY(), ((GLXFBConfig
*)m_glFBCInfo
)[0]);
591 XFree(m_glVisualInfo
);
592 m_glVisualInfo
= wxGLCanvas::ChooseGLVisual(attribList
);
595 return m_glVisualInfo
!= NULL
;
598 #endif // wxUSE_GLCANVAS