[totem/wip/hadess/glsink: 4/12] backend: Port to gtkglsink




commit 22b2d3d8c3bc2ad78b5435ab882ef65f4886a3bb
Author: Bastien Nocera <hadess hadess net>
Date:   Thu Jan 27 14:12:47 2022 +0100

    backend: Port to gtkglsink
    
    Replace the clutter-gtk based video widget with a native GL GStreamer
    widget, "gtkglsink".
    
    - Display aspect-ratio support for non-square pixels was removed. While
      it still worked correctly (you can try setting your display's resolution
      to a different aspect ratio), things like text and icons, and everything
      else in every application and the shell chrome would have been looked
      broken, including the video player. Except the video in the video player.
    - Video aspect ratio, pillar-boxing, letter-boxing and automatic rotation
      is now handled in the GStreamer widget
    - The placeholder logos, when playing files with unsupported video, or
      no video tracks have been changed.
    - Handling of mouse events has been simplified
    
    Some functionality could not be brought forward at this time:
    - Crop-zooming (available using the R/T keys) isn't implemented yet
    - Gestures support, which never worked properly anyway, wasn't
      reimplemented

 data/controls.ui                      |   5 +
 docs/reference/meson.build            |   4 -
 docs/reference/totem-sections.txt     |   6 -
 meson.build                           |   1 -
 src/backend/bacon-video-widget.c      | 999 +++++-----------------------------
 src/backend/bacon-video-widget.h      |  22 +-
 src/backend/bvw-test.c                |  36 +-
 src/backend/meson.build               |   8 -
 src/meson.build                       |   4 -
 src/plugins/rotation/totem-rotation.c |   5 -
 src/totem-object.c                    | 367 +++++++++----
 src/totem-private.h                   |   9 +-
 12 files changed, 420 insertions(+), 1046 deletions(-)
---
diff --git a/data/controls.ui b/data/controls.ui
index a7ebe9468..a9b1b59e4 100644
--- a/data/controls.ui
+++ b/data/controls.ui
@@ -9,6 +9,11 @@
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="border_width">0</property>
+        <property name="opacity">0.86</property>
+        <style>
+          <class name="osd"/>
+          <class name="bottom"/>
+        </style>
         <child>
           <object class="GtkToolItem" id="controls_toolbutton">
             <property name="visible">True</property>
diff --git a/docs/reference/meson.build b/docs/reference/meson.build
index 6eec8d9d1..0aab998d7 100644
--- a/docs/reference/meson.build
+++ b/docs/reference/meson.build
@@ -2,15 +2,11 @@ doc_module = meson.project_name()
 
 private_headers = [
   'bacon-time-label.h',
-  'bacon-video-controls-actor.h',
-  'bacon-video-spinner-actor.h',
   'bacon-video-widget-gst-missing-plugins.h',
   'bacon-video-widget-properties.h',
-  'clock.h',
   'gd-tagged-entry.h',
   'icon-helpers.h',
   'screenshot-filename-builder.h',
-  'totem-aspect-frame.h',
   'totem-gallery-progress.h',
   'totem-gallery.h',
   'totem-grilo.h',
diff --git a/docs/reference/totem-sections.txt b/docs/reference/totem-sections.txt
index 814907b6d..2a10eb101 100644
--- a/docs/reference/totem-sections.txt
+++ b/docs/reference/totem-sections.txt
@@ -181,14 +181,8 @@ bacon_video_widget_is_seekable
 bacon_video_widget_get_rate
 bacon_video_widget_set_rate
 bacon_video_widget_step
-bacon_video_widget_get_controls_object
-bacon_video_widget_get_header_controls_object
-bacon_video_widget_set_fullscreen
 bacon_video_widget_set_next_language
 bacon_video_widget_set_next_subtitle
-bacon_video_widget_show_popup
-bacon_video_widget_mark_popup_busy
-bacon_video_widget_unmark_popup_busy
 <SUBSECTION Standard>
 BVW_TYPE_ASPECT_RATIO
 BVW_TYPE_AUDIO_OUTPUT_TYPE
diff --git a/meson.build b/meson.build
index f6e7a3cfe..b13b1cfa2 100644
--- a/meson.build
+++ b/meson.build
@@ -152,7 +152,6 @@ gst_pbutils_dep = dependency('gstreamer-pbutils-1.0')
 peas_dep = dependency('libpeas-1.0', version: peas_req_version)
 peas_gtk_dep = dependency('libpeas-gtk-1.0', version: peas_req_version)
 totem_plparser_dep = dependency('totem-plparser', version: totem_plparser_req_version)
-clutter_gtk_dep = dependency('clutter-gtk-1.0', version: '>= 1.8.1')
 m_dep = cc.find_library('m', required: true)
 
 libgd = subproject(
diff --git a/src/backend/bacon-video-widget.c b/src/backend/bacon-video-widget.c
index 030e21224..0564e8598 100644
--- a/src/backend/bacon-video-widget.c
+++ b/src/backend/bacon-video-widget.c
@@ -63,9 +63,6 @@
 /* for the cover metadata info */
 #include <gst/tag/tag.h>
 
-#include <clutter-gst/clutter-gst.h>
-#include "totem-aspect-frame.h"
-
 /* system */
 #include <unistd.h>
 #include <time.h>
@@ -83,8 +80,6 @@
 #include "totem-gst-pixbuf-helpers.h"
 #include "bacon-video-widget.h"
 #include "bacon-video-widget-gst-missing-plugins.h"
-#include "bacon-video-controls-actor.h"
-#include "bacon-video-spinner-actor.h"
 #include "bacon-video-widget-enums.h"
 
 #define DEFAULT_USER_AGENT "Videos/"VERSION
@@ -92,7 +87,6 @@
 #define DEFAULT_CONTROLS_WIDTH 600             /* In pixels */
 #define LOGO_SIZE 256                          /* Maximum size of the logo */
 #define REWIND_OR_PREVIOUS 4000
-#define POPUP_HIDING_TIMEOUT 2
 
 #define MAX_NETWORK_SPEED 10752
 #define BUFFERING_LEFT_RATIO 1.1
@@ -127,6 +121,7 @@ enum
   SIGNAL_SEEK_REQUESTED,
   SIGNAL_TRACK_SKIP_REQUESTED,
   SIGNAL_VOLUME_CHANGE_REQUESTED,
+  SIGNAL_PLAY_STARTING,
   LAST_SIGNAL
 };
 
@@ -150,7 +145,7 @@ enum
   PROP_HUE,
   PROP_AUDIO_OUTPUT_TYPE,
   PROP_AV_OFFSET,
-  PROP_REVEAL_CONTROLS
+  PROP_SHOW_CURSOR,
 };
 
 static const gchar *video_props_str[4] = {
@@ -162,7 +157,7 @@ static const gchar *video_props_str[4] = {
 
 struct _BaconVideoWidget
 {
-  GtkClutterEmbed              parent;
+  GtkOverlay                   parent;
 
   char                        *user_agent;
 
@@ -178,8 +173,6 @@ struct _BaconVideoWidget
   guint                        update_id;
   guint                        fill_id;
 
-  GdkPixbuf                   *logo_pixbuf;
-
   gboolean                     media_has_video;
   gboolean                     media_has_audio;
   gint                         seekable; /* -1 = don't know, FALSE = no */
@@ -197,23 +190,10 @@ struct _BaconVideoWidget
 
   gboolean                     got_redirect;
 
-  ClutterActor                *stage;
-  ClutterActor                *texture;
-  ClutterActor                *frame;
-  ClutterActor                *header_controls;
-  ClutterActor                *controls;
-  ClutterActor                *spinner;
-
-  ClutterActor                *logo_frame;
-  ClutterContent              *logo;
+  GtkWidget                   *stack;
 
   GdkCursor                   *cursor;
 
-  /* Controls */
-  gboolean                     reveal_controls;
-  guint                        transition_timeout_id;
-  GHashTable                  *busy_popup_ht; /* key=reason string, value=gboolean */
-
   /* Visual effects */
   GstElement                  *audio_capsfilter;
   GstElement                  *audio_pitchcontrol;
@@ -230,10 +210,6 @@ struct _BaconVideoWidget
   
   gint                         video_width; /* Movie width */
   gint                         video_height; /* Movie height */
-  gint                         movie_par_n; /* Movie pixel aspect ratio numerator */
-  gint                         movie_par_d; /* Movie pixel aspect ratio denominator */
-  gint                         video_width_pixels; /* Scaled movie width */
-  gint                         video_height_pixels; /* Scaled movie height */
   gint                         video_fps_n;
   gint                         video_fps_d;
 
@@ -279,7 +255,7 @@ struct _BaconVideoWidget
   float                        rate;
 };
 
-G_DEFINE_TYPE_WITH_CODE (BaconVideoWidget, bacon_video_widget, GTK_CLUTTER_TYPE_EMBED,
+G_DEFINE_TYPE_WITH_CODE (BaconVideoWidget, bacon_video_widget, GTK_TYPE_OVERLAY,
                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
                                                bacon_video_widget_initable_iface_init))
 
@@ -302,9 +278,6 @@ static gboolean bacon_video_widget_seek_time_no_lock (BaconVideoWidget *bvw,
                                                      gint64 _time,
                                                      GstSeekFlags flag,
                                                      GError **error);
-static void set_controls_visibility (BaconVideoWidget *bvw,
-                                    gboolean          visible,
-                                    gboolean          animate);
 
 typedef struct {
   GstTagList *tags;
@@ -398,246 +371,13 @@ bvw_check_if_video_decoder_is_missing (BaconVideoWidget * bvw)
   }
 }
 
-static void
-set_display_pixel_aspect_ratio (GdkMonitor *monitor,
-                               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 par_index;
-  gdouble ratio;
-  gdouble delta;
-  GdkRectangle rect;
-
-#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 */
-  gdk_monitor_get_geometry (monitor, &rect);
-
-  ratio = (gdouble) (gdk_monitor_get_width_mm (monitor) * rect.height) /
-    (gdk_monitor_get_height_mm (monitor) * rect.width);
-
-  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);
-  par_index = 0;
-
-  for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
-    gdouble this_delta = DELTA (i);
-
-    if (this_delta < delta) {
-      par_index = i;
-      delta = this_delta;
-    }
-  }
-
-  GST_DEBUG ("Decided on index %d (%d/%d)", par_index,
-            par[par_index][0], par[par_index][1]);
-  gst_value_set_fraction (value, par[par_index][0], par[par_index][1]);
-}
-
-static void
-get_media_size (BaconVideoWidget *bvw, gint *width, gint *height)
-{
-  if (bvw->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 (gtk_widget_get_realized (GTK_WIDGET (bvw))) {
-      GdkDisplay *display;
-      GdkWindow *window;
-      GdkMonitor *monitor;
-
-      display = gtk_widget_get_display (GTK_WIDGET (bvw));
-      window = gtk_widget_get_window (GTK_WIDGET (bvw));
-      if (window)
-        monitor = gdk_display_get_monitor_at_window (display, window);
-      else
-        monitor = gdk_display_get_primary_monitor (display);
-      set_display_pixel_aspect_ratio (monitor, &disp_par);
-    }
-
-    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->ratio_type != BVW_RATIO_AUTO) {
-      switch (bvw->ratio_type) {
-        case BVW_RATIO_SQUARE:
-          movie_par_n = 1;
-          movie_par_d = 1;
-          break;
-        case BVW_RATIO_FOURBYTHREE:
-          movie_par_n = 4 * bvw->video_height;
-          movie_par_d = 3 * bvw->video_width;
-          break;
-        case BVW_RATIO_ANAMORPHIC:
-          movie_par_n = 16 * bvw->video_height;
-          movie_par_d = 9 * bvw->video_width;
-          break;
-        case BVW_RATIO_DVB:
-          movie_par_n = 20 * bvw->video_height;
-          movie_par_d = 9 * bvw->video_width;
-          break;
-        /* handle these to avoid compiler warnings */
-        case BVW_RATIO_AUTO:
-        default:
-          movie_par_n = 0;
-          movie_par_d = 0;
-          g_assert_not_reached ();
-      }
-    } else {
-      /* Use the movie pixel aspect ratio if any */
-      movie_par_n = bvw->movie_par_n;
-      movie_par_d = bvw->movie_par_d;
-    }
-
-    GST_DEBUG ("movie PAR is %d/%d", movie_par_n, movie_par_d);
-
-    if (bvw->video_width == 0 || bvw->video_height == 0) {
-      GST_DEBUG ("width and/or height 0, assuming 1/1 ratio");
-      num = 1;
-      den = 1;
-    } else if (!gst_video_calculate_display_ratio (&num, &den,
-        bvw->video_width, bvw->video_height,
-        movie_par_n, movie_par_d, disp_par_n, disp_par_d)) {
-      GST_WARNING ("overflow calculating display aspect ratio!");
-      num = 1;   /* FIXME: what values to use here? */
-      den = 1;
-    }
-
-    GST_DEBUG ("calculated scaling ratio %d/%d for video %dx%d", num, den,
-        bvw->video_width, bvw->video_height);
-
-    /* now find a width x height that respects this display ratio.
-     * prefer those that have one of w/h the same as the incoming video
-     * using wd / hd = num / den */
-
-    /* start with same height, because of interlaced video */
-    /* check hd / den is an integer scale factor, and scale wd with the PAR */
-    if (bvw->video_height % den == 0) {
-      GST_DEBUG ("keeping video height");
-      bvw->video_width_pixels =
-          (guint) gst_util_uint64_scale (bvw->video_height, num, den);
-      bvw->video_height_pixels = bvw->video_height;
-    } else if (bvw->video_width % num == 0) {
-      GST_DEBUG ("keeping video width");
-      bvw->video_width_pixels = bvw->video_width;
-      bvw->video_height_pixels =
-          (guint) gst_util_uint64_scale (bvw->video_width, den, num);
-    } else {
-      GST_DEBUG ("approximating while keeping video height");
-      bvw->video_width_pixels =
-          (guint) gst_util_uint64_scale (bvw->video_height, num, den);
-      bvw->video_height_pixels = bvw->video_height;
-    }
-    GST_DEBUG ("scaling to %dx%d", bvw->video_width_pixels,
-        bvw->video_height_pixels);
-
-    *width = bvw->video_width_pixels;
-    *height = bvw->video_height_pixels;
-
-    /* Free the PAR fraction */
-    g_value_unset (&disp_par);
-  }
-  else {
-    if (bvw->logo_pixbuf) {
-      *width = gdk_pixbuf_get_width (bvw->logo_pixbuf);
-      *height = gdk_pixbuf_get_height (bvw->logo_pixbuf);
-      if (*width == *height) {
-       /* The icons will be square, so lie so we get a 16:9
-        * ratio */
-       *width = (int) ((float) *height / 9. * 16.);
-      }
-    } else {
-      *width = 0;
-      *height = 0;
-    }
-  }
-}
-
-static gboolean
-leave_notify_cb (GtkWidget        *widget,
-                GdkEventCrossing *event,
-                gpointer          user_data)
-{
-  gboolean res = GDK_EVENT_PROPAGATE;
-  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (user_data);
-  GdkDevice *device;
-
-  if (event->detail != GDK_NOTIFY_NONLINEAR &&
-      event->detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
-    return res;
-
-  device = gdk_event_get_source_device ((GdkEvent *) event);
-  if (gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN)
-    return res;
-
-  if (bvw->reveal_controls) {
-    gboolean not_busy;
-
-    not_busy = g_hash_table_size (bvw->busy_popup_ht) == 0;
-    if (not_busy) {
-      GST_DEBUG ("will hide because we're not busy and cursor left");
-      set_controls_visibility (bvw, FALSE, TRUE);
-    }
-  }
-
-  return res;
-}
-
-static void
-bvw_set_logo (BaconVideoWidget *bvw, const gchar *name)
-{
-  GtkIconTheme *theme;
-  GError *error = NULL;
-
-  theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (bvw)));
-  bvw->logo_pixbuf = gtk_icon_theme_load_icon (theme, name, LOGO_SIZE, 0, &error);
-
-  if (error) {
-    g_warning ("An error occurred trying to open logo %s: %s", name, error->message);
-    g_error_free (error);
-    return;
-  }
-}
-
 static void
 bacon_video_widget_realize (GtkWidget * widget)
 {
   BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
-  GtkWidget *toplevel;
 
   GTK_WIDGET_CLASS (parent_class)->realize (widget);
 
-  gtk_widget_set_realized (widget, TRUE);
-
-  bvw_set_logo (bvw, APPLICATION_ID);
-
-  /* setup the toplevel, ready to be resized */
-  toplevel = gtk_widget_get_toplevel (widget);
-  gtk_window_set_geometry_hints (GTK_WINDOW (toplevel), widget, NULL, 0);
-  g_signal_connect (G_OBJECT (toplevel), "leave-notify-event",
-                   G_CALLBACK (leave_notify_cb), bvw);
-
   bvw->missing_plugins_cancellable = g_cancellable_new ();
   g_object_set_data_full (G_OBJECT (bvw), "missing-plugins-cancellable",
                          bvw->missing_plugins_cancellable, g_object_unref);
@@ -648,16 +388,9 @@ static void
 bacon_video_widget_unrealize (GtkWidget *widget)
 {
   BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
-  GtkWidget *toplevel;
 
   GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
 
-  gtk_widget_set_realized (widget, FALSE);
-
-  toplevel = gtk_widget_get_toplevel (widget);
-  g_signal_handlers_disconnect_by_func (G_OBJECT (toplevel),
-                                       leave_notify_cb, bvw);
-
   g_cancellable_cancel (bvw->missing_plugins_cancellable);
   bvw->missing_plugins_cancellable = NULL;
   g_object_set_data (G_OBJECT (bvw), "missing-plugins-cancellable", NULL);
@@ -668,119 +401,10 @@ set_current_actor (BaconVideoWidget *bvw)
 {
   gboolean draw_logo;
 
-  if (bvw->stage == NULL)
-    return;
-
-  /* If there's only audio draw the logo as well. */
+  /* If there's only audio draw the logo */
   draw_logo = bvw->media_has_audio && !bvw->media_has_video;
-
-  if (draw_logo) {
-    if (bvw->logo_pixbuf != NULL) {
-      gboolean ret;
-      GError *err = NULL;
-
-      ret = clutter_image_set_data (CLUTTER_IMAGE (bvw->logo),
-                                   gdk_pixbuf_get_pixels (bvw->logo_pixbuf),
-                                   gdk_pixbuf_get_has_alpha (bvw->logo_pixbuf) ? COGL_PIXEL_FORMAT_RGBA_8888 
: COGL_PIXEL_FORMAT_RGB_888,
-                                   gdk_pixbuf_get_width (bvw->logo_pixbuf),
-                                   gdk_pixbuf_get_height (bvw->logo_pixbuf),
-                                   gdk_pixbuf_get_rowstride (bvw->logo_pixbuf),
-                                   &err);
-      if (ret == FALSE) {
-       g_warning ("clutter_image_set_data() failed %s", err->message);
-       g_error_free (err);
-      } else {
-       clutter_actor_show (CLUTTER_ACTOR (bvw->logo_frame));
-       clutter_actor_hide (CLUTTER_ACTOR (bvw->frame));
-       return;
-      }
-    }
-  }
-
-  clutter_actor_show (CLUTTER_ACTOR (bvw->frame));
-  clutter_actor_hide (CLUTTER_ACTOR (bvw->logo_frame));
-}
-
-static void
-unschedule_hiding_popup (BaconVideoWidget *bvw)
-{
-  if (bvw->transition_timeout_id > 0)
-    g_source_remove (bvw->transition_timeout_id);
-  bvw->transition_timeout_id = 0;
-}
-
-static gboolean
-hide_popup_timeout_cb (BaconVideoWidget *bvw)
-{
-  set_controls_visibility (bvw, FALSE, TRUE);
-  unschedule_hiding_popup (bvw);
-  return G_SOURCE_REMOVE;
-}
-
-static void
-schedule_hiding_popup (BaconVideoWidget *bvw)
-{
-  unschedule_hiding_popup (bvw);
-  bvw->transition_timeout_id = g_timeout_add_seconds (POPUP_HIDING_TIMEOUT, (GSourceFunc) 
hide_popup_timeout_cb, bvw);
-  g_source_set_name_by_id (bvw->transition_timeout_id, "[totem] hide_popup_timeout_cb");
-}
-
-static void
-set_show_cursor (BaconVideoWidget *bvw,
-                gboolean show_cursor)
-{
-  GdkWindow *window;
-
-  bvw->cursor_shown = show_cursor;
-  window = gtk_widget_get_window (GTK_WIDGET (bvw));
-
-  if (!window)
-    return;
-
-  if (show_cursor == FALSE) {
-    GdkCursor *cursor;
-    GdkDisplay *display;
-
-    display = gdk_window_get_display (window);
-    cursor = gdk_cursor_new_for_display (display, GDK_BLANK_CURSOR);
-    gdk_window_set_cursor (window, cursor);
-    g_object_unref (cursor);
-  } else {
-    gdk_window_set_cursor (window, bvw->cursor);
-  }
-}
-
-static void
-set_controls_visibility (BaconVideoWidget *bvw,
-                        gboolean          visible,
-                        gboolean          animate)
-{
-  guint8 opacity = visible ? OVERLAY_OPACITY : 0;
-  gint header_controls_height;
-  gfloat header_controls_y;
-  guint duration;
-
-  gtk_widget_get_preferred_height (gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (bvw->header_controls)),
-                                   NULL,
-                                   &header_controls_height);
-  header_controls_y = visible ? 0 : -header_controls_height;
-
-  duration = animate ? 250 : 0;
-
-  /* FIXME:
-   * Using a show/hide seems to not trigger the
-   * controls to redraw, so let's change the opacity instead */
-  clutter_actor_set_easing_duration (bvw->controls, duration);
-  clutter_actor_set_easing_duration (bvw->header_controls, duration);
-  clutter_actor_set_opacity (bvw->controls, opacity);
-  clutter_actor_set_y (bvw->header_controls, header_controls_y);
-
-  set_show_cursor (bvw, visible);
-  if (visible && animate)
-    schedule_hiding_popup (bvw);
-
-  bvw->reveal_controls = visible;
-  g_object_notify (G_OBJECT (bvw), "reveal-controls");
+  gtk_stack_set_visible_child_name (GTK_STACK (bvw->stack),
+                                   draw_logo ? "logo" : "video");
 }
 
 static void
@@ -802,22 +426,6 @@ translate_coords (GtkWidget   *widget,
   }
 }
 
-static gboolean
-ignore_event (BaconVideoWidget *bvw,
-             int               x,
-             int               y)
-{
-  ClutterActor *actor;
-
-  actor = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (bvw->stage), CLUTTER_PICK_REACTIVE, x, y);
-
-  /* Eat the GTK+ event if we're not clicking on the video itself */
-  if (actor == bvw->controls)
-    return TRUE;
-
-  return FALSE;
-}
-
 /* 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 */
@@ -827,8 +435,6 @@ bacon_video_widget_motion_notify (GtkWidget *widget, GdkEventMotion *event)
 {
   gboolean res = GDK_EVENT_PROPAGATE;
   BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
-  GdkDevice *device;
-  int x, y;
 
   g_return_val_if_fail (bvw->play != NULL, FALSE);
 
@@ -838,21 +444,6 @@ bacon_video_widget_motion_notify (GtkWidget *widget, GdkEventMotion *event)
   if (GTK_WIDGET_CLASS (parent_class)->motion_notify_event)
     res |= GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event);
 
-  device = gdk_event_get_source_device ((GdkEvent *) event);
-  if (gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN)
-    return res;
-
-  if (!bvw->reveal_controls)
-    set_controls_visibility (bvw, TRUE, TRUE);
-
-  translate_coords (widget, event->window, event->x, event->y, &x, &y);
-  if (ignore_event (bvw, x, y)) {
-    /* Is the mouse on the popups? */
-    unschedule_hiding_popup (bvw);
-  } else {
-    schedule_hiding_popup (bvw);
-  }
-
   return res;
 }
 
@@ -861,7 +452,6 @@ bacon_video_widget_button_press_or_release (GtkWidget *widget, GdkEventButton *e
 {
   gboolean res = FALSE;
   BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
-  int x, y;
   GdkDevice *device;
 
   device = gdk_event_get_source_device ((GdkEvent *) event);
@@ -870,10 +460,6 @@ bacon_video_widget_button_press_or_release (GtkWidget *widget, GdkEventButton *e
 
   g_return_val_if_fail (bvw->play != NULL, FALSE);
 
-  translate_coords (widget, event->window, event->x, event->y, &x, &y);
-  if (ignore_event (bvw, x, y))
-    return GDK_EVENT_STOP;
-
   if (event->type != GDK_BUTTON_PRESS &&
       event->type != GDK_BUTTON_RELEASE)
     goto bail;
@@ -881,8 +467,10 @@ bacon_video_widget_button_press_or_release (GtkWidget *widget, GdkEventButton *e
   if (bvw->navigation &&
       event->button == 1 &&
       bvw->is_menu != FALSE) {
+    int x, y;
     const char *event_str;
     event_str = (event->type == GDK_BUTTON_PRESS) ? "mouse-button-press" : "mouse-button-release";
+    translate_coords (widget, event->window, event->x, event->y, &x, &y);
     gst_navigation_send_mouse_event (bvw->navigation,
                                     event_str, event->button, x, y);
 
@@ -900,49 +488,6 @@ bail:
   return res;
 }
 
-static gboolean
-bacon_video_widget_handle_scroll (GtkWidget        *widget,
-                                 GdkEventScroll   *event,
-                                 BaconVideoWidget *bvw)
-{
-  int x, y;
-  gboolean forward;
-  gdouble delta_y;
-
-  g_return_val_if_fail (bvw->play != NULL, FALSE);
-
-  if (event->direction != GDK_SCROLL_SMOOTH)
-    return GDK_EVENT_PROPAGATE;
-
-  if (widget == (gpointer) bvw) {
-    translate_coords (widget, event->window, event->x, event->y, &x, &y);
-    if (ignore_event (bvw, x, y))
-      return GDK_EVENT_STOP;
-  }
-
-  gdk_event_get_scroll_deltas ((GdkEvent *) event, NULL, &delta_y);
-  if (delta_y == 0.0)
-    return GDK_EVENT_PROPAGATE;
-  forward = delta_y >= 0.0 ? FALSE : TRUE;
-
-  if (widget == (gpointer) bvw ||
-      widget == g_object_get_data (G_OBJECT (bvw->controls), "seek_scale")) {
-    if (bvw->seekable > 0)
-      g_signal_emit (G_OBJECT (bvw), bvw_signals[SIGNAL_SEEK_REQUESTED], 0, forward);
-  } else if (widget == g_object_get_data (G_OBJECT (bvw->controls), "volume_button")) {
-    if (bacon_video_widget_can_set_volume (bvw))
-      g_signal_emit (G_OBJECT (bvw), bvw_signals[SIGNAL_VOLUME_CHANGE_REQUESTED], 0, forward);
-  }
-
-  return GDK_EVENT_STOP;
-}
-
-static gboolean
-bacon_video_widget_scroll (GtkWidget *widget, GdkEventScroll *event)
-{
-  return bacon_video_widget_handle_scroll (widget, event, BACON_VIDEO_WIDGET (widget));
-}
-
 static void
 bacon_video_widget_get_preferred_width (GtkWidget *widget,
                                         gint      *minimum,
@@ -980,8 +525,6 @@ bacon_video_widget_class_init (BaconVideoWidgetClass * klass)
   GObjectClass *object_class;
   GtkWidgetClass *widget_class;
 
-  clutter_gst_init (NULL, NULL);
-
   object_class = (GObjectClass *) klass;
   widget_class = (GtkWidgetClass *) klass;
 
@@ -996,7 +539,6 @@ bacon_video_widget_class_init (BaconVideoWidgetClass * klass)
   widget_class->motion_notify_event = bacon_video_widget_motion_notify;
   widget_class->button_press_event = bacon_video_widget_button_press_or_release;
   widget_class->button_release_event = bacon_video_widget_button_press_or_release;
-  widget_class->scroll_event = bacon_video_widget_scroll;
 
   /* GObject */
   object_class->set_property = bacon_video_widget_set_property;
@@ -1174,14 +716,14 @@ bacon_video_widget_class_init (BaconVideoWidgetClass * klass)
                                                       G_PARAM_STATIC_STRINGS));
 
   /**
-   * BaconVideoWidget:reveal-controls:
+   * BaconVideoWidget:show-cursor:
    *
-   * Whether to show or hide the controls.
+   * Whether the mouse cursor is shown.
    **/
-  g_object_class_install_property (object_class, PROP_REVEAL_CONTROLS,
-                                   g_param_spec_boolean ("reveal-controls", "Reveal controls",
-                                                         "Whether to show or hide the controls.", FALSE,
-                                                         G_PARAM_READABLE |
+  g_object_class_install_property (object_class, PROP_SHOW_CURSOR,
+                                   g_param_spec_boolean ("show-cursor", "Show cursor",
+                                                         "Whether the mouse cursor is shown.", FALSE,
+                                                         G_PARAM_READWRITE |
                                                          G_PARAM_STATIC_STRINGS));
 
   /* Signals */
@@ -1384,6 +926,25 @@ bacon_video_widget_class_init (BaconVideoWidgetClass * klass)
                   0,
                   NULL, NULL,
                   g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+  /**
+   * BaconVideoWidget::play-starting:
+   * @bvw: the #BaconVideoWidget which received the signal
+   *
+   * Emitted when a movie will start playing, meaning it's not buffering, or paused
+   *  waiting for plugins to be installed, drives to be mounted or authentication
+   *  to succeed.
+   *
+   * This usually means that OSD popups can be hidden.
+   *
+   **/
+  bvw_signals[SIGNAL_PLAY_STARTING] =
+    g_signal_new ("play-starting",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
 }
 
 static void
@@ -1395,14 +956,11 @@ bacon_video_widget_init (BaconVideoWidget * bvw)
   g_type_class_ref (BVW_TYPE_DVD_EVENT);
   g_type_class_ref (BVW_TYPE_ROTATION);
 
-  g_object_set (G_OBJECT (bvw), "use-layout-size", TRUE, NULL);
-
   bvw->update_id = 0;
   bvw->tagcache = NULL;
   bvw->audiotags = NULL;
   bvw->videotags = NULL;
   bvw->volume = -1.0;
-  bvw->movie_par_n = bvw->movie_par_d = 1;
   bvw->rate = FORWARD_RATE;
 
   bvw->tag_update_queue = g_async_queue_new_full ((GDestroyNotify) update_tags_delayed_data_destroy);
@@ -1421,8 +979,6 @@ bacon_video_widget_init (BaconVideoWidget * bvw)
   bvw->auth_last_result = G_MOUNT_OPERATION_HANDLED;
   bvw->auth_dialog = NULL;
 
-  bvw->busy_popup_ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-
   bacon_video_widget_gst_missing_plugins_block ();
 }
 
@@ -1455,15 +1011,7 @@ bvw_handle_application_message (BaconVideoWidget *bvw, GstMessage *msg)
     bvw_update_stream_info (bvw);
   }
   else if (strcmp (msg_name, "video-size") == 0) {
-    int w, h;
-
     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. */
-    get_media_size (bvw, &w, &h);
-    clutter_actor_set_size (bvw->texture, w, h);
-
     set_current_actor (bvw);
   } else {
     g_debug ("Unhandled application message %s", msg_name);
@@ -1600,7 +1148,7 @@ bvw_handle_element_message (BaconVideoWidget *bvw, GstMessage *msg)
     val = gst_structure_get_value (structure, "file");
     if (val == NULL)
       goto done;
-      
+
     file = G_FILE (g_value_get_object (val));
     if (file == NULL)
       goto done;
@@ -1976,37 +1524,6 @@ bvw_check_missing_plugins_on_preroll (BaconVideoWidget * bvw)
   return bvw_emit_missing_plugins_signal (bvw, TRUE); 
 }
 
-static void
-update_orientation_from_video (BaconVideoWidget *bvw)
-{
-  BvwRotation rotation = BVW_ROTATION_R_ZERO;
-  char *orientation_str = NULL;
-  gboolean ret;
-  gdouble angle;
-
-  /* Don't change the rotation if explicitely set */
-  if (bvw->rotation != BVW_ROTATION_R_ZERO)
-    return;
-
-  ret = gst_tag_list_get_string_index (bvw->tagcache,
-                                      GST_TAG_IMAGE_ORIENTATION, 0, &orientation_str);
-  if (!ret || !orientation_str || g_str_equal (orientation_str, "rotate-0"))
-    rotation = BVW_ROTATION_R_ZERO;
-  else if (g_str_equal (orientation_str, "rotate-90"))
-    rotation = BVW_ROTATION_R_90R;
-  else if (g_str_equal (orientation_str, "rotate-180"))
-    rotation = BVW_ROTATION_R_180;
-  else if (g_str_equal (orientation_str, "rotate-270"))
-    rotation = BVW_ROTATION_R_90L;
-  else
-    g_warning ("Unhandled orientation value: '%s'", orientation_str);
-
-  g_free (orientation_str);
-
-  angle = rotation * 90.0;
-  totem_aspect_frame_set_rotation (TOTEM_ASPECT_FRAME (bvw->frame), angle);
-}
-
 static void
 bvw_update_tags (BaconVideoWidget * bvw, GstTagList *tag_list, const gchar *type)
 {
@@ -2048,8 +1565,6 @@ bvw_update_tags (BaconVideoWidget * bvw, GstTagList *tag_list, const gchar *type
 
   g_signal_emit (bvw, bvw_signals[SIGNAL_GOT_METADATA], 0);
 
-  update_orientation_from_video (bvw);
-
   set_current_actor (bvw);
 }
 
@@ -2214,15 +1729,6 @@ bvw_handle_buffering_message (GstMessage * message, BaconVideoWidget *bvw)
   gst_message_parse_buffering (message, &percent);
   g_signal_emit (bvw, bvw_signals[SIGNAL_BUFFERING], 0, (gdouble) percent / 100.0);
 
-  if (percent >= 100) {
-    clutter_actor_hide (bvw->spinner);
-    /* Reset */
-    g_object_set (G_OBJECT (bvw->spinner), "percent", 0.0, NULL);
-  } else {
-    clutter_actor_show (bvw->spinner);
-    g_object_set (G_OBJECT (bvw->spinner), "percent", (float) percent, NULL);
-  }
-
   if (percent >= 100) {
     /* a 100% message means buffering is done */
     bvw->buffering = FALSE;
@@ -2833,29 +2339,12 @@ caps_set (GObject * obj,
   /* Get video decoder caps */
   s = gst_caps_get_structure (caps, 0);
   if (s) {
-    const GValue *movie_par;
-
     /* We need at least width/height and framerate */
-    if (!(gst_structure_get_fraction (s, "framerate", &bvw->video_fps_n, 
+    if (!(gst_structure_get_fraction (s, "framerate", &bvw->video_fps_n,
           &bvw->video_fps_d) &&
           gst_structure_get_int (s, "width", &bvw->video_width) &&
           gst_structure_get_int (s, "height", &bvw->video_height)))
       return;
-    
-    /* Get the movie PAR if available */
-    movie_par = gst_structure_get_value (s, "pixel-aspect-ratio");
-    if (movie_par) {
-      bvw->movie_par_n = gst_value_get_fraction_numerator (movie_par);
-      bvw->movie_par_d = gst_value_get_fraction_denominator (movie_par);
-    }
-    else {
-      /* Square pixels */
-      bvw->movie_par_n = 1;
-      bvw->movie_par_d = 1;
-    }
-    
-    /* Now set for real */
-    bacon_video_widget_set_aspect_ratio (bvw, bvw->ratio_type);
   }
 
   gst_caps_unref (caps);
@@ -2921,8 +2410,6 @@ bacon_video_widget_finalize (GObject * object)
   g_type_class_unref (g_type_class_peek (BVW_TYPE_DVD_EVENT));
   g_type_class_unref (g_type_class_peek (BVW_TYPE_ROTATION));
 
-  unschedule_hiding_popup (bvw);
-
   if (bvw->bus) {
     /* make bus drop all messages to make sure none of our callbacks is ever
      * called again (main loop might be run again to display error dialog) */
@@ -2938,7 +2425,6 @@ bacon_video_widget_finalize (GObject * object)
   g_clear_pointer (&bvw->referrer, g_free);
   g_clear_pointer (&bvw->mrl, g_free);
   g_clear_pointer (&bvw->subtitle_uri, g_free);
-  g_clear_pointer (&bvw->busy_popup_ht, g_hash_table_destroy);
 
   g_clear_object (&bvw->clock);
 
@@ -3020,6 +2506,9 @@ bacon_video_widget_set_property (GObject * object, guint property_id,
     case PROP_AV_OFFSET:
       g_object_set_property (G_OBJECT (bvw->play), "av-offset", value);
       break;
+    case PROP_SHOW_CURSOR:
+      bacon_video_widget_set_show_cursor (bvw, g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -3080,8 +2569,8 @@ bacon_video_widget_get_property (GObject * object, guint property_id,
     case PROP_AV_OFFSET:
       g_object_get_property (G_OBJECT (bvw->play), "av-offset", value);
       break;
-    case PROP_REVEAL_CONTROLS:
-      g_value_set_boolean (value, bvw->reveal_controls);
+    case PROP_SHOW_CURSOR:
+      g_value_set_boolean (value, bvw->cursor_shown);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -3678,113 +3167,6 @@ bacon_video_widget_set_audio_output_type (BaconVideoWidget *bvw,
   set_audio_filter (bvw);
 }
 
-/**
- * bacon_video_widget_show_popup:
- * @bvw: a #BaconVideoWidget
- *
- * Show the video controls popup, and schedule for it to be hidden again after
- * a timeout.
- *
- * Since: 3.12
- */
-void
-bacon_video_widget_show_popup (BaconVideoWidget *bvw)
-{
-  g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
-
-  set_controls_visibility (bvw, TRUE, FALSE);
-  schedule_hiding_popup (bvw);
-}
-
-/**
- * bacon_video_widget_mark_popup_busy:
- * @bvw: a #BaconVideoWidget
- * @reason: human-readable reason for the controls popup being marked as busy
- *
- * Mark the video controls popup as busy, for the given @reason. Use
- * bacon_video_widget_unmark_popup_busy() to undo.
- *
- * Since: 3.12
- */
-void
-bacon_video_widget_mark_popup_busy (BaconVideoWidget *bvw,
-                                   const char       *reason)
-{
-  g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
-
-  g_hash_table_insert (bvw->busy_popup_ht,
-                      g_strdup (reason),
-                      GINT_TO_POINTER (1));
-
-  set_controls_visibility (bvw, TRUE, FALSE);
-
-  GST_DEBUG ("Adding popup busy for reason %s", reason);
-
-  unschedule_hiding_popup (bvw);
-}
-
-/**
- * bacon_video_widget_unmark_popup_busy:
- * @bvw: a #BaconVideoWidget
- * @reason: human-readable reason for the controls popup being unmarked as busy
- *
- * Unmark the video controls popup as busy, for the given @reason. The popup
- * must previously have been marked as busy using
- * bacon_video_widget_mark_popup_busy().
- *
- * Since: 3.12
- */
-void
-bacon_video_widget_unmark_popup_busy (BaconVideoWidget *bvw,
-                                     const char       *reason)
-{
-  g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
-
-  g_hash_table_remove (bvw->busy_popup_ht, reason);
-
-  GST_DEBUG ("Removing popup busy for reason %s", reason);
-
-  if (g_hash_table_size (bvw->busy_popup_ht) == 0 &&
-      clutter_actor_get_opacity (bvw->controls) != 0) {
-    GST_DEBUG ("Will hide popup soon");
-    schedule_hiding_popup (bvw);
-  }
-}
-
-/**
- * bacon_video_widget_get_controls_object:
- * @bvw: a #BaconVideoWidget
- *
- * Get the widget which displays the video controls.
- *
- * Returns: (transfer none): controls widget
- * Since: 3.12
- */
-GObject *
-bacon_video_widget_get_controls_object (BaconVideoWidget *bvw)
-{
-  g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), NULL);
-
-  return G_OBJECT (bvw->controls);
-}
-
-/**
- * bacon_video_widget_get_header_controls_object:
- * @bvw: a #BaconVideoWidget
- *
- * Get the widget which displays the video header controls.
- *
- * Returns: (transfer none): header controls widget
- * Since: 3.20
- */
-GObject *
-bacon_video_widget_get_header_controls_object (BaconVideoWidget *bvw)
-{
-  g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), NULL);
-
-  return G_OBJECT (gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (bvw->header_controls)));
-}
-
 /* =========================================== */
 /*                                             */
 /*               Play/Pause, Stop              */
@@ -4059,8 +3441,6 @@ bacon_video_widget_open (BaconVideoWidget *bvw,
   bvw->target_state = GST_STATE_PAUSED;
   bvw_clear_missing_plugins_messages (bvw);
 
-  bacon_video_widget_mark_popup_busy (bvw, "opening file");
-
   gst_element_set_state (bvw->play, GST_STATE_PAUSED);
 
   g_signal_emit (bvw, bvw_signals[SIGNAL_CHANNELS_CHANGE], 0);
@@ -4125,7 +3505,7 @@ bacon_video_widget_play (BaconVideoWidget * bvw, GError ** error)
     return FALSE;
   }
 
-  bacon_video_widget_unmark_popup_busy (bvw, "opening file");
+  g_signal_emit (bvw, bvw_signals[SIGNAL_PLAY_STARTING], 0);
 
   GST_DEBUG ("play");
   gst_element_set_state (bvw->play, GST_STATE_PLAYING);
@@ -4334,10 +3714,10 @@ bvw_stop_play_pipeline (BaconVideoWidget * bvw)
   g_clear_pointer (&bvw->download_filename, g_free);
   bvw->buffering_left = -1;
   bvw_reconfigure_fill_timeout (bvw, 0);
-  bvw->movie_par_n = bvw->movie_par_d = 1;
-  clutter_actor_hide (bvw->spinner);
-  g_object_set (G_OBJECT (bvw->spinner), "percent", 0.0, NULL);
-  totem_aspect_frame_set_internal_rotation (TOTEM_ASPECT_FRAME (bvw->frame), 0.0);
+  g_signal_emit (bvw, bvw_signals[SIGNAL_BUFFERING], 0, 100.0);
+  g_object_set (bvw->video_sink,
+                "rotate-method", GST_VIDEO_ORIENTATION_AUTO,
+                NULL);
   GST_DEBUG ("stopped");
 }
 
@@ -4799,6 +4179,43 @@ bacon_video_widget_get_volume (BaconVideoWidget * bvw)
   return bvw->volume;
 }
 
+/**
+ * bacon_video_widget_set_show_cursor:
+ * @bvw: a #BaconVideoWidget
+ * @show_cursor: %TRUE to show the cursor, %FALSE otherwise
+ *
+ * Sets whether the cursor should be shown when it is over the video
+ * widget. If @show_cursor is %FALSE, the cursor will be invisible
+ * when it is moved over the video widget.
+ **/
+void
+bacon_video_widget_set_show_cursor (BaconVideoWidget * bvw,
+                                    gboolean show_cursor)
+{
+  GdkWindow *window;
+
+  g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
+
+
+  bvw->cursor_shown = show_cursor;
+  window = gtk_widget_get_window (GTK_WIDGET (bvw));
+
+  if (!window)
+    return;
+
+  if (show_cursor == FALSE) {
+    GdkCursor *cursor;
+    GdkDisplay *display;
+
+    display = gdk_window_get_display (window);
+    cursor = gdk_cursor_new_for_display (display, GDK_BLANK_CURSOR);
+    gdk_window_set_cursor (window, cursor);
+    g_object_unref (cursor);
+  } else {
+    gdk_window_set_cursor (window, bvw->cursor);
+  }
+}
+
 /**
  * bacon_video_widget_set_aspect_ratio:
  * @bvw: a #BaconVideoWidget
@@ -4810,18 +4227,41 @@ bacon_video_widget_get_volume (BaconVideoWidget * bvw)
  **/
 void
 bacon_video_widget_set_aspect_ratio (BaconVideoWidget *bvw,
-                                BvwAspectRatio ratio)
+                                     BvwAspectRatio ratio)
 {
-  GstMessage *msg;
-
   g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
 
   bvw->ratio_type = ratio;
-  msg = gst_message_new_application (GST_OBJECT (bvw->play),
-      gst_structure_new ("video-size", "width", G_TYPE_INT,
-          bvw->video_width, "height", G_TYPE_INT,
-          bvw->video_height, NULL));
-  gst_element_post_message (bvw->play, msg);
+
+  switch (bvw->ratio_type) {
+  case BVW_RATIO_SQUARE:
+    g_object_set (bvw->video_sink,
+                 "video-aspect-ratio-override", 1, 1,
+                 NULL);
+    break;
+  case BVW_RATIO_FOURBYTHREE:
+    g_object_set (bvw->video_sink,
+                 "video-aspect-ratio-override", 4, 3,
+                 NULL);
+    break;
+  case BVW_RATIO_ANAMORPHIC:
+    g_object_set (bvw->video_sink,
+                 "video-aspect-ratio-override", 16, 9,
+                 NULL);
+    break;
+  case BVW_RATIO_DVB:
+    g_object_set (bvw->video_sink,
+                 "video-aspect-ratio-override", 20, 9,
+                 NULL);
+    break;
+    /* handle these to avoid compiler warnings */
+  case BVW_RATIO_AUTO:
+  default:
+    g_object_set (bvw->video_sink,
+                 "video-aspect-ratio-override", 0, 1,
+                 NULL);
+    break;
+  }
 }
 
 /**
@@ -4854,11 +4294,7 @@ bacon_video_widget_set_zoom (BaconVideoWidget *bvw,
 {
   g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
 
-  if (bvw->frame == NULL)
-    return;
-
-  totem_aspect_frame_set_expand (TOTEM_ASPECT_FRAME (bvw->frame),
-                             (mode == BVW_ZOOM_EXPAND));
+  g_debug ("%s not implemented", G_STRFUNC);
 }
 
 /**
@@ -4872,12 +4308,10 @@ bacon_video_widget_set_zoom (BaconVideoWidget *bvw,
 BvwZoomMode
 bacon_video_widget_get_zoom (BaconVideoWidget *bvw)
 {
-  gboolean expand;
+  g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), BVW_ZOOM_NONE);
 
-  g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 1.0);
-
-  expand = totem_aspect_frame_get_expand (TOTEM_ASPECT_FRAME (bvw->frame));
-  return expand ? BVW_ZOOM_EXPAND : BVW_ZOOM_NONE;
+  g_debug ("%s not implemented", G_STRFUNC);
+  return BVW_ZOOM_NONE;
 }
 
 /**
@@ -4891,22 +4325,15 @@ void
 bacon_video_widget_set_rotation (BaconVideoWidget *bvw,
                                 BvwRotation       rotation)
 {
-  gfloat angle;
-
   g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
 
-  if (bvw->frame == NULL)
-    return;
-
   GST_DEBUG ("Rotating to %s (%f degrees) from %s",
             g_enum_to_string (BVW_TYPE_ROTATION, rotation),
             rotation * 90.0,
             g_enum_to_string (BVW_TYPE_ROTATION, bvw->rotation));
 
   bvw->rotation = rotation;
-
-  angle = rotation * 90.0;
-  totem_aspect_frame_set_rotation (TOTEM_ASPECT_FRAME (bvw->frame), angle);
+  g_object_set (bvw->video_sink, "rotate-method", rotation, NULL);
 }
 
 /**
@@ -5867,59 +5294,6 @@ bvw_set_playback_direction (BaconVideoWidget *bvw, gboolean forward)
   return retval;
 }
 
-static gboolean
-navigation_event (ClutterActor *actor,
-                  ClutterEvent *event,
-                  BaconVideoWidget *bvw)
-{
-  ClutterGstFrame *frame =
-    clutter_gst_video_sink_get_frame (CLUTTER_GST_VIDEO_SINK (bvw->video_sink));
-  gfloat actor_width, actor_height;
-  gfloat x, y;
-
-  if (frame == NULL)
-    return CLUTTER_EVENT_PROPAGATE;
-
-  /* Get event coordinates into the actor's coordinates. */
-  clutter_event_get_coords (event, &x, &y);
-  clutter_actor_transform_stage_point (actor, x, y, &x, &y);
-
-  clutter_actor_get_size (actor, &actor_width, &actor_height);
-
-  /* Convert event's coordinates into the frame's coordinates. */
-  x = x * frame->resolution.width / actor_width;
-  y = y * frame->resolution.height / actor_height;
-
-  if (event->type == CLUTTER_MOTION) {
-    gst_navigation_send_mouse_event (GST_NAVIGATION (bvw->video_sink),
-                                     "mouse-move", 0, x, y);
-  } else if (event->type == CLUTTER_BUTTON_PRESS ||
-             event->type == CLUTTER_BUTTON_RELEASE) {
-    ClutterButtonEvent *bevent = (ClutterButtonEvent *) event;
-    const char *type = (event->type == CLUTTER_BUTTON_PRESS) ?
-      "mouse-button-press" : "mouse-button-release";
-    gst_navigation_send_mouse_event (GST_NAVIGATION (bvw->video_sink), type,
-                                     bevent->button, x, y);
-  }
-
-  return CLUTTER_EVENT_PROPAGATE;
-}
-
-static void
-listen_navigation_events (ClutterActor *actor,
-                          BaconVideoWidget *bvw)
-{
-  const char * const events[] = {
-    "button-press-event",
-    "button-release-event",
-    "motion-event"
-  };
-  guint i;
-
-  for (i = 0; i < G_N_ELEMENTS (events); i++)
-    g_signal_connect (actor, events[i], G_CALLBACK (navigation_event), bvw);
-}
-
 static GstElement *
 element_make_or_warn (const char *plugin,
                      const char *name)
@@ -5940,10 +5314,9 @@ bacon_video_widget_initable_init (GInitable     *initable,
   GstElement *audio_sink = NULL;
   gchar *version_str;
   GstPlayFlags flags;
-  ClutterActor *layout;
-  GstElement *audio_bin;
+  GtkWidget *tmp;
+  GstElement *glsinkbin, *audio_bin;
   GstPad *audio_pad;
-  GObject *item;
   char *template;
 
   bvw = BACON_VIDEO_WIDGET (initable);
@@ -5961,10 +5334,20 @@ bacon_video_widget_initable_init (GInitable     *initable,
 
   gst_pb_utils_init ();
 
+  gtk_widget_set_events (GTK_WIDGET (bvw),
+                        gtk_widget_get_events (GTK_WIDGET (bvw)) |
+                        GDK_SCROLL_MASK |
+                        GDK_POINTER_MOTION_MASK |
+                        GDK_BUTTON_MOTION_MASK |
+                        GDK_BUTTON_PRESS_MASK |
+                        GDK_BUTTON_RELEASE_MASK |
+                        GDK_KEY_PRESS_MASK);
+
   /* Instantiate all the fallible plugins */
   bvw->play = element_make_or_warn ("playbin", "play");
   bvw->audio_pitchcontrol = element_make_or_warn ("scaletempo", "scaletempo");
-  bvw->video_sink = GST_ELEMENT (clutter_gst_video_sink_new ());
+  bvw->video_sink = element_make_or_warn ("gtkglsink", "video-sink");
+  glsinkbin = element_make_or_warn ("glsinkbin", "glsinkbin");
   audio_sink = element_make_or_warn ("autoaudiosink", "audio-sink");
 
   if (!bvw->play ||
@@ -6006,93 +5389,28 @@ bacon_video_widget_initable_init (GInitable     *initable,
 
   bvw->cursor_shown = TRUE;
 
-  bvw->stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (bvw));
-  clutter_actor_set_text_direction (bvw->stage,
-                                   CLUTTER_TEXT_DIRECTION_LTR);
-  clutter_actor_set_layout_manager (bvw->stage,
-                                    clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_FILL, 
CLUTTER_BIN_ALIGNMENT_FILL));
-  clutter_actor_set_name (bvw->stage, "stage");
-  clutter_actor_set_background_color (bvw->stage, CLUTTER_COLOR_Black);
-
-  /* Video sink, with aspect frame */
-  bvw->texture = g_object_new (CLUTTER_TYPE_ACTOR,
-                                     "content", g_object_new (CLUTTER_GST_TYPE_CONTENT,
-                                                              "sink", bvw->video_sink,
-                                                              NULL),
-                                    "name", "texture",
-                                    "reactive", TRUE,
-                                    NULL);
-  listen_navigation_events (bvw->texture, bvw);
-
-  /* The logo */
-  bvw->logo_frame = clutter_actor_new ();
-  clutter_actor_set_name (bvw->logo_frame, "logo-frame");
-  bvw->logo = clutter_image_new ();
-  clutter_actor_set_content (bvw->logo_frame, bvw->logo);
-  clutter_actor_set_content_gravity (bvw->logo_frame, CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT);
-  clutter_actor_add_child (bvw->stage, bvw->logo_frame);
-  clutter_actor_hide (CLUTTER_ACTOR (bvw->logo_frame));
-
-  /* The video */
-  bvw->frame = totem_aspect_frame_new ();
-  clutter_actor_set_name (bvw->frame, "frame");
-  totem_aspect_frame_set_child (TOTEM_ASPECT_FRAME (bvw->frame), bvw->texture);
-
-  clutter_actor_add_child (bvw->stage, bvw->frame);
-
-  clutter_actor_set_child_above_sibling (bvw->stage,
-                                        bvw->logo_frame,
-                                        bvw->frame);
-
-  /* The spinner */
-  bvw->spinner = bacon_video_spinner_actor_new ();
-  clutter_actor_set_name (bvw->spinner, "spinner");
-  clutter_actor_add_child (bvw->stage, bvw->spinner);
-  clutter_actor_set_child_above_sibling (bvw->stage,
-                                        bvw->spinner,
-                                        bvw->frame);
-  clutter_actor_hide (bvw->spinner);
-
-  /* Fullscreen header controls */
-  bvw->header_controls = gtk_clutter_actor_new ();
-  clutter_actor_set_opacity (bvw->header_controls, OVERLAY_OPACITY);
-  clutter_actor_set_name (bvw->header_controls, "header-controls");
-  clutter_actor_add_constraint (bvw->header_controls,
-                                clutter_bind_constraint_new (bvw->stage,
-                                                             CLUTTER_BIND_WIDTH,
-                                                             0));
-  layout = g_object_new (CLUTTER_TYPE_ACTOR,
-                        "layout-manager", clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER, 
CLUTTER_BIN_ALIGNMENT_START),
-                        NULL);
-  clutter_actor_set_name (layout, "layout");
-  clutter_actor_add_child (layout, bvw->header_controls);
-  clutter_actor_add_child (bvw->stage, layout);
-
-  /* The controls */
-  bvw->controls = bacon_video_controls_actor_new ();
-  clutter_actor_set_name (bvw->controls, "controls");
-  layout = g_object_new (CLUTTER_TYPE_ACTOR,
-                        "layout-manager", clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER, 
CLUTTER_BIN_ALIGNMENT_END),
-                        NULL);
-  clutter_actor_set_name (layout, "layout");
-  clutter_actor_add_child (layout, bvw->controls);
+  /* Create video output widget and logo */
+  bvw->stack = gtk_stack_new ();
+  gtk_container_add (GTK_CONTAINER (bvw), bvw->stack);
+  gtk_widget_show (bvw->stack);
 
-  clutter_actor_add_child (bvw->stage, layout);
-  clutter_actor_set_child_above_sibling (bvw->stage,
-                                        layout,
-                                        bvw->logo_frame);
+  g_object_set (glsinkbin, "sink", bvw->video_sink, NULL);
+  g_object_get (bvw->video_sink, "widget", &tmp, NULL);
+  gtk_stack_add_named (GTK_STACK (bvw->stack), tmp, "video");
+  gtk_widget_show (tmp);
+  g_object_unref (tmp);
 
-  clutter_actor_set_opacity (bvw->controls, 0);
+  tmp = gtk_image_new_from_icon_name (APPLICATION_ID, GTK_ICON_SIZE_DIALOG);
+  gtk_image_set_pixel_size (GTK_IMAGE (tmp), LOGO_SIZE);
+  gtk_stack_add_named (GTK_STACK (bvw->stack), tmp, "logo");
+  gtk_widget_show (tmp);
 
-  item = g_object_get_data (G_OBJECT (bvw->controls), "seek_scale");
-  g_signal_connect (item, "scroll-event",
-                   G_CALLBACK (bacon_video_widget_handle_scroll), bvw);
-  item = g_object_get_data (G_OBJECT (bvw->controls), "volume_button");
-  g_signal_connect (item, "scroll-event",
-                   G_CALLBACK (bacon_video_widget_handle_scroll), bvw);
+  g_object_set (bvw->video_sink,
+                "rotate-method", GST_VIDEO_ORIENTATION_AUTO,
+                NULL);
 
   /* And tell playbin */
-  g_object_set (bvw->play, "video-sink", bvw->video_sink, NULL);
+  g_object_set (bvw->play, "video-sink", glsinkbin, NULL);
 
   /* Link the audiopitch element */
   bvw->audio_capsfilter =
@@ -6228,23 +5546,6 @@ bacon_video_widget_set_rate (BaconVideoWidget *bvw,
   return retval;
 }
 
-/**
- * bacon_video_widget_set_fullscreen:
- * @bvw: a #BaconVideoWidget
- * @fullscreen: the new fullscreen state
- *
- * Sets the fullscreen state, enabling a toplevel header bar sliding from
- * the top of the video widget.
- **/
-void
-bacon_video_widget_set_fullscreen (BaconVideoWidget *bvw,
-                                   gboolean          fullscreen)
-{
-  g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
-
-  g_object_set (bvw->header_controls, "visible", fullscreen, NULL);
-}
-
 /*
  * vim: sw=2 ts=8 cindent noai bs=2
  */
diff --git a/src/backend/bacon-video-widget.h b/src/backend/bacon-video-widget.h
index 734dbdbe9..63ba2e16b 100644
--- a/src/backend/bacon-video-widget.h
+++ b/src/backend/bacon-video-widget.h
@@ -27,14 +27,10 @@
 
 #pragma once
 
-#include <clutter-gtk/clutter-gtk.h>
-
-#ifndef glib_autoptr_clear_GtkClutterEmbed
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkClutterEmbed, g_object_unref)
-#endif
+#include <gtk/gtk.h>
 
 #define BACON_TYPE_VIDEO_WIDGET                     (bacon_video_widget_get_type ())
-G_DECLARE_FINAL_TYPE(BaconVideoWidget, bacon_video_widget, BACON, VIDEO_WIDGET, GtkClutterEmbed)
+G_DECLARE_FINAL_TYPE(BaconVideoWidget, bacon_video_widget, BACON, VIDEO_WIDGET, GtkOverlay)
 #define BVW_ERROR bacon_video_widget_error_quark ()
 
 /**
@@ -144,8 +140,8 @@ gboolean bacon_video_widget_set_rate                 (BaconVideoWidget *bvw,
                                                  gfloat new_rate);
 gfloat bacon_video_widget_get_rate              (BaconVideoWidget *bvw);
 
-void bacon_video_widget_set_fullscreen           (BaconVideoWidget *bvw,
-                                                  gboolean          fullscreen);
+void bacon_video_widget_set_show_cursor          (BaconVideoWidget *bvw,
+                                                 gboolean          show_cursor);
 
 /* Metadata */
 /**
@@ -415,13 +411,3 @@ BvwAudioOutputType bacon_video_widget_get_audio_output_type
                                                 (BaconVideoWidget *bvw);
 void bacon_video_widget_set_audio_output_type    (BaconVideoWidget *bvw,
                                                  BvwAudioOutputType type);
-
-/* OSD */
-void bacon_video_widget_show_popup                (BaconVideoWidget *bvw);
-void bacon_video_widget_mark_popup_busy           (BaconVideoWidget *bvw,
-                                                  const char       *reason);
-void bacon_video_widget_unmark_popup_busy         (BaconVideoWidget *bvw,
-                                                  const char       *reason);
-
-GObject * bacon_video_widget_get_controls_object  (BaconVideoWidget *bvw);
-GObject * bacon_video_widget_get_header_controls_object (BaconVideoWidget *bvw);
diff --git a/src/backend/bvw-test.c b/src/backend/bvw-test.c
index 60c173234..8174fce15 100644
--- a/src/backend/bvw-test.c
+++ b/src/backend/bvw-test.c
@@ -85,9 +85,6 @@ int main
        XInitThreads ();
 #endif
 
-       if (gtk_clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
-               g_assert_not_reached ();
-
        context = g_option_context_new ("- Play audio and video inside a web browser");
        baconoptiongroup = bacon_video_widget_get_option_group();
        g_option_context_add_main_entries (context, option_entries, GETTEXT_PACKAGE);
@@ -123,38 +120,7 @@ int main
        g_signal_connect (G_OBJECT (bvw), "got-redirect", G_CALLBACK (on_redirect), NULL);
        g_signal_connect (G_OBJECT (bvw), "error", G_CALLBACK (error_cb), NULL);
 
-       box = g_object_get_data (bacon_video_widget_get_controls_object (BACON_VIDEO_WIDGET (bvw)), 
"controls_box");
-
-       /* Previous */
-       item = gtk_tool_button_new (NULL, NULL);
-       gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), "media-skip-backward-symbolic");
-       gtk_box_pack_start (box, GTK_WIDGET (item), FALSE, FALSE, 0);
-
-       /* Play/Pause */
-       item = gtk_tool_button_new (NULL, NULL);
-       gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), "media-playback-start-symbolic");
-       gtk_box_pack_start (box, GTK_WIDGET (item), FALSE, FALSE, 0);
-
-       /* Next */
-       item = gtk_tool_button_new (NULL, NULL);
-       gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), "media-skip-forward-symbolic");
-       gtk_box_pack_start (box, GTK_WIDGET (item), FALSE, FALSE, 0);
-
-       /* Separator */
-       item = gtk_separator_tool_item_new ();
-       gtk_box_pack_start (box, GTK_WIDGET (item), FALSE, FALSE, 0);
-
-       /* Go button */
-       item = g_object_get_data (bacon_video_widget_get_controls_object (BACON_VIDEO_WIDGET (bvw)), 
"go_button");
-       image = gtk_image_new_from_icon_name ("view-more-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR);
-       gtk_button_set_image (GTK_BUTTON (item), image);
-
-       gtk_widget_show_all (GTK_WIDGET (box));
-
-       gtk_container_add (GTK_CONTAINER (win),bvw);
-
-       gtk_widget_realize (GTK_WIDGET (win));
-       gtk_widget_realize (bvw);
+       gtk_container_add (GTK_CONTAINER (win), bvw);
 
        gtk_widget_show (win);
        gtk_widget_show (bvw);
diff --git a/src/backend/meson.build b/src/backend/meson.build
index c6df9b150..effdfe60e 100644
--- a/src/backend/meson.build
+++ b/src/backend/meson.build
@@ -35,12 +35,8 @@ endforeach
 
 sources = files(
   'bacon-time-label.c',
-  'bacon-video-controls-actor.c',
-  'bacon-video-spinner-actor.c',
   'bacon-video-widget-gst-missing-plugins.c',
   'bacon-video-widget.c',
-  'clock.c',
-  'totem-aspect-frame.c'
 )
 
 enum_headers = files('bacon-video-widget.h')
@@ -62,10 +58,6 @@ libbacon_video_widget_deps = [
   gst_tag_dep,
   dependency('gstreamer-audio-1.0'),
   gst_video_dep,
-  dependency('clutter-1.0', version: '>= 1.17.3'),
-  dependency('clutter-gst-3.0', version: '>= 2.99.2'),
-  clutter_gtk_dep,
-  dependency('cairo', version: '>= 1.14.0'),
   dependency('gsettings-desktop-schemas'),
   m_dep,
   libtotem_gst_helpers_dep,
diff --git a/src/meson.build b/src/meson.build
index b74fc1a6c..bc371baf3 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -6,12 +6,8 @@ subdir('backend')
 
 enum_headers = files(
   'backend/bacon-time-label.h',
-  'backend/bacon-video-controls-actor.h',
-  'backend/bacon-video-spinner-actor.h',
   'backend/bacon-video-widget-gst-missing-plugins.h',
   'backend/bacon-video-widget.h',
-  'backend/clock.h',
-  'backend/totem-aspect-frame.h',
   'icon-helpers.h',
   'totem-grilo.h',
   'totem-interface.h',
diff --git a/src/plugins/rotation/totem-rotation.c b/src/plugins/rotation/totem-rotation.c
index 3402de98c..087915a09 100644
--- a/src/plugins/rotation/totem-rotation.c
+++ b/src/plugins/rotation/totem-rotation.c
@@ -160,8 +160,6 @@ update_state (TotemRotationPlugin *pi,
        TotemRotationPluginPrivate *priv = pi->priv;
 
        if (mrl == NULL) {
-               bacon_video_widget_set_rotation (BACON_VIDEO_WIDGET (priv->bvw),
-                                        BVW_ROTATION_R_ZERO);
                g_simple_action_set_enabled (priv->rotate_left_action, FALSE);
                g_simple_action_set_enabled (priv->rotate_right_action, FALSE);
        } else {
@@ -298,9 +296,6 @@ impl_deactivate (PeasActivatable *plugin)
        g_action_map_remove_action (G_ACTION_MAP (priv->totem), "rotate-left");
        g_action_map_remove_action (G_ACTION_MAP (priv->totem), "rotate-right");
 
-       bacon_video_widget_set_rotation (BACON_VIDEO_WIDGET (priv->bvw),
-                                        BVW_ROTATION_R_ZERO);
-
        priv->totem = NULL;
        priv->bvw = NULL;
 }
diff --git a/src/totem-object.c b/src/totem-object.c
index 8ba50a0b4..51d6f3cfe 100644
--- a/src/totem-object.c
+++ b/src/totem-object.c
@@ -77,6 +77,9 @@
 #define DEFAULT_WINDOW_W 650
 #define DEFAULT_WINDOW_H 500
 
+#define POPUP_HIDING_TIMEOUT 2 /* seconds */
+#define OVERLAY_OPACITY 0.86
+
 #define TOTEM_SESSION_SAVE_TIMEOUT 10 /* seconds */
 
 /* casts are to shut gcc up */
@@ -164,6 +167,7 @@ static void
 totem_object_app_activate (GApplication *app)
 {
        Totem *totem;
+       GtkStyleContext *style_context;
 
        totem = TOTEM_OBJECT (app);
 
@@ -178,14 +182,10 @@ totem_object_app_activate (GApplication *app)
 
        totem->win = GTK_WIDGET (gtk_builder_get_object (totem->xml, "totem_main_window"));
 #if DEVELOPMENT_VERSION
-       {
-               GtkStyleContext *style_context;
-               style_context = gtk_widget_get_style_context (GTK_WIDGET (totem->win));
-               gtk_style_context_add_class (style_context, "devel");
-       }
+       style_context = gtk_widget_get_style_context (GTK_WIDGET (totem->win));
+       gtk_style_context_add_class (style_context, "devel");
 #endif
 
-
        /* Menubar */
        totem->stack = GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_main_stack"));
 
@@ -214,11 +214,30 @@ totem_object_app_activate (GApplication *app)
 
        totem->controls_visibility = TOTEM_CONTROLS_UNDEFINED;
 
-       totem->seek = g_object_get_data (totem->controls, "seek_scale");
+       totem->controls = gtk_builder_new ();
+       const char *objects[] = { "toolbar", NULL };
+       GError *error = NULL;
+        if (gtk_builder_add_objects_from_file (totem->controls, DATADIR "/totem/controls.ui", (gchar **) 
objects, &error) == 0)
+               g_assert_not_reached ();
+       gtk_grid_attach (GTK_GRID (totem->bvw_grid),
+                        GTK_WIDGET (gtk_builder_get_object (totem->controls, "toolbar")),
+                        0, 2, 3, 1);
+       gtk_widget_set_hexpand (GTK_WIDGET (gtk_builder_get_object (totem->controls, "toolbar")), TRUE);
+       gtk_widget_set_vexpand (GTK_WIDGET (gtk_builder_get_object (totem->controls, "toolbar")), TRUE);
+       gtk_widget_set_valign (GTK_WIDGET (gtk_builder_get_object (totem->controls, "toolbar")), 
GTK_ALIGN_END);
+
+       totem->spinner = gtk_spinner_new ();
+       gtk_grid_attach (GTK_GRID (totem->bvw_grid), totem->spinner, 1, 2, 1, 1);
+       gtk_widget_set_vexpand (totem->spinner, TRUE);
+       gtk_widget_set_hexpand (totem->spinner, TRUE);
+       style_context = gtk_widget_get_style_context (totem->spinner);
+       gtk_style_context_add_class (style_context, "osd");
+
+       totem->seek = GTK_WIDGET (gtk_builder_get_object (totem->controls, "seek_scale"));
        totem->seekadj = gtk_range_get_adjustment (GTK_RANGE (totem->seek));
-       totem->volume = g_object_get_data (totem->controls, "volume_button");
-       totem->time_label = g_object_get_data (totem->controls, "time_label");
-       totem->time_rem_label = g_object_get_data (totem->controls, "time_rem_label");
+       totem->volume = GTK_WIDGET (gtk_builder_get_object (totem->controls, "volume_button"));
+       totem->time_label = BACON_TIME_LABEL (gtk_builder_get_object (totem->controls, "time_label"));
+       totem->time_rem_label = BACON_TIME_LABEL (gtk_builder_get_object (totem->controls, "time_rem_label"));
        totem->pause_start = optionstate.pause;
 
        totem_callback_connect (totem);
@@ -514,14 +533,13 @@ totem_object_class_init (TotemObjectClass *klass)
 static void
 totem_object_init (TotemObject *totem)
 {
-       if (gtk_clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
-               g_warning ("gtk-clutter failed to initialise, expect problems from here on.");
-
        totem->settings = g_settings_new (TOTEM_GSETTINGS_SCHEMA);
 
        g_application_add_main_option_entries (G_APPLICATION (totem), all_options);
        g_application_add_option_group (G_APPLICATION (totem), bacon_video_widget_get_option_group ());
 
+       totem->busy_popup_ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
        totem_app_actions_setup (totem);
 }
 
@@ -530,6 +548,7 @@ totem_object_finalize (GObject *object)
 {
        TotemObject *totem = TOTEM_OBJECT (object);
 
+       g_clear_pointer (&totem->busy_popup_ht, g_hash_table_destroy);
        g_clear_pointer (&totem->title, g_free);
        g_clear_pointer (&totem->subtitle, g_free);
        g_clear_pointer (&totem->search_string, g_free);
@@ -992,6 +1011,41 @@ totem_object_set_current_subtitle (TotemObject *totem, const char *subtitle_uri)
        totem_playlist_set_current_subtitle (totem->playlist, subtitle_uri);
 }
 
+static void set_controls_visibility (TotemObject      *totem,
+                                    gboolean          visible,
+                                    gboolean          animate);
+
+static void
+unschedule_hiding_popup (TotemObject *totem)
+{
+       if (totem->transition_timeout_id > 0)
+               g_source_remove (totem->transition_timeout_id);
+       totem->transition_timeout_id = 0;
+}
+
+static gboolean
+hide_popup_timeout_cb (TotemObject *totem)
+{
+       set_controls_visibility (totem, FALSE, TRUE);
+       unschedule_hiding_popup (totem);
+       return G_SOURCE_REMOVE;
+}
+
+static void
+schedule_hiding_popup (TotemObject *totem)
+{
+       unschedule_hiding_popup (totem);
+       totem->transition_timeout_id = g_timeout_add_seconds (POPUP_HIDING_TIMEOUT, (GSourceFunc) 
hide_popup_timeout_cb, totem);
+       g_source_set_name_by_id (totem->transition_timeout_id, "[totem] schedule_hiding_popup");
+}
+
+static void
+show_popup (TotemObject *totem)
+{
+       set_controls_visibility (totem, TRUE, FALSE);
+       schedule_hiding_popup (totem);
+}
+
 void
 totem_object_set_main_page (TotemObject *totem,
                            const char  *page_id)
@@ -1029,7 +1083,7 @@ totem_object_set_main_page (TotemObject *totem,
                gtk_widget_show (totem->gear_button);
                gtk_widget_hide (totem->add_button);
                gtk_widget_hide (totem->main_menu_button);
-               bacon_video_widget_show_popup (totem->bvw);
+               show_popup (totem);
        } else if (g_strcmp0 (page_id, "grilo") == 0) {
                totem_grilo_start (TOTEM_GRILO (totem->grilo));
                g_object_set (totem->header,
@@ -1234,6 +1288,10 @@ totem_remote_setting_get_type (void)
        return etype;
 }
 
+static void
+unmark_popup_busy (TotemObject      *totem,
+                  const char       *reason);
+
 static void
 reset_seek_status (TotemObject *totem)
 {
@@ -1242,7 +1300,7 @@ reset_seek_status (TotemObject *totem)
 
        if (totem->seek_lock != FALSE) {
                totem->seek_lock = FALSE;
-               bacon_video_widget_unmark_popup_busy (totem->bvw, "seek started");
+               unmark_popup_busy (totem, "seek started");
                bacon_video_widget_seek (totem->bvw, 0, NULL);
                bacon_video_widget_stop (totem->bvw);
                play_pause_set_label (totem, STATE_STOPPED);
@@ -1638,19 +1696,18 @@ window_state_event_cb (GtkWidget           *window,
                        totem_object_save_size (totem);
 
                totem->controls_visibility = TOTEM_CONTROLS_FULLSCREEN;
-               show_controls (totem, FALSE);
        } else {
                totem->controls_visibility = TOTEM_CONTROLS_VISIBLE;
-               show_controls (totem, TRUE);
+               totem_object_save_size (totem);
        }
 
-       bacon_video_widget_set_fullscreen (totem->bvw,
-                                          totem->controls_visibility == TOTEM_CONTROLS_FULLSCREEN);
-
        action = g_action_map_lookup_action (G_ACTION_MAP (totem), "fullscreen");
        g_simple_action_set_state (G_SIMPLE_ACTION (action),
                                   g_variant_new_boolean (totem->controls_visibility == 
TOTEM_CONTROLS_FULLSCREEN));
 
+       if (totem->transition_timeout_id > 0)
+               set_controls_visibility (totem, TRUE, FALSE);
+
        g_object_notify (G_OBJECT (totem), "fullscreen");
 
        return FALSE;
@@ -1819,6 +1876,47 @@ totem_object_set_next_subtitle (TotemObject *totem,
        totem->next_subtitle = g_strdup (subtitle);
 }
 
+static void
+set_controls_visibility (TotemObject      *totem,
+                        gboolean          visible,
+                        gboolean          animate)
+{
+       gtk_widget_set_visible (GTK_WIDGET (gtk_builder_get_object (totem->controls, "toolbar")), visible);
+       gtk_widget_set_visible (totem->fullscreen_header, visible &&
+                               totem->controls_visibility == TOTEM_CONTROLS_FULLSCREEN);
+       bacon_video_widget_set_show_cursor (totem->bvw, visible);
+       if (visible && animate)
+               schedule_hiding_popup (totem);
+       totem->reveal_controls = visible;
+}
+
+static void
+mark_popup_busy (TotemObject      *totem,
+                const char       *reason)
+{
+       g_hash_table_insert (totem->busy_popup_ht,
+                            g_strdup (reason),
+                            GINT_TO_POINTER (1));
+       g_debug ("Adding popup busy for reason %s", reason);
+
+       set_controls_visibility (totem, TRUE, FALSE);
+       unschedule_hiding_popup (totem);
+}
+
+static void
+unmark_popup_busy (TotemObject      *totem,
+                  const char       *reason)
+{
+       g_hash_table_remove (totem->busy_popup_ht, reason);
+       g_debug ("Removing popup busy for reason %s", reason);
+
+       if (g_hash_table_size (totem->busy_popup_ht) == 0 &&
+           gtk_widget_get_opacity (GTK_WIDGET (gtk_builder_get_object (totem->controls, "toolbar"))) != 0.0) 
{
+               g_debug ("Will hide popup soon");
+               schedule_hiding_popup (totem);
+       }
+}
+
 /**
  * totem_object_set_mrl:
  * @totem: a #TotemObject
@@ -1866,7 +1964,7 @@ totem_object_set_mrl (TotemObject *totem,
                /* Subtitle selection */
                totem_object_set_sensitivity2 ("select-subtitle", FALSE);
 
-               /* Set the logo */
+               /* Set the label */
                update_mrl_label (totem, NULL);
 
                g_object_notify (G_OBJECT (totem), "playing");
@@ -1886,6 +1984,7 @@ totem_object_set_mrl (TotemObject *totem,
 
                g_application_mark_busy (G_APPLICATION (totem));
                bacon_video_widget_open (totem->bvw, mrl);
+               mark_popup_busy (totem, "opening file");
                if (subtitle) {
                        bacon_video_widget_set_text_subtitle (totem->bvw, subtitle);
                } else if (autoload_sub) {
@@ -2373,8 +2472,9 @@ back_button_clicked_cb (GtkButton   *button,
 {
        if (g_strcmp0 (totem_object_get_main_page (totem), "player") == 0) {
                totem_playlist_clear (totem->playlist);
-               gtk_window_unfullscreen (GTK_WINDOW (totem->win));
                totem_object_set_main_page (totem, "grilo");
+               gtk_window_unfullscreen (GTK_WINDOW (totem->win));
+               bacon_video_widget_set_show_cursor (totem->bvw, TRUE);
        } else {
                totem_grilo_back_button_clicked (TOTEM_GRILO (totem->grilo));
        }
@@ -2485,9 +2585,19 @@ on_error_event (BaconVideoWidget *bvw, char *message,
 }
 
 static void
-on_buffering_event (BaconVideoWidget *bvw, gdouble percentage, TotemObject *totem)
+on_buffering_event (BaconVideoWidget *bvw, gdouble percent, TotemObject *totem)
 {
-       //FIXME show that somehow
+       if (percent >= 1.0) {
+               gtk_spinner_stop (GTK_SPINNER (totem->spinner));
+               gtk_widget_hide (totem->spinner);
+               unmark_popup_busy (totem, "buffering");
+       } else {
+               g_autofree char *text = NULL;
+
+               mark_popup_busy (totem, "buffering");
+               gtk_widget_show (totem->spinner);
+               gtk_spinner_start (GTK_SPINNER (totem->spinner));
+       }
 }
 
 static void
@@ -2496,6 +2606,29 @@ on_download_buffering_event (BaconVideoWidget *bvw, gdouble level, TotemObject *
        update_fill (totem, level);
 }
 
+static void
+play_starting_cb (BaconVideoWidget *bvw,
+                 TotemObject      *totem)
+{
+       unmark_popup_busy (totem, "opening file");
+}
+
+static gboolean
+on_bvw_motion_notify_cb (BaconVideoWidget *bvw,
+                        GdkEventMotion   *event,
+                        TotemObject      *totem)
+{
+       if (!totem->reveal_controls)
+               set_controls_visibility (totem, TRUE, TRUE);
+
+       /* FIXME: handle hover
+        * if (hovering)
+        *         unschedule_hiding_popup (bvw);
+        */
+
+       return GDK_EVENT_PROPAGATE;
+}
+
 static void
 update_fill (TotemObject *totem, gdouble level)
 {
@@ -2594,6 +2727,34 @@ volume_button_value_changed_cb (GtkScaleButton *button, gdouble value, TotemObje
        bacon_video_widget_set_volume (totem->bvw, value);
 }
 
+static gboolean
+volume_button_scroll_event_cb (GtkWidget      *widget,
+                              GdkEventScroll *event,
+                              gpointer        user_data)
+{
+       TotemObject *totem = user_data;
+       gboolean increase;
+
+       if (event->direction == GDK_SCROLL_SMOOTH) {
+               gdouble delta_y;
+
+               gdk_event_get_scroll_deltas ((GdkEvent *) event, NULL, &delta_y);
+               if (delta_y == 0.0)
+                       return GDK_EVENT_PROPAGATE;
+
+               increase = delta_y < 0.0;
+       } else if (event->direction == GDK_SCROLL_UP) {
+               increase = TRUE;
+       } else if (event->direction == GDK_SCROLL_DOWN) {
+               increase = SEEK_BACKWARD_OFFSET * 1000;
+       } else {
+               return GDK_EVENT_PROPAGATE;
+       }
+
+       totem_object_set_volume_relative (totem, increase ? VOLUME_UP_OFFSET : VOLUME_DOWN_OFFSET);
+       return GDK_EVENT_STOP;
+}
+
 static void
 update_volume_sliders (TotemObject *totem)
 {
@@ -2629,7 +2790,7 @@ seek_slider_pressed_cb (GtkWidget *widget, GdkEventButton *event, TotemObject *t
        event->button = GDK_BUTTON_PRIMARY;
 
        totem->seek_lock = TRUE;
-       bacon_video_widget_mark_popup_busy (totem->bvw, "seek started");
+       mark_popup_busy (totem, "seek started");
 
        return FALSE;
 }
@@ -2667,7 +2828,7 @@ seek_slider_released_cb (GtkWidget *widget, GdkEventButton *event, TotemObject *
        /* set to FALSE here to avoid triggering a final seek when
         * syncing the adjustments while being in direct seek mode */
        totem->seek_lock = FALSE;
-       bacon_video_widget_unmark_popup_busy (totem->bvw, "seek started");
+       unmark_popup_busy (totem, "seek started");
 
        /* sync both adjustments */
        adj = gtk_range_get_adjustment (GTK_RANGE (widget));
@@ -2679,6 +2840,33 @@ seek_slider_released_cb (GtkWidget *widget, GdkEventButton *event, TotemObject *
        return FALSE;
 }
 
+static gboolean
+seek_slider_scroll_event_cb (GtkWidget      *widget,
+                            GdkEventScroll *event,
+                            gpointer        user_data)
+{
+       TotemObject *totem = user_data;
+       gint64 offset;
+
+       if (event->direction == GDK_SCROLL_SMOOTH) {
+               gdouble delta_y;
+
+               gdk_event_get_scroll_deltas ((GdkEvent *) event, NULL, &delta_y);
+               if (delta_y == 0.0)
+                       return GDK_EVENT_PROPAGATE;
+
+               offset = delta_y >= 0.0 ? SEEK_BACKWARD_OFFSET * 1000 : SEEK_FORWARD_OFFSET * 1000;
+       } else if (event->direction == GDK_SCROLL_UP) {
+               offset = SEEK_FORWARD_OFFSET * 1000;
+       } else if (event->direction == GDK_SCROLL_DOWN) {
+               offset = SEEK_BACKWARD_OFFSET * 1000;
+       } else {
+               return GDK_EVENT_PROPAGATE;
+       }
+       totem_object_seek_relative (totem, offset, FALSE);
+       return GDK_EVENT_STOP;
+}
+
 gboolean
 totem_object_open_files (TotemObject *totem, char **list)
 {
@@ -2779,24 +2967,6 @@ totem_object_open_files_list (TotemObject *totem, GSList *list)
        return changed;
 }
 
-void
-show_controls (TotemObject *totem, gboolean was_fullscreen)
-{
-       GtkWidget *bvw_box;
-
-       if (totem->bvw == NULL)
-               return;
-
-       bvw_box = GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_bvw_box"));
-
-       if (totem->controls_visibility == TOTEM_CONTROLS_VISIBLE) {
-               totem_object_save_size (totem);
-       } else {
-                /* We won't show controls in fullscreen */
-               gtk_container_set_border_width (GTK_CONTAINER (bvw_box), 0);
-       }
-}
-
 /**
  * totem_object_next_angle:
  * @totem: a #TotemObject
@@ -3279,7 +3449,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
        case GDK_KEY_B:
        case GDK_KEY_b:
                totem_object_seek_previous (totem);
-               bacon_video_widget_show_popup (totem->bvw);
+               show_popup (totem);
                break;
        case GDK_KEY_C:
        case GDK_KEY_c:
@@ -3321,7 +3491,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
        case GDK_KEY_n:
        case GDK_KEY_End:
                totem_object_seek_next (totem);
-               bacon_video_widget_show_popup (totem->bvw);
+               show_popup (totem);
                break;
        case GDK_KEY_OpenURL:
                totem_object_set_fullscreen (totem, FALSE);
@@ -3426,7 +3596,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
 
                        if (totem_object_is_seekable (totem)) {
                                totem_object_handle_seek (totem, event, is_forward);
-                               bacon_video_widget_show_popup (totem->bvw);
+                               show_popup (totem);
                        }
                } else {
                        if (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_Page_Down)
@@ -3437,7 +3607,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
                break;
        case GDK_KEY_Home:
                totem_object_seek (totem, 0);
-               bacon_video_widget_show_popup (totem->bvw);
+               show_popup (totem);
                break;
        case GDK_KEY_Up:
                if (bacon_video_widget_has_menus (totem->bvw) != FALSE)
@@ -3465,7 +3635,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
                break;
        case GDK_KEY_Menu:
        case GDK_KEY_F10:
-               bacon_video_widget_show_popup (totem->bvw);
+               show_popup (totem);
                if (totem->controls_visibility != TOTEM_CONTROLS_FULLSCREEN) {
                        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (totem->gear_button),
                                                      !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON 
(totem->gear_button)));
@@ -3475,7 +3645,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
                }
                break;
        case GDK_KEY_Time:
-               bacon_video_widget_show_popup (totem->bvw);
+               show_popup (totem);
                break;
        case GDK_KEY_equal:
                if (mask == GDK_CONTROL_MASK)
@@ -3489,7 +3659,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
        case GDK_KEY_KP_Add:
                if (mask != GDK_CONTROL_MASK) {
                        totem_object_seek_next (totem);
-                       bacon_video_widget_show_popup (totem->bvw);
+                       show_popup (totem);
                } else {
                        totem_object_set_zoom (totem, TRUE);
                }
@@ -3498,7 +3668,7 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
        case GDK_KEY_KP_Subtract:
                if (mask != GDK_CONTROL_MASK) {
                        totem_object_seek_previous (totem);
-                       bacon_video_widget_show_popup (totem->bvw);
+                       show_popup (totem);
                } else {
                        totem_object_set_zoom (totem, FALSE);
                }
@@ -3534,33 +3704,6 @@ totem_object_handle_key_press (TotemObject *totem, GdkEventKey *event)
        return retval;
 }
 
-static void
-on_seek_requested_event (BaconVideoWidget *bvw,
-                        gboolean          forward,
-                        TotemObject      *totem)
-{
-       gint64 offset;
-
-       offset = forward ? SEEK_FORWARD_OFFSET * 1000 : SEEK_BACKWARD_OFFSET * 1000;
-       totem_object_seek_relative (totem, offset, FALSE);
-}
-
-static void
-on_track_skip_requested_event (BaconVideoWidget *bvw,
-                              gboolean          is_forward,
-                              TotemObject      *totem)
-{
-       totem_object_direction (totem, is_forward ? TOTEM_PLAYLIST_DIRECTION_NEXT : 
TOTEM_PLAYLIST_DIRECTION_PREVIOUS);
-}
-
-static void
-on_volume_change_requested_event (BaconVideoWidget *bvw,
-                                 gboolean          increase,
-                                 TotemObject      *totem)
-{
-       totem_object_set_volume_relative (totem, increase ? VOLUME_UP_OFFSET : VOLUME_DOWN_OFFSET);
-}
-
 gboolean
 window_key_press_event_cb (GtkWidget *win, GdkEventKey *event, TotemObject *totem)
 {
@@ -3776,9 +3919,9 @@ popup_menu_shown_cb (GtkToggleButton *button,
                     TotemObject     *totem)
 {
        if (gtk_toggle_button_get_active (button))
-               bacon_video_widget_mark_popup_busy (totem->bvw, "toolbar/go menu visible");
+               mark_popup_busy (totem, "toolbar/go menu visible");
        else
-               bacon_video_widget_unmark_popup_busy (totem->bvw, "toolbar/go menu visible");
+               unmark_popup_busy (totem, "toolbar/go menu visible");
 }
 
 static void
@@ -3787,9 +3930,9 @@ volume_button_menu_shown_cb (GObject     *popover,
                             TotemObject *totem)
 {
        if (gtk_widget_is_visible (GTK_WIDGET (popover)))
-               bacon_video_widget_mark_popup_busy (totem->bvw, "volume menu visible");
+               mark_popup_busy (totem, "volume menu visible");
        else
-               bacon_video_widget_unmark_popup_busy (totem->bvw, "volume menu visible");
+               unmark_popup_busy (totem, "volume menu visible");
 }
 
 static void
@@ -3854,7 +3997,7 @@ totem_callback_connect (TotemObject *totem)
                                   g_variant_new_boolean (totem_playlist_get_repeat (totem->playlist)));
 
        /* Controls */
-       box = g_object_get_data (totem->controls, "controls_box");
+       box = GTK_BOX (gtk_builder_get_object (totem->controls, "controls_box"));
        gtk_widget_insert_action_group (GTK_WIDGET (box), "app", G_ACTION_GROUP (totem));
 
        /* Previous */
@@ -3880,18 +4023,22 @@ totem_callback_connect (TotemObject *totem)
                          G_CALLBACK (seek_slider_pressed_cb), totem);
        g_signal_connect (totem->seek, "button-release-event",
                          G_CALLBACK (seek_slider_released_cb), totem);
+       g_signal_connect (totem->seek, "scroll-event",
+                         G_CALLBACK (seek_slider_scroll_event_cb), totem);
        g_signal_connect (totem->seekadj, "value-changed",
                          G_CALLBACK (seek_slider_changed_cb), totem);
 
        /* Volume */
        g_signal_connect (totem->volume, "value-changed",
                          G_CALLBACK (volume_button_value_changed_cb), totem);
+       g_signal_connect (totem->volume, "scroll-event",
+                         G_CALLBACK (volume_button_scroll_event_cb), totem);
        item = gtk_scale_button_get_popup (GTK_SCALE_BUTTON (totem->volume));
        g_signal_connect (G_OBJECT (item), "notify::visible",
                          G_CALLBACK (volume_button_menu_shown_cb), totem);
 
        /* Go button */
-       item = g_object_get_data (totem->controls, "go_button");
+       item = GTK_WIDGET (gtk_builder_get_object (totem->controls, "go_button"));
        menu = (GMenuModel *) gtk_builder_get_object (totem->xml, "gomenu");
        gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (item), menu);
        popover = gtk_menu_button_get_popover (GTK_MENU_BUTTON (item));
@@ -4040,17 +4187,17 @@ grilo_widget_setup (TotemObject *totem)
 }
 
 static void
-add_fullscreen_toolbar (TotemObject *totem)
+add_fullscreen_toolbar (TotemObject *totem,
+                       GtkWidget   *container)
 {
-       GtkWidget *container, *item;
+       GtkWidget *item;
        GMenuModel *menu;
 
-       container = GTK_WIDGET (bacon_video_widget_get_header_controls_object (totem->bvw));
-
        totem->fullscreen_header = g_object_new (TOTEM_TYPE_MAIN_TOOLBAR,
                                                 "show-search-button", FALSE,
                                                 "show-select-button", FALSE,
                                                 "show-back-button", TRUE,
+                                                "opacity", OVERLAY_OPACITY,
                                                 NULL);
        g_object_bind_property (totem->header, "title",
                                totem->fullscreen_header, "title", 0);
@@ -4079,8 +4226,12 @@ add_fullscreen_toolbar (TotemObject *totem)
                          G_CALLBACK (popup_menu_shown_cb), totem);
        totem->fullscreen_gear_button = item;
 
-       gtk_container_add (GTK_CONTAINER (container), totem->fullscreen_header);
+       gtk_grid_attach (GTK_GRID (container), totem->fullscreen_header, 0, 0, 3, 1);
+       gtk_widget_set_halign (totem->fullscreen_header, GTK_ALIGN_FILL);
+       gtk_widget_set_hexpand (totem->fullscreen_header, TRUE);
+       gtk_widget_set_opacity (totem->fullscreen_header, OVERLAY_OPACITY);
        gtk_widget_show_all (totem->fullscreen_header);
+       gtk_widget_hide (totem->fullscreen_header);
 }
 
 void
@@ -4088,9 +4239,6 @@ video_widget_create (TotemObject *totem)
 {
        GError *err = NULL;
        GtkContainer *container;
-       BaconVideoWidget **bvw;
-       GdkWindow *window;
-       gboolean fullscreen;
 
        totem->bvw = BACON_VIDEO_WIDGET (bacon_video_widget_new (&err));
 
@@ -4100,12 +4248,6 @@ video_widget_create (TotemObject *totem)
                        g_error_free (err);
        }
 
-       window = gtk_widget_get_window (totem->win);
-
-       fullscreen = window && ((gdk_window_get_state (window) & GDK_WINDOW_STATE_FULLSCREEN) != 0);
-       bacon_video_widget_set_fullscreen (totem->bvw, fullscreen);
-       totem->controls = bacon_video_widget_get_controls_object (totem->bvw);
-
        g_signal_connect_after (G_OBJECT (totem->bvw),
                        "button-press-event",
                        G_CALLBACK (on_video_button_press_event),
@@ -4143,23 +4285,28 @@ video_widget_create (TotemObject *totem)
                        G_CALLBACK (on_error_event),
                        totem);
        g_signal_connect (G_OBJECT (totem->bvw),
-                         "seek-requested",
-                         G_CALLBACK (on_seek_requested_event),
+                         "play-starting",
+                         G_CALLBACK (play_starting_cb),
                          totem);
        g_signal_connect (G_OBJECT (totem->bvw),
-                         "track-skip-requested",
-                         G_CALLBACK (on_track_skip_requested_event),
+                         "scroll-event",
+                         G_CALLBACK (seek_slider_scroll_event_cb),
                          totem);
        g_signal_connect (G_OBJECT (totem->bvw),
-                         "volume-change-requested",
-                         G_CALLBACK (on_volume_change_requested_event),
+                         "motion-notify-event",
+                         G_CALLBACK (on_bvw_motion_notify_cb),
                          totem);
 
        container = GTK_CONTAINER (gtk_builder_get_object (totem->xml, "tmw_bvw_box"));
        gtk_container_add (container,
                        GTK_WIDGET (totem->bvw));
 
-       add_fullscreen_toolbar (totem);
+       totem->bvw_grid = gtk_grid_new ();
+       gtk_overlay_add_overlay (GTK_OVERLAY (totem->bvw), totem->bvw_grid);
+       gtk_widget_set_halign (totem->bvw_grid, GTK_ALIGN_FILL);
+       gtk_widget_set_valign (totem->bvw_grid, GTK_ALIGN_FILL);
+       gtk_widget_show (totem->bvw_grid);
+       add_fullscreen_toolbar (totem, totem->bvw_grid);
 
        /* Events for the widget video window as well */
        gtk_widget_add_events (GTK_WIDGET (totem->bvw),
@@ -4175,15 +4322,7 @@ video_widget_create (TotemObject *totem)
                           target_table, G_N_ELEMENTS (target_table),
                           GDK_ACTION_MOVE);
 
-       bvw = &(totem->bvw);
-       g_object_add_weak_pointer (G_OBJECT (totem->bvw),
-                                  (gpointer *) bvw);
-
        gtk_widget_show (GTK_WIDGET (totem->bvw));
-
-       /* FIXME: Otherwise we get a visible but
-        * not realized widget ?!?! */
-       gtk_widget_realize (GTK_WIDGET (totem->bvw));
 }
 
 /**
diff --git a/src/totem-private.h b/src/totem-private.h
index de6edb42d..12f31aa7c 100644
--- a/src/totem-private.h
+++ b/src/totem-private.h
@@ -46,7 +46,7 @@
                widget = GTK_WIDGET (gtk_builder_get_object (xml, name));       \
                gtk_widget_set_sensitive (widget, state);                       \
        }
-#define totem_controls_set_sensitivity(name, state) gtk_widget_set_sensitive (g_object_get_data 
(totem->controls, name), state)
+#define totem_controls_set_sensitivity(name, state) gtk_widget_set_sensitive (GTK_WIDGET 
(gtk_builder_get_object (totem->controls, name)), state)
 
 #define totem_object_set_sensitivity2(name, state)                                     \
        {                                                                               \
@@ -75,12 +75,14 @@ struct _TotemObject {
        GtkWidget *win;
        GtkWidget *stack;
        BaconVideoWidget *bvw;
+       GtkWidget *bvw_grid;
        GtkWidget *prefs;
        GtkWindow *shortcuts_win;
+       GtkWidget *spinner;
 
        GtkWidget *grilo;
 
-       GObject *controls;
+       GtkBuilder *controls;
        GtkWidget *play_button;
        BaconTimeLabel *time_label;
        BaconTimeLabel *time_rem_label;
@@ -112,6 +114,9 @@ struct _TotemObject {
 
        /* controls management */
        ControlsVisibility controls_visibility;
+       gboolean reveal_controls;
+       guint transition_timeout_id;
+       GHashTable *busy_popup_ht; /* key=reason string, value=gboolean */
 
        /* Stream info */
        gint64 stream_length;


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