[clutter/wip/cogl-winsys-wgl: 2/2] cogl: Add a full winsys for WGL



commit 46298011e0e4e048b2c3b94d609c515769d4f3ed
Author: Neil Roberts <neil linux intel com>
Date:   Thu Apr 21 16:46:39 2011 +0100

    cogl: Add a full winsys for WGL
    
    This moves down the winsys-related Clutter code from the Win32 backend
    to Cogl in a similar way to GLX backend. The winsys doesn't yet
    support creating onscreen buffers that aren't using a foreign window.

 clutter/cogl/cogl/Makefile.am                      |    4 +-
 clutter/cogl/cogl/cogl-framebuffer-private.h       |    8 +
 clutter/cogl/cogl/cogl-framebuffer.c               |   17 +
 clutter/cogl/cogl/cogl-framebuffer.h               |   15 +
 clutter/cogl/cogl/cogl.h                           |    3 +
 clutter/cogl/cogl/winsys/cogl-winsys-private.h     |    9 +
 .../winsys/cogl-winsys-wgl-feature-functions.h     |   36 ++
 clutter/cogl/cogl/winsys/cogl-winsys-wgl.c         |  639 +++++++++++++++++++-
 clutter/win32/clutter-backend-win32.c              |  348 +++--------
 clutter/win32/clutter-backend-win32.h              |    6 +-
 clutter/win32/clutter-event-win32.c                |    8 +
 clutter/win32/clutter-stage-win32.c                |   59 +-
 clutter/win32/clutter-stage-win32.h                |    3 +-
 configure.ac                                       |    2 +
 14 files changed, 855 insertions(+), 302 deletions(-)
---
diff --git a/clutter/cogl/cogl/Makefile.am b/clutter/cogl/cogl/Makefile.am
index 80bbf91..0fc6e5a 100644
--- a/clutter/cogl/cogl/Makefile.am
+++ b/clutter/cogl/cogl/Makefile.am
@@ -352,8 +352,8 @@ cogl_sources_c += \
 endif
 if SUPPORT_WIN32
 cogl_sources_c += \
-       $(srcdir)/winsys/cogl-winsys-wgl.c \
-       $(srcdir)/winsys/cogl-winsys-stub.c
+       $(srcdir)/winsys/cogl-winsys-wgl-feature-functions.h \
+       $(srcdir)/winsys/cogl-winsys-wgl.c
 endif
 if SUPPORT_OSX
 cogl_sources_c += \
diff --git a/clutter/cogl/cogl/cogl-framebuffer-private.h b/clutter/cogl/cogl/cogl-framebuffer-private.h
index 278cd15..6b2cefc 100644
--- a/clutter/cogl/cogl/cogl-framebuffer-private.h
+++ b/clutter/cogl/cogl/cogl-framebuffer-private.h
@@ -38,6 +38,10 @@
 #include <GL/glxext.h>
 #endif
 
+#ifdef COGL_HAS_WGL_SUPPORT
+#include <windows.h>
+#endif
+
 typedef enum _CoglFramebufferType {
   COGL_FRAMEBUFFER_TYPE_ONSCREEN,
   COGL_FRAMEBUFFER_TYPE_OFFSCREEN
@@ -120,6 +124,10 @@ struct _CoglOnscreen
   guint32 foreign_xid;
 #endif
 
+#ifdef COGL_HAS_WGL_SUPPORT
+  HWND foreign_hwnd;
+#endif
+
   gboolean swap_throttled;
 
   void *winsys;
diff --git a/clutter/cogl/cogl/cogl-framebuffer.c b/clutter/cogl/cogl/cogl-framebuffer.c
index 8f0769d..b9df8df 100644
--- a/clutter/cogl/cogl/cogl-framebuffer.c
+++ b/clutter/cogl/cogl/cogl-framebuffer.c
@@ -1623,6 +1623,23 @@ cogl_onscreen_x11_get_visual_xid (CoglOnscreen *onscreen)
 }
 #endif /* COGL_HAS_X11_SUPPORT */
 
+#ifdef COGL_HAS_WIN32_SUPPORT
+
+void
+cogl_onscreen_win32_set_foreign_window (CoglOnscreen *onscreen,
+                                        HWND hwnd)
+{
+  onscreen->foreign_hwnd = hwnd;
+}
+
+HWND
+cogl_onscreen_win32_get_window (CoglOnscreen *onscreen)
+{
+  return _cogl_winsys_onscreen_win32_get_window (onscreen);
+}
+
+#endif /* COGL_HAS_WIN32_SUPPORT */
+
 unsigned int
 cogl_framebuffer_add_swap_buffers_callback (CoglFramebuffer *framebuffer,
                                             CoglSwapBuffersNotify callback,
diff --git a/clutter/cogl/cogl/cogl-framebuffer.h b/clutter/cogl/cogl/cogl-framebuffer.h
index 8042428..688fa50 100644
--- a/clutter/cogl/cogl/cogl-framebuffer.h
+++ b/clutter/cogl/cogl/cogl-framebuffer.h
@@ -30,6 +30,9 @@
 
 #include <glib.h>
 
+#ifdef COGL_HAS_WIN32
+#include <windows.h>
+#endif /* COGL_HAS_WIN32 */
 
 G_BEGIN_DECLS
 
@@ -101,6 +104,18 @@ guint32
 cogl_onscreen_x11_get_visual_xid (CoglOnscreen *onscreen);
 #endif /* COGL_HAS_X11 */
 
+#ifdef COGL_HAS_WIN32_SUPPORT
+#define cogl_onscreen_win32_set_foreign_window \
+  cogl_onscreen_win32_set_foreign_window_EXP
+void
+cogl_onscreen_win32_set_foreign_window (CoglOnscreen *onscreen,
+                                        HWND hwnd);
+
+#define cogl_onscreen_win32_get_window cogl_onscreen_win32_get_window_EXP
+HWND
+cogl_onscreen_win32_get_window (CoglOnscreen *onscreen);
+#endif /* COGL_HAS_WIN32_SUPPORT */
+
 void
 cogl_onscreen_set_swap_throttled (CoglOnscreen *onscreen,
                                   gboolean throttled);
diff --git a/clutter/cogl/cogl/cogl.h b/clutter/cogl/cogl/cogl.h
index cbd2d0c..75c37de 100644
--- a/clutter/cogl/cogl/cogl.h
+++ b/clutter/cogl/cogl/cogl.h
@@ -88,6 +88,9 @@ typedef struct _CoglFramebuffer CoglFramebuffer;
 #ifdef COGL_HAS_XLIB
 #include <cogl/cogl-xlib.h>
 #endif
+#ifdef COGL_HAS_WIN32
+#include <cogl/cogl-win32.h>
+#endif
 /* XXX: This will definitly go away once all the Clutter winsys
  * code has been migrated down into Cogl! */
 #include <cogl/cogl-clutter.h>
diff --git a/clutter/cogl/cogl/winsys/cogl-winsys-private.h b/clutter/cogl/cogl/winsys/cogl-winsys-private.h
index 8d56bea..368ff9b 100644
--- a/clutter/cogl/cogl/winsys/cogl-winsys-private.h
+++ b/clutter/cogl/cogl/winsys/cogl-winsys-private.h
@@ -30,6 +30,10 @@
 #include <X11/Xutil.h>
 #endif
 
+#ifdef COGL_HAS_WGL_SUPPORT
+#include <windows.h>
+#endif /* COGL_HAS_WGL_SUPPORT */
+
 GQuark
 _cogl_winsys_error_quark (void);
 
@@ -115,4 +119,9 @@ void
 _cogl_winsys_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
                                                     unsigned int id);
 
+#ifdef COGL_HAS_WIN32_SUPPORT
+HWND
+_cogl_winsys_onscreen_win32_get_window (CoglOnscreen *onscreen);
+#endif /* COGL_HAS_WIN32_SUPPORT */
+
 #endif /* __COGL_WINSYS_PRIVATE_H */
diff --git a/clutter/cogl/cogl/winsys/cogl-winsys-wgl-feature-functions.h b/clutter/cogl/cogl/winsys/cogl-winsys-wgl-feature-functions.h
new file mode 100644
index 0000000..cd75a7c
--- /dev/null
+++ b/clutter/cogl/cogl/winsys/cogl-winsys-wgl-feature-functions.h
@@ -0,0 +1,36 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+/* See cogl-winsys-glx-feature-functions.h for a description of how
+   this file is used */
+
+COGL_WINSYS_FEATURE_BEGIN (swap_control,
+                           "EXT\0",
+                           "swap_control\0",
+                           0,
+                           0,
+                           COGL_WINSYS_FEATURE_SWAP_THROTTLE)
+COGL_WINSYS_FEATURE_FUNCTION (int, wglSwapInterval,
+                              (int interval))
+COGL_WINSYS_FEATURE_END ()
diff --git a/clutter/cogl/cogl/winsys/cogl-winsys-wgl.c b/clutter/cogl/cogl/winsys/cogl-winsys-wgl.c
index 7088fa4..707765f 100644
--- a/clutter/cogl/cogl/winsys/cogl-winsys-wgl.c
+++ b/clutter/cogl/cogl/winsys/cogl-winsys-wgl.c
@@ -3,7 +3,7 @@
  *
  * An object oriented GL/GLES Abstraction/Utility Layer
  *
- * Copyright (C) 2007,2008,2009 Intel Corporation.
+ * Copyright (C) 2007,2008,2009,2011 Intel Corporation.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -25,11 +25,648 @@
 #include "config.h"
 #endif
 
+#include <windows.h>
+
 #include "cogl.h"
 
+#include "cogl-winsys-private.h"
+#include "cogl-context-private.h"
+#include "cogl-framebuffer.h"
+#include "cogl-swap-chain-private.h"
+#include "cogl-renderer-private.h"
+#include "cogl-display-private.h"
+#include "cogl-onscreen-template-private.h"
+#include "cogl-private.h"
+#include "cogl-feature-private.h"
+
+typedef struct _CoglRendererWgl
+{
+  /* Function pointers for GLX specific extensions */
+#define COGL_WINSYS_FEATURE_BEGIN(a, b, c, d, e, f)
+
+#define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) \
+  ret (APIENTRY * pf_ ## name) args;
+
+#define COGL_WINSYS_FEATURE_END()
+
+#include "cogl-winsys-wgl-feature-functions.h"
+
+#undef COGL_WINSYS_FEATURE_BEGIN
+#undef COGL_WINSYS_FEATURE_FUNCTION
+#undef COGL_WINSYS_FEATURE_END
+} CoglRendererWgl;
+
+typedef struct _CoglDisplayWgl
+{
+  HGLRC wgl_context;
+  HWND dummy_hwnd;
+  HDC dummy_dc;
+} CoglDisplayWgl;
+
+typedef struct _CoglOnscreenWin32
+{
+  HWND hwnd;
+  gboolean is_foreign_hwnd;
+} CoglOnscreenWin32;
+
+typedef struct _CoglContextWgl
+{
+  HDC current_dc;
+} CoglContextWgl;
+
+typedef struct _CoglOnscreenWgl
+{
+  CoglOnscreenWin32 _parent;
+
+  HDC client_dc;
+
+  gboolean swap_throttled;
+} CoglOnscreenWgl;
+
+/* Define a set of arrays containing the functions required from GL
+   for each winsys feature */
+#define COGL_WINSYS_FEATURE_BEGIN(name, namespaces, extension_names,    \
+                                  feature_flags, feature_flags_private, \
+                                  winsys_feature)                       \
+  static const CoglFeatureFunction                                      \
+  cogl_wgl_feature_ ## name ## _funcs[] = {
+#define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args)                   \
+  { G_STRINGIFY (name), G_STRUCT_OFFSET (CoglRendererWgl, pf_ ## name) },
+#define COGL_WINSYS_FEATURE_END()               \
+  { NULL, 0 },                                  \
+    };
+#include "cogl-winsys-wgl-feature-functions.h"
+
+/* Define an array of features */
+#undef COGL_WINSYS_FEATURE_BEGIN
+#define COGL_WINSYS_FEATURE_BEGIN(name, namespaces, extension_names,    \
+                                  feature_flags, feature_flags_private, \
+                                  winsys_feature)                       \
+  { 255, 255, namespaces, extension_names,                              \
+      feature_flags, feature_flags_private,                             \
+      winsys_feature,                                                   \
+      cogl_wgl_feature_ ## name ## _funcs },
+#undef COGL_WINSYS_FEATURE_FUNCTION
+#define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args)
+#undef COGL_WINSYS_FEATURE_END
+#define COGL_WINSYS_FEATURE_END()
+
+static const CoglFeatureData winsys_feature_data[] =
+  {
+#include "cogl-winsys-wgl-feature-functions.h"
+  };
+
 CoglFuncPtr
 _cogl_winsys_get_proc_address (const char *name)
 {
   return (CoglFuncPtr) wglGetProcAddress ((LPCSTR) name);
 }
 
+void
+_cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
+{
+  g_slice_free (CoglRendererWgl, renderer->winsys);
+}
+
+static CoglOnscreen *
+find_onscreen_for_hwnd (CoglContext *context, HWND hwnd)
+{
+  GList *l;
+
+  for (l = context->framebuffers; l; l = l->next)
+    {
+      CoglFramebuffer *framebuffer = l->data;
+
+      if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
+        {
+          CoglOnscreenWin32 *win32_onscreen =
+            COGL_ONSCREEN (framebuffer)->winsys;
+
+          if (win32_onscreen->hwnd == hwnd)
+            return COGL_ONSCREEN (framebuffer);
+        }
+    }
+
+  return NULL;
+}
+
+static CoglFilterReturn
+win32_event_filter_cb (void *native_event, void *data)
+{
+  MSG *msg = native_event;
+  CoglContext *context = data;
+
+  if (msg->message == WM_SIZE)
+    {
+      CoglOnscreen *onscreen =
+        find_onscreen_for_hwnd (context, msg->hwnd);
+
+      if (onscreen)
+        {
+          CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+
+          /* Ignore size changes resulting from the stage being
+             minimized - otherwise it will think the window has been
+             resized to 0,0 */
+          if (msg->wParam != SIZE_MINIMIZED)
+            {
+              WORD new_width = LOWORD (msg->lParam);
+              WORD new_height = HIWORD (msg->lParam);
+              _cogl_framebuffer_winsys_update_size (framebuffer,
+                                                    new_width,
+                                                    new_height);
+            }
+        }
+    }
+
+  return COGL_FILTER_CONTINUE;
+}
+
+gboolean
+_cogl_winsys_renderer_connect (CoglRenderer *renderer,
+                               GError **error)
+{
+  renderer->winsys = g_slice_new0 (CoglRendererWgl);
+
+  return TRUE;
+}
+
+static ATOM
+get_dummy_window_class ()
+{
+  static ATOM klass = 0;
+
+  if (klass == 0)
+    {
+      WNDCLASSW wndclass;
+      memset (&wndclass, 0, sizeof (wndclass));
+      wndclass.lpfnWndProc = DefWindowProc;
+      wndclass.hInstance = GetModuleHandleW (NULL);
+      wndclass.lpszClassName = L"CoglWin32DummyWindow";
+      klass = RegisterClassW (&wndclass);
+    }
+
+  return klass;
+}
+
+static gboolean
+pixel_format_is_better (const PIXELFORMATDESCRIPTOR *pfa,
+                        const PIXELFORMATDESCRIPTOR *pfb)
+{
+  /* Always prefer a format with a stencil buffer */
+  if (pfa->cStencilBits == 0)
+    {
+      if (pfb->cStencilBits > 0)
+        return TRUE;
+    }
+  else if (pfb->cStencilBits == 0)
+    return FALSE;
+
+  /* Prefer a bigger color buffer */
+  if (pfb->cColorBits > pfa->cColorBits)
+    return TRUE;
+  else if (pfb->cColorBits < pfa->cColorBits)
+    return FALSE;
+
+  /* Prefer a bigger depth buffer */
+  return pfb->cDepthBits > pfa->cDepthBits;
+}
+
+static int
+choose_pixel_format (HDC dc, PIXELFORMATDESCRIPTOR *pfd)
+{
+  int i, num_formats, best_pf = 0;
+  PIXELFORMATDESCRIPTOR best_pfd;
+
+  num_formats = DescribePixelFormat (dc, 0, sizeof (best_pfd), NULL);
+
+  for (i = 1; i <= num_formats; i++)
+    {
+      memset (pfd, 0, sizeof (*pfd));
+
+      if (DescribePixelFormat (dc, i, sizeof (best_pfd), pfd) &&
+          /* Check whether this format is useable by Cogl */
+          ((pfd->dwFlags & (PFD_SUPPORT_OPENGL |
+                            PFD_DRAW_TO_WINDOW |
+                            PFD_DOUBLEBUFFER |
+                            PFD_GENERIC_FORMAT)) ==
+           (PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW)) &&
+          pfd->iPixelType == PFD_TYPE_RGBA &&
+          pfd->cColorBits >= 16 && pfd->cColorBits <= 32 &&
+          pfd->cDepthBits >= 16 && pfd->cDepthBits <= 32 &&
+          /* Check whether this is a better format than one we've
+             already found */
+          (best_pf == 0 || pixel_format_is_better (&best_pfd, pfd)))
+        {
+          best_pf = i;
+          best_pfd = *pfd;
+        }
+    }
+
+  *pfd = best_pfd;
+
+  return best_pf;
+}
+
+static gboolean
+create_context (CoglDisplay *display, GError **error)
+{
+  CoglDisplayWgl *wgl_display = display->winsys;
+
+  g_return_val_if_fail (wgl_display->wgl_context == NULL, FALSE);
+
+  /* COGL assumes that there is always a GL context selected; in order
+   * to make sure that a WGL context exists and is made current, we
+   * use a small dummy window that never gets shown to which we can
+   * always fall back if no stage is available
+   */
+  if (wgl_display->dummy_hwnd == NULL)
+    {
+      ATOM window_class = get_dummy_window_class ();
+
+      if (window_class == 0)
+        {
+          g_set_error (error, COGL_WINSYS_ERROR,
+                       COGL_WINSYS_ERROR_CREATE_CONTEXT,
+                       "Unable to register window class");
+          return FALSE;
+        }
+
+      wgl_display->dummy_hwnd =
+        CreateWindowW ((LPWSTR) MAKEINTATOM (window_class),
+                       L".",
+                       WS_OVERLAPPEDWINDOW,
+                       CW_USEDEFAULT,
+                       CW_USEDEFAULT,
+                       1, 1,
+                       NULL, NULL,
+                       GetModuleHandle (NULL),
+                       NULL);
+
+      if (wgl_display->dummy_hwnd == NULL)
+        {
+          g_set_error (error, COGL_WINSYS_ERROR,
+                       COGL_WINSYS_ERROR_CREATE_CONTEXT,
+                       "Unable to create dummy window");
+          return FALSE;
+        }
+    }
+
+  if (wgl_display->dummy_dc == NULL)
+    {
+      PIXELFORMATDESCRIPTOR pfd;
+      int pf;
+
+      wgl_display->dummy_dc = GetDC (wgl_display->dummy_hwnd);
+
+      pf = choose_pixel_format (wgl_display->dummy_dc, &pfd);
+
+      if (pf == 0 || !SetPixelFormat (wgl_display->dummy_dc, pf, &pfd))
+        {
+          g_set_error (error, COGL_WINSYS_ERROR,
+                       COGL_WINSYS_ERROR_CREATE_CONTEXT,
+                       "Unable to find suitable GL pixel format");
+          ReleaseDC (wgl_display->dummy_hwnd, wgl_display->dummy_dc);
+          wgl_display->dummy_dc = NULL;
+          return FALSE;
+        }
+    }
+
+  if (wgl_display->wgl_context == NULL)
+    {
+      wgl_display->wgl_context = wglCreateContext (wgl_display->dummy_dc);
+
+      if (wgl_display->wgl_context == NULL)
+        {
+          g_set_error (error, COGL_WINSYS_ERROR,
+                       COGL_WINSYS_ERROR_CREATE_CONTEXT,
+                       "Unable to create suitable GL context");
+          return FALSE;
+        }
+    }
+
+  COGL_NOTE (WINSYS, "Selecting dummy 0x%x for the WGL context",
+             (unsigned int) wgl_display->dummy_hwnd);
+
+  wglMakeCurrent (wgl_display->dummy_dc, wgl_display->wgl_context);
+
+  return TRUE;
+}
+
+void
+_cogl_winsys_display_destroy (CoglDisplay *display)
+{
+  CoglDisplayWgl *wgl_display = display->winsys;
+
+  g_return_if_fail (wgl_display != NULL);
+
+  if (wgl_display->wgl_context)
+    {
+      wglMakeCurrent (NULL, NULL);
+      wglDeleteContext (wgl_display->wgl_context);
+    }
+
+  if (wgl_display->dummy_dc)
+    ReleaseDC (wgl_display->dummy_hwnd, wgl_display->dummy_dc);
+
+  if (wgl_display->dummy_hwnd)
+    DestroyWindow (wgl_display->dummy_hwnd);
+
+  g_slice_free (CoglDisplayWgl, display->winsys);
+  display->winsys = NULL;
+}
+
+gboolean
+_cogl_winsys_display_setup (CoglDisplay *display,
+                            GError **error)
+{
+  CoglDisplayWgl *wgl_display;
+
+  g_return_val_if_fail (display->winsys == NULL, FALSE);
+
+  wgl_display = g_slice_new0 (CoglDisplayWgl);
+  display->winsys = wgl_display;
+
+  if (!create_context (display, error))
+    goto error;
+
+  return TRUE;
+
+error:
+  _cogl_winsys_display_destroy (display);
+  return FALSE;
+}
+
+const char *
+get_wgl_extensions_string (HDC dc)
+{
+  const char * (APIENTRY *pf_wglGetExtensionsStringARB) (HDC);
+  const char * (APIENTRY *pf_wglGetExtensionsStringEXT) (void);
+
+  /* According to the docs for these two extensions, you are supposed
+     to use wglGetProcAddress to detect their availability so
+     presumably it will return NULL if they are not available */
+
+  pf_wglGetExtensionsStringARB =
+    (void *) wglGetProcAddress ("wglGetExtensionsStringARB");
+
+  if (pf_wglGetExtensionsStringARB)
+    return pf_wglGetExtensionsStringARB (dc);
+
+  pf_wglGetExtensionsStringEXT =
+    (void *) wglGetProcAddress ("wglGetExtensionsStringEXT");
+
+  if (pf_wglGetExtensionsStringEXT)
+    return pf_wglGetExtensionsStringEXT ();
+
+  /* The WGL_EXT_swap_control is also advertised as a GL extension as
+     GL_EXT_SWAP_CONTROL so if the extension to get the list of WGL
+     extensions isn't supported then we can at least fake it to
+     support the swap control extension */
+  if (_cogl_check_extension ("WGL_EXT_swap_control",
+                             (char *) glGetString (GL_EXTENSIONS)))
+    return "WGL_EXT_swap_control";
+
+  return NULL;
+}
+
+void
+update_winsys_features (CoglContext *context)
+{
+  CoglDisplayWgl *wgl_display = context->display->winsys;
+  CoglRendererWgl *wgl_renderer = context->display->renderer->winsys;
+  const char *wgl_extensions;
+  int i;
+
+  g_return_if_fail (wgl_display->wgl_context);
+
+  _cogl_gl_update_features (context);
+
+  memset (context->winsys_features, 0, sizeof (context->winsys_features));
+
+  context->feature_flags |= COGL_FEATURE_ONSCREEN_MULTIPLE;
+  COGL_FLAGS_SET (context->winsys_features,
+                  COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN,
+                  TRUE);
+
+  wgl_extensions = get_wgl_extensions_string (wgl_display->dummy_dc);
+
+  if (wgl_extensions)
+    {
+      COGL_NOTE (WINSYS, "  WGL Extensions: %s", wgl_extensions);
+
+      for (i = 0; i < G_N_ELEMENTS (winsys_feature_data); i++)
+        if (_cogl_feature_check ("WGL", winsys_feature_data + i, 0, 0,
+                                 wgl_extensions,
+                                 wgl_renderer))
+          {
+            context->feature_flags |= winsys_feature_data[i].feature_flags;
+            if (winsys_feature_data[i].winsys_feature)
+              COGL_FLAGS_SET (context->winsys_features,
+                              winsys_feature_data[i].winsys_feature,
+                              TRUE);
+          }
+    }
+}
+
+gboolean
+_cogl_winsys_context_init (CoglContext *context, GError **error)
+{
+  CoglContextWgl *wgl_context;
+
+  wgl_context = context->winsys = g_new0 (CoglContextWgl, 1);
+
+  cogl_renderer_add_native_filter (context->display->renderer,
+                                   win32_event_filter_cb,
+                                   context);
+
+  update_winsys_features (context);
+
+  return TRUE;
+}
+
+void
+_cogl_winsys_context_deinit (CoglContext *context)
+{
+  cogl_renderer_remove_native_filter (context->display->renderer,
+                                      win32_event_filter_cb,
+                                      context);
+
+  g_free (context->winsys);
+}
+
+gboolean
+_cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
+                            GError **error)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *context = framebuffer->context;
+  CoglDisplay *display = context->display;
+  CoglDisplayWgl *wgl_display = display->winsys;
+  CoglOnscreenWgl *wgl_onscreen;
+  CoglOnscreenWin32 *win32_onscreen;
+  PIXELFORMATDESCRIPTOR pfd;
+  int pf;
+  HWND hwnd;
+
+  g_return_val_if_fail (wgl_display->wgl_context, FALSE);
+
+  /* XXX: Note we ignore the user's original width/height when given a
+   * foreign window. */
+  if (onscreen->foreign_hwnd)
+    {
+      RECT client_rect;
+
+      hwnd = onscreen->foreign_hwnd;
+
+      GetClientRect (hwnd, &client_rect);
+
+      _cogl_framebuffer_winsys_update_size (framebuffer,
+                                            client_rect.right,
+                                            client_rect.bottom);
+    }
+  else
+    {
+      /* FIXME */
+      g_assert_not_reached ();
+    }
+
+  onscreen->winsys = g_slice_new0 (CoglOnscreenWgl);
+  win32_onscreen = onscreen->winsys;
+  wgl_onscreen = onscreen->winsys;
+
+  win32_onscreen->hwnd = hwnd;
+
+  wgl_onscreen->client_dc = GetDC (hwnd);
+
+  /* Use the same pixel format as the dummy DC from the renderer */
+  pf = GetPixelFormat (wgl_display->dummy_dc);
+  DescribePixelFormat (wgl_display->dummy_dc, pf, sizeof (pfd), &pfd);
+  if (!SetPixelFormat (wgl_onscreen->client_dc, pf, &pfd))
+    {
+      g_set_error (error, COGL_WINSYS_ERROR,
+                   COGL_WINSYS_ERROR_CREATE_ONSCREEN,
+                   "Error setting pixel format on the window");
+      ReleaseDC (hwnd, wgl_onscreen->client_dc);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+void
+_cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
+{
+  CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
+  CoglContextWgl *wgl_context = context->winsys;
+  CoglOnscreenWin32 *win32_onscreen = onscreen->winsys;
+  CoglOnscreenWgl *wgl_onscreen = onscreen->winsys;
+
+  if (wgl_context->current_dc == wgl_onscreen->client_dc)
+    _cogl_winsys_onscreen_bind (NULL);
+
+  ReleaseDC (win32_onscreen->hwnd, wgl_onscreen->client_dc);
+
+  if (!win32_onscreen->is_foreign_hwnd)
+    {
+      /* FIXME */
+      g_assert_not_reached ();
+    }
+}
+
+void
+_cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
+{
+  CoglContext *context;
+  CoglContextWgl *wgl_context;
+  CoglDisplayWgl *wgl_display;
+  CoglOnscreenWgl *wgl_onscreen;
+  CoglRendererWgl *wgl_renderer;
+
+  /* The glx backend tries to bind the dummy context if onscreen ==
+     NULL, but this isn't really going to work because before checking
+     whether onscreen == NULL it reads the pointer to get the
+     context */
+  g_return_if_fail (onscreen != NULL);
+
+  context = COGL_FRAMEBUFFER (onscreen)->context;
+  wgl_context = context->winsys;
+  wgl_display = context->display->winsys;
+  wgl_onscreen = onscreen->winsys;
+  wgl_renderer = context->display->renderer->winsys;
+
+  if (wgl_context->current_dc == wgl_onscreen->client_dc)
+    return;
+
+  wglMakeCurrent (wgl_onscreen->client_dc, wgl_display->wgl_context);
+
+  /* According to the specs for WGL_EXT_swap_control SwapInterval()
+   * applies to the current window not the context so we apply it here
+   * to ensure its up-to-date even for new windows.
+   */
+  if (wgl_renderer->pf_wglSwapInterval)
+    {
+      if (onscreen->swap_throttled)
+        wgl_renderer->pf_wglSwapInterval (1);
+      else
+        wgl_renderer->pf_wglSwapInterval (0);
+    }
+
+  wgl_context->current_dc = wgl_onscreen->client_dc;
+}
+
+void
+_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
+{
+  CoglOnscreenWgl *wgl_onscreen = onscreen->winsys;
+
+  SwapBuffers (wgl_onscreen->client_dc);
+}
+
+void
+_cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
+                                   int *rectangles,
+                                   int n_rectangles)
+{
+  /* We don't advertise swap region support so this should never be called */
+  g_assert_not_reached ();
+}
+
+unsigned int
+_cogl_winsys_onscreen_add_swap_buffers_callback (CoglOnscreen *onscreen,
+                                                 CoglSwapBuffersNotify callback,
+                                                 void *user_data)
+{
+  /* We don't support swap events so this should never be called */
+  g_assert_not_reached ();
+}
+
+void
+_cogl_winsys_onscreen_remove_swap_buffers_callback (CoglOnscreen *onscreen,
+                                                    unsigned int id)
+{
+  /* We don't support swap events so this should never be called */
+  g_assert_not_reached ();
+}
+
+void
+_cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen)
+{
+  CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
+  CoglContextWgl *wgl_context = context->winsys;
+  CoglOnscreenWgl *wgl_onscreen = onscreen->winsys;
+
+  if (wgl_context->current_dc != wgl_onscreen->client_dc)
+    return;
+
+  /* This will cause it to rebind the context and update the swap interval */
+  wgl_context->current_dc = NULL;
+  _cogl_winsys_onscreen_bind (onscreen);
+}
+
+HWND
+_cogl_winsys_onscreen_win32_get_window (CoglOnscreen *onscreen)
+{
+  CoglOnscreenWin32 *win32_onscreen = onscreen->winsys;
+  return win32_onscreen->hwnd;
+}
diff --git a/clutter/win32/clutter-backend-win32.c b/clutter/win32/clutter-backend-win32.c
index a5c367f..da61ea3 100644
--- a/clutter/win32/clutter-backend-win32.c
+++ b/clutter/win32/clutter-backend-win32.c
@@ -54,6 +54,15 @@ static HINSTANCE clutter_hinst = NULL;
 /* various flags corresponding to pre init setup calls */
 static gboolean _no_event_retrieval = FALSE;
 
+G_CONST_RETURN gchar *
+_clutter_backend_win32_get_vblank (void)
+{
+  if (clutter_vblank_name && strcmp (clutter_vblank_name, "0") == 0)
+    return "none";
+  else
+    return clutter_vblank_name;
+}
+
 gboolean
 clutter_backend_win32_pre_parse (ClutterBackend  *backend,
 				 GError         **error)
@@ -125,6 +134,7 @@ clutter_backend_win32_finalize (GObject *gobject)
 static void
 clutter_backend_win32_dispose (GObject *gobject)
 {
+  ClutterBackend *backend = CLUTTER_BACKEND (gobject);
   ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (gobject);
   ClutterStageManager *stage_manager;
 
@@ -139,26 +149,13 @@ clutter_backend_win32_dispose (GObject *gobject)
   /* Unrealize all shaders, since the GL context is going away */
   _clutter_shader_release_all ();
 
-  if (backend_win32->gl_context)
-    {
-      wglMakeCurrent (NULL, NULL);
-      wglDeleteContext (backend_win32->gl_context);
-      backend_win32->gl_context = NULL;
-    }
-
-  if (backend_win32->dummy_dc)
-    {
-      ReleaseDC (backend_win32->dummy_hwnd, backend_win32->dummy_dc);
-      backend_win32->dummy_dc = NULL;
-    }
+  G_OBJECT_CLASS (clutter_backend_win32_parent_class)->dispose (gobject);
 
-  if (backend_win32->dummy_hwnd)
+  if (backend->cogl_context)
     {
-      DestroyWindow (backend_win32->dummy_hwnd);
-      backend_win32->dummy_hwnd = NULL;
+      cogl_object_unref (backend->cogl_context);
+      backend->cogl_context = NULL;
     }
-
-  G_OBJECT_CLASS (clutter_backend_win32_parent_class)->dispose (gobject);
 }
 
 static GObject *
@@ -185,296 +182,110 @@ clutter_backend_win32_constructor (GType                  gtype,
   return g_object_ref (backend_singleton);
 }
 
-static gboolean
-check_vblank_env (const char *name)
-{
-  return clutter_vblank_name && !g_ascii_strcasecmp (clutter_vblank_name, name);
-}
-
 ClutterFeatureFlags
 clutter_backend_win32_get_features (ClutterBackend *backend)
 {
-  ClutterFeatureFlags  flags;
-  const gchar         *extensions;
-  SwapIntervalProc     swap_interval;
-  ClutterBackendWin32 *backend_win32;
-
-  /* this will make sure that the GL context exists and is bound to a
-     drawable */
-  backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
-  g_return_val_if_fail (backend_win32->gl_context != NULL, 0);
-  g_return_val_if_fail (wglGetCurrentDC () != NULL, 0);
-
-  extensions = (const gchar *) glGetString (GL_EXTENSIONS);
-
-  CLUTTER_NOTE (BACKEND,
-                "Checking features\n"
-                "  GL_VENDOR: %s\n"
-                "  GL_RENDERER: %s\n"
-                "  GL_VERSION: %s\n"
-                "  GL_EXTENSIONS: %s\n",
-                glGetString (GL_VENDOR),
-                glGetString (GL_RENDERER),
-                glGetString (GL_VERSION),
-                extensions);
-
-  flags = CLUTTER_FEATURE_STAGE_USER_RESIZE
-    | CLUTTER_FEATURE_STAGE_CURSOR
-    | CLUTTER_FEATURE_STAGE_MULTIPLE;
-
-  /* If the VBlank should be left at the default or it has been
-     disabled elsewhere (eg NVIDIA) then don't bother trying to check
-     for the swap control extension */
-  if (getenv ("__GL_SYNC_TO_VBLANK") || check_vblank_env ("default"))
-    CLUTTER_NOTE (BACKEND, "vblank sync: left at default at user request");
-  else if (cogl_clutter_check_extension ("WGL_EXT_swap_control", extensions)
-	   && (swap_interval = (SwapIntervalProc)
-	       cogl_get_proc_address ("wglSwapIntervalEXT")))
-    {
-      /* According to the specification for the WGL_EXT_swap_control
-	 extension the default swap interval is 1 anyway, so if no
-	 vblank is requested then we should explicitly set it to
-	 zero */
-      if (check_vblank_env ("none"))
-	{
-	  if (swap_interval (0))
-	    CLUTTER_NOTE (BACKEND, "vblank sync: successfully disabled");
-	  else
-	    CLUTTER_NOTE (BACKEND, "vblank sync: disabling failed");
-	}
-      else
-	{
-	  if (swap_interval (1))
-	    {
-	      flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
-	      CLUTTER_NOTE (BACKEND, "vblank sync: wglSwapIntervalEXT "
-			    "vblank setup success");
-	    }
-	  else
-	    CLUTTER_NOTE (BACKEND, "vblank sync: wglSwapIntervalEXT "
-			  "vblank setup failed");
-	}
-    }
-  else
-    CLUTTER_NOTE (BACKEND, "no use-able vblank mechanism found");
-
-  CLUTTER_NOTE (BACKEND, "backend features checked");
+  ClutterBackendClass *parent_class;
+  ClutterFeatureFlags flags;
 
-  return flags;
-}
+  parent_class = CLUTTER_BACKEND_CLASS (clutter_backend_win32_parent_class);
 
-static ATOM
-clutter_backend_win32_get_dummy_window_class ()
-{
-  static ATOM klass = 0;
+  flags = CLUTTER_FEATURE_STAGE_USER_RESIZE | CLUTTER_FEATURE_STAGE_CURSOR;
 
-  if (klass == 0)
+  if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN))
     {
-      WNDCLASSW wndclass;
-      memset (&wndclass, 0, sizeof (wndclass));
-      wndclass.lpfnWndProc = DefWindowProc;
-      wndclass.hInstance = GetModuleHandleW (NULL);
-      wndclass.lpszClassName = L"ClutterBackendWin32DummyWindow";
-      klass = RegisterClassW (&wndclass);
+      CLUTTER_NOTE (BACKEND, "Cogl supports multiple onscreen framebuffers");
+      flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
     }
-
-  return klass;
-}
-
-static gboolean
-clutter_backend_win32_pixel_format_is_better (const PIXELFORMATDESCRIPTOR *pfa,
-                                              const PIXELFORMATDESCRIPTOR *pfb)
-{
-  /* Always prefer a format with a stencil buffer */
-  if (pfa->cStencilBits == 0)
+  else
     {
-      if (pfb->cStencilBits > 0)
-        return TRUE;
+      CLUTTER_NOTE (BACKEND, "Cogl only supports one onscreen framebuffer");
+      flags |= CLUTTER_FEATURE_STAGE_STATIC;
     }
-  else if (pfb->cStencilBits == 0)
-    return FALSE;
 
-  /* Prefer a bigger color buffer */
-  if (pfb->cColorBits > pfa->cColorBits)
-    return TRUE;
-  else if (pfb->cColorBits < pfa->cColorBits)
-    return FALSE;
-
-  /* Prefer a bigger depth buffer */
-  return pfb->cDepthBits > pfa->cDepthBits;
-}
-
-static int
-clutter_backend_win32_choose_pixel_format (HDC dc, PIXELFORMATDESCRIPTOR *pfd)
-{
-  int i, num_formats, best_pf = 0;
-  PIXELFORMATDESCRIPTOR best_pfd;
-
-  num_formats = DescribePixelFormat (dc, 0, sizeof (best_pfd), NULL);
-
-  for (i = 1; i <= num_formats; i++)
+  if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_THROTTLE))
     {
-      memset (pfd, 0, sizeof (*pfd));
-
-      if (DescribePixelFormat (dc, i, sizeof (best_pfd), pfd)
-          /* Check whether this format is useable by Clutter */
-          && ((pfd->dwFlags & (PFD_SUPPORT_OPENGL
-                               | PFD_DRAW_TO_WINDOW
-                               | PFD_DOUBLEBUFFER
-                               | PFD_GENERIC_FORMAT))
-              == (PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW))
-          && pfd->iPixelType == PFD_TYPE_RGBA
-          && pfd->cColorBits >= 16 && pfd->cColorBits <= 32
-          && pfd->cDepthBits >= 16 && pfd->cDepthBits <= 32
-          /* Check whether this is a better format than one we've
-             already found */
-          && (best_pf == 0
-              || clutter_backend_win32_pixel_format_is_better (&best_pfd, pfd)))
-        {
-          best_pf = i;
-          best_pfd = *pfd;
-        }
+      CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers throttling");
+      flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
     }
+  else
+    CLUTTER_NOTE (BACKEND, "Cogl doesn't support swap buffers throttling");
 
-  *pfd = best_pfd;
+  CLUTTER_NOTE (BACKEND, "backend features checked");
 
-  return best_pf;
+  return flags;
 }
 
 static gboolean
 clutter_backend_win32_create_context (ClutterBackend  *backend,
                                       GError         **error)
 {
-  ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
+  CoglSwapChain *swap_chain;
+  CoglOnscreenTemplate *onscreen_template;
 
-  /* COGL assumes that there is always a GL context selected; in order
-   * to make sure that a WGL context exists and is made current, we
-   * use a small dummy window that never gets shown to which we can
-   * always fall back if no stage is available
-   */
-  if (backend_win32->dummy_hwnd == NULL)
-    {
-      ATOM window_class = clutter_backend_win32_get_dummy_window_class ();
-
-      if (window_class == 0)
-        {
-          g_critical ("Unable to register window class");
-          return FALSE;
-        }
-
-      backend_win32->dummy_hwnd =
-        CreateWindowW ((LPWSTR) MAKEINTATOM (window_class),
-                       L".",
-                       WS_OVERLAPPEDWINDOW,
-                       CW_USEDEFAULT,
-                       CW_USEDEFAULT,
-                       1, 1,
-                       NULL, NULL,
-                       GetModuleHandle (NULL),
-                       NULL);
-
-      if (backend_win32->dummy_hwnd == NULL)
-        {
-          g_critical ("Unable to create dummy window");
-          return FALSE;
-        }
-    }
+  if (backend->cogl_context)
+    return TRUE;
 
-  if (backend_win32->dummy_dc == NULL)
-    {
-      PIXELFORMATDESCRIPTOR pfd;
-      int pf;
+  backend->cogl_renderer = cogl_renderer_new ();
+  if (!cogl_renderer_connect (backend->cogl_renderer, error))
+    goto error;
 
-      backend_win32->dummy_dc = GetDC (backend_win32->dummy_hwnd);
+  swap_chain = cogl_swap_chain_new ();
 
-      pf = clutter_backend_win32_choose_pixel_format (backend_win32->dummy_dc,
-                                                      &pfd);
+  onscreen_template = cogl_onscreen_template_new (swap_chain);
+  cogl_object_unref (swap_chain);
 
-      if (pf == 0 || !SetPixelFormat (backend_win32->dummy_dc, pf, &pfd))
-        {
-          g_critical ("Unable to find suitable GL pixel format");
-          ReleaseDC (backend_win32->dummy_hwnd, backend_win32->dummy_dc);
-          backend_win32->dummy_dc = NULL;
-          return FALSE;
-        }
-    }
+  if (!cogl_renderer_check_onscreen_template (backend->cogl_renderer,
+                                              onscreen_template,
+                                              error))
+    goto error;
 
-  if (backend_win32->gl_context == NULL)
-    {
-      backend_win32->gl_context = wglCreateContext (backend_win32->dummy_dc);
+  backend->cogl_display = cogl_display_new (backend->cogl_renderer,
+                                            onscreen_template);
+  cogl_object_unref (backend->cogl_renderer);
+  cogl_object_unref (onscreen_template);
 
-      if (backend_win32->gl_context == NULL)
-        {
-          g_critical ("Unable to create suitable GL context");
-          return FALSE;
-        }
-    }
+  if (!cogl_display_setup (backend->cogl_display, error))
+    goto error;
 
-  CLUTTER_NOTE (BACKEND, "Selecting dummy 0x%x for the WGL context",
-                (unsigned int) backend_win32->dummy_hwnd);
+  backend->cogl_context = cogl_context_new (backend->cogl_display, error);
+  if (!backend->cogl_context)
+    goto error;
 
-  wglMakeCurrent (backend_win32->dummy_dc, backend_win32->gl_context);
+  /* XXX: eventually this should go away but a lot of Cogl code still
+   * depends on a global default context. */
+  cogl_set_default_context (backend->cogl_context);
 
   return TRUE;
+
+error:
+  if (backend->cogl_display)
+    {
+      cogl_object_unref (backend->cogl_display);
+      backend->cogl_display = NULL;
+    }
+
+  if (onscreen_template)
+    cogl_object_unref (onscreen_template);
+  if (swap_chain)
+    cogl_object_unref (swap_chain);
+
+  if (backend->cogl_renderer)
+    {
+      cogl_object_unref (backend->cogl_renderer);
+      backend->cogl_renderer = NULL;
+    }
+  return FALSE;
 }
 
 static void
 clutter_backend_win32_ensure_context (ClutterBackend *backend, 
 				      ClutterStage   *stage)
 {
-  ClutterStageWindow  *impl;
-
-  if (stage == NULL ||
-      CLUTTER_ACTOR_IN_DESTRUCTION (stage) ||
-      ((impl = _clutter_stage_get_window (stage)) == NULL))
-    {
-      CLUTTER_NOTE (MULTISTAGE, "Clearing all context");
+  ClutterStageWin32 *stage_win32 =
+    CLUTTER_STAGE_WIN32 (_clutter_stage_get_window (stage));
 
-      wglMakeCurrent (NULL, NULL);
-    }
-  else
-    {
-      ClutterBackendWin32 *backend_win32;
-      ClutterStageWin32   *stage_win32;
-
-      g_return_if_fail (impl != NULL);
-      
-      CLUTTER_NOTE (MULTISTAGE, "Setting context for stage of type %s [%p]",
-		    g_type_name (G_OBJECT_TYPE (impl)),
-		    impl);
-
-      backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
-      stage_win32 = CLUTTER_STAGE_WIN32 (impl);
-      
-      /* no GL context to set */
-      if (backend_win32->gl_context == NULL)
-        return;
-
-      /* we might get here inside the final dispose cycle, so we
-       * need to handle this gracefully
-       */
-      if (stage_win32->client_dc == NULL)
-        {
-          CLUTTER_NOTE (MULTISTAGE,
-                        "Received a stale stage, clearing all context");
-
-          if (backend_win32->dummy_dc != NULL)
-            wglMakeCurrent (backend_win32->dummy_dc,
-                            backend_win32->gl_context);
-          else
-            wglMakeCurrent (NULL, NULL);
-        }
-      else
-        {
-          CLUTTER_NOTE (BACKEND,
-			"MakeCurrent window %p (%s), context %p",
-			stage_win32->hwnd,
-			stage_win32->is_foreign_win ? "foreign" : "native",
-			backend_win32->gl_context);
-          wglMakeCurrent (stage_win32->client_dc,
-			  backend_win32->gl_context);
-        }
-    }
+  cogl_set_framebuffer (COGL_FRAMEBUFFER (stage_win32->onscreen));
 }
 
 static ClutterStageWindow *
@@ -558,7 +369,6 @@ clutter_backend_win32_class_init (ClutterBackendWin32Class *klass)
 static void
 clutter_backend_win32_init (ClutterBackendWin32 *backend_win32)
 {
-  backend_win32->gl_context         = NULL;
   backend_win32->invisible_cursor   = NULL;
 
   /* FIXME: get from GetSystemMetric?
diff --git a/clutter/win32/clutter-backend-win32.h b/clutter/win32/clutter-backend-win32.h
index 0bcaa8f..bfa74f7 100644
--- a/clutter/win32/clutter-backend-win32.h
+++ b/clutter/win32/clutter-backend-win32.h
@@ -46,10 +46,6 @@ struct _ClutterBackendWin32
 {
   ClutterBackend parent_instance;
 
-  HGLRC          gl_context;
-  HWND           dummy_hwnd;
-  HDC            dummy_dc;
-
   HCURSOR        invisible_cursor;
 
   GSource       *event_source;
@@ -76,6 +72,8 @@ clutter_backend_win32_get_features (ClutterBackend *backend);
 
 HCURSOR _clutter_backend_win32_get_invisible_cursor (ClutterBackend *backend);
 
+G_CONST_RETURN gchar *_clutter_backend_win32_get_vblank (void);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_BACKEND_WIN32_H__ */
diff --git a/clutter/win32/clutter-event-win32.c b/clutter/win32/clutter-event-win32.c
index b97a6ab..517ef14 100644
--- a/clutter/win32/clutter-event-win32.c
+++ b/clutter/win32/clutter-event-win32.c
@@ -348,6 +348,7 @@ get_key_modifier_state (const BYTE *key_states)
 gboolean
 clutter_win32_handle_event (const MSG *msg)
 {
+  ClutterBackend       *backend;
   ClutterBackendWin32  *backend_win32;
   ClutterStageWin32    *stage_win32;
   ClutterDeviceManager *manager;
@@ -365,6 +366,13 @@ clutter_win32_handle_event (const MSG *msg)
   impl = _clutter_stage_get_window (stage);
   stage_win32 = CLUTTER_STAGE_WIN32 (impl);
   backend_win32 = stage_win32->backend;
+  backend = CLUTTER_BACKEND (backend_win32);
+
+  /* Give Cogl a chance to handle the message first */
+  if (backend->cogl_renderer != NULL &&
+      cogl_renderer_handle_native_event (backend->cogl_renderer,
+                                         (void *) msg) == COGL_FILTER_REMOVE)
+    return TRUE;
 
   manager = clutter_device_manager_get_default ();
   core_pointer =
diff --git a/clutter/win32/clutter-stage-win32.c b/clutter/win32/clutter-stage-win32.c
index 8eb3567..0cdeae9 100644
--- a/clutter/win32/clutter-stage-win32.c
+++ b/clutter/win32/clutter-stage-win32.c
@@ -392,14 +392,24 @@ static gboolean
 clutter_stage_win32_realize (ClutterStageWindow *stage_window)
 {
   ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
+  ClutterBackend *backend;
   ClutterBackendWin32 *backend_win32;
-  PIXELFORMATDESCRIPTOR pfd;
-  int pf;
+  CoglFramebuffer *framebuffer;
+  gfloat width;
+  gfloat height;
   GError *error = NULL;
+  const char *clutter_vblank;
 
   CLUTTER_NOTE (MISC, "Realizing main stage");
 
-  backend_win32 = CLUTTER_BACKEND_WIN32 (clutter_get_default_backend ());
+  backend = CLUTTER_BACKEND (stage_win32->backend);
+  backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
+
+  clutter_actor_get_size (CLUTTER_ACTOR (stage_win32->wrapper),
+                          &width, &height);
+
+  stage_win32->onscreen = cogl_onscreen_new (backend->cogl_context,
+                                             width, height);
 
   if (stage_win32->hwnd == NULL)
     {
@@ -457,26 +467,29 @@ clutter_stage_win32_realize (ClutterStageWindow *stage_window)
       SetWindowLongPtrW (stage_win32->hwnd, 0, (LONG_PTR) stage_win32);
     }
 
-  if (stage_win32->client_dc)
-    ReleaseDC (stage_win32->hwnd, stage_win32->client_dc);
+  cogl_onscreen_win32_set_foreign_window (stage_win32->onscreen,
+                                          stage_win32->hwnd);
 
-  stage_win32->client_dc = GetDC (stage_win32->hwnd);
+  clutter_vblank = _clutter_backend_win32_get_vblank ();
+  if (clutter_vblank && strcmp (clutter_vblank, "none") == 0)
+    cogl_onscreen_set_swap_throttled (stage_win32->onscreen, FALSE);
 
-  /* Create a context. This will be a no-op if we already have one */
-  if (!_clutter_backend_create_context (CLUTTER_BACKEND (backend_win32),
-                                        &error))
+  framebuffer = COGL_FRAMEBUFFER (stage_win32->onscreen);
+  if (!cogl_framebuffer_allocate (framebuffer, &error))
     {
-      g_critical ("Unable to realize stage: %s", error->message);
+      g_warning ("Failed to allocate stage: %s", error->message);
       g_error_free (error);
+      cogl_object_unref (stage_win32->onscreen);
+      stage_win32->onscreen = NULL;
       goto fail;
     }
 
-  /* Use the same pixel format as the dummy DC */
-  pf = GetPixelFormat (backend_win32->dummy_dc);
-  DescribePixelFormat (backend_win32->dummy_dc, pf, sizeof (pfd), &pfd);
-  if (!SetPixelFormat (stage_win32->client_dc, pf, &pfd))
+  /* Create a context. This will be a no-op if we already have one */
+  if (!_clutter_backend_create_context (CLUTTER_BACKEND (backend_win32),
+                                        &error))
     {
-      g_critical ("Unable to find suitable GL pixel format");
+      g_critical ("Unable to realize stage: %s", error->message);
+      g_error_free (error);
       goto fail;
     }
 
@@ -491,12 +504,6 @@ clutter_stage_win32_realize (ClutterStageWindow *stage_window)
 static void
 clutter_stage_win32_unprepare_window (ClutterStageWin32 *stage_win32)
 {
-  if (stage_win32->client_dc)
-    {
-      ReleaseDC (stage_win32->hwnd, stage_win32->client_dc);
-      stage_win32->client_dc = NULL;
-    }
-
   if (!stage_win32->is_foreign_win && stage_win32->hwnd)
     {
       /* Drop the pointer to this stage in the window so that any
@@ -527,8 +534,8 @@ clutter_stage_win32_redraw (ClutterStageWindow *stage_window)
   _clutter_stage_do_paint (stage_win32->wrapper, NULL);
   cogl_flush ();
 
-  if (stage_win32->client_dc)
-    SwapBuffers (stage_win32->client_dc);
+  if (stage_win32->onscreen)
+    cogl_framebuffer_swap_buffers (COGL_FRAMEBUFFER (stage_win32->onscreen));
 }
 
 static void
@@ -543,7 +550,10 @@ clutter_stage_win32_dispose (GObject *gobject)
     clutter_stage_win32_unprepare_window (stage_win32);
 
   if (stage_win32->wtitle)
-    g_free (stage_win32->wtitle);
+    {
+      g_free (stage_win32->wtitle);
+      stage_win32->wtitle = NULL;
+    }
 
   G_OBJECT_CLASS (clutter_stage_win32_parent_class)->dispose (gobject);
 }
@@ -560,7 +570,6 @@ static void
 clutter_stage_win32_init (ClutterStageWin32 *stage)
 {
   stage->hwnd = NULL;
-  stage->client_dc = NULL;
   stage->win_width = 640;
   stage->win_height = 480;
   stage->backend = NULL;
diff --git a/clutter/win32/clutter-stage-win32.h b/clutter/win32/clutter-stage-win32.h
index ac330f8..2418936 100644
--- a/clutter/win32/clutter-stage-win32.h
+++ b/clutter/win32/clutter-stage-win32.h
@@ -44,8 +44,9 @@ struct _ClutterStageWin32
 {
   ClutterGroup parent_instance;
 
+  CoglOnscreen *onscreen;
+
   HWND         hwnd;
-  HDC          client_dc;
   gint         win_width;
   gint         win_height;
   gint         scroll_pos;
diff --git a/configure.ac b/configure.ac
index 8184696..91be97d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -428,6 +428,8 @@ AS_CASE([$CLUTTER_FLAVOUR],
           AC_DEFINE([COGL_HAS_WIN32_SUPPORT], [1], [Cogl supports the win32 window system])
           AC_DEFINE([COGL_HAS_WGL_SUPPORT], [1], [Cogl supports OpenGL using the WGL API])
 
+          AC_DEFINE([COGL_HAS_FULL_WINSYS], [1], [Cogl can create its own OpenGL context])
+
           COGL_DRIVER="gl"
           AC_DEFINE([HAVE_COGL_GL], [1], [Have GL for rendering])
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]