* src/hildon.h * src/hildon-remote-texture.c * src/hildon-remote-texture.h * src...
authorGordon Williams <gordon.williams@collabora.co.uk>
Wed, 11 Feb 2009 11:00:00 +0000 (11:00 +0000)
committerGordon Williams <gordon.williams@collabora.co.uk>
Wed, 11 Feb 2009 11:00:00 +0000 (11:00 +0000)
* examples/hildon-remote-texture-example.c
* examples/Makefile.am
Added example file for remote texture usage

ChangeLog
examples/Makefile.am
examples/hildon-remote-texture-example.c [new file with mode: 0644]
src/Makefile.am
src/hildon-remote-texture-private.h [new file with mode: 0644]
src/hildon-remote-texture.c [new file with mode: 0644]
src/hildon-remote-texture.h [new file with mode: 0644]
src/hildon.h

index f13b9bf..4376b37 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2009-02-11  Gordon Williams <gordon.williams@collabora.co.uk>
+
+       * src/hildon.h
+       * src/hildon-remote-texture.c
+       * src/hildon-remote-texture.h
+       * src/hildon-remote-texture-private.h
+       * src/Makefile.am
+       Added remote texture widget (for Clutter shared memory textures)
+
+       * examples/hildon-remote-texture-example.c
+       * examples/Makefile.am
+       Added example file for remote texture usage
+
 2009-02-10  Claudio Saavedra  <csaavedra@igalia.com>
 
        * configure.ac: post release version bump.
index 72d1b3e..efc840a 100644 (file)
@@ -35,7 +35,8 @@ EXAMPLES                              = hildon-window-example                         \
                                          hildon-touch-selector-example                 \
                                          hildon-touch-selector-multi-cells-example     \
                                          hildon-touch-selector-entry-example           \
-                                         hildon-progress-indicator-example
+                                         hildon-progress-indicator-example             \
+                                         hildon-remote-texture-example
 if USE_MAEMO_GTK
 MAEMO_GTK_EXAMPLES                      = hildon-pannable-area-touch-list-example      \
                                          hildon-pannable-area-touch-grid-example
@@ -441,4 +442,10 @@ hildon_progress_indicator_example_CFLAGS   = $(HILDON_OBJ_CFLAGS)                  \
                                                  $(EXTRA_CFLAGS)
 hildon_progress_indicator_example_SOURCES      = hildon-progress-indicator-example.c
 
+# Hildon remote texture
+hildon_remote_texture_example_LDADD            = $(HILDON_OBJ_LIBS)
+hildon_remote_texture_example_CFLAGS           = $(HILDON_OBJ_CFLAGS)                  \
+                                                 $(EXTRA_CFLAGS)
+hildon_remote_texture_example_SOURCES          = hildon-remote-texture-example.c
+
 endif
diff --git a/examples/hildon-remote-texture-example.c b/examples/hildon-remote-texture-example.c
new file mode 100644 (file)
index 0000000..927ecae
--- /dev/null
@@ -0,0 +1,222 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <sys/types.h>
+#include <sys/shm.h>
+#include <string.h>
+#include <math.h>
+#include "hildon.h"
+
+#define W 800
+#define H 480
+
+/* Press and drag to pan around, or tap to move between zoom levels.
+ * A file must be specified on the command-line, and it must be > 640x480.
+ *
+ * This file will be loaded and placed into a shared memory area, which will
+ * be read by hildon-desktop.
+ * An area 640x480 in the top-left corner will be updated with an animation
+ * to show how to modify the area. */
+
+#define ANIM_X 0
+#define ANIM_Y 0
+#define ANIM_WIDTH 640
+#define ANIM_HEIGHT 480
+#define ANIM_FRAMES 64
+
+static key_t shm_key = 0xCAFEBEEF;
+static gint  bpp, width, height;
+static guchar *shm = 0; /* shared mem */
+static int anim_frame = 0;
+
+static double scale = 1;
+static double scale_smooth = 1;
+static double x = 0;
+static double y = 0;
+static double x_inc = 0;
+static double y_inc = 0;
+static double cursor_move = 0;
+
+static int last_x, last_y, pressed = 0;
+
+static void timeout_cb (void *obj)
+{
+    HildonRemoteTexture *actor = HILDON_REMOTE_TEXTURE (obj);
+
+    if (shm) {
+      gint x,y;
+
+      for (y=0;y<ANIM_HEIGHT;y++)
+        {
+          guchar *anim = &shm[(width*(y+ANIM_Y) + ANIM_X)*bpp];
+          for (x=0;x<ANIM_WIDTH;x++)
+            {
+              *anim = ((x+anim_frame)&(ANIM_FRAMES-1)) * 256 / ANIM_FRAMES;
+              anim += bpp;
+            }
+        }
+
+      hildon_remote_texture_update_area(actor,
+          ANIM_X, ANIM_Y, ANIM_WIDTH, ANIM_HEIGHT);
+      anim_frame++;
+    }
+
+    if (!pressed)
+      {
+        x += x_inc;
+        y += y_inc;
+        x_inc = x_inc * 0.8;
+        y_inc = y_inc * 0.8;
+        hildon_remote_texture_set_position (actor, x, y);
+
+        scale_smooth = scale_smooth*0.9 + scale*0.1;
+        hildon_remote_texture_set_scale (actor, scale_smooth, scale_smooth);
+      }
+
+}
+
+static void press_cb (GtkWidget *widget,
+               GdkEventButton *event, gpointer data)
+{
+  pressed = TRUE;
+  last_x = event->x;
+  last_y = event->y;
+  cursor_move = 0;
+}
+
+static void release_cb (GtkWidget *widget,
+               GdkEventButton *event, gpointer obj)
+{
+  pressed = FALSE;
+  last_x = event->x;
+  last_y = event->y;
+
+  if (cursor_move < 40)
+    {
+      scale = scale * 1.5;
+      if (scale>8) scale=0.125;
+      /* scale smooth will actually do the update */
+    }
+}
+
+static void motion_cb (GtkWidget *widget,
+                GdkEventMotion *event, gpointer data)
+{
+  HildonRemoteTexture *actor = HILDON_REMOTE_TEXTURE(data);
+
+  if (pressed)
+    {
+      x_inc = event->x - last_x;
+      y_inc = event->y - last_y;
+      cursor_move += fabs(x_inc) + fabs(y_inc);
+
+      x_inc /= scale;
+      y_inc /= scale;
+
+      x += x_inc;
+      y += y_inc;
+      hildon_remote_texture_set_position (actor, x, y);
+    }
+
+  last_x = event->x;
+  last_y = event->y;
+}
+
+int
+main (int argc, char **argv)
+{
+    gtk_init (&argc, &argv);
+
+    GdkPixbuf        *pixbuf;
+    GError           *error = 0;
+    guchar           *gpixels;
+
+    if (argc!=2)
+      {
+        printf("USAGE: hildon-remote-texture-example image.png\n");
+        printf("NB. Image should be 640x480 in size or greater\n");
+        return EXIT_FAILURE;
+      }
+
+    g_debug("Loading Image %s...", argv[1]);
+    pixbuf          = gdk_pixbuf_new_from_file (argv[1], &error);
+    width           = gdk_pixbuf_get_width (pixbuf);
+    height          = gdk_pixbuf_get_height (pixbuf);
+    bpp             = gdk_pixbuf_get_n_channels (pixbuf); /* assume 8 bit */
+    gpixels         = gdk_pixbuf_get_pixels (pixbuf);
+    g_debug("Creating Shared Memory");
+
+
+    size_t shm_size = width*height*bpp;
+    int shmid;
+
+    /*
+     * Create the segment, attach it to our data space, and copy in the
+     * texture we loaded
+     */
+    if ((shmid = shmget(shm_key, shm_size, IPC_CREAT | 0666)) < 0) {
+        perror("shmget");
+        exit(1);
+    }
+
+    if ((shm = shmat(shmid, NULL, 0)) == (guchar *) -1) {
+        perror("shmat");
+        exit(1);
+    }
+
+    memcpy(shm, gpixels, shm_size);
+
+    g_debug("Done.");
+
+
+
+    HildonProgram *program = hildon_program_get_instance ();
+
+    HildonWindow *window = HILDON_WINDOW(
+        hildon_window_new());
+    hildon_program_add_window (program, window);
+    gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
+    gtk_widget_show (GTK_WIDGET(window));
+
+    HildonRemoteTexture *actor = HILDON_REMOTE_TEXTURE
+       (hildon_remote_texture_new ());
+    gtk_window_resize(GTK_WINDOW(actor), W, H);
+
+    g_set_application_name ("Animation");
+
+    g_signal_connect (G_OBJECT (actor),
+                      "delete_event",
+                      G_CALLBACK (gtk_main_quit), NULL);
+    g_signal_connect (G_OBJECT (actor),
+                              "button-press-event",
+                              G_CALLBACK (press_cb),
+                              actor);
+    g_signal_connect (G_OBJECT (actor),
+                                  "button-release-event",
+                                  G_CALLBACK (release_cb),
+                                  actor);
+    g_signal_connect (G_OBJECT (actor),
+                      "motion-notify-event",
+                      G_CALLBACK (motion_cb),
+                      actor);
+    gtk_widget_add_events (GTK_WIDGET(actor),
+                           GDK_BUTTON_PRESS_MASK|
+                           GDK_BUTTON_MOTION_MASK|
+                           GDK_BUTTON_RELEASE_MASK);
+
+
+    gtk_widget_show_all (GTK_WIDGET (actor));
+    gdk_flush ();
+
+    hildon_remote_texture_set_parent(actor, GTK_WINDOW(window));
+    hildon_remote_texture_set_image(actor, shm_key, width, height, bpp);
+    hildon_remote_texture_set_position (actor, x, y);
+    hildon_remote_texture_set_show (actor, 1);
+
+    g_timeout_add (25, (GSourceFunc)timeout_cb, actor);
+
+    printf ("going to gtk_main ()\n");
+    gtk_main ();
+    return 0;
+}
index 350d187..07dd516 100644 (file)
@@ -70,6 +70,7 @@ libhildon_@API_VERSION_MAJOR@_la_SOURCES = \
                hildon-stackable-window.c               \
                hildon-window-stack.c                   \
                hildon-animation-actor.c                \
+               hildon-remote-texture.c                 \
                hildon-program.c                        \
                hildon-code-dialog.c                    \
                hildon-enum-types.c                     \
@@ -141,6 +142,7 @@ libhildon_@API_VERSION_MAJOR@_public_headers = \
                hildon-stackable-window.h               \
                hildon-window-stack.h                   \
                hildon-animation-actor.h                \
+               hildon-remote-texture.h                 \
                hildon-wizard-dialog.h                  \
                hildon-calendar.h                       \
                hildon-pannable-area.h                  \
@@ -189,6 +191,7 @@ noinst_HEADERS = hildon-banner-private.h            \
                hildon-stackable-window-private.h       \
                hildon-window-stack-private.h           \
                hildon-animation-actor-private.h        \
+               hildon-remote-texture-private.h         \
                hildon-wizard-dialog-private.h          \
                hildon-calendar-private.h               \
                hildon-app-menu-private.h               \
diff --git a/src/hildon-remote-texture-private.h b/src/hildon-remote-texture-private.h
new file mode 100644 (file)
index 0000000..a9a30eb
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * This file is a part of hildon
+ *
+ * Copyright (C) 2008 Nokia Corporation, all rights reserved.
+ *
+ * Contact: Rodrigo Novo <rodrigo.novo@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef                                         __HILDON_REMOTE_TEXTURE_PRIVATE_H__
+#define                                         __HILDON_REMOTE_TEXTURE_PRIVATE_H__
+
+
+#include <gtk/gtk.h>
+#include <sys/types.h>
+
+G_BEGIN_DECLS
+
+typedef struct                                  _HildonRemoteTexturePrivate HildonRemoteTexturePrivate;
+
+#define                                         HILDON_REMOTE_TEXTURE_GET_PRIVATE(obj) \
+                                                (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+                                                HILDON_TYPE_REMOTE_TEXTURE, HildonRemoteTexturePrivate));
+
+struct                                          _HildonRemoteTexturePrivate
+{
+    guint   ready : 1;
+
+    guint   set_shm : 1;
+    guint   set_damage : 1;
+    guint   set_show : 1;
+    guint   set_position : 1;
+    guint   set_scale : 1;
+    guint   set_parent : 1;
+
+    key_t   shm_key;
+    guint   shm_width;
+    guint   shm_height;
+    guint   shm_bpp;
+
+    gint    damage_x1;
+    gint    damage_y1;
+    gint    damage_x2;
+    gint    damage_y2;
+
+    guint   show;
+    guint   opacity;
+
+    double   position_x;
+    double   position_y;
+
+    double  scale_x;
+    double  scale_y;
+
+    GtkWindow* parent;
+    gulong  parent_map_event_cb_id;
+
+    gulong  map_event_cb_id;
+};
+
+G_END_DECLS
+
+#endif                                          /* __HILDON_REMOTE_TEXTURE_PRIVATE_H__ */
diff --git a/src/hildon-remote-texture.c b/src/hildon-remote-texture.c
new file mode 100644 (file)
index 0000000..cc8f607
--- /dev/null
@@ -0,0 +1,850 @@
+/*
+ * This file is a part of hildon
+ *
+ * Copyright (C) 2008 Nokia Corporation, all rights reserved.
+ *
+ * Contact: Rodrigo Novo <rodrigo.novo@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * SECTION:hildon-remote-texture
+ * @short_description: Widget representing a Clutter/GLES texture created
+ * from a shared memory area.
+ *
+ * The #HildonRemoteTexture is a GTK+ widget which allows the rendering of
+ * a shared memory area within hildon-desktop. It allows the memory area to
+ * be positioned and scaled, without altering its' contents.
+ */
+
+#include                                        <X11/X.h>
+#include                                        <X11/Xatom.h>
+
+#include                                        "hildon-remote-texture.h"
+#include                                        "hildon-remote-texture-private.h"
+#include                                        "hildon-program.h"
+#include                                        "hildon-window-private.h"
+#include                                        "hildon-program-private.h"
+
+G_DEFINE_TYPE (HildonRemoteTexture, hildon_remote_texture, GTK_TYPE_WINDOW);
+
+static GdkFilterReturn
+hildon_remote_texture_event_filter (GdkXEvent *xevent,
+                                     GdkEvent *event,
+                                     gpointer data);
+static void
+hildon_remote_texture_update_ready (HildonRemoteTexture *self);
+static void
+hildon_remote_texture_send_pending_messages (HildonRemoteTexture *self);
+static void
+hildon_remote_texture_send_all_messages (HildonRemoteTexture *self);
+static gboolean
+hildon_remote_texture_parent_map_event (GtkWidget *parent,
+                                        GdkEvent *event,
+                                        gpointer user_data);
+static gboolean
+hildon_remote_texture_map_event (GtkWidget *widget,
+                                 GdkEvent *event,
+                                 gpointer user_data);
+
+static guint32 shm_atom;
+static guint32 damage_atom;
+static guint32 show_atom;
+static guint32 position_atom;
+static guint32 scale_atom;
+static guint32 parent_atom;
+static guint32 ready_atom;
+
+static gboolean atoms_initialized = FALSE;
+
+static void
+hildon_remote_texture_realize                 (GtkWidget *widget)
+{
+    GdkDisplay *display;
+    Atom wm_type, applet_type;
+
+    GTK_WIDGET_CLASS (hildon_remote_texture_parent_class)->realize (widget);
+
+    /* Set remote texture window type. */
+
+    display = gdk_drawable_get_display (widget->window);
+
+    wm_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE");
+    applet_type = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_WM_WINDOW_TYPE_REMOTE_TEXTURE");
+
+    XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (widget->window), wm_type,
+                     XA_ATOM, 32, PropModeReplace,
+                     (unsigned char *) &applet_type, 1);
+
+    /* This is a bit of a hack, but for the sake of speed (it is assumed that
+     * once HildonRemoteTexture is created, a lot of ClientMessages will
+     * follow), we cache all ClientMessages atoms in static variables. */
+
+    if (!atoms_initialized)
+    {
+        shm_atom =
+            gdk_x11_get_xatom_by_name_for_display
+            (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_SHM");
+        damage_atom =
+            gdk_x11_get_xatom_by_name_for_display
+            (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_DAMAGE");
+       show_atom =
+           gdk_x11_get_xatom_by_name_for_display
+           (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_SHOW");
+       position_atom =
+           gdk_x11_get_xatom_by_name_for_display
+           (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_POSITION");
+       scale_atom =
+           gdk_x11_get_xatom_by_name_for_display
+           (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_SCALE");
+       parent_atom =
+           gdk_x11_get_xatom_by_name_for_display
+           (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_PARENT");
+       ready_atom =
+           gdk_x11_get_xatom_by_name_for_display
+           (display, "_HILDON_TEXTURE_CLIENT_READY");
+#if 0
+       g_debug ("shm atom = %lu\n", shm_atom);
+       g_debug ("damage atom = %lu\n", damage_atom);
+       g_debug ("show atom = %lu\n", show_atom);
+       g_debug ("position atom = %lu\n", position_atom);
+       g_debug ("scale atom = %lu\n", scale_atom);
+       g_debug ("parent atom = %lu\n", parent_atom);
+       g_debug ("ready atom = %lu\n", ready_atom);
+#endif
+
+       atoms_initialized = TRUE;
+    }
+
+    /* Wait for a ready message */
+
+    gdk_window_add_filter (widget->window,
+                          hildon_remote_texture_event_filter,
+                          widget);
+}
+
+static void
+hildon_remote_texture_unrealize               (GtkWidget *widget)
+{
+    gdk_window_remove_filter (widget->window,
+                             hildon_remote_texture_event_filter,
+                             widget);
+
+    GTK_WIDGET_CLASS (hildon_remote_texture_parent_class)->unrealize (widget);
+}
+
+static void
+hildon_remote_texture_show                    (GtkWidget *widget)
+{
+    HildonRemoteTexture        *self = HILDON_REMOTE_TEXTURE (widget);
+
+    GTK_WIDGET_CLASS (hildon_remote_texture_parent_class)->show (widget);
+    hildon_remote_texture_set_show (self, 1);
+}
+
+static void
+hildon_remote_texture_hide                    (GtkWidget *widget)
+{
+    HildonRemoteTexture        *self = HILDON_REMOTE_TEXTURE (widget);
+
+    hildon_remote_texture_set_show (self, 0);
+    GTK_WIDGET_CLASS (hildon_remote_texture_parent_class)->hide (widget);
+}
+
+static void
+hildon_remote_texture_class_init              (HildonRemoteTextureClass *klass)
+{
+    GtkWidgetClass    *widget_class = GTK_WIDGET_CLASS (klass);
+
+    widget_class->realize           = hildon_remote_texture_realize;
+    widget_class->unrealize         = hildon_remote_texture_unrealize;
+    widget_class->show              = hildon_remote_texture_show;
+    widget_class->hide              = hildon_remote_texture_hide;
+
+    g_type_class_add_private (klass, sizeof (HildonRemoteTexturePrivate));
+}
+
+static void
+hildon_remote_texture_init                    (HildonRemoteTexture *self)
+{
+    HildonRemoteTexturePrivate
+                      *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
+
+    /* Default non-zero values for the private variables */
+
+    priv->scale_x = 1;
+    priv->scale_y = 1;
+    priv->opacity = 0xff;
+}
+
+/**
+ * hildon_remote_texture_new:
+ *
+ * Creates a new #HildonRemoteTexture.
+ *
+ * Return value: A #HildonRemoteTexture
+ **/
+GtkWidget*
+hildon_remote_texture_new                     (void)
+{
+    HildonRemoteTexture *newwindow = g_object_new (HILDON_TYPE_REMOTE_TEXTURE, NULL);
+
+    gtk_window_set_decorated (GTK_WINDOW (newwindow), FALSE);
+
+    return GTK_WIDGET (newwindow);
+}
+
+/*
+ * An filter for GDK X11 events, waiting for PropertyNotify (window property
+ * changes) events, keeping track of remote texture ready atom.
+ * Having the ready atom set on the window by the window manager will trigger
+ * updates of actor parameters (position/rotation/etc...) to be sent off
+ * to the window manager for processing.
+ */
+static GdkFilterReturn
+hildon_remote_texture_event_filter             (GdkXEvent *xevent,
+                                                GdkEvent *event,
+                                                gpointer data)
+{
+    HildonRemoteTexture *self = HILDON_REMOTE_TEXTURE (data);
+    XAnyEvent *any = xevent;
+
+    if (any->type == PropertyNotify)
+    {
+       XPropertyEvent *property = xevent;
+
+       if (property->atom == ready_atom)
+       {
+           hildon_remote_texture_update_ready (self);
+       }
+    }
+
+    return GDK_FILTER_CONTINUE;
+}
+
+/*
+ * Check for the ready atom on the remote texture X11 window.
+ * If present, send all pending remote texture messages to the
+ * window manager.
+ */
+static void
+hildon_remote_texture_update_ready (HildonRemoteTexture *self)
+{
+    HildonRemoteTexturePrivate
+                      *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
+    GtkWidget          *widget = GTK_WIDGET (self);
+    Display            *display = GDK_WINDOW_XDISPLAY (widget->window);
+    Window              window = GDK_WINDOW_XID (widget->window);
+
+    int status;
+    gint xerror;
+
+    Atom actual_type;
+    int  actual_format;
+    unsigned long nitems, bytes_after;
+    unsigned char *prop = NULL;
+
+    /* Check for the "ready" property */
+
+    gdk_error_trap_push ();
+    status = XGetWindowProperty (display, window,
+                                ready_atom, 0, 32,
+                                False, XA_ATOM,
+                                &actual_type, &actual_format,
+                                &nitems, &bytes_after, &prop);
+    xerror = gdk_error_trap_pop();
+
+    if (prop)
+    {
+       /* We do not actually use the property value for anything,
+        * it is enough that the property is set. */
+
+       XFree (prop);
+    }
+
+    if (xerror ||
+       (status != Success) || (actual_type != XA_ATOM) ||
+               (actual_format != 32) || (nitems != 1))
+    {
+       priv->ready = 0;
+       return;
+    }
+
+    if (priv->ready)
+    {
+       /* The ready flag has been set once already. This means that
+        * the WM has restarted. Trigger re-mapping of the widget to
+        * update the texture actor first. Then push all remote
+        * texture settings anew. */
+
+       priv->map_event_cb_id =
+           g_signal_connect (G_OBJECT (self),
+                             "map-event",
+                             G_CALLBACK(hildon_remote_texture_map_event),
+                             self);
+
+       if (GTK_WIDGET_MAPPED (GTK_WIDGET (self)))
+       {
+           gtk_widget_unmap (GTK_WIDGET (self));
+           gtk_widget_map (GTK_WIDGET (self));
+       }
+
+       return;
+    }
+
+    priv->ready = 1;
+
+    /* Send all pending messages */
+
+    hildon_remote_texture_send_pending_messages (self);
+}
+
+static void
+hildon_remote_texture_send_pending_messages (HildonRemoteTexture *self)
+{
+    HildonRemoteTexturePrivate
+                      *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
+
+    if (priv->set_shm)
+      hildon_remote_texture_set_image(self,
+                                      priv->shm_key,
+                                      priv->shm_width, priv->shm_height,
+                                      priv->shm_bpp);
+
+    if (priv->set_damage)
+      hildon_remote_texture_update_area (self,
+                                         priv->damage_x1,
+                                         priv->damage_y1,
+                                         priv->damage_x2 - priv->damage_x1,
+                                         priv->damage_y2 - priv->damage_y1);
+
+    if (priv->set_position)
+       hildon_remote_texture_set_position (self,
+                                            priv->position_x,
+                                            priv->position_y);
+
+    if (priv->set_scale)
+       hildon_remote_texture_set_scale (self,
+                                        priv->scale_x,
+                                        priv->scale_y);
+
+    if (priv->set_parent)
+       hildon_remote_texture_set_parent (self,
+                                          priv->parent);
+
+    if (priv->set_show)
+       hildon_remote_texture_set_show_full (self,
+                                             priv->show, priv->opacity);
+}
+
+static void
+hildon_remote_texture_send_all_messages (HildonRemoteTexture *self)
+{
+    HildonRemoteTexturePrivate
+                      *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
+
+    priv->set_shm = 1;
+    priv->set_damage = 1;
+    priv->set_position = 1;
+    priv->set_scale = 1;
+    priv->set_parent = 1;
+    priv->set_show = 1;
+
+    hildon_remote_texture_send_pending_messages (self);
+}
+
+/* ------------------------------------------------------------- */
+
+/**
+ * hildon_remote_texture_send_message:
+ * @self: A #HildonRemoteTexture
+ * @message_type: Message id for the remote texture message.
+ * @l0: 1st remote texture message parameter.
+ * @l1: 2nd remote texture message parameter.
+ * @l2: 3rd remote texture message parameter.
+ * @l3: 4th remote texture message parameter.
+ * @l4: 5th remote texture message parameter.
+ *
+ * Sends an X11 ClientMessage event to the window manager with
+ * the specified parameters -- id (@message_type) and data (@l0,
+ * @l1, @l2, @l3, @l4).
+ *
+ * This is an internal utility function that application will
+ * not need to call directly.
+ **/
+void
+hildon_remote_texture_send_message (HildonRemoteTexture *self,
+                                     guint32 message_type,
+                                     guint32 l0,
+                                     guint32 l1,
+                                     guint32 l2,
+                                     guint32 l3,
+                                     guint32 l4)
+{
+    GtkWidget          *widget = GTK_WIDGET (self);
+    Display            *display = GDK_WINDOW_XDISPLAY (widget->window);
+    Window              window = GDK_WINDOW_XID (widget->window);
+
+    XEvent event = { 0 };
+
+    event.xclient.type = ClientMessage;
+    event.xclient.window = window;
+    event.xclient.message_type = (Atom)message_type;
+    event.xclient.format = 32;
+    event.xclient.data.l[0] = l0;
+    event.xclient.data.l[1] = l1;
+    event.xclient.data.l[2] = l2;
+    event.xclient.data.l[3] = l3;
+    event.xclient.data.l[4] = l4;
+
+#if 0
+    g_debug ("%lu (%lu %lu %lu %lu %lu) -> %lu\n",
+             message_type,
+             l0, l1, l2, l3, l4,
+             window);
+#endif
+
+    XSendEvent (display, window, True,
+                StructureNotifyMask,
+                (XEvent *)&event);
+}
+
+/**
+ * hildon_remote_texture_set_image:
+ * @self: A #HildonRemoteTexture
+ * @key: The key that would be used with shmget in hildon-desktop. The key
+ * should probably be created with ftok, and the relevant shared memory
+ * area should be created before this call.
+ * @width: width of image in pixels
+ * @height: height of image in pixels
+ * @bpp: BYTES per pixel - usually 2,3 or 4
+ */
+void
+hildon_remote_texture_set_image (HildonRemoteTexture *self,
+                                 key_t key,
+                                 guint width,
+                                 guint height,
+                                 guint bpp)
+{
+  HildonRemoteTexturePrivate
+                       *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
+  GtkWidget          *widget = GTK_WIDGET (self);
+
+  priv->set_shm = 1;
+  priv->shm_key = key;
+  priv->shm_width = width;
+  priv->shm_height = height;
+  priv->shm_bpp = bpp;
+
+  if (GTK_WIDGET_MAPPED (widget) && priv->ready)
+    {
+        hildon_remote_texture_send_message (self,
+                                            shm_atom,
+                                            priv->shm_key,
+                                            priv->shm_width,
+                                            priv->shm_height,
+                                            priv->shm_bpp,
+                                            0);
+        priv->set_shm = 0;
+    }
+}
+
+/**
+ * hildon_remote_texture_update_area:
+ * @self: A #HildonRemoteTexture
+ * @x: offset of damaged area in pixels
+ * @y: offset of damaged area in pixels
+ * @width: width of damaged area in pixels
+ * @height: height of damaged area in pixels
+ *
+ * This signals to hildon-desktop that a specific region of the memory area
+ * has changed. This will trigger a redraw and will update the relevant tiles
+ * of the texture.
+ */
+void
+hildon_remote_texture_update_area (HildonRemoteTexture *self,
+                                 gint x,
+                                 gint y,
+                                 gint width,
+                                 gint height)
+{
+  HildonRemoteTexturePrivate
+                     *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
+  GtkWidget          *widget = GTK_WIDGET (self);
+
+  if (priv->damage_x1==priv->damage_x2 || priv->damage_y1==priv->damage_y2)
+    {
+      priv->damage_x1 = x;
+      priv->damage_y1 = y;
+      priv->damage_x2 = x+width;
+      priv->damage_y2 = y+height;
+    }
+  else
+    {
+      if (x<priv->damage_x1) priv->damage_x1 = x;
+      if (y<priv->damage_y1) priv->damage_y1 = y;
+      if (x+width>priv->damage_x2) priv->damage_x2 = x+width;
+      if (y+height>priv->damage_y2) priv->damage_y2 = y+height;
+    }
+  priv->set_damage = 1;
+
+  if (GTK_WIDGET_MAPPED (widget) && priv->ready)
+  {
+      hildon_remote_texture_send_message (self,
+                                          damage_atom,
+                                          priv->damage_x1,
+                                          priv->damage_y1,
+                                          priv->damage_x2 - priv->damage_x1,
+                                          priv->damage_y2 - priv->damage_y1,
+                                          0);
+      priv->set_damage = 0;
+      priv->damage_x1 = 0;
+      priv->damage_y1 = 0;
+      priv->damage_x2 = 0;
+      priv->damage_y2 = 0;
+  }
+}
+
+/**
+ * hildon_remote_texture_set_show_full:
+ * @self: A #HildonRemoteTexture
+ * @show: A boolean flag setting the visibility of the remote texture.
+ * @opacity: Desired opacity setting
+ *
+ * Send a message to the window manager setting the visibility of
+ * the remote texture. This will only affect the visibility of
+ * the remote texture set by the compositing window manager in its own
+ * rendering pipeline, after X has drawn the window to the off-screen
+ * buffer. This setting, naturally, has no effect if the #HildonRemoteTexture
+ * widget is not visible in X11 terms (i.e. realized and mapped).
+ *
+ * Furthermore, if a widget is parented, its final visibility will be
+ * affected by that of the parent window.
+ *
+ * The opacity setting ranges from zero (0), being completely transparent
+ * to 255 (0xff) being fully opaque.
+ *
+ * If the remote texture WM-counterpart is not ready, the show message
+ * will be queued until the WM is ready for it.
+ **/
+void
+hildon_remote_texture_set_show_full (HildonRemoteTexture *self,
+                                     gint show,
+                                     gint opacity)
+{
+    HildonRemoteTexturePrivate
+                      *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
+    GtkWidget          *widget = GTK_WIDGET (self);
+
+    if (opacity > 255)
+       opacity = 255;
+
+    if (opacity < 0)
+       opacity = 0;
+
+    priv->show = show;
+    priv->opacity = opacity;
+    priv->set_show = 1;
+
+    if (GTK_WIDGET_MAPPED (widget) && priv->ready)
+    {
+       /* Defer show messages until the remote texture is parented
+        * and the parent window is mapped */
+
+       if (!priv->parent || !GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent)))
+           return;
+
+       hildon_remote_texture_send_message (self,
+                                            show_atom,
+                                            show, opacity,
+                                            0, 0, 0);
+       priv->set_show = 0;
+    }
+}
+
+/**
+ * hildon_remote_texture_set_show:
+ * @self: A #HildonRemoteTexture
+ * @show: A boolean flag setting the visibility of the remote texture.
+ *
+ * This function is a shortcut for hildon_remote_texture_set_show_full(),
+ * setting the overall actor visibility without changing it's opacity
+ * setting.
+ **/
+void
+hildon_remote_texture_set_show (HildonRemoteTexture *self,
+                                gint show)
+{
+    HildonRemoteTexturePrivate
+                      *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
+
+    hildon_remote_texture_set_show_full (self,
+                                         show, priv->opacity);
+}
+
+/**
+ * hildon_remote_texture_set_opacity:
+ * @self: A #HildonRemoteTexture
+ * @opacity: Desired opacity setting
+ *
+ * This function is a shortcut for hildon_remote_texture_set_show_full(),
+ * setting actor opacity without changing it's overall visibility.
+ *
+ * See hildon_remote_texture_set_show_full() for description of the range
+ * of values @opacity argument takes.
+ **/
+void
+hildon_remote_texture_set_opacity (HildonRemoteTexture *self,
+                                   gint opacity)
+{
+    HildonRemoteTexturePrivate
+                      *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
+
+    hildon_remote_texture_set_show_full (self,
+                                         priv->show, opacity);
+}
+
+/**
+ * hildon_remote_texture_set_position_full:
+ * @self: A #HildonRemoteTexture
+ * @x: Desired X coordinate
+ * @y: Desired Y coordinate
+ * @depth: Desired window depth (Z coordinate)
+ *
+ * Send a message to the window manager setting the offset of the remote
+ * texture in the window (in Remote texture's pixels). The texture
+ * is also subject to the animation effects rendered by the compositing
+ * window manager on that window (like those by task switcher).
+ *
+ * If the remote texture WM-counterpart is not ready, the show message
+ * will be queued until the WM is ready for it.
+ **/
+void
+hildon_remote_texture_set_position (HildonRemoteTexture *self,
+                                    double x,
+                                    double y)
+{
+    HildonRemoteTexturePrivate
+                      *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
+    GtkWidget          *widget = GTK_WIDGET (self);
+
+    priv->position_x = x;
+    priv->position_y = y;
+    priv->set_position = 1;
+
+    if (GTK_WIDGET_MAPPED (widget) && priv->ready)
+    {
+       hildon_remote_texture_send_message (self,
+                                           position_atom,
+                                           (gint)(x*65536), (gint)(y*65536),
+                                           0, 0, 0);
+       priv->set_position = 0;
+    }
+}
+
+/**
+ * hildon_remote_texture_set_scalex:
+ * @self: A #HildonRemoteTexture
+ * @x_scale: The scale factor for the memory area to be rendered in the X-axis
+ * @y_scale: The scale factor for the memory area to be rendered in the X-axis
+ **/
+void
+hildon_remote_texture_set_scale (HildonRemoteTexture *self,
+                               double x_scale,
+                               double y_scale)
+{
+    HildonRemoteTexturePrivate
+                      *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
+    GtkWidget          *widget = GTK_WIDGET (self);
+
+    priv->scale_x = x_scale;
+    priv->scale_y = y_scale;
+    priv->set_scale = 1;
+
+    if (GTK_WIDGET_MAPPED (widget) && priv->ready)
+    {
+       hildon_remote_texture_send_message (self,
+                                            scale_atom,
+                                            priv->scale_x * (1 << 16),
+                                            priv->scale_y * (1 << 16),
+                                            0, 0, 0);
+       priv->set_scale = 0;
+    }
+}
+
+/*
+ * This callback will be triggered by the parent widget of
+ * an remote texture when it is mapped. The compositing
+ * window manager is now ready to parent the remote texture
+ * into the target parent window.
+ */
+static gboolean
+hildon_remote_texture_parent_map_event (GtkWidget *parent,
+                                        GdkEvent *event,
+                                        gpointer user_data)
+{
+    hildon_remote_texture_set_parent (HILDON_REMOTE_TEXTURE (user_data),
+                                      GTK_WINDOW (parent));
+    return FALSE;
+}
+
+/*
+ * This callback will be triggered by the widget re-mapping
+ * itself in case of WM restarting. The point is to push all
+ * remote texture parameters anew to the WM.
+ */
+static gboolean
+hildon_remote_texture_map_event (GtkWidget *widget,
+                                 GdkEvent *event,
+                                 gpointer user_data)
+{
+    HildonRemoteTexture
+                      *self = HILDON_REMOTE_TEXTURE (user_data);
+    HildonRemoteTexturePrivate
+                      *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
+
+    hildon_remote_texture_send_all_messages (self);
+
+    /* Disconnect the "map-event" handler after the "emergency resend all
+     * actor parameters" drill is over. */
+
+    if (priv->map_event_cb_id)
+    {
+       g_signal_handler_disconnect (self,
+                                    priv->map_event_cb_id);
+       priv->map_event_cb_id = 0;
+    }
+
+    return FALSE;
+}
+
+/**
+ * hildon_remote_texture_set_parent:
+ * @self: A #HildonRemoteTexture
+ * @parent: A #GtkWindow that the actor will be parented to.
+ *
+ * Send a message to the window manager setting the parent window
+ * for the remote texture. Parenting an actor will not affect the
+ * X window that the HildonRemoteTexture represents, but it's off-screen
+ * bitmap as it is handled by the compositing window manager.
+ *
+ * Parenting an remote texture will affect its visibility as set
+ * by the gtk_widget_show(), gtk_widget_hide() and
+ * hildon_remote_texture_set_show(). The remote texture will only be
+ * visible when the top-level window it is parented is visible.
+ *
+ * Passing %NULL as a @parent argument will unparent the remote texture.
+ * This will restore the actor's visibility if it was suppressed by
+ * being unparented or parented to an unmapped window.
+ *
+ * If the remote texture WM-counterpart is not ready, the show message
+ * will be queued until the WM is ready for it.
+ **/
+void
+hildon_remote_texture_set_parent (HildonRemoteTexture *self,
+                                  GtkWindow *parent)
+{
+    HildonRemoteTexturePrivate
+                      *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self);
+    GtkWidget          *widget = GTK_WIDGET (self);
+
+    gtk_window_set_transient_for (GTK_WINDOW (self), parent);
+
+    if (priv->parent != parent)
+    {
+       /* Setting a new parent */
+
+       if (priv->parent)
+       {
+           if (priv->parent_map_event_cb_id)
+               g_signal_handler_disconnect (priv->parent,
+                                            priv->parent_map_event_cb_id);
+
+           /* Might need a synchronized "parent(0)" or "parent(new parent)"
+            * message here before we can safely decrease the reference count. */
+
+           g_object_unref (priv->parent);
+       }
+
+       priv->parent = parent;
+       priv->set_parent = 1;
+
+       if (parent != 0)
+       {
+           /* The widget is being (re)parented, not unparented. */
+
+           g_object_ref (parent);
+
+           priv->parent_map_event_cb_id =
+               g_signal_connect (G_OBJECT (priv->parent),
+                                 "map-event",
+                                 G_CALLBACK(hildon_remote_texture_parent_map_event),
+                                 self);
+       }
+       else
+       {
+           priv->parent_map_event_cb_id = 0;
+       }
+    }
+
+    if (GTK_WIDGET_MAPPED (widget) && priv->ready)
+    {
+       Window win = 0;
+
+       /* If the remote texture is being unparented or parented to an
+        * unmapped widget, force its visibility to "hidden". */
+
+       if (!priv->parent || !GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent)))
+       {
+           hildon_remote_texture_send_message (self,
+                                                show_atom,
+                                                0, priv->opacity,
+                                                0, 0, 0);
+       }
+
+       /* If the widget is being parented (parent != 0), only proceed when
+        * the parent widget is realized, since we need the X window id of
+        * the parent. If the widget is being unparented (parent == 0), pass
+        * the "special" window id of 0 in the message. */
+
+       if (priv->parent)
+       {
+           if (!GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent)))
+               return;
+
+           GdkWindow *gdk = GTK_WIDGET (parent)->window;
+           win = GDK_WINDOW_XID (gdk);
+       }
+
+       hildon_remote_texture_send_message (self,
+                                            parent_atom,
+                                            win,
+                                            0, 0, 0, 0);
+       priv->set_parent = 0;
+
+       /* Set remote texture visibility to desired value (in case it was
+        * forced off when the actor was parented into an unmapped widget). */
+
+       hildon_remote_texture_send_message (self,
+                                            show_atom,
+                                            priv->show, priv->opacity,
+                                            0, 0, 0);
+       priv->set_show = 0;
+    }
+}
+
diff --git a/src/hildon-remote-texture.h b/src/hildon-remote-texture.h
new file mode 100644 (file)
index 0000000..5889122
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * This file is a part of hildon
+ *
+ * Copyright (C) 2008 Nokia Corporation, all rights reserved.
+ *
+ * Contact: Rodrigo Novo <rodrigo.novo@nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef                                         __HILDON_REMOTE_TEXTURE_H__
+#define                                         __HILDON_REMOTE_TEXTURE_H__
+
+#include                                        "hildon-window.h"
+#include                                        <gtk/gtk.h>
+#include                                        <sys/types.h>
+
+G_BEGIN_DECLS
+
+#define                                         HILDON_TYPE_REMOTE_TEXTURE \
+                                                (hildon_remote_texture_get_type())
+
+#define                                         HILDON_REMOTE_TEXTURE(obj) \
+                                                (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+                                                HILDON_TYPE_REMOTE_TEXTURE, \
+                                                HildonRemoteTexture))
+
+#define                                         HILDON_REMOTE_TEXTURE_CLASS(klass) \
+                                                (G_TYPE_CHECK_CLASS_CAST ((klass), \
+                                                HILDON_TYPE_REMOTE_TEXTURE, \
+                                                HildonRemoteTextureClass))
+
+#define                                         HILDON_IS_REMOTE_TEXTURE(obj) \
+                                                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+                                                HILDON_TYPE_REMOTE_TEXTURE))
+
+#define                                         HILDON_IS_REMOTE_TEXTURE_CLASS(klass) \
+                                                (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+                                                HILDON_TYPE_REMOTE_TEXTURE))
+
+#define                                         HILDON_REMOTE_TEXTURE_GET_CLASS(obj) \
+                                                (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+                                                HILDON_TYPE_REMOTE_TEXTURE, \
+                                                HildonRemoteTextureClass))
+
+typedef struct                                  _HildonRemoteTexture HildonRemoteTexture;
+typedef struct                                  _HildonRemoteTextureClass HildonRemoteTextureClass;
+
+struct                                          _HildonRemoteTextureClass
+{
+    GtkWindowClass parent_class;
+
+    /* Padding for future extension */
+    void (*_hildon_reserved1)(void);
+    void (*_hildon_reserved2)(void);
+    void (*_hildon_reserved3)(void);
+    void (*_hildon_reserved4)(void);
+};
+
+struct                                          _HildonRemoteTexture
+{
+    GtkWindow parent;
+};
+
+GType
+hildon_remote_texture_get_type                (void) G_GNUC_CONST;
+
+GtkWidget*
+hildon_remote_texture_new                     (void);
+
+void
+hildon_remote_texture_send_message (HildonRemoteTexture *self,
+                                     guint32 message_type,
+                                     guint32 l0,
+                                     guint32 l1,
+                                     guint32 l2,
+                                     guint32 l3,
+                                     guint32 l4);
+
+void
+hildon_remote_texture_set_image (HildonRemoteTexture *self,
+                                 key_t key,
+                                 guint width,
+                                 guint height,
+                                 guint bpp);
+void
+hildon_remote_texture_update_area (HildonRemoteTexture *self,
+                                   gint x,
+                                   gint y,
+                                   gint width,
+                                   gint height);
+void
+hildon_remote_texture_set_show_full (HildonRemoteTexture *self,
+                                     gint show,
+                                     gint opacity);
+void
+hildon_remote_texture_set_show (HildonRemoteTexture *self,
+                                gint show);
+void
+hildon_remote_texture_set_opacity (HildonRemoteTexture *self,
+                                   gint opacity);
+void
+hildon_remote_texture_set_position (HildonRemoteTexture *self,
+                                    double x,
+                                    double y);
+void
+hildon_remote_texture_set_scale (HildonRemoteTexture *self,
+                                 double x_scale,
+                                 double y_scale);
+void
+hildon_remote_texture_set_parent (HildonRemoteTexture *self,
+                                  GtkWindow *parent);
+
+G_END_DECLS
+
+#endif                                 /* __HILDON_REMOTE_TEXTURE_H__ */
index 221e675..41c0e12 100644 (file)
@@ -71,6 +71,7 @@
 #include                                        "hildon-stackable-window.h"
 #include                                        "hildon-window-stack.h"
 #include                                        "hildon-animation-actor.h"
+#include                                        "hildon-remote-texture.h"
 #include                                        "hildon-wizard-dialog.h"
 #include                                        "hildon-calendar.h"
 #include                                        "hildon-bread-crumb-trail.h"
@@ -84,4 +85,4 @@
 #include                                        "hildon-dialog.h"
 #include                                        "hildon-main.h"
 
-#endif 
+#endif