d8cf5a97d49dc2e22ec01c9b3522b186bcfdfa6c
[clutter-gtk] / clutter-gtk / clutter-gtk.c
1 /*
2  * Clutter-Gtk
3  *
4  * GTK+ widget for Clutter.
5  *
6  * Authored By Iain Holmes  <iain@openedhand.com>
7  *
8  * Copyright (C) 2006 OpenedHand
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */
25
26 /**
27  * SECTION:gtk-clutter
28  * @short_description: GTK+ widget displaying a #ClutterStage.
29  *
30  * #GtkClutter is a GTK+ widget, derived from #GtkSocket, that contains a
31  * #ClutterStage, allowing it to be used in a GTK+ based program like any 
32  * normal GTK+ widget.
33  */
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #include <gdk/gdkx.h>
40
41 #include <gtk/gtkwidget.h>
42
43 #include <clutter/clutter-main.h>
44 #include <clutter/clutter-stage.h>
45 #include <clutter/clutter-x11.h>
46
47 #include "clutter-gtk.h"
48
49 #define GTK_CLUTTER_GET_PRIVATE(obj) \
50 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CLUTTER, GtkClutterPrivate))
51
52 struct _GtkClutterPrivate
53 {
54   ClutterActor *stage;
55
56   guint is_embedded : 1;
57 };
58
59 enum
60 {
61   PROP_0,
62
63   PROP_EMBEDDED
64 };
65
66 G_DEFINE_TYPE (GtkClutter, gtk_clutter, GTK_TYPE_SOCKET);
67
68 static void
69 gtk_clutter_destroy (GtkObject *object)
70 {
71   GtkClutterPrivate *priv;
72
73   priv = GTK_CLUTTER (object)->priv;
74
75   /* XXX - there's no clutter main loop running, so we cannot
76    * release the resources we create when we initialise clutter.
77    */
78   if (priv->stage)
79     priv->stage = NULL;
80
81   GTK_OBJECT_CLASS (gtk_clutter_parent_class)->destroy (object);
82 }
83
84 static void
85 gtk_clutter_size_allocate (GtkWidget     *widget,
86                            GtkAllocation *allocation)
87 {
88   GtkClutterPrivate *priv = GTK_CLUTTER (widget)->priv;
89
90   clutter_actor_set_size (priv->stage,
91                           allocation->width,
92                           allocation->height);
93
94   if (CLUTTER_ACTOR_IS_VISIBLE (priv->stage))
95     clutter_actor_queue_redraw (priv->stage);
96
97   GTK_WIDGET_CLASS (gtk_clutter_parent_class)->size_allocate (widget, 
98                                                               allocation);
99 }
100
101 static void
102 gtk_clutter_size_request (GtkWidget      *widget,
103                           GtkRequisition *req)
104 {
105   GtkClutterPrivate *priv;
106
107   priv = GTK_CLUTTER (widget)->priv;
108
109   req->width = clutter_actor_get_width (priv->stage);
110   req->height = clutter_actor_get_height (priv->stage);
111 }
112
113 static void
114 gtk_clutter_map (GtkWidget *widget)
115 {
116   GtkSocket *socket = GTK_SOCKET (widget);
117   GtkClutterPrivate *priv = GTK_CLUTTER (widget)->priv;
118   ClutterStage *stage = CLUTTER_STAGE (priv->stage);
119
120   if (!priv->is_embedded)
121     {
122       g_object_ref (widget);
123
124       gtk_socket_add_id (socket, clutter_x11_get_stage_window (stage)); 
125       priv->is_embedded = TRUE;
126
127       g_object_notify (G_OBJECT (widget), "embedded");
128       g_object_unref (widget);
129     }
130
131   GTK_WIDGET_CLASS (gtk_clutter_parent_class)->map (widget);
132 }
133
134 static void
135 gtk_clutter_get_property (GObject    *gobject,
136                           guint       prop_id,
137                           GValue     *value,
138                           GParamSpec *pspec)
139 {
140   GtkClutter *gtk_clutter = GTK_CLUTTER (gobject);
141
142   switch (prop_id)
143     {
144     case PROP_EMBEDDED:
145       g_value_set_boolean (value, gtk_clutter->priv->is_embedded);
146       break;
147     default:
148       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
149       break;
150     }
151 }
152
153 static void
154 gtk_clutter_class_init (GtkClutterClass *klass)
155 {
156   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
157   GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
158   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
159
160   gobject_class->get_property = gtk_clutter_get_property;
161
162   object_class->destroy = gtk_clutter_destroy;
163
164   widget_class->size_request = gtk_clutter_size_request;
165   widget_class->size_allocate = gtk_clutter_size_allocate;
166   widget_class->map = gtk_clutter_map;
167
168   g_object_class_install_property (gobject_class,
169                                    PROP_EMBEDDED,
170                                    g_param_spec_boolean ("embedded",
171                                                          "Embedded",
172                                                          "Whether the stage has been successfully embedded",
173                                                          FALSE,
174                                                          G_PARAM_READABLE));
175
176   g_type_class_add_private (gobject_class, sizeof (GtkClutterPrivate));
177 }
178
179 static void
180 gtk_clutter_init (GtkClutter *clutter)
181 {
182   GtkClutterPrivate *priv;
183
184   clutter->priv = priv = GTK_CLUTTER_GET_PRIVATE (clutter);
185
186   gtk_widget_set_double_buffered (GTK_WIDGET (clutter), FALSE);
187   gtk_widget_set_app_paintable (GTK_WIDGET (clutter), TRUE);
188
189   priv->stage = clutter_stage_get_default ();
190   clutter_stage_set_user_resizable (CLUTTER_STAGE (priv->stage), TRUE);
191
192   priv->is_embedded = FALSE;
193 }
194
195 /**
196  * gtk_clutter_get_stage:
197  * @clutter: A #GtkClutter object.
198  *
199  * Obtains the #ClutterStage associated with this object.
200  *
201  * Return value: the main stage
202  */
203 ClutterActor *
204 gtk_clutter_get_stage (GtkClutter *clutter)
205 {
206   g_return_val_if_fail (GTK_IS_CLUTTER (clutter), NULL);
207
208   return clutter->priv->stage;
209 }
210
211 /**
212  * gtk_clutter_new:
213  * 
214  * Creates a new #GtkClutter widget. You can use this widget inside
215  * any GTK+ application. Once you added it to a container you should
216  * call gtk_clutter_get_stage() to obtain the #ClutterStage and add
217  * Clutter actors to it.
218  *
219  * All the mouse events will be forwarded to the stage.
220  *
221  * Return value: the newly created #GtkClutter widget
222  */
223 GtkWidget *
224 gtk_clutter_new (void)
225 {
226   return g_object_new (GTK_TYPE_CLUTTER, NULL);
227 }