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