diff --git a/ChangeLog b/ChangeLog index 6336e2358..49de87a29 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2008-03-30 Neil Roberts + + * clutter/win32/clutter-win32.h: + * clutter/win32/clutter-stage-win32.h: + * clutter/win32/clutter-stage-win32.c: + * clutter/win32/clutter-event-win32.c: + * clutter/win32/clutter-backend-win32.h: + * clutter/win32/clutter-backend-win32.c: + Upgraded for multi-stage support. + + * clutter/win32/clutter-stage-win32.c + (clutter_stage_win32_request_coords): Fixed so that it doesn't set + the position or size if it hasn't changed. This was causing + problems when the window was resized using the top left corner. In + that case the window receives resize and move messages separately + which caused the window to flash at a different size or position + while one message was handled before the other. + (clutter_stage_win32_realize): Added PFD_GENERIC_ACCELERATED to + the list of pixel format flags to force it to use hardware + acceleration. + 2008-03-28 Matthew Allum * clutter/Makefile.am: diff --git a/clutter/win32/clutter-backend-win32.c b/clutter/win32/clutter-backend-win32.c index b298e146f..9b5d938ad 100644 --- a/clutter/win32/clutter-backend-win32.c +++ b/clutter/win32/clutter-backend-win32.c @@ -66,14 +66,6 @@ clutter_backend_win32_init_events (ClutterBackend *backend) _clutter_backend_win32_events_init (backend); } -ClutterActor * -clutter_backend_win32_get_stage (ClutterBackend *backend) -{ - ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend); - - return backend_win32->stage; -} - static const GOptionEntry entries[] = { { @@ -104,18 +96,19 @@ static void clutter_backend_win32_dispose (GObject *gobject) { ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (gobject); + ClutterMainContext *context; + ClutterStageManager *stage_manager; + GSList *l; - if (backend_win32->stage) + 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) { - CLUTTER_NOTE (BACKEND, "Disposing the main stage"); - - /* we unset the private flag on the stage so we can safely - * destroy it without a warning from clutter_actor_destroy() - */ - CLUTTER_UNSET_PRIVATE_FLAGS (backend_win32->stage, - CLUTTER_ACTOR_IS_TOPLEVEL); - clutter_actor_destroy (backend_win32->stage); - backend_win32->stage = NULL; + ClutterActor *stage = CLUTTER_ACTOR (l->data); + clutter_actor_destroy (stage); } CLUTTER_NOTE (BACKEND, "Removing the event source"); @@ -175,7 +168,9 @@ clutter_backend_win32_get_features (ClutterBackend *backend) glGetString (GL_VERSION), extensions); - flags = CLUTTER_FEATURE_STAGE_USER_RESIZE | CLUTTER_FEATURE_STAGE_CURSOR; + 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 @@ -217,52 +212,61 @@ clutter_backend_win32_get_features (ClutterBackend *backend) } static void -clutter_backend_win32_redraw (ClutterBackend *backend) +clutter_backend_win32_ensure_context (ClutterBackend *backend, + ClutterStage *stage) { - ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend); - ClutterStageWin32 *stage_win32; + ClutterBackendWin32 *backend_win32; + ClutterStageWin32 *stage_win32; - stage_win32 = CLUTTER_STAGE_WIN32 (backend_win32->stage); + stage_win32 = CLUTTER_STAGE_WIN32 (stage); + backend_win32 = CLUTTER_BACKEND_WIN32 (backend); - clutter_actor_paint (CLUTTER_ACTOR (stage_win32)); + CLUTTER_NOTE (MULTISTAGE, "setting context for stage:%p", stage ); + + 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); + + clutter_actor_paint (CLUTTER_ACTOR (stage)); if (stage_win32->client_dc) SwapBuffers (stage_win32->client_dc); } -static gboolean -clutter_backend_win32_init_stage (ClutterBackend *backend, - GError **error) +static ClutterActor * +clutter_backend_win32_create_stage (ClutterBackend *backend, + GError **error) { ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend); + ClutterStageWin32 *stage_win32; + ClutterActor *stage; - if (!backend_win32->stage) - { - ClutterStageWin32 *stage_win32; - ClutterActor *stage; + stage = g_object_new (CLUTTER_TYPE_STAGE_WIN32, NULL); - stage = g_object_new (CLUTTER_TYPE_STAGE_WIN32, NULL); + /* copy backend data into the stage */ + stage_win32 = CLUTTER_STAGE_WIN32 (stage); + stage_win32->backend = backend_win32; - /* copy backend data into the stage */ - stage_win32 = CLUTTER_STAGE_WIN32 (stage); - stage_win32->backend = backend_win32; + /* needed ? */ + g_object_set_data (G_OBJECT (stage), "clutter-backend", backend); - g_object_set_data (G_OBJECT (stage), "clutter-backend", backend); + clutter_actor_realize (stage); - backend_win32->stage = g_object_ref_sink (stage); - } - - clutter_actor_realize (backend_win32->stage); - - if (!CLUTTER_ACTOR_IS_REALIZED (backend_win32->stage)) + if (!CLUTTER_ACTOR_IS_REALIZED (stage)) { g_set_error (error, CLUTTER_INIT_ERROR, CLUTTER_INIT_ERROR_INTERNAL, "Unable to realize the main stage"); - return FALSE; + return NULL; } - return TRUE; + return stage; } static void @@ -275,13 +279,13 @@ clutter_backend_win32_class_init (ClutterBackendWin32Class *klass) gobject_class->dispose = clutter_backend_win32_dispose; gobject_class->finalize = clutter_backend_win32_finalize; - backend_class->pre_parse = clutter_backend_win32_pre_parse; - backend_class->init_events = clutter_backend_win32_init_events; - backend_class->init_stage = clutter_backend_win32_init_stage; - backend_class->get_stage = clutter_backend_win32_get_stage; - backend_class->add_options = clutter_backend_win32_add_options; - backend_class->get_features = clutter_backend_win32_get_features; - backend_class->redraw = clutter_backend_win32_redraw; + backend_class->pre_parse = clutter_backend_win32_pre_parse; + backend_class->init_events = clutter_backend_win32_init_events; + backend_class->create_stage = clutter_backend_win32_create_stage; + backend_class->add_options = clutter_backend_win32_add_options; + backend_class->get_features = clutter_backend_win32_get_features; + backend_class->redraw = clutter_backend_win32_redraw; + backend_class->ensure_context = clutter_backend_win32_ensure_context; } static void @@ -289,6 +293,8 @@ clutter_backend_win32_init (ClutterBackendWin32 *backend_win32) { ClutterBackend *backend = CLUTTER_BACKEND (backend_win32); + backend_win32->gl_context = NULL; + /* FIXME: get from GetSystemMetric? */ clutter_backend_set_double_click_time (backend, 250); clutter_backend_set_double_click_distance (backend, 5); diff --git a/clutter/win32/clutter-backend-win32.h b/clutter/win32/clutter-backend-win32.h index 649a3b14d..245bc1903 100644 --- a/clutter/win32/clutter-backend-win32.h +++ b/clutter/win32/clutter-backend-win32.h @@ -45,8 +45,7 @@ struct _ClutterBackendWin32 { ClutterBackend parent_instance; - /* main stage singleton */ - ClutterActor *stage; + HGLRC gl_context; GSource *event_source; }; @@ -61,9 +60,6 @@ void _clutter_backend_win32_events_uninit (ClutterBackend *backend); GType clutter_backend_win32_get_type (void) G_GNUC_CONST; -ClutterActor * -clutter_backend_win32_get_stage (ClutterBackend *backend); - void clutter_backend_win32_add_options (ClutterBackend *backend, GOptionGroup *group); diff --git a/clutter/win32/clutter-event-win32.c b/clutter/win32/clutter-event-win32.c index e85b0eb7a..df3028659 100644 --- a/clutter/win32/clutter-event-win32.c +++ b/clutter/win32/clutter-event-win32.c @@ -307,16 +307,17 @@ message_translate (ClutterBackend *backend, ClutterStageWin32 *stage_win32; ClutterStage *stage; gboolean res; - HWND stage_hwnd; backend_win32 = CLUTTER_BACKEND_WIN32 (backend); - stage = CLUTTER_STAGE (_clutter_backend_get_stage (backend)); - stage_win32 = CLUTTER_STAGE_WIN32 (stage); - stage_hwnd = clutter_win32_get_stage_window (stage); /* Do further processing only on events for the stage window */ - if (stage_hwnd != msg->hwnd) + stage = clutter_win32_get_stage_from_window (msg->hwnd); + + if (stage == NULL) return FALSE; + stage_win32 = CLUTTER_STAGE_WIN32 (stage); + + event->any.stage = stage; res = TRUE; @@ -393,7 +394,8 @@ message_translate (ClutterBackend *backend, break; case WM_PAINT: - clutter_actor_queue_redraw (CLUTTER_ACTOR (stage_win32)); + CLUTTER_NOTE (MULTISTAGE, "expose for stage:%p, redrawing", stage); + clutter_redraw (stage); res = FALSE; break; diff --git a/clutter/win32/clutter-stage-win32.c b/clutter/win32/clutter-stage-win32.c index bd6fa18f5..171776ae0 100644 --- a/clutter/win32/clutter-stage-win32.c +++ b/clutter/win32/clutter-stage-win32.c @@ -36,6 +36,7 @@ #include "../clutter-private.h" #include "../clutter-debug.h" #include "../clutter-units.h" +#include "../clutter-stage.h" #include "cogl.h" @@ -171,18 +172,23 @@ clutter_stage_win32_request_coords (ClutterActor *self, ClutterActorBox *box) { ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (self); - gint new_xpos, new_ypos, new_width, new_height; + int change_flags = SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE; new_xpos = CLUTTER_UNITS_TO_INT (MIN (box->x1, box->x2)); new_ypos = CLUTTER_UNITS_TO_INT (MIN (box->y1, box->y2)); new_width = ABS (CLUTTER_UNITS_TO_INT (box->x2 - box->x1)); new_height = ABS (CLUTTER_UNITS_TO_INT (box->y2 - box->y1)); - if ((new_width != stage_win32->win_width - || new_height != stage_win32->win_height - || new_xpos != stage_win32->win_xpos - || new_ypos != stage_win32->win_ypos) + if (new_width != stage_win32->win_width + || new_height != stage_win32->win_height) + change_flags &= ~SWP_NOSIZE; + + if (new_xpos != stage_win32->win_xpos + || new_ypos != stage_win32->win_ypos) + change_flags &= ~SWP_NOMOVE; + + if ((change_flags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE) /* Ignore size requests if we are in full screen mode */ && (stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN) == 0) { @@ -205,7 +211,7 @@ clutter_stage_win32_request_coords (ClutterActor *self, SetWindowPos (stage_win32->hwnd, NULL, full_xpos, full_ypos, full_width, full_height, - SWP_NOZORDER); + change_flags); } CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_SYNC_MATRICES); @@ -316,6 +322,7 @@ clutter_stage_win32_set_fullscreen (ClutterStage *stage, /* Report the state change */ memset (&event, 0, sizeof (event)); event.type = CLUTTER_STAGE_STATE; + event.stage = CLUTTER_STAGE (stage_win32); event.new_state = stage_win32->state; event.changed_mask = CLUTTER_STAGE_STATE_FULLSCREEN; clutter_event_put ((ClutterEvent *) &event); @@ -382,11 +389,14 @@ static void clutter_stage_win32_realize (ClutterActor *actor) { ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (actor); + ClutterBackendWin32 *backend_win32; PIXELFORMATDESCRIPTOR pfd; int pf; CLUTTER_NOTE (MISC, "Realizing main stage"); + backend_win32 = CLUTTER_BACKEND_WIN32 (clutter_get_default_backend ()); + if (stage_win32->hwnd == NULL) { ATOM window_class = clutter_stage_win32_get_window_class (); @@ -459,9 +469,6 @@ clutter_stage_win32_realize (ClutterActor *actor) SetWindowLongPtrW (stage_win32->hwnd, 0, (LONG_PTR) stage_win32); } - if (stage_win32->gl_context) - wglDeleteContext (stage_win32->gl_context); - if (stage_win32->client_dc) ReleaseDC (stage_win32->hwnd, stage_win32->client_dc); @@ -470,7 +477,8 @@ clutter_stage_win32_realize (ClutterActor *actor) memset (&pfd, 0, sizeof (pfd)); pfd.nSize = sizeof (pfd); pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL + | PFD_DOUBLEBUFFER | PFD_GENERIC_ACCELERATED; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; pfd.cAlphaBits = 8; @@ -486,17 +494,21 @@ clutter_stage_win32_realize (ClutterActor *actor) return; } - stage_win32->gl_context = wglCreateContext (stage_win32->client_dc); - - if (stage_win32->gl_context == NULL) + if (backend_win32->gl_context == NULL) { - g_critical ("Unable to create suitable GL context"); - CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); - return; + backend_win32->gl_context = wglCreateContext (stage_win32->client_dc); + + if (backend_win32->gl_context == NULL) + { + g_critical ("Unable to create suitable GL context"); + CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); + return; + } } CLUTTER_NOTE (GL, "wglMakeCurrent"); - wglMakeCurrent (stage_win32->client_dc, stage_win32->gl_context); + + clutter_stage_ensure_current (CLUTTER_STAGE (stage_win32)); if (!clutter_stage_win32_check_gl_version ()) { @@ -516,12 +528,6 @@ clutter_stage_win32_unrealize (ClutterActor *actor) wglMakeCurrent (NULL, NULL); - if (stage_win32->gl_context != NULL) - { - wglDeleteContext (stage_win32->gl_context); - stage_win32->gl_context = NULL; - } - if (stage_win32->client_dc) { ReleaseDC (stage_win32->hwnd, stage_win32->client_dc); @@ -572,7 +578,6 @@ clutter_stage_win32_init (ClutterStageWin32 *stage) { stage->hwnd = NULL; stage->client_dc = NULL; - stage->gl_context = NULL; stage->win_xpos = 0; stage->win_ypos = 0; stage->win_width = 640; @@ -599,6 +604,31 @@ clutter_win32_get_stage_window (ClutterStage *stage) return CLUTTER_STAGE_WIN32 (stage)->hwnd; } +/** + * clutter_win32_get_stage_from_window: + * @hwnd: a window handle + * + * Gets the stage for a particular window. + * + * Return value: The stage or NULL if a stage does not exist for the + * window. + * + * Since: 0.8 + */ +ClutterStage * +clutter_win32_get_stage_from_window (HWND hwnd) +{ + /* Check whether the window handle is an instance of the stage + window class */ + if ((ATOM) GetClassLongPtrW (hwnd, GCW_ATOM) + == 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); + else + return NULL; +} + void clutter_stage_win32_map (ClutterStageWin32 *stage_win32) { diff --git a/clutter/win32/clutter-stage-win32.h b/clutter/win32/clutter-stage-win32.h index 4a195af3e..79e09a1d7 100644 --- a/clutter/win32/clutter-stage-win32.h +++ b/clutter/win32/clutter-stage-win32.h @@ -46,7 +46,6 @@ struct _ClutterStageWin32 HWND hwnd; HDC client_dc; - HGLRC gl_context; gint win_xpos; gint win_ypos; gint win_width; @@ -65,8 +64,6 @@ struct _ClutterStageWin32Class GType clutter_stage_win32_get_type (void) G_GNUC_CONST; -HWND clutter_win32_get_stage_window (ClutterStage *stage); - void clutter_stage_win32_map (ClutterStageWin32 *stage_win32); void clutter_stage_win32_unmap (ClutterStageWin32 *stage_win32); diff --git a/clutter/win32/clutter-win32.h b/clutter/win32/clutter-win32.h index 3f9019bce..df416e640 100644 --- a/clutter/win32/clutter-win32.h +++ b/clutter/win32/clutter-win32.h @@ -43,7 +43,8 @@ G_BEGIN_DECLS -HWND clutter_win32_get_stage_window (ClutterStage *stage); +HWND clutter_win32_get_stage_window (ClutterStage *stage); +ClutterStage *clutter_win32_get_stage_from_window (HWND hwnd); G_END_DECLS diff --git a/doc/reference/ChangeLog b/doc/reference/ChangeLog index 244977aa3..1b9ce74b7 100644 --- a/doc/reference/ChangeLog +++ b/doc/reference/ChangeLog @@ -1,3 +1,7 @@ +2008-03-30 Neil Roberts + + * clutter-sections.txt: Added clutter_win32_get_stage_from_window + 2008-03-26 Neil Roberts * clutter-sections.txt: Added a section for the Win32 specific diff --git a/doc/reference/clutter-sections.txt b/doc/reference/clutter-sections.txt index c618ff777..92065787e 100644 --- a/doc/reference/clutter-sections.txt +++ b/doc/reference/clutter-sections.txt @@ -1008,6 +1008,7 @@ clutter_x11_remove_filter
clutter-win32 Win32 Specific Support +clutter_win32_get_stage_from_window clutter_win32_get_stage_window