[totem] backend: Use clutter-gst to draw video



commit cb53bbda6b56d3c2e2f78331fa436cb0382bd14e
Author: Bastien Nocera <hadess hadess net>
Date:   Thu Mar 31 18:33:12 2011 +0100

    backend: Use clutter-gst to draw video
    
    This allows use to draw arbitrary actors on top of the video
    widget, while having them resize and move with the video widget.
    
    Major changes include:
    * Implement simpler zoom (crop or none)
    * Remove width/height parameters to bvw_new()
    * Colour balance through videobalance
    * Simplified interface checking, and no-locking
    * Fix disabling effects when setting a cover as the logo,
      and showing a logo when disabling the effects
    
    https://bugzilla.gnome.org/show_bug.cgi?id=646364

 configure.in                              |    4 +-
 data/totem.ui                             |   33 +-
 src/backend/Makefile.am                   |    1 +
 src/backend/bacon-video-widget-gst-0.10.c |  927 +++++++----------------------
 src/backend/bacon-video-widget.h          |   26 +-
 src/backend/bvw-test.c                    |   20 +-
 src/totem-audio-preview.c                 |    2 +-
 src/totem-menu.c                          |   23 +-
 src/totem-object.c                        |   92 +---
 src/totem-private.h                       |    4 +-
 src/totem-properties-view.c               |    2 +-
 src/totem-video-indexer.c                 |    2 +-
 src/totem-video-thumbnailer.c             |    2 +-
 13 files changed, 282 insertions(+), 856 deletions(-)
---
diff --git a/configure.in b/configure.in
index 27a3497..a3096b3 100644
--- a/configure.in
+++ b/configure.in
@@ -78,6 +78,7 @@ dnl release versions.
 GST_MAJORMINOR=0.10
 GST_REQS=0.10.30
 GSTPLUG_REQS=0.10.30
+CLUTTER_REQS=1.6.7
 
 HAVE_GSTREAMER=no
 
@@ -111,7 +112,7 @@ if test "x$enable_easy_codec_installation" != "xno"; then
 	])
 fi
 
-MM="gstreamer-0.10 >= $GST_REQS gstreamer-base-0.10 >= $GST_REQS gstreamer-plugins-base-0.10 >= $GSTPLUG_REQS gstreamer-tag-0.10 >= $GSTPLUG_REQS"
+MM="gstreamer-0.10 >= $GST_REQS gstreamer-base-0.10 >= $GST_REQS gstreamer-plugins-base-0.10 >= $GSTPLUG_REQS gstreamer-tag-0.10 >= $GSTPLUG_REQS clutter-1.0 >= $CLUTTER_REQS clutter-gst-1.0 clutter-gtk-1.0 mx-1.0"
 PKG_CHECK_MODULES(GST, $MM)
 GST_LIBS="$GST_LIBS -lgstbase-$GST_MAJORMINOR -lgstinterfaces-$GST_MAJORMINOR -lgstvideo-$GST_MAJORMINOR -lgstaudio-$GST_MAJORMINOR -lgstpbutils-$GST_MAJORMINOR -lgsttag-$GST_MAJORMINOR"
 AC_SUBST(GST_LIBS)
@@ -198,6 +199,7 @@ PKG_CHECK_MODULES([DEPENDENCY],[
   gmodule-2.0
   totem-plparser >= $TOTEM_PLPARSER_REQS
   gstreamer-tag-0.10 >= 0.10.26
+  clutter-gtk-1.0
   cairo])
 
 PKG_CHECK_MODULES(MM, $MM)
diff --git a/data/totem.ui b/data/totem.ui
index 5b2670f..3f1ffaf 100644
--- a/data/totem.ui
+++ b/data/totem.ui
@@ -362,36 +362,15 @@
                <property name="hide-if-empty">False</property>
             </object>
          </child>
-      </object>
-   </child>
-   <child>
-      <object class="GtkActionGroup" id="zoom-action-group">
+
          <child>
-            <object class="GtkAction" id="zoom-in">
+            <object class="GtkToggleAction" id="zoom-toggle">
                <property name="label" translatable="yes">Zoom In</property>
                <property name="stock-id">gtk-zoom-in</property>
                <property name="tooltip" translatable="yes">Zoom in</property>
-               <signal name="activate" handler="zoom_in_action_callback"/>
-            </object>
-            <accelerator key="R" modifiers="GDK_CONTROL_MASK"/>
-         </child>
-         <child>
-            <object class="GtkAction" id="zoom-reset">
-               <property name="label" translatable="yes">Zoom Reset</property>
-               <property name="stock-id">gtk-zoom-100</property>
-               <property name="tooltip" translatable="yes">Zoom reset</property>
-               <signal name="activate" handler="zoom_reset_action_callback"/>
-            </object>
-            <accelerator key="0" modifiers="GDK_CONTROL_MASK"/>
-         </child>
-         <child>
-            <object class="GtkAction" id="zoom-out">
-               <property name="label" translatable="yes">Zoom Out</property>
-               <property name="stock-id">gtk-zoom-out</property>
-               <property name="tooltip" translatable="yes">Zoom out</property>
-               <signal name="activate" handler="zoom_out_action_callback"/>
+               <signal name="activate" handler="zoom_toggle_action_callback"/>
             </object>
-            <accelerator key="T" modifiers="GDK_CONTROL_MASK"/>
+            <accelerator key="Z" modifiers="GDK_CONTROL_MASK"/>
          </child>
       </object>
    </child>
@@ -452,9 +431,7 @@
                <menuitem name="zoom-1-1" action="zoom-1-1"/>
                <menuitem name="zoom-2-1" action="zoom-2-1"/>
             </menu>
-            <menuitem name="zoom-in" action="zoom-in"/>
-            <menuitem name="zoom-reset" action="zoom-reset"/>
-            <menuitem name="zoom-out" action="zoom-out"/>
+            <menuitem name="zoom-toggle" action="zoom-toggle"/>
             <separator/>
             <menu name="aspect-ratio" action="aspect-ratio-menu">
                <menuitem name="aspect-ratio-auto" action="aspect-ratio-auto"/>
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index 49c5610..9150136 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -12,6 +12,7 @@ bvw_test_CPPFLAGS = \
 
 bvw_test_CFLAGS = \
 	$(DEPENDENCY_CFLAGS)	\
+	$(MM_CFLAGS)		\
 	$(AM_CFLAGS)
 
 bvw_test_LDADD = \
diff --git a/src/backend/bacon-video-widget-gst-0.10.c b/src/backend/bacon-video-widget-gst-0.10.c
index bea7283..05b5812 100644
--- a/src/backend/bacon-video-widget-gst-0.10.c
+++ b/src/backend/bacon-video-widget-gst-0.10.c
@@ -46,7 +46,6 @@
 #include <gst/gst.h>
 
 /* GStreamer Interfaces */
-#include <gst/interfaces/xoverlay.h>
 #include <gst/interfaces/navigation.h>
 #include <gst/interfaces/colorbalance.h>
 /* for detecting sources of errors */
@@ -64,6 +63,9 @@
 /* for the cover metadata info */
 #include <gst/tag/tag.h>
 
+#include <clutter-gst/clutter-gst.h>
+#include <mx/mx.h>
+
 /* system */
 #include <unistd.h>
 #include <time.h>
@@ -89,8 +91,6 @@
 
 #define FORWARD_RATE 1.0
 #define REVERSE_RATE -1.0
-#define SMALL_STREAM_WIDTH 200
-#define SMALL_STREAM_HEIGHT 120
 /* Maximum size of the logo */
 #define LOGO_SIZE 256
 #define NANOSECS_IN_SEC 1000000000
@@ -102,7 +102,7 @@
 
 #define I_(string) (g_intern_static_string (string))
 
-G_DEFINE_TYPE (BaconVideoWidget, bacon_video_widget, GTK_TYPE_EVENT_BOX)
+G_DEFINE_TYPE (BaconVideoWidget, bacon_video_widget, GTK_CLUTTER_TYPE_EMBED)
 
 /* Signals */
 enum
@@ -177,11 +177,8 @@ struct BaconVideoWidgetPrivate
 
   GstElement                  *play;
   GstElement                  *source;
-  GstXOverlay                 *xoverlay;      /* protect with lock */
-  GstColorBalance             *balance;       /* protect with lock */
-  GstNavigation               *navigation;    /* protect with lock */
-  guint                        interface_update_id;  /* protect with lock */
-  GMutex                      *lock;
+  GstColorBalance             *balance;
+  GstNavigation               *navigation;
 
   guint                        update_id;
   guint                        fill_id;
@@ -207,7 +204,13 @@ struct BaconVideoWidgetPrivate
 
   gboolean                     got_redirect;
 
-  GdkWindow                   *video_window;
+  ClutterActor                *stage;
+  ClutterActor                *texture;
+  ClutterActor                *frame;
+
+  ClutterActor                *logo_frame;
+  ClutterActor                *logo;
+
   GdkCursor                   *cursor;
 
   /* Visual effects */
@@ -237,8 +240,6 @@ struct BaconVideoWidgetPrivate
   gint                         video_fps_n;
   gint                         video_fps_d;
 
-  gdouble                      zoom;
-  
   gchar                       *media_device;
 
   BvwAudioOutputType           speakersetup;
@@ -247,7 +248,6 @@ struct BaconVideoWidgetPrivate
   GstMessageType               ignore_messages_mask;
 
   GstBus                      *bus;
-  gulong                       sig_bus_sync;
   gulong                       sig_bus_async;
 
   BvwUseType                   use_type;
@@ -302,11 +302,8 @@ static void bacon_video_widget_get_property (GObject * object,
 
 static void bacon_video_widget_finalize (GObject * object);
 
-static void bvw_update_interface_implementations (BaconVideoWidget *bvw);
 static void setup_vis (BaconVideoWidget * bvw);
 static GList * get_visualization_features (void);
-static gboolean bacon_video_widget_configure_event (GtkWidget *widget,
-    GdkEventConfigure *event, BaconVideoWidget *bvw);
 static void size_changed_cb (GdkScreen *screen, BaconVideoWidget *bvw);
 static void bvw_process_pending_tag_messages (BaconVideoWidget * bvw);
 static void bvw_stop_play_pipeline (BaconVideoWidget * bvw);
@@ -434,6 +431,50 @@ bvw_error_msg (BaconVideoWidget * bvw, GstMessage * msg)
 }
 
 static void
+set_display_pixel_aspect_ratio (GdkScreen *screen,
+				GValue    *value)
+{
+  static const gint par[][2] = {
+    {1, 1},                     /* regular screen */
+    {16, 15},                   /* PAL TV */
+    {11, 10},                   /* 525 line Rec.601 video */
+    {54, 59},                   /* 625 line Rec.601 video */
+    {64, 45},                   /* 1280x1024 on 16:9 display */
+    {5, 3},                     /* 1280x1024 on 4:3 display */
+    {4, 3}                      /*  800x600 on 16:9 display */
+  };
+  guint i;
+  gint index;
+  gdouble ratio;
+  gdouble delta;
+
+#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
+
+  /* first calculate the "real" ratio based on the X values;
+   *    * which is the "physical" w/h divided by the w/h in pixels of the display */
+  ratio = (gdouble) (gdk_screen_get_width_mm (screen) * gdk_screen_get_height (screen))
+    / (gdk_screen_get_height_mm (screen) * gdk_screen_get_width (screen));
+
+  GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
+  /* now find the one from par[][2] with the lowest delta to the real one */
+  delta = DELTA (0);
+  index = 0;
+
+  for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
+    gdouble this_delta = DELTA (i);
+
+    if (this_delta < delta) {
+      index = i;
+      delta = this_delta;
+    }
+  }
+
+  GST_DEBUG ("Decided on index %d (%d/%d)", index,
+	     par[index][0], par[index][1]);
+  gst_value_set_fraction (value, par[index][0], par[index][1]);
+}
+
+static void
 get_media_size (BaconVideoWidget *bvw, gint *width, gint *height)
 {
   if (bvw->priv->logo_mode) {
@@ -456,42 +497,22 @@ get_media_size (BaconVideoWidget *bvw, gint *width, gint *height)
     if (bvw->priv->media_has_video) {
       GValue disp_par = {0, };
       guint movie_par_n, movie_par_d, disp_par_n, disp_par_d, num, den;
-      
+
       /* Create and init the fraction value */
       g_value_init (&disp_par, GST_TYPE_FRACTION);
 
       /* Square pixel is our default */
       gst_value_set_fraction (&disp_par, 1, 1);
-    
-      /* Now try getting display's pixel aspect ratio */
-      if (bvw->priv->xoverlay) {
-        GObjectClass *klass;
-        GParamSpec *pspec;
 
-        klass = G_OBJECT_GET_CLASS (bvw->priv->xoverlay);
-        pspec = g_object_class_find_property (klass, "pixel-aspect-ratio");
-      
-        if (pspec != NULL) {
-          GValue disp_par_prop = { 0, };
-
-          g_value_init (&disp_par_prop, pspec->value_type);
-          g_object_get_property (G_OBJECT (bvw->priv->xoverlay),
-              "pixel-aspect-ratio", &disp_par_prop);
+      /* Now try getting display's pixel aspect ratio */
+      if (gtk_widget_get_realized (GTK_WIDGET (bvw)))
+	set_display_pixel_aspect_ratio (gtk_widget_get_screen (GTK_WIDGET (bvw)), &disp_par);
 
-          if (!g_value_transform (&disp_par_prop, &disp_par)) {
-            GST_WARNING ("Transform failed, assuming pixel-aspect-ratio = 1/1");
-            gst_value_set_fraction (&disp_par, 1, 1);
-          }
-        
-          g_value_unset (&disp_par_prop);
-        }
-      }
-      
       disp_par_n = gst_value_get_fraction_numerator (&disp_par);
       disp_par_d = gst_value_get_fraction_denominator (&disp_par);
-      
+
       GST_DEBUG ("display PAR is %d/%d", disp_par_n, disp_par_d);
-      
+
       /* If movie pixel aspect ratio is enforced, use that */
       if (bvw->priv->ratio_type != BVW_RATIO_AUTO) {
         switch (bvw->priv->ratio_type) {
@@ -518,13 +539,12 @@ get_media_size (BaconVideoWidget *bvw, gint *width, gint *height)
             movie_par_d = 0;
             g_assert_not_reached ();
         }
-      }
-      else {
+      } else {
         /* Use the movie pixel aspect ratio if any */
         movie_par_n = bvw->priv->movie_par_n;
         movie_par_d = bvw->priv->movie_par_d;
       }
-      
+
       GST_DEBUG ("movie PAR is %d/%d", movie_par_n, movie_par_d);
 
       if (bvw->priv->video_width == 0 || bvw->priv->video_height == 0) {
@@ -584,61 +604,20 @@ static void
 bacon_video_widget_realize (GtkWidget * widget)
 {
   BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
-  GdkWindowAttr attributes;
-  gint attributes_mask;
-  GdkColor black = { 0, 0, 0 };
-  GdkWindow *window;
-  GdkEventMask event_mask;
-  GtkAllocation allocation;
   GtkWidget *toplevel;
 
-  event_mask = gtk_widget_get_events (widget)
-    | GDK_POINTER_MOTION_MASK
-    | GDK_KEY_PRESS_MASK;
-  gtk_widget_set_events (widget, event_mask);
-
   GTK_WIDGET_CLASS (parent_class)->realize (widget);
 
-  window = gtk_widget_get_window (widget);
-  gdk_window_ensure_native (window);
-
-  /* Creating our video window */
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.x = 0;
-  attributes.y = 0;
-  gtk_widget_get_allocation (widget, &allocation);
-  attributes.visual = gdk_screen_get_system_visual (gtk_widget_get_screen (widget));
-  attributes.width = allocation.width;
-  attributes.height = allocation.height;
-  attributes.wclass = GDK_INPUT_OUTPUT;
-  attributes.event_mask = gtk_widget_get_events (widget);
-  attributes.event_mask |= GDK_EXPOSURE_MASK |
-                           GDK_POINTER_MOTION_MASK |
-                           GDK_BUTTON_PRESS_MASK |
-                           GDK_KEY_PRESS_MASK;
-  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
-
-  bvw->priv->video_window = gdk_window_new (window,
-      &attributes, attributes_mask);
-  gdk_window_ensure_native (bvw->priv->video_window);
-  gdk_window_set_user_data (bvw->priv->video_window, widget);
-  gdk_window_set_background (window, &black);
-
-  gdk_window_set_background (window, &black);
-
   gtk_widget_set_realized (widget, TRUE);
 
-  /* Connect to configure event on the top level window */
-  g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (widget)),
-      "configure-event", G_CALLBACK (bacon_video_widget_configure_event), bvw);
-
   /* get screen size changes */
   g_signal_connect (G_OBJECT (gtk_widget_get_screen (widget)),
-      "size-changed", G_CALLBACK (size_changed_cb), bvw);
+		    "size-changed", G_CALLBACK (size_changed_cb), bvw);
 
   /* setup the toplevel, ready to be resized */
   toplevel = gtk_widget_get_toplevel (widget);
-  if (gtk_widget_is_toplevel (toplevel))
+  if (gtk_widget_is_toplevel (toplevel) &&
+      gtk_widget_get_parent (widget) != toplevel)
     gtk_window_set_geometry_hints (GTK_WINDOW (toplevel), widget, NULL, 0);
 
   bacon_video_widget_gst_missing_plugins_setup (bvw);
@@ -652,97 +631,21 @@ bacon_video_widget_unrealize (GtkWidget *widget)
   BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
 
   g_object_unref (bvw->priv->bacon_resize);
-  gdk_window_set_user_data (bvw->priv->video_window, NULL);
-  gdk_window_destroy (bvw->priv->video_window);
-  bvw->priv->video_window = NULL;
 
   GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
 }
 
 static void
-bacon_video_widget_show (GtkWidget *widget)
-{
-  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
-  GdkWindow *window;
-
-  window = gtk_widget_get_window (widget);
-  if (window)
-    gdk_window_show (window);
-  if (bvw->priv->video_window)
-    gdk_window_show (bvw->priv->video_window);
-
-  if (GTK_WIDGET_CLASS (parent_class)->show)
-    GTK_WIDGET_CLASS (parent_class)->show (widget);
-}
-
-static void
-bacon_video_widget_hide (GtkWidget *widget)
-{
-  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
-  GdkWindow *window;
-
-  window = gtk_widget_get_window (widget);
-  if (window)
-    gdk_window_hide (window);
-  if (bvw->priv->video_window)
-    gdk_window_hide (bvw->priv->video_window);
-
-  if (GTK_WIDGET_CLASS (parent_class)->hide)
-    GTK_WIDGET_CLASS (parent_class)->hide (widget);
-}
-
-static gboolean
-bacon_video_widget_configure_event (GtkWidget *widget, GdkEventConfigure *event,
-    BaconVideoWidget *bvw)
-{
-  GstXOverlay *xoverlay = NULL;
-  
-  g_return_val_if_fail (bvw != NULL, FALSE);
-  g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
-  
-  xoverlay = bvw->priv->xoverlay;
-  
-  if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay)) {
-    gst_x_overlay_expose (xoverlay);
-  }
-  
-  return FALSE;
-}
-
-static void
 size_changed_cb (GdkScreen *screen, BaconVideoWidget *bvw)
 {
   /* FIXME */
   setup_vis (bvw);
 }
 
-static gboolean
-bacon_video_widget_draw (GtkWidget *widget, cairo_t *cr)
+static void
+set_current_actor (BaconVideoWidget *bvw)
 {
-  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
-  GstXOverlay *xoverlay;
   gboolean draw_logo;
-  XID window;
-  GtkAllocation allocation;
-
-  g_mutex_lock (bvw->priv->lock);
-  xoverlay = bvw->priv->xoverlay;
-  if (xoverlay == NULL) {
-    bvw_update_interface_implementations (bvw);
-    xoverlay = bvw->priv->xoverlay;
-  }
-  if (xoverlay != NULL)
-    gst_object_ref (xoverlay);
-
-  g_mutex_unlock (bvw->priv->lock);
-
-  window = gdk_x11_window_get_xid (bvw->priv->video_window);
-
-  if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay))
-    gst_x_overlay_set_xwindow_id (xoverlay, window);
-
-  /* Start with a nice black canvas */
-  gtk_widget_get_allocation (widget, &allocation);
 
   /* If there's only audio and no visualisation, draw the logo as well.
    * If we have a cover image to display, we display it regardless of whether we're
@@ -755,76 +658,32 @@ bacon_video_widget_draw (GtkWidget *widget, cairo_t *cr)
 
     pixbuf = bvw_get_logo_pixbuf (bvw);
     if (pixbuf != NULL) {
-      /* draw logo here */
-      gint s_width, s_height, d_width, d_height;
-      gfloat ratio;
-
-      s_width = gdk_pixbuf_get_width (pixbuf);
-      s_height = gdk_pixbuf_get_height (pixbuf);
-      d_width = allocation.width;
-      d_height = allocation.height;
-
-      /* Limit the width/height to 256Ã?256 pixels, but only if we're displaying the logo proper */
-      if (!bvw->priv->cover_pixbuf && d_width > LOGO_SIZE && d_height > LOGO_SIZE)
-        d_width = d_height = LOGO_SIZE;
-
-      if ((gfloat) d_width / s_width > (gfloat) d_height / s_height) {
-        ratio = (gfloat) d_height / s_height;
+      gboolean ret;
+      GError *err = NULL;
+
+      ret = clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (bvw->priv->logo),
+					       gdk_pixbuf_get_pixels (pixbuf),
+					       gdk_pixbuf_get_has_alpha (pixbuf),
+					       gdk_pixbuf_get_width (pixbuf),
+					       gdk_pixbuf_get_height (pixbuf),
+					       gdk_pixbuf_get_rowstride (pixbuf),
+					       gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3,
+					       CLUTTER_TEXTURE_NONE, &err);
+      if (ret == FALSE) {
+	g_message ("clutter_texture_set_from_rgb_data failed %s", err->message);
+	g_error_free (err);
       } else {
-        ratio = (gfloat) d_width / s_width;
+	clutter_actor_show (CLUTTER_ACTOR (bvw->priv->logo_frame));
+	clutter_actor_hide (CLUTTER_ACTOR (bvw->priv->frame));
+	return;
       }
-
-      /* center the current point, then scale the context so the logo fills up
-       * all the space */
-      cairo_translate (cr, allocation.width / 2, allocation.height / 2);
-      cairo_scale (cr, ratio, ratio);
-
-      /* fill with black */
-      cairo_set_source_rgb (cr, 0, 0, 0);
-      cairo_paint (cr);
-
-      /* then draw logo on top */
-      gdk_cairo_set_source_pixbuf (cr, pixbuf, - s_width / 2, - s_height / 2);
-      cairo_paint (cr);
-    }
-  } else if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay)) {
-    /* no logo, use gst */
-
-    /* Paint the non-video parts black */
-    if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget))) {
-      cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
-      cairo_paint (cr);
     }
-
-    /* let gst paint the video */
-    if (gtk_cairo_should_draw_window (cr, bvw->priv->video_window))
-      gst_x_overlay_expose (xoverlay);
-  } else {
-    /* if not even gst exists, just paint black */
-    cairo_set_source_rgb (cr, 0, 0, 0);
-    cairo_paint (cr);
   }
 
-  if (xoverlay != NULL)
-    gst_object_unref (xoverlay);
-
-  return FALSE;
+  clutter_actor_show (CLUTTER_ACTOR (bvw->priv->frame));
+  clutter_actor_hide (CLUTTER_ACTOR (bvw->priv->logo_frame));
 }
 
-static GstNavigation *
-bvw_get_navigation_iface (BaconVideoWidget *bvw, gboolean update_interfaces)
-{
-  GstNavigation *nav = NULL;
-  g_mutex_lock (bvw->priv->lock);
-  if (bvw->priv->navigation == NULL && update_interfaces == TRUE)
-    bvw_update_interface_implementations (bvw);
-  if (bvw->priv->navigation)
-    nav = gst_object_ref (GST_OBJECT (bvw->priv->navigation));
-  g_mutex_unlock (bvw->priv->lock);
-
-  return nav;
-}
-    
 /* need to use gstnavigation interface for these vmethods, to allow for the sink
    to map screen coordinates to video coordinates in the presence of e.g.
    hardware scaling */
@@ -837,13 +696,8 @@ bacon_video_widget_motion_notify (GtkWidget *widget, GdkEventMotion *event)
 
   g_return_val_if_fail (bvw->priv->play != NULL, FALSE);
 
-  if (!bvw->priv->logo_mode) {
-    GstNavigation *nav = bvw_get_navigation_iface (bvw, FALSE);
-    if (nav) {
-      gst_navigation_send_mouse_event (nav, "mouse-move", 0, event->x, event->y);
-      gst_object_unref (GST_OBJECT (nav));
-    }
-  }
+  if (!bvw->priv->logo_mode)
+    gst_navigation_send_mouse_event (bvw->priv->navigation, "mouse-move", 0, event->x, event->y);
 
   if (GTK_WIDGET_CLASS (parent_class)->motion_notify_event)
     res |= GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event);
@@ -860,16 +714,12 @@ bacon_video_widget_button_press (GtkWidget *widget, GdkEventButton *event)
   g_return_val_if_fail (bvw->priv->play != NULL, FALSE);
 
   if (!bvw->priv->logo_mode) {
-    GstNavigation *nav = bvw_get_navigation_iface (bvw, FALSE);
-    if (nav) {
-      gst_navigation_send_mouse_event (nav,
-          "mouse-button-press", event->button, event->x, event->y);
-      gst_object_unref (GST_OBJECT (nav));
-
-      /* FIXME need to check whether the backend will have handled
-       * the button press
-      res = TRUE; */
-    }
+    gst_navigation_send_mouse_event (bvw->priv->navigation,
+				     "mouse-button-press", event->button, event->x, event->y);
+
+    /* FIXME need to check whether the backend will have handled
+     * the button press
+     res = TRUE; */
   }
 
   if (GTK_WIDGET_CLASS (parent_class)->button_press_event)
@@ -887,14 +737,10 @@ bacon_video_widget_button_release (GtkWidget *widget, GdkEventButton *event)
   g_return_val_if_fail (bvw->priv->play != NULL, FALSE);
 
   if (!bvw->priv->logo_mode) {
-    GstNavigation *nav = bvw_get_navigation_iface (bvw, FALSE);
-    if (nav) {
-      gst_navigation_send_mouse_event (nav,
-          "mouse-button-release", event->button, event->x, event->y);
-      gst_object_unref (GST_OBJECT (nav));
+    gst_navigation_send_mouse_event (bvw->priv->navigation,
+				     "mouse-button-release", event->button, event->x, event->y);
 
-      res = TRUE;
-    }
+    res = TRUE;
   }
 
   if (GTK_WIDGET_CLASS (parent_class)->button_release_event)
@@ -919,66 +765,6 @@ bacon_video_widget_get_preferred_height (GtkWidget *widget,
   *minimum = *natural = 180;
 }
 
-static void
-resize_video_window (BaconVideoWidget *bvw)
-{
-  GtkAllocation allocation;
-  gfloat width, height, ratio, x, y;
-  int w, h;
-
-  g_return_if_fail (bvw != NULL);
-  g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
-
-  gtk_widget_get_allocation (GTK_WIDGET (bvw), &allocation);
-
-  get_media_size (bvw, &w, &h);
-  if (!w || !h) {
-    w = allocation.width;
-    h = allocation.height;
-  }
-  width = w;
-  height = h;
-
-  /* calculate ratio for fitting video into the available space */
-  if ((gfloat) allocation.width / width >
-      (gfloat) allocation.height / height) {
-    ratio = (gfloat) allocation.height / height;
-  } else {
-    ratio = (gfloat) allocation.width / width;
-  }
-
-  /* apply zoom factor */
-  ratio = ratio * bvw->priv->zoom;
-
-  width *= ratio;
-  height *= ratio;
-  x = (allocation.width - width) / 2;
-  y = (allocation.height - height) / 2;
-
-  gdk_window_move_resize (bvw->priv->video_window, x, y, width, height);
-  gtk_widget_queue_draw (GTK_WIDGET (bvw));
-}
-
-static void
-bacon_video_widget_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
-{
-  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (BACON_IS_VIDEO_WIDGET (widget));
-
-  gtk_widget_set_allocation (widget, allocation);
-
-  if (gtk_widget_get_realized (widget)) {
-
-    gdk_window_move_resize (gtk_widget_get_window (widget),
-                            allocation->x, allocation->y,
-                            allocation->width, allocation->height);
-
-    resize_video_window (bvw);
-  }
-}
-
 static gboolean
 bvw_boolean_handled_accumulator (GSignalInvocationHint * ihint,
     GValue * return_accu, const GValue * handler_return, gpointer foobar)
@@ -1009,12 +795,8 @@ bacon_video_widget_class_init (BaconVideoWidgetClass * klass)
   /* GtkWidget */
   widget_class->get_preferred_width = bacon_video_widget_get_preferred_width;
   widget_class->get_preferred_height = bacon_video_widget_get_preferred_height;
-  widget_class->size_allocate = bacon_video_widget_size_allocate;
   widget_class->realize = bacon_video_widget_realize;
   widget_class->unrealize = bacon_video_widget_unrealize;
-  widget_class->show = bacon_video_widget_show;
-  widget_class->hide = bacon_video_widget_hide;
-  widget_class->draw = bacon_video_widget_draw;
   widget_class->motion_notify_event = bacon_video_widget_motion_notify;
   widget_class->button_press_event = bacon_video_widget_button_press;
   widget_class->button_release_event = bacon_video_widget_button_release;
@@ -1404,7 +1186,6 @@ bacon_video_widget_init (BaconVideoWidget * bvw)
   BaconVideoWidgetPrivate *priv;
 
   gtk_widget_set_can_focus (GTK_WIDGET (bvw), TRUE);
-  gtk_widget_set_double_buffered (GTK_WIDGET (bvw), FALSE);
 
   bvw->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (bvw, BACON_TYPE_VIDEO_WIDGET, BaconVideoWidgetPrivate);
 
@@ -1412,7 +1193,6 @@ bacon_video_widget_init (BaconVideoWidget * bvw)
   priv->tagcache = NULL;
   priv->audiotags = NULL;
   priv->videotags = NULL;
-  priv->zoom = 1.0;
   priv->volume = -1.0;
   priv->movie_par_n = priv->movie_par_d = 1;
   priv->rate = FORWARD_RATE;
@@ -1420,8 +1200,6 @@ bacon_video_widget_init (BaconVideoWidget * bvw)
   priv->tag_update_queue = g_async_queue_new_full ((GDestroyNotify) update_tags_delayed_data_destroy);
   priv->tag_update_id = 0;
 
-  priv->lock = g_mutex_new ();
-
   priv->seek_mutex = g_mutex_new ();
   priv->clock = gst_system_clock_obtain ();
   priv->seek_req_time = GST_CLOCK_TIME_NONE;
@@ -1460,7 +1238,6 @@ static void
 bvw_handle_application_message (BaconVideoWidget *bvw, GstMessage *msg)
 {
   const gchar *msg_name;
-  GtkAllocation allocation;
 
   msg_name = gst_structure_get_name (msg->structure);
   g_return_if_fail (msg_name != NULL);
@@ -1478,16 +1255,22 @@ bvw_handle_application_message (BaconVideoWidget *bvw, GstMessage *msg)
       g_signal_emit (bvw, bvw_signals[SIGNAL_GOT_METADATA], 0, NULL);
     }
 
+    /* This is necessary for the pixel-aspect-ratio of the
+     * display to be taken into account.
+     * If we wanted to ignore it, we could get rid of that */
+    if (bvw->priv->use_type == BVW_USE_TYPE_VIDEO) {
+      int w, h;
+      get_media_size (bvw, &w, &h);
+      clutter_actor_set_size (bvw->priv->texture, w, h);
+    }
+
     if (bvw->priv->auto_resize
 	&& !bvw->priv->fullscreen_mode
 	&& !bvw->priv->window_resized) {
       bacon_video_widget_set_scale_ratio (bvw, 0.0);
-    } else {
-      gtk_widget_get_allocation (GTK_WIDGET (bvw), &allocation);
-      bacon_video_widget_size_allocate (GTK_WIDGET (bvw),
-                                        &allocation);
     }
     bvw->priv->window_resized = TRUE;
+    set_current_actor (bvw);
   } else {
     g_message ("Unhandled application message %s", msg_name);
   }
@@ -1496,16 +1279,7 @@ bvw_handle_application_message (BaconVideoWidget *bvw, GstMessage *msg)
 static gboolean
 bvw_do_navigation_query (BaconVideoWidget * bvw, GstQuery *query)
 {
-  GstNavigation *nav = bvw_get_navigation_iface (bvw, TRUE);
-  gboolean res;
-
-  if (G_UNLIKELY (nav == NULL || !GST_IS_ELEMENT (nav)))
-    return FALSE;
-
-  res = gst_element_query (GST_ELEMENT_CAST (nav), query);
-  gst_object_unref (GST_OBJECT (nav));
-
-  return res;
+  return gst_element_query (GST_ELEMENT_CAST (bvw->priv->navigation), query);
 }
 
 static void
@@ -1585,10 +1359,6 @@ bvw_handle_element_message (BaconVideoWidget *bvw, GstMessage *msg)
         g_signal_emit (bvw, bvw_signals[SIGNAL_BUFFERING], 0, percent);
     }
     goto done;
-  } else if (strcmp (type_name, "prepare-xwindow-id") == 0 ||
-      strcmp (type_name, "have-xwindow-id") == 0) {
-    /* we handle these synchronously or want to ignore them */
-    goto done;
   } else if (gst_is_missing_plugin_message (msg)) {
     bvw->priv->missing_plugins =
       g_list_prepend (bvw->priv->missing_plugins, gst_message_ref (msg));
@@ -1957,6 +1727,8 @@ bvw_update_tags (BaconVideoWidget * bvw, GstTagList *tag_list, const gchar *type
   else if (bvw->priv->use_type == BVW_USE_TYPE_CAPTURE &&
 	   bvw->priv->cover_pixbuf != NULL)
     g_signal_emit (bvw, bvw_signals[SIGNAL_GOT_METADATA], 0);
+
+  set_current_actor (bvw);
 }
 
 static void
@@ -2657,13 +2429,13 @@ parse_stream_info (BaconVideoWidget *bvw)
   g_object_get (G_OBJECT (bvw->priv->play), "n-audio", &n_audio,
       "n-video", &n_video, NULL);
 
+  bvw_check_for_cover_pixbuf (bvw);
+
   bvw->priv->media_has_video = FALSE;
   if (n_video > 0) {
     gint i;
 
     bvw->priv->media_has_video = TRUE;
-    if (bvw->priv->video_window)
-      gdk_window_show (bvw->priv->video_window);
 
     for (i = 0; i < n_video && videopad == NULL; i++)
       g_signal_emit_by_name (bvw->priv->play, "get-video-pad", i, &videopad);
@@ -2672,19 +2444,14 @@ parse_stream_info (BaconVideoWidget *bvw)
   bvw->priv->media_has_audio = FALSE;
   if (n_audio > 0) {
     bvw->priv->media_has_audio = TRUE;
-    if (!bvw->priv->media_has_video && bvw->priv->video_window) {
+    if (!bvw->priv->media_has_video) {
       gint flags;
 
       g_object_get (bvw->priv->play, "flags", &flags, NULL);
-      if (bvw->priv->show_vfx) {
-        gdk_window_show (bvw->priv->video_window);
-	gtk_widget_set_double_buffered (GTK_WIDGET (bvw), FALSE);
+      if (bvw->priv->show_vfx && !bvw->priv->cover_pixbuf)
 	flags |= GST_PLAY_FLAG_VIS;
-      } else {
-        gdk_window_hide (bvw->priv->video_window);
-	gtk_widget_set_double_buffered (GTK_WIDGET (bvw), TRUE);
+      else
 	flags &= ~GST_PLAY_FLAG_VIS;
-      }
       g_object_set (bvw->priv->play, "flags", flags, NULL);
     }
   }
@@ -2703,6 +2470,8 @@ parse_stream_info (BaconVideoWidget *bvw)
     get_visualization_size (bvw, &bvw->priv->video_width,
         &bvw->priv->video_height, NULL, NULL);
   }
+
+  set_current_actor (bvw);
 }
 
 static void
@@ -2730,9 +2499,6 @@ bacon_video_widget_finalize (GObject * object)
      * called again (main loop might be run again to display error dialog) */
     gst_bus_set_flushing (bvw->priv->bus, TRUE);
 
-    if (bvw->priv->sig_bus_sync)
-      g_signal_handler_disconnect (bvw->priv->bus, bvw->priv->sig_bus_sync);
-
     if (bvw->priv->sig_bus_async)
       g_signal_handler_disconnect (bvw->priv->bus, bvw->priv->sig_bus_async);
 
@@ -2786,11 +2552,6 @@ bacon_video_widget_finalize (GObject * object)
     bvw->priv->update_id = 0;
   }
 
-  if (bvw->priv->interface_update_id) {
-    g_source_remove (bvw->priv->interface_update_id);
-    bvw->priv->interface_update_id = 0;
-  }
-
   if (bvw->priv->tagcache) {
     gst_tag_list_free (bvw->priv->tagcache);
     bvw->priv->tagcache = NULL;
@@ -2822,7 +2583,6 @@ bacon_video_widget_finalize (GObject * object)
     bvw->priv->mount_cancellable = NULL;
   }
 
-  g_mutex_free (bvw->priv->lock);
   g_mutex_free (bvw->priv->seek_mutex);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -3775,7 +3535,6 @@ gboolean
 bacon_video_widget_open (BaconVideoWidget * bvw,
                          const gchar * mrl, const gchar *subtitle_uri, GError ** error)
 {
-  GtkAllocation allocation;
   GstMessage *err_msg = NULL;
   GFile *file;
   gboolean ret;
@@ -3843,16 +3602,6 @@ bacon_video_widget_open (BaconVideoWidget * bvw,
   bvw->priv->stream_length = 0;
   bvw->priv->ignore_messages_mask = 0;
 
-  /* We hide the video window for now. Will show when video of vfx comes up */
-  if (bvw->priv->video_window) {
-    gdk_window_hide (bvw->priv->video_window);
-    /* We also take the whole widget until we know video size */
-    gtk_widget_get_allocation (GTK_WIDGET (bvw), &allocation);
-    gdk_window_move_resize (bvw->priv->video_window, 0, 0,
-                            allocation.width,
-                            allocation.height);
-  }
-
   if (bvw->priv->ready_idle_id) {
     g_source_remove (bvw->priv->ready_idle_id);
     bvw->priv->ready_idle_id = 0;
@@ -4327,12 +4076,7 @@ bacon_video_widget_close (BaconVideoWidget * bvw)
 static void
 bvw_do_navigation_command (BaconVideoWidget * bvw, GstNavigationCommand command)
 {
-  GstNavigation *nav = bvw_get_navigation_iface (bvw, TRUE);
-  if (nav == NULL)
-    return;
-
-  gst_navigation_send_command (nav, command);
-  gst_object_unref (GST_OBJECT (nav));
+  gst_navigation_send_command (bvw->priv->navigation, command);
 }
 
 /**
@@ -4460,7 +4204,10 @@ bacon_video_widget_set_logo (BaconVideoWidget *bvw, const gchar *name)
   if (error) {
     g_warning ("An error occurred trying to open logo %s: %s", name, error->message);
     g_error_free (error);
+    return;
   }
+
+  set_current_actor (bvw);
 }
 
 /**
@@ -4486,21 +4233,10 @@ bacon_video_widget_set_logo_mode (BaconVideoWidget * bvw, gboolean logo_mode)
   if (priv->logo_mode != logo_mode) {
     priv->logo_mode = logo_mode;
 
-    if (priv->video_window) {
-      if (logo_mode) {
-        gdk_window_hide (priv->video_window);
-	gtk_widget_set_double_buffered (GTK_WIDGET (bvw), TRUE);
-      } else {
-        gdk_window_show (priv->video_window);
-	gtk_widget_set_double_buffered (GTK_WIDGET (bvw), FALSE);
-      }
-    }
+    set_current_actor (bvw);
 
     g_object_notify (G_OBJECT (bvw), "logo_mode");
     g_object_notify (G_OBJECT (bvw), "seekable");
-
-    /* Queue a redraw of the widget */
-    gtk_widget_queue_draw (GTK_WIDGET (bvw));
   }
 }
 
@@ -4876,8 +4612,13 @@ get_visualization_size (BaconVideoWidget *bvw,
   g_return_if_fail (h != NULL);
   g_return_if_fail (bvw->priv->visq < G_N_ELEMENTS (vis_qualities));
 
-  if (!bvw->priv->video_window)
+  if (gtk_widget_get_realized (GTK_WIDGET (bvw)) == FALSE) {
+    if (fps_n)
+      *fps_n = 1;
+    if (fps_d)
+      *fps_d = 1;
     return;
+  }
 
   *h = vis_qualities[bvw->priv->visq].height;
   new_fps_n = vis_qualities[bvw->priv->visq].fps;
@@ -4885,9 +4626,9 @@ get_visualization_size (BaconVideoWidget *bvw,
   screen = gtk_widget_get_screen (GTK_WIDGET (bvw));
   *w = *h * gdk_screen_get_width (screen) / gdk_screen_get_height (screen);
 
-  if (fps_n) 
+  if (fps_n)
     *fps_n = new_fps_n;
-  if (fps_d) 
+  if (fps_d)
     *fps_d = 1;
 }
 
@@ -4933,7 +4674,11 @@ setup_vis (BaconVideoWidget * bvw)
 
   GST_DEBUG ("setup_vis called, show_vfx %d, vis element %s",
       bvw->priv->show_vfx, bvw->priv->vis_element_name);
-  
+
+  /* Check to see if we have an embedded cover image. If we do, don't show visualisations.
+   * FIXME probably wrong now, hide that and use an OSD instead */
+  bvw_check_for_cover_pixbuf (bvw);
+
   if (bvw->priv->show_vfx && !bvw->priv->cover_pixbuf && bvw->priv->vis_element_name) {
     GstElement *vis_element = NULL, *vis_capsfilter = NULL;
     GstPad *pad = NULL;
@@ -5029,26 +4774,17 @@ setup_vis (BaconVideoWidget * bvw)
     }
   }
 
-  /* Check to see if we have an embedded cover image. If we do, don't show visualisations. */
-  bvw_check_for_cover_pixbuf (bvw);
-
   if (bvw->priv->media_has_audio &&
-      !bvw->priv->media_has_video && bvw->priv->video_window) {
+      !bvw->priv->media_has_video) {
     gint flags;
 
     g_object_get (bvw->priv->play, "flags", &flags, NULL);
     if (bvw->priv->show_vfx && !bvw->priv->cover_pixbuf) {
-      gdk_window_show (bvw->priv->video_window);
-      gtk_widget_set_double_buffered (GTK_WIDGET (bvw), FALSE);
       flags |= GST_PLAY_FLAG_VIS;
     } else {
-      gdk_window_hide (bvw->priv->video_window);
-      gtk_widget_set_double_buffered (GTK_WIDGET (bvw), TRUE);
       flags &= ~GST_PLAY_FLAG_VIS;
     }
     g_object_set (bvw->priv->play, "flags", flags, NULL);
-
-    gtk_widget_queue_draw (GTK_WIDGET (bvw));
   }
 
 beach:
@@ -5079,6 +4815,7 @@ bacon_video_widget_set_show_visualizations (BaconVideoWidget * bvw,
 
   bvw->priv->show_vfx = show_visualizations;
   setup_vis (bvw);
+  set_current_actor (bvw);
 }
 
 static gboolean
@@ -5293,9 +5030,6 @@ bacon_video_widget_set_scale_ratio (BaconVideoWidget * bvw, gfloat ratio)
 
   GST_DEBUG ("ratio = %.2f", ratio);
 
-  if (bvw->priv->video_window == NULL)
-    return;
-
   if (!bvw->priv->media_has_video && bvw->priv->show_vfx) {
     get_visualization_size (bvw, &w, &h, NULL, NULL);
   } else {
@@ -5330,41 +5064,42 @@ bacon_video_widget_set_scale_ratio (BaconVideoWidget * bvw, gfloat ratio)
 /**
  * bacon_video_widget_set_zoom:
  * @bvw: a #BaconVideoWidget
- * @zoom: a percentage zoom factor
+ * @mode: the #BvwZoomMode
  *
- * Sets the zoom factor applied to the video when it is displayed,
- * as an integeric percentage between %0 and %1
- * (e.g. set @zoom to %1 to not zoom at all).
+ * Sets the zoom type applied to the video when it is displayed.
  **/
 void
 bacon_video_widget_set_zoom (BaconVideoWidget *bvw,
-                             double            zoom)
+                             BvwZoomMode       mode)
 {
   g_return_if_fail (bvw != NULL);
   g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
 
-  bvw->priv->zoom = zoom;
-  if (bvw->priv->video_window != NULL)
-    resize_video_window (bvw);
+  if (bvw->priv->frame == NULL)
+    return;
+
+  mx_aspect_frame_set_expand (MX_ASPECT_FRAME (bvw->priv->frame),
+			      (mode == BVW_ZOOM_EXPAND));
 }
 
 /**
  * bacon_video_widget_get_zoom:
  * @bvw: a #BaconVideoWidget
  *
- * Returns the zoom factor applied to videos displayed by the widget,
- * as an integeric percentage between %0 and %1
- * (e.g. %1 means no zooming at all).
+ * Returns the zoom mode applied to videos displayed by the widget.
  *
- * Return value: the zoom factor
+ * Return value: a #BvwZoomMode
  **/
-double
+BvwZoomMode
 bacon_video_widget_get_zoom (BaconVideoWidget *bvw)
 {
+  gboolean expand;
+
   g_return_val_if_fail (bvw != NULL, 1.0);
   g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 1.0);
 
-  return bvw->priv->zoom;
+  expand = mx_aspect_frame_get_expand (MX_ASPECT_FRAME (bvw->priv->frame));
+  return expand ? BVW_ZOOM_EXPAND : BVW_ZOOM_NONE;
 }
 
 /* Search for the color balance channel corresponding to type and return it. */
@@ -5413,8 +5148,6 @@ bacon_video_widget_get_video_property (BaconVideoWidget *bvw,
   g_return_val_if_fail (bvw != NULL, 65535/2);
   g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 65535/2);
   
-  g_mutex_lock (bvw->priv->lock);
-
   ret = 0;
   
   if (bvw->priv->balance && GST_IS_COLOR_BALANCE (bvw->priv->balance))
@@ -5438,7 +5171,7 @@ bacon_video_widget_get_video_property (BaconVideoWidget *bvw,
 
         GST_DEBUG ("channel %s: returning value %d", found_channel->label, ret);
         g_object_unref (found_channel);
-        goto done;
+        return ret;
       } else {
 	ret = -1;
       }
@@ -5446,9 +5179,6 @@ bacon_video_widget_get_video_property (BaconVideoWidget *bvw,
 
   GST_DEBUG ("nothing found for type %d, returning value %d", type, ret);
 
-done:
-
-  g_mutex_unlock (bvw->priv->lock);
   return ret;
 }
 
@@ -6504,6 +6234,7 @@ bacon_video_widget_get_current_frame (BaconVideoWidget * bvw)
 GOptionGroup*
 bacon_video_widget_get_option_group (void)
 {
+  gtk_clutter_init (NULL, NULL);
   return gst_init_get_option_group ();
 }
 
@@ -6521,6 +6252,7 @@ bacon_video_widget_get_option_group (void)
 void
 bacon_video_widget_init_backend (int *argc, char ***argv)
 {
+  gtk_clutter_init (argc, argv);
   gst_init (argc, argv);
 }
 
@@ -6535,191 +6267,6 @@ bacon_video_widget_error_quark (void)
   return q;
 }
 
-/* fold function to pick the best colorspace element */
-static gboolean
-find_colorbalance_element (GstElement *element, GValue * ret, GstElement **cb)
-{
-  GstColorBalanceClass *cb_class;
-
-  GST_DEBUG ("Checking element %s ...", GST_OBJECT_NAME (element));
-
-  if (!GST_IS_COLOR_BALANCE (element))
-    return TRUE;
-
-  GST_DEBUG ("Element %s is a color balance", GST_OBJECT_NAME (element));
-
-  cb_class = GST_COLOR_BALANCE_GET_CLASS (element);
-  if (GST_COLOR_BALANCE_TYPE (cb_class) == GST_COLOR_BALANCE_HARDWARE) {
-    gst_object_replace ((GstObject **) cb, (GstObject *) element);
-    /* shortcuts the fold */
-    return FALSE;
-  } else if (*cb == NULL) {
-    gst_object_replace ((GstObject **) cb, (GstObject *) element);
-    return TRUE;
-  } else {
-    return TRUE;
-  }
-}
-
-static gboolean
-bvw_update_interfaces_delayed (BaconVideoWidget *bvw)
-{
-  GST_DEBUG ("Delayed updating interface implementations");
-  g_mutex_lock (bvw->priv->lock);
-  bvw_update_interface_implementations (bvw);
-  bvw->priv->interface_update_id = 0;
-  g_mutex_unlock (bvw->priv->lock);
-
-  return FALSE;
-}
-
-/* Must be called with bvw->priv->lock held */
-static void
-bvw_update_interface_implementations (BaconVideoWidget *bvw)
-{
-  GstColorBalance *old_balance = bvw->priv->balance;
-  GstXOverlay *old_xoverlay = bvw->priv->xoverlay;
-  GstElement *video_sink = NULL;
-  GstElement *element = NULL;
-  GstIterator *iter;
-  GstElement *play;
-
-  if (g_thread_self() != gui_thread) {
-    if (bvw->priv->balance)
-      gst_object_unref (bvw->priv->balance);
-    bvw->priv->balance = NULL;
-    if (bvw->priv->xoverlay)
-      gst_object_unref (bvw->priv->xoverlay);
-    bvw->priv->xoverlay = NULL;
-    if (bvw->priv->navigation)
-      gst_object_unref (bvw->priv->navigation);
-    bvw->priv->navigation = NULL;
-
-    if (bvw->priv->interface_update_id)
-       g_source_remove (bvw->priv->interface_update_id);
-    bvw->priv->interface_update_id =
-        g_idle_add ((GSourceFunc) bvw_update_interfaces_delayed, bvw);
-    return;
-  }
-
-  play = gst_object_ref(bvw->priv->play);
-
-  g_mutex_unlock (bvw->priv->lock);
-  g_object_get (bvw->priv->play, "video-sink", &video_sink, NULL);
-  g_assert (video_sink != NULL);
-  g_mutex_lock (bvw->priv->lock);
-
-  gst_object_unref(play);
-
-  /* We try to get an element supporting XOverlay interface */
-  if (GST_IS_BIN (video_sink)) {
-    GST_DEBUG ("Retrieving xoverlay from bin ...");
-    element = gst_bin_get_by_interface (GST_BIN (video_sink),
-                                        GST_TYPE_X_OVERLAY);
-  } else {
-    element = gst_object_ref(video_sink);
-  }
-
-  if (GST_IS_X_OVERLAY (element)) {
-    GST_DEBUG ("Found xoverlay: %s", GST_OBJECT_NAME (element));
-    bvw->priv->xoverlay = GST_X_OVERLAY (element);
-  } else {
-    GST_DEBUG ("No xoverlay found");
-    if (element)
-      gst_object_unref (element);
-    bvw->priv->xoverlay = NULL;
-  }
-
-  /* Try to find the navigation interface */
-  if (GST_IS_BIN (video_sink)) {
-    GST_DEBUG ("Retrieving navigation from bin ...");
-    element = gst_bin_get_by_interface (GST_BIN (video_sink),
-                                        GST_TYPE_NAVIGATION);
-  } else {
-    element = gst_object_ref(video_sink);
-  }
-
-  if (GST_IS_NAVIGATION (element)) {
-    GST_DEBUG ("Found navigation: %s", GST_OBJECT_NAME (element));
-    bvw->priv->navigation = GST_NAVIGATION (element);
-  } else {
-    GST_DEBUG ("No navigation found");
-    if (element)
-      gst_object_unref (element);
-    bvw->priv->navigation = NULL;
-  }
-
-  /* Find best color balance element (using custom iterator so
-   * we can prefer hardware implementations to software ones) */
-
-  /* FIXME: this doesn't work reliably yet, most of the time
-   * the fold function doesn't even get called, while sometimes
-   * it does ... */
-  iter = gst_bin_iterate_all_by_interface (GST_BIN (bvw->priv->play),
-                                           GST_TYPE_COLOR_BALANCE);
-  /* naively assume no resync */
-  element = NULL;
-  gst_iterator_fold (iter,
-      (GstIteratorFoldFunction) find_colorbalance_element, NULL, &element);
-  gst_iterator_free (iter);
-
-  if (element) {
-    bvw->priv->balance = GST_COLOR_BALANCE (element);
-    GST_DEBUG ("Best colorbalance found: %s",
-        GST_OBJECT_NAME (bvw->priv->balance));
-  } else if (GST_IS_COLOR_BALANCE (bvw->priv->xoverlay)) {
-    bvw->priv->balance = GST_COLOR_BALANCE (bvw->priv->xoverlay);
-    gst_object_ref (bvw->priv->balance);
-    GST_DEBUG ("Colorbalance backup found: %s",
-        GST_OBJECT_NAME (bvw->priv->balance));
-  } else {
-    GST_DEBUG ("No colorbalance found");
-    bvw->priv->balance = NULL;
-  }
-
-  if (old_xoverlay)
-    gst_object_unref (GST_OBJECT (old_xoverlay));
-
-  if (old_balance)
-    gst_object_unref (GST_OBJECT (old_balance));
-
-  gst_object_unref (video_sink);
-}
-
-static void
-bvw_element_msg_sync (GstBus *bus, GstMessage *msg, gpointer data)
-{
-  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (data);
-
-  g_assert (msg->type == GST_MESSAGE_ELEMENT);
-
-  if (msg->structure == NULL)
-    return;
-
-  /* This only gets sent if we haven't set an ID yet. This is our last
-   * chance to set it before the video sink will create its own window */
-  if (gst_structure_has_name (msg->structure, "prepare-xwindow-id")) {
-    XID window;
-
-    GST_DEBUG ("Handling sync prepare-xwindow-id message");
-
-    g_mutex_lock (bvw->priv->lock);
-    bvw_update_interface_implementations (bvw);
-    if (bvw->priv->xoverlay == NULL) {
-      GstObject *sender = GST_MESSAGE_SRC (msg);
-      if (sender && GST_IS_X_OVERLAY (sender))
-        bvw->priv->xoverlay = GST_X_OVERLAY (gst_object_ref (sender));
-    }
-    g_mutex_unlock (bvw->priv->lock);
-
-    g_return_if_fail (bvw->priv->xoverlay != NULL);
-    g_return_if_fail (bvw->priv->video_window != NULL);
-
-    window = gdk_x11_window_get_xid (bvw->priv->video_window);
-    gst_x_overlay_set_xwindow_id (bvw->priv->xoverlay, window);
-  }
-}
-
 static gboolean
 bvw_set_playback_direction (BaconVideoWidget *bvw, gboolean forward)
 {
@@ -6782,21 +6329,8 @@ bvw_set_playback_direction (BaconVideoWidget *bvw, gboolean forward)
   return retval;
 }
 
-static void
-got_new_video_sink_bin_element (GstBin *video_sink, GstElement *element,
-                                gpointer data)
-{
-  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (data);
-
-  g_mutex_lock (bvw->priv->lock);
-  bvw_update_interface_implementations (bvw);
-  g_mutex_unlock (bvw->priv->lock);
-}
-
 /**
  * bacon_video_widget_new:
- * @width: initial or expected video width, in pixels, or %-1
- * @height: initial or expected video height, in pixels, or %-1
  * @type: the widget's use type
  * @error: a #GError, or %NULL
  *
@@ -6814,13 +6348,13 @@ got_new_video_sink_bin_element (GstBin *video_sink, GstElement *element,
  * Return value: a new #BaconVideoWidget, or %NULL; destroy with gtk_widget_destroy()
  **/
 GtkWidget *
-bacon_video_widget_new (int width, int height,
-                        BvwUseType type, GError ** error)
+bacon_video_widget_new (BvwUseType type, GError ** error)
 {
   BaconVideoWidget *bvw;
   GstElement *audio_sink = NULL, *video_sink = NULL;
   gchar *version_str;
   GstPlayFlags flags;
+  ClutterColor black = { 0x00, 0x00, 0x00, 0xff };
 
 #ifndef GST_DISABLE_GST_DEBUG
   if (_totem_gst_debug_cat == NULL) {
@@ -6905,75 +6439,68 @@ bacon_video_widget_new (int width, int height,
   }
 
   if (type == BVW_USE_TYPE_VIDEO) {
-    if (width > 0 && width < SMALL_STREAM_WIDTH &&
-        height > 0 && height < SMALL_STREAM_HEIGHT) {
-      GST_INFO ("forcing ximagesink, image size only %dx%d", width, height);
-      video_sink = gst_element_factory_make ("ximagesink", "video-sink");
-    } else {
-      video_sink = gst_element_factory_make ("gconfvideosink", "video-sink");
-      if (video_sink == NULL) {
-        g_warning ("Could not create element 'gconfvideosink'");
-        /* Try to fallback on ximagesink */
-        video_sink = gst_element_factory_make ("ximagesink", "video-sink");
-      }
-    }
-
-    /* Set the display if the video sink supports it */
-    if (g_object_class_find_property (G_OBJECT_GET_CLASS (video_sink), "display")) {
-      const char *display;
-
-      display = gdk_get_display_arg_name();
-      if (display != NULL)
-	g_object_set (G_OBJECT (video_sink), "display", display, NULL);
-    }
+    ClutterConstraint *constraint;
+    GstElement *balance, *sink, *bin;
+    GstPad *pad, *ghostpad;
+
+    bvw->priv->stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (bvw));
+    clutter_stage_set_color (CLUTTER_STAGE (bvw->priv->stage), &black);
+
+    /* Bin */
+    bin = gst_bin_new ("video_sink_bin");
+
+    /* Video sink, with aspect frame */
+    bvw->priv->texture = g_object_new (CLUTTER_TYPE_TEXTURE,
+				       "disable-slicing", TRUE,
+				       NULL);
+    sink = clutter_gst_video_sink_new (CLUTTER_TEXTURE (bvw->priv->texture));
+    bvw->priv->navigation = GST_NAVIGATION (sink);
+    if (sink == NULL)
+      g_critical ("Could not create Clutter video sink");
+
+    /* The logo */
+    bvw->priv->logo_frame = mx_aspect_frame_new ();
+    bvw->priv->logo = clutter_texture_new ();
+    mx_bin_set_child (MX_BIN (bvw->priv->logo_frame), bvw->priv->logo);
+    clutter_container_add_actor (CLUTTER_CONTAINER (bvw->priv->stage), bvw->priv->logo_frame);
+    mx_bin_set_fill (MX_BIN (bvw->priv->logo_frame), FALSE, FALSE);
+    mx_bin_set_alignment (MX_BIN (bvw->priv->logo_frame), MX_ALIGN_MIDDLE, MX_ALIGN_MIDDLE);
+    clutter_actor_set_size (bvw->priv->logo, LOGO_SIZE, LOGO_SIZE);
+    constraint = clutter_bind_constraint_new (bvw->priv->stage, CLUTTER_BIND_SIZE, 0.0);
+    clutter_actor_add_constraint_with_name (bvw->priv->logo_frame, "size", constraint);
+    clutter_actor_hide (CLUTTER_ACTOR (bvw->priv->logo_frame));
+
+    /* The video */
+    bvw->priv->frame = mx_aspect_frame_new ();
+    mx_bin_set_child (MX_BIN (bvw->priv->frame), bvw->priv->texture);
+
+    clutter_container_add_actor (CLUTTER_CONTAINER (bvw->priv->stage), bvw->priv->frame);
+    constraint = clutter_bind_constraint_new (bvw->priv->stage, CLUTTER_BIND_SIZE, 0.0);
+    clutter_actor_add_constraint_with_name (bvw->priv->frame, "size", constraint);
+
+    clutter_actor_raise (CLUTTER_ACTOR (bvw->priv->frame),
+			 CLUTTER_ACTOR (bvw->priv->logo_frame));
+
+    gst_bin_add (GST_BIN (bin), sink);
+
+    /* Add video balance */
+    balance = gst_element_factory_make ("videobalance", "video_balance");
+    gst_bin_add (GST_BIN (bin), balance);
+    bvw->priv->balance = GST_COLOR_BALANCE (balance);
+    pad = gst_element_get_static_pad (balance, "sink");
+    ghostpad = gst_ghost_pad_new ("sink", pad);
+    gst_element_add_pad (bin, ghostpad);
+
+    gst_element_link (balance, sink);
+
+    video_sink = bin;
+    gst_element_set_state (video_sink, GST_STATE_READY);
   } else {
     video_sink = gst_element_factory_make ("fakesink", "video-fake-sink");
     if (video_sink)
       g_object_set (video_sink, "sync", TRUE, NULL);
   }
 
-  if (video_sink) {
-    GstStateChangeReturn ret;
-
-    /* need to set bus explicitly as it's not in a bin yet and
-     * poll_for_state_change() needs one to catch error messages */
-    gst_element_set_bus (video_sink, bvw->priv->bus);
-    /* state change NULL => READY should always be synchronous */
-    ret = gst_element_set_state (video_sink, GST_STATE_READY);
-    if (ret == GST_STATE_CHANGE_FAILURE) {
-      /* Drop this video sink */
-      gst_element_set_state (video_sink, GST_STATE_NULL);
-      gst_object_unref (video_sink);
-      /* Try again with ximagesink */
-      video_sink = gst_element_factory_make ("ximagesink", "video-sink");
-      gst_element_set_bus (video_sink, bvw->priv->bus);
-      ret = gst_element_set_state (video_sink, GST_STATE_READY);
-      if (ret == GST_STATE_CHANGE_FAILURE) {
-        GstMessage *err_msg;
-
-        err_msg = gst_bus_poll (bvw->priv->bus, GST_MESSAGE_ERROR, 0);
-        if (err_msg == NULL) {
-          g_warning ("Should have gotten an error message, please file a bug.");
-          g_set_error_literal (error, BVW_ERROR, BVW_ERROR_VIDEO_PLUGIN,
-               _("Failed to open video output. It may not be available. "
-                 "Please select another video output in the Multimedia "
-                 "Systems Selector."));
-        } else if (error) {
-          *error = bvw_error_from_gst_error (bvw, err_msg);
-          gst_message_unref (err_msg);
-        }
-        goto sink_error;
-      }
-    }
-  } else {
-    g_set_error_literal (error, BVW_ERROR, BVW_ERROR_VIDEO_PLUGIN,
-                 _("Could not find the video output. "
-                   "You may need to install additional GStreamer plugins, "
-                   "or select another video output in the Multimedia Systems "
-                   "Selector."));
-    goto sink_error;
-  }
-
   if (audio_sink) {
     GstStateChangeReturn ret;
     GstBus *bus;
@@ -7030,7 +6557,8 @@ bacon_video_widget_new (int width, int height,
   }
 
   /* set back to NULL to close device again in order to avoid interrupts
-   * being generated after startup while there's nothing to play yet */
+   * being generated after startup while there's nothing to play yet
+   * FIXME not needed anymore, PulseAudio? */
   gst_element_set_state (audio_sink, GST_STATE_NULL);
 
   do {
@@ -7094,25 +6622,6 @@ bacon_video_widget_new (int width, int height,
           "Please select another video output in the Multimedia Systems Selector."));
       return NULL;
     }
-    g_mutex_lock (bvw->priv->lock);
-    bvw_update_interface_implementations (bvw);
-    g_mutex_unlock (bvw->priv->lock);
-  }
-
-  /* we want to catch "prepare-xwindow-id" element messages synchronously */
-  gst_bus_set_sync_handler (bvw->priv->bus, gst_bus_sync_signal_handler, bvw);
-
-  bvw->priv->sig_bus_sync = 
-      g_signal_connect (bvw->priv->bus, "sync-message::element",
-                        G_CALLBACK (bvw_element_msg_sync), bvw);
-
-  if (GST_IS_BIN (video_sink)) {
-    /* video sink bins like gconfvideosink might remove their children and
-     * create new ones when set to NULL state, and they are currently set
-     * to NULL state whenever playbin re-creates its internal video bin
-     * (it sets all elements to NULL state before gst_bin_remove()ing them) */
-    g_signal_connect (video_sink, "element-added",
-                      G_CALLBACK (got_new_video_sink_bin_element), bvw);
   }
 
   return GTK_WIDGET (bvw);
diff --git a/src/backend/bacon-video-widget.h b/src/backend/bacon-video-widget.h
index 25bc80a..5b004d6 100644
--- a/src/backend/bacon-video-widget.h
+++ b/src/backend/bacon-video-widget.h
@@ -28,7 +28,7 @@
 #ifndef HAVE_BACON_VIDEO_WIDGET_H
 #define HAVE_BACON_VIDEO_WIDGET_H
 
-#include <gtk/gtk.h>
+#include <clutter-gtk/clutter-gtk.h>
 /* for optical disc enumeration type */
 #include <totem-disc.h>
 
@@ -51,7 +51,7 @@ typedef struct BaconVideoWidgetCommon BaconVideoWidgetCommon;
  **/
 typedef struct {
 	/*< private >*/
-	GtkEventBox parent;
+	GtkClutterEmbed parent;
 	BaconVideoWidgetPrivate *priv;
 } BaconVideoWidget;
 
@@ -62,7 +62,7 @@ typedef struct {
  **/
 typedef struct {
 	/*< private >*/
-	GtkEventBoxClass parent_class;
+	GtkClutterEmbedClass parent_class;
 
 	void (*error) (GtkWidget *bvw, const char *message,
                        gboolean playback_stopped, gboolean fatal);
@@ -160,8 +160,7 @@ typedef enum {
 	BVW_USE_TYPE_METADATA
 } BvwUseType;
 
-GtkWidget *bacon_video_widget_new		 (int width, int height,
-						  BvwUseType type,
+GtkWidget *bacon_video_widget_new		 (BvwUseType type,
 						  GError **error);
 
 char *bacon_video_widget_get_backend_name (BaconVideoWidget *bvw);
@@ -388,6 +387,19 @@ typedef enum {
 	BVW_RATIO_DVB = 4
 } BvwAspectRatio;
 
+/**
+ * BvwZoomMode:
+ * @BVW_ZOOM_NONE: No video zooming/cropping
+ * @BVW_ZOOM_EXPAND: Fill area with video, and crop the excess
+ *
+ * The zoom mode used by the video widget, as set by
+ * bacon_video_widget_set_zoom().
+ **/
+typedef enum {
+	BVW_ZOOM_NONE = 0,
+	BVW_ZOOM_EXPAND = 1
+} BvwZoomMode;
+
 void bacon_video_widget_set_deinterlacing        (BaconVideoWidget *bvw,
 						  gboolean deinterlace);
 gboolean bacon_video_widget_get_deinterlacing    (BaconVideoWidget *bvw);
@@ -401,8 +413,8 @@ void bacon_video_widget_set_scale_ratio          (BaconVideoWidget *bvw,
 						  float ratio);
 
 void bacon_video_widget_set_zoom		 (BaconVideoWidget *bvw,
-						  double zoom);
-double bacon_video_widget_get_zoom		 (BaconVideoWidget *bvw);
+						  BvwZoomMode       mode);
+BvwZoomMode bacon_video_widget_get_zoom		 (BaconVideoWidget *bvw);
 
 int bacon_video_widget_get_video_property        (BaconVideoWidget *bvw,
 						  BvwVideoProperty type);
diff --git a/src/backend/bvw-test.c b/src/backend/bvw-test.c
index 818aa01..6d85b1f 100644
--- a/src/backend/bvw-test.c
+++ b/src/backend/bvw-test.c
@@ -66,8 +66,6 @@ int main
 (int argc, char **argv)
 {
 	GtkWidget *win, *bvw;
-	guint32 height = 500;
-	guint32 width = 500;
 
 	if (argc > 2) {
 		g_warning ("Usage: %s <file>", argv[0]);
@@ -83,13 +81,13 @@ int main
 	gdk_threads_init ();
 
 	win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-	gtk_window_set_default_size (GTK_WINDOW (win), width, height);
+	gtk_window_set_default_size (GTK_WINDOW (win), 500, 500);
 	g_signal_connect (G_OBJECT (win), "destroy",
 			G_CALLBACK (gtk_main_quit), NULL);
 
-	bvw = bacon_video_widget_new (width, height,
-			BVW_USE_TYPE_VIDEO, NULL);
+	bvw = bacon_video_widget_new (BVW_USE_TYPE_VIDEO, NULL);
 	bacon_video_widget_set_logo (BACON_VIDEO_WIDGET (bvw), "totem");
+	bacon_video_widget_set_show_visualizations (BACON_VIDEO_WIDGET (bvw), TRUE);
 
 	g_signal_connect (G_OBJECT (bvw), "eos", G_CALLBACK (on_eos_event), NULL);
 	g_signal_connect (G_OBJECT (bvw), "got-metadata", G_CALLBACK (on_got_metadata), NULL);
@@ -104,10 +102,14 @@ int main
 	gtk_widget_show (win);
 	gtk_widget_show (bvw);
 
-	mrl = NULL;
-	test_bvw_set_mrl (bvw, argv[1] ? argv[1] : LOGO_PATH);
-	argument = g_strdup (argv[1] ? argv[1] : LOGO_PATH);
-	bacon_video_widget_play (BACON_VIDEO_WIDGET (bvw), NULL);
+	if (argv[1]) {
+		test_bvw_set_mrl (bvw, argv[1]);
+		argument = g_strdup (argv[1]);
+		bacon_video_widget_play (BACON_VIDEO_WIDGET (bvw), NULL);
+	} else {
+		bacon_video_widget_set_logo_mode (BACON_VIDEO_WIDGET (bvw), TRUE);
+	}
+
 	gtk_main ();
 
 	return 0;
diff --git a/src/totem-audio-preview.c b/src/totem-audio-preview.c
index 9b800d8..8e41fca 100644
--- a/src/totem-audio-preview.c
+++ b/src/totem-audio-preview.c
@@ -117,7 +117,7 @@ int main (int argc, char **argv)
 	}
 	path = filenames ? filenames[0] : "fd://0";
 
-	widget = bacon_video_widget_new (-1, -1, BVW_USE_TYPE_AUDIO, &error);
+	widget = bacon_video_widget_new (BVW_USE_TYPE_AUDIO, &error);
 	if (widget == NULL) {
 		g_print ("error creating the video widget: %s\n", error->message);
 		g_error_free (error);
diff --git a/src/totem-menu.c b/src/totem-menu.c
index e08e0f5..86bd248 100644
--- a/src/totem-menu.c
+++ b/src/totem-menu.c
@@ -53,9 +53,7 @@ G_MODULE_EXPORT void fullscreen_action_callback (GtkAction *action, Totem *totem
 G_MODULE_EXPORT void zoom_1_2_action_callback (GtkAction *action, Totem *totem);
 G_MODULE_EXPORT void zoom_1_1_action_callback (GtkAction *action, Totem *totem);
 G_MODULE_EXPORT void zoom_2_1_action_callback (GtkAction *action, Totem *totem);
-G_MODULE_EXPORT void zoom_in_action_callback (GtkAction *action, Totem *totem);
-G_MODULE_EXPORT void zoom_reset_action_callback (GtkAction *action, Totem *totem);
-G_MODULE_EXPORT void zoom_out_action_callback (GtkAction *action, Totem *totem);
+G_MODULE_EXPORT void zoom_toggle_action_callback (GtkToggleAction *action, Totem *totem);
 G_MODULE_EXPORT void next_angle_action_callback (GtkAction *action, Totem *totem);
 G_MODULE_EXPORT void dvd_root_menu_action_callback (GtkAction *action, Totem *totem);
 G_MODULE_EXPORT void dvd_title_menu_action_callback (GtkAction *action, Totem *totem);
@@ -1075,21 +1073,11 @@ zoom_2_1_action_callback (GtkAction *action, Totem *totem)
 }
 
 void
-zoom_in_action_callback (GtkAction *action, Totem *totem)
+zoom_toggle_action_callback (GtkToggleAction *action,
+			     Totem           *totem)
 {
-	totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
-}
-
-void
-zoom_reset_action_callback (GtkAction *action, Totem *totem)
-{
-	totem_action_zoom_reset (totem);
-}
-
-void
-zoom_out_action_callback (GtkAction *action, Totem *totem)
-{
-	totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
+	bacon_video_widget_set_zoom (totem->bvw,
+				     gtk_toggle_action_get_active (action) ? BVW_ZOOM_EXPAND : BVW_ZOOM_NONE);
 }
 
 void
@@ -1379,7 +1367,6 @@ void
 totem_ui_manager_setup (Totem *totem)
 {
 	totem->main_action_group = GTK_ACTION_GROUP (gtk_builder_get_object (totem->xml, "main-action-group"));
-	totem->zoom_action_group = GTK_ACTION_GROUP (gtk_builder_get_object (totem->xml, "zoom-action-group"));
 
 	/* FIXME: Moving these to GtkBuilder depends on bug #457631 */
 	if (gtk_widget_get_direction (totem->win) == GTK_TEXT_DIR_RTL) {
diff --git a/src/totem-object.c b/src/totem-object.c
index 22c234c..cc25a9e 100644
--- a/src/totem-object.c
+++ b/src/totem-object.c
@@ -79,12 +79,6 @@
 #define SEEK_FORWARD_LONG_OFFSET 10*60
 #define SEEK_BACKWARD_LONG_OFFSET -3*60
 
-#define ZOOM_UPPER 2.0
-#define ZOOM_RESET 1.0
-#define ZOOM_LOWER 0.1
-#define ZOOM_DISABLE (ZOOM_LOWER - 1)
-#define ZOOM_ENABLE (ZOOM_UPPER + 1)
-
 #define DEFAULT_WINDOW_W 650
 #define DEFAULT_WINDOW_H 500
 
@@ -1999,58 +1993,14 @@ totem_object_action_seek_time (TotemObject *totem, gint64 msec, gboolean accurat
 	totem_seek_time_rel (totem, msec, FALSE, accurate);
 }
 
-static void
-totem_action_zoom (TotemObject *totem, double zoom)
-{
-	GtkAction *action;
-	gboolean zoom_reset, zoom_in, zoom_out;
-
-	if (totem->bvw == NULL)
-		return;
-
-	if (zoom == ZOOM_ENABLE)
-		zoom = bacon_video_widget_get_zoom (totem->bvw);
-
-	if (zoom == ZOOM_DISABLE) {
-		zoom_reset = zoom_in = zoom_out = FALSE;
-	} else if (zoom < ZOOM_LOWER || zoom > ZOOM_UPPER) {
-		return;
-	} else {
-		bacon_video_widget_set_zoom (totem->bvw, zoom);
-		zoom_reset = (zoom != ZOOM_RESET);
-		zoom_out = zoom != ZOOM_LOWER;
-		zoom_in = zoom != ZOOM_UPPER;
-	}
-
-	action = gtk_action_group_get_action (totem->zoom_action_group,
-			"zoom-in");
-	gtk_action_set_sensitive (action, zoom_in);
-
-	action = gtk_action_group_get_action (totem->zoom_action_group,
-			"zoom-out");
-	gtk_action_set_sensitive (action, zoom_out);
-
-	action = gtk_action_group_get_action (totem->zoom_action_group,
-			"zoom-reset");
-	gtk_action_set_sensitive (action, zoom_reset);
-}
-
 void
-totem_action_zoom_relative (TotemObject *totem, double off_pct)
+totem_action_set_zoom (TotemObject *totem,
+		       gboolean     zoom)
 {
-	double zoom;
-
-	if (totem->bvw == NULL)
-		return;
+	GtkAction *action;
 
-	zoom = bacon_video_widget_get_zoom (totem->bvw);
-	totem_action_zoom (totem, zoom + off_pct);
-}
-
-void
-totem_action_zoom_reset (TotemObject *totem)
-{
-	totem_action_zoom (totem, ZOOM_RESET);
+	action = gtk_action_group_get_action (totem->main_action_group, "zoom-toggle");
+	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), zoom);
 }
 
 /**
@@ -2702,14 +2652,6 @@ property_notify_cb_volume (BaconVideoWidget *bvw, GParamSpec *spec, TotemObject
 }
 
 static void
-property_notify_cb_logo_mode (BaconVideoWidget *bvw, GParamSpec *spec, TotemObject *totem)
-{
-	gboolean enabled;
-	enabled = bacon_video_widget_get_logo_mode (totem->bvw);
-	totem_action_zoom (totem, enabled ? ZOOM_DISABLE : ZOOM_ENABLE);
-}
-
-static void
 property_notify_cb_seekable (BaconVideoWidget *bvw, GParamSpec *spec, TotemObject *totem)
 {
 	update_seekable (totem);
@@ -3198,10 +3140,10 @@ totem_object_action_remote (TotemObject *totem, TotemRemoteCommand cmd, const ch
 				BVW_DVD_ROOT_MENU);
 		break;
 	case TOTEM_REMOTE_COMMAND_ZOOM_UP:
-		totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
+		totem_action_set_zoom (totem, TRUE);
 		break;
 	case TOTEM_REMOTE_COMMAND_ZOOM_DOWN:
-		totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
+		totem_action_set_zoom (totem, FALSE);
 		break;
 	case TOTEM_REMOTE_COMMAND_EJECT:
 		totem_action_eject (totem);
@@ -3661,12 +3603,12 @@ totem_action_handle_key_press (TotemObject *totem, GdkEventKey *event)
 	case GDK_KEY_r:
 	case GDK_KEY_R:
 	case GDK_KEY_ZoomIn:
-		totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
+		totem_action_set_zoom (totem, TRUE);
 		break;
 	case GDK_KEY_t:
 	case GDK_KEY_T:
 	case GDK_KEY_ZoomOut:
-		totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
+		totem_action_set_zoom (totem, FALSE);
 		break;
 	case GDK_KEY_Eject:
 		totem_action_eject (totem);
@@ -3738,7 +3680,7 @@ totem_action_handle_key_press (TotemObject *totem, GdkEventKey *event)
 		break;
 	case GDK_KEY_0:
 		if (event->state & GDK_CONTROL_MASK)
-			totem_action_zoom_reset (totem);
+			totem_action_set_zoom (totem, FALSE);
 		else
 			totem_action_set_scale_ratio (totem, 0.5);
 		break;
@@ -3762,18 +3704,18 @@ totem_action_handle_key_press (TotemObject *totem, GdkEventKey *event)
 		break;
 	case GDK_KEY_equal:
 		if (event->state & GDK_CONTROL_MASK)
-			totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
+			totem_action_set_zoom (totem, TRUE);
 		break;
 	case GDK_KEY_hyphen:
 		if (event->state & GDK_CONTROL_MASK)
-			totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
+			totem_action_set_zoom (totem, FALSE);
 		break;
 	case GDK_KEY_plus:
 	case GDK_KEY_KP_Add:
 		if (!(event->state & GDK_CONTROL_MASK)) {
 			totem_action_next (totem);
 		} else {
-			totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
+			totem_action_set_zoom (totem, TRUE);
 		}
 		break;
 	case GDK_KEY_minus:
@@ -3781,7 +3723,7 @@ totem_action_handle_key_press (TotemObject *totem, GdkEventKey *event)
 		if (!(event->state & GDK_CONTROL_MASK)) {
 			totem_action_previous (totem);
 		} else {
-			totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
+			totem_action_set_zoom (totem, FALSE);
 		}
 		break;
 	case GDK_KEY_KP_Up:
@@ -4274,7 +4216,7 @@ video_widget_create (TotemObject *totem)
 	BaconVideoWidget **bvw;
 
 	totem->bvw = BACON_VIDEO_WIDGET
-		(bacon_video_widget_new (-1, -1, BVW_USE_TYPE_VIDEO, &err));
+		(bacon_video_widget_new (BVW_USE_TYPE_VIDEO, &err));
 
 	if (totem->bvw == NULL) {
 		totem_action_error_and_exit (_("Totem could not startup."), err != NULL ? err->message : _("No reason."), totem);
@@ -4282,8 +4224,6 @@ video_widget_create (TotemObject *totem)
 			g_error_free (err);
 	}
 
-	totem_action_zoom (totem, ZOOM_RESET);
-
 	g_signal_connect_after (G_OBJECT (totem->bvw),
 			"button-press-event",
 			G_CALLBACK (on_video_button_press_event),
@@ -4355,8 +4295,6 @@ video_widget_create (TotemObject *totem)
 
 	g_signal_connect (G_OBJECT (totem->bvw), "notify::volume",
 			G_CALLBACK (property_notify_cb_volume), totem);
-	g_signal_connect (G_OBJECT (totem->bvw), "notify::logo-mode",
-			G_CALLBACK (property_notify_cb_logo_mode), totem);
 	g_signal_connect (G_OBJECT (totem->bvw), "notify::seekable",
 			G_CALLBACK (property_notify_cb_seekable), totem);
 	update_volume_sliders (totem);
diff --git a/src/totem-private.h b/src/totem-private.h
index deca5ab..092153a 100644
--- a/src/totem-private.h
+++ b/src/totem-private.h
@@ -80,7 +80,6 @@ struct _TotemObject {
 
 	/* UI manager */
 	GtkActionGroup *main_action_group;
-	GtkActionGroup *zoom_action_group;
 	GtkUIManager *ui_manager;
 
 	GtkActionGroup *devices_action_group;
@@ -182,8 +181,7 @@ GtkWidget *totem_volume_create (void);
 void	totem_action_open			(Totem *totem);
 void	totem_action_open_location		(Totem *totem);
 void	totem_action_eject			(Totem *totem);
-void	totem_action_zoom_relative		(Totem *totem, double off_pct);
-void	totem_action_zoom_reset			(Totem *totem);
+void	totem_action_set_zoom			(Totem *totem, gboolean zoom);
 void	totem_action_show_help			(Totem *totem);
 void	totem_action_show_properties		(Totem *totem);
 gboolean totem_action_open_files		(Totem *totem, char **list);
diff --git a/src/totem-properties-view.c b/src/totem-properties-view.c
index 7716400..f7f6e72 100644
--- a/src/totem-properties-view.c
+++ b/src/totem-properties-view.c
@@ -106,7 +106,7 @@ totem_properties_view_init (TotemPropertiesView *props)
 	props->priv = g_new0 (TotemPropertiesViewPriv, 1);
 
 	props->priv->bvw = BACON_VIDEO_WIDGET (bacon_video_widget_new
-			(-1, -1, BVW_USE_TYPE_METADATA, &err));
+			(BVW_USE_TYPE_METADATA, &err));
 
 	if (props->priv->bvw != NULL)
 	{
diff --git a/src/totem-video-indexer.c b/src/totem-video-indexer.c
index 465d198..c27f7e6 100644
--- a/src/totem-video-indexer.c
+++ b/src/totem-video-indexer.c
@@ -190,7 +190,7 @@ int main (int argc, char **argv)
 		return 1;
 	}
 
-	widget = bacon_video_widget_new (-1, -1, BVW_USE_TYPE_METADATA, &error);
+	widget = bacon_video_widget_new (BVW_USE_TYPE_METADATA, &error);
 	if (widget == NULL) {
 		g_print ("error creating the video widget: %s\n", error->message);
 		g_error_free (error);
diff --git a/src/totem-video-thumbnailer.c b/src/totem-video-thumbnailer.c
index cb235dd..8ac478b 100644
--- a/src/totem-video-thumbnailer.c
+++ b/src/totem-video-thumbnailer.c
@@ -850,7 +850,7 @@ int main (int argc, char *argv[])
 	PROGRESS_DEBUG("Initialised libraries, about to create video widget");
 	PRINT_PROGRESS (2.0);
 
-	bvw = BACON_VIDEO_WIDGET (bacon_video_widget_new (-1, -1, BVW_USE_TYPE_CAPTURE, &err));
+	bvw = BACON_VIDEO_WIDGET (bacon_video_widget_new (BVW_USE_TYPE_CAPTURE, &err));
 	if (err != NULL) {
 		g_print ("totem-video-thumbnailer couldn't create the video "
 				"widget.\nReason: %s.\n", err->message);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]