/** * clutter_gdk_set_stage_foreign: * @stage: a #ClutterStage * @window: an existing #GdkWindow * * Target the #ClutterStage to use an existing external #GdkWindow * * Return value: %TRUE if foreign window is valid * * Since: 1.10 */ gboolean clutter_gdk_set_stage_foreign (ClutterStage *stage, GdkWindow *window) { ForeignWindowClosure closure; ClutterStageGdk *stage_gdk; ClutterStageWindow *impl; ClutterActor *actor; g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); g_return_val_if_fail (!CLUTTER_ACTOR_IN_DESTRUCTION (stage), FALSE); g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); impl = _clutter_stage_get_window (stage); if (!CLUTTER_IS_STAGE_GDK (impl)) { g_critical ("The Clutter backend is not a GDK backend"); return FALSE; } stage_gdk = CLUTTER_STAGE_GDK (impl); if (g_object_get_data (G_OBJECT (window), "clutter-stage-window") != NULL) { g_critical ("The provided GdkWindow is already in use by another ClutterStage"); return FALSE; } closure.stage_gdk = stage_gdk; closure.window = g_object_ref (window); actor = CLUTTER_ACTOR (stage); _clutter_actor_rerealize (actor, set_foreign_window_callback, &closure); /* Queue a relayout - so the stage will be allocated the new * window size. * * Note also that when the stage gets allocated the new * window size that will result in the stage's * priv->viewport being changed, which will in turn result * in the Cogl viewport changing when _clutter_do_redraw * calls _clutter_stage_maybe_setup_viewport(). */ clutter_actor_queue_relayout (actor); return TRUE; }
static void clutter_stage_gdk_set_fullscreen (ClutterStageWindow *stage_window, gboolean is_fullscreen) { ClutterStageGdk *stage_gdk = CLUTTER_STAGE_GDK (stage_window); ClutterStage *stage = CLUTTER_STAGE_COGL (stage_window)->wrapper; if (stage == NULL || CLUTTER_ACTOR_IN_DESTRUCTION (stage)) return; if (stage_gdk->window == NULL) return; CLUTTER_NOTE (BACKEND, "%ssetting fullscreen", is_fullscreen ? "" : "un"); if (is_fullscreen) gdk_window_fullscreen (stage_gdk->window); else gdk_window_unfullscreen (stage_gdk->window); }
static void clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window, gboolean is_fullscreen) { ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); ClutterStage *stage = stage_cogl->wrapper; gboolean was_fullscreen; if (stage == NULL || CLUTTER_ACTOR_IN_DESTRUCTION (stage)) return; was_fullscreen = _clutter_stage_is_fullscreen (stage); is_fullscreen = !!is_fullscreen; if (was_fullscreen == is_fullscreen) return; CLUTTER_NOTE (BACKEND, "%ssetting fullscreen", is_fullscreen ? "" : "un"); if (is_fullscreen) { #if 0 int width, height; /* FIXME: this will do the wrong thing for dual-headed displays. This will return the size of the combined display but Metacity (at least) will fullscreen to only one of the displays. This will cause the actor to report the wrong size until the ConfigureNotify for the correct size is received */ width = DisplayWidth (backend_x11->xdpy, backend_x11->xscreen_num); height = DisplayHeight (backend_x11->xdpy, backend_x11->xscreen_num); #endif /* Set the fullscreen hint so we can retain the old size of the window. */ stage_x11->fullscreening = TRUE; if (stage_x11->xwin != None) { /* if the actor is not mapped we resize the stage window to match * the size of the screen; this is useful for e.g. EGLX to avoid * a resize when calling clutter_stage_fullscreen() before showing * the stage */ if (!STAGE_X11_IS_MAPPED (stage_x11)) { CLUTTER_NOTE (BACKEND, "Fullscreening unmapped stage"); update_state (stage_x11, backend_x11, &backend_x11->atom_NET_WM_STATE_FULLSCREEN, TRUE); } else { CLUTTER_NOTE (BACKEND, "Fullscreening mapped stage"); /* We need to fix the window size so that it will remove the maximum and minimum window hints. Otherwise metacity will honour the restrictions and not fullscreen correctly. */ clutter_stage_x11_fix_window_size (stage_x11, -1, -1); send_wmspec_change_state (backend_x11, stage_x11->xwin, backend_x11->atom_NET_WM_STATE_FULLSCREEN, TRUE); } } else stage_x11->fullscreen_on_realize = TRUE; } else { stage_x11->fullscreening = FALSE; if (stage_x11->xwin != None) { if (!STAGE_X11_IS_MAPPED (stage_x11)) { CLUTTER_NOTE (BACKEND, "Un-fullscreening unmapped stage"); update_state (stage_x11, backend_x11, &backend_x11->atom_NET_WM_STATE_FULLSCREEN, FALSE); } else { CLUTTER_NOTE (BACKEND, "Un-fullscreening mapped stage"); send_wmspec_change_state (backend_x11, stage_x11->xwin, backend_x11->atom_NET_WM_STATE_FULLSCREEN, FALSE); /* Fix the window size to restore the minimum/maximum restriction */ clutter_stage_x11_fix_window_size (stage_x11, stage_x11->xwin_width, stage_x11->xwin_height); } } else stage_x11->fullscreen_on_realize = FALSE; } /* XXX: Note we rely on the ConfigureNotify mechanism as the common * mechanism to handle notifications of new X window sizes from the * X server so we don't actively change the stage viewport here or * queue a relayout etc. */ }
/** * clutter_x11_set_stage_foreign: * @stage: a #ClutterStage * @xwindow: an existing X Window id * * Target the #ClutterStage to use an existing external X Window * * Return value: %TRUE if foreign window is valid * * */ gboolean clutter_x11_set_stage_foreign (ClutterStage *stage, Window xwindow) { ClutterBackendX11 *backend_x11; ClutterStageX11 *stage_x11; ClutterStageCogl *stage_cogl; ClutterStageWindow *impl; ClutterActor *actor; gint x, y; guint width, height, border, depth; Window root_return; Status status; ForeignWindowData fwd; XVisualInfo *xvisinfo; g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); g_return_val_if_fail (!CLUTTER_ACTOR_IN_DESTRUCTION (stage), FALSE); g_return_val_if_fail (xwindow != None, FALSE); impl = _clutter_stage_get_window (stage); stage_x11 = CLUTTER_STAGE_X11 (impl); stage_cogl = CLUTTER_STAGE_COGL (impl); backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend); xvisinfo = _clutter_backend_x11_get_visual_info (backend_x11); g_return_val_if_fail (xvisinfo != NULL, FALSE); clutter_x11_trap_x_errors (); status = XGetGeometry (backend_x11->xdpy, xwindow, &root_return, &x, &y, &width, &height, &border, &depth); if (clutter_x11_untrap_x_errors () || !status) { g_critical ("Unable to retrieve the geometry of the foreign window: " "XGetGeometry() failed (status code: %d)", status); return FALSE; } if (width == 0 || height == 0) { g_warning ("The size of the foreign window is 0x0"); return FALSE; } if (depth != xvisinfo->depth) { g_warning ("The depth of the visual of the foreign window is %d, but " "Clutter has been initialized to require a visual depth " "of %d", depth, xvisinfo->depth); return FALSE; } fwd.stage_x11 = stage_x11; fwd.xwindow = xwindow; /* destroy the old Window, if we have one and it's ours */ if (stage_x11->xwin != None && !stage_x11->is_foreign_xwin) fwd.destroy_old_xwindow = TRUE; else fwd.destroy_old_xwindow = FALSE; fwd.geom.x = x; fwd.geom.y = y; fwd.geom.width = width; fwd.geom.height = height; actor = CLUTTER_ACTOR (stage); _clutter_actor_rerealize (actor, set_foreign_window_callback, &fwd); /* Queue a relayout - so the stage will be allocated the new * window size. * * Note also that when the stage gets allocated the new * window size that will result in the stage's * priv->viewport being changed, which will in turn result * in the Cogl viewport changing when _clutter_do_redraw * calls _clutter_stage_maybe_setup_viewport(). */ clutter_actor_queue_relayout (actor); return TRUE; }