Release Clutter 1.11.4 (snapshot)
[profile/ivi/clutter.git] / clutter / clutter-content.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Copyright (C) 2011  Intel Corporation.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20  *
21  * Author:
22  *   Emmanuele Bassi <ebassi@linux.intel.com>
23  */
24
25 /**
26  * SECTION:clutter-content
27  * @Title: ClutterContent
28  * @Short_Description: Delegate for painting the content of an actor
29  *
30  * #ClutterContent is an interface to implement types responsible for
31  * painting the content of a #ClutterActor.
32  *
33  * Multiple actors can use the same #ClutterContent instance, in order
34  * to share the resources associated with painting the same content.
35  *
36  * #ClutterContent is available since Clutter 1.10.
37  */
38
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42
43 #include "clutter-content-private.h"
44
45 #include "clutter-debug.h"
46 #include "clutter-marshal.h"
47 #include "clutter-private.h"
48
49 typedef struct _ClutterContentIface     ClutterContentInterface;
50
51 enum
52 {
53   ATTACHED,
54   DETACHED,
55
56   LAST_SIGNAL
57 };
58
59 static GQuark quark_content_actors = 0;
60
61 static guint content_signals[LAST_SIGNAL] = { 0, };
62
63 G_DEFINE_INTERFACE (ClutterContent, clutter_content, G_TYPE_OBJECT)
64
65 static gboolean
66 clutter_content_real_get_preferred_size (ClutterContent *content,
67                                          gfloat         *width,
68                                          gfloat         *height)
69 {
70   if (width != NULL)
71     *width = 0.f;
72
73   if (height != NULL)
74     *height = 0.f;
75
76   return FALSE;
77 }
78
79 static void
80 clutter_content_real_attached (ClutterContent *content,
81                                ClutterActor   *actor)
82 {
83 }
84
85 static void
86 clutter_content_real_detached (ClutterContent *content,
87                                ClutterActor   *actor)
88 {
89 }
90
91 static void
92 clutter_content_real_invalidate (ClutterContent *content)
93 {
94 }
95
96 static void
97 clutter_content_real_paint_content (ClutterContent   *content,
98                                     ClutterActor     *actor,
99                                     ClutterPaintNode *context)
100 {
101 }
102
103 static void
104 clutter_content_default_init (ClutterContentInterface *iface)
105 {
106   quark_content_actors = g_quark_from_static_string ("-clutter-content-actors");
107
108   iface->get_preferred_size = clutter_content_real_get_preferred_size;
109   iface->paint_content = clutter_content_real_paint_content;
110   iface->attached = clutter_content_real_attached;
111   iface->detached = clutter_content_real_detached;
112   iface->invalidate = clutter_content_real_invalidate;
113
114   /**
115    * ClutterContent::attached:
116    * @content: the object that emitted the signal
117    * @actor: a #ClutterActor
118    *
119    * This signal is emitted each time a #ClutterContent implementation is
120    * assigned to a #ClutterActor.
121    *
122    * Since: 1.10
123    */
124   content_signals[ATTACHED] =
125     g_signal_new (I_("attached"),
126                   G_TYPE_FROM_INTERFACE (iface),
127                   G_SIGNAL_RUN_FIRST,
128                   G_STRUCT_OFFSET (ClutterContentIface, attached),
129                   NULL, NULL,
130                   _clutter_marshal_VOID__OBJECT,
131                   G_TYPE_NONE, 1,
132                   CLUTTER_TYPE_ACTOR);
133
134   /**
135    * ClutterContent::detached:
136    * @content: the object that emitted the signal
137    * @actor: a #ClutterActor
138    *
139    * This signal is emitted each time a #ClutterContent implementation is
140    * removed from a #ClutterActor.
141    *
142    * Since: 1.10
143    */
144   content_signals[DETACHED] =
145     g_signal_new (I_("detached"),
146                   G_TYPE_FROM_INTERFACE (iface),
147                   G_SIGNAL_RUN_FIRST,
148                   G_STRUCT_OFFSET (ClutterContentIface, detached),
149                   NULL, NULL,
150                   _clutter_marshal_VOID__OBJECT,
151                   G_TYPE_NONE, 1,
152                   CLUTTER_TYPE_ACTOR);
153 }
154
155 /**
156  * clutter_content_invalidate:
157  * @content: a #ClutterContent
158  *
159  * Invalidates a #ClutterContent.
160  *
161  * This function should be called by #ClutterContent implementations when
162  * they change the way a the content should be painted regardless of the
163  * actor state.
164  *
165  * Since: 1.10
166  */
167 void
168 clutter_content_invalidate (ClutterContent *content)
169 {
170   GHashTable *actors;
171   GHashTableIter iter;
172   gpointer key_p, value_p;
173
174   g_return_if_fail (CLUTTER_IS_CONTENT (content));
175
176   CLUTTER_CONTENT_GET_IFACE (content)->invalidate (content);
177
178   actors = g_object_get_qdata (G_OBJECT (content), quark_content_actors);
179   if (actors == NULL)
180     return;
181
182   g_hash_table_iter_init (&iter, actors);
183   while (g_hash_table_iter_next (&iter, &key_p, &value_p))
184     {
185       ClutterActor *actor = key_p;
186
187       g_assert (actor != NULL);
188
189       clutter_actor_queue_redraw (actor);
190     }
191 }
192
193 /*< private >
194  * _clutter_content_attached:
195  * @content: a #ClutterContent
196  * @actor: a #ClutterActor
197  *
198  * Attaches @actor to the @content.
199  *
200  * This function should be used internally every time a #ClutterActor
201  * is associated to a #ClutterContent, to set up a backpointer from
202  * the @content to the @actor.
203  *
204  * This function will invoke the #ClutterContentIface.attached() virtual
205  * function.
206  */
207 void
208 _clutter_content_attached (ClutterContent *content,
209                            ClutterActor   *actor)
210 {
211   GObject *obj = G_OBJECT (content);
212   GHashTable *actors;
213
214   actors = g_object_get_qdata (obj, quark_content_actors);
215   if (actors == NULL)
216     {
217       actors = g_hash_table_new (NULL, NULL);
218       g_object_set_qdata_full (obj, quark_content_actors,
219                                actors,
220                                (GDestroyNotify) g_hash_table_unref);
221     }
222
223   g_hash_table_insert (actors, actor, actor);
224
225   g_signal_emit (content, content_signals[ATTACHED], 0, actor);
226 }
227
228 /*< private >
229  * _clutter_content_detached:
230  * @content: a #ClutterContent
231  * @actor: a #ClutterActor
232  *
233  * Detaches @actor from @content.
234  *
235  * This function should be used internally every time a #ClutterActor
236  * removes the association with a #ClutterContent.
237  *
238  * This function will invoke the #ClutterContentIface.detached() virtual
239  * function.
240  */
241 void
242 _clutter_content_detached (ClutterContent *content,
243                            ClutterActor   *actor)
244 {
245   GObject *obj = G_OBJECT (content);
246   GHashTable *actors;
247
248   actors = g_object_get_qdata (obj, quark_content_actors);
249   g_assert (actors != NULL);
250
251   g_hash_table_remove (actors, actor);
252
253   if (g_hash_table_size (actors) == 0)
254     g_object_set_qdata (obj, quark_content_actors, NULL);
255
256   g_signal_emit (content, content_signals[DETACHED], 0, actor);
257 }
258
259 /*< private >
260  * _clutter_content_paint_content:
261  * @content: a #ClutterContent
262  * @actor: a #ClutterActor
263  * @context: a #ClutterPaintNode
264  *
265  * Creates the render tree for the @content and @actor.
266  *
267  * This function will invoke the #ClutterContentIface.paint_content()
268  * virtual function.
269  */
270 void
271 _clutter_content_paint_content (ClutterContent   *content,
272                                 ClutterActor     *actor,
273                                 ClutterPaintNode *node)
274 {
275   CLUTTER_CONTENT_GET_IFACE (content)->paint_content (content, actor, node);
276 }
277
278 /**
279  * clutter_content_get_preferred_size:
280  * @content: a #ClutterContent
281  * @width: (out): return location for the natural width of the content
282  * @height: (out): return location for the natural height of the content
283  *
284  * Retrieves the natural size of the @content, if any.
285  *
286  * The natural size of a #ClutterContent is defined as the size the content
287  * would have regardless of the allocation of the actor that is painting it,
288  * for instance the size of an image data.
289  *
290  * Return value: %TRUE if the content has a preferred size, and %FALSE
291  *   otherwise
292  *
293  * Since: 1.10
294  */
295 gboolean
296 clutter_content_get_preferred_size (ClutterContent *content,
297                                     gfloat         *width,
298                                     gfloat         *height)
299 {
300   g_return_val_if_fail (CLUTTER_IS_CONTENT (content), FALSE);
301
302   return CLUTTER_CONTENT_GET_IFACE (content)->get_preferred_size (content,
303                                                                   width,
304                                                                   height);
305 }