834c4373ae635ee4333a09611a5eaa30ff8b8730
[hildon] / hildon / hildon-animation-actor.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2008 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Rodrigo Novo <rodrigo.novo@nokia.com>
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 License
10  * as published by the Free Software Foundation; version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * 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, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 /**
26  * SECTION:hildon-animation-window
27  * @short_description: Animation actor for
28  * WM-assisted animation effects in the Hildon framework.
29  *
30  * The #HildonAnimationActor is an
31  * animation actor for WM-assisted animation effects in the Hildon
32  * framework. It derives from #GtkWindow and can host any widgets much
33  * like a normal window. The special features available to the
34  * animation actor is the ability to set its position, scale factor
35  * and rotation. These parameters are interpreted by Hildon's
36  * compositing window manager to alter the on-screen representation of
37  * the animation actor window. Bear in mind, however, that by design
38  * decision, animation actors are not reactive -- the widgets placed
39  * in such window will not receive keyboard, motion or button
40  * events. Animation actors are input-transparent -- the input events
41  * will be sent to the underlying real windows and widgets.
42  *
43  * The animation actors may exist in a parented or an unparented
44  * state. To be displayed, animations actors must be parented to
45  * another top-level window widget. Animation actors display on top
46  * (in front) of the standard window contents unless the position
47  * (depth, z-coordinate) is specifically adjusted. Animation actors in
48  * an unparented state do not display at all.
49  *
50  * Parented animation actors are placed in the coordinate space of the
51  * parent window and visually become a part of the parent window
52  * iteslf -- they inherit the transformations and effects enforced by
53  * the window manager on the parent window (task switcher animations,
54  * minimize events, etc.).
55  *
56  * All animation actor settings (position, scale, rotation, opacity,
57  * depth) can be applied to unparented actors, but will only take
58  * effect as the actor is parented to a top-level window and that
59  * window is shown. All settings are preserved during
60  * unparenting/reparenting.
61  *
62  * The #HildonAnimationActor API closely follows the #ClutterActor
63  * API.  Please take a look at the #ClutterActor description for the
64  * modelview transformations order that applies to
65  * HildonAnimationActor and ClutterActor alike.
66  *
67  * Animation actor widget controls the animation actor as it is
68  * transformed by the window manager using ClientMessage X11
69  * events. It tries to minimize the amount of such events and couples
70  * conceptually related parameters (visibility and opacity, position
71  * and depth) to the same message.  The API, however, offers
72  * convenience functions for the programmer to be able to modify every
73  * parameter individually.
74  *
75  * <example>
76  * <title>Basic HildonAnimationActor example</title>
77  * <programlisting>
78  * static void
79  * animation_cb (void *obj)
80  * {
81  *     HildonAnimationActor *actor = HILDON_ANIMATION_ACTOR (obj);
82  * <!-- -->
83  *     static int x_inc = 1;
84  *     static int y_inc = 1;
85  *     static int x = 0;
86  *     static int y = 0;
87  *     static int r = 0;
88  * <!-- -->
89  *     if (((x_inc > 0) && (x > 800)) ||
90  *         ((x_inc < 0) && (x < 1)))
91  *         x_inc = -x_inc;
92  *     if (((y_inc > 0) && (y > 480)) ||
93  *         ((y_inc < 0) && (y < 1)))
94  *         y_inc = -y_inc;
95  * <!-- -->
96  *     x += x_inc;
97  *     y += y_inc;
98  *     r ++;
99  * <!-- -->
100  *     // Set animation actor position and rotation
101  *     hildon_animation_actor_set_position (actor, x, y);
102  *     hildon_animation_actor_set_rotation (actor,
103  *                                          HILDON_AA_Z_AXIS,
104  *                                          r,
105  *                                          0, 0, 0);
106  * }
107  * <!-- -->
108  * int
109  * main (int argc, char **argv)
110  * {
111  *     GtkWidget *win;
112  *     GtkWidget *image;
113  *     GtkWidget *actor;
114  * <!-- -->
115  *     gtk_init (&amp;argc, &amp;argv);
116  * <!-- -->
117  *     // ... set up a normal window
118  *     win = hildon_window_new ();
119  *     g_signal_connect (win, "destroy", G_CALLBACK (gtk_main_quit), NULL);
120  *     gtk_widget_show_all (win);
121  * <!-- -->
122  *     // ... load an image
123  *     image = gtk_image_new_from_file ("image.jpg");
124  * <!-- -->
125  *     actor = hildon_animation_actor_new();
126  *     gtk_container_add (GTK_CONTAINER (actor), image);
127  * <!-- -->
128  *     // Parent the animation actor
129  *     hildon_animation_actor_set_parent (HILDON_ANIMATION_ACTOR (actor), win);
130  * <!-- -->
131  *     // Set anchor point to the actor center
132  *     hildon_animation_actor_set_anchor_from_gravity (HILDON_ANIMATION_ACTOR (actor),
133                                                        HILDON_AA_CENTER_GRAVITY);
134  * <!-- -->
135  *     gtk_widget_show_all (actor);
136  * <!-- -->
137  *     // Set up animation
138  *     g_timeout_add (100, (GSourceFunc)animation_cb, actor);
139  * <!-- -->
140  *     gtk_main ();
141  * <!-- -->
142  *     return 0;
143  * }
144  * </programlisting>
145  * </example>
146  */
147
148 #include                                        <gdk/gdkx.h>
149 #include                                        <X11/Xatom.h>
150
151 #include                                        "hildon-animation-actor.h"
152 #include                                        "hildon-animation-actor-private.h"
153
154 G_DEFINE_TYPE (HildonAnimationActor, hildon_animation_actor, GTK_TYPE_WINDOW);
155
156 static GdkFilterReturn
157 hildon_animation_actor_event_filter (GdkXEvent *xevent,
158                                      GdkEvent *event,
159                                      gpointer data);
160 static void
161 hildon_animation_actor_update_ready (HildonAnimationActor *self);
162 static void
163 hildon_animation_actor_send_pending_messages (HildonAnimationActor *self);
164 static void
165 hildon_animation_actor_send_all_messages (HildonAnimationActor *self);
166 static gboolean
167 hildon_animation_actor_parent_map_event (GtkWidget *parent,
168                                          GdkEvent *event,
169                                          gpointer user_data);
170 static gboolean
171 hildon_animation_actor_map_event (GtkWidget *widget,
172                                   GdkEvent *event,
173                                   gpointer user_data);
174
175 static guint32 show_atom;
176 static guint32 position_atom;
177 static guint32 rotation_atom;
178 static guint32 scale_atom;
179 static guint32 anchor_atom;
180 static guint32 parent_atom;
181 static guint32 ready_atom;
182
183 static gboolean atoms_initialized = FALSE;
184
185 static void
186 hildon_animation_actor_realize                 (GtkWidget *widget)
187 {
188     GdkDisplay *display;
189     Atom wm_type, applet_type;
190
191     GTK_WIDGET_CLASS (hildon_animation_actor_parent_class)->realize (widget);
192
193     /* Set animation actor window type. */
194
195     display = gdk_drawable_get_display (widget->window);
196
197     wm_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE");
198     applet_type = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_WM_WINDOW_TYPE_ANIMATION_ACTOR");
199
200     XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (widget->window), wm_type,
201                      XA_ATOM, 32, PropModeReplace,
202                      (unsigned char *) &applet_type, 1);
203
204     /* This is a bit of a hack, but for the sake of speed (it is assumed that
205      * once HildonAnimationActor is created, a lot of ClientMessages will
206      * follow), we cache all ClientMessages atoms in static variables. */
207
208     if (!atoms_initialized)
209     {
210         show_atom =
211             gdk_x11_get_xatom_by_name_for_display
212             (display, "_HILDON_ANIMATION_CLIENT_MESSAGE_SHOW");
213         position_atom =
214             gdk_x11_get_xatom_by_name_for_display
215             (display, "_HILDON_ANIMATION_CLIENT_MESSAGE_POSITION");
216         rotation_atom =
217             gdk_x11_get_xatom_by_name_for_display
218             (display, "_HILDON_ANIMATION_CLIENT_MESSAGE_ROTATION");
219         scale_atom =
220             gdk_x11_get_xatom_by_name_for_display
221             (display, "_HILDON_ANIMATION_CLIENT_MESSAGE_SCALE");
222         anchor_atom =
223             gdk_x11_get_xatom_by_name_for_display
224             (display, "_HILDON_ANIMATION_CLIENT_MESSAGE_ANCHOR");
225         parent_atom =
226             gdk_x11_get_xatom_by_name_for_display
227             (display, "_HILDON_ANIMATION_CLIENT_MESSAGE_PARENT");
228         ready_atom =
229             gdk_x11_get_xatom_by_name_for_display
230             (display, "_HILDON_ANIMATION_CLIENT_READY");
231 #if 0
232         g_debug ("show atom = %lu\n", show_atom);
233         g_debug ("position atom = %lu\n", position_atom);
234         g_debug ("rotation atom = %lu\n", rotation_atom);
235         g_debug ("scale atom = %lu\n", scale_atom);
236         g_debug ("anchor atom = %lu\n", anchor_atom);
237         g_debug ("parent atom = %lu\n", parent_atom);
238         g_debug ("ready atom = %lu\n", ready_atom);
239 #endif
240
241         atoms_initialized = TRUE;
242     }
243
244     /* Wait for a ready message */
245
246     gdk_window_add_filter (widget->window,
247                            hildon_animation_actor_event_filter,
248                            widget);
249 }
250
251 static void
252 hildon_animation_actor_unrealize               (GtkWidget *widget)
253 {
254     gdk_window_remove_filter (widget->window,
255                               hildon_animation_actor_event_filter,
256                               widget);
257
258     GTK_WIDGET_CLASS (hildon_animation_actor_parent_class)->unrealize (widget);
259 }
260
261 static void
262 hildon_animation_actor_show                    (GtkWidget *widget)
263 {
264     HildonAnimationActor        *self = HILDON_ANIMATION_ACTOR (widget);
265
266     GTK_WIDGET_CLASS (hildon_animation_actor_parent_class)->show (widget);
267     hildon_animation_actor_set_show (self, 1);
268 }
269
270 static void
271 hildon_animation_actor_hide                    (GtkWidget *widget)
272 {
273     HildonAnimationActor        *self = HILDON_ANIMATION_ACTOR (widget);
274
275     hildon_animation_actor_set_show (self, 0);
276     GTK_WIDGET_CLASS (hildon_animation_actor_parent_class)->hide (widget);
277 }
278
279 static void
280 hildon_animation_actor_finalize                (GObject *object)
281 {
282     HildonAnimationActor        *self = HILDON_ANIMATION_ACTOR (object);
283     HildonAnimationActorPrivate
284                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
285
286     if (priv->parent)
287     {
288         if (priv->parent_map_event_cb_id)
289             g_signal_handler_disconnect (priv->parent,
290                                          priv->parent_map_event_cb_id);
291
292         g_object_unref (priv->parent);
293     }
294 }
295
296 static void
297 hildon_animation_actor_class_init              (HildonAnimationActorClass *klass)
298 {
299     GObjectClass      *gobject_class = G_OBJECT_CLASS (klass);
300     GtkWidgetClass    *widget_class = GTK_WIDGET_CLASS (klass);
301
302     gobject_class->finalize         = hildon_animation_actor_finalize;
303
304     widget_class->realize           = hildon_animation_actor_realize;
305     widget_class->unrealize         = hildon_animation_actor_unrealize;
306     widget_class->show              = hildon_animation_actor_show;
307     widget_class->hide              = hildon_animation_actor_hide;
308
309     g_type_class_add_private (klass, sizeof (HildonAnimationActorPrivate));
310 }
311
312 static void
313 hildon_animation_actor_init                    (HildonAnimationActor *self)
314 {
315     HildonAnimationActorPrivate
316                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
317
318     /* Default non-zero values for the private variables */
319
320     priv->scale_x = 1 << 16;
321     priv->scale_y = 1 << 16;
322     priv->opacity = 0xff;
323 }
324
325 /**
326  * hildon_animation_actor_new:
327  *
328  * Creates a new #HildonAnimationActor.
329  *
330  * Return value: A #HildonAnimationActor
331  *
332  * Since: 2.2
333  **/
334 GtkWidget*
335 hildon_animation_actor_new                     (void)
336 {
337     HildonAnimationActor *newwindow = g_object_new (HILDON_TYPE_ANIMATION_ACTOR, NULL);
338
339     gtk_window_set_decorated (GTK_WINDOW (newwindow), FALSE);
340
341     return GTK_WIDGET (newwindow);
342 }
343
344 /*
345  * An filter for GDK X11 events, waiting for PropertyNotify (window property
346  * changes) events, keeping track of animation actor ready atom.
347  * Having the ready atom set on the window by the window manager will trigger
348  * updates of actor parameters (position/rotation/etc...) to be sent off
349  * to the window manager for processing.
350  */
351 static GdkFilterReturn
352 hildon_animation_actor_event_filter             (GdkXEvent *xevent,
353                                                  GdkEvent *event,
354                                                  gpointer data)
355 {
356     HildonAnimationActor *self = HILDON_ANIMATION_ACTOR (data);
357     XAnyEvent *any = xevent;
358
359     if (any->type == PropertyNotify)
360     {
361         XPropertyEvent *property = xevent;
362
363         if (property->atom == ready_atom)
364         {
365             hildon_animation_actor_update_ready (self);
366         }
367     }
368
369     return GDK_FILTER_CONTINUE;
370 }
371
372 /*
373  * Check for the ready atom on the animation actor X11 window.
374  * If present, send all pending animation actor messages to the
375  * window manager.
376  */
377 static void
378 hildon_animation_actor_update_ready (HildonAnimationActor *self)
379 {
380     HildonAnimationActorPrivate
381                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
382     GtkWidget          *widget = GTK_WIDGET (self);
383     Display            *display = GDK_WINDOW_XDISPLAY (widget->window);
384     Window              window = GDK_WINDOW_XID (widget->window);
385
386     int status;
387     gint xerror;
388
389     Atom actual_type;
390     int  actual_format;
391     unsigned long nitems, bytes_after;
392     unsigned char *prop = NULL;
393
394     /* Check for the "ready" property */
395
396     gdk_error_trap_push ();
397     status = XGetWindowProperty (display, window,
398                                  ready_atom, 0, 32,
399                                  False, XA_ATOM,
400                                  &actual_type, &actual_format,
401                                  &nitems, &bytes_after, &prop);
402     xerror = gdk_error_trap_pop();
403
404     if (prop)
405     {
406         /* We do not actually use the property value for anything,
407          * it is enough that the property is set. */
408
409         XFree (prop);
410     }
411
412     if (xerror ||
413         (status != Success) || (actual_type != XA_ATOM) ||
414         (actual_format != 32) || (nitems != 1))
415     {
416         priv->ready = 0;
417         return;
418     }
419
420     if (priv->ready)
421     {
422         /* The ready flag has been set once already. This means that
423          * the WM has restarted. Trigger re-mapping of the widget to
424          * update the texture actor first. Then push all animation
425          * actor settings anew. */
426
427         priv->map_event_cb_id =
428             g_signal_connect (G_OBJECT (self),
429                               "map-event",
430                               G_CALLBACK(hildon_animation_actor_map_event),
431                               self);
432
433         if (GTK_WIDGET_MAPPED (GTK_WIDGET (self)))
434         {
435             gtk_widget_unmap (GTK_WIDGET (self));
436             gtk_widget_map (GTK_WIDGET (self));
437         }
438
439         return;
440     }
441
442     priv->ready = 1;
443
444     /* Send all pending messages */
445
446     hildon_animation_actor_send_pending_messages (self);
447 }
448
449 static void
450 hildon_animation_actor_send_pending_messages (HildonAnimationActor *self)
451 {
452     HildonAnimationActorPrivate
453                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
454
455     if (priv->set_anchor)
456     {
457         if (priv->gravity == 0)
458             hildon_animation_actor_set_anchor (self,
459                                                priv->anchor_x,
460                                                priv->anchor_y);
461         else
462             hildon_animation_actor_set_anchor_from_gravity (self,
463                                                             priv->gravity);
464     }
465
466     if (priv->set_position)
467         hildon_animation_actor_set_position_full (self,
468                                                   priv->position_x,
469                                                   priv->position_y,
470                                                   priv->depth);
471
472     if (priv->set_rotation & (1 << HILDON_AA_X_AXIS))
473         hildon_animation_actor_set_rotationx (self,
474                                               HILDON_AA_X_AXIS,
475                                               priv->x_rotation_angle,
476                                               0,
477                                               priv->x_rotation_y,
478                                               priv->x_rotation_z);
479
480     if (priv->set_rotation & (1 << HILDON_AA_Y_AXIS))
481         hildon_animation_actor_set_rotationx (self,
482                                               HILDON_AA_Y_AXIS,
483                                               priv->y_rotation_angle,
484                                               priv->y_rotation_x,
485                                               0,
486                                               priv->y_rotation_z);
487
488     if (priv->set_rotation & (1 << HILDON_AA_Z_AXIS))
489         hildon_animation_actor_set_rotationx (self,
490                                               HILDON_AA_Z_AXIS,
491                                               priv->z_rotation_angle,
492                                               priv->z_rotation_x,
493                                               priv->z_rotation_y,
494                                               0);
495
496     if (priv->set_scale)
497         hildon_animation_actor_set_scalex (self,
498                                            priv->scale_x,
499                                            priv->scale_y);
500
501     if (priv->set_parent)
502         hildon_animation_actor_set_parent (self,
503                                            priv->parent);
504
505     if (priv->set_show)
506         hildon_animation_actor_set_show_full (self,
507                                               priv->show, priv->opacity);
508 }
509
510 static void
511 hildon_animation_actor_send_all_messages (HildonAnimationActor *self)
512 {
513     HildonAnimationActorPrivate
514                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
515
516     priv->set_anchor = 1;
517     priv->set_position = 1;
518     priv->set_rotation = (1 << HILDON_AA_X_AXIS) |
519                          (1 << HILDON_AA_Y_AXIS) |
520                          (1 << HILDON_AA_Z_AXIS);
521     priv->set_scale = 1;
522     priv->set_parent = 1;
523     priv->set_show = 1;
524
525     hildon_animation_actor_send_pending_messages (self);
526 }
527
528 /* ------------------------------------------------------------- */
529
530 /**
531  * hildon_animation_actor_send_message:
532  * @self: A #HildonAnimationActor
533  * @message_type: Message id for the animation actor message.
534  * @l0: 1st animation actor message parameter.
535  * @l1: 2nd animation actor message parameter.
536  * @l2: 3rd animation actor message parameter.
537  * @l3: 4th animation actor message parameter.
538  * @l4: 5th animation actor message parameter.
539  *
540  * Sends an X11 ClientMessage event to the window manager with
541  * the specified parameters -- id (@message_type) and data (@l0,
542  * @l1, @l2, @l3, @l4).
543  *
544  * This is an internal utility function that application will
545  * not need to call directly.
546  *
547  * Since: 2.2
548  **/
549 void
550 hildon_animation_actor_send_message (HildonAnimationActor *self,
551                                      guint32 message_type,
552                                      guint32 l0,
553                                      guint32 l1,
554                                      guint32 l2,
555                                      guint32 l3,
556                                      guint32 l4)
557 {
558     GtkWidget          *widget = GTK_WIDGET (self);
559     Display            *display = GDK_WINDOW_XDISPLAY (widget->window);
560     Window              window = GDK_WINDOW_XID (widget->window);
561 #if 0
562     XClientMessageEvent event;
563
564     event.type = ClientMessage;
565     event.window = window;
566     event.message_type = (Atom)message_type;
567     event.format = 32;
568     event.data.l[0] = l0;
569     event.data.l[1] = l1;
570     event.data.l[2] = l2;
571     event.data.l[3] = l3;
572     event.data.l[4] = l4;
573 #else
574     XEvent event = { 0 };
575
576     event.xclient.type = ClientMessage;
577     event.xclient.window = window;
578     event.xclient.message_type = (Atom)message_type;
579     event.xclient.format = 32;
580     event.xclient.data.l[0] = l0;
581     event.xclient.data.l[1] = l1;
582     event.xclient.data.l[2] = l2;
583     event.xclient.data.l[3] = l3;
584     event.xclient.data.l[4] = l4;
585 #endif
586
587 #if 0
588     g_debug ("%lu (%lu %lu %lu %lu %lu) -> %lu\n",
589              message_type,
590              l0, l1, l2, l3, l4,
591              window);
592 #endif
593
594     XSendEvent (display, window, True,
595                 StructureNotifyMask,
596                 (XEvent *)&event);
597 }
598
599 /**
600  * hildon_animation_actor_set_show_full:
601  * @self: A #HildonAnimationActor
602  * @show: A boolean flag setting the visibility of the animation actor.
603  * @opacity: Desired opacity setting
604  *
605  * Send a message to the window manager setting the visibility of
606  * the animation actor. This will only affect the visibility of
607  * the animation actor set by the compositing window manager in its own
608  * rendering pipeline, after X has drawn the window to the off-screen
609  * buffer. This setting, naturally, has no effect if the #HildonAnimationActor
610  * widget is not visible in X11 terms (i.e. realized and mapped).
611  *
612  * Furthermore, if a widget is parented, its final visibility will be
613  * affected by that of the parent window.
614  *
615  * The opacity setting ranges from zero (0), being completely transparent
616  * to 255 (0xff) being fully opaque.
617  *
618  * If the animation actor WM-counterpart is not ready, the show message
619  * will be queued until the WM is ready for it.
620  *
621  * Since: 2.2
622  **/
623 void
624 hildon_animation_actor_set_show_full (HildonAnimationActor *self,
625                                       gint show,
626                                       gint opacity)
627 {
628     HildonAnimationActorPrivate
629                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
630     GtkWidget          *widget = GTK_WIDGET (self);
631
632     if (opacity > 255)
633         opacity = 255;
634
635     if (opacity < 0)
636         opacity = 0;
637
638     priv->show = show;
639     priv->opacity = opacity;
640     priv->set_show = 1;
641
642     if (GTK_WIDGET_MAPPED (widget) && priv->ready)
643     {
644         /* Defer show messages until the animation actor is parented
645          * and the parent window is mapped */
646
647         if (!priv->parent || !GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent)))
648             return;
649
650         hildon_animation_actor_send_message (self,
651                                              show_atom,
652                                              show, opacity,
653                                              0, 0, 0);
654         priv->set_show = 0;
655     }
656 }
657
658 /**
659  * hildon_animation_actor_set_show:
660  * @self: A #HildonAnimationActor
661  * @show: A boolean flag setting the visibility of the animation actor.
662  *
663  * This function is a shortcut for hildon_animation_actor_set_show_full(),
664  * setting the overall actor visibility without changing it's opacity
665  * setting.
666  *
667  * Since: 2.2
668  **/
669 void
670 hildon_animation_actor_set_show (HildonAnimationActor *self,
671                                  gint show)
672 {
673     HildonAnimationActorPrivate
674                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
675
676     hildon_animation_actor_set_show_full (self,
677                                           show, priv->opacity);
678 }
679
680 /**
681  * hildon_animation_actor_set_opacity:
682  * @self: A #HildonAnimationActor
683  * @opacity: Desired opacity setting
684  *
685  * This function is a shortcut for hildon_animation_actor_set_show_full(),
686  * setting actor opacity without changing it's overall visibility.
687  *
688  * See hildon_animation_actor_set_show_full() for description of the range
689  * of values @opacity argument takes.
690  *
691  * Since: 2.2
692  **/
693 void
694 hildon_animation_actor_set_opacity (HildonAnimationActor *self,
695                                     gint opacity)
696 {
697     HildonAnimationActorPrivate
698                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
699
700     hildon_animation_actor_set_show_full (self,
701                                           priv->show, opacity);
702 }
703
704 /**
705  * hildon_animation_actor_set_position_full:
706  * @self: A #HildonAnimationActor
707  * @x: Desired X coordinate
708  * @y: Desired Y coordinate
709  * @depth: Desired window depth (Z coordinate)
710  *
711  * Send a message to the window manager setting the position of the
712  * animation actor. This will set the position of the animation
713  * actor off-screen bitmap as it is rendered to the screen. The
714  * position of the actor is relative to the parent window. The actor
715  * is also subject to the animation effects rendered by the compositing
716  * window manager on that window (like those by task switcher).
717  *
718  * The window depth affects the stacking of animation actors within
719  * a parent window and, more generally, the stacking of clutter actors
720  * within a stage/container. The default depth is 0 and a parent
721  * window's container will have it's window texture stacked at that level.
722  * The stacking at any depth level is sequential -- animation actor B
723  * created/parented after animation actor A will obscure the latter
724  * if they overlap.
725  *
726  * Animation actors with non-zero depth settings are subject to scaling as
727  * per the global scene perspective setup, which limits the depth setting
728  * as the primary parameter to control the stacking order. Since the
729  * stacking order follows the parenting order, it may be better to use
730  * hildon_animation_actor_set_parent() for setting the stacking.
731  *
732  * If the animation actor WM-counterpart is not ready, the show message
733  * will be queued until the WM is ready for it.
734  *
735  * Since: 2.2
736  **/
737 void
738 hildon_animation_actor_set_position_full (HildonAnimationActor *self,
739                                           gint x,
740                                           gint y,
741                                           gint depth)
742 {
743     HildonAnimationActorPrivate
744                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
745     GtkWidget          *widget = GTK_WIDGET (self);
746
747     priv->position_x = x;
748     priv->position_y = y;
749     priv->depth = depth;
750     priv->set_position = 1;
751
752     if (GTK_WIDGET_MAPPED (widget) && priv->ready)
753     {
754         hildon_animation_actor_send_message (self,
755                                              position_atom,
756                                              x, y, depth,
757                                              0, 0);
758         priv->set_position = 0;
759     }
760 }
761
762 /**
763  * hildon_animation_actor_set_position:
764  * @self: A #HildonAnimationActor
765  * @x: Desired window X coordinate
766  * @y: Desired window Y coordinate
767  *
768  * A shortcut for hildon_animation_actor_set_position_full(),
769  * changing the window position, but preserving it's depth setting.
770  *
771  * Since: 2.2
772  **/
773 void
774 hildon_animation_actor_set_position (HildonAnimationActor *self,
775                                      gint x,
776                                      gint y)
777 {
778     HildonAnimationActorPrivate
779                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
780
781     hildon_animation_actor_set_position_full (self,
782                                               x, y, priv->depth);
783 }
784
785 /**
786  * hildon_animation_actor_set_depth:
787  * @self: A #HildonAnimationActor
788  * @depth: Desired window depth (Z coordinate)
789  *
790  * A shortcut for hildon_animation_actor_set_position_full(),
791  * changing the window depth, but preserving it's position.
792  *
793  * Since: 2.2
794  **/
795 void
796 hildon_animation_actor_set_depth (HildonAnimationActor *self,
797                                   gint depth)
798 {
799     HildonAnimationActorPrivate
800                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
801
802     hildon_animation_actor_set_position_full (self,
803                                               priv->position_x,
804                                               priv->position_y,
805                                               depth);
806 }
807
808 /**
809  * hildon_animation_actor_set_scalex:
810  * @self: A #HildonAnimationActor
811  * @x_scale: Window's desired scale factor along the X-axis
812  * @y_scale: Window's desired scale factor along the Y-axis
813  *
814  * This function is just like hildon_animation_actor_set_scale(),
815  * but the scale factors are given as 16-bit fixed-point number.
816  *
817  * Since: 2.2
818  **/
819 void
820 hildon_animation_actor_set_scalex (HildonAnimationActor *self,
821                                    gint32 x_scale,
822                                    gint32 y_scale)
823 {
824     HildonAnimationActorPrivate
825                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
826     GtkWidget          *widget = GTK_WIDGET (self);
827
828     priv->scale_x = x_scale;
829     priv->scale_y = y_scale;
830     priv->set_scale = 1;
831
832     if (GTK_WIDGET_MAPPED (widget) && priv->ready)
833     {
834         hildon_animation_actor_send_message (self,
835                                              scale_atom,
836                                              x_scale, y_scale,
837                                              0, 0, 0);
838         priv->set_scale = 0;
839     }
840 }
841
842 /**
843  * hildon_animation_actor_set_scale:
844  * @self: A #HildonAnimationActor
845  * @x_scale: Window's desired scale factor along the X-axis
846  * @y_scale: Window's desired scale factor along the Y-axis
847  *
848  * Send a message to the window manager setting the scale factors of the
849  * animation actor. This will set the scale factors on the animation
850  * actor off-screen bitmap as it is rendered to the screen. If the
851  * animation actor is parented to another top-level window, the
852  * animation effects rendered by the compositing window manager
853  * on that top-level window (like those by task switcher) will
854  * also affect the animation actor.
855  *
856  * If the animation actor WM-counterpart is not ready, the show message
857  * will be queued until the WM is ready for it.
858  *
859  * Since: 2.2
860  **/
861 void
862 hildon_animation_actor_set_scale (HildonAnimationActor *self,
863                                   double x_scale,
864                                   double y_scale)
865 {
866     gint32 f_x_scale = x_scale * (1 << 16);
867     gint32 f_y_scale = y_scale * (1 << 16);
868
869     hildon_animation_actor_set_scalex (self, f_x_scale, f_y_scale);
870 }
871
872 /**
873  * hildon_animation_actor_set_rotationx:
874  * @self: A #HildonAnimationActor
875  * @axis: The rotation axis.
876  * @degrees: The rotation angle in degrees.
877  * @x: Center of the rotation, X coordinate.
878  * @y: Center of the rotation, Y coordinate.
879  * @z: Center of the rotation, Z coordinate.
880  *
881  * This function is just like hildon_animation_actor_set_rotation(),
882  * but the rotation angle is given as 16-bit fixed-point number.
883  *
884  * Since: 2.2
885  **/
886 void
887 hildon_animation_actor_set_rotationx (HildonAnimationActor *self,
888                                       gint   axis,
889                                       gint32 degrees,
890                                       gint   x,
891                                       gint   y,
892                                       gint   z)
893 {
894     HildonAnimationActorPrivate
895                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
896     GtkWidget          *widget = GTK_WIDGET (self);
897
898     guint mask = 0;
899
900     switch (axis)
901     {
902         case HILDON_AA_X_AXIS:
903             priv->x_rotation_angle = degrees;
904             priv->x_rotation_y = y;
905             priv->x_rotation_z = z;
906             mask = (1 << HILDON_AA_X_AXIS);
907             break;
908         case HILDON_AA_Y_AXIS:
909             priv->y_rotation_angle = degrees;
910             priv->y_rotation_x = x;
911             priv->y_rotation_z = z;
912             mask = (1 << HILDON_AA_Y_AXIS);
913             break;
914         case HILDON_AA_Z_AXIS:
915             priv->z_rotation_angle = degrees;
916             priv->z_rotation_x = x;
917             priv->z_rotation_y = y;
918             mask = (1 << HILDON_AA_Z_AXIS);
919             break;
920         default:
921             return;
922     }
923
924     priv->set_rotation |= mask;
925
926     if (GTK_WIDGET_MAPPED (widget) && priv->ready)
927     {
928         hildon_animation_actor_send_message (self,
929                                              rotation_atom,
930                                              axis, degrees, x, y, z);
931         priv->set_rotation &= ~mask;
932     }
933 }
934
935 /**
936  * hildon_animation_actor_set_rotation:
937  * @self: A #HildonAnimationActor
938  * @axis: The rotation axis.
939  * @degrees: The rotation angle in degrees.
940  * @x: Center of the rotation, X coordinate.
941  * @y: Center of the rotation, Y coordinate.
942  * @z: Center of the rotation, Z coordinate.
943  *
944  * Send a message to the window manager setting the animation actor
945  * rotation around one of the three axes. The rotation center coordinates
946  * depend on the axis of rotation:
947  *
948  *   * %HILDON_AA_X_AXIS requires @y and @z coordinates.
949  *   * %HILDON_AA_Y_AXIS requires @x and @z coordinates.
950  *   * %HILDON_AA_Z_AXIS requires @x and @y coordinates.
951  *
952  * If the animation actor WM-counterpart is not ready, the show message
953  * will be queued until the WM is ready for it.
954  *
955  * Since: 2.2
956  **/
957 void
958 hildon_animation_actor_set_rotation (HildonAnimationActor *self,
959                                      gint   axis,
960                                      double degrees,
961                                      gint   x,
962                                      gint   y,
963                                      gint   z)
964 {
965     gint32 f_degrees = degrees * (1 << 16);
966
967     hildon_animation_actor_set_rotationx (self, axis, f_degrees, x, y, z);
968 }
969
970 /**
971  * hildon_animation_actor_set_anchor:
972  * @self: A #HildonAnimationActor
973  * @x: The X coordinate of the anchor point.
974  * @y: The Y coordinate of the anchor point.
975  *
976  * Send a message to the window manager setting the anchor point for
977  * the animation actor. The anchor point is the point to which the
978  * actor position within its parent it is relative.
979  *
980  * If the animation actor WM-counterpart is not ready, the show message
981  * will be queued until the WM is ready for it.
982  *
983  * Since: 2.2
984  **/
985 void
986 hildon_animation_actor_set_anchor (HildonAnimationActor *self,
987                                    gint x,
988                                    gint y)
989 {
990     HildonAnimationActorPrivate
991                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
992     GtkWidget          *widget = GTK_WIDGET (self);
993
994     priv->gravity = 0;
995     priv->anchor_x = x;
996     priv->anchor_y = y;
997     priv->set_anchor = 1;
998
999     if (GTK_WIDGET_MAPPED (widget) && priv->ready)
1000     {
1001         hildon_animation_actor_send_message (self,
1002                                              anchor_atom,
1003                                              0, x, y,
1004                                              0, 0);
1005         priv->set_anchor = 0;
1006     }
1007 }
1008
1009 /**
1010  * hildon_animation_actor_set_anchor_from_gravity:
1011  * @self: A #HildonAnimationActor
1012  * @gravity: The gravity constant.
1013  *
1014  * Send a message to the window manager setting the anchor point for
1015  * the animation actor. The anchor point is the point to which the
1016  * actor position within its parent it is relative. Instead of being
1017  * defined in (x, y)-coordinates, the anchor point is defined in the
1018  * relative "gravity" constant as:
1019  *
1020  *   * %HILDON_AA_N_GRAVITY translates to (width / 2, 0) coordinate
1021  *   * %HILDON_AA_NE_GRAVITY translates to (width, 0) coordinate
1022  *   * %HILDON_AA_E_GRAVITY translates to (width, height / 2) coordinate
1023  *   * %HILDON_AA_SE_GRAVITY translates to (width, height) coordinate
1024  *   * %HILDON_AA_S_GRAVITY translates to (width / 2, height) coordinate
1025  *   * %HILDON_AA_SW_GRAVITY translates to (0, height) coordinate
1026  *   * %HILDON_AA_W_GRAVITY translates to (0, height / 2) coordinate
1027  *   * %HILDON_AA_NW_GRAVITY translates to (0, 0) coordinate
1028  *   * %HILDON_AA_CENTER_GRAVITY translates to (width / 2, height / 2) coordinate
1029  *
1030  * If the animation actor WM-counterpart is not ready, the show message
1031  * will be queued until the WM is ready for it.
1032  *
1033  * Since: 2.2
1034  **/
1035 void
1036 hildon_animation_actor_set_anchor_from_gravity (HildonAnimationActor *self,
1037                                                 guint gravity)
1038 {
1039     HildonAnimationActorPrivate
1040                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
1041     GtkWidget          *widget = GTK_WIDGET (self);
1042
1043     priv->gravity = gravity;
1044     priv->set_anchor = 1;
1045
1046     if (GTK_WIDGET_MAPPED (widget) && priv->ready)
1047     {
1048         hildon_animation_actor_send_message (self,
1049                                              anchor_atom,
1050                                              gravity, 0, 0,
1051                                              0, 0);
1052         priv->set_anchor = 0;
1053     }
1054 }
1055
1056 /*
1057  * This callback will be triggered by the parent widget of
1058  * an animation actor when it is mapped. The compositing
1059  * window manager is now ready to parent the animation actor
1060  * into the target parent window.
1061  */
1062 static gboolean
1063 hildon_animation_actor_parent_map_event (GtkWidget *parent,
1064                                          GdkEvent *event,
1065                                          gpointer user_data)
1066 {
1067     hildon_animation_actor_set_parent (HILDON_ANIMATION_ACTOR (user_data),
1068                                        GTK_WINDOW (parent));
1069     return FALSE;
1070 }
1071
1072 /*
1073  * This callback will be triggered by the widget re-mapping
1074  * itself in case of WM restarting. The point is to push all
1075  * animation actor parameters anew to the WM.
1076  */
1077 static gboolean
1078 hildon_animation_actor_map_event (GtkWidget *widget,
1079                                   GdkEvent *event,
1080                                   gpointer user_data)
1081 {
1082     HildonAnimationActor
1083                        *self = HILDON_ANIMATION_ACTOR (user_data);
1084     HildonAnimationActorPrivate
1085                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
1086
1087     hildon_animation_actor_send_all_messages (self);
1088
1089     /* Disconnect the "map-event" handler after the "emergency resend all
1090      * actor parameters" drill is over. */
1091
1092     if (priv->map_event_cb_id)
1093     {
1094         g_signal_handler_disconnect (self,
1095                                      priv->map_event_cb_id);
1096         priv->map_event_cb_id = 0;
1097     }
1098
1099     return FALSE;
1100 }
1101
1102 /**
1103  * hildon_animation_actor_set_parent:
1104  * @self: A #HildonAnimationActor
1105  * @parent: A #GtkWindow that the actor will be parented to.
1106  *
1107  * Send a message to the window manager setting the parent window
1108  * for the animation actor. Parenting an actor will not affect the
1109  * X window that the HildonAnimationActor represents, but it's off-screen
1110  * bitmap as it is handled by the compositing window manager.
1111  *
1112  * Parenting an animation actor will affect its visibility as set
1113  * by the gtk_widget_show(), gtk_widget_hide() and
1114  * hildon_animation_actor_set_show(). The animation actor will only be
1115  * visible when the top-level window it is parented is visible.
1116  *
1117  * Passing %NULL as a @parent argument will unparent the animation actor.
1118  * This will restore the actor's visibility if it was suppressed by
1119  * being unparented or parented to an unmapped window.
1120  *
1121  * If the animation actor WM-counterpart is not ready, the show message
1122  * will be queued until the WM is ready for it.
1123  *
1124  * Since: 2.2
1125  **/
1126 void
1127 hildon_animation_actor_set_parent (HildonAnimationActor *self,
1128                                    GtkWindow *parent)
1129 {
1130     HildonAnimationActorPrivate
1131                        *priv = HILDON_ANIMATION_ACTOR_GET_PRIVATE (self);
1132     GtkWidget          *widget = GTK_WIDGET (self);
1133
1134     gtk_window_set_transient_for (GTK_WINDOW (self), parent);
1135
1136     if (priv->parent != parent)
1137     {
1138         /* Setting a new parent */
1139
1140         if (priv->parent)
1141         {
1142             if (priv->parent_map_event_cb_id)
1143                 g_signal_handler_disconnect (priv->parent,
1144                                              priv->parent_map_event_cb_id);
1145
1146             /* Might need a synchronized "parent(0)" or "parent(new parent)"
1147              * message here before we can safely decrease the reference count. */
1148
1149             g_object_unref (priv->parent);
1150         }
1151
1152         priv->parent = parent;
1153         priv->set_parent = 1;
1154
1155         if (parent != 0)
1156         {
1157             /* The widget is being (re)parented, not unparented. */
1158
1159             g_object_ref (parent);
1160
1161             priv->parent_map_event_cb_id =
1162                 g_signal_connect (G_OBJECT (priv->parent),
1163                                   "map-event",
1164                                   G_CALLBACK(hildon_animation_actor_parent_map_event),
1165                                   self);
1166         }
1167         else
1168         {
1169             priv->parent_map_event_cb_id = 0;
1170         }
1171     }
1172
1173     if (GTK_WIDGET_MAPPED (widget) && priv->ready)
1174     {
1175         Window win = 0;
1176
1177         /* If the animation actor is being unparented or parented to an
1178          * unmapped widget, force its visibility to "hidden". */
1179
1180         if (!priv->parent || !GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent)))
1181         {
1182             hildon_animation_actor_send_message (self,
1183                                                  show_atom,
1184                                                  0, priv->opacity,
1185                                                  0, 0, 0);
1186         }
1187
1188         /* If the widget is being parented (parent != 0), only proceed when
1189          * the parent widget is realized, since we need the X window id of
1190          * the parent. If the widget is being unparented (parent == 0), pass
1191          * the "special" window id of 0 in the message. */
1192
1193         if (priv->parent)
1194         {
1195             if (!GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent)))
1196                 return;
1197
1198             GdkWindow *gdk = GTK_WIDGET (parent)->window;
1199             win = GDK_WINDOW_XID (gdk);
1200         }
1201
1202         hildon_animation_actor_send_message (self,
1203                                              parent_atom,
1204                                              win,
1205                                              0, 0, 0, 0);
1206         priv->set_parent = 0;
1207
1208         /* Set animation actor visibility to desired value (in case it was
1209          * forced off when the actor was parented into an unmapped widget). */
1210
1211         hildon_animation_actor_send_message (self,
1212                                              show_atom,
1213                                              priv->show, priv->opacity,
1214                                              0, 0, 0);
1215         priv->set_show = 0;
1216     }
1217 }
1218