1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/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"
17 #include "wx/glcanvas.h"
22 #include "wx/colour.h"
23 #include "wx/module.h"
33 #include "wx/gtk/win_gtk.h"
34 #include "wx/gtk/private.h"
36 // DLL options compatibility check:
38 WX_CHECK_BUILD_OPTIONS("wxGL")
41 //---------------------------------------------------------------------------
43 //---------------------------------------------------------------------------
44 int wxGLCanvas::m_glxVersion
= 0;
46 //---------------------------------------------------------------------------
48 //---------------------------------------------------------------------------
50 XVisualInfo
*g_vi
= (XVisualInfo
*) NULL
;
52 //---------------------------------------------------------------------------
54 //---------------------------------------------------------------------------
56 IMPLEMENT_CLASS(wxGLContext
,wxObject
)
58 wxGLContext::wxGLContext( bool WXUNUSED(isRGB
), wxWindow
*win
, const wxPalette
& WXUNUSED(palette
) )
61 m_widget
= win
->m_wxwindow
;
63 wxGLCanvas
*gc
= (wxGLCanvas
*) win
;
65 if (wxGLCanvas::GetGLXVersion() >= 13)
68 GLXFBConfig
*fbc
= gc
->m_fbc
;
69 wxCHECK_RET( fbc
, _T("invalid GLXFBConfig for OpenGl") );
70 m_glContext
= glXCreateNewContext( GDK_DISPLAY(), fbc
[0], GLX_RGBA_TYPE
, None
, GL_TRUE
);
75 XVisualInfo
*vi
= (XVisualInfo
*) gc
->m_vi
;
76 wxCHECK_RET( vi
, _T("invalid visual for OpenGl") );
77 m_glContext
= glXCreateContext( GDK_DISPLAY(), vi
, None
, GL_TRUE
);
80 wxCHECK_RET( m_glContext
, _T("Couldn't create OpenGl context") );
83 wxGLContext::wxGLContext(
84 bool WXUNUSED(isRGB
), wxWindow
*win
,
85 const wxPalette
& WXUNUSED(palette
),
86 const wxGLContext
*other
/* for sharing display lists */
90 m_widget
= win
->m_wxwindow
;
92 wxGLCanvas
*gc
= (wxGLCanvas
*) win
;
94 if (wxGLCanvas::GetGLXVersion() >= 13)
97 GLXFBConfig
*fbc
= gc
->m_fbc
;
98 wxCHECK_RET( fbc
, _T("invalid GLXFBConfig for OpenGl") );
99 m_glContext
= glXCreateNewContext( GDK_DISPLAY(), fbc
[0], GLX_RGBA_TYPE
,
100 other
? other
->m_glContext
: None
,
106 XVisualInfo
*vi
= (XVisualInfo
*) gc
->m_vi
;
107 wxCHECK_RET( vi
, _T("invalid visual for OpenGl") );
108 m_glContext
= glXCreateContext( GDK_DISPLAY(), vi
,
109 other
? other
->m_glContext
: None
,
115 wxFAIL_MSG( _T("Couldn't create OpenGl context") );
119 wxGLContext::~wxGLContext()
121 if (!m_glContext
) return;
123 if (m_glContext
== glXGetCurrentContext())
125 if (wxGLCanvas::GetGLXVersion() >= 13)
127 glXMakeContextCurrent( GDK_DISPLAY(), None
, None
, NULL
);
130 glXMakeCurrent( GDK_DISPLAY(), None
, NULL
);
133 glXDestroyContext( GDK_DISPLAY(), m_glContext
);
136 void wxGLContext::SwapBuffers()
140 GdkWindow
*window
= GTK_PIZZA(m_widget
)->bin_window
;
141 glXSwapBuffers( GDK_DISPLAY(), GDK_WINDOW_XWINDOW( window
) );
145 void wxGLContext::SetCurrent()
149 GdkWindow
*window
= GTK_PIZZA(m_widget
)->bin_window
;
151 if (wxGLCanvas::GetGLXVersion() >= 13)
153 glXMakeContextCurrent( GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window
),
154 GDK_WINDOW_XWINDOW(window
), m_glContext
);
157 glXMakeCurrent( GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window
), m_glContext
);
161 void wxGLContext::SetColour(const wxChar
*colour
)
163 wxColour col
= wxTheColourDatabase
->Find(colour
);
166 float r
= (float)(col
.Red()/256.0);
167 float g
= (float)(col
.Green()/256.0);
168 float b
= (float)(col
.Blue()/256.0);
173 void wxGLContext::SetupPixelFormat()
177 void wxGLContext::SetupPalette( const wxPalette
& WXUNUSED(palette
) )
181 wxPalette
wxGLContext::CreateDefaultPalette()
183 return wxNullPalette
;
186 //-----------------------------------------------------------------------------
187 // "realize" from m_wxwindow
188 //-----------------------------------------------------------------------------
192 gtk_glwindow_realized_callback( GtkWidget
*WXUNUSED(widget
), wxGLCanvas
*win
)
194 if ( !win
->m_glContext
)
196 wxGLContext
*share
= win
->m_sharedContext
;
197 if ( !share
&& win
->m_sharedContextOf
)
198 share
= win
->m_sharedContextOf
->GetContext();
200 win
->m_glContext
= new wxGLContext( TRUE
, win
, wxNullPalette
, share
);
207 //-----------------------------------------------------------------------------
208 // "map" from m_wxwindow
209 //-----------------------------------------------------------------------------
213 gtk_glwindow_map_callback( GtkWidget
* WXUNUSED(widget
), wxGLCanvas
*win
)
215 if (win
->m_glContext
/* && win->m_exposed*/)
217 wxPaintEvent
event( win
->GetId() );
218 event
.SetEventObject( win
);
219 win
->GetEventHandler()->ProcessEvent( event
);
221 win
->m_exposed
= false;
222 win
->GetUpdateRegion().Clear();
229 //-----------------------------------------------------------------------------
230 // "expose_event" of m_wxwindow
231 //-----------------------------------------------------------------------------
235 gtk_glwindow_expose_callback( GtkWidget
*WXUNUSED(widget
), GdkEventExpose
*gdk_event
, wxGLCanvas
*win
)
237 // don't need to install idle handler, its done from "event" signal
239 win
->m_exposed
= true;
241 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
243 gdk_event
->area
.width
,
244 gdk_event
->area
.height
);
248 //-----------------------------------------------------------------------------
249 // "size_allocate" of m_wxwindow
250 //-----------------------------------------------------------------------------
254 gtk_glcanvas_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxGLCanvas
*win
)
257 wxapp_install_idle_handler();
262 wxSizeEvent
event( wxSize(win
->m_width
,win
->m_height
), win
->GetId() );
263 event
.SetEventObject( win
);
264 win
->GetEventHandler()->ProcessEvent( event
);
268 //---------------------------------------------------------------------------
270 //---------------------------------------------------------------------------
272 IMPLEMENT_CLASS(wxGLCanvas
, wxWindow
)
274 BEGIN_EVENT_TABLE(wxGLCanvas
, wxWindow
)
275 EVT_SIZE(wxGLCanvas::OnSize
)
278 wxGLCanvas::wxGLCanvas( wxWindow
*parent
, wxWindowID id
,
279 const wxPoint
& pos
, const wxSize
& size
,
280 long style
, const wxString
& name
,
282 const wxPalette
& palette
)
284 Create( parent
, NULL
, NULL
, id
, pos
, size
, style
, name
, attribList
, palette
);
287 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
288 const wxGLContext
*shared
,
290 const wxPoint
& pos
, const wxSize
& size
,
291 long style
, const wxString
& name
,
293 const wxPalette
& palette
)
295 Create( parent
, shared
, NULL
, id
, pos
, size
, style
, name
, attribList
, palette
);
298 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
299 const wxGLCanvas
*shared
,
301 const wxPoint
& pos
, const wxSize
& size
,
302 long style
, const wxString
& name
,
304 const wxPalette
& palette
)
306 Create( parent
, NULL
, shared
, id
, pos
, size
, style
, name
, attribList
, palette
);
309 bool wxGLCanvas::Create( wxWindow
*parent
,
310 const wxGLContext
*shared
,
311 const wxGLCanvas
*shared_context_of
,
313 const wxPoint
& pos
, const wxSize
& size
,
314 long style
, const wxString
& name
,
316 const wxPalette
& palette
)
318 m_sharedContext
= (wxGLContext
*)shared
; // const_cast
319 m_sharedContextOf
= (wxGLCanvas
*)shared_context_of
; // const_cast
320 m_glContext
= (wxGLContext
*) NULL
;
324 m_nativeSizeEvent
= true;
328 // to be sure the glx version is known
329 wxGLCanvas::QueryGLXVersion();
331 if (wxGLCanvas::GetGLXVersion() >= 13)
333 // GLX >= 1.3 uses a GLXFBConfig
334 GLXFBConfig
* fbc
= NULL
;
335 if (wxTheApp
->m_glFBCInfo
!= NULL
)
337 fbc
= (GLXFBConfig
*) wxTheApp
->m_glFBCInfo
;
338 m_canFreeFBC
= false; // owned by wxTheApp - don't free upon destruction
342 fbc
= (GLXFBConfig
*) wxGLCanvas::ChooseGLFBC(attribList
);
345 m_fbc
= fbc
; // save for later use
346 wxCHECK_MSG( m_fbc
, false, _T("required FBConfig couldn't be found") );
349 XVisualInfo
*vi
= NULL
;
350 if (wxTheApp
->m_glVisualInfo
!= NULL
)
352 vi
= (XVisualInfo
*)wxTheApp
->m_glVisualInfo
;
353 m_canFreeVi
= false; // owned by wxTheApp - don't free upon destruction
357 if (wxGLCanvas::GetGLXVersion() >= 13)
359 vi
= glXGetVisualFromFBConfig(GDK_DISPLAY(), m_fbc
[0]);
362 vi
= (XVisualInfo
*) ChooseGLVisual(attribList
);
367 m_vi
= vi
; // save for later use
369 wxCHECK_MSG( m_vi
, false, _T("required visual couldn't be found") );
371 GdkColormap
*colormap
;
373 // MR: This needs a fix for lower gtk+ versions too. Might need to rethink logic (FIXME)
374 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2,2,0)
375 if (!gtk_check_version(2,2,0))
377 wxWindow::Create( parent
, id
, pos
, size
, style
, name
);
379 m_glWidget
= m_wxwindow
;
381 GdkScreen
*screen
= gtk_widget_get_screen( m_glWidget
);
382 colormap
= gdk_screen_get_default_colormap(screen
);
383 visual
= gdk_colormap_get_visual(colormap
);
385 if (GDK_VISUAL_XVISUAL(visual
)->visualid
!= vi
->visualid
)
387 visual
= gdk_x11_screen_lookup_visual( screen
, vi
->visualid
);
388 colormap
= gdk_colormap_new(visual
, FALSE
);
391 gtk_widget_set_colormap( m_glWidget
, colormap
);
396 visual
= gdkx_visual_get( vi
->visualid
);
397 colormap
= gdk_colormap_new( visual
, TRUE
);
399 gtk_widget_push_colormap( colormap
);
401 wxWindow::Create( parent
, id
, pos
, size
, style
, name
);
402 m_glWidget
= m_wxwindow
;
405 gtk_widget_set_double_buffered( m_glWidget
, FALSE
);
407 g_signal_connect (m_wxwindow
, "realize",
408 G_CALLBACK (gtk_glwindow_realized_callback
),
410 g_signal_connect (m_wxwindow
, "map",
411 G_CALLBACK (gtk_glwindow_map_callback
),
413 g_signal_connect (m_wxwindow
, "expose_event",
414 G_CALLBACK (gtk_glwindow_expose_callback
),
416 g_signal_connect (m_widget
, "size_allocate",
417 G_CALLBACK (gtk_glcanvas_size_callback
),
420 if (gtk_check_version(2,2,0) != NULL
)
422 gtk_widget_pop_colormap();
425 // if our parent window is already visible, we had been realized before we
426 // connected to the "realize" signal and hence our m_glContext hasn't been
427 // initialized yet and we have to do it now
428 if (GTK_WIDGET_REALIZED(m_wxwindow
))
429 gtk_glwindow_realized_callback( m_wxwindow
, this );
431 if (GTK_WIDGET_MAPPED(m_wxwindow
))
432 gtk_glwindow_map_callback( m_wxwindow
, this );
437 wxGLCanvas::~wxGLCanvas()
439 GLXFBConfig
* fbc
= (GLXFBConfig
*) m_fbc
;
440 if (fbc
&& m_canFreeFBC
)
443 XVisualInfo
*vi
= (XVisualInfo
*) m_vi
;
444 if (vi
&& m_canFreeVi
)
450 void* wxGLCanvas::ChooseGLVisual(int *attribList
)
453 GetGLAttribListFromWX( attribList
, data
);
454 attribList
= (int*) data
;
456 Display
*dpy
= GDK_DISPLAY();
458 return glXChooseVisual( dpy
, DefaultScreen(dpy
), attribList
);
461 void* wxGLCanvas::ChooseGLFBC(int *attribList
)
464 GetGLAttribListFromWX( attribList
, data
);
465 attribList
= (int*) data
;
468 return glXChooseFBConfig( GDK_DISPLAY(), DefaultScreen(GDK_DISPLAY()),
469 attribList
, &returned
);
473 void wxGLCanvas::GetGLAttribListFromWX(int *wx_attribList
, int *gl_attribList
)
477 if (wxGLCanvas::GetGLXVersion() >= 13)
478 // leave GLX >= 1.3 choose the default attributes
479 gl_attribList
[0] = 0;
483 // default settings if attriblist = 0
484 gl_attribList
[i
++] = GLX_RGBA
;
485 gl_attribList
[i
++] = GLX_DOUBLEBUFFER
;
486 gl_attribList
[i
++] = GLX_DEPTH_SIZE
; gl_attribList
[i
++] = 1;
487 gl_attribList
[i
++] = GLX_RED_SIZE
; gl_attribList
[i
++] = 1;
488 gl_attribList
[i
++] = GLX_GREEN_SIZE
; gl_attribList
[i
++] = 1;
489 gl_attribList
[i
++] = GLX_BLUE_SIZE
; gl_attribList
[i
++] = 1;
490 gl_attribList
[i
++] = GLX_ALPHA_SIZE
; gl_attribList
[i
++] = 0;
491 gl_attribList
[i
++] = None
;
497 while( (wx_attribList
[arg
]!=0) && (p
<510) )
499 switch( wx_attribList
[arg
++] )
502 if (wxGLCanvas::GetGLXVersion() <= 12)
503 // for GLX >= 1.3, GLX_RGBA is useless (setting this flags will crash on most opengl implm)
504 gl_attribList
[p
++] = GLX_RGBA
;
506 case WX_GL_BUFFER_SIZE
:
507 gl_attribList
[p
++] = GLX_BUFFER_SIZE
;
508 gl_attribList
[p
++] = wx_attribList
[arg
++];
511 gl_attribList
[p
++] = GLX_LEVEL
;
512 gl_attribList
[p
++] = wx_attribList
[arg
++];
514 case WX_GL_DOUBLEBUFFER
:
515 if (wxGLCanvas::GetGLXVersion() <= 12)
516 gl_attribList
[p
++] = GLX_DOUBLEBUFFER
;
518 // for GLX >= 1.3, GLX_DOUBLEBUFFER format is different (1 <=> True)
519 // it seems this flag is useless for some hardware opengl implementation.
520 // but for Mesa 6.2.1, this flag is used so don't ignore it.
521 gl_attribList
[p
++] = GLX_DOUBLEBUFFER
;
522 gl_attribList
[p
++] = 1;
525 gl_attribList
[p
++] = GLX_STEREO
;
527 case WX_GL_AUX_BUFFERS
:
528 gl_attribList
[p
++] = GLX_AUX_BUFFERS
;
529 gl_attribList
[p
++] = wx_attribList
[arg
++];
532 gl_attribList
[p
++] = GLX_RED_SIZE
;
533 gl_attribList
[p
++] = wx_attribList
[arg
++];
535 case WX_GL_MIN_GREEN
:
536 gl_attribList
[p
++] = GLX_GREEN_SIZE
;
537 gl_attribList
[p
++] = wx_attribList
[arg
++];
540 gl_attribList
[p
++] = GLX_BLUE_SIZE
;
541 gl_attribList
[p
++] = wx_attribList
[arg
++];
543 case WX_GL_MIN_ALPHA
:
544 gl_attribList
[p
++] = GLX_ALPHA_SIZE
;
545 gl_attribList
[p
++] = wx_attribList
[arg
++];
547 case WX_GL_DEPTH_SIZE
:
548 gl_attribList
[p
++] = GLX_DEPTH_SIZE
;
549 gl_attribList
[p
++] = wx_attribList
[arg
++];
551 case WX_GL_STENCIL_SIZE
:
552 gl_attribList
[p
++] = GLX_STENCIL_SIZE
;
553 gl_attribList
[p
++] = wx_attribList
[arg
++];
555 case WX_GL_MIN_ACCUM_RED
:
556 gl_attribList
[p
++] = GLX_ACCUM_RED_SIZE
;
557 gl_attribList
[p
++] = wx_attribList
[arg
++];
559 case WX_GL_MIN_ACCUM_GREEN
:
560 gl_attribList
[p
++] = GLX_ACCUM_GREEN_SIZE
;
561 gl_attribList
[p
++] = wx_attribList
[arg
++];
563 case WX_GL_MIN_ACCUM_BLUE
:
564 gl_attribList
[p
++] = GLX_ACCUM_BLUE_SIZE
;
565 gl_attribList
[p
++] = wx_attribList
[arg
++];
567 case WX_GL_MIN_ACCUM_ALPHA
:
568 gl_attribList
[p
++] = GLX_ACCUM_ALPHA_SIZE
;
569 gl_attribList
[p
++] = wx_attribList
[arg
++];
576 gl_attribList
[p
] = 0;
580 void wxGLCanvas::QueryGLXVersion()
582 if (m_glxVersion
== 0)
584 // check the GLX version
585 int glxMajorVer
, glxMinorVer
;
586 bool ok
= glXQueryVersion(GDK_DISPLAY(), &glxMajorVer
, &glxMinorVer
);
587 wxASSERT_MSG( ok
, _T("GLX version not found") );
589 m_glxVersion
= 10; // 1.0 by default
591 m_glxVersion
= glxMajorVer
*10 + glxMinorVer
;
595 int wxGLCanvas::GetGLXVersion()
597 wxASSERT_MSG( m_glxVersion
>0, _T("GLX version has not been initialized with wxGLCanvas::QueryGLXVersion()") );
602 void wxGLCanvas::SwapBuffers()
605 m_glContext
->SwapBuffers();
608 void wxGLCanvas::OnSize(wxSizeEvent
& WXUNUSED(event
))
612 void wxGLCanvas::SetCurrent()
615 m_glContext
->SetCurrent();
618 void wxGLCanvas::SetColour( const wxChar
*colour
)
621 m_glContext
->SetColour( colour
);
624 void wxGLCanvas::OnInternalIdle()
626 if (m_glContext
&& m_exposed
)
628 wxPaintEvent
event( GetId() );
629 event
.SetEventObject( this );
630 GetEventHandler()->ProcessEvent( event
);
633 GetUpdateRegion().Clear();
636 wxWindow::OnInternalIdle();
641 //---------------------------------------------------------------------------
643 //---------------------------------------------------------------------------
645 IMPLEMENT_CLASS(wxGLApp
, wxApp
)
652 XFree(m_glVisualInfo
);
655 bool wxGLApp::InitGLVisual(int *attribList
)
657 wxGLCanvas::QueryGLXVersion();
659 if (wxGLCanvas::GetGLXVersion() >= 13)
664 m_glFBCInfo
= wxGLCanvas::ChooseGLFBC(attribList
);
669 XFree(m_glVisualInfo
);
670 m_glVisualInfo
= glXGetVisualFromFBConfig(GDK_DISPLAY(), ((GLXFBConfig
*)m_glFBCInfo
)[0]);
672 return (m_glFBCInfo
!= NULL
) && (m_glVisualInfo
!= NULL
);
678 XFree(m_glVisualInfo
);
679 m_glVisualInfo
= wxGLCanvas::ChooseGLVisual(attribList
);
680 return m_glVisualInfo
!= NULL
;