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.
This commit is contained in:
Neil Roberts 2008-04-13 08:43:32 +00:00
parent bf48bd1f55
commit 0b8a500fca
5 changed files with 250 additions and 75 deletions

View File

@ -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> 2008-04-11 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/clutter-container.c: * clutter/clutter-container.c:

View File

@ -33,6 +33,7 @@
#include "../clutter-main.h" #include "../clutter-main.h"
#include "../clutter-debug.h" #include "../clutter-debug.h"
#include "../clutter-private.h" #include "../clutter-private.h"
#include "../clutter-version.h"
#include "cogl.h" #include "cogl.h"
@ -100,22 +101,27 @@ clutter_backend_win32_dispose (GObject *gobject)
ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (gobject); ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (gobject);
ClutterMainContext *context; ClutterMainContext *context;
ClutterStageManager *stage_manager; ClutterStageManager *stage_manager;
GSList *l;
CLUTTER_NOTE (BACKEND, "Disposing the of stages"); CLUTTER_NOTE (BACKEND, "Disposing the of stages");
context = clutter_context_get_default (); context = clutter_context_get_default ();
stage_manager = context->stage_manager; stage_manager = context->stage_manager;
for (l = stage_manager->stages; l; l = l->next) /* Destroy all of the stages. g_slist_foreach is used because the
{ finalizer for the stages will remove the stage from the
ClutterActor *stage = CLUTTER_ACTOR (l->data); stage_manager's list and g_slist_foreach has some basic
clutter_actor_destroy (stage); protection against this */
} g_slist_foreach (stage_manager->stages, (GFunc) clutter_actor_destroy, NULL);
CLUTTER_NOTE (BACKEND, "Removing the event source"); CLUTTER_NOTE (BACKEND, "Removing the event source");
_clutter_backend_win32_events_uninit (CLUTTER_BACKEND (backend_win32)); _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); G_OBJECT_CLASS (clutter_backend_win32_parent_class)->dispose (gobject);
} }
@ -155,11 +161,18 @@ clutter_backend_win32_get_features (ClutterBackend *backend)
ClutterFeatureFlags flags; ClutterFeatureFlags flags;
const gchar *extensions; const gchar *extensions;
SwapIntervalProc swap_interval; SwapIntervalProc swap_interval;
ClutterBackendWin32 *backend_win32;
/* FIXME: we really need to check if gl context is set */ /* FIXME: we really need to check if gl context is set */
extensions = glGetString (GL_EXTENSIONS); 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" CLUTTER_NOTE (BACKEND, "Checking features\n"
"GL_VENDOR: %s\n" "GL_VENDOR: %s\n"
"GL_RENDERER: %s\n" "GL_RENDERER: %s\n"
@ -217,24 +230,70 @@ static void
clutter_backend_win32_ensure_context (ClutterBackend *backend, clutter_backend_win32_ensure_context (ClutterBackend *backend,
ClutterStage *stage) ClutterStage *stage)
{ {
if (stage == NULL)
{
CLUTTER_NOTE (MULTISTAGE, "Clearing all context");
wglMakeCurrent (NULL, NULL);
}
else
{
ClutterBackendWin32 *backend_win32; ClutterBackendWin32 *backend_win32;
ClutterStageWin32 *stage_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);
stage_win32 = CLUTTER_STAGE_WIN32 (stage);
backend_win32 = CLUTTER_BACKEND_WIN32 (backend); backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
stage_win32 = CLUTTER_STAGE_WIN32 (impl);
CLUTTER_NOTE (MULTISTAGE, "setting context for stage:%p", stage ); /* 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, wglMakeCurrent (stage_win32->client_dc,
backend_win32->gl_context); backend_win32->gl_context);
}
}
} }
static void static void
clutter_backend_win32_redraw (ClutterBackend *backend, clutter_backend_win32_redraw (ClutterBackend *backend,
ClutterStage *stage) 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)); clutter_actor_paint (CLUTTER_ACTOR (stage));
if (stage_win32->client_dc) if (stage_win32->client_dc)
@ -243,21 +302,33 @@ clutter_backend_win32_redraw (ClutterBackend *backend,
static ClutterActor * static ClutterActor *
clutter_backend_win32_create_stage (ClutterBackend *backend, clutter_backend_win32_create_stage (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error) GError **error)
{ {
ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend); ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
ClutterStageWin32 *stage_win32; ClutterStageWin32 *stage_win32;
ClutterActor *stage; 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 */ /* copy backend data into the stage */
stage_win32 = CLUTTER_STAGE_WIN32 (stage); stage_win32 = CLUTTER_STAGE_WIN32 (stage);
stage_win32->backend = backend_win32; 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 ? */ /* needed ? */
g_object_set_data (G_OBJECT (stage), "clutter-backend", backend); 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); clutter_actor_realize (stage);
if (!CLUTTER_ACTOR_IS_REALIZED (stage)) if (!CLUTTER_ACTOR_IS_REALIZED (stage))

View File

@ -301,11 +301,13 @@ get_key_modifier_state (const BYTE *key_states)
static gboolean static gboolean
message_translate (ClutterBackend *backend, message_translate (ClutterBackend *backend,
ClutterEvent *event, ClutterEvent *event,
const MSG *msg) const MSG *msg,
gboolean *call_def_window_proc)
{ {
ClutterBackendWin32 *backend_win32; ClutterBackendWin32 *backend_win32;
ClutterStageWin32 *stage_win32; ClutterStageWin32 *stage_win32;
ClutterStage *stage; ClutterStage *stage;
ClutterStageWindow *impl;
gboolean res; gboolean res;
backend_win32 = CLUTTER_BACKEND_WIN32 (backend); backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
@ -315,7 +317,8 @@ message_translate (ClutterBackend *backend,
if (stage == NULL) if (stage == NULL)
return FALSE; return FALSE;
stage_win32 = CLUTTER_STAGE_WIN32 (stage); impl = _clutter_stage_get_window (stage);
stage_win32 = CLUTTER_STAGE_WIN32 (impl);
event->any.stage = stage; event->any.stage = stage;
@ -404,6 +407,16 @@ message_translate (ClutterBackend *backend,
event->type = CLUTTER_DESTROY_NOTIFY; event->type = CLUTTER_DESTROY_NOTIFY;
break; 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: case WM_LBUTTONDOWN:
make_button_event (msg, event, 1, 1, FALSE); make_button_event (msg, event, 1, 1, FALSE);
break; break;
@ -552,6 +565,15 @@ message_translate (ClutterBackend *backend,
} }
break; 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: default:
/* ignore every other message */ /* ignore every other message */
res = FALSE; res = FALSE;
@ -567,6 +589,7 @@ _clutter_stage_win32_window_proc (HWND hwnd, UINT umsg,
{ {
ClutterStageWin32 *stage_win32 ClutterStageWin32 *stage_win32
= (ClutterStageWin32 *) GetWindowLongPtrW (hwnd, 0); = (ClutterStageWin32 *) GetWindowLongPtrW (hwnd, 0);
gboolean call_def_window_proc = TRUE;
/* Ignore any messages before SetWindowLongPtr has been called to /* Ignore any messages before SetWindowLongPtr has been called to
set the stage */ 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.x = (SHORT) LOWORD (message_pos);
msg.pt.y = (SHORT) HIWORD (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)) if (message_translate (CLUTTER_BACKEND (backend_win32), event,
&msg, &call_def_window_proc))
/* push directly here to avoid copy of queue_put */ /* push directly here to avoid copy of queue_put */
g_queue_push_head (clutter_context->events_queue, event); g_queue_push_head (clutter_context->events_queue, event);
else else
clutter_event_free (event); clutter_event_free (event);
} }
}
if (call_def_window_proc)
return DefWindowProcW (hwnd, umsg, wparam, lparam); return DefWindowProcW (hwnd, umsg, wparam, lparam);
else
return 0;
} }

View File

@ -27,6 +27,7 @@
#include "clutter-stage-win32.h" #include "clutter-stage-win32.h"
#include "clutter-win32.h" #include "clutter-win32.h"
#include "../clutter-stage-window.h"
#include "../clutter-main.h" #include "../clutter-main.h"
#include "../clutter-feature.h" #include "../clutter-feature.h"
#include "../clutter-color.h" #include "../clutter-color.h"
@ -36,13 +37,21 @@
#include "../clutter-private.h" #include "../clutter-private.h"
#include "../clutter-debug.h" #include "../clutter-debug.h"
#include "../clutter-units.h" #include "../clutter-units.h"
#include "../clutter-shader.h"
#include "../clutter-stage.h" #include "../clutter-stage.h"
#include "cogl.h" #include "cogl.h"
#include <windows.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 static void
clutter_stage_win32_show (ClutterActor *actor) clutter_stage_win32_show (ClutterActor *actor)
@ -122,7 +131,7 @@ get_full_window_pos (ClutterStageWin32 *stage_win32,
int *xpos_out, int *ypos_out) int *xpos_out, int *ypos_out)
{ {
gboolean resizable 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 /* The window position passed to CreateWindow includes the window
decorations */ decorations */
*xpos_out = xpos_in - GetSystemMetrics (resizable ? SM_CXSIZEFRAME *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) int *width_out, int *height_out)
{ {
gboolean resizable 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 /* The window size passed to CreateWindow includes the window
decorations */ decorations */
*width_out = width_in + GetSystemMetrics (resizable ? SM_CXSIZEFRAME *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 /* If the window isn't resizable then set the max and min size to
the current size */ 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; int full_width, full_height;
get_full_window_size (stage_win32, get_full_window_size (stage_win32,
@ -214,7 +223,8 @@ clutter_stage_win32_request_coords (ClutterActor *self,
change_flags); 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) CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class)
@ -222,10 +232,10 @@ clutter_stage_win32_request_coords (ClutterActor *self,
} }
static void static void
clutter_stage_win32_set_title (ClutterStage *stage, clutter_stage_win32_set_title (ClutterStageWindow *stage_window,
const gchar *title) const gchar *title)
{ {
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage); ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
wchar_t *wtitle; wchar_t *wtitle;
/* Empty window titles not allowed, so set it to just a period. */ /* 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 static LONG
get_window_style (ClutterStageWin32 *stage_win32) get_window_style (ClutterStageWin32 *stage_win32)
{ {
ClutterStage *wrapper = stage_win32->wrapper;
/* Fullscreen mode shouldn't have any borders */ /* Fullscreen mode shouldn't have any borders */
if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN)) if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN))
return WS_POPUP; return WS_POPUP;
/* Otherwise it's an overlapped window but if it isn't resizable /* Otherwise it's an overlapped window but if it isn't resizable
then it shouldn't have a thick frame */ 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; return WS_OVERLAPPEDWINDOW;
else else
return WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME; return WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME;
} }
static void static void
clutter_stage_win32_set_user_resize (ClutterStage *stage, clutter_stage_win32_set_user_resize (ClutterStageWindow *stage_window,
gboolean value) gboolean value)
{ {
HWND hwnd = CLUTTER_STAGE_WIN32 (stage)->hwnd; HWND hwnd = CLUTTER_STAGE_WIN32 (stage_window)->hwnd;
LONG old_style = GetWindowLongW (hwnd, GWL_STYLE); LONG old_style = GetWindowLongW (hwnd, GWL_STYLE);
/* Update the window style but preserve the visibility */ /* Update the window style but preserve the visibility */
SetWindowLongW (hwnd, GWL_STYLE, SetWindowLongW (hwnd, GWL_STYLE,
get_window_style (CLUTTER_STAGE_WIN32 (stage)) get_window_style (CLUTTER_STAGE_WIN32 (stage_window))
| (old_style & WS_VISIBLE)); | (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 static void
clutter_stage_win32_set_fullscreen (ClutterStage *stage, clutter_stage_win32_set_fullscreen (ClutterStageWindow *stage_window,
gboolean value) gboolean value)
{ {
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage); ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
HWND hwnd = CLUTTER_STAGE_WIN32 (stage)->hwnd; HWND hwnd = CLUTTER_STAGE_WIN32 (stage_window)->hwnd;
LONG old_style = GetWindowLongW (hwnd, GWL_STYLE); LONG old_style = GetWindowLongW (hwnd, GWL_STYLE);
ClutterStageStateEvent event; ClutterStageStateEvent event;
@ -316,13 +334,14 @@ clutter_stage_win32_set_fullscreen (ClutterStage *stage,
SWP_NOZORDER); 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 */ /* Report the state change */
memset (&event, 0, sizeof (event)); memset (&event, 0, sizeof (event));
event.type = CLUTTER_STAGE_STATE; 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.new_state = stage_win32->state;
event.changed_mask = CLUTTER_STAGE_STATE_FULLSCREEN; event.changed_mask = CLUTTER_STAGE_STATE_FULLSCREEN;
clutter_event_put ((ClutterEvent *) &event); clutter_event_put ((ClutterEvent *) &event);
@ -407,6 +426,8 @@ clutter_stage_win32_realize (ClutterActor *actor)
if (window_class == 0) if (window_class == 0)
{ {
g_critical ("Unable to register window class"); 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); CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return; return;
} }
@ -449,6 +470,8 @@ clutter_stage_win32_realize (ClutterActor *actor)
if (stage_win32->hwnd == NULL) if (stage_win32->hwnd == NULL)
{ {
g_critical ("Unable to create stage window"); 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); CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return; return;
} }
@ -490,6 +513,8 @@ clutter_stage_win32_realize (ClutterActor *actor)
|| !SetPixelFormat (stage_win32->client_dc, pf, &pfd)) || !SetPixelFormat (stage_win32->client_dc, pf, &pfd))
{ {
g_critical ("Unable to find suitable GL pixel format"); 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); CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return; return;
} }
@ -501,24 +526,30 @@ clutter_stage_win32_realize (ClutterActor *actor)
if (backend_win32->gl_context == NULL) if (backend_win32->gl_context == NULL)
{ {
g_critical ("Unable to create suitable GL context"); 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); CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return; return;
} }
} }
CLUTTER_NOTE (GL, "wglMakeCurrent"); /* below will call wglMakeCurrent */
CLUTTER_ACTOR_SET_FLAGS (stage_win32->wrapper, CLUTTER_ACTOR_REALIZED);
clutter_stage_ensure_current (CLUTTER_STAGE (stage_win32)); CLUTTER_ACTOR_SET_FLAGS (stage_win32, CLUTTER_ACTOR_REALIZED);
clutter_stage_ensure_current (stage_win32->wrapper);
if (!clutter_stage_win32_check_gl_version ()) if (!clutter_stage_win32_check_gl_version ())
{ {
g_critical ("OpenGL version number is too low"); 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); CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return; return;
} }
/* Make sure the viewport gets set up correctly */ /* 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 static void
@ -526,7 +557,18 @@ clutter_stage_win32_unrealize (ClutterActor *actor)
{ {
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (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) if (stage_win32->client_dc)
{ {
@ -536,6 +578,11 @@ clutter_stage_win32_unrealize (ClutterActor *actor)
if (stage_win32->hwnd) 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); DestroyWindow (stage_win32->hwnd);
stage_win32->hwnd = NULL; stage_win32->hwnd = NULL;
} }
@ -557,7 +604,6 @@ clutter_stage_win32_class_init (ClutterStageWin32Class *klass)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
ClutterStageClass *stage_class = CLUTTER_STAGE_CLASS (klass);
gobject_class->dispose = clutter_stage_win32_dispose; 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->query_coords = clutter_stage_win32_query_coords;
actor_class->realize = clutter_stage_win32_realize; actor_class->realize = clutter_stage_win32_realize;
actor_class->unrealize = clutter_stage_win32_unrealize; 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 static void
@ -584,6 +626,19 @@ clutter_stage_win32_init (ClutterStageWin32 *stage)
stage->win_height = 480; stage->win_height = 480;
stage->backend = NULL; stage->backend = NULL;
stage->scroll_pos = 0; 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 HWND
clutter_win32_get_stage_window (ClutterStage *stage) clutter_win32_get_stage_window (ClutterStage *stage)
{ {
g_return_val_if_fail (CLUTTER_IS_STAGE_WIN32 (stage), NULL); ClutterStageWindow *impl;
return CLUTTER_STAGE_WIN32 (stage)->hwnd; 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 (impl)->hwnd;
} }
/** /**
@ -624,7 +685,7 @@ clutter_win32_get_stage_from_window (HWND hwnd)
== clutter_stage_win32_get_window_class ()) == clutter_stage_win32_get_window_class ())
/* If it is there should be a pointer to the stage in the window /* If it is there should be a pointer to the stage in the window
extra data */ extra data */
return (ClutterStage *) GetWindowLongPtrW (hwnd, 0); return CLUTTER_STAGE_WIN32 (GetWindowLongPtrW (hwnd, 0))->wrapper;
else else
return NULL; return NULL;
} }
@ -633,12 +694,14 @@ void
clutter_stage_win32_map (ClutterStageWin32 *stage_win32) clutter_stage_win32_map (ClutterStageWin32 *stage_win32)
{ {
CLUTTER_ACTOR_SET_FLAGS (stage_win32, CLUTTER_ACTOR_MAPPED); 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 void
clutter_stage_win32_unmap (ClutterStageWin32 *stage_win32) clutter_stage_win32_unmap (ClutterStageWin32 *stage_win32)
{ {
CLUTTER_ACTOR_UNSET_FLAGS (stage_win32, CLUTTER_ACTOR_MAPPED); CLUTTER_ACTOR_UNSET_FLAGS (stage_win32, CLUTTER_ACTOR_MAPPED);
CLUTTER_ACTOR_UNSET_FLAGS (stage_win32->wrapper, CLUTTER_ACTOR_MAPPED);
} }

View File

@ -22,7 +22,7 @@
#ifndef __CLUTTER_STAGE_WIN32_H__ #ifndef __CLUTTER_STAGE_WIN32_H__
#define __CLUTTER_STAGE_WIN32_H__ #define __CLUTTER_STAGE_WIN32_H__
#include <glib-object.h> #include <clutter/clutter-group.h>
#include <clutter/clutter-stage.h> #include <clutter/clutter-stage.h>
#include <windows.h> #include <windows.h>
@ -42,7 +42,7 @@ typedef struct _ClutterStageWin32Class ClutterStageWin32Class;
struct _ClutterStageWin32 struct _ClutterStageWin32
{ {
ClutterStage parent_instance; ClutterGroup parent_instance;
HWND hwnd; HWND hwnd;
HDC client_dc; HDC client_dc;
@ -55,11 +55,13 @@ struct _ClutterStageWin32
ClutterBackendWin32 *backend; ClutterBackendWin32 *backend;
ClutterStageState state; ClutterStageState state;
ClutterStage *wrapper;
}; };
struct _ClutterStageWin32Class struct _ClutterStageWin32Class
{ {
ClutterStageClass parent_class; ClutterGroupClass parent_class;
}; };
GType clutter_stage_win32_get_type (void) G_GNUC_CONST; GType clutter_stage_win32_get_type (void) G_GNUC_CONST;