Add HildonAppMenu::changed signal
[hildon] / hildon / hildon-remote-texture.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-remote-texture
27  * @short_description: Clutter/GLES texture created
28  * from a shared memory area.
29  *
30  * The #HildonRemoteTexture is a GTK+ widget which allows the rendering of
31  * a shared memory area within hildon-desktop. It allows the memory area to
32  * be positioned and scaled, without altering its' contents.
33  */
34
35 #include                                        <gdk/gdkx.h>
36 #include                                        <X11/Xatom.h>
37
38 #include                                        "hildon-remote-texture.h"
39 #include                                        "hildon-remote-texture-private.h"
40
41 G_DEFINE_TYPE (HildonRemoteTexture, hildon_remote_texture, GTK_TYPE_WINDOW);
42
43 static GdkFilterReturn
44 hildon_remote_texture_event_filter (GdkXEvent *xevent,
45                                      GdkEvent *event,
46                                      gpointer data);
47 static void
48 hildon_remote_texture_update_ready (HildonRemoteTexture *self);
49 static void
50 hildon_remote_texture_send_pending_messages (HildonRemoteTexture *self);
51 static void
52 hildon_remote_texture_send_all_messages (HildonRemoteTexture *self);
53 static gboolean
54 hildon_remote_texture_parent_map_event (GtkWidget *parent,
55                                          GdkEvent *event,
56                                          gpointer user_data);
57 static gboolean
58 hildon_remote_texture_map_event (GtkWidget *widget,
59                                   GdkEvent *event,
60                                   gpointer user_data);
61
62 static guint32 shm_atom;
63 static guint32 damage_atom;
64 static guint32 show_atom;
65 static guint32 position_atom;
66 static guint32 offset_atom;
67 static guint32 scale_atom;
68 static guint32 parent_atom;
69 static guint32 ready_atom;
70
71 static gboolean atoms_initialized = FALSE;
72
73 static void
74 hildon_remote_texture_realize                 (GtkWidget *widget)
75 {
76     GdkDisplay *display;
77     Atom wm_type, applet_type;
78
79     GTK_WIDGET_CLASS (hildon_remote_texture_parent_class)->realize (widget);
80
81     /* Set remote texture window type. */
82
83     display = gdk_drawable_get_display (widget->window);
84
85     wm_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE");
86     applet_type = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_WM_WINDOW_TYPE_REMOTE_TEXTURE");
87
88     XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (widget->window), wm_type,
89                      XA_ATOM, 32, PropModeReplace,
90                      (unsigned char *) &applet_type, 1);
91
92     /* This is a bit of a hack, but for the sake of speed (it is assumed that
93      * once HildonRemoteTexture is created, a lot of ClientMessages will
94      * follow), we cache all ClientMessages atoms in static variables. */
95
96     if (!atoms_initialized)
97     {
98         shm_atom =
99             gdk_x11_get_xatom_by_name_for_display
100             (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_SHM");
101         damage_atom =
102             gdk_x11_get_xatom_by_name_for_display
103             (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_DAMAGE");
104         show_atom =
105             gdk_x11_get_xatom_by_name_for_display
106             (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_SHOW");
107         position_atom =
108             gdk_x11_get_xatom_by_name_for_display
109             (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_POSITION");
110         offset_atom =
111             gdk_x11_get_xatom_by_name_for_display
112             (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_OFFSET");
113         scale_atom =
114             gdk_x11_get_xatom_by_name_for_display
115             (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_SCALE");
116         parent_atom =
117             gdk_x11_get_xatom_by_name_for_display
118             (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_PARENT");
119         ready_atom =
120             gdk_x11_get_xatom_by_name_for_display
121             (display, "_HILDON_TEXTURE_CLIENT_READY");
122 #if 0
123         g_debug ("shm atom = %lu\n", shm_atom);
124         g_debug ("damage atom = %lu\n", damage_atom);
125         g_debug ("show atom = %lu\n", show_atom);
126         g_debug ("position atom = %lu\n", position_atom);
127         g_debug ("offset atom = %lu\n", offset_atom);
128         g_debug ("scale atom = %lu\n", scale_atom);
129         g_debug ("parent atom = %lu\n", parent_atom);
130         g_debug ("ready atom = %lu\n", ready_atom);
131 #endif
132
133         atoms_initialized = TRUE;
134     }
135
136     /* Wait for a ready message */
137
138     gdk_window_add_filter (widget->window,
139                            hildon_remote_texture_event_filter,
140                            widget);
141 }
142
143 static void
144 hildon_remote_texture_unrealize               (GtkWidget *widget)
145 {
146     gdk_window_remove_filter (widget->window,
147                               hildon_remote_texture_event_filter,
148                               widget);
149
150     GTK_WIDGET_CLASS (hildon_remote_texture_parent_class)->unrealize (widget);
151 }
152
153 static void
154 hildon_remote_texture_show                    (GtkWidget *widget)
155 {
156     HildonRemoteTexture        *self = HILDON_REMOTE_TEXTURE (widget);
157
158     GTK_WIDGET_CLASS (hildon_remote_texture_parent_class)->show (widget);
159     hildon_remote_texture_set_show (self, 1);
160 }
161
162 static void
163 hildon_remote_texture_hide                    (GtkWidget *widget)
164 {
165     HildonRemoteTexture        *self = HILDON_REMOTE_TEXTURE (widget);
166
167     hildon_remote_texture_set_show (self, 0);
168     GTK_WIDGET_CLASS (hildon_remote_texture_parent_class)->hide (widget);
169 }
170
171 static void
172 hildon_remote_texture_finalize                (GObject *object)
173 {
174     HildonRemoteTexture        *self = HILDON_REMOTE_TEXTURE (object);
175     HildonRemoteTexturePrivate
176                        *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
177
178     if (priv->parent)
179     {
180         if (priv->parent_map_event_cb_id)
181             g_signal_handler_disconnect (priv->parent,
182                                          priv->parent_map_event_cb_id);
183
184         g_object_unref (priv->parent);
185     }
186 }
187
188 static void
189 hildon_remote_texture_class_init              (HildonRemoteTextureClass *klass)
190 {
191     GObjectClass      *gobject_class = G_OBJECT_CLASS (klass);
192     GtkWidgetClass    *widget_class = GTK_WIDGET_CLASS (klass);
193
194     gobject_class->finalize         = hildon_remote_texture_finalize;
195
196     widget_class->realize           = hildon_remote_texture_realize;
197     widget_class->unrealize         = hildon_remote_texture_unrealize;
198     widget_class->show              = hildon_remote_texture_show;
199     widget_class->hide              = hildon_remote_texture_hide;
200
201     g_type_class_add_private (klass, sizeof (HildonRemoteTexturePrivate));
202 }
203
204 static void
205 hildon_remote_texture_init                    (HildonRemoteTexture *self)
206 {
207     HildonRemoteTexturePrivate
208                        *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
209
210     /* Default non-zero values for the private variables */
211
212     priv->scale_x = 1;
213     priv->scale_y = 1;
214     priv->opacity = 0xff;
215 }
216
217 /**
218  * hildon_remote_texture_new:
219  *
220  * Creates a new #HildonRemoteTexture.
221  *
222  * Return value: A #HildonRemoteTexture
223  *
224  * Since: 2.2
225  **/
226 GtkWidget*
227 hildon_remote_texture_new                     (void)
228 {
229     HildonRemoteTexture *newwindow = g_object_new (HILDON_TYPE_REMOTE_TEXTURE, NULL);
230
231     gtk_window_set_decorated (GTK_WINDOW (newwindow), FALSE);
232
233     return GTK_WIDGET (newwindow);
234 }
235
236 /*
237  * An filter for GDK X11 events, waiting for PropertyNotify (window property
238  * changes) events, keeping track of remote texture ready atom.
239  * Having the ready atom set on the window by the window manager will trigger
240  * updates of actor parameters (position/rotation/etc...) to be sent off
241  * to the window manager for processing.
242  */
243 static GdkFilterReturn
244 hildon_remote_texture_event_filter             (GdkXEvent *xevent,
245                                                  GdkEvent *event,
246                                                  gpointer data)
247 {
248     HildonRemoteTexture *self = HILDON_REMOTE_TEXTURE (data);
249     XAnyEvent *any = xevent;
250
251     if (any->type == PropertyNotify)
252     {
253         XPropertyEvent *property = xevent;
254
255         if (property->atom == ready_atom)
256         {
257             hildon_remote_texture_update_ready (self);
258         }
259     }
260
261     return GDK_FILTER_CONTINUE;
262 }
263
264 /*
265  * Check for the ready atom on the remote texture X11 window.
266  * If present, send all pending remote texture messages to the
267  * window manager.
268  */
269 static void
270 hildon_remote_texture_update_ready (HildonRemoteTexture *self)
271 {
272     HildonRemoteTexturePrivate
273                        *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
274     GtkWidget          *widget = GTK_WIDGET (self);
275     Display            *display = GDK_WINDOW_XDISPLAY (widget->window);
276     Window              window = GDK_WINDOW_XID (widget->window);
277
278     int status;
279     gint xerror;
280
281     Atom actual_type;
282     int  actual_format;
283     unsigned long nitems, bytes_after;
284     unsigned char *prop = NULL;
285
286     /* Check for the "ready" property */
287
288     gdk_error_trap_push ();
289     status = XGetWindowProperty (display, window,
290                                  ready_atom, 0, 32,
291                                  False, XA_ATOM,
292                                  &actual_type, &actual_format,
293                                  &nitems, &bytes_after, &prop);
294     xerror = gdk_error_trap_pop();
295
296     if (prop)
297     {
298         /* We do not actually use the property value for anything,
299          * it is enough that the property is set. */
300
301         XFree (prop);
302     }
303
304     if (xerror ||
305         (status != Success) || (actual_type != XA_ATOM) ||
306         (actual_format != 32) || (nitems != 1))
307     {
308         priv->ready = 0;
309         return;
310     }
311
312     if (priv->ready)
313     {
314         /* The ready flag has been set once already. This means that
315          * the WM has restarted. Trigger re-mapping of the widget to
316          * update the texture actor first. Then push all remote
317          * texture settings anew. */
318
319         priv->map_event_cb_id =
320             g_signal_connect (G_OBJECT (self),
321                               "map-event",
322                               G_CALLBACK(hildon_remote_texture_map_event),
323                               self);
324
325         if (GTK_WIDGET_MAPPED (GTK_WIDGET (self)))
326         {
327             gtk_widget_unmap (GTK_WIDGET (self));
328             gtk_widget_map (GTK_WIDGET (self));
329         }
330
331         return;
332     }
333
334     priv->ready = 1;
335
336     /* Send all pending messages */
337
338     hildon_remote_texture_send_pending_messages (self);
339 }
340
341 static void
342 hildon_remote_texture_send_pending_messages (HildonRemoteTexture *self)
343 {
344     HildonRemoteTexturePrivate
345                        *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
346
347     if (priv->set_shm)
348       hildon_remote_texture_set_image(self,
349                                       priv->shm_key,
350                                       priv->shm_width, priv->shm_height,
351                                       priv->shm_bpp);
352
353     if (priv->set_damage)
354       hildon_remote_texture_update_area (self,
355                                          priv->damage_x1,
356                                          priv->damage_y1,
357                                          priv->damage_x2 - priv->damage_x1,
358                                          priv->damage_y2 - priv->damage_y1);
359
360     if (priv->set_position)
361         hildon_remote_texture_set_position (self,
362                                             priv->x,
363                                             priv->y,
364                                             priv->width,
365                                             priv->height);
366
367     if (priv->set_offset)
368         hildon_remote_texture_set_offset (self,
369                                           priv->offset_x,
370                                           priv->offset_y);
371
372     if (priv->set_scale)
373         hildon_remote_texture_set_scale (self,
374                                          priv->scale_x,
375                                          priv->scale_y);
376
377     if (priv->set_parent)
378         hildon_remote_texture_set_parent (self,
379                                            priv->parent);
380
381     if (priv->set_show)
382         hildon_remote_texture_set_show_full (self,
383                                               priv->show, priv->opacity);
384 }
385
386 static void
387 hildon_remote_texture_send_all_messages (HildonRemoteTexture *self)
388 {
389     HildonRemoteTexturePrivate
390                        *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
391
392     priv->set_shm = 1;
393     priv->set_damage = 1;
394     priv->set_position = 1;
395     priv->set_scale = 1;
396     priv->set_parent = 1;
397     priv->set_show = 1;
398
399     hildon_remote_texture_send_pending_messages (self);
400 }
401
402 /* ------------------------------------------------------------- */
403
404 /**
405  * hildon_remote_texture_send_message:
406  * @self: A #HildonRemoteTexture
407  * @message_type: Message id for the remote texture message.
408  * @l0: 1st remote texture message parameter.
409  * @l1: 2nd remote texture message parameter.
410  * @l2: 3rd remote texture message parameter.
411  * @l3: 4th remote texture message parameter.
412  * @l4: 5th remote texture message parameter.
413  *
414  * Sends an X11 ClientMessage event to the window manager with
415  * the specified parameters -- id (@message_type) and data (@l0,
416  * @l1, @l2, @l3, @l4).
417  *
418  * This is an internal utility function that application will
419  * not need to call directly.
420  *
421  * Since: 2.2
422  **/
423 void
424 hildon_remote_texture_send_message (HildonRemoteTexture *self,
425                                      guint32 message_type,
426                                      guint32 l0,
427                                      guint32 l1,
428                                      guint32 l2,
429                                      guint32 l3,
430                                      guint32 l4)
431 {
432     GtkWidget          *widget = GTK_WIDGET (self);
433     Display            *display = GDK_WINDOW_XDISPLAY (widget->window);
434     Window              window = GDK_WINDOW_XID (widget->window);
435
436     XEvent event = { 0 };
437
438     event.xclient.type = ClientMessage;
439     event.xclient.window = window;
440     event.xclient.message_type = (Atom)message_type;
441     event.xclient.format = 32;
442     event.xclient.data.l[0] = l0;
443     event.xclient.data.l[1] = l1;
444     event.xclient.data.l[2] = l2;
445     event.xclient.data.l[3] = l3;
446     event.xclient.data.l[4] = l4;
447
448 #if 0
449     g_debug ("%lu (%lu %lu %lu %lu %lu) -> %lu\n",
450              message_type,
451              l0, l1, l2, l3, l4,
452              window);
453 #endif
454
455     XSendEvent (display, window, True,
456                 StructureNotifyMask,
457                 (XEvent *)&event);
458 }
459
460 /**
461  * hildon_remote_texture_set_image:
462  * @self: A #HildonRemoteTexture
463  * @key: The key that would be used with shmget in hildon-desktop. The key
464  * should probably be created with ftok, and the relevant shared memory
465  * area should be created before this call.
466  * @width: width of image in pixels
467  * @height: height of image in pixels
468  * @bpp: BYTES per pixel - usually 2,3 or 4
469  *
470  * Since: 2.2
471  */
472 void
473 hildon_remote_texture_set_image (HildonRemoteTexture *self,
474                                  key_t key,
475                                  guint width,
476                                  guint height,
477                                  guint bpp)
478 {
479   HildonRemoteTexturePrivate
480                        *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
481   GtkWidget          *widget = GTK_WIDGET (self);
482
483   priv->set_shm = 1;
484   priv->shm_key = key;
485   priv->shm_width = width;
486   priv->shm_height = height;
487   priv->shm_bpp = bpp;
488
489   if (GTK_WIDGET_MAPPED (widget) && priv->ready)
490     {
491        /* Defer messages until the remote texture is parented
492         * and the parent window is mapped */
493         if (!priv->parent || !GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent)))
494             return;
495         hildon_remote_texture_send_message (self,
496                                             shm_atom,
497                                             priv->shm_key,
498                                             priv->shm_width,
499                                             priv->shm_height,
500                                             priv->shm_bpp,
501                                             0);
502         priv->set_shm = 0;
503     }
504 }
505
506 /**
507  * hildon_remote_texture_update_area:
508  * @self: A #HildonRemoteTexture
509  * @x: offset of damaged area in pixels
510  * @y: offset of damaged area in pixels
511  * @width: width of damaged area in pixels
512  * @height: height of damaged area in pixels
513  *
514  * This signals to hildon-desktop that a specific region of the memory area
515  * has changed. This will trigger a redraw and will update the relevant tiles
516  * of the texture.
517  *
518  * Since: 2.2
519  */
520 void
521 hildon_remote_texture_update_area (HildonRemoteTexture *self,
522                                  gint x,
523                                  gint y,
524                                  gint width,
525                                  gint height)
526 {
527   HildonRemoteTexturePrivate
528                      *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
529   GtkWidget          *widget = GTK_WIDGET (self);
530
531   if (priv->damage_x1==priv->damage_x2 || priv->damage_y1==priv->damage_y2)
532     {
533       priv->damage_x1 = x;
534       priv->damage_y1 = y;
535       priv->damage_x2 = x+width;
536       priv->damage_y2 = y+height;
537     }
538   else
539     {
540       if (x<priv->damage_x1) priv->damage_x1 = x;
541       if (y<priv->damage_y1) priv->damage_y1 = y;
542       if (x+width>priv->damage_x2) priv->damage_x2 = x+width;
543       if (y+height>priv->damage_y2) priv->damage_y2 = y+height;
544     }
545   priv->set_damage = 1;
546
547   if (GTK_WIDGET_MAPPED (widget) && priv->ready)
548   {
549      /* Defer messages until the remote texture is parented
550       * and the parent window is mapped */
551       if (!priv->parent || !GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent)))
552           return;
553       hildon_remote_texture_send_message (self,
554                                           damage_atom,
555                                           priv->damage_x1,
556                                           priv->damage_y1,
557                                           priv->damage_x2 - priv->damage_x1,
558                                           priv->damage_y2 - priv->damage_y1,
559                                           0);
560       priv->set_damage = 0;
561       priv->damage_x1 = 0;
562       priv->damage_y1 = 0;
563       priv->damage_x2 = 0;
564       priv->damage_y2 = 0;
565   }
566 }
567
568 /**
569  * hildon_remote_texture_set_show_full:
570  * @self: A #HildonRemoteTexture
571  * @show: A boolean flag setting the visibility of the remote texture.
572  * @opacity: Desired opacity setting
573  *
574  * Send a message to the window manager setting the visibility of
575  * the remote texture. This will only affect the visibility of
576  * the remote texture set by the compositing window manager in its own
577  * rendering pipeline, after X has drawn the window to the off-screen
578  * buffer. This setting, naturally, has no effect if the #HildonRemoteTexture
579  * widget is not visible in X11 terms (i.e. realized and mapped).
580  *
581  * Furthermore, if a widget is parented, its final visibility will be
582  * affected by that of the parent window.
583  *
584  * The opacity setting ranges from zero (0), being completely transparent
585  * to 255 (0xff) being fully opaque.
586  *
587  * If the remote texture WM-counterpart is not ready, the show message
588  * will be queued until the WM is ready for it.
589  *
590  * Since: 2.2
591  **/
592 void
593 hildon_remote_texture_set_show_full (HildonRemoteTexture *self,
594                                       gint show,
595                                       gint opacity)
596 {
597     HildonRemoteTexturePrivate
598                        *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
599     GtkWidget          *widget = GTK_WIDGET (self);
600
601     if (opacity > 255)
602         opacity = 255;
603
604     if (opacity < 0)
605         opacity = 0;
606
607     priv->show = show;
608     priv->opacity = opacity;
609     priv->set_show = 1;
610
611     if (GTK_WIDGET_MAPPED (widget) && priv->ready)
612     {
613         /* Defer show messages until the remote texture is parented
614          * and the parent window is mapped */
615         if (!priv->parent || !GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent)))
616             return;
617         hildon_remote_texture_send_message (self,
618                                              show_atom,
619                                              show, opacity,
620                                              0, 0, 0);
621         priv->set_show = 0;
622     }
623 }
624
625 /**
626  * hildon_remote_texture_set_show:
627  * @self: A #HildonRemoteTexture
628  * @show: A boolean flag setting the visibility of the remote texture.
629  *
630  * This function is a shortcut for hildon_remote_texture_set_show_full(),
631  * setting the overall actor visibility without changing it's opacity
632  * setting.
633  *
634  * Since: 2.2
635  **/
636 void
637 hildon_remote_texture_set_show (HildonRemoteTexture *self,
638                                  gint show)
639 {
640     HildonRemoteTexturePrivate
641                        *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
642
643     hildon_remote_texture_set_show_full (self,
644                                           show, priv->opacity);
645 }
646
647 /**
648  * hildon_remote_texture_set_opacity:
649  * @self: A #HildonRemoteTexture
650  * @opacity: Desired opacity setting
651  *
652  * This function is a shortcut for hildon_remote_texture_set_show_full(),
653  * setting actor opacity without changing it's overall visibility.
654  *
655  * See hildon_remote_texture_set_show_full() for description of the range
656  * of values @opacity argument takes.
657  *
658  * Since: 2.2
659  **/
660 void
661 hildon_remote_texture_set_opacity (HildonRemoteTexture *self,
662                                     gint opacity)
663 {
664     HildonRemoteTexturePrivate
665                        *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
666
667     hildon_remote_texture_set_show_full (self,
668                                           priv->show, opacity);
669 }
670
671 /**
672  * hildon_remote_texture_set_position:
673  * @self: A #HildonRemoteTexture
674  * @x: Desired X coordinate
675  * @y: Desired Y coordinate
676  * @width: Desired width
677  * @height: Desired height
678  *
679  * Send a message to the window manager setting the offset of the remote
680  * texture in the window (in Remote texture's pixels). The texture
681  * is also subject to the animation effects rendered by the compositing
682  * window manager on that window (like those by task switcher).
683  *
684  * If the remote texture WM-counterpart is not ready, the show message
685  * will be queued until the WM is ready for it.
686  *
687  * Since: 2.2
688  **/
689 void
690 hildon_remote_texture_set_position (HildonRemoteTexture *self,
691                                         gint x,
692                                         gint y,
693                                         gint width,
694                                         gint height)
695 {
696     HildonRemoteTexturePrivate
697                        *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
698     GtkWidget          *widget = GTK_WIDGET (self);
699
700     priv->x = x;
701     priv->y = y;
702     priv->width = width;
703     priv->height = height;
704     priv->set_position = 1;
705
706     if (GTK_WIDGET_MAPPED (widget) && priv->ready)
707     {
708         /* Defer messages until the remote texture is parented
709          * and the parent window is mapped */
710
711         if (!priv->parent || !GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent)))
712             return;
713         hildon_remote_texture_send_message (self,
714                                             position_atom,
715                                             x, y,
716                                             width, height, 0);
717         priv->set_position = 0;
718     }
719 }
720
721 /**
722  * hildon_remote_texture_set_offset:
723  * @self: A #HildonRemoteTexture
724  * @x: Desired X offset
725  * @y: Desired Y offset
726  *
727  * Send a message to the window manager setting the offset of the remote
728  * texture in the window (in Remote texture's pixels). The texture
729  * is also subject to the animation effects rendered by the compositing
730  * window manager on that window (like those by task switcher).
731  *
732  * If the remote texture 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_remote_texture_set_offset (HildonRemoteTexture *self,
739                                     double x,
740                                     double y)
741 {
742     HildonRemoteTexturePrivate
743                        *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
744     GtkWidget          *widget = GTK_WIDGET (self);
745
746     priv->offset_x = x;
747     priv->offset_y = y;
748     priv->set_offset = 1;
749
750     if (GTK_WIDGET_MAPPED (widget) && priv->ready)
751     {
752         /* Defer messages until the remote texture is parented
753          * and the parent window is mapped */
754
755         if (!priv->parent || !GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent)))
756             return;
757         hildon_remote_texture_send_message (self,
758                                             offset_atom,
759                                             (gint)(x*65536), (gint)(y*65536),
760                                             0, 0, 0);
761         priv->set_offset = 0;
762     }
763 }
764
765 /**
766  * hildon_remote_texture_set_scalex:
767  * @self: A #HildonRemoteTexture
768  * @x_scale: The scale factor for the memory area to be rendered in the X-axis
769  * @y_scale: The scale factor for the memory area to be rendered in the X-axis
770  *
771  * Since: 2.2
772  **/
773 void
774 hildon_remote_texture_set_scale (HildonRemoteTexture *self,
775                                double x_scale,
776                                double y_scale)
777 {
778     HildonRemoteTexturePrivate
779                        *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
780     GtkWidget          *widget = GTK_WIDGET (self);
781
782     priv->scale_x = x_scale;
783     priv->scale_y = y_scale;
784     priv->set_scale = 1;
785
786     if (GTK_WIDGET_MAPPED (widget) && priv->ready)
787     {
788         /* Defer messages until the remote texture is parented
789          * and the parent window is mapped */
790         if (!priv->parent || !GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent)))
791             return;
792         hildon_remote_texture_send_message (self,
793                                              scale_atom,
794                                              priv->scale_x * (1 << 16),
795                                              priv->scale_y * (1 << 16),
796                                              0, 0, 0);
797         priv->set_scale = 0;
798     }
799 }
800
801 /*
802  * This callback will be triggered by the parent widget of
803  * an remote texture when it is mapped. The compositing
804  * window manager is now ready to parent the remote texture
805  * into the target parent window.
806  */
807 static gboolean
808 hildon_remote_texture_parent_map_event (GtkWidget *parent,
809                                          GdkEvent *event,
810                                          gpointer user_data)
811 {
812     hildon_remote_texture_set_parent (HILDON_REMOTE_TEXTURE (user_data),
813                                        GTK_WINDOW (parent));
814     return FALSE;
815 }
816
817 /*
818  * This callback will be triggered by the widget re-mapping
819  * itself in case of WM restarting. The point is to push all
820  * remote texture parameters anew to the WM.
821  */
822 static gboolean
823 hildon_remote_texture_map_event (GtkWidget *widget,
824                                   GdkEvent *event,
825                                   gpointer user_data)
826 {
827     HildonRemoteTexture
828                        *self = HILDON_REMOTE_TEXTURE (user_data);
829     HildonRemoteTexturePrivate
830                        *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
831
832     hildon_remote_texture_send_all_messages (self);
833
834     /* Disconnect the "map-event" handler after the "emergency resend all
835      * actor parameters" drill is over. */
836
837     if (priv->map_event_cb_id)
838     {
839         g_signal_handler_disconnect (self,
840                                      priv->map_event_cb_id);
841         priv->map_event_cb_id = 0;
842     }
843
844     return FALSE;
845 }
846
847 /**
848  * hildon_remote_texture_set_parent:
849  * @self: A #HildonRemoteTexture
850  * @parent: A #GtkWindow that the actor will be parented to.
851  *
852  * Send a message to the window manager setting the parent window
853  * for the remote texture. Parenting an actor will not affect the
854  * X window that the HildonRemoteTexture represents, but it's off-screen
855  * bitmap as it is handled by the compositing window manager.
856  *
857  * Parenting an remote texture will affect its visibility as set
858  * by the gtk_widget_show(), gtk_widget_hide() and
859  * hildon_remote_texture_set_show(). The remote texture will only be
860  * visible when the top-level window it is parented is visible.
861  *
862  * Passing %NULL as a @parent argument will unparent the remote texture.
863  * This will restore the actor's visibility if it was suppressed by
864  * being unparented or parented to an unmapped window.
865  *
866  * If the remote texture WM-counterpart is not ready, the show message
867  * will be queued until the WM is ready for it.
868  *
869  * Since: 2.2
870  **/
871 void
872 hildon_remote_texture_set_parent (HildonRemoteTexture *self,
873                                    GtkWindow *parent)
874 {
875     HildonRemoteTexturePrivate
876                        *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
877     GtkWidget          *widget = GTK_WIDGET (self);
878
879     gtk_window_set_transient_for (GTK_WINDOW (self), parent);
880
881     if (priv->parent != parent)
882     {
883         /* Setting a new parent */
884
885         if (priv->parent)
886         {
887             if (priv->parent_map_event_cb_id)
888                 g_signal_handler_disconnect (priv->parent,
889                                              priv->parent_map_event_cb_id);
890
891             /* Might need a synchronized "parent(0)" or "parent(new parent)"
892              * message here before we can safely decrease the reference count. */
893
894             g_object_unref (priv->parent);
895         }
896
897         priv->parent = parent;
898         priv->set_parent = 1;
899
900         if (parent != 0)
901         {
902             /* The widget is being (re)parented, not unparented. */
903
904             g_object_ref (parent);
905
906             priv->parent_map_event_cb_id =
907                 g_signal_connect (G_OBJECT (priv->parent),
908                                   "map-event",
909                                   G_CALLBACK(hildon_remote_texture_parent_map_event),
910                                   self);
911         }
912         else
913         {
914             priv->parent_map_event_cb_id = 0;
915         }
916     }
917
918     if (GTK_WIDGET_MAPPED (widget) && priv->ready)
919     {
920         Window win = 0;
921
922         /* If the remote texture is being unparented or parented to an
923          * unmapped widget, force its visibility to "hidden". */
924
925         if (!priv->parent || !GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent)))
926         {
927             hildon_remote_texture_send_message (self,
928                                                  show_atom,
929                                                  0, priv->opacity,
930                                                  0, 0, 0);
931         }
932
933         /* If the widget is being parented (parent != 0), only proceed when
934          * the parent widget is realized, since we need the X window id of
935          * the parent. If the widget is being unparented (parent == 0), pass
936          * the "special" window id of 0 in the message. */
937
938         if (priv->parent)
939         {
940             if (!GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent)))
941                 return;
942
943             GdkWindow *gdk = GTK_WIDGET (parent)->window;
944             win = GDK_WINDOW_XID (gdk);
945         }
946
947         hildon_remote_texture_send_message (self,
948                                              parent_atom,
949                                              win,
950                                              0, 0, 0, 0);
951         priv->set_parent = 0;
952
953         /* Set remote texture visibility to desired value (in case it was
954          * forced off when the actor was parented into an unmapped widget). */
955
956         hildon_remote_texture_send_message (self,
957                                              show_atom,
958                                              priv->show, priv->opacity,
959                                              0, 0, 0);
960         priv->set_show = 0;
961     }
962 }
963