diff --git a/ChangeLog b/ChangeLog index df91bb900..81b9484fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2008-04-15 Neil Roberts + + Added support for foreign windows to the Win32 backend. + + * clutter/win32/clutter-stage-win32.c + (clutter_stage_win32_request_coords): Don't resize foreign + windows. + (clutter_stage_win32_unrealize): Don't destroy foreign windows. + (clutter_stage_win32_init): Added initialiser for is_foreign_win. + (clutter_win32_get_stage_from_window): Resort to looking in the + stage list if the window isn't the right window class so that it + can still find stages with foreign windows. + (clutter_win32_set_stage_foreign): New public function to set a + foreign window for a stage. + + * clutter/win32/clutter-event-win32.c + (clutter_win32_disable_event_retrieval): New public function to + disable event retrieval. + (message_translate): Don't handle WM_SIZE or WM_MOVE for foreign + windows. + + * clutter/win32/clutter-backend-win32.h (struct + _ClutterBackendWin32): Added a flag to disable event retrieval + + * clutter/win32/clutter-backend-win32.c + (clutter_backend_win32_ensure_context): Update debug note to + include whether the stage is foreign or not. + 2008-04-15 Øyvind Kolås * clutter/clutter-actor.c: (clutter_actor_set_shader_param): queue a diff --git a/clutter/win32/clutter-backend-win32.c b/clutter/win32/clutter-backend-win32.c index 22a81ab8f..bc86a3035 100644 --- a/clutter/win32/clutter-backend-win32.c +++ b/clutter/win32/clutter-backend-win32.c @@ -269,8 +269,9 @@ clutter_backend_win32_ensure_context (ClutterBackend *backend, else { CLUTTER_NOTE (BACKEND, - "MakeCurrent window %p, context %p", + "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); @@ -366,7 +367,8 @@ clutter_backend_win32_init (ClutterBackendWin32 *backend_win32) { ClutterBackend *backend = CLUTTER_BACKEND (backend_win32); - backend_win32->gl_context = NULL; + backend_win32->gl_context = NULL; + backend_win32->no_event_retrieval = FALSE; /* FIXME: get from GetSystemMetric? */ clutter_backend_set_double_click_time (backend, 250); diff --git a/clutter/win32/clutter-backend-win32.h b/clutter/win32/clutter-backend-win32.h index 245bc1903..c301f68e1 100644 --- a/clutter/win32/clutter-backend-win32.h +++ b/clutter/win32/clutter-backend-win32.h @@ -45,9 +45,10 @@ struct _ClutterBackendWin32 { ClutterBackend parent_instance; - HGLRC gl_context; + HGLRC gl_context; + gboolean no_event_retrieval; - GSource *event_source; + GSource *event_source; }; struct _ClutterBackendWin32Class diff --git a/clutter/win32/clutter-event-win32.c b/clutter/win32/clutter-event-win32.c index 9a46a5491..88b12efbb 100644 --- a/clutter/win32/clutter-event-win32.c +++ b/clutter/win32/clutter-event-win32.c @@ -212,6 +212,28 @@ make_button_event (const MSG *msg, ClutterEvent *event, event->button.click_count = click_count; } +/** + * clutter_win32_disable_event_retrieval + * + * Disables retrieval of Windows messages in the main loop. Use to + * create event-less canvas. + * + * This function can only be called before calling clutter_init(). + * + * Since: 0.8 + */ +void +clutter_win32_disable_event_retrieval (void) +{ + ClutterBackendWin32 *backend; + ClutterMainContext *clutter_context; + + clutter_context = clutter_context_get_default (); + backend = CLUTTER_BACKEND_WIN32 (clutter_context->backend); + + backend->no_event_retrieval = TRUE; +} + static gboolean clutter_event_prepare (GSource *source, gint *timeout) @@ -327,34 +349,36 @@ message_translate (ClutterBackend *backend, switch (msg->message) { case WM_SIZE: - { - WORD new_width = LOWORD (msg->lParam); - WORD new_height = HIWORD (msg->lParam); - guint old_width, old_height; + if (!stage_win32->is_foreign_win) + { + WORD new_width = LOWORD (msg->lParam); + WORD new_height = HIWORD (msg->lParam); + guint old_width, old_height; - clutter_actor_get_size (CLUTTER_ACTOR (stage), - &old_width, &old_height); + clutter_actor_get_size (CLUTTER_ACTOR (stage), + &old_width, &old_height); - if (new_width != old_width || new_height != old_height) - clutter_actor_set_size (CLUTTER_ACTOR (stage), - new_width, new_height); - } + if (new_width != old_width || new_height != old_height) + clutter_actor_set_size (CLUTTER_ACTOR (stage), + new_width, new_height); + } res = FALSE; break; case WM_MOVE: - { - WORD new_xpos = GET_X_LPARAM (msg->lParam); - WORD new_ypos = GET_Y_LPARAM (msg->lParam); - guint old_xpos, old_ypos; + if (!stage_win32->is_foreign_win) + { + WORD new_xpos = GET_X_LPARAM (msg->lParam); + WORD new_ypos = GET_Y_LPARAM (msg->lParam); + guint old_xpos, old_ypos; - clutter_actor_get_position (CLUTTER_ACTOR (stage), - &old_xpos, &old_ypos); + clutter_actor_get_position (CLUTTER_ACTOR (stage), + &old_xpos, &old_ypos); - if (new_xpos != old_xpos || new_ypos != old_ypos) - clutter_actor_set_position (CLUTTER_ACTOR (stage), - new_xpos, new_ypos); - } + if (new_xpos != old_xpos || new_ypos != old_ypos) + clutter_actor_set_position (CLUTTER_ACTOR (stage), + new_xpos, new_ypos); + } res = FALSE; break; diff --git a/clutter/win32/clutter-stage-win32.c b/clutter/win32/clutter-stage-win32.c index 54c8cef23..5d615f50c 100644 --- a/clutter/win32/clutter-stage-win32.c +++ b/clutter/win32/clutter-stage-win32.c @@ -206,7 +206,7 @@ clutter_stage_win32_request_coords (ClutterActor *self, stage_win32->win_width = new_width; stage_win32->win_height = new_height; - if (stage_win32->hwnd != NULL) + if (stage_win32->hwnd != NULL && !stage_win32->is_foreign_win) { int full_xpos, full_ypos, full_width, full_height; @@ -576,7 +576,7 @@ clutter_stage_win32_unrealize (ClutterActor *actor) stage_win32->client_dc = NULL; } - if (stage_win32->hwnd) + if (!stage_win32->is_foreign_win && 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 @@ -626,6 +626,7 @@ clutter_stage_win32_init (ClutterStageWin32 *stage) stage->win_height = 480; stage->backend = NULL; stage->scroll_pos = 0; + stage->is_foreign_win = FALSE; stage->wrapper = NULL; @@ -687,9 +688,86 @@ clutter_win32_get_stage_from_window (HWND hwnd) extra data */ return CLUTTER_STAGE_WIN32 (GetWindowLongPtrW (hwnd, 0))->wrapper; else - return NULL; + { + /* Otherwise it might be a foreign window so we should check the + stage list */ + ClutterMainContext *context = clutter_context_get_default (); + ClutterStageManager *stage_manager = context->stage_manager; + GSList *l; + + for (l = stage_manager->stages; l; l = l->next) + { + ClutterStage *stage = l->data; + ClutterStageWindow *impl; + + impl = _clutter_stage_get_window (stage); + g_assert (CLUTTER_IS_STAGE_WIN32 (impl)); + + if (CLUTTER_STAGE_WIN32 (impl)->hwnd == hwnd) + return stage; + } + } + + return NULL; } +/** + * clutter_win32_set_stage_foreign: + * @stage: a #ClutterStage + * @hwnd: an existing window handle + * + * Target the #ClutterStage to use an existing external window handle. + * + * Return value: %TRUE if foreign window is valid + * + * Since: 0.8 + */ +gboolean +clutter_win32_set_stage_foreign (ClutterStage *stage, + HWND hwnd) +{ + ClutterStageWin32 *stage_win32; + ClutterStageWindow *impl; + ClutterActor *actor; + RECT client_rect; + POINT window_pos; + ClutterGeometry geom; + + g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); + g_return_val_if_fail (hwnd != NULL, FALSE); + + actor = CLUTTER_ACTOR (stage); + + impl = _clutter_stage_get_window (stage); + stage_win32 = CLUTTER_STAGE_WIN32 (impl); + + clutter_actor_unrealize (actor); + + if (!GetClientRect (hwnd, &client_rect)) + { + g_warning ("Unable to retrieve the new window geometry"); + return FALSE; + } + window_pos.x = client_rect.left; + window_pos.y = client_rect.right; + ClientToScreen (hwnd, &window_pos); + + CLUTTER_NOTE (BACKEND, "Setting foreign window (0x%x)", (int) hwnd); + + stage_win32->hwnd = hwnd; + stage_win32->is_foreign_win = TRUE; + + geom.x = window_pos.x; + geom.y = window_pos.y; + geom.width = client_rect.right - client_rect.left; + geom.height = client_rect.bottom - client_rect.top; + + clutter_actor_set_geometry (actor, &geom); + clutter_actor_realize (actor); + + return TRUE; +} + 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 eff18cd1f..9d009e4b0 100644 --- a/clutter/win32/clutter-stage-win32.h +++ b/clutter/win32/clutter-stage-win32.h @@ -52,6 +52,7 @@ struct _ClutterStageWin32 gint win_height; gint scroll_pos; RECT fullscreen_rect; + gboolean is_foreign_win; ClutterBackendWin32 *backend; ClutterStageState state; diff --git a/clutter/win32/clutter-win32.h b/clutter/win32/clutter-win32.h index df416e640..b4cb47e97 100644 --- a/clutter/win32/clutter-win32.h +++ b/clutter/win32/clutter-win32.h @@ -43,8 +43,13 @@ G_BEGIN_DECLS -HWND clutter_win32_get_stage_window (ClutterStage *stage); -ClutterStage *clutter_win32_get_stage_from_window (HWND hwnd); +HWND clutter_win32_get_stage_window (ClutterStage *stage); +ClutterStage *clutter_win32_get_stage_from_window (HWND hwnd); + +gboolean clutter_win32_set_stage_foreign (ClutterStage *stage, + HWND hwnd); + +void clutter_win32_disable_event_retrieval (void); G_END_DECLS