]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/glcanvas.cpp
correction to last commit: don't test unsetenv() return value, it's void under Darwin
[wxWidgets.git] / src / msw / glcanvas.cpp
index 4f84b3c3884f7e828c8dfb5103b3425fa01d5161..a95e48a54be6981ccbb149ff1fab0368433f4acb 100644 (file)
@@ -1,6 +1,6 @@
 /////////////////////////////////////////////////////////////////////////////
 // Name:        src/msw/glcanvas.cpp
-// Purpose:     wxGLCanvas, for using OpenGL with wxWindows under MS Windows
+// Purpose:     wxGLCanvas, for using OpenGL with wxWidgets under MS Windows
 // Author:      Julian Smart
 // Modified by:
 // Created:     04/01/98
@@ -9,33 +9,47 @@
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
-#ifdef __GNUG__
-#pragma implementation "glcanvas.h"
-#endif
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
 
 #include "wx/wxprec.h"
 
 #if defined(__BORLANDC__)
-#pragma hdrstop
+    #pragma hdrstop
 #endif
 
 #if wxUSE_GLCANVAS
 
 #ifndef WX_PRECOMP
-    #include "wx/frame.h"
-    #include "wx/settings.h"
     #include "wx/intl.h"
     #include "wx/log.h"
+    #include "wx/app.h"
+    #include "wx/module.h"
 #endif
 
 #include "wx/msw/private.h"
 
-// DLL options compatibility check:
-#include "wx/build.h"
-WX_CHECK_BUILD_OPTIONS("wxGL")
-
 #include "wx/glcanvas.h"
 
+// from src/msw/window.cpp
+LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
+                                   WPARAM wParam, LPARAM lParam);
+
+#ifdef GL_EXT_vertex_array
+    #define WXUNUSED_WITHOUT_GL_EXT_vertex_array(name) name
+#else
+    #define WXUNUSED_WITHOUT_GL_EXT_vertex_array(name) WXUNUSED(name)
+#endif
+
+// ----------------------------------------------------------------------------
+// libraries
+// ----------------------------------------------------------------------------
+
 /*
   The following two compiler directives are specific to the Microsoft Visual
   C++ family of compilers
@@ -45,7 +59,7 @@ WX_CHECK_BUILD_OPTIONS("wxGL")
   these two libraries to either the Makefile or project file.
 
   This is NOT a recommended technique, and certainly is unlikely to be used
-  anywhere else in wxWindows given it is so specific to not only wxMSW, but
+  anywhere else in wxWidgets given it is so specific to not only wxMSW, but
   also the VC compiler. However, in the case of opengl support, it's an
   applicable technique as opengl is optional in setup.h This code (wrapped by
   wxUSE_GLCANVAS), now allows opengl support to be added purely by modifying
@@ -58,186 +72,186 @@ WX_CHECK_BUILD_OPTIONS("wxGL")
 #  pragma comment( lib, "glu32" )
 #endif
 
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
 
 static const wxChar *wxGLCanvasClassName = wxT("wxGLCanvasClass");
 static const wxChar *wxGLCanvasClassNameNoRedraw = wxT("wxGLCanvasClassNR");
 
-LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
-                                   WPARAM wParam, LPARAM lParam);
+// ============================================================================
+// implementation
+// ============================================================================
 
-/*
- * GLContext implementation
- */
+// ----------------------------------------------------------------------------
+// wxGLModule is responsible for unregistering wxGLCanvasClass Windows class
+// ----------------------------------------------------------------------------
 
-wxGLContext::wxGLContext(bool isRGB, wxGLCanvas *win, const wxPalette& palette)
+class wxGLModule : public wxModule
 {
-  m_window = win;
+public:
+    bool OnInit() { return true; }
+    void OnExit() { UnregisterClasses(); }
 
-  m_hDC = win->GetHDC();
+    // register the GL classes if not done yet, return true if ok, false if
+    // registration failed
+    static bool RegisterClasses();
 
-  m_glContext = wglCreateContext((HDC) m_hDC);
-  wxCHECK_RET( m_glContext, wxT("Couldn't create OpenGl context") );
+    // unregister the classes, done automatically on program termination
+    static void UnregisterClasses();
 
-  wglMakeCurrent((HDC) m_hDC, m_glContext);
-}
+private:
+    // wxGLCanvas is only used from the main thread so this is MT-ok
+    static bool ms_registeredGLClasses;
+
+    DECLARE_DYNAMIC_CLASS(wxGLModule)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxGLModule, wxModule)
+
+bool wxGLModule::ms_registeredGLClasses = false;
 
-wxGLContext::wxGLContext(
-               bool isRGB, wxGLCanvas *win,
-               const wxPalette& palette,
-               const wxGLContext *other  /* for sharing display lists */
-             )
+/* static */
+bool wxGLModule::RegisterClasses()
 {
-  m_window = win;
+    if ( ms_registeredGLClasses )
+        return true;
 
-  m_hDC = win->GetHDC();
+    // We have to register a special window class because we need the CS_OWNDC
+    // style for GLCanvas: some OpenGL drivers are buggy and don't work with
+    // windows without this style
+    WNDCLASS wndclass;
 
-  m_glContext = wglCreateContext((HDC) m_hDC);
-  wxCHECK_RET( m_glContext, wxT("Couldn't create OpenGl context") );
+    // the fields which are common to all classes
+    wndclass.lpfnWndProc   = (WNDPROC)wxWndProc;
+    wndclass.cbClsExtra    = 0;
+    wndclass.cbWndExtra    = sizeof( DWORD ); // VZ: what is this DWORD used for?
+    wndclass.hInstance     = wxhInstance;
+    wndclass.hIcon         = (HICON) NULL;
+    wndclass.hCursor       = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
+    wndclass.lpszMenuName  = NULL;
 
-  if( other != 0 )
-    wglShareLists( other->m_glContext, m_glContext );
+    // Register the GLCanvas class name
+    wndclass.hbrBackground = (HBRUSH)NULL;
+    wndclass.lpszClassName = wxGLCanvasClassName;
+    wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
 
-  wglMakeCurrent((HDC) m_hDC, m_glContext);
-}
+    if ( !::RegisterClass(&wndclass) )
+    {
+        wxLogLastError(wxT("RegisterClass(wxGLCanvasClass)"));
+        return false;
+    }
 
-wxGLContext::~wxGLContext()
-{
-  if (m_glContext)
-  {
-    wglMakeCurrent(NULL, NULL);
-    wglDeleteContext(m_glContext);
-  }
+    // Register the GLCanvas class name for windows which don't do full repaint
+    // on resize
+    wndclass.lpszClassName = wxGLCanvasClassNameNoRedraw;
+    wndclass.style        &= ~(CS_HREDRAW | CS_VREDRAW);
+
+    if ( !::RegisterClass(&wndclass) )
+    {
+        wxLogLastError(wxT("RegisterClass(wxGLCanvasClassNameNoRedraw)"));
+
+        ::UnregisterClass(wxGLCanvasClassName, wxhInstance);
+
+        return false;
+    }
+
+    ms_registeredGLClasses = true;
+
+    return true;
 }
 
-void wxGLContext::SwapBuffers()
+/* static */
+void wxGLModule::UnregisterClasses()
 {
-  if (m_glContext)
-  {
-    wglMakeCurrent((HDC) m_hDC, m_glContext);
-    ::SwapBuffers((HDC) m_hDC);    //blits the backbuffer into DC
-  }
+    // we need to unregister the classes in case we're in a DLL which is
+    // unloaded and then loaded again because if we don't, the registration is
+    // going to fail in wxGLCanvas::Create() the next time we're loaded
+    if ( ms_registeredGLClasses )
+    {
+        ::UnregisterClass(wxGLCanvasClassName, wxhInstance);
+        ::UnregisterClass(wxGLCanvasClassNameNoRedraw, wxhInstance);
+
+        ms_registeredGLClasses = false;
+    }
 }
 
-void wxGLContext::SetCurrent()
+// ----------------------------------------------------------------------------
+// wxGLContext
+// ----------------------------------------------------------------------------
+
+IMPLEMENT_CLASS(wxGLContext, wxObject)
+
+wxGLContext::wxGLContext(wxGLCanvas *win, const wxGLContext* other)
 {
-  if (m_glContext)
-  {
-    wglMakeCurrent((HDC) m_hDC, m_glContext);
-  }
+    m_glContext = wglCreateContext(win->GetHDC());
+    wxCHECK_RET( m_glContext, wxT("Couldn't create OpenGL context") );
 
-  /*
-  setupPixelFormat(hDC);
-  setupPalette(hDC);
-  */
+    if ( other )
+    {
+        if ( !wglShareLists(other->m_glContext, m_glContext) )
+            wxLogLastError(_T("wglShareLists"));
+    }
 }
 
-void wxGLContext::SetColour(const wxChar *colour)
+wxGLContext::~wxGLContext()
 {
-  float r = 0.0;
-  float g = 0.0;
-  float b = 0.0;
-  wxColour *col = wxTheColourDatabase->FindColour(colour);
-  if (col)
-  {
-    r = (float)(col->Red()/256.0);
-    g = (float)(col->Green()/256.0);
-    b = (float)(col->Blue()/256.0);
-    glColor3f( r, g, b);
-  }
+    // note that it's ok to delete the context even if it's the current one
+    wglDeleteContext(m_glContext);
 }
 
+void wxGLContext::SetCurrent(const wxGLCanvas& win) const
+{
+    if ( !wglMakeCurrent(win.GetHDC(), m_glContext) )
+    {
+        wxLogLastError(_T("wglMakeCurrent"));
+    }
+}
 
-/*
- * wxGLCanvas implementation
- */
+// ============================================================================
+// wxGLCanvas
+// ============================================================================
 
 IMPLEMENT_CLASS(wxGLCanvas, wxWindow)
 
 BEGIN_EVENT_TABLE(wxGLCanvas, wxWindow)
-    EVT_SIZE(wxGLCanvas::OnSize)
     EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged)
     EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette)
 END_EVENT_TABLE()
 
-wxGLCanvas::wxGLCanvas(wxWindow *parent, wxWindowID id,
-    const wxPoint& pos, const wxSize& size, long style, const wxString& name,
-    int *attribList, const wxPalette& palette) : wxWindow()
-{
-  m_glContext = (wxGLContext*) NULL;
-
-  bool ret = Create(parent, id, pos, size, style, name);
-
-  if ( ret )
-  {
-    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
-    SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
-  }
-
-  m_hDC = (WXHDC) ::GetDC((HWND) GetHWND());
-
-  SetupPixelFormat(attribList);
-  SetupPalette(palette);
-
-  m_glContext = new wxGLContext(TRUE, this, palette);
-}
+// ----------------------------------------------------------------------------
+// wxGLCanvas construction
+// ----------------------------------------------------------------------------
 
-wxGLCanvas::wxGLCanvas( wxWindow *parent,
-              const wxGLContext *shared, wxWindowID id,
-              const wxPoint& pos, const wxSize& size, long style, const wxString& name,
-              int *attribList, const wxPalette& palette )
-  : wxWindow()
+void wxGLCanvas::Init()
 {
-  m_glContext = (wxGLContext*) NULL;
-
-  bool ret = Create(parent, id, pos, size, style, name);
-
-  if ( ret )
-  {
-    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
-    SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
-  }
-
-  m_hDC = (WXHDC) ::GetDC((HWND) GetHWND());
-
-  SetupPixelFormat(attribList);
-  SetupPalette(palette);
-
-  m_glContext = new wxGLContext(TRUE, this, palette, shared );
+#if WXWIN_COMPATIBILITY_2_8
+    m_glContext = NULL;
+#endif
+    m_hDC = NULL;
 }
 
-// Not very useful for wxMSW, but this is to be wxGTK compliant
-
-wxGLCanvas::wxGLCanvas( wxWindow *parent, const wxGLCanvas *shared, wxWindowID id,
-                        const wxPoint& pos, const wxSize& size, long style, const wxString& name,
-                        int *attribList, const wxPalette& palette ):
-  wxWindow()
+wxGLCanvas::wxGLCanvas(wxWindow *parent,
+                       wxWindowID id,
+                       const int *attribList,
+                       const wxPoint& pos,
+                       const wxSize& size,
+                       long style,
+                       const wxString& name,
+                       const wxPalette& palette)
 {
-  m_glContext = (wxGLContext*) NULL;
-
-  bool ret = Create(parent, id, pos, size, style, name);
-
-  if ( ret )
-  {
-    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
-    SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
-  }
-
-  m_hDC = (WXHDC) ::GetDC((HWND) GetHWND());
+    Init();
 
-  SetupPixelFormat(attribList);
-  SetupPalette(palette);
-
-  wxGLContext *sharedContext=0;
-  if (shared) sharedContext=shared->GetContext();
-  m_glContext = new wxGLContext(TRUE, this, palette, sharedContext );
+    (void)Create(parent, id, pos, size, style, name, attribList, palette);
 }
 
 wxGLCanvas::~wxGLCanvas()
 {
-  if (m_glContext)
+#if WXWIN_COMPATIBILITY_2_8
     delete m_glContext;
+#endif
 
-  ::ReleaseDC((HWND) GetHWND(), (HDC) m_hDC);
+    ::ReleaseDC(GetHwnd(), m_hDC);
 }
 
 // Replaces wxWindow::Create functionality, since we need to use a different
@@ -247,249 +261,271 @@ bool wxGLCanvas::Create(wxWindow *parent,
                         const wxPoint& pos,
                         const wxSize& size,
                         long style,
-                        const wxString& name)
+                        const wxString& name,
+                        const int *attribList,
+                        const wxPalette& palette)
 {
-  static bool s_registeredGLCanvasClass = FALSE;
+    wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") );
 
-  // We have to register a special window class because we need
-  // the CS_OWNDC style for GLCanvas.
-
-  /*
-  From Angel Popov <jumpo@bitex.com>
-
-  Here are two snips from a dicussion in the OpenGL Gamedev list that explains
-  how this problem can be fixed:
-
-  "There are 5 common DCs available in Win95. These are aquired when you call
-  GetDC or GetDCEx from a window that does _not_ have the OWNDC flag.
-  OWNDC flagged windows do not get their DC from the common DC pool, the issue
-  is they require 800 bytes each from the limited 64Kb local heap for GDI."
-
-  "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps
-  do), Win95 will actually "steal" it from you.  MakeCurrent fails,
-  apparently, because Windows re-assigns the HDC to a different window.  The
-  only way to prevent this, the only reliable means, is to set CS_OWNDC."
-  */
-
-  if (!s_registeredGLCanvasClass)
-  {
-    WNDCLASS wndclass;
-
-    // the fields which are common to all classes
-    wndclass.lpfnWndProc   = (WNDPROC)wxWndProc;
-    wndclass.cbClsExtra    = 0;
-    wndclass.cbWndExtra    = sizeof( DWORD ); // VZ: what is this DWORD used for?
-    wndclass.hInstance     = wxhInstance;
-    wndclass.hIcon         = (HICON) NULL;
-    wndclass.hCursor       = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
-    wndclass.lpszMenuName  = NULL;
-
-    // Register the GLCanvas class name
-    wndclass.hbrBackground = (HBRUSH)NULL;
-    wndclass.lpszClassName = wxGLCanvasClassName;
-    wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
-
-    if ( !::RegisterClass(&wndclass) )
+    if ( !wxGLModule::RegisterClasses() )
     {
-      wxLogLastError(wxT("RegisterClass(wxGLCanvasClass)"));
-      return FALSE;
-    }
+        wxLogError(_("Failed to register OpenGL window class."));
 
-    // Register the GLCanvas class name for windows which don't do full repaint
-    // on resize
-    wndclass.lpszClassName = wxGLCanvasClassNameNoRedraw;
-    wndclass.style        &= ~(CS_HREDRAW | CS_VREDRAW);
-
-    if ( !::RegisterClass(&wndclass) )
-    {
-        wxLogLastError(wxT("RegisterClass(wxGLCanvasClassNameNoRedraw)"));
+        return false;
+    }
 
-        ::UnregisterClass(wxGLCanvasClassName, wxhInstance);
+    if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
+        return false;
 
-        return FALSE;
-    }
+    parent->AddChild(this);
 
-    s_registeredGLCanvasClass = TRUE;
-  }
+    /*
+       A general rule with OpenGL and Win32 is that any window that will have a
+       HGLRC built for it must have two flags:  WS_CLIPCHILDREN & WS_CLIPSIBLINGS.
+       You can find references about this within the knowledge base and most OpenGL
+       books that contain the wgl function descriptions.
+     */
+    WXDWORD exStyle = 0;
+    DWORD msflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+    msflags |= MSWGetStyle(style, &exStyle);
 
-  wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") );
+    if ( !MSWCreate(wxGLCanvasClassName, NULL, pos, size, msflags, exStyle) )
+        return false;
 
-  if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
-    return FALSE;
+    m_hDC = ::GetDC(GetHwnd());
+    if ( !m_hDC )
+        return false;
 
-  parent->AddChild(this);
+    if ( !DoSetup(attribList) )
+        return false;
 
-  DWORD msflags = 0;
+#if wxUSE_PALETTE
+    if ( !SetupPalette(palette) )
+        return false;
+#else // !wxUSE_PALETTE
+    wxUnusedVar(palette);
+#endif // wxUSE_PALETTE/!wxUSE_PALETTE
 
-  /*
-  A general rule with OpenGL and Win32 is that any window that will have a
-  HGLRC built for it must have two flags:  WS_CLIPCHILDREN & WS_CLIPSIBLINGS.
-  You can find references about this within the knowledge base and most OpenGL
-  books that contain the wgl function descriptions.
-  */
+    return true;
+}
 
-  WXDWORD exStyle = 0;
-  msflags |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
-  msflags |= MSWGetStyle(style, & exStyle) ;
+// ----------------------------------------------------------------------------
+// operations
+// ----------------------------------------------------------------------------
 
-  return MSWCreate(wxGLCanvasClassName, NULL, pos, size, msflags, exStyle);
+void wxGLCanvas::SwapBuffers()
+{
+    if ( !::SwapBuffers(m_hDC) )
+        wxLogLastError(_T("SwapBuffers"));
 }
 
-static void AdjustPFDForAttributes(PIXELFORMATDESCRIPTOR& pfd, int *attribList)
+// ----------------------------------------------------------------------------
+// pixel format stuff
+// ----------------------------------------------------------------------------
+
+static void
+AdjustPFDForAttributes(PIXELFORMATDESCRIPTOR& pfd, const int *attribList)
 {
-  if (attribList) {
+    if ( !attribList )
+        return;
+
     pfd.dwFlags &= ~PFD_DOUBLEBUFFER;
     pfd.iPixelType = PFD_TYPE_COLORINDEX;
     pfd.cColorBits = 0;
     int arg=0;
 
-    while( (attribList[arg]!=0) )
+    while ( attribList[arg] )
     {
-      switch( attribList[arg++] )
-      {
-        case WX_GL_RGBA:
-          pfd.iPixelType = PFD_TYPE_RGBA;
-          break;
-        case WX_GL_BUFFER_SIZE:
-          pfd.cColorBits = attribList[arg++];
-          break;
-        case WX_GL_LEVEL:
-          // this member looks like it may be obsolete
-          if (attribList[arg] > 0) {
-            pfd.iLayerType = (BYTE)PFD_OVERLAY_PLANE;
-          } else if (attribList[arg] < 0) {
-            pfd.iLayerType = (BYTE)PFD_UNDERLAY_PLANE;
-          } else {
-            pfd.iLayerType = (BYTE)PFD_MAIN_PLANE;
-          }
-          arg++;
-          break;
-        case WX_GL_DOUBLEBUFFER:
-          pfd.dwFlags |= PFD_DOUBLEBUFFER;
-          break;
-        case WX_GL_STEREO:
-          pfd.dwFlags |= PFD_STEREO;
-          break;
-        case WX_GL_AUX_BUFFERS:
-          pfd.cAuxBuffers = attribList[arg++];
-          break;
-        case WX_GL_MIN_RED:
-          pfd.cColorBits += (pfd.cRedBits = attribList[arg++]);
-          break;
-        case WX_GL_MIN_GREEN:
-          pfd.cColorBits += (pfd.cGreenBits = attribList[arg++]);
-          break;
-        case WX_GL_MIN_BLUE:
-          pfd.cColorBits += (pfd.cBlueBits = attribList[arg++]);
-          break;
-        case WX_GL_MIN_ALPHA:
-          // doesn't count in cColorBits
-          pfd.cAlphaBits = attribList[arg++];
-          break;
-        case WX_GL_DEPTH_SIZE:
-          pfd.cDepthBits = attribList[arg++];
-          break;
-        case WX_GL_STENCIL_SIZE:
-          pfd.cStencilBits = attribList[arg++];
-          break;
-        case WX_GL_MIN_ACCUM_RED:
-          pfd.cAccumBits += (pfd.cAccumRedBits = attribList[arg++]);
-          break;
-        case WX_GL_MIN_ACCUM_GREEN:
-          pfd.cAccumBits += (pfd.cAccumGreenBits = attribList[arg++]);
-          break;
-        case WX_GL_MIN_ACCUM_BLUE:
-          pfd.cAccumBits += (pfd.cAccumBlueBits = attribList[arg++]);
-          break;
-        case WX_GL_MIN_ACCUM_ALPHA:
-          pfd.cAccumBits += (pfd.cAccumAlphaBits = attribList[arg++]);
-          break;
-        default:
-          break;
-      }
+        switch ( attribList[arg++] )
+        {
+            case WX_GL_RGBA:
+                pfd.iPixelType = PFD_TYPE_RGBA;
+                break;
+            case WX_GL_BUFFER_SIZE:
+                pfd.cColorBits = attribList[arg++];
+                break;
+            case WX_GL_LEVEL:
+                // this member looks like it may be obsolete
+                if ( attribList[arg] > 0 )
+                    pfd.iLayerType = PFD_OVERLAY_PLANE;
+                else if ( attribList[arg] < 0 )
+                    pfd.iLayerType = (BYTE)PFD_UNDERLAY_PLANE;
+                else
+                    pfd.iLayerType = PFD_MAIN_PLANE;
+                arg++;
+                break;
+            case WX_GL_DOUBLEBUFFER:
+                pfd.dwFlags |= PFD_DOUBLEBUFFER;
+                break;
+            case WX_GL_STEREO:
+                pfd.dwFlags |= PFD_STEREO;
+                break;
+            case WX_GL_AUX_BUFFERS:
+                pfd.cAuxBuffers = attribList[arg++];
+                break;
+            case WX_GL_MIN_RED:
+                pfd.cColorBits = (pfd.cColorBits +
+                        (pfd.cRedBits = attribList[arg++]));
+                break;
+            case WX_GL_MIN_GREEN:
+                pfd.cColorBits = (pfd.cColorBits +
+                        (pfd.cGreenBits = attribList[arg++]));
+                break;
+            case WX_GL_MIN_BLUE:
+                pfd.cColorBits = (pfd.cColorBits +
+                        (pfd.cBlueBits = attribList[arg++]));
+                break;
+            case WX_GL_MIN_ALPHA:
+                // doesn't count in cColorBits
+                pfd.cAlphaBits = attribList[arg++];
+                break;
+            case WX_GL_DEPTH_SIZE:
+                pfd.cDepthBits = attribList[arg++];
+                break;
+            case WX_GL_STENCIL_SIZE:
+                pfd.cStencilBits = attribList[arg++];
+                break;
+            case WX_GL_MIN_ACCUM_RED:
+                pfd.cAccumBits = (pfd.cAccumBits +
+                        (pfd.cAccumRedBits = attribList[arg++]));
+                break;
+            case WX_GL_MIN_ACCUM_GREEN:
+                pfd.cAccumBits = (pfd.cAccumBits +
+                        (pfd.cAccumGreenBits = attribList[arg++]));
+                break;
+            case WX_GL_MIN_ACCUM_BLUE:
+                pfd.cAccumBits = (pfd.cAccumBits +
+                        (pfd.cAccumBlueBits = attribList[arg++]));
+                break;
+            case WX_GL_MIN_ACCUM_ALPHA:
+                pfd.cAccumBits = (pfd.cAccumBits +
+                        (pfd.cAccumAlphaBits = attribList[arg++]));
+                break;
+        }
     }
-  }
 }
 
-void wxGLCanvas::SetupPixelFormat(int *attribList) // (HDC hDC)
+/* static */
+int
+wxGLCanvas::ChooseMatchingPixelFormat(HDC hdc,
+                                      const int *attribList,
+                                      PIXELFORMATDESCRIPTOR *ppfd)
 {
-  PIXELFORMATDESCRIPTOR pfd = {
-        sizeof(PIXELFORMATDESCRIPTOR),    /* size */
-        1,                /* version */
+    // default neutral pixel format
+    PIXELFORMATDESCRIPTOR pfd =
+    {
+        sizeof(PIXELFORMATDESCRIPTOR),  // size
+        1,                              // version
         PFD_SUPPORT_OPENGL |
         PFD_DRAW_TO_WINDOW |
-        PFD_DOUBLEBUFFER,        /* support double-buffering */
-        PFD_TYPE_RGBA,            /* color type */
-        16,                /* prefered color depth */
-        0, 0, 0, 0, 0, 0,        /* color bits (ignored) */
-        0,                /* no alpha buffer */
-        0,                /* alpha bits (ignored) */
-        0,                /* no accumulation buffer */
-        0, 0, 0, 0,            /* accum bits (ignored) */
-        16,                /* depth buffer */
-        0,                /* no stencil buffer */
-        0,                /* no auxiliary buffers */
-        PFD_MAIN_PLANE,            /* main layer */
-        0,                /* reserved */
-        0, 0, 0,            /* no layer, visible, damage masks */
+        PFD_DOUBLEBUFFER,               // support double-buffering
+        PFD_TYPE_RGBA,                  // color type
+        16,                             // preferred color depth
+        0, 0, 0, 0, 0, 0,               // color bits (ignored)
+        0,                              // no alpha buffer
+        0,                              // alpha bits (ignored)
+        0,                              // no accumulation buffer
+        0, 0, 0, 0,                     // accumulator bits (ignored)
+        16,                             // depth buffer
+        0,                              // no stencil buffer
+        0,                              // no auxiliary buffers
+        PFD_MAIN_PLANE,                 // main layer
+        0,                              // reserved
+        0, 0, 0,                        // no layer, visible, damage masks
     };
 
-  AdjustPFDForAttributes(pfd, attribList);
+    if ( !ppfd )
+        ppfd = &pfd;
+    else
+        *ppfd = pfd;
 
-  int pixelFormat = ChoosePixelFormat((HDC) m_hDC, &pfd);
-  if (pixelFormat == 0) {
-    wxLogLastError(_T("ChoosePixelFormat"));
-  }
-  else {
-    if ( !::SetPixelFormat((HDC) m_hDC, pixelFormat, &pfd) ) {
-      wxLogLastError(_T("SetPixelFormat"));
-    }
-  }
+    AdjustPFDForAttributes(*ppfd, attribList);
+
+    return ::ChoosePixelFormat(hdc, ppfd);
 }
 
-void wxGLCanvas::SetupPalette(const wxPalette& palette)
+bool wxGLCanvas::DoSetup(const int *attribList)
 {
-    int pixelFormat = GetPixelFormat((HDC) m_hDC);
     PIXELFORMATDESCRIPTOR pfd;
+    const int pixelFormat = ChooseMatchingPixelFormat(m_hDC, attribList, &pfd);
+    if ( !pixelFormat )
+    {
+        wxLogLastError(_T("ChoosePixelFormat"));
+        return false;
+    }
+
+    if ( !::SetPixelFormat(m_hDC, pixelFormat, &pfd) )
+    {
+        wxLogLastError(_T("SetPixelFormat"));
+        return false;
+    }
 
-    DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
+    return true;
+}
+
+// ----------------------------------------------------------------------------
+// palette stuff
+// ----------------------------------------------------------------------------
 
-    if (pfd.dwFlags & PFD_NEED_PALETTE)
+#if wxUSE_PALETTE
+
+bool wxGLCanvas::SetupPalette(const wxPalette& palette)
+{
+    const int pixelFormat = ::GetPixelFormat(m_hDC);
+    if ( !pixelFormat )
     {
+        wxLogLastError(_T("GetPixelFormat"));
+        return false;
     }
-    else
+
+    PIXELFORMATDESCRIPTOR pfd;
+    if ( !::DescribePixelFormat(m_hDC, pixelFormat, sizeof(pfd), &pfd) )
     {
-      return;
+        wxLogLastError(_T("DescribePixelFormat"));
+        return false;
     }
 
+    if ( !(pfd.dwFlags & PFD_NEED_PALETTE) )
+        return true;
+
     m_palette = palette;
 
     if ( !m_palette.Ok() )
     {
         m_palette = CreateDefaultPalette();
+        if ( !m_palette.Ok() )
+            return false;
     }
 
-    if (m_palette.Ok())
+    if ( !::SelectPalette(m_hDC, GetHpaletteOf(m_palette), FALSE) )
     {
-        SelectPalette((HDC) m_hDC, (HPALETTE) m_palette.GetHPALETTE(), FALSE);
-        RealizePalette((HDC) m_hDC);
+        wxLogLastError(_T("SelectPalette"));
+        return false;
     }
+
+    if ( ::RealizePalette(m_hDC) == GDI_ERROR )
+    {
+        wxLogLastError(_T("RealizePalette"));
+        return false;
+    }
+
+    return true;
 }
 
 wxPalette wxGLCanvas::CreateDefaultPalette()
 {
     PIXELFORMATDESCRIPTOR pfd;
     int paletteSize;
-    int pixelFormat = GetPixelFormat((HDC) m_hDC);
+    int pixelFormat = GetPixelFormat(m_hDC);
 
-    DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
+    DescribePixelFormat(m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
 
     paletteSize = 1 << pfd.cColorBits;
 
     LOGPALETTE* pPal =
      (LOGPALETTE*) malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY));
     pPal->palVersion = 0x300;
-    pPal->palNumEntries = paletteSize;
+    pPal->palNumEntries = (WORD)paletteSize;
 
     /* build a simple RGB color palette */
     {
@@ -500,11 +536,11 @@ wxPalette wxGLCanvas::CreateDefaultPalette()
 
     for (i=0; i<paletteSize; ++i) {
         pPal->palPalEntry[i].peRed =
-            (((i >> pfd.cRedShift) & redMask) * 255) / redMask;
+            (BYTE)((((i >> pfd.cRedShift) & redMask) * 255) / redMask);
         pPal->palPalEntry[i].peGreen =
-            (((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask;
+            (BYTE)((((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask);
         pPal->palPalEntry[i].peBlue =
-            (((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask;
+            (BYTE)((((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask);
         pPal->palPalEntry[i].peFlags = 0;
     }
     }
@@ -518,47 +554,20 @@ wxPalette wxGLCanvas::CreateDefaultPalette()
     return palette;
 }
 
-void wxGLCanvas::SwapBuffers()
-{
-  if (m_glContext)
-    m_glContext->SwapBuffers();
-}
-
-void wxGLCanvas::OnSize(wxSizeEvent& event)
-{
-}
-
-void wxGLCanvas::SetCurrent()
-{
-  if (m_glContext)
-  {
-    m_glContext->SetCurrent();
-  }
-}
-
-void wxGLCanvas::SetColour(const wxChar *colour)
-{
-  if (m_glContext)
-    m_glContext->SetColour(colour);
-}
-
-// TODO: Have to have this called by parent frame (?)
-// So we need wxFrame to call OnQueryNewPalette for all children...
 void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent& event)
 {
   /* realize palette if this is the current window */
   if ( GetPalette()->Ok() ) {
     ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
-    ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
-    ::RealizePalette((HDC) GetHDC());
+    ::SelectPalette(GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
+    ::RealizePalette(GetHDC());
     Refresh();
-    event.SetPaletteRealized(TRUE);
+    event.SetPaletteRealized(true);
   }
   else
-    event.SetPaletteRealized(FALSE);
+    event.SetPaletteRealized(false);
 }
 
-// I think this doesn't have to be propagated to child windows.
 void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent& event)
 {
   /* realize palette if this is *not* the current window */
@@ -566,190 +575,84 @@ void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent& event)
        GetPalette()->Ok() && (this != event.GetChangedWindow()) )
   {
     ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
-    ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
-    ::RealizePalette((HDC) GetHDC());
+    ::SelectPalette(GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
+    ::RealizePalette(GetHDC());
     Refresh();
   }
 }
 
-/* Give extensions proper function names. */
+#endif // wxUSE_PALETTE
 
-/* EXT_vertex_array */
-void glArrayElementEXT(GLint i)
-{
-}
+// ----------------------------------------------------------------------------
+// deprecated wxGLCanvas methods using implicit wxGLContext
+// ----------------------------------------------------------------------------
 
-void glColorPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
-{
-}
+// deprecated constructors creating an implicit m_glContext
+#if WXWIN_COMPATIBILITY_2_8
 
-void glDrawArraysEXT(GLenum mode, GLint first, GLsizei count)
+wxGLCanvas::wxGLCanvas(wxWindow *parent,
+                       wxWindowID id,
+                       const wxPoint& pos,
+                       const wxSize& size,
+                       long style,
+                       const wxString& name,
+                       const int *attribList,
+                       const wxPalette& palette)
 {
-#ifdef GL_EXT_vertex_array
-    static PFNGLDRAWARRAYSEXTPROC proc = 0;
-
-    if ( !proc )
-    {
-        proc = (PFNGLDRAWARRAYSEXTPROC) wglGetProcAddress("glDrawArraysEXT");
-    }
-
-    if ( proc )
-        (* proc) (mode, first, count);
-#endif
-}
+    Init();
 
-void glEdgeFlagPointerEXT(GLsizei stride, GLsizei count, const GLboolean *pointer)
-{
+    if ( Create(parent, id, pos, size, style, name, attribList, palette) )
+        m_glContext = new wxGLContext(this);
 }
 
-void glGetPointervEXT(GLenum pname, GLvoid* *params)
+wxGLCanvas::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)
 {
-}
+    Init();
 
-void glIndexPointerEXT(GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
-{
+    if ( Create(parent, id, pos, size, style, name, attribList, palette) )
+        m_glContext = new wxGLContext(this, shared);
 }
 
-void glNormalPointerEXT(GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
+wxGLCanvas::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)
 {
-#ifdef GL_EXT_vertex_array
-  static PFNGLNORMALPOINTEREXTPROC proc = 0;
-
-  if ( !proc )
-  {
-    proc = (PFNGLNORMALPOINTEREXTPROC) wglGetProcAddress("glNormalPointerEXT");
-  }
+    Init();
 
-  if ( proc )
-    (* proc) (type, stride, count, pointer);
-#endif
+    if ( Create(parent, id, pos, size, style, name, attribList, palette) )
+        m_glContext = new wxGLContext(this, shared ? shared->m_glContext : NULL);
 }
 
-void glTexCoordPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
-{
-}
+#endif // WXWIN_COMPATIBILITY_2_8
 
-void glVertexPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
-{
-#ifdef GL_EXT_vertex_array
-  static PFNGLVERTEXPOINTEREXTPROC proc = 0;
 
-  if ( !proc )
-  {
-    proc = (PFNGLVERTEXPOINTEREXTPROC) wglGetProcAddress("glVertexPointerEXT");
-  }
-  if ( proc )
-    (* proc) (size, type, stride, count, pointer);
-#endif
-}
-
-/* EXT_color_subtable */
-void glColorSubtableEXT(GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *table)
-{
-}
-
-/* EXT_color_table */
-void glColorTableEXT(GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table)
-{
-}
-
-void glCopyColorTableEXT(GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width)
-{
-}
-
-void glGetColorTableEXT(GLenum target, GLenum format, GLenum type, GLvoid *table)
-{
-}
-
-void glGetColorTableParamaterfvEXT(GLenum target, GLenum pname, GLfloat *params)
-{
-}
-
-void glGetColorTavleParameterivEXT(GLenum target, GLenum pname, GLint *params)
-{
-}
-
-/* SGI_compiled_vertex_array */
-void glLockArraysSGI(GLint first, GLsizei count)
-{
-}
-
-void glUnlockArraysSGI()
-{
-}
-
-
-/* SGI_cull_vertex */
-void glCullParameterdvSGI(GLenum pname, GLdouble* params)
-{
-}
-
-void glCullParameterfvSGI(GLenum pname, GLfloat* params)
-{
-}
-
-/* SGI_index_func */
-void glIndexFuncSGI(GLenum func, GLclampf ref)
-{
-}
-
-/* SGI_index_material */
-void glIndexMaterialSGI(GLenum face, GLenum mode)
-{
-}
-
-/* WIN_swap_hint */
-void glAddSwapHintRectWin(GLint x, GLint y, GLsizei width, GLsizei height)
-{
-}
-
-
-//---------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
 // wxGLApp
-//---------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
 
-IMPLEMENT_CLASS(wxGLApp, wxApp)
-
-bool wxGLApp::InitGLVisual(int *attribList)
+bool wxGLApp::InitGLVisual(const int *attribList)
 {
-  int pixelFormat;
-  PIXELFORMATDESCRIPTOR pfd = {
-        sizeof(PIXELFORMATDESCRIPTOR),    /* size */
-        1,                /* version */
-        PFD_SUPPORT_OPENGL |
-        PFD_DRAW_TO_WINDOW |
-        PFD_DOUBLEBUFFER,        /* support double-buffering */
-        PFD_TYPE_RGBA,            /* color type */
-        16,                /* prefered color depth */
-        0, 0, 0, 0, 0, 0,        /* color bits (ignored) */
-        0,                /* no alpha buffer */
-        0,                /* alpha bits (ignored) */
-        0,                /* no accumulation buffer */
-        0, 0, 0, 0,            /* accum bits (ignored) */
-        16,                /* depth buffer */
-        0,                /* no stencil buffer */
-        0,                /* no auxiliary buffers */
-        PFD_MAIN_PLANE,            /* main layer */
-        0,                /* reserved */
-        0, 0, 0,            /* no layer, visible, damage masks */
-    };
-
-  AdjustPFDForAttributes(pfd, attribList);
-
-  // use DC for whole (root) screen, since no windows have yet been created
-  pixelFormat = ChoosePixelFormat(ScreenHDC(), &pfd);
-
-  if (pixelFormat == 0) {
-    wxLogError(_("Failed to initialize OpenGL"));
-    return FALSE;
-  }
-
-  return TRUE;
-}
+    if ( !wxGLCanvas::ChooseMatchingPixelFormat(ScreenHDC(), attribList) )
+    {
+        wxLogError(_("Failed to initialize OpenGL"));
+        return false;
+    }
 
-wxGLApp::~wxGLApp()
-{
+    return true;
 }
 
-#endif
-    // wxUSE_GLCANVAS
+#endif // wxUSE_GLCANVAS