2006-06-21 Matthew Allum <mallum@openedhand.com>
authorMatthew Allum <mallum@openedhand.com>
Wed, 21 Jun 2006 16:29:28 +0000 (16:29 +0000)
committerMatthew Allum <mallum@openedhand.com>
Wed, 21 Jun 2006 16:29:28 +0000 (16:29 +0000)
        * clutter/Makefile.am:
        Make sure clutter.h included.
        * clutter/clutter-stage.c: (clutter_stage_realize),
        (clutter_stage_get_actor_at_pos):
        Select for motion events on X window.
        Return highest rather than lowest found actor for actor_at_pos.
        * examples/Makefile.am:
        Remove test-text, remane test video.
        * examples/README:
        Add info about the included examples.
        * examples/test-video.c:
        * examples/video-player.c:
        Redo test-video a little nicer and rename.
        * examples/video-cube.c:
        Fix so it at least 'works' again.
        * examples/test.c:
        Clean up a little.

12 files changed:
ChangeLog
clutter/Makefile.am
clutter/clutter-stage.c
examples/Makefile.am
examples/README [new file with mode: 0644]
examples/media-actions-pause.png [new file with mode: 0644]
examples/media-actions-start.png [new file with mode: 0644]
examples/test-video.c [deleted file]
examples/test.c
examples/vid-panel.png [new file with mode: 0644]
examples/video-cube.c
examples/video-player.c [new file with mode: 0644]

index b74d007..d87024b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2006-06-21  Matthew Allum  <mallum@openedhand.com>
+
+       * clutter/Makefile.am:
+       Make sure clutter.h included.
+       * clutter/clutter-stage.c: (clutter_stage_realize),
+       (clutter_stage_get_actor_at_pos):
+       Select for motion events on X window.
+       Return highest rather than lowest found actor for actor_at_pos.
+       * examples/Makefile.am:
+       Remove test-text, remane test video.
+       * examples/README:
+       Add info about the included examples.
+       * examples/test-video.c:
+       * examples/video-player.c:
+       Redo test-video a little nicer and rename.
+       * examples/video-cube.c: 
+       Fix so it at least 'works' again.
+       * examples/test.c: 
+       Clean up a little.
+
 2006-06-21  Ross Burton  <ross@openedhand.com>
 
        * Makefile.am:
index e1c1d89..30146b2 100644 (file)
@@ -5,22 +5,22 @@ GLIB_MKENUMS=`pkg-config --variable=glib_mkenums glib-2.0`
 
 BUILT_SOURCES = $(MARSHALFILES) $(ENUMFILES)
 
-source_h =                               \
-       $(srcdir)/clutter-keysyms.h       \
-       $(srcdir)/clutter-util.h          \
-       $(srcdir)/clutter-media.h         \
-        $(srcdir)/clutter-event.h         \
-       $(srcdir)/clutter-color.h         \
-       $(srcdir)/clutter-timeline.h      \
-       $(srcdir)/clutter-actor.h         \
-       $(srcdir)/clutter-group.h         \
-       $(srcdir)/clutter-stage.h         \
-       $(srcdir)/clutter-rectangle.h     \
-       $(srcdir)/clutter-texture.h       \
-       $(srcdir)/clutter-clone-texture.h \
-       $(srcdir)/clutter-video-texture.h \
-       $(srcdir)/clutter-label.h         \
-        $(srcdir)/clutter-main.h          
+source_h = clutter.h               \
+          clutter-keysyms.h       \
+          clutter-util.h          \
+          clutter-media.h         \
+           clutter-event.h         \
+          clutter-color.h         \
+          clutter-timeline.h      \
+          clutter-actor.h         \
+          clutter-group.h         \
+          clutter-stage.h         \
+          clutter-rectangle.h     \
+          clutter-texture.h       \
+          clutter-clone-texture.h \
+          clutter-video-texture.h \
+          clutter-label.h         \
+           clutter-main.h          
 
 clutter-marshal.h: clutter-marshal.list
        ( $(GLIB_GENMARSHAL) --prefix=clutter_marshal \
index f39296a..79ee032 100644 (file)
@@ -403,6 +403,8 @@ clutter_stage_realize (ClutterActor *actor)
                   priv->xwin, 
                   StructureNotifyMask
                   |ExposureMask
+                  /* FIXME: we may want to eplicity enable MotionMask */
+                  |PointerMotionMask
                   |KeyPressMask
                   |KeyReleaseMask
                   |ButtonPressMask
@@ -1058,7 +1060,8 @@ clutter_stage_get_actor_at_pos (ClutterStage *stage,
        g_print ("Hit at %i\n", buff[i * 4 + 3]);
 #endif
   
-      found = clutter_group_find_child_by_id (CLUTTER_GROUP (stage), buff[3]);
+      found = clutter_group_find_child_by_id (CLUTTER_GROUP (stage), 
+                                             buff[(hits-1) * 4 + 3]);
     }
   
   sync_gl_viewport (stage);
index 5f74677..86881d9 100644 (file)
@@ -1,4 +1,4 @@
-noinst_PROGRAMS = test test-video video-cube test-text super-oh
+noinst_PROGRAMS = test video-player video-cube super-oh
 
 INCLUDES = -I$(top_srcdir)/
 
@@ -10,9 +10,9 @@ test_LDFLAGS = \
     $(GCONF_LIBS) \
     $(top_builddir)/clutter/libclutter-@CLUTTER_MAJORMINOR@.la 
 
-test_video_SOURCES = test-video.c
-test_video_CFLAGS = $(CLUTTER_CFLAGS) $(GST_CFLAGS) $(GCONF_CFLAGS)
-test_video_LDFLAGS = \
+video_player_SOURCES = video-player.c
+video_player_CFLAGS = $(CLUTTER_CFLAGS) $(GST_CFLAGS) $(GCONF_CFLAGS)
+video_player_LDFLAGS = \
     $(CLUTTER_LIBS) \
     $(GST_LIBS)   \
     $(GCONF_LIBS) \
@@ -26,14 +26,6 @@ video_cube_LDFLAGS = \
     $(GCONF_LIBS) \
     $(top_builddir)/clutter/libclutter-@CLUTTER_MAJORMINOR@.la 
 
-test_text_SOURCES = test-text.c
-test_text_CFLAGS = $(CLUTTER_CFLAGS) $(GST_CFLAGS) $(GCONF_CFLAGS)
-test_text_LDFLAGS = \
-    $(CLUTTER_LIBS) \
-    $(GST_LIBS)   \
-    $(GCONF_LIBS) \
-    $(top_builddir)/clutter/libclutter-@CLUTTER_MAJORMINOR@.la 
-
 super_oh_SOURCES = super-oh.c
 super_oh_CFLAGS = $(CLUTTER_CFLAGS) $(GST_CFLAGS) $(GCONF_CFLAGS)
 super_oh_LDFLAGS = \
@@ -42,4 +34,9 @@ super_oh_LDFLAGS = \
     $(GCONF_LIBS) \
     $(top_builddir)/clutter/libclutter-@CLUTTER_MAJORMINOR@.la 
 
-EXTRA_DIST = redhand.png clutter-logo-800x600.png
\ No newline at end of file
+EXTRA_DIST = redhand.png              \
+             clutter-logo-800x600.png \
+             media-actions-pause.png  \
+             media-actions-start.png  \
+             vid-panel.png            \
+             README 
diff --git a/examples/README b/examples/README
new file mode 100644 (file)
index 0000000..1e2e389
--- /dev/null
@@ -0,0 +1,37 @@
+examples/
+===
+
+This directory contains a number of simple hacks come tests come
+examples come clutter demos.
+
+There are:
+
+ o test
+
+   Lots of randomness. Scratchpad to test new features.
+
+ o test.py
+
+   Like above but more randomness in python.
+
+ o super-oh
+
+   Spinning OH logos. Click to dissapear.
+
+ o video-player.
+   Simple fullscreen video player. 
+
+   - Move mouse to see controls.
+   - Hit q or Esc to exit, p to toggle pause state.
+   - Has some useless cheesy effects built in.
+      - Hit e to flip the video. 
+
+ o video-cube.
+   Pure evil. A nasty hack to do a video cube with clutter.
+   Could be done much nicer.
+
+Also see http://svn.o-hand.com/repos/misc/trunk/opt for a simple
+clutter based presentation program.
diff --git a/examples/media-actions-pause.png b/examples/media-actions-pause.png
new file mode 100644 (file)
index 0000000..38614e1
Binary files /dev/null and b/examples/media-actions-pause.png differ
diff --git a/examples/media-actions-start.png b/examples/media-actions-start.png
new file mode 100644 (file)
index 0000000..b3c6170
Binary files /dev/null and b/examples/media-actions-start.png differ
diff --git a/examples/test-video.c b/examples/test-video.c
deleted file mode 100644 (file)
index efa0690..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-#include <clutter/clutter.h>
-
-ClutterActor *rect; /* um... */
-
-
-void input_cb (ClutterStage *stage, 
-              ClutterEvent *event,
-              gpointer      user_data)
-{
-  ClutterVideoTexture *vtex = CLUTTER_VIDEO_TEXTURE(user_data);
-  static gint paused = 0;
-
-  if (event->type == CLUTTER_KEY_RELEASE)
-    {
-      if (paused)
-       {
-         clutter_media_set_playing (CLUTTER_MEDIA(vtex), TRUE);
-         paused = 0;
-       }
-      else
-       {
-         clutter_media_set_playing (CLUTTER_MEDIA(vtex), FALSE);
-         paused = 1;
-       }
-    }
-}
-
-void
-size_change (ClutterTexture *texture, 
-            gint            width,
-            gint            height,
-            gpointer        user_data)
-{
-  ClutterActor  *stage;
-  ClutterGeometry  stage_geom;
-  gint             vid_width, vid_height, new_y, new_height;
-
-  stage = clutter_stage_get_default ();
-
-  clutter_actor_get_geometry (stage, &stage_geom);
-
-  clutter_texture_get_base_size (texture, &vid_width, &vid_height);
-
-  printf("*** vid : %ix%i stage %ix%i ***\n", 
-        vid_width, vid_height, stage_geom.width, stage_geom.height);
-
-
-  new_height = ( vid_height * stage_geom.width ) / vid_width;
-  new_y      = (stage_geom.height - new_height) / 2;
-
-  clutter_actor_set_position (CLUTTER_ACTOR (texture), 0, new_y);
-
-  clutter_actor_set_size (CLUTTER_ACTOR (texture),
-                           stage_geom.width,
-                           new_height);
-
-  // clutter_actor_set_opacity (CLUTTER_ACTOR (texture), 50);
-
-  printf("*** Pos set to +%i+%i , %ix%i ***\n", 
-        0, new_y, stage_geom.width, new_height);
-}
-
-void 
-tick (GObject      *object,
-      GParamSpec   *pspec,
-      ClutterLabel *label)
-{
-  ClutterVideoTexture *vtex;
-  gint                 w, h, position, duration;
-  gchar                buf[256];
-
-  vtex = CLUTTER_VIDEO_TEXTURE(object);
-
-  position = clutter_media_get_position (CLUTTER_MEDIA(vtex));
-  duration = clutter_media_get_duration (CLUTTER_MEDIA(vtex));
-
-  g_snprintf(buf, 256, "%i / %i", position, duration);
-
-  clutter_label_set_text (label, buf);
-
-  clutter_texture_get_base_size (CLUTTER_TEXTURE(label), &w, &h);
-  clutter_actor_set_size(rect, w+10, h+10);
-}
-
-int
-main (int argc, char *argv[])
-{
-  ClutterActor        *label, *vtexture, *ctexture;
-  ClutterActor        *stage;
-  ClutterColor           rect_color =  { 0xde, 0xde, 0xdf, 0xaa };
-  ClutterColor           stage_color = { 0x00, 0x00, 0x00, 0x00 };
-  GError                *err = NULL;
-
-  if (argc < 2)
-    g_error("%s <video file>", argv[0]);
-
-  clutter_init (&argc, &argv);
-
-  vtexture = clutter_video_texture_new ();
-
-  clutter_media_set_filename(CLUTTER_MEDIA(vtexture), argv[1]);
-
-  stage = clutter_stage_get_default ();
-
-  /* Broken..
-  g_object_set(vtexture, "repeat-x", TRUE, NULL);
-  g_object_set(vtexture, "repeat-y", TRUE, NULL);
-  */
-
-  if (vtexture == NULL || err != NULL)
-    {
-      g_error("failed to create vtexture, err: %s", err->message);
-    }
-
-  label = clutter_label_new_with_text ("Sans Bold 24", "Loading...");
-
-  clutter_actor_set_position(label, 10, 10);
-
-  rect = clutter_rectangle_new_with_color (&rect_color);
-  clutter_actor_set_size(rect, 0, 0);
-  clutter_actor_set_position(rect, 5, 5);
-
-  ctexture = clutter_clone_texture_new (CLUTTER_TEXTURE(vtexture));
-  clutter_actor_set_opacity (CLUTTER_ACTOR (ctexture), 100);
-
-  clutter_actor_set_size (ctexture, 640, 50);
-  clutter_actor_set_position (ctexture, 0, 430);
-
-  clutter_group_add_many (CLUTTER_GROUP (stage), 
-                         vtexture, rect, label, ctexture, NULL);
-
-  clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); 
-
-  g_signal_connect (stage, "input-event",
-                   G_CALLBACK (input_cb), 
-                   vtexture);
-  clutter_group_show_all (CLUTTER_GROUP (stage));
-
-  clutter_media_set_playing (CLUTTER_MEDIA(vtexture), TRUE);
-
-  g_signal_connect (CLUTTER_MEDIA(vtexture),
-                   "notify::position",
-                   G_CALLBACK (tick),
-                   label);
-
-  g_object_set (G_OBJECT(vtexture), "sync-size", FALSE, NULL);
-
-  g_signal_connect (CLUTTER_TEXTURE(vtexture), 
-                   "size-change",
-                   G_CALLBACK (size_change), NULL);
-
-  clutter_main();
-
-  g_object_unref (stage);
-
-  return 0;
-}
index 60d5a45..5a9e7b3 100644 (file)
@@ -1,6 +1,6 @@
 #include <clutter/clutter.h>
 
-#define PARA_TEXT "This is a paragraph of text to check both" \
+#define PARA_TEXT "This is a paragraph of text to check both " \
                   "word wrapping and basic clipping."
 
 void
@@ -91,6 +91,7 @@ main (int argc, char *argv[])
 
   para = clutter_label_new_with_text ("Sans 24", PARA_TEXT);
   clutter_actor_set_position(para, 10, 10);
+  clutter_label_set_text_extents (CLUTTER_LABEL(para), 200, 0);
 
   clutter_group_add (CLUTTER_GROUP (stage), texture);
   clutter_group_add (CLUTTER_GROUP (stage), label);
diff --git a/examples/vid-panel.png b/examples/vid-panel.png
new file mode 100644 (file)
index 0000000..d7c3e18
Binary files /dev/null and b/examples/vid-panel.png differ
index 221e073..9aa95b2 100644 (file)
@@ -228,15 +228,17 @@ int
 main (int argc, char *argv[])
 {
   ClutterActor      *label, *texture, *vtexture; 
-  ClutterActor      *stage = clutter_stage_get_default ();
-  GdkPixbuf           *pixbuf;
-  GError              *err = NULL;
+  ClutterActor      *stage;
+  GdkPixbuf         *pixbuf;
+  GError            *err = NULL;
 
   if (argc < 2)
     g_error("%s <video file>", argv[0]);
 
   clutter_init (&argc, &argv);
 
+  stage = clutter_stage_get_default ();
+
   pixbuf = gdk_pixbuf_new_from_file ("clutter-logo-800x600.png", NULL);
 
   if (!pixbuf)
@@ -254,7 +256,6 @@ main (int argc, char *argv[])
       g_error("failed to create vtexture, err: %s", err->message);
     }
 
-
   clutter_media_set_filename (CLUTTER_MEDIA(vtexture), argv[1]);
 
   clutter_group_add (CLUTTER_GROUP (stage), texture);
diff --git a/examples/video-player.c b/examples/video-player.c
new file mode 100644 (file)
index 0000000..e2662b4
--- /dev/null
@@ -0,0 +1,383 @@
+#include <clutter/clutter.h>
+
+#define SEEK_H 20
+#define SEEK_W 690
+
+typedef struct VideoApp
+{
+  ClutterActor *vtexture;
+
+  ClutterActor    *control, *control_bg, *control_play, *control_pause, 
+    *control_seek1, *control_seek2, *control_seekbar, *control_label;
+  gboolean         controls_showing, paused;
+  guint            controls_timeout;
+  ClutterTimeline *controls_tl, *effect1_tl;
+}
+VideoApp;
+
+static void
+show_controls (VideoApp *app, gboolean vis);
+
+void
+control_tl_cb (ClutterTimeline *timeline, 
+              gint             frame_num, 
+              VideoApp        *app)
+{
+  guint8 opacity;
+
+  clutter_group_show_all (CLUTTER_GROUP (app->control));
+  clutter_actor_hide (app->paused ? app->control_pause : app->control_play);
+  clutter_actor_show (app->paused ? app->control_play : app->control_pause);
+
+  opacity = ( frame_num * 0xde ) / clutter_timeline_get_n_frames(timeline);
+
+  if (!app->controls_showing)
+    opacity = 0xde - opacity;
+  
+  clutter_actor_set_opacity (app->control, opacity);
+}
+
+void
+control_tl_complete_cb (ClutterTimeline *timeline, 
+                       VideoApp        *app)
+{
+  if (!app->controls_showing)
+      clutter_group_hide_all (CLUTTER_GROUP (app->control));
+
+  app->controls_timeout = 0;
+}
+
+static gboolean
+controls_timeout_cb (VideoApp *app)
+{
+  show_controls (app, FALSE);
+  return FALSE;
+}
+
+static void
+show_controls (VideoApp *app, gboolean vis)
+{
+  if (clutter_timeline_is_playing (app->controls_tl))
+    return;
+
+  if (vis == TRUE && app->controls_showing == FALSE)
+    {
+      app->controls_showing = TRUE;
+      clutter_timeline_start (app->controls_tl);
+
+      app->controls_timeout = g_timeout_add (5 * 1000,  
+                                            (GSourceFunc)controls_timeout_cb,
+                                            app);
+      return;
+    }
+
+  if (vis == TRUE && app->controls_showing == TRUE)
+    {
+      if (app->controls_timeout)
+       {
+         g_source_remove (app->controls_timeout);
+
+         app->controls_timeout 
+           = g_timeout_add (5 * 1000,  
+                            (GSourceFunc)controls_timeout_cb,
+                            app);
+       }
+      return;
+    }
+
+  if (vis == FALSE && app->controls_showing == TRUE)
+    {
+      app->controls_showing = FALSE;
+      clutter_timeline_start (app->controls_tl);
+      return;
+    }
+}
+
+void
+toggle_pause_state (VideoApp *app)
+{
+  if (app->paused)
+    {
+      clutter_media_set_playing (CLUTTER_MEDIA(app->vtexture), 
+                                TRUE);
+      app->paused = FALSE;
+      clutter_actor_hide (app->control_play);
+      clutter_actor_show (app->control_pause);
+    }
+  else
+    {
+      clutter_media_set_playing (CLUTTER_MEDIA(app->vtexture), 
+                                FALSE);
+      app->paused = TRUE;
+      clutter_actor_hide (app->control_pause);
+      clutter_actor_show (app->control_play);
+    }
+}
+
+void 
+input_cb (ClutterStage *stage, 
+         ClutterEvent *event,
+         gpointer      user_data)
+{
+  VideoApp *app = (VideoApp*)user_data;
+
+  switch (event->type)
+    {
+    case CLUTTER_MOTION:
+      show_controls (app, TRUE);
+      break;
+    case CLUTTER_BUTTON_PRESS:
+      if (app->controls_showing)
+       {
+         ClutterActor       *actor;
+         ClutterButtonEvent *bev = (ClutterButtonEvent *) event;
+
+         actor 
+           = clutter_stage_get_actor_at_pos 
+                                (CLUTTER_STAGE(clutter_stage_get_default()),
+                                 bev->x, bev->y);
+
+         if (actor == app->control_pause || actor == app->control_play)
+           {
+             toggle_pause_state (app);
+             return;
+           }
+
+         if (actor == app->control_seek1 
+             || actor == app->control_seek2
+             || actor == app->control_seekbar)
+           {
+             gint x, y, dist, pos;
+
+             clutter_actor_get_abs_position (app->control_seekbar, &x, &y);
+
+             dist = bev->x - x;
+
+             CLAMP(dist, 0, SEEK_W);
+
+             pos = (dist * clutter_media_get_duration 
+                               (CLUTTER_MEDIA(app->vtexture))) / SEEK_W;
+
+             clutter_media_set_position (CLUTTER_MEDIA(app->vtexture),
+                                         pos);
+           }
+       }
+      break;
+    case CLUTTER_KEY_RELEASE:
+      {
+       ClutterKeyEvent* kev = (ClutterKeyEvent *) event;
+       
+       switch (clutter_key_event_symbol (kev))
+         {
+         case CLUTTER_q:
+         case CLUTTER_Escape:
+           clutter_main_quit ();
+           break;
+         case CLUTTER_e:
+           if (!clutter_timeline_is_playing (app->effect1_tl))
+             clutter_timeline_start (app->effect1_tl);
+           break;
+         default:
+           toggle_pause_state (app);
+           break;
+         }
+      }
+    default:
+      break;
+    }
+}
+
+void
+size_change (ClutterTexture *texture, 
+            gint             width,
+            gint             height,
+            gpointer         user_data)
+{
+  ClutterActor  *stage;
+  ClutterGeometry  stage_geom;
+  gint             vid_width, vid_height, new_y, new_height;
+
+  clutter_texture_get_base_size (texture, &vid_width, &vid_height);
+
+  new_height = ( vid_height * CLUTTER_STAGE_WIDTH() ) / vid_width;
+  new_y      = ( CLUTTER_STAGE_HEIGHT() - new_height) / 2;
+
+  clutter_actor_set_position (CLUTTER_ACTOR (texture), 0, new_y);
+
+  clutter_actor_set_size (CLUTTER_ACTOR (texture),
+                         CLUTTER_STAGE_WIDTH(),
+                         new_height);
+}
+
+void 
+tick (GObject      *object,
+      GParamSpec   *pspec,
+      VideoApp     *app)
+{
+  ClutterVideoTexture *vtex;
+  gint                 w, h, position, duration, seek_w;
+  gchar                buf[256];
+
+  vtex = CLUTTER_VIDEO_TEXTURE(object);
+
+  position = clutter_media_get_position (CLUTTER_MEDIA(vtex));
+  duration = clutter_media_get_duration (CLUTTER_MEDIA(vtex));
+
+  if (duration == 0 || position == 0)
+    return;
+
+  clutter_actor_set_size (app->control_seekbar, 
+                         (position * SEEK_W) / duration, 
+                         SEEK_H);  
+}
+
+int
+effect1_tl_cb (ClutterTimeline *timeline, 
+              gint             frame_num, 
+              VideoApp        *app)
+{
+  clutter_actor_rotate_y (app->vtexture,
+                         frame_num * 12,
+                         CLUTTER_STAGE_WIDTH()/2,
+                         0);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  VideoApp            *app = NULL;
+  ClutterActor        *stage;
+  ClutterColor         stage_color = { 0x00, 0x00, 0x00, 0x00 };
+  ClutterColor         control_color1 = { 73, 74, 77, 0xee };
+  ClutterColor         control_color2 = { 0xcc, 0xcc, 0xcc, 0xff };
+  GdkPixbuf           *pixb;
+  gint                 x,y;
+
+  if (argc < 2)
+    g_error("%s <video file>", argv[0]);
+
+  clutter_init (&argc, &argv);
+
+  stage = clutter_stage_get_default ();
+  g_object_set (stage, "fullscreen", TRUE, NULL);
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); 
+
+  app = g_new0(VideoApp, 1);
+
+  app->vtexture = clutter_video_texture_new ();
+
+  if (app->vtexture == NULL)
+    {
+      g_error("failed to create vtexture");
+    }
+
+  /* Dont let the underlying pixbuf dictate size */
+  g_object_set (G_OBJECT(app->vtexture), "sync-size", FALSE, NULL);
+
+  /* Handle it ourselves so can scale up for fullscreen better */
+  g_signal_connect (CLUTTER_TEXTURE(app->vtexture), 
+                   "size-change",
+                   G_CALLBACK (size_change), NULL);
+
+  /* Load up out video texture */
+  clutter_media_set_filename(CLUTTER_MEDIA(app->vtexture), argv[1]);
+
+  /* Create the control UI */
+  app->control = clutter_group_new ();
+
+  pixb = gdk_pixbuf_new_from_file ("vid-panel.png", NULL);
+
+  if (pixb == NULL)
+    g_error("Unable to load vid-panel.png");
+
+  app->control_bg = clutter_texture_new_from_pixbuf (pixb);
+  
+  pixb = gdk_pixbuf_new_from_file("media-actions-start.png", NULL);
+
+  if (pixb == NULL)
+    g_error("Unable to load media-actions-start.png");
+
+  app->control_play = clutter_texture_new_from_pixbuf (pixb);
+
+  pixb = gdk_pixbuf_new_from_file("media-actions-pause.png", NULL);
+
+  if (pixb == NULL)
+    g_error("Unable to load media-actions-pause.png");
+
+  app->control_pause = clutter_texture_new_from_pixbuf (pixb);
+
+  app->control_seek1   = clutter_rectangle_new_with_color (&control_color1);
+  app->control_seek2   = clutter_rectangle_new_with_color (&control_color2);
+  app->control_seekbar = clutter_rectangle_new_with_color (&control_color1);
+  clutter_actor_set_opacity (app->control_seekbar, 0x99);
+
+  app->control_label 
+    = clutter_label_new_with_text("Sans Bold 24", 
+                                 g_path_get_basename(argv[1]));
+  clutter_label_set_color (CLUTTER_LABEL(app->control_label), &control_color1);
+  
+  clutter_group_add_many (CLUTTER_GROUP (app->control), 
+                         app->control_bg, 
+                         app->control_play, 
+                         app->control_pause,
+                         app->control_seek1,
+                         app->control_seek2,
+                         app->control_seekbar,
+                         app->control_label,
+                         NULL);
+
+  x = (CLUTTER_STAGE_WIDTH() - clutter_actor_get_width(app->control))/2;
+  y = CLUTTER_STAGE_HEIGHT() - (CLUTTER_STAGE_HEIGHT()/3);
+    
+  clutter_actor_set_position (app->control, x, y);
+  clutter_actor_set_opacity (app->control, 0xee);
+
+  clutter_actor_set_position (app->control_play, 30, 30);
+  clutter_actor_set_position (app->control_pause, 30, 30);
+
+  clutter_actor_set_size (app->control_seek1, SEEK_W+10, SEEK_H+10);
+  clutter_actor_set_position (app->control_seek1, 200, 100);
+  clutter_actor_set_size (app->control_seek2, SEEK_W, SEEK_H);
+  clutter_actor_set_position (app->control_seek2, 205, 105);
+  clutter_actor_set_size (app->control_seekbar, 0, SEEK_H);
+  clutter_actor_set_position (app->control_seekbar, 205, 105);
+
+  clutter_actor_set_position (app->control_label, 200, 40);
+
+  /* Add control UI to stage */
+  clutter_group_add_many (CLUTTER_GROUP (stage), 
+                         app->vtexture, app->control, NULL);
+
+  /* hook up a time line for fading controls */
+  app->controls_tl = clutter_timeline_new (10, 30);
+  g_signal_connect (app->controls_tl, "new-frame", 
+                   G_CALLBACK (control_tl_cb), app);
+  g_signal_connect (app->controls_tl, "completed", 
+                   G_CALLBACK (control_tl_complete_cb), app);
+
+
+  app->effect1_tl = clutter_timeline_new (30, 90);
+  g_signal_connect (app->effect1_tl, "new-frame", 
+                   G_CALLBACK (effect1_tl_cb), app);
+
+  /* Hook up other events */
+  g_signal_connect (stage, "input-event",
+                   G_CALLBACK (input_cb), 
+                   app);
+
+  g_signal_connect (CLUTTER_MEDIA(app->vtexture),
+                   "notify::position",
+                   G_CALLBACK (tick),
+                   app);
+
+  clutter_media_set_playing (CLUTTER_MEDIA(app->vtexture), TRUE);
+
+  clutter_group_show_all (CLUTTER_GROUP (stage));
+
+  clutter_main();
+
+  g_object_unref (stage);
+
+  return 0;
+}