Upgraded the Win32 backend to work with the multi-stage
authorNeil Roberts <neil@openedhand.com>
Sun, 13 Apr 2008 08:43:32 +0000 (08:43 +0000)
committerNeil Roberts <neil@openedhand.com>
Sun, 13 Apr 2008 08:43:32 +0000 (08:43 +0000)
subclassing code.

* clutter/win32/clutter-stage-win32.h:
* clutter/win32/clutter-stage-win32.c: Now inherits from
ClutterGroup and implements ClutterStageWindow instead of
inheriting directly from ClutterStage.

* clutter/win32/clutter-event-win32.c (message_translate): Now
takes an extra parameter to return whether DefWindowProc should be
called. This is needed to prevent the default WM_CLOSE handler
from destroying the window.

* clutter/win32/clutter-backend-win32.c
(clutter_backend_win32_dispose): Destroy all of the stages using
g_slist_foreach as per bug #871. Now also destroys the GL context.
(clutter_backend_win32_get_features): Added assertions to ensure
there is a valid GL context.
(clutter_backend_win32_ensure_context): Accepts NULL stage. Gets
implementation pointer from the stage.

ChangeLog
clutter/win32/clutter-backend-win32.c
clutter/win32/clutter-event-win32.c
clutter/win32/clutter-stage-win32.c
clutter/win32/clutter-stage-win32.h

index 1b3819d..a308dd3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2008-04-13  Neil Roberts  <neil@o-hand.com>
+
+       Upgraded the Win32 backend to work with the multi-stage
+       subclassing code.
+
+       * clutter/win32/clutter-stage-win32.h: 
+       * clutter/win32/clutter-stage-win32.c: Now inherits from
+       ClutterGroup and implements ClutterStageWindow instead of
+       inheriting directly from ClutterStage.
+
+       * clutter/win32/clutter-event-win32.c (message_translate): Now
+       takes an extra parameter to return whether DefWindowProc should be
+       called. This is needed to prevent the default WM_CLOSE handler
+       from destroying the window.
+
+       * clutter/win32/clutter-backend-win32.c
+       (clutter_backend_win32_dispose): Destroy all of the stages using
+       g_slist_foreach as per bug #871. Now also destroys the GL context.
+       (clutter_backend_win32_get_features): Added assertions to ensure
+       there is a valid GL context.
+       (clutter_backend_win32_ensure_context): Accepts NULL stage. Gets
+       implementation pointer from the stage.
+
 2008-04-11  Emmanuele Bassi  <ebassi@openedhand.com>
 
        * clutter/clutter-container.c:
index 3de069f..22a81ab 100644 (file)
@@ -33,6 +33,7 @@
 #include "../clutter-main.h"
 #include "../clutter-debug.h"
 #include "../clutter-private.h"
+#include "../clutter-version.h"
 
 #include "cogl.h"
 
@@ -100,22 +101,27 @@ clutter_backend_win32_dispose (GObject *gobject)
   ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (gobject);
   ClutterMainContext  *context;
   ClutterStageManager *stage_manager;
-  GSList              *l;
 
   CLUTTER_NOTE (BACKEND, "Disposing the of stages");
 
   context = clutter_context_get_default ();
   stage_manager = context->stage_manager;
 
-  for (l = stage_manager->stages; l; l = l->next)
-    {
-      ClutterActor *stage = CLUTTER_ACTOR (l->data);
-      clutter_actor_destroy (stage);
-    }
+  /* Destroy all of the stages. g_slist_foreach is used because the
+     finalizer for the stages will remove the stage from the
+     stage_manager's list and g_slist_foreach has some basic
+     protection against this */
+  g_slist_foreach (stage_manager->stages, (GFunc) clutter_actor_destroy, NULL);
 
   CLUTTER_NOTE (BACKEND, "Removing the event source");
   _clutter_backend_win32_events_uninit (CLUTTER_BACKEND (backend_win32));
 
+  if (backend_win32->gl_context)
+    {
+      wglDeleteContext (backend_win32->gl_context);
+      backend_win32->gl_context = NULL;
+    }
+
   G_OBJECT_CLASS (clutter_backend_win32_parent_class)->dispose (gobject);
 }
 
@@ -152,14 +158,21 @@ check_vblank_env (const char *name)
 ClutterFeatureFlags
 clutter_backend_win32_get_features (ClutterBackend *backend)
 {
-  ClutterFeatureFlags flags;
-  const gchar *extensions;
-  SwapIntervalProc swap_interval;
+  ClutterFeatureFlags  flags;
+  const gchar         *extensions;
+  SwapIntervalProc     swap_interval;
+  ClutterBackendWin32 *backend_win32;
 
   /* FIXME: we really need to check if gl context is set */
 
   extensions = glGetString (GL_EXTENSIONS);
 
+  /* 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);
+
   CLUTTER_NOTE (BACKEND, "Checking features\n"
                 "GL_VENDOR: %s\n"
                 "GL_RENDERER: %s\n"
@@ -217,24 +230,70 @@ static void
 clutter_backend_win32_ensure_context (ClutterBackend *backend, 
                                      ClutterStage   *stage)
 {
-  ClutterBackendWin32 *backend_win32;
-  ClutterStageWin32   *stage_win32;
-
-  stage_win32 = CLUTTER_STAGE_WIN32 (stage);
-  backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
-
-  CLUTTER_NOTE (MULTISTAGE, "setting context for stage:%p", stage );
+  if (stage == NULL)
+    {
+      CLUTTER_NOTE (MULTISTAGE, "Clearing all context");
 
-  wglMakeCurrent (stage_win32->client_dc,
-                  backend_win32->gl_context);
+      wglMakeCurrent (NULL, NULL);
+    }
+  else
+    {
+      ClutterBackendWin32 *backend_win32;
+      ClutterStageWin32   *stage_win32;
+      ClutterStageWindow  *impl;
+
+      impl = _clutter_stage_get_window (stage);
+      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");
+        
+         wglMakeCurrent (NULL, NULL);
+       }
+      else
+       {
+         CLUTTER_NOTE (BACKEND,
+                       "MakeCurrent window %p, context %p",
+                       stage_win32->hwnd,
+                       backend_win32->gl_context);
+         wglMakeCurrent (stage_win32->client_dc,
+                         backend_win32->gl_context);
+       }
+    }
 }
 
 static void
 clutter_backend_win32_redraw (ClutterBackend *backend,
                              ClutterStage   *stage)
 {
-  ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage);
+  ClutterStageWin32  *stage_win32;
+  ClutterStageWindow *impl;
+
+  impl = _clutter_stage_get_window (stage);
+  if (impl == NULL)
+    return;
+
+  g_return_if_fail (CLUTTER_IS_STAGE_WIN32 (impl));
 
+  stage_win32 = CLUTTER_STAGE_WIN32 (impl);
+
+  /* this will cause the stage implementation to be painted */
   clutter_actor_paint (CLUTTER_ACTOR (stage));
 
   if (stage_win32->client_dc)
@@ -243,21 +302,33 @@ clutter_backend_win32_redraw (ClutterBackend *backend,
 
 static ClutterActor *
 clutter_backend_win32_create_stage (ClutterBackend  *backend,
+                                   ClutterStage    *wrapper,
                                    GError         **error)
 {
   ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
   ClutterStageWin32 *stage_win32;
   ClutterActor *stage;
 
-  stage = g_object_new (CLUTTER_TYPE_STAGE_WIN32, NULL);
+  CLUTTER_NOTE (BACKEND, "Creating stage of type `%s'",
+               g_type_name (CLUTTER_STAGE_TYPE));
+
+  stage = g_object_new (CLUTTER_STAGE_TYPE, NULL);
 
   /* copy backend data into the stage */
   stage_win32 = CLUTTER_STAGE_WIN32 (stage);
   stage_win32->backend = backend_win32;
+  stage_win32->wrapper = wrapper;
+
+  /* set the pointer back into the wrapper */
+  _clutter_stage_set_window (wrapper, CLUTTER_STAGE_WINDOW (stage));
 
   /* needed ? */
   g_object_set_data (G_OBJECT (stage), "clutter-backend", backend);
 
+  /* FIXME - is this needed? we should call realize inside the clutter
+   * init sequence for the default stage, and let the usual realization
+   * sequence be used for any other stage
+   */
   clutter_actor_realize (stage);
 
   if (!CLUTTER_ACTOR_IS_REALIZED (stage))
index df30286..9a46a54 100644 (file)
@@ -301,11 +301,13 @@ get_key_modifier_state (const BYTE *key_states)
 static gboolean
 message_translate (ClutterBackend *backend,
                   ClutterEvent   *event,
-                  const MSG      *msg)
+                  const MSG      *msg,
+                  gboolean       *call_def_window_proc)
 {
   ClutterBackendWin32 *backend_win32;
   ClutterStageWin32   *stage_win32;
   ClutterStage        *stage;
+  ClutterStageWindow  *impl;
   gboolean            res;
 
   backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
@@ -315,7 +317,8 @@ message_translate (ClutterBackend *backend,
 
   if (stage == NULL)
     return FALSE;
-  stage_win32 = CLUTTER_STAGE_WIN32 (stage);
+  impl        = _clutter_stage_get_window (stage);
+  stage_win32 = CLUTTER_STAGE_WIN32 (impl);
 
   event->any.stage = stage;
 
@@ -404,6 +407,16 @@ message_translate (ClutterBackend *backend,
       event->type = CLUTTER_DESTROY_NOTIFY;
       break;
 
+    case WM_CLOSE:
+      CLUTTER_NOTE (EVENT, "WM_CLOSE");
+      event->type = CLUTTER_DELETE;
+      /* The default window proc will destroy the window so we want to
+        prevent this to allow applications to optionally destroy the
+        window themselves */
+      if (call_def_window_proc)
+       *call_def_window_proc = FALSE;
+      break;
+
     case WM_LBUTTONDOWN:
       make_button_event (msg, event, 1, 1, FALSE);
       break;
@@ -552,6 +565,15 @@ message_translate (ClutterBackend *backend,
       }
       break;
 
+    case WM_GETMINMAXINFO:
+      {
+       MINMAXINFO *min_max_info = (MINMAXINFO *) msg->lParam;
+       _clutter_stage_win32_get_min_max_info (stage_win32, min_max_info);
+       if (call_def_window_proc)
+         *call_def_window_proc = FALSE;
+      }
+      break;
+
     default:
       /* ignore every other message */
       res = FALSE;
@@ -567,6 +589,7 @@ _clutter_stage_win32_window_proc (HWND hwnd, UINT umsg,
 {
   ClutterStageWin32 *stage_win32
     = (ClutterStageWin32 *) GetWindowLongPtrW (hwnd, 0);
+  gboolean call_def_window_proc = TRUE;
 
   /* Ignore any messages before SetWindowLongPtr has been called to
      set the stage */
@@ -590,25 +613,18 @@ _clutter_stage_win32_window_proc (HWND hwnd, UINT umsg,
       msg.pt.x = (SHORT) LOWORD (message_pos);
       msg.pt.y = (SHORT) HIWORD (message_pos);
 
-      /* Some messages are handled here specially outside of
-        message_translate so that DefWindowProc can be overridden */
-      if (umsg == WM_GETMINMAXINFO)
-       {
-         MINMAXINFO *min_max_info = (MINMAXINFO *) lparam;
-         _clutter_stage_win32_get_min_max_info (stage_win32, min_max_info);
-         return 0;
-       }
-      else
-       {
-         event = clutter_event_new (CLUTTER_NOTHING);
+      event = clutter_event_new (CLUTTER_NOTHING);
          
-         if (message_translate (CLUTTER_BACKEND (backend_win32), event, &msg))
-           /* push directly here to avoid copy of queue_put */
-           g_queue_push_head (clutter_context->events_queue, event);
-         else
-           clutter_event_free (event);
-       }
+      if (message_translate (CLUTTER_BACKEND (backend_win32), event,
+                            &msg, &call_def_window_proc))
+       /* push directly here to avoid copy of queue_put */
+       g_queue_push_head (clutter_context->events_queue, event);
+      else
+       clutter_event_free (event);
     }
 
-  return DefWindowProcW (hwnd, umsg, wparam, lparam);
+  if (call_def_window_proc)
+    return DefWindowProcW (hwnd, umsg, wparam, lparam);
+  else
+    return 0;
 }
index 171776a..54c8cef 100644 (file)
@@ -27,6 +27,7 @@
 #include "clutter-stage-win32.h"
 #include "clutter-win32.h"
 
+#include "../clutter-stage-window.h"
 #include "../clutter-main.h"
 #include "../clutter-feature.h"
 #include "../clutter-color.h"
 #include "../clutter-private.h"
 #include "../clutter-debug.h"
 #include "../clutter-units.h"
+#include "../clutter-shader.h"
 #include "../clutter-stage.h"
 
 #include "cogl.h"
 
 #include <windows.h>
 
-G_DEFINE_TYPE (ClutterStageWin32, clutter_stage_win32, CLUTTER_TYPE_STAGE);
+static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
+        
+G_DEFINE_TYPE_WITH_CODE (ClutterStageWin32,
+                        clutter_stage_win32,
+                        CLUTTER_TYPE_GROUP,
+                        G_IMPLEMENT_INTERFACE
+                        (CLUTTER_TYPE_STAGE_WINDOW,
+                         clutter_stage_window_iface_init));
 
 static void
 clutter_stage_win32_show (ClutterActor *actor)
@@ -122,7 +131,7 @@ get_full_window_pos (ClutterStageWin32 *stage_win32,
                     int *xpos_out, int *ypos_out)
 {
   gboolean resizable
-    = clutter_stage_get_user_resizable (CLUTTER_STAGE (stage_win32));
+    = clutter_stage_get_user_resizable (stage_win32->wrapper);
   /* The window position passed to CreateWindow includes the window
      decorations */
   *xpos_out = xpos_in - GetSystemMetrics (resizable ? SM_CXSIZEFRAME
@@ -138,7 +147,7 @@ get_full_window_size (ClutterStageWin32 *stage_win32,
                      int *width_out, int *height_out)
 {
   gboolean resizable
-    = clutter_stage_get_user_resizable (CLUTTER_STAGE (stage_win32));
+    = clutter_stage_get_user_resizable (stage_win32->wrapper);
   /* The window size passed to CreateWindow includes the window
      decorations */
   *width_out = width_in + GetSystemMetrics (resizable ? SM_CXSIZEFRAME
@@ -154,7 +163,7 @@ _clutter_stage_win32_get_min_max_info (ClutterStageWin32 *stage_win32,
 {
   /* If the window isn't resizable then set the max and min size to
      the current size */
-  if (!clutter_stage_get_user_resizable (CLUTTER_STAGE (stage_win32)))
+  if (!clutter_stage_get_user_resizable (CLUTTER_STAGE (stage_win32->wrapper)))
     {
       int full_width, full_height;
       get_full_window_size (stage_win32,
@@ -214,7 +223,8 @@ clutter_stage_win32_request_coords (ClutterActor        *self,
                        change_flags);
        }
 
-      CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_SYNC_MATRICES);
+      CLUTTER_SET_PRIVATE_FLAGS (stage_win32->wrapper,
+                                CLUTTER_ACTOR_SYNC_MATRICES);
     }
 
   CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class)
@@ -222,10 +232,10 @@ clutter_stage_win32_request_coords (ClutterActor        *self,
 }
 
 static void
-clutter_stage_win32_set_title (ClutterStage *stage,
-                              const gchar  *title)
+clutter_stage_win32_set_title (ClutterStageWindow *stage_window,
+                              const gchar        *title)
 {
-  ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage);
+  ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
   wchar_t *wtitle;
 
   /* Empty window titles not allowed, so set it to just a period. */
@@ -240,36 +250,44 @@ clutter_stage_win32_set_title (ClutterStage *stage,
 static LONG
 get_window_style (ClutterStageWin32 *stage_win32)
 {
+  ClutterStage *wrapper = stage_win32->wrapper;
+
   /* Fullscreen mode shouldn't have any borders */
   if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN))
     return WS_POPUP;
   /* Otherwise it's an overlapped window but if it isn't resizable
      then it shouldn't have a thick frame */
-  else if (clutter_stage_get_user_resizable (CLUTTER_STAGE (stage_win32)))
+  else if (clutter_stage_get_user_resizable (wrapper))
     return WS_OVERLAPPEDWINDOW;
   else
     return WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME;
 }
 
 static void
-clutter_stage_win32_set_user_resize (ClutterStage *stage,
-                                    gboolean      value)
+clutter_stage_win32_set_user_resize (ClutterStageWindow *stage_window,
+                                    gboolean            value)
 {
-  HWND hwnd = CLUTTER_STAGE_WIN32 (stage)->hwnd;
+  HWND hwnd = CLUTTER_STAGE_WIN32 (stage_window)->hwnd;
   LONG old_style = GetWindowLongW (hwnd, GWL_STYLE);
 
   /* Update the window style but preserve the visibility */
   SetWindowLongW (hwnd, GWL_STYLE,
-                 get_window_style (CLUTTER_STAGE_WIN32 (stage))
+                 get_window_style (CLUTTER_STAGE_WIN32 (stage_window))
                  | (old_style & WS_VISIBLE));
 }
 
+static ClutterActor *
+clutter_stage_win32_get_wrapper (ClutterStageWindow *stage_window)
+{
+  return CLUTTER_ACTOR (CLUTTER_STAGE_WIN32 (stage_window)->wrapper);
+}
+
 static void
-clutter_stage_win32_set_fullscreen (ClutterStage *stage,
-                                   gboolean      value)
+clutter_stage_win32_set_fullscreen (ClutterStageWindow *stage_window,
+                                   gboolean            value)
 {
-  ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage);
-  HWND hwnd = CLUTTER_STAGE_WIN32 (stage)->hwnd;
+  ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
+  HWND hwnd = CLUTTER_STAGE_WIN32 (stage_window)->hwnd;
   LONG old_style = GetWindowLongW (hwnd, GWL_STYLE);
   ClutterStageStateEvent event;
 
@@ -316,13 +334,14 @@ clutter_stage_win32_set_fullscreen (ClutterStage *stage,
                        SWP_NOZORDER);
        }
 
-      CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
+      CLUTTER_SET_PRIVATE_FLAGS (stage_win32->wrapper,
+                                CLUTTER_ACTOR_SYNC_MATRICES);
     }
 
   /* Report the state change */
   memset (&event, 0, sizeof (event));
   event.type = CLUTTER_STAGE_STATE;
-  event.stage = CLUTTER_STAGE (stage_win32);
+  event.stage = CLUTTER_STAGE (stage_win32->wrapper);
   event.new_state = stage_win32->state;
   event.changed_mask = CLUTTER_STAGE_STATE_FULLSCREEN;
   clutter_event_put ((ClutterEvent *) &event);
@@ -407,6 +426,8 @@ clutter_stage_win32_realize (ClutterActor *actor)
       if (window_class == 0)
        {
           g_critical ("Unable to register window class");
+         CLUTTER_ACTOR_UNSET_FLAGS (stage_win32->wrapper,
+                                    CLUTTER_ACTOR_REALIZED);
           CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
           return;
        }
@@ -449,6 +470,8 @@ clutter_stage_win32_realize (ClutterActor *actor)
       if (stage_win32->hwnd == NULL)
        {
          g_critical ("Unable to create stage window");
+         CLUTTER_ACTOR_UNSET_FLAGS (stage_win32->wrapper,
+                                    CLUTTER_ACTOR_REALIZED);
          CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
          return;
        }
@@ -490,6 +513,8 @@ clutter_stage_win32_realize (ClutterActor *actor)
       || !SetPixelFormat (stage_win32->client_dc, pf, &pfd))
     {
       g_critical ("Unable to find suitable GL pixel format");
+      CLUTTER_ACTOR_UNSET_FLAGS (stage_win32->wrapper,
+                                CLUTTER_ACTOR_REALIZED);
       CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
       return;
     }
@@ -501,24 +526,30 @@ clutter_stage_win32_realize (ClutterActor *actor)
       if (backend_win32->gl_context == NULL)
        {
          g_critical ("Unable to create suitable GL context");
+         CLUTTER_ACTOR_UNSET_FLAGS (stage_win32->wrapper,
+                                    CLUTTER_ACTOR_REALIZED);
          CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
          return;
        }
     }
 
-  CLUTTER_NOTE (GL, "wglMakeCurrent");
-
-  clutter_stage_ensure_current (CLUTTER_STAGE (stage_win32));
+  /* below will call wglMakeCurrent */
+  CLUTTER_ACTOR_SET_FLAGS (stage_win32->wrapper, CLUTTER_ACTOR_REALIZED);
+  CLUTTER_ACTOR_SET_FLAGS (stage_win32, CLUTTER_ACTOR_REALIZED);
+  clutter_stage_ensure_current (stage_win32->wrapper);
 
   if (!clutter_stage_win32_check_gl_version ())
     {
       g_critical ("OpenGL version number is too low");
+      CLUTTER_ACTOR_UNSET_FLAGS (stage_win32->wrapper,
+                                CLUTTER_ACTOR_REALIZED);
       CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
       return;
     }
       
   /* Make sure the viewport gets set up correctly */
-  CLUTTER_SET_PRIVATE_FLAGS (actor, CLUTTER_ACTOR_SYNC_MATRICES);
+  CLUTTER_SET_PRIVATE_FLAGS (stage_win32->wrapper,
+                            CLUTTER_ACTOR_SYNC_MATRICES);
 }
 
 static void
@@ -526,7 +557,18 @@ clutter_stage_win32_unrealize (ClutterActor *actor)
 {
   ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (actor);
 
-  wglMakeCurrent (NULL, NULL);
+  CLUTTER_NOTE (BACKEND, "Unrealizing stage");
+
+  /* Chain up so all children get unrealized, needed to move texture
+   * data across contexts
+   */
+  CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class)->unrealize (actor);
+
+  /* Unrealize all shaders, since the GL context is going away */
+  _clutter_shader_release_all ();
+
+  /* As unrealised the context will now get cleared */
+  clutter_stage_ensure_current (stage_win32->wrapper);
 
   if (stage_win32->client_dc)
     {
@@ -536,6 +578,11 @@ clutter_stage_win32_unrealize (ClutterActor *actor)
 
   if (stage_win32->hwnd)
     {
+      /* Drop the pointer to this stage in the window so that any
+        further messages won't be processed. The stage might be being
+        destroyed so otherwise the messages would be handled with an
+        invalid stage instance */
+      SetWindowLongPtrW (stage_win32->hwnd, 0, (LONG_PTR) 0);
       DestroyWindow (stage_win32->hwnd);
       stage_win32->hwnd = NULL;
     }
@@ -557,7 +604,6 @@ clutter_stage_win32_class_init (ClutterStageWin32Class *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
-  ClutterStageClass *stage_class = CLUTTER_STAGE_CLASS (klass);
 
   gobject_class->dispose = clutter_stage_win32_dispose;
   
@@ -567,10 +613,6 @@ clutter_stage_win32_class_init (ClutterStageWin32Class *klass)
   actor_class->query_coords = clutter_stage_win32_query_coords;
   actor_class->realize = clutter_stage_win32_realize;
   actor_class->unrealize = clutter_stage_win32_unrealize;
-  
-  stage_class->set_title = clutter_stage_win32_set_title;
-  stage_class->set_user_resize = clutter_stage_win32_set_user_resize;
-  stage_class->set_fullscreen = clutter_stage_win32_set_fullscreen;
 }
 
 static void
@@ -584,6 +626,19 @@ clutter_stage_win32_init (ClutterStageWin32 *stage)
   stage->win_height = 480;
   stage->backend = NULL;
   stage->scroll_pos = 0;
+
+  stage->wrapper = NULL;
+        
+  CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IS_TOPLEVEL);
+}
+
+static void
+clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
+{
+  iface->get_wrapper = clutter_stage_win32_get_wrapper;
+  iface->set_title = clutter_stage_win32_set_title;
+  iface->set_fullscreen = clutter_stage_win32_set_fullscreen;
+  iface->set_user_resizable = clutter_stage_win32_set_user_resize;
 }
 
 /**
@@ -599,9 +654,15 @@ clutter_stage_win32_init (ClutterStageWin32 *stage)
 HWND
 clutter_win32_get_stage_window (ClutterStage *stage)
 {
-  g_return_val_if_fail (CLUTTER_IS_STAGE_WIN32 (stage), NULL);
+  ClutterStageWindow *impl;
+
+  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
+
+  impl = _clutter_stage_get_window (stage);
+
+  g_return_val_if_fail (CLUTTER_IS_STAGE_WIN32 (impl), NULL);
 
-  return CLUTTER_STAGE_WIN32 (stage)->hwnd;
+  return CLUTTER_STAGE_WIN32 (impl)->hwnd;
 }
 
 /**
@@ -624,7 +685,7 @@ clutter_win32_get_stage_from_window (HWND hwnd)
       == clutter_stage_win32_get_window_class ())
     /* If it is there should be a pointer to the stage in the window
        extra data */
-    return (ClutterStage *) GetWindowLongPtrW (hwnd, 0);
+    return CLUTTER_STAGE_WIN32 (GetWindowLongPtrW (hwnd, 0))->wrapper;
   else
     return NULL;
 }
@@ -633,12 +694,14 @@ void
 clutter_stage_win32_map (ClutterStageWin32 *stage_win32)
 {
   CLUTTER_ACTOR_SET_FLAGS (stage_win32, CLUTTER_ACTOR_MAPPED);
+  CLUTTER_ACTOR_SET_FLAGS (stage_win32->wrapper, CLUTTER_ACTOR_MAPPED);
 
-  clutter_actor_queue_redraw (CLUTTER_ACTOR (stage_win32));
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (stage_win32->wrapper));
 }
 
 void
 clutter_stage_win32_unmap (ClutterStageWin32 *stage_win32)
 {
   CLUTTER_ACTOR_UNSET_FLAGS (stage_win32, CLUTTER_ACTOR_MAPPED);
+  CLUTTER_ACTOR_UNSET_FLAGS (stage_win32->wrapper, CLUTTER_ACTOR_MAPPED);
 }
index 79e09a1..eff18cd 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef __CLUTTER_STAGE_WIN32_H__
 #define __CLUTTER_STAGE_WIN32_H__
 
-#include <glib-object.h>
+#include <clutter/clutter-group.h>
 #include <clutter/clutter-stage.h>
 #include <windows.h>
 
@@ -42,7 +42,7 @@ typedef struct _ClutterStageWin32Class    ClutterStageWin32Class;
 
 struct _ClutterStageWin32
 {
-  ClutterStage parent_instance;
+  ClutterGroup parent_instance;
 
   HWND         hwnd;
   HDC          client_dc;
@@ -55,11 +55,13 @@ struct _ClutterStageWin32
 
   ClutterBackendWin32 *backend;
   ClutterStageState   state;
+
+  ClutterStage *wrapper;
 };
 
 struct _ClutterStageWin32Class
 {
-  ClutterStageClass parent_class;
+  ClutterGroupClass parent_class;
 };
 
 GType clutter_stage_win32_get_type (void) G_GNUC_CONST;