/* gtk-clutter-window.c: GtkWindow which provides a hidden ClutterStage * * Copyright (C) 2009 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not see . * * Authors: * Danielle Madeley */ /** * SECTION:gtk-clutter-window * @Title: GtkClutterWindow * @short_description: a GtkWindow that embeds its contents onto a stage * * #GtkClutterWindow is a #GtkWindow sub-class that embeds a Clutter stage. * * #GtkClutterWindow behaves exactly like a #GtkWindow, except that its * child is automatically embedded inside a #GtkClutterActor and it is * thus part of the embedded #ClutterStage. * * Clutter actors can be added to the same stage by calling * gtk_clutter_window_get_stage(). */ #include "config.h" #include "gtk-clutter-window.h" #include "gtk-clutter-actor.h" #include "gtk-clutter-embed.h" #include "gtk-clutter-util.h" #include G_DEFINE_TYPE (GtkClutterWindow, gtk_clutter_window, GTK_TYPE_WINDOW); #define GTK_CLUTTER_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_CLUTTER_TYPE_WINDOW, GtkClutterWindowPrivate)) struct _GtkClutterWindowPrivate { GtkWidget *embed; ClutterActor *actor; }; static void gtk_clutter_window_finalize (GObject *self) { G_OBJECT_CLASS (gtk_clutter_window_parent_class)->finalize (self); } static void gtk_clutter_window_get_preferred_width (GtkWidget *self, gint *minimum, gint *natural) { GtkClutterWindowPrivate *priv = GTK_CLUTTER_WINDOW (self)->priv; GtkWidget *bin; bin = gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (priv->actor)); gtk_widget_get_preferred_width (gtk_bin_get_child (GTK_BIN (bin)), minimum, natural); } static void gtk_clutter_window_get_preferred_height (GtkWidget *self, gint *minimum, gint *natural) { GtkClutterWindowPrivate *priv = GTK_CLUTTER_WINDOW (self)->priv; GtkWidget *bin; bin = gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (priv->actor)); gtk_widget_get_preferred_height (gtk_bin_get_child (GTK_BIN (bin)), minimum, natural); } static void gtk_clutter_window_add (GtkContainer *self, GtkWidget *widget) { GtkClutterWindowPrivate *priv; GtkWidget *bin; g_return_if_fail (GTK_CLUTTER_IS_WINDOW (self)); priv = GTK_CLUTTER_WINDOW (self)->priv; bin = gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (priv->actor)); GTK_CONTAINER_GET_CLASS (bin)->add (GTK_CONTAINER (bin), widget); } static void gtk_clutter_window_remove (GtkContainer *self, GtkWidget *widget) { GtkClutterWindowPrivate *priv; GtkWidget *bin; g_return_if_fail (GTK_CLUTTER_IS_WINDOW (self)); priv = GTK_CLUTTER_WINDOW (self)->priv; bin = gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (priv->actor)); GTK_CONTAINER_GET_CLASS (bin)->remove (GTK_CONTAINER (bin), widget); } static void gtk_clutter_window_forall (GtkContainer *self, gboolean include_internals, GtkCallback callback, gpointer callback_data) { GtkClutterWindowPrivate *priv; GtkWidget *bin; g_return_if_fail (GTK_CLUTTER_IS_WINDOW (self)); priv = GTK_CLUTTER_WINDOW (self)->priv; /* this is particularly dodgy -- if we have asked to include_internals * let's only return the internals, on the assumption that when events * are sent to those internals, the child container will be iterated; * otherwise, we don't want anyone to know about the container, so we * return the contents of the bin */ if (include_internals) { GTK_CONTAINER_CLASS (gtk_clutter_window_parent_class)->forall (self, include_internals, callback, callback_data); } else { bin = gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (priv->actor)); GTK_CONTAINER_GET_CLASS (bin)->forall (GTK_CONTAINER (bin), include_internals, callback, callback_data); } } static void gtk_clutter_window_set_focus_child (GtkContainer *self, GtkWidget *widget) { GtkClutterWindowPrivate *priv; GtkWidget *bin; g_return_if_fail (GTK_CLUTTER_IS_WINDOW (self)); priv = GTK_CLUTTER_WINDOW (self)->priv; bin = gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (priv->actor)); GTK_CONTAINER_GET_CLASS (bin)->set_focus_child (GTK_CONTAINER (bin), widget); } static GType gtk_clutter_window_child_type (GtkContainer *self) { GtkClutterWindowPrivate *priv; GtkWidget *bin; priv = GTK_CLUTTER_WINDOW (self)->priv; bin = gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (priv->actor)); return GTK_CONTAINER_GET_CLASS (bin)->child_type (GTK_CONTAINER (bin)); } static char * gtk_clutter_window_composite_name (GtkContainer *self, GtkWidget *widget) { GtkClutterWindowPrivate *priv; GtkWidget *bin; priv = GTK_CLUTTER_WINDOW (self)->priv; bin = gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (priv->actor)); return GTK_CONTAINER_GET_CLASS (bin)->composite_name (GTK_CONTAINER (bin), widget); } static void gtk_clutter_window_set_child_property (GtkContainer *self, GtkWidget *widget, guint property_id, const GValue *value, GParamSpec *pspec) { GtkClutterWindowPrivate *priv; GtkWidget *bin; priv = GTK_CLUTTER_WINDOW (self)->priv; bin = gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (priv->actor)); GTK_CONTAINER_GET_CLASS (bin)->set_child_property (GTK_CONTAINER (bin), widget, property_id, value, pspec); } static void gtk_clutter_window_get_child_property (GtkContainer *self, GtkWidget *widget, guint property_id, GValue *value, GParamSpec *pspec) { GtkClutterWindowPrivate *priv; GtkWidget *bin; priv = GTK_CLUTTER_WINDOW (self)->priv; bin = gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (priv->actor)); GTK_CONTAINER_GET_CLASS (bin)->get_child_property (GTK_CONTAINER (bin), widget, property_id, value, pspec); } static void gtk_clutter_window_class_init (GtkClutterWindowClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); g_type_class_add_private (klass, sizeof (GtkClutterWindowPrivate)); gobject_class->finalize = gtk_clutter_window_finalize; widget_class->get_preferred_width = gtk_clutter_window_get_preferred_width; widget_class->get_preferred_height = gtk_clutter_window_get_preferred_height; /* connect all of the container methods up to our bin */ container_class->add = gtk_clutter_window_add; container_class->remove = gtk_clutter_window_remove; container_class->forall = gtk_clutter_window_forall; container_class->set_focus_child = gtk_clutter_window_set_focus_child; container_class->child_type = gtk_clutter_window_child_type; container_class->composite_name = gtk_clutter_window_composite_name; container_class->set_child_property = gtk_clutter_window_set_child_property; container_class->get_child_property = gtk_clutter_window_get_child_property; } static void gtk_clutter_window_init (GtkClutterWindow *self) { GtkClutterWindowPrivate *priv; ClutterActor *stage; self->priv = priv = GTK_CLUTTER_WINDOW_GET_PRIVATE (self); priv->embed = gtk_clutter_embed_new (); gtk_widget_set_name (priv->embed, "GtkClutterEmbed"); GTK_CONTAINER_CLASS (gtk_clutter_window_parent_class)->add (GTK_CONTAINER (self), priv->embed); gtk_widget_show (priv->embed); stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (priv->embed)); priv->actor = gtk_clutter_actor_new (); clutter_actor_add_child (stage, priv->actor); clutter_actor_set_name (priv->actor, "GtkClutterActor"); clutter_actor_add_constraint_with_name (priv->actor, "content-x", clutter_bind_constraint_new (stage, CLUTTER_BIND_WIDTH, 0.0)); clutter_actor_add_constraint_with_name (priv->actor, "content-y", clutter_bind_constraint_new (stage, CLUTTER_BIND_HEIGHT, 0.0)); } /** * gtk_clutter_window_new: * * Creates a new #GtkClutterWindow widget. * * This window provides a hidden #ClutterStage on which the child * #GtkWidgets are placed. This allows other #ClutterActors * to also be placed on the stage. * * Return value: the newly created #GtkClutterWindow */ GtkWidget * gtk_clutter_window_new (void) { return g_object_new (GTK_CLUTTER_TYPE_WINDOW, NULL); } /** * gtk_clutter_window_get_stage: * @window: the #GtkClutterWindow * * Retrieves the #ClutterStage that this window is embedding * * Use this function if you wish to add other actors to the #ClutterStage. * * Return value: (transfer none): the window's #ClutterStage */ ClutterActor * gtk_clutter_window_get_stage (GtkClutterWindow *window) { GtkClutterWindowPrivate *priv; g_return_val_if_fail (GTK_CLUTTER_IS_WINDOW (window), NULL); priv = window->priv; return gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (priv->embed)); }