1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/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"
19 #include "wx/glcanvas.h"
22 #include "wx/colour.h"
23 #include "wx/module.h"
33 #include "wx/gtk/win_gtk.h"
35 // DLL options compatibility check:
37 WX_CHECK_BUILD_OPTIONS("wxGL")
40 //---------------------------------------------------------------------------
42 //---------------------------------------------------------------------------
43 int wxGLCanvas::m_glxVersion
= 0;
45 //---------------------------------------------------------------------------
47 //---------------------------------------------------------------------------
49 XVisualInfo
*g_vi
= (XVisualInfo
*) NULL
;
50 //-----------------------------------------------------------------------------
52 //-----------------------------------------------------------------------------
54 extern void wxapp_install_idle_handler();
57 //---------------------------------------------------------------------------
59 //---------------------------------------------------------------------------
61 IMPLEMENT_CLASS(wxGLContext
,wxObject
)
63 wxGLContext::wxGLContext( bool WXUNUSED(isRGB
), wxWindow
*win
, const wxPalette
& WXUNUSED(palette
) )
66 m_widget
= win
->m_wxwindow
;
68 wxGLCanvas
*gc
= (wxGLCanvas
*) win
;
70 if (wxGLCanvas::GetGLXVersion() >= 13)
73 GLXFBConfig
*fbc
= gc
->m_fbc
;
74 wxCHECK_RET( fbc
, _T("invalid GLXFBConfig for OpenGl") );
75 m_glContext
= glXCreateNewContext( GDK_DISPLAY(), fbc
[0], GLX_RGBA_TYPE
, None
, GL_TRUE
);
80 XVisualInfo
*vi
= (XVisualInfo
*) gc
->m_vi
;
81 wxCHECK_RET( vi
, _T("invalid visual for OpenGl") );
82 m_glContext
= glXCreateContext( GDK_DISPLAY(), vi
, None
, GL_TRUE
);
85 wxCHECK_RET( m_glContext
, _T("Couldn't create OpenGl context") );
88 wxGLContext::wxGLContext(
89 bool WXUNUSED(isRGB
), wxWindow
*win
,
90 const wxPalette
& WXUNUSED(palette
),
91 const wxGLContext
*other
/* for sharing display lists */
95 m_widget
= win
->m_wxwindow
;
97 wxGLCanvas
*gc
= (wxGLCanvas
*) win
;
99 if (wxGLCanvas::GetGLXVersion() >= 13)
102 GLXFBConfig
*fbc
= gc
->m_fbc
;
103 wxCHECK_RET( fbc
, _T("invalid GLXFBConfig for OpenGl") );
104 m_glContext
= glXCreateNewContext( GDK_DISPLAY(), fbc
[0], GLX_RGBA_TYPE
,
105 other
? other
->m_glContext
: None
,
111 XVisualInfo
*vi
= (XVisualInfo
*) gc
->m_vi
;
112 wxCHECK_RET( vi
, _T("invalid visual for OpenGl") );
113 m_glContext
= glXCreateContext( GDK_DISPLAY(), vi
,
114 other
? other
->m_glContext
: None
,
120 wxFAIL_MSG( _T("Couldn't create OpenGl context") );
124 wxGLContext::~wxGLContext()
126 if (!m_glContext
) return;
128 if (m_glContext
== glXGetCurrentContext())
130 if (wxGLCanvas::GetGLXVersion() >= 13)
132 glXMakeContextCurrent( GDK_DISPLAY(), None
, None
, NULL
);
135 glXMakeCurrent( GDK_DISPLAY(), None
, NULL
);
138 glXDestroyContext( GDK_DISPLAY(), m_glContext
);
141 void wxGLContext::SwapBuffers()
145 GdkWindow
*window
= GTK_PIZZA(m_widget
)->bin_window
;
146 glXSwapBuffers( GDK_DISPLAY(), GDK_WINDOW_XWINDOW( window
) );
150 void wxGLContext::SetCurrent()
154 GdkWindow
*window
= GTK_PIZZA(m_widget
)->bin_window
;
156 if (wxGLCanvas::GetGLXVersion() >= 13)
158 glXMakeContextCurrent( GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window
),
159 GDK_WINDOW_XWINDOW(window
), m_glContext
);
162 glXMakeCurrent( GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window
), m_glContext
);
166 void wxGLContext::SetColour(const wxChar
*colour
)
168 wxColour col
= wxTheColourDatabase
->Find(colour
);
171 float r
= (float)(col
.Red()/256.0);
172 float g
= (float)(col
.Green()/256.0);
173 float b
= (float)(col
.Blue()/256.0);
178 void wxGLContext::SetupPixelFormat()
182 void wxGLContext::SetupPalette( const wxPalette
& WXUNUSED(palette
) )
186 wxPalette
wxGLContext::CreateDefaultPalette()
188 return wxNullPalette
;
191 //-----------------------------------------------------------------------------
192 // "realize" from m_wxwindow
193 //-----------------------------------------------------------------------------
197 gtk_glwindow_realized_callback( GtkWidget
*WXUNUSED(widget
), wxGLCanvas
*win
)
199 if ( !win
->m_glContext
)
201 wxGLContext
*share
= win
->m_sharedContext
;
202 if ( !share
&& win
->m_sharedContextOf
)
203 share
= win
->m_sharedContextOf
->GetContext();
205 win
->m_glContext
= new wxGLContext( TRUE
, win
, wxNullPalette
, share
);
212 //-----------------------------------------------------------------------------
213 // "map" from m_wxwindow
214 //-----------------------------------------------------------------------------
218 gtk_glwindow_map_callback( GtkWidget
* WXUNUSED(widget
), wxGLCanvas
*win
)
220 if (win
->m_glContext
/* && win->m_exposed*/)
222 wxPaintEvent
event( win
->GetId() );
223 event
.SetEventObject( win
);
224 win
->GetEventHandler()->ProcessEvent( event
);
226 win
->m_exposed
= FALSE
;
227 win
->GetUpdateRegion().Clear();
234 //-----------------------------------------------------------------------------
235 // "expose_event" of m_wxwindow
236 //-----------------------------------------------------------------------------
240 gtk_glwindow_expose_callback( GtkWidget
*WXUNUSED(widget
), GdkEventExpose
*gdk_event
, wxGLCanvas
*win
)
243 wxapp_install_idle_handler();
245 win
->m_exposed
= TRUE
;
247 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
249 gdk_event
->area
.width
,
250 gdk_event
->area
.height
);
254 //-----------------------------------------------------------------------------
255 // "size_allocate" of m_wxwindow
256 //-----------------------------------------------------------------------------
260 gtk_glcanvas_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxGLCanvas
*win
)
263 wxapp_install_idle_handler();
268 wxSizeEvent
event( wxSize(win
->m_width
,win
->m_height
), win
->GetId() );
269 event
.SetEventObject( win
);
270 win
->GetEventHandler()->ProcessEvent( event
);
274 //---------------------------------------------------------------------------
276 //---------------------------------------------------------------------------
278 IMPLEMENT_CLASS(wxGLCanvas
, wxWindow
)
280 BEGIN_EVENT_TABLE(wxGLCanvas
, wxWindow
)
281 EVT_SIZE(wxGLCanvas::OnSize
)
284 wxGLCanvas::wxGLCanvas( wxWindow
*parent
, wxWindowID id
,
285 const wxPoint
& pos
, const wxSize
& size
,
286 long style
, const wxString
& name
,
288 const wxPalette
& palette
)
290 Create( parent
, NULL
, NULL
, id
, pos
, size
, style
, name
, attribList
, palette
);
293 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
294 const wxGLContext
*shared
,
296 const wxPoint
& pos
, const wxSize
& size
,
297 long style
, const wxString
& name
,
299 const wxPalette
& palette
)
301 Create( parent
, shared
, NULL
, id
, pos
, size
, style
, name
, attribList
, palette
);
304 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
305 const wxGLCanvas
*shared
,
307 const wxPoint
& pos
, const wxSize
& size
,
308 long style
, const wxString
& name
,
310 const wxPalette
& palette
)
312 Create( parent
, NULL
, shared
, id
, pos
, size
, style
, name
, attribList
, palette
);
315 bool wxGLCanvas::Create( wxWindow
*parent
,
316 const wxGLContext
*shared
,
317 const wxGLCanvas
*shared_context_of
,
319 const wxPoint
& pos
, const wxSize
& size
,
320 long style
, const wxString
& name
,
322 const wxPalette
& palette
)
324 m_sharedContext
= (wxGLContext
*)shared
; // const_cast
325 m_sharedContextOf
= (wxGLCanvas
*)shared_context_of
; // const_cast
326 m_glContext
= (wxGLContext
*) NULL
;
330 m_nativeSizeEvent
= TRUE
;
334 // to be sure the glx version is known
335 wxGLCanvas::QueryGLXVersion();
337 if (wxGLCanvas::GetGLXVersion() >= 13)
339 // GLX >= 1.3 uses a GLXFBConfig
340 GLXFBConfig
* fbc
= NULL
;
341 if (wxTheApp
->m_glFBCInfo
!= NULL
)
343 fbc
= (GLXFBConfig
*) wxTheApp
->m_glFBCInfo
;
344 m_canFreeFBC
= FALSE
; // owned by wxTheApp - don't free upon destruction
348 fbc
= (GLXFBConfig
*) wxGLCanvas::ChooseGLFBC(attribList
);
351 m_fbc
= fbc
; // save for later use
352 wxCHECK_MSG( m_fbc
, FALSE
, _T("required FBConfig couldn't be found") );
355 XVisualInfo
*vi
= NULL
;
356 if (wxTheApp
->m_glVisualInfo
!= NULL
)
358 vi
= (XVisualInfo
*)wxTheApp
->m_glVisualInfo
;
359 m_canFreeVi
= FALSE
; // owned by wxTheApp - don't free upon destruction
363 if (wxGLCanvas::GetGLXVersion() >= 13)
365 vi
= glXGetVisualFromFBConfig(GDK_DISPLAY(), m_fbc
[0]);
368 vi
= (XVisualInfo
*) ChooseGLVisual(attribList
);
373 m_vi
= vi
; // save for later use
375 wxCHECK_MSG( m_vi
, FALSE
, _T("required visual couldn't be found") );
377 GdkColormap
*colormap
;
379 // MR: This needs a fix for lower gtk+ versions too. Might need to rethink logic (FIXME)
380 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2,2,0)
381 if (!gtk_check_version(2,2,0))
383 wxWindow::Create( parent
, id
, pos
, size
, style
, name
);
385 m_glWidget
= m_wxwindow
;
387 GdkScreen
*screen
= gtk_widget_get_screen( m_glWidget
);
388 colormap
= gdk_screen_get_default_colormap(screen
);
389 visual
= gdk_colormap_get_visual(colormap
);
391 if (GDK_VISUAL_XVISUAL(visual
)->visualid
!= vi
->visualid
)
393 visual
= gdk_x11_screen_lookup_visual( screen
, vi
->visualid
);
394 colormap
= gdk_colormap_new(visual
, FALSE
);
397 gtk_widget_set_colormap( m_glWidget
, colormap
);
402 visual
= gdkx_visual_get( vi
->visualid
);
403 colormap
= gdk_colormap_new( visual
, TRUE
);
405 gtk_widget_push_colormap( colormap
);
406 gtk_widget_push_visual( visual
);
408 wxWindow::Create( parent
, id
, pos
, size
, style
, name
);
409 m_glWidget
= m_wxwindow
;
412 gtk_widget_set_double_buffered( m_glWidget
, FALSE
);
414 gtk_pizza_set_clear( GTK_PIZZA(m_wxwindow
), FALSE
);
416 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
417 GTK_SIGNAL_FUNC(gtk_glwindow_realized_callback
), (gpointer
) this );
419 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "map",
420 GTK_SIGNAL_FUNC(gtk_glwindow_map_callback
), (gpointer
) this );
422 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
423 GTK_SIGNAL_FUNC(gtk_glwindow_expose_callback
), (gpointer
)this );
425 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_allocate",
426 GTK_SIGNAL_FUNC(gtk_glcanvas_size_callback
), (gpointer
)this );
428 if (gtk_check_version(2,2,0) != NULL
)
430 gtk_widget_pop_visual();
431 gtk_widget_pop_colormap();
434 // if our parent window is already visible, we had been realized before we
435 // connected to the "realize" signal and hence our m_glContext hasn't been
436 // initialized yet and we have to do it now
437 if (GTK_WIDGET_REALIZED(m_wxwindow
))
438 gtk_glwindow_realized_callback( m_wxwindow
, this );
440 if (GTK_WIDGET_MAPPED(m_wxwindow
))
441 gtk_glwindow_map_callback( m_wxwindow
, this );
446 wxGLCanvas::~wxGLCanvas()
448 GLXFBConfig
* fbc
= (GLXFBConfig
*) m_fbc
;
449 if (fbc
&& m_canFreeFBC
)
452 XVisualInfo
*vi
= (XVisualInfo
*) m_vi
;
453 if (vi
&& m_canFreeVi
)
459 void* wxGLCanvas::ChooseGLVisual(int *attribList
)
462 GetGLAttribListFromWX( attribList
, data
);
463 attribList
= (int*) data
;
465 Display
*dpy
= GDK_DISPLAY();
467 return glXChooseVisual( dpy
, DefaultScreen(dpy
), attribList
);
470 void* wxGLCanvas::ChooseGLFBC(int *attribList
)
473 GetGLAttribListFromWX( attribList
, data
);
474 attribList
= (int*) data
;
477 return glXChooseFBConfig( GDK_DISPLAY(), DefaultScreen(GDK_DISPLAY()),
478 attribList
, &returned
);
482 void wxGLCanvas::GetGLAttribListFromWX(int *wx_attribList
, int *gl_attribList
)
486 if (wxGLCanvas::GetGLXVersion() >= 13)
487 // leave GLX >= 1.3 choose the default attributes
488 gl_attribList
[0] = 0;
492 // default settings if attriblist = 0
493 gl_attribList
[i
++] = GLX_RGBA
;
494 gl_attribList
[i
++] = GLX_DOUBLEBUFFER
;
495 gl_attribList
[i
++] = GLX_DEPTH_SIZE
; gl_attribList
[i
++] = 1;
496 gl_attribList
[i
++] = GLX_RED_SIZE
; gl_attribList
[i
++] = 1;
497 gl_attribList
[i
++] = GLX_GREEN_SIZE
; gl_attribList
[i
++] = 1;
498 gl_attribList
[i
++] = GLX_BLUE_SIZE
; gl_attribList
[i
++] = 1;
499 gl_attribList
[i
++] = GLX_ALPHA_SIZE
; gl_attribList
[i
++] = 0;
500 gl_attribList
[i
++] = None
;
506 while( (wx_attribList
[arg
]!=0) && (p
<510) )
508 switch( wx_attribList
[arg
++] )
511 if (wxGLCanvas::GetGLXVersion() <= 12)
512 // for GLX >= 1.3, GLX_RGBA is useless (setting this flags will crash on most opengl implm)
513 gl_attribList
[p
++] = GLX_RGBA
;
515 case WX_GL_BUFFER_SIZE
:
516 gl_attribList
[p
++] = GLX_BUFFER_SIZE
;
517 gl_attribList
[p
++] = wx_attribList
[arg
++];
520 gl_attribList
[p
++] = GLX_LEVEL
;
521 gl_attribList
[p
++] = wx_attribList
[arg
++];
523 case WX_GL_DOUBLEBUFFER
:
524 if (wxGLCanvas::GetGLXVersion() <= 12)
525 gl_attribList
[p
++] = GLX_DOUBLEBUFFER
;
527 // for GLX >= 1.3, GLX_DOUBLEBUFFER format is different (1 <=> True)
528 // it seems this flag is useless for some hardware opengl implementation.
529 // but for Mesa 6.2.1, this flag is used so don't ignore it.
530 gl_attribList
[p
++] = GLX_DOUBLEBUFFER
;
531 gl_attribList
[p
++] = 1;
534 gl_attribList
[p
++] = GLX_STEREO
;
536 case WX_GL_AUX_BUFFERS
:
537 gl_attribList
[p
++] = GLX_AUX_BUFFERS
;
538 gl_attribList
[p
++] = wx_attribList
[arg
++];
541 gl_attribList
[p
++] = GLX_RED_SIZE
;
542 gl_attribList
[p
++] = wx_attribList
[arg
++];
544 case WX_GL_MIN_GREEN
:
545 gl_attribList
[p
++] = GLX_GREEN_SIZE
;
546 gl_attribList
[p
++] = wx_attribList
[arg
++];
549 gl_attribList
[p
++] = GLX_BLUE_SIZE
;
550 gl_attribList
[p
++] = wx_attribList
[arg
++];
552 case WX_GL_MIN_ALPHA
:
553 gl_attribList
[p
++] = GLX_ALPHA_SIZE
;
554 gl_attribList
[p
++] = wx_attribList
[arg
++];
556 case WX_GL_DEPTH_SIZE
:
557 gl_attribList
[p
++] = GLX_DEPTH_SIZE
;
558 gl_attribList
[p
++] = wx_attribList
[arg
++];
560 case WX_GL_STENCIL_SIZE
:
561 gl_attribList
[p
++] = GLX_STENCIL_SIZE
;
562 gl_attribList
[p
++] = wx_attribList
[arg
++];
564 case WX_GL_MIN_ACCUM_RED
:
565 gl_attribList
[p
++] = GLX_ACCUM_RED_SIZE
;
566 gl_attribList
[p
++] = wx_attribList
[arg
++];
568 case WX_GL_MIN_ACCUM_GREEN
:
569 gl_attribList
[p
++] = GLX_ACCUM_GREEN_SIZE
;
570 gl_attribList
[p
++] = wx_attribList
[arg
++];
572 case WX_GL_MIN_ACCUM_BLUE
:
573 gl_attribList
[p
++] = GLX_ACCUM_BLUE_SIZE
;
574 gl_attribList
[p
++] = wx_attribList
[arg
++];
576 case WX_GL_MIN_ACCUM_ALPHA
:
577 gl_attribList
[p
++] = GLX_ACCUM_ALPHA_SIZE
;
578 gl_attribList
[p
++] = wx_attribList
[arg
++];
585 gl_attribList
[p
] = 0;
589 void wxGLCanvas::QueryGLXVersion()
591 if (m_glxVersion
== 0)
593 // check the GLX version
594 int glxMajorVer
, glxMinorVer
;
595 bool ok
= glXQueryVersion(GDK_DISPLAY(), &glxMajorVer
, &glxMinorVer
);
596 wxASSERT_MSG( ok
, _T("GLX version not found") );
598 m_glxVersion
= 10; // 1.0 by default
600 m_glxVersion
= glxMajorVer
*10 + glxMinorVer
;
604 int wxGLCanvas::GetGLXVersion()
606 wxASSERT_MSG( m_glxVersion
>0, _T("GLX version has not been initialized with wxGLCanvas::QueryGLXVersion()") );
611 void wxGLCanvas::SwapBuffers()
614 m_glContext
->SwapBuffers();
617 void wxGLCanvas::OnSize(wxSizeEvent
& WXUNUSED(event
))
621 void wxGLCanvas::SetCurrent()
624 m_glContext
->SetCurrent();
627 void wxGLCanvas::SetColour( const wxChar
*colour
)
630 m_glContext
->SetColour( colour
);
633 void wxGLCanvas::OnInternalIdle()
635 if (m_glContext
&& m_exposed
)
637 wxPaintEvent
event( GetId() );
638 event
.SetEventObject( this );
639 GetEventHandler()->ProcessEvent( event
);
642 GetUpdateRegion().Clear();
645 wxWindow::OnInternalIdle();
650 //---------------------------------------------------------------------------
652 //---------------------------------------------------------------------------
654 IMPLEMENT_CLASS(wxGLApp
, wxApp
)
661 XFree(m_glVisualInfo
);
664 bool wxGLApp::InitGLVisual(int *attribList
)
666 wxGLCanvas::QueryGLXVersion();
668 if (wxGLCanvas::GetGLXVersion() >= 13)
673 m_glFBCInfo
= wxGLCanvas::ChooseGLFBC(attribList
);
678 XFree(m_glVisualInfo
);
679 m_glVisualInfo
= glXGetVisualFromFBConfig(GDK_DISPLAY(), ((GLXFBConfig
*)m_glFBCInfo
)[0]);
681 return (m_glFBCInfo
!= NULL
) && (m_glVisualInfo
!= NULL
);
687 XFree(m_glVisualInfo
);
688 m_glVisualInfo
= wxGLCanvas::ChooseGLVisual(attribList
);
689 return m_glVisualInfo
!= NULL
;