[totem] main: Implement new overlay controls



commit 848309db1d8029709098c178bbc6b6b242f58599
Author: Bastien Nocera <hadess hadess net>
Date:   Thu Apr 4 12:48:01 2013 +0200

    main: Implement new overlay controls
    
    To replace the static controls we currently have.
    With help from Cosimo Cecchi for the overlay theming.
    
    Note that how controls will be shown and hidden will
    be implemented as part of bug 697897.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=694435

 data/Makefile.am                         |    2 +-
 data/controls.ui                         |  196 ++++++++++
 data/fullscreen.ui                       |  263 -------------
 data/totem.ui                            |  136 -------
 po/POTFILES.in                           |    2 +-
 src/Makefile.am                          |    4 -
 src/backend/Makefile.am                  |   15 +-
 src/backend/bacon-time-label.c           |  161 ++++++++
 src/backend/bacon-time-label.h           |   57 +++
 src/backend/bacon-video-controls-actor.c |  118 ++++++
 src/backend/bacon-video-controls-actor.h |   61 +++
 src/backend/bacon-video-header-actor.c   |   96 +++++
 src/backend/bacon-video-header-actor.h   |   61 +++
 src/backend/bacon-video-spinner-actor.c  |  130 +++++++
 src/backend/bacon-video-spinner-actor.h  |   61 +++
 src/backend/bacon-video-widget.c         |  191 ++++++++--
 src/backend/bacon-video-widget.h         |    3 +
 src/backend/bvw-test.c                   |    1 -
 src/backend/clock.c                      |  183 +++++++++
 src/backend/clock.h                      |   56 +++
 src/totem-fullscreen.c                   |  594 ------------------------------
 src/totem-fullscreen.h                   |   85 -----
 src/totem-menu.c                         |   52 ---
 src/totem-object.c                       |  320 +++++++----------
 src/totem-private.h                      |   13 +-
 src/totem-sidebar.c                      |    5 +-
 src/totem-statusbar.c                    |  351 ------------------
 src/totem-statusbar.h                    |   73 ----
 src/totem.c                              |   23 +-
 29 files changed, 1506 insertions(+), 1807 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index f1d56cc..9f1e54d 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -23,12 +23,12 @@ stuff_DATA =                                \
        filmholes-big-left.png          \
        filmholes-big-right.png         \
        totem.ui                        \
-       fullscreen.ui                   \
        playlist.ui                     \
        mozilla-viewer.ui               \
        preferences.ui                  \
        properties.ui                   \
        uri.ui                          \
+       controls.ui                     \
        mozilla-viewer.css
 EXTRA_DIST += $(stuff_DATA)
 
diff --git a/data/controls.ui b/data/controls.ui
new file mode 100644
index 0000000..d19abc3
--- /dev/null
+++ b/data/controls.ui
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.6 -->
+  <object class="GtkAction" id="action1"/>
+  <object class="GtkWindow" id="window">
+    <property name="can_focus">False</property>
+    <child>
+      <object class="GtkToolbar" id="toolbar">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="show_arrow">False</property>
+        <child>
+          <object class="GtkToolItem" id="toolbutton">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkBox" id="box2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkBox" id="top_row">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="homogeneous">True</property>
+                    <child>
+                      <object class="GtkBox" id="left_box">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="orientation">vertical</property>
+                        <child>
+                          <placeholder/>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkBox" id="center_box">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="halign">start</property>
+                        <property name="spacing">12</property>
+                        <child>
+                          <object class="GtkBox" id="controls_box">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <child>
+                              <placeholder/>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkBox" id="fullscreen_box">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="orientation">vertical</property>
+                            <child>
+                              <object class="GtkButton" id="fullscreen_button">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="has_tooltip">True</property>
+                                <property name="focus_on_click">False</property>
+                                <property name="tooltip_text" translatable="yes">Fullscreen</property>
+                                <property name="action_name">app.fullscreen</property>
+                                <child internal-child="accessible">
+                                  <object class="AtkObject" id="fullscreen_accessible">
+                                    <property name="AtkObject::accessible-name" 
translatable="yes">Fullscreen</property>
+                                  </object>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkBox" id="right_box">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="halign">end</property>
+                        <child>
+                          <object class="GtkVolumeButton" id="volume_button">
+                            <property name="visible">True</property>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <property name="has_tooltip">True</property>
+                            <property name="relief">normal</property>
+                            <property name="focus_on_click">False</property>
+                            <property name="orientation">vertical</property>
+                            <property name="use_symbolic">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">4</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkBox" id="bottom_row">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="BaconTimeLabel" id="time_label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkScale" id="seek_scale">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="draw_value">False</property>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="BaconTimeLabel" id="time_rem_label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="remaining">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="homogeneous">True</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/data/totem.ui b/data/totem.ui
index c54503d..680f5be 100644
--- a/data/totem.ui
+++ b/data/totem.ui
@@ -528,132 +528,6 @@
                </packing>
              </child>
 
-             <child>
-               <object class="GtkVBox" id="tmw_controls_vbox">
-                 <property name="border_width">6</property>
-                 <property name="visible">True</property>
-                 <property name="homogeneous">False</property>
-                 <property name="spacing">6</property>
-                  <property name="orientation">vertical</property>
-
-                 <child>
-                   <object class="GtkHBox" id="tmw_seek_hbox">
-                     <property name="visible">True</property>
-                     <property name="homogeneous">False</property>
-                     <property name="spacing">6</property>
-
-                     <child>
-                       <object class="GtkLabel" id="tmw_time_label">
-                         <property name="visible">True</property>
-                         <property name="label" translatable="yes">Time:</property>
-                         <property name="use_underline">False</property>
-                         <property name="use_markup">False</property>
-                         <property name="justify">GTK_JUSTIFY_LEFT</property>
-                         <property name="wrap">False</property>
-                         <property name="selectable">False</property>
-                         <property name="xalign">0.5</property>
-                         <property name="yalign">0.5</property>
-                         <property name="xpad">0</property>
-                         <property name="ypad">0</property>
-                         <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-                         <property name="width_chars">-1</property>
-                         <property name="single_line_mode">False</property>
-                         <property name="angle">0</property>
-                         <accessibility>
-                           <relation target="tmw_seek_hscale" type="label-for"/>
-                         </accessibility>
-                       </object>
-                       <packing>
-                         <property name="padding">0</property>
-                         <property name="expand">False</property>
-                         <property name="fill">False</property>
-                       </packing>
-                     </child>
-
-                     <child>
-                       <object class="GtkHScale" id="tmw_seek_hscale">
-                         <property name="visible">True</property>
-                         <property name="sensitive">False</property>
-                         <property name="can_focus">True</property>
-                         <property name="draw_value">False</property>
-                         <property name="value_pos">GTK_POS_TOP</property>
-                         <property name="digits">1</property>
-                         <property name="inverted">False</property>
-                         <property name="adjustment">tmw_seek_adjustment</property>
-                         <signal name="button-press-event" handler="seek_slider_pressed_cb"/>
-                         <signal name="button-release-event" handler="seek_slider_released_cb"/>
-                         <signal name="scroll-event" handler="window_scroll_event_cb"/>
-                         <child internal-child="accessible">
-                            <object class="AtkObject" id="a11y-tmw_seek_hscale">
-                              <property name="AtkObject::accessible-name" translatable="yes">Time seek 
bar</property>
-                            </object>
-                          </child>
-                         <accessibility>
-                           <relation target="tmw_time_label" type="labelled-by"/>
-                         </accessibility>
-                       </object>
-                       <packing>
-                         <property name="padding">0</property>
-                         <property name="expand">True</property>
-                         <property name="fill">True</property>
-                       </packing>
-                     </child>
-                   </object>
-                   <packing>
-                     <property name="padding">0</property>
-                     <property name="expand">False</property>
-                     <property name="fill">True</property>
-                   </packing>
-                 </child>
-
-                 <child>
-                   <object class="GtkHBox" id="tmw_buttons_hbox">
-                     <property name="visible">True</property>
-                     <property name="homogeneous">False</property>
-                     <property name="spacing">6</property>
-
-                     <child>
-                       <object class="GtkHBox" id="tmw_sidebar_button_hbox">
-                         <property name="visible">True</property>
-                         <property name="homogeneous">False</property>
-                         <property name="spacing">0</property>
-                       </object>
-                       <packing>
-                         <property name="padding">0</property>
-                         <property name="expand">False</property>
-                         <property name="fill">False</property>
-                         <property name="pack_type">GTK_PACK_END</property>
-                       </packing>
-                     </child>
-
-                     <child>
-                       <object class="GtkVolumeButton" id="tmw_volume_button">
-                         <property name="visible">True</property>
-                         <property name="sensitive">False</property>
-                         <property name="use-symbolic">True</property>
-                         <signal name="value-changed" handler="volume_button_value_changed_cb"/>
-                       </object>
-                       <packing>
-                         <property name="padding">0</property>
-                         <property name="expand">False</property>
-                         <property name="fill">True</property>
-                         <property name="pack_type">GTK_PACK_END</property>
-                       </packing>
-                     </child>
-                   </object>
-                   <packing>
-                     <property name="padding">0</property>
-                     <property name="expand">False</property>
-                     <property name="fill">True</property>
-                   </packing>
-                 </child>
-               </object>
-               <packing>
-                 <property name="padding">0</property>
-                 <property name="expand">False</property>
-                 <property name="fill">True</property>
-               </packing>
-             </child>
            </object>
            <packing>
              <property name="shrink">False</property>
@@ -670,16 +544,6 @@
        </packing>
       </child>
 
-      <child>
-       <object class="TotemStatusbar" id="tmw_statusbar">
-         <property name="visible">True</property>
-       </object>
-       <packing>
-         <property name="padding">0</property>
-         <property name="expand">False</property>
-         <property name="fill">True</property>
-       </packing>
-      </child>
     </object>
   </child>
 </object>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0d1c32f..5aa1a44 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -11,6 +11,7 @@ data/totem.desktop.in.in.in
 [type: gettext/glade]data/totem.ui
 [type: gettext/glade]data/uri.ui
 src/backend/bacon-video-widget.c
+src/backend/bacon-time-label.c
 src/eggfileformatchooser.c
 src/gst/totem-time-helpers.c
 src/properties/bacon-video-widget-properties.c
@@ -28,7 +29,6 @@ src/totem-preferences.c
 src/totem-properties-main.c
 src/totem-properties-view.c
 src/totem-sidebar.c
-src/totem-statusbar.c
 src/totem-subtitle-encoding.c
 src/totem-time-label.c
 src/totem-uri.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 92893b8..48deaa3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -34,11 +34,7 @@ header_DATA = $(INST_H_FILES)
 # Totem UI ltlibrary (used by browser plugins)
 libtotem_player_la_SOURCES = \
        $(INST_H_FILES)         \
-       totem-statusbar.c       \
-       totem-statusbar.h       \
        totem-interface.c       \
-       totem-fullscreen.c      \
-       totem-fullscreen.h      \
        gd-fullscreen-filter.c  \
        gd-fullscreen-filter.h  \
        totem-time-label.c      \
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index afdd88e..7167ddb 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -17,7 +17,8 @@ bvw_test_CFLAGS =             \
 
 bvw_test_LDADD =               \
        libbaconvideowidget.la  \
-       $(BACKEND_LIBS)
+       $(BACKEND_LIBS)         \
+       $(top_builddir)/src/gst/libtotemtimehelpers.la
 
 # Enums
 BVW_ENUM_FILES = bacon-video-widget-enums.c bacon-video-widget-enums.h
@@ -52,10 +53,20 @@ libbaconvideowidget_la_SOURCES = \
        gsd-osd-window.h                                \
        gsd-osd-window-private.h                        \
        bacon-video-osd-actor.c                         \
-       bacon-video-osd-actor.h
+       bacon-video-osd-actor.h                         \
+       bacon-video-controls-actor.c                    \
+       bacon-video-controls-actor.h                    \
+       bacon-video-header-actor.h                      \
+       bacon-video-header-actor.c                      \
+       bacon-video-spinner-actor.h                     \
+       bacon-video-spinner-actor.c                     \
+       clock.c clock.h                                 \
+       bacon-time-label.c                              \
+       bacon-time-label.h
 
 libbaconvideowidget_la_CPPFLAGS = \
        -D_REENTRANT                            \
+       -DDATADIR=\"$(pkgdatadir)\"             \
        -I$(top_srcdir)/src/gst/                \
        -I$(top_builddir)/src/backend           \
        $(DISABLE_DEPRECATED)                   \
diff --git a/src/backend/bacon-time-label.c b/src/backend/bacon-time-label.c
new file mode 100644
index 0000000..ce88927
--- /dev/null
+++ b/src/backend/bacon-time-label.c
@@ -0,0 +1,161 @@
+/*
+ * Time label widget
+ *
+ * Copyright (C) 2004-2013 Bastien Nocera <hadess hadess net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include "bacon-time-label.h"
+#include <glib/gi18n.h>
+#include "totem-time-helpers.h"
+
+struct _BaconTimeLabelPrivate {
+       gint64 time;
+       gint64 length;
+       gboolean remaining;
+};
+
+G_DEFINE_TYPE (BaconTimeLabel, bacon_time_label, GTK_TYPE_LABEL)
+#define BACON_TIME_LABEL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), BACON_TYPE_TIME_LABEL, 
BaconTimeLabelPrivate))
+
+enum {
+       PROP_0,
+       PROP_REMAINING
+};
+
+static void
+bacon_time_label_init (BaconTimeLabel *label)
+{
+       char *time_string;
+       label->priv = G_TYPE_INSTANCE_GET_PRIVATE (label, BACON_TYPE_TIME_LABEL, BaconTimeLabelPrivate);
+
+       time_string = totem_time_to_string (0, FALSE, FALSE);
+       gtk_label_set_text (GTK_LABEL (label), time_string);
+       g_free (time_string);
+
+       label->priv->time = 0;
+       label->priv->length = -1;
+       label->priv->remaining = FALSE;
+}
+
+GtkWidget *
+bacon_time_label_new (void)
+{
+       return GTK_WIDGET (g_object_new (BACON_TYPE_TIME_LABEL, NULL));
+}
+
+static void
+bacon_time_label_set_property (GObject      *object,
+                              guint         property_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+       switch (property_id) {
+       case PROP_REMAINING:
+               bacon_time_label_set_remaining (BACON_TIME_LABEL (object), g_value_get_boolean (value));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+               break;
+       }
+}
+
+static void
+bacon_time_label_class_init (BaconTimeLabelClass *klass)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (klass, sizeof (BaconTimeLabelPrivate));
+
+       object_class = (GObjectClass *) klass;
+       object_class->set_property = bacon_time_label_set_property;
+
+       g_object_class_install_property (object_class, PROP_REMAINING,
+                                        g_param_spec_boolean ("remaining", "Remaining",
+                                                              "Whether to show a remaining time.", FALSE,
+                                                              G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+update_label_text (BaconTimeLabel *label)
+{
+       char *label_str;
+       gboolean force_hour = FALSE;
+       gint64 _time, length;
+
+       _time = label->priv->time;
+       length = label->priv->length;
+
+       if (length > 60 * 60 * 1000)
+               force_hour = TRUE;
+
+       if (length <= 0) {
+               if (!label->priv->remaining) {
+                       label_str = totem_time_to_string (_time, FALSE, force_hour);
+               } else {
+                       /* translators: Unknown remaining time */
+                       label_str = g_strdup (_("--:--"));
+               }
+       } else {
+               if (!label->priv->remaining) {
+                       /* Elapsed */
+                       label_str = totem_time_to_string (_time, FALSE, force_hour);
+               } else {
+                       /* Remaining */
+                       label_str = totem_time_to_string (length - _time, TRUE, force_hour);
+               }
+       }
+
+       gtk_label_set_text (GTK_LABEL (label), label_str);
+       g_free (label_str);
+}
+
+void
+bacon_time_label_set_time (BaconTimeLabel *label,
+                          gint64          _time,
+                          gint64          length)
+{
+       g_return_if_fail (BACON_IS_TIME_LABEL (label));
+
+       if (!label->priv->remaining) {
+               if (_time / 1000 == label->priv->time / 1000)
+                       return;
+       } else {
+               if (_time / 1000 == label->priv->time / 1000 &&
+                   length / 1000 == label->priv->length / 1000)
+               return;
+       }
+
+       label->priv->time = _time;
+       label->priv->length = length;
+
+       update_label_text (label);
+}
+
+void
+bacon_time_label_set_remaining (BaconTimeLabel *label,
+                               gboolean        remaining)
+{
+       g_return_if_fail (BACON_IS_TIME_LABEL (label));
+
+       label->priv->remaining = remaining;
+       update_label_text (label);
+}
diff --git a/src/backend/bacon-time-label.h b/src/backend/bacon-time-label.h
new file mode 100644
index 0000000..a896c12
--- /dev/null
+++ b/src/backend/bacon-time-label.h
@@ -0,0 +1,57 @@
+/*
+ * Time label widget
+ *
+ * Copyright (C) 2004-2013 Bastien Nocera <hadess hadess net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef BACON_TIME_LABEL_H
+#define BACON_TIME_LABEL_H
+
+#include <gtk/gtk.h>
+
+#define BACON_TYPE_TIME_LABEL            (bacon_time_label_get_type ())
+#define BACON_TIME_LABEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), BACON_TYPE_TIME_LABEL, 
BaconTimeLabel))
+#define BACON_TIME_LABEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), BACON_TYPE_TIME_LABEL, 
BaconTimeLabelClass))
+#define BACON_IS_TIME_LABEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BACON_TYPE_TIME_LABEL))
+#define BACON_IS_TIME_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BACON_TYPE_TIME_LABEL))
+
+typedef struct BaconTimeLabel        BaconTimeLabel;
+typedef struct BaconTimeLabelClass    BaconTimeLabelClass;
+typedef struct _BaconTimeLabelPrivate BaconTimeLabelPrivate;
+
+struct BaconTimeLabel {
+       GtkLabel parent;
+       BaconTimeLabelPrivate *priv;
+};
+
+struct BaconTimeLabelClass {
+       GtkLabelClass parent_class;
+};
+
+G_MODULE_EXPORT GType bacon_time_label_get_type (void);
+GtkWidget *bacon_time_label_new                 (void);
+void       bacon_time_label_set_time            (BaconTimeLabel *label,
+                                                 gint64          time,
+                                                 gint64          length);
+void
+bacon_time_label_set_remaining                  (BaconTimeLabel *label,
+                                                 gboolean        remaining);
+
+#endif /* BACON_TIME_LABEL_H */
diff --git a/src/backend/bacon-video-controls-actor.c b/src/backend/bacon-video-controls-actor.c
new file mode 100644
index 0000000..a3e6560
--- /dev/null
+++ b/src/backend/bacon-video-controls-actor.c
@@ -0,0 +1,118 @@
+/*
+ * Overlaid controls
+ *
+ * Copyright (C) 2013 Bastien Nocera <hadess hadess net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include "bacon-video-controls-actor.h"
+#include "bacon-time-label.h"
+
+#define BACON_VIDEO_CONTROLS_ACTOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), 
BACON_TYPE_VIDEO_CONTROLS_ACTOR, BaconVideoControlsActorPrivate))
+
+struct BaconVideoControlsActorPrivate
+{
+       GtkBuilder *builder;
+       GtkRange *seek;
+       GObject *bvw;
+};
+
+G_DEFINE_TYPE (BaconVideoControlsActor, bacon_video_controls_actor, GTK_CLUTTER_TYPE_ACTOR);
+
+static void
+bacon_video_controls_actor_finalize (GObject *object)
+{
+       BaconVideoControlsActor *controls;
+
+       controls = BACON_VIDEO_CONTROLS_ACTOR (object);
+
+       g_object_unref (controls->priv->builder);
+
+       G_OBJECT_CLASS (bacon_video_controls_actor_parent_class)->finalize (object);
+}
+
+static void
+bacon_video_controls_actor_constructed (GObject *object)
+{
+       GtkWidget *contents;
+       GdkRGBA transparent = { 0, 0, 0, 0 };
+       BaconVideoControlsActor *controls;
+
+       controls = BACON_VIDEO_CONTROLS_ACTOR (object);
+
+       contents = GTK_WIDGET (gtk_builder_get_object (controls->priv->builder, "toolbar"));
+       g_object_set (object, "contents", contents, "opacity", OVERLAY_OPACITY, "x-expand", TRUE, NULL);
+
+       /* Theming */
+       gtk_style_context_add_class (gtk_widget_get_style_context (contents), "osd");
+       gtk_widget_override_background_color (gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (object)), 0, 
&transparent);
+}
+
+static void
+bacon_video_controls_actor_class_init (BaconVideoControlsActorClass *klass)
+{
+        GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+        gobject_class->finalize = bacon_video_controls_actor_finalize;
+        gobject_class->constructed = bacon_video_controls_actor_constructed;
+
+        g_type_class_add_private (klass, sizeof (BaconVideoControlsActorPrivate));
+}
+
+static void
+setup_object (BaconVideoControlsActor *controls,
+             const char              *name)
+{
+       GObject *obj;
+
+       obj = gtk_builder_get_object (controls->priv->builder, name);
+
+       /* Setup an easy way to lookup the widgets by name without
+        * exposing the API directly to totem or the plugin viewer */
+       g_object_set_data (G_OBJECT (controls), name, obj);
+}
+
+static void
+bacon_video_controls_actor_init (BaconVideoControlsActor *controls)
+{
+       char *objects[] = { "toolbar", NULL };
+
+       controls->priv = BACON_VIDEO_CONTROLS_ACTOR_GET_PRIVATE (G_OBJECT (controls));
+
+       g_type_class_ref (BACON_TYPE_TIME_LABEL);
+
+       controls->priv->builder = gtk_builder_new ();
+       if (gtk_builder_add_objects_from_file (controls->priv->builder, DATADIR "/controls.ui", objects, 
NULL) == 0)
+               g_assert_not_reached ();
+
+       setup_object (controls, "seek_scale");
+       setup_object (controls, "controls_box");
+       setup_object (controls, "fullscreen_button");
+       setup_object (controls, "volume_button");
+       setup_object (controls, "time_label");
+       setup_object (controls, "time_rem_label");
+}
+
+ClutterActor *
+bacon_video_controls_actor_new (void)
+{
+        return g_object_new (BACON_TYPE_VIDEO_CONTROLS_ACTOR, NULL);
+}
diff --git a/src/backend/bacon-video-controls-actor.h b/src/backend/bacon-video-controls-actor.h
new file mode 100644
index 0000000..d777154
--- /dev/null
+++ b/src/backend/bacon-video-controls-actor.h
@@ -0,0 +1,61 @@
+/*
+ * Overlaid controls
+ *
+ * Copyright (C) 2013 Bastien Nocera <hadess hadess net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef BACON_VIDEO_CONTROLS_ACTOR_H
+#define BACON_VIDEO_CONTROLS_ACTOR_H
+
+#include <glib-object.h>
+#include <clutter-gtk/clutter-gtk.h>
+
+G_BEGIN_DECLS
+
+#define OVERLAY_OPACITY 220
+
+#define BACON_TYPE_VIDEO_CONTROLS_ACTOR            (bacon_video_controls_actor_get_type ())
+#define BACON_VIDEO_CONTROLS_ACTOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj),  
BACON_TYPE_VIDEO_CONTROLS_ACTOR, BaconVideoControlsActor))
+#define BACON_VIDEO_CONTROLS_ACTOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),   
BACON_TYPE_VIDEO_CONTROLS_ACTOR, BaconVideoControlsActorClass))
+#define BACON_IS_VIDEO_CONTROLS_ACTOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj),  
BACON_TYPE_VIDEO_CONTROLS_ACTOR))
+#define BACON_IS_VIDEO_CONTROLS_ACTOR_CLASS(klass) (G_TYPE_INSTANCE_GET_CLASS ((klass), 
BACON_TYPE_VIDEO_CONTROLS_ACTOR))
+#define BACON_VIDEO_CONTROLS_ACTOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), 
BACON_TYPE_VIDEO_CONTROLS_ACTOR, BaconVideoControlsActorClass))
+
+typedef struct BaconVideoControlsActor                   BaconVideoControlsActor;
+typedef struct BaconVideoControlsActorClass              BaconVideoControlsActorClass;
+typedef struct BaconVideoControlsActorPrivate            BaconVideoControlsActorPrivate;
+
+struct BaconVideoControlsActor {
+        GtkClutterActor                  parent;
+
+        BaconVideoControlsActorPrivate  *priv;
+};
+
+struct BaconVideoControlsActorClass {
+        GtkClutterActorClass parent_class;
+};
+
+GType                 bacon_video_controls_actor_get_type          (void);
+
+ClutterActor *        bacon_video_controls_actor_new               (void);
+
+G_END_DECLS
+
+#endif
diff --git a/src/backend/bacon-video-header-actor.c b/src/backend/bacon-video-header-actor.c
new file mode 100644
index 0000000..efd9e55
--- /dev/null
+++ b/src/backend/bacon-video-header-actor.c
@@ -0,0 +1,96 @@
+/*
+ * Overlaid header
+ *
+ * Copyright (C) 2013 Bastien Nocera <hadess hadess net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include "bacon-video-header-actor.h"
+
+#define BACON_VIDEO_HEADER_ACTOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), 
BACON_TYPE_VIDEO_HEADER_ACTOR, BaconVideoHeaderActorPrivate))
+
+struct BaconVideoHeaderActorPrivate
+{
+       GtkWidget *widget;
+       GtkWidget *button;
+};
+
+G_DEFINE_TYPE (BaconVideoHeaderActor, bacon_video_header_actor, GTK_CLUTTER_TYPE_ACTOR);
+
+static void
+bacon_video_header_actor_constructed (GObject *object)
+{
+       GdkRGBA transparent = { 0, 0, 0, 0 };
+       BaconVideoHeaderActor *header;
+
+       header = BACON_VIDEO_HEADER_ACTOR (object);
+
+       g_object_set (object, "contents", header->priv->widget, "opacity", OVERLAY_OPACITY, "x-expand", TRUE, 
NULL);
+       gtk_widget_show_all (header->priv->widget);
+
+       /* Theming */
+       gtk_style_context_add_class (gtk_widget_get_style_context (header->priv->widget), "osd");
+       gtk_widget_override_background_color (gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (object)), 0, 
&transparent);
+}
+
+static void
+bacon_video_header_actor_class_init (BaconVideoHeaderActorClass *klass)
+{
+        GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+        gobject_class->constructed = bacon_video_header_actor_constructed;
+
+        g_type_class_add_private (klass, sizeof (BaconVideoHeaderActorPrivate));
+}
+
+static void
+setup_object (BaconVideoHeaderActor *header,
+             const char            *name,
+             GtkWidget             *widget)
+{
+       /* Setup an easy way to lookup the widgets by name without
+        * exposing the API directly to totem or the plugin viewer */
+       g_object_set_data (G_OBJECT (header), name, widget);
+}
+
+static void
+bacon_video_header_actor_init (BaconVideoHeaderActor *header)
+{
+       GtkWidget *image;
+
+       header->priv = BACON_VIDEO_HEADER_ACTOR_GET_PRIVATE (G_OBJECT (header));
+       header->priv->widget = gtk_header_bar_new ();
+       setup_object (header, "header", header->priv->widget);
+
+       header->priv->button = gtk_menu_button_new ();
+       image = gtk_image_new_from_icon_name ("emblem-system-symbolic", GTK_ICON_SIZE_MENU);
+       gtk_button_set_image (GTK_BUTTON (header->priv->button), image);
+       setup_object (header, "button", header->priv->button);
+
+       gtk_header_bar_pack_end (GTK_HEADER_BAR (header->priv->widget),
+                                header->priv->button);
+}
+
+ClutterActor *
+bacon_video_header_actor_new (void)
+{
+        return g_object_new (BACON_TYPE_VIDEO_HEADER_ACTOR, NULL);
+}
diff --git a/src/backend/bacon-video-header-actor.h b/src/backend/bacon-video-header-actor.h
new file mode 100644
index 0000000..e168027
--- /dev/null
+++ b/src/backend/bacon-video-header-actor.h
@@ -0,0 +1,61 @@
+/*
+ * Overlaid header
+ *
+ * Copyright (C) 2013 Bastien Nocera <hadess hadess net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef BACON_VIDEO_HEADER_ACTOR_H
+#define BACON_VIDEO_HEADER_ACTOR_H
+
+#include <glib-object.h>
+#include <clutter-gtk/clutter-gtk.h>
+
+G_BEGIN_DECLS
+
+#define OVERLAY_OPACITY 220
+
+#define BACON_TYPE_VIDEO_HEADER_ACTOR            (bacon_video_header_actor_get_type ())
+#define BACON_VIDEO_HEADER_ACTOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj),  
BACON_TYPE_VIDEO_HEADER_ACTOR, BaconVideoHeaderActor))
+#define BACON_VIDEO_HEADER_ACTOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),   
BACON_TYPE_VIDEO_HEADER_ACTOR, BaconVideoHeaderActorClass))
+#define BACON_IS_VIDEO_HEADER_ACTOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj),  
BACON_TYPE_VIDEO_HEADER_ACTOR))
+#define BACON_IS_VIDEO_HEADER_ACTOR_CLASS(klass) (G_TYPE_INSTANCE_GET_CLASS ((klass), 
BACON_TYPE_VIDEO_HEADER_ACTOR))
+#define BACON_VIDEO_HEADER_ACTOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), 
BACON_TYPE_VIDEO_HEADER_ACTOR, BaconVideoHeaderActorClass))
+
+typedef struct BaconVideoHeaderActor                   BaconVideoHeaderActor;
+typedef struct BaconVideoHeaderActorClass              BaconVideoHeaderActorClass;
+typedef struct BaconVideoHeaderActorPrivate            BaconVideoHeaderActorPrivate;
+
+struct BaconVideoHeaderActor {
+        GtkClutterActor                  parent;
+
+        BaconVideoHeaderActorPrivate  *priv;
+};
+
+struct BaconVideoHeaderActorClass {
+        GtkClutterActorClass parent_class;
+};
+
+GType                 bacon_video_header_actor_get_type          (void);
+
+ClutterActor *        bacon_video_header_actor_new               (void);
+
+G_END_DECLS
+
+#endif
diff --git a/src/backend/bacon-video-spinner-actor.c b/src/backend/bacon-video-spinner-actor.c
new file mode 100644
index 0000000..f205741
--- /dev/null
+++ b/src/backend/bacon-video-spinner-actor.c
@@ -0,0 +1,130 @@
+/*
+ * Overlaid spinner
+ *
+ * Copyright (C) 2013 Bastien Nocera <hadess hadess net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include "bacon-video-spinner-actor.h"
+#include "clock.h"
+
+#define BACON_VIDEO_SPINNER_ACTOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), 
BACON_TYPE_VIDEO_SPINNER_ACTOR, BaconVideoSpinnerActorPrivate))
+
+struct BaconVideoSpinnerActorPrivate
+{
+       ClutterActor     *clock;
+};
+
+G_DEFINE_TYPE (BaconVideoSpinnerActor, bacon_video_spinner_actor, CLUTTER_TYPE_ACTOR);
+
+enum {
+       PROP_0,
+       PROP_PERCENT
+};
+
+static void
+bacon_video_spinner_actor_set_property (GObject      *object,
+                                       guint         property_id,
+                                       const GValue *value,
+                                       GParamSpec   *pspec)
+{
+       BaconVideoSpinnerActor *spinner = BACON_VIDEO_SPINNER_ACTOR (object);
+
+       switch (property_id) {
+       case PROP_PERCENT:
+               g_object_set (G_OBJECT (spinner->priv->clock), "angle", g_value_get_float (value) * 360.0 / 
100.0, NULL);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+               break;
+       }
+}
+
+static void
+bacon_video_spinner_actor_get_property (GObject      *object,
+                                       guint         property_id,
+                                       GValue       *value,
+                                       GParamSpec   *pspec)
+{
+       BaconVideoSpinnerActor *spinner = BACON_VIDEO_SPINNER_ACTOR (object);
+       gfloat angle;
+
+       switch (property_id) {
+       case PROP_PERCENT:
+               g_object_get (G_OBJECT (spinner->priv->clock), "angle", &angle, NULL);
+               g_value_set_float (value, angle / 360.0 * 100.0);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+               break;
+       }
+}
+
+static void
+bacon_video_spinner_actor_class_init (BaconVideoSpinnerActorClass *klass)
+{
+        GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+       gobject_class->set_property = bacon_video_spinner_actor_set_property;
+       gobject_class->get_property = bacon_video_spinner_actor_get_property;
+
+       g_object_class_install_property (gobject_class, PROP_PERCENT,
+                                        g_param_spec_float ("percent", "Percent",
+                                                            "Percentage fill",
+                                                            0.0, 100.0, 0.0,
+                                                            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+        g_type_class_add_private (klass, sizeof (BaconVideoSpinnerActorPrivate));
+}
+
+static void
+bacon_video_spinner_actor_init (BaconVideoSpinnerActor *spinner)
+{
+       ClutterActor *actor, *layout;
+       ClutterConstraint *constraint;
+       ClutterColor *color;
+
+       spinner->priv = BACON_VIDEO_SPINNER_ACTOR_GET_PRIVATE (G_OBJECT (spinner));
+       actor = CLUTTER_ACTOR (spinner);
+
+       /* We'll set that colour on the layout, as the child doesn't
+        * take the whole space */
+       color = clutter_color_copy (clutter_color_get_static (CLUTTER_COLOR_BLACK));
+       color->alpha = 128;
+
+       spinner->priv->clock = clock_new ();
+       layout = g_object_new (CLUTTER_TYPE_ACTOR,
+                              "layout-manager", clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER, 
CLUTTER_BIN_ALIGNMENT_CENTER),
+                              "background-color", color,
+                              NULL);
+       clutter_color_free (color);
+       clutter_actor_add_child (layout, spinner->priv->clock);
+       clutter_actor_add_child (actor, layout);
+
+       constraint = clutter_bind_constraint_new (actor, CLUTTER_BIND_SIZE, 0.0);
+       clutter_actor_add_constraint_with_name (layout, "size", constraint);
+}
+
+ClutterActor *
+bacon_video_spinner_actor_new (void)
+{
+        return g_object_new (BACON_TYPE_VIDEO_SPINNER_ACTOR, NULL);
+}
diff --git a/src/backend/bacon-video-spinner-actor.h b/src/backend/bacon-video-spinner-actor.h
new file mode 100644
index 0000000..128aded
--- /dev/null
+++ b/src/backend/bacon-video-spinner-actor.h
@@ -0,0 +1,61 @@
+/*
+ * Overlaid spinner
+ *
+ * Copyright (C) 2013 Bastien Nocera <hadess hadess net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef BACON_VIDEO_SPINNER_ACTOR_H
+#define BACON_VIDEO_SPINNER_ACTOR_H
+
+#include <glib-object.h>
+#include <clutter-gtk/clutter-gtk.h>
+
+G_BEGIN_DECLS
+
+#define OVERLAY_OPACITY 220
+
+#define BACON_TYPE_VIDEO_SPINNER_ACTOR            (bacon_video_spinner_actor_get_type ())
+#define BACON_VIDEO_SPINNER_ACTOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj),  
BACON_TYPE_VIDEO_SPINNER_ACTOR, BaconVideoSpinnerActor))
+#define BACON_VIDEO_SPINNER_ACTOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),   
BACON_TYPE_VIDEO_SPINNER_ACTOR, BaconVideoSpinnerActorClass))
+#define BACON_IS_VIDEO_SPINNER_ACTOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj),  
BACON_TYPE_VIDEO_SPINNER_ACTOR))
+#define BACON_IS_VIDEO_SPINNER_ACTOR_CLASS(klass) (G_TYPE_INSTANCE_GET_CLASS ((klass), 
BACON_TYPE_VIDEO_SPINNER_ACTOR))
+#define BACON_VIDEO_SPINNER_ACTOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), 
BACON_TYPE_VIDEO_SPINNER_ACTOR, BaconVideoSpinnerActorClass))
+
+typedef struct BaconVideoSpinnerActor                   BaconVideoSpinnerActor;
+typedef struct BaconVideoSpinnerActorClass              BaconVideoSpinnerActorClass;
+typedef struct BaconVideoSpinnerActorPrivate            BaconVideoSpinnerActorPrivate;
+
+struct BaconVideoSpinnerActor {
+        ClutterActor                    parent;
+
+        BaconVideoSpinnerActorPrivate  *priv;
+};
+
+struct BaconVideoSpinnerActorClass {
+        ClutterActorClass parent_class;
+};
+
+GType                 bacon_video_spinner_actor_get_type          (void);
+
+ClutterActor *        bacon_video_spinner_actor_new               (void);
+
+G_END_DECLS
+
+#endif
diff --git a/src/backend/bacon-video-widget.c b/src/backend/bacon-video-widget.c
index 653151a..62a0dfb 100644
--- a/src/backend/bacon-video-widget.c
+++ b/src/backend/bacon-video-widget.c
@@ -87,6 +87,9 @@
 #include "bacon-video-widget.h"
 #include "bacon-video-widget-gst-missing-plugins.h"
 #include "bacon-video-osd-actor.h"
+#include "bacon-video-controls-actor.h"
+#include "bacon-video-header-actor.h"
+#include "bacon-video-spinner-actor.h"
 #include "bacon-video-widget-enums.h"
 #include "video-utils.h"
 
@@ -94,6 +97,8 @@
 
 #define OSD_SIZE 130                           /* Size of the OSD popup */
 #define OSD_MARGIN 8                           /* Pixels from the top-left */
+#define CONTROLS_MARGIN 32.0                   /* Pixels from the bottom, left and right */
+#define DEFAULT_CONTROLS_WIDTH 600             /* In pixels */
 #define LOGO_SIZE 256                          /* Maximum size of the logo */
 #define REWIND_OR_PREVIOUS 4000
 
@@ -205,6 +210,9 @@ struct BaconVideoWidgetPrivate
   ClutterActor                *texture;
   ClutterActor                *frame;
   ClutterActor                *osd;
+  ClutterActor                *controls;
+  ClutterActor                *header;
+  ClutterActor                *spinner;
 
   ClutterActor                *logo_frame;
   ClutterContent              *logo;
@@ -691,45 +699,91 @@ bacon_video_widget_motion_notify (GtkWidget *widget, GdkEventMotion *event)
   return res;
 }
 
-static gboolean
-bacon_video_widget_button_press (GtkWidget *widget, GdkEventButton *event)
+static void
+toggle_controls (BaconVideoWidget *bvw)
 {
-  gboolean res = FALSE;
-  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
-
-  g_return_val_if_fail (bvw->priv->play != NULL, FALSE);
+  /* FIXME:
+   * Using a show/hide seems to not trigger the
+   * controls to redraw, so let's change the opacity instead */
+  if (clutter_actor_get_opacity (bvw->priv->controls) != 0) {
+    clutter_actor_set_opacity (bvw->priv->controls, 0);
+    clutter_actor_set_opacity (bvw->priv->header, 0);
+  } else {
+    clutter_actor_set_opacity (bvw->priv->header, OVERLAY_OPACITY);
+    clutter_actor_set_opacity (bvw->priv->controls, OVERLAY_OPACITY);
+  }
+}
 
-  if (bvw->priv->navigation && !bvw->priv->logo_mode) {
-    gst_navigation_send_mouse_event (bvw->priv->navigation,
-                                    "mouse-button-press", event->button, event->x, event->y);
+static void
+translate_coords (GtkWidget      *widget,
+                 GdkEventButton *event,
+                 int            *x,
+                 int            *y)
+{
+  GtkWidget *src;
 
-    /* FIXME need to check whether the backend will have handled
-     * the button press
-     res = TRUE; */
+  gdk_window_get_user_data (event->window, (gpointer *)&src);
+  if (src && src != widget) {
+    gtk_widget_translate_coordinates (src, widget, event->x, event->y, x, y);
+  } else {
+    *x = event->x;
+    *y = event->y;
   }
+}
 
-  if (GTK_WIDGET_CLASS (parent_class)->button_press_event)
-    res |= GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
+static gboolean
+ignore_event (BaconVideoWidget *bvw,
+             int               x,
+             int               y)
+{
+  ClutterActor *actor;
 
-  return res;
+  actor = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (bvw->priv->stage), CLUTTER_PICK_REACTIVE, x, y);
+
+  /* Eat the GTK+ event if we're not clicking on the video itself */
+  if (actor == bvw->priv->controls || actor == bvw->priv->header)
+    return TRUE;
+
+  return FALSE;
 }
 
 static gboolean
-bacon_video_widget_button_release (GtkWidget *widget, GdkEventButton *event)
+bacon_video_widget_button_press_or_release (GtkWidget *widget, GdkEventButton *event)
 {
   gboolean res = FALSE;
   BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
+  int x, y;
 
   g_return_val_if_fail (bvw->priv->play != NULL, FALSE);
 
-  if (bvw->priv->navigation && !bvw->priv->logo_mode) {
+  translate_coords (widget, event, &x, &y);
+  if (ignore_event (bvw, x, y))
+    return TRUE;
+
+  if (event->type != GDK_BUTTON_PRESS &&
+      event->type != GDK_BUTTON_RELEASE)
+    goto bail;
+
+  if (bvw->priv->navigation &&
+      !bvw->priv->logo_mode &&
+      event->button == 1 &&
+      bvw->priv->is_menu != FALSE) {
+    const char *event_str;
+    event_str = (event->type == GDK_BUTTON_PRESS) ? "mouse-button-press" : "mouse-button-release";
     gst_navigation_send_mouse_event (bvw->priv->navigation,
-                                    "mouse-button-release", event->button, event->x, event->y);
+                                    event_str, event->button, x, y);
 
-    res = TRUE;
+    /* FIXME need to check whether the backend will have handled
+     * the button press
+     res = TRUE; */
+  } else if (event->type == GDK_BUTTON_RELEASE) {
+    toggle_controls (bvw);
   }
 
-  if (GTK_WIDGET_CLASS (parent_class)->button_release_event)
+bail:
+  if (event->type == GDK_BUTTON_PRESS && GTK_WIDGET_CLASS (parent_class)->button_press_event)
+    res |= GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
+  if (event->type == GDK_BUTTON_RELEASE && GTK_WIDGET_CLASS (parent_class)->button_release_event)
     res |= GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event);
 
   return res;
@@ -740,7 +794,8 @@ bacon_video_widget_get_preferred_width (GtkWidget *widget,
                                         gint      *minimum,
                                         gint      *natural)
 {
-  *minimum = *natural = 240;
+  /* We could also make the actor a minimum width, based on its contents */
+  *minimum = *natural = DEFAULT_CONTROLS_WIDTH + 2 * CONTROLS_MARGIN;
 }
 
 static void
@@ -748,7 +803,7 @@ bacon_video_widget_get_preferred_height (GtkWidget *widget,
                                          gint      *minimum,
                                          gint      *natural)
 {
-  *minimum = *natural = 180;
+  *minimum = *natural = (DEFAULT_CONTROLS_WIDTH + 2 * CONTROLS_MARGIN) / 16 * 9;
 }
 
 static gboolean
@@ -785,11 +840,9 @@ bacon_video_widget_class_init (BaconVideoWidgetClass * klass)
   widget_class->get_preferred_height = bacon_video_widget_get_preferred_height;
   widget_class->realize = bacon_video_widget_realize;
 
-  /* FIXME: Remove those when GtkClutterEmbedded passes on GDK XI 1.2
-   * events properly */
   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;
+  widget_class->button_press_event = bacon_video_widget_button_press_or_release;
+  widget_class->button_release_event = bacon_video_widget_button_press_or_release;
 
   /* GObject */
   object_class->set_property = bacon_video_widget_set_property;
@@ -1161,6 +1214,8 @@ bacon_video_widget_init (BaconVideoWidget * bvw)
 
   bvw->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (bvw, BACON_TYPE_VIDEO_WIDGET, BaconVideoWidgetPrivate);
 
+  g_object_set (G_OBJECT (bvw), "use-layout-size", TRUE, NULL);
+
   priv->update_id = 0;
   priv->tagcache = NULL;
   priv->audiotags = NULL;
@@ -1890,6 +1945,15 @@ bvw_handle_buffering_message (GstMessage * message, BaconVideoWidget *bvw)
   g_signal_emit (bvw, bvw_signals[SIGNAL_BUFFERING], 0, (gdouble) percent / 100.0);
 
   if (percent >= 100) {
+    clutter_actor_hide (bvw->priv->spinner);
+    /* Reset */
+    g_object_set (G_OBJECT (bvw->priv->spinner), "percent", 0.0, NULL);
+  } else {
+    clutter_actor_show (bvw->priv->spinner);
+    g_object_set (G_OBJECT (bvw->priv->spinner), "percent", (float) percent, NULL);
+  }
+
+  if (percent >= 100) {
     /* a 100% message means buffering is done */
     bvw->priv->buffering = FALSE;
     /* if the desired state is playing, go back */
@@ -3354,6 +3418,22 @@ bacon_video_widget_popup_osd (BaconVideoWidget *bvw,
   bacon_video_osd_actor_show_and_fade (BACON_VIDEO_OSD_ACTOR (bvw->priv->osd));
 }
 
+GObject *
+bacon_video_widget_get_controls_object (BaconVideoWidget *bvw)
+{
+  g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
+
+  return G_OBJECT (bvw->priv->controls);
+}
+
+GObject *
+bacon_video_widget_get_header_object (BaconVideoWidget *bvw)
+{
+  g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
+
+  return G_OBJECT (bvw->priv->header);
+}
+
 /* =========================================== */
 /*                                             */
 /*               Play/Pause, Stop              */
@@ -5914,6 +5994,7 @@ bacon_video_widget_initable_init (GInitable     *initable,
   gchar *version_str;
   GstPlayFlags flags;
   ClutterConstraint *constraint;
+  ClutterActor *layout;
   GstElement *audio_bin, *audio_converter;
   GstPad *audio_pad;
 
@@ -6011,13 +6092,24 @@ bacon_video_widget_initable_init (GInitable     *initable,
   clutter_actor_set_name (bvw->priv->frame, "frame");
   totem_aspect_frame_set_child (TOTEM_ASPECT_FRAME (bvw->priv->frame), bvw->priv->texture);
 
-  clutter_actor_add_child (CLUTTER_ACTOR (bvw->priv->stage), bvw->priv->frame);
+  clutter_actor_add_child (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_set_child_above_sibling (CLUTTER_ACTOR (bvw->priv->stage),
-                                        CLUTTER_ACTOR (bvw->priv->logo_frame),
-                                        CLUTTER_ACTOR (bvw->priv->frame));
+  clutter_actor_set_child_above_sibling (bvw->priv->stage,
+                                        bvw->priv->logo_frame,
+                                        bvw->priv->frame);
+
+  /* The spinner */
+  bvw->priv->spinner = bacon_video_spinner_actor_new ();
+  clutter_actor_set_name (bvw->priv->spinner, "spinner");
+  clutter_actor_add_child (bvw->priv->stage, bvw->priv->spinner);
+  constraint = clutter_bind_constraint_new (bvw->priv->stage, CLUTTER_BIND_SIZE, 0.0);
+  clutter_actor_add_constraint_with_name (bvw->priv->spinner, "size", constraint);
+  clutter_actor_set_child_above_sibling (bvw->priv->stage,
+                                        bvw->priv->spinner,
+                                        bvw->priv->frame);
+  clutter_actor_hide (bvw->priv->spinner);
 
   /* The OSD */
   bvw->priv->osd = bacon_video_osd_actor_new ();
@@ -6030,6 +6122,45 @@ bacon_video_widget_initable_init (GInitable     *initable,
                                         bvw->priv->frame);
   bacon_video_osd_actor_hide (BACON_VIDEO_OSD_ACTOR (bvw->priv->osd));
 
+  /* The controls */
+  bvw->priv->controls = bacon_video_controls_actor_new ();
+  clutter_actor_set_name (bvw->priv->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->priv->controls);
+
+  clutter_actor_add_child (bvw->priv->stage, layout);
+  g_object_set (G_OBJECT (bvw->priv->controls),
+               "margin-bottom", CONTROLS_MARGIN,
+               "margin-left", CONTROLS_MARGIN,
+               "margin-right", CONTROLS_MARGIN,
+               NULL);
+
+  clutter_actor_set_child_above_sibling (bvw->priv->stage,
+                                        layout,
+                                        bvw->priv->logo_frame);
+  constraint = clutter_bind_constraint_new (bvw->priv->stage, CLUTTER_BIND_SIZE, 0.0);
+  clutter_actor_add_constraint_with_name (layout, "size", constraint);
+
+  /* The header bar */
+  bvw->priv->header = bacon_video_header_actor_new ();
+  clutter_actor_set_name (bvw->priv->header, "header");
+  layout = g_object_new (CLUTTER_TYPE_ACTOR,
+                        "layout-manager", clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_FILL, 
CLUTTER_BIN_ALIGNMENT_START),
+                        NULL);
+  clutter_actor_set_name (layout, "layout");
+  clutter_actor_add_child (layout, bvw->priv->header);
+
+  clutter_actor_add_child (bvw->priv->stage, layout);
+
+  clutter_actor_set_child_above_sibling (bvw->priv->stage,
+                                        layout,
+                                        bvw->priv->logo_frame);
+  constraint = clutter_bind_constraint_new (bvw->priv->stage, CLUTTER_BIND_SIZE, 0.0);
+  clutter_actor_add_constraint_with_name (layout, "size", constraint);
+
   /* And tell playbin */
   g_object_set (bvw->priv->play, "video-sink", video_sink, NULL);
 
diff --git a/src/backend/bacon-video-widget.h b/src/backend/bacon-video-widget.h
index 746f215..8ae53e1 100644
--- a/src/backend/bacon-video-widget.h
+++ b/src/backend/bacon-video-widget.h
@@ -458,6 +458,9 @@ void bacon_video_widget_set_audio_output_type    (BaconVideoWidget *bvw,
 void bacon_video_widget_popup_osd                 (BaconVideoWidget *bvw,
                                                   const char       *icon_name);
 
+GObject * bacon_video_widget_get_controls_object  (BaconVideoWidget *bvw);
+GObject * bacon_video_widget_get_header_object  (BaconVideoWidget *bvw);
+
 G_END_DECLS
 
 #endif                         /* HAVE_BACON_VIDEO_WIDGET_H */
diff --git a/src/backend/bvw-test.c b/src/backend/bvw-test.c
index 477a962..5d9103b 100644
--- a/src/backend/bvw-test.c
+++ b/src/backend/bvw-test.c
@@ -110,7 +110,6 @@ int main
        g_object_set (G_OBJECT (gtk_settings), "gtk-application-prefer-dark-theme", TRUE, NULL);
 
        win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-       gtk_window_set_default_size (GTK_WINDOW (win), 500, 500);
        g_signal_connect (G_OBJECT (win), "destroy",
                        G_CALLBACK (gtk_main_quit), NULL);
 
diff --git a/src/backend/clock.c b/src/backend/clock.c
new file mode 100644
index 0000000..dacad0f
--- /dev/null
+++ b/src/backend/clock.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Joaquim Rocha <me joaquimrocha com>
+ */
+
+#include <math.h>
+#include "clock.h"
+
+#define CLOCK_RADIUS                   150
+#define CLOCK_LINE_WIDTH               40
+#define CLOCK_LINE_PADDING             10
+#define ANGLE_PROP_NAME                "angle"
+
+G_DEFINE_TYPE (Clock, clock, CLUTTER_TYPE_ACTOR);
+
+enum {
+  PROP_0,
+  PROP_ANGLE,
+  N_PROPERTIES
+};
+
+static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
+
+static void
+draw_clock (ClutterCairoTexture *texture,
+            cairo_t             *cr,
+            gint                 width,
+            gint                 height,
+            Clock               *self)
+{
+  cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+  cairo_paint (cr);
+
+  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+
+  /* Draw the clock background */
+  cairo_arc(cr, width / 2, height / 2, CLOCK_RADIUS / 2, 0.0, 2.0 * M_PI);
+  cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
+  cairo_fill_preserve(cr);
+  cairo_stroke(cr);
+
+  cairo_set_line_width(cr, CLOCK_LINE_WIDTH);
+
+  cairo_arc(cr,
+            width / 2,
+            height / 2,
+            (CLOCK_RADIUS - CLOCK_LINE_WIDTH - CLOCK_LINE_PADDING) / 2,
+            3 * M_PI_2,
+            3 * M_PI_2 + self->angle * M_PI / 180.0);
+  cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+  cairo_stroke(cr);
+}
+
+static void
+clock_set_property (GObject      *object,
+                    guint         property_id,
+                    const GValue *value,
+                    GParamSpec   *pspec)
+{
+  Clock *self = CLOCK (object);
+  ClutterContent *content;
+  content = clutter_actor_get_content (CLUTTER_ACTOR (self));
+
+  switch (property_id)
+    {
+    case PROP_ANGLE:
+      self->angle = g_value_get_float (value);
+      if (content)
+        clutter_content_invalidate (content);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+clock_get_property (GObject      *object,
+                    guint         property_id,
+                    GValue       *value,
+                    GParamSpec   *pspec)
+{
+  Clock *self = CLOCK (object);
+
+  switch (property_id)
+    {
+    case PROP_ANGLE:
+      g_value_set_float (value, self->angle);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+clock_init (Clock *self)
+{
+  self->angle = 0;
+
+  ClutterContent *content;
+  content = clutter_canvas_new ();
+  clutter_canvas_set_size (CLUTTER_CANVAS (content),
+                           CLOCK_RADIUS + 2,
+                           CLOCK_RADIUS + 2);
+  clutter_actor_set_content (CLUTTER_ACTOR (self), content);
+  g_signal_connect (CLUTTER_CANVAS (content),
+                    "draw",
+                    G_CALLBACK (draw_clock),
+                    self);
+  g_object_unref (content);
+}
+
+static void
+clock_get_preferred_width (ClutterActor *actor,
+                           gfloat        for_height,
+                           gfloat       *min_width_p,
+                           gfloat       *natural_width_p)
+{
+  *min_width_p = CLOCK_RADIUS + 2;
+  *natural_width_p = CLOCK_RADIUS + 2;
+}
+
+static void
+clock_get_preferred_height (ClutterActor *actor,
+                            gfloat        for_width,
+                            gfloat       *min_height_p,
+                            gfloat       *natural_height_p)
+{
+  *min_height_p = CLOCK_RADIUS + 2;
+  *natural_height_p = CLOCK_RADIUS + 2;
+}
+
+
+static void
+clock_class_init (ClockClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *clutter_actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+  gobject_class->set_property = clock_set_property;
+  gobject_class->get_property = clock_get_property;
+
+  clutter_actor_class->get_preferred_width = clock_get_preferred_width;
+  clutter_actor_class->get_preferred_height = clock_get_preferred_height;
+
+  obj_properties[PROP_ANGLE] =
+    g_param_spec_float (ANGLE_PROP_NAME,
+                        "The angle of the clock's progress",
+                        "Set the angle of the clock's progress",
+                        .0,
+                        360.0,
+                        .0,
+                        G_PARAM_READWRITE |
+                        G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (gobject_class,
+                                     N_PROPERTIES,
+                                     obj_properties);
+}
+
+ClutterActor *
+clock_new (void)
+{
+  return g_object_new (CLOCK_TYPE, NULL);
+}
diff --git a/src/backend/clock.h b/src/backend/clock.h
new file mode 100644
index 0000000..b59a1b6
--- /dev/null
+++ b/src/backend/clock.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Joaquim Rocha <me joaquimrocha com>
+ */
+
+#ifndef __CLOCK_H__
+#define __CLOCK_H__
+
+#include <glib.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define CLOCK_TYPE            (clock_get_type ())
+#define CLOCK(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLOCK_TYPE, Clock))
+#define CLOCK_IS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLOCK_TYPE))
+#define CLOCK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CLOCK_TYPE, ClockClass))
+#define CLOCK_IS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLOCK_TYPE))
+#define CLOCK_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CLOCK_TYPE, ClockClass))
+
+typedef struct _Clock      Clock;
+typedef struct _ClockClass ClockClass;
+
+struct _Clock
+{
+  ClutterActor parent_instance;
+
+  /*< private >*/
+  gfloat angle;
+};
+
+struct _ClockClass
+{
+  ClutterActorClass parent_class;
+};
+
+ClutterActor * clock_new (void);
+
+GType clock_get_type (void);
+
+#endif /* __CLOCK_H__ */
diff --git a/src/totem-menu.c b/src/totem-menu.c
index 1c045ed..3895326 100644
--- a/src/totem-menu.c
+++ b/src/totem-menu.c
@@ -34,7 +34,6 @@
 #include "totem-interface.h"
 #include "totem-private.h"
 #include "totem-sidebar.h"
-#include "totem-statusbar.h"
 #include "bacon-video-widget.h"
 #include "totem-uri.h"
 
@@ -668,55 +667,6 @@ clear_playlist_action_callback (GtkAction *action, Totem *totem)
 }
 
 /* Show help in status bar when selecting (hovering over) a menu item. */
-static void
-menu_item_select_cb (GtkMenuItem *proxy, Totem *totem)
-{
-       GtkAction *action;
-       const gchar *message;
-
-       action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (proxy));
-       g_return_if_fail (action != NULL);
-
-       message = gtk_action_get_tooltip (action);
-       if (message)
-               totem_statusbar_push_help (TOTEM_STATUSBAR (totem->statusbar), message);
-}
-
-static void
-menu_item_deselect_cb (GtkMenuItem *proxy, Totem *totem)
-{
-       totem_statusbar_pop_help (TOTEM_STATUSBAR (totem->statusbar));
-}
-
-static void
-setup_action (Totem *totem, GtkAction *action)
-{
-       GSList *proxies;
-       for (proxies = gtk_action_get_proxies (action); proxies != NULL; proxies = proxies->next) {
-               if (GTK_IS_MENU_ITEM (proxies->data)) {
-                       g_signal_connect (proxies->data, "select", G_CALLBACK (menu_item_select_cb), totem);
-                       g_signal_connect (proxies->data, "deselect", G_CALLBACK (menu_item_deselect_cb), 
totem);
-               }
-
-       }
-}
-
-static void
-setup_menu_items (Totem *totem)
-{
-       GList *action_groups;
-
-       /* FIXME: We can remove this once GTK+ bug #574001 is fixed */
-       for (action_groups = gtk_ui_manager_get_action_groups (totem->ui_manager);
-            action_groups != NULL; action_groups = action_groups->next) {
-               GtkActionGroup *action_group = GTK_ACTION_GROUP (action_groups->data);
-               GList *actions;
-               for (actions = gtk_action_group_list_actions (action_group); actions != NULL; actions = 
actions->next) {
-                       setup_action (totem, GTK_ACTION (actions->data));
-               }
-       }
-}
-
 void
 totem_ui_manager_setup (Totem *totem)
 {
@@ -736,8 +686,6 @@ totem_ui_manager_setup (Totem *totem)
 
        totem->ui_manager = GTK_UI_MANAGER (gtk_builder_get_object (totem->xml, "totem-ui-manager"));
 
-       setup_menu_items (totem);
-
        totem->devices_action_group = NULL;
        totem->devices_ui_id = gtk_ui_manager_new_merge_id (totem->ui_manager);
        totem->languages_action_group = NULL;
diff --git a/src/totem-object.c b/src/totem-object.c
index d3d145e..b050bfc 100644
--- a/src/totem-object.c
+++ b/src/totem-object.c
@@ -53,7 +53,7 @@
 #include "totem-plugins-engine.h"
 #include "totem-playlist.h"
 #include "bacon-video-widget.h"
-#include "totem-statusbar.h"
+#include "bacon-time-label.h"
 #include "totem-time-label.h"
 #include "totem-sidebar.h"
 #include "totem-menu.h"
@@ -936,8 +936,6 @@ reset_seek_status (TotemObject *totem)
         * avoid being "stuck" seeking on errors */
 
        if (totem->seek_lock != FALSE) {
-               totem_statusbar_set_seeking (TOTEM_STATUSBAR (totem->statusbar), FALSE);
-               totem_time_label_set_seeking (TOTEM_TIME_LABEL (totem->fs->time_label), FALSE);
                totem->seek_lock = FALSE;
                bacon_video_widget_seek (totem->bvw, 0, NULL);
                totem_object_action_stop (totem);
@@ -1088,7 +1086,6 @@ totem_object_action_exit (TotemObject *totem)
        totem_destroy_file_filters ();
 
        g_clear_object (&totem->settings);
-       g_clear_object (&totem->fs);
 
        if (totem->win)
                gtk_widget_destroy (GTK_WIDGET (totem->win));
@@ -1129,24 +1126,20 @@ play_pause_set_label (TotemObject *totem, TotemStates state)
        switch (state)
        {
        case STATE_PLAYING:
-               totem_statusbar_set_text (TOTEM_STATUSBAR (totem->statusbar),
-                               _("Playing"));
                id = "media-playback-pause-symbolic";
                tip = N_("Pause");
                totem_playlist_set_playing (totem->playlist, TOTEM_PLAYLIST_STATUS_PLAYING);
                break;
        case STATE_PAUSED:
-               totem_statusbar_set_text (TOTEM_STATUSBAR (totem->statusbar),
-                               _("Paused"));
                id = "media-playback-start-symbolic";
                tip = N_("Play");
                totem_playlist_set_playing (totem->playlist, TOTEM_PLAYLIST_STATUS_PAUSED);
                break;
        case STATE_STOPPED:
-               totem_statusbar_set_text (TOTEM_STATUSBAR (totem->statusbar),
-                               _("Stopped"));
-               totem_statusbar_set_time_and_length
-                       (TOTEM_STATUSBAR (totem->statusbar), 0, 0);
+               bacon_time_label_set_time (totem->time_label,
+                                          0, 0);
+               bacon_time_label_set_time (totem->time_rem_label,
+                                          0, 0);
                id = "media-playback-start-symbolic";
                totem_playlist_set_playing (totem->playlist, TOTEM_PLAYLIST_STATUS_NONE);
                tip = N_("Play");
@@ -1390,13 +1383,10 @@ window_state_event_cb (GtkWidget *window, GdkEventWindowState *event,
        if (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) {
                if (totem->controls_visibility != TOTEM_CONTROLS_UNDEFINED)
                        totem_action_save_size (totem);
-               totem_fullscreen_set_fullscreen (totem->fs, TRUE);
 
                totem->controls_visibility = TOTEM_CONTROLS_FULLSCREEN;
                show_controls (totem, FALSE);
        } else {
-               totem_fullscreen_set_fullscreen (totem->fs, FALSE);
-
                totem->controls_visibility = TOTEM_CONTROLS_VISIBLE;
                show_controls (totem, TRUE);
        }
@@ -1432,7 +1422,10 @@ totem_action_fullscreen (TotemObject *totem, gboolean state)
        if (totem_object_is_fullscreen (totem) == state)
                return;
 
-       gtk_window_fullscreen (GTK_WINDOW (totem->win));
+       if (state)
+               gtk_window_fullscreen (GTK_WINDOW (totem->win));
+       else
+               gtk_window_unfullscreen (GTK_WINDOW (totem->win));
 }
 
 void
@@ -1562,26 +1555,19 @@ bail:
 static void
 update_mrl_label (TotemObject *totem, const char *name)
 {
-       if (name != NULL)
-       {
+       if (name != NULL) {
                /* Update the mrl label */
-               totem_fullscreen_set_title (totem->fs, name);
-
-               /* Title */
-               gtk_window_set_title (GTK_WINDOW (totem->win), name);
+               gtk_header_bar_set_title (GTK_HEADER_BAR (totem->header), name);
        } else {
-               totem_statusbar_set_time_and_length (TOTEM_STATUSBAR
-                               (totem->statusbar), 0, 0);
-               totem_statusbar_set_text (TOTEM_STATUSBAR (totem->statusbar),
-                               _("Stopped"));
+               bacon_time_label_set_time (totem->time_label,
+                                          0, 0);
+               bacon_time_label_set_time (totem->time_rem_label,
+                                          0, 0);
 
                g_object_notify (G_OBJECT (totem), "stream-length");
 
                /* Update the mrl label */
-               totem_fullscreen_set_title (totem->fs, NULL);
-
-               /* Title */
-               gtk_window_set_title (GTK_WINDOW (totem->win), _("Videos"));
+               gtk_header_bar_set_title (GTK_HEADER_BAR (totem->header), "");
        }
 }
 
@@ -1622,14 +1608,12 @@ totem_action_set_mrl (TotemObject *totem,
                totem_action_set_sensitivity ("play", FALSE);
 
                /* Volume */
-               totem_main_set_sensitivity ("tmw_volume_button", FALSE);
+               totem_controls_set_sensitivity ("volume_button", FALSE);
                totem_action_set_sensitivity ("volume-up", FALSE);
                totem_action_set_sensitivity ("volume-down", FALSE);
                totem->volume_sensitive = FALSE;
 
                /* Control popup */
-               totem_fullscreen_set_can_set_volume (totem->fs, FALSE);
-               totem_fullscreen_set_seekable (totem->fs, FALSE);
                totem_action_set_sensitivity ("next-chapter", FALSE);
                totem_action_set_sensitivity ("previous-chapter", FALSE);
 
@@ -1676,8 +1660,7 @@ totem_action_set_mrl (TotemObject *totem,
 
                /* Volume */
                caps = bacon_video_widget_can_set_volume (totem->bvw);
-               totem_main_set_sensitivity ("tmw_volume_button", caps);
-               totem_fullscreen_set_can_set_volume (totem->fs, caps);
+               totem_controls_set_sensitivity ("volume_button", caps);
                volume = bacon_video_widget_get_volume (totem->bvw);
                totem_action_set_sensitivity ("volume-up", caps && volume < (1.0 - VOLUME_EPSILON));
                totem_action_set_sensitivity ("volume-down", caps && volume > VOLUME_EPSILON);
@@ -1791,9 +1774,6 @@ totem_seek_time_rel (TotemObject *totem, gint64 _time, gboolean relative, gboole
        if (bacon_video_widget_is_seekable (totem->bvw) == FALSE)
                return;
 
-       totem_statusbar_set_seeking (TOTEM_STATUSBAR (totem->statusbar), TRUE);
-       totem_time_label_set_seeking (TOTEM_TIME_LABEL (totem->fs->time_label), TRUE);
-
        if (relative != FALSE) {
                gint64 oldmsec;
                oldmsec = bacon_video_widget_get_current_time (totem->bvw);
@@ -1804,9 +1784,6 @@ totem_seek_time_rel (TotemObject *totem, gint64 _time, gboolean relative, gboole
 
        bacon_video_widget_seek_time (totem->bvw, sec, accurate, &err);
 
-       totem_statusbar_set_seeking (TOTEM_STATUSBAR (totem->statusbar), FALSE);
-       totem_time_label_set_seeking (TOTEM_TIME_LABEL (totem->fs->time_label), FALSE);
-
        if (err != NULL)
        {
                char *msg, *disp;
@@ -2304,7 +2281,7 @@ on_error_event (BaconVideoWidget *bvw, char *message,
 static void
 on_buffering_event (BaconVideoWidget *bvw, gdouble percentage, TotemObject *totem)
 {
-       totem_statusbar_push (TOTEM_STATUSBAR (totem->statusbar), percentage);
+       //FIXME show that somehow
 }
 
 static void
@@ -2318,13 +2295,9 @@ update_fill (TotemObject *totem, gdouble level)
 {
        if (level < 0.0) {
                gtk_range_set_show_fill_level (GTK_RANGE (totem->seek), FALSE);
-               gtk_range_set_show_fill_level (GTK_RANGE (totem->fs->seek), FALSE);
        } else {
                gtk_range_set_fill_level (GTK_RANGE (totem->seek), level * 65535.0f);
                gtk_range_set_show_fill_level (GTK_RANGE (totem->seek), TRUE);
-
-               gtk_range_set_fill_level (GTK_RANGE (totem->fs->seek), level * 65535.0f);
-               gtk_range_set_show_fill_level (GTK_RANGE (totem->fs->seek), TRUE);
        }
 }
 
@@ -2343,10 +2316,6 @@ update_seekable (TotemObject *totem)
        /* Check if the stream is seekable */
        gtk_widget_set_sensitive (totem->seek, seekable);
 
-       totem_main_set_sensitivity ("tmw_seek_hbox", seekable);
-
-       totem_fullscreen_set_seekable (totem->fs, seekable);
-
        /* FIXME: We can use this code again once bug #457631 is fixed and
         * skip-* are back in the main action group. */
        /*totem_action_set_sensitivity ("skip-forward", seekable);
@@ -2384,10 +2353,8 @@ update_slider_visibility (TotemObject *totem,
                return;
        if (stream_length != 0) {
                gtk_range_set_range (GTK_RANGE (totem->seek), 0., 65535.);
-               gtk_range_set_range (GTK_RANGE (totem->fs->seek), 0., 65535.);
        } else {
                gtk_range_set_range (GTK_RANGE (totem->seek), 0., 0.);
-               gtk_range_set_range (GTK_RANGE (totem->fs->seek), 0., 0.);
        }
 }
 
@@ -2406,19 +2373,18 @@ update_current_time (BaconVideoWidget *bvw,
 
                if (stream_length == 0 && totem->mrl != NULL)
                {
-                       totem_statusbar_set_time_and_length
-                               (TOTEM_STATUSBAR (totem->statusbar),
-                               (int) (current_time / 1000), -1);
+                       bacon_time_label_set_time (totem->time_label,
+                                                  (current_time), -1);
+                       bacon_time_label_set_time (totem->time_rem_label,
+                                                  (current_time), -1);
                } else {
-                       totem_statusbar_set_time_and_length
-                               (TOTEM_STATUSBAR (totem->statusbar),
-                               (int) (current_time / 1000),
-                               (int) (stream_length / 1000));
+                       bacon_time_label_set_time (totem->time_label,
+                                                  current_time,
+                                                  stream_length);
+                       bacon_time_label_set_time (totem->time_rem_label,
+                                                  current_time,
+                                                  stream_length);
                }
-
-               totem_time_label_set_time
-                       (TOTEM_TIME_LABEL (totem->fs->time_label),
-                        current_time, stream_length);
        }
 
        if (totem->stream_length != stream_length) {
@@ -2476,10 +2442,6 @@ seek_slider_pressed_cb (GtkWidget *widget, GdkEventButton *event, TotemObject *t
        event->button = GDK_BUTTON_PRIMARY;
 
        totem->seek_lock = TRUE;
-       if (bacon_video_widget_can_direct_seek (totem->bvw) == FALSE) {
-               totem_statusbar_set_seeking (TOTEM_STATUSBAR (totem->statusbar), TRUE);
-               totem_time_label_set_seeking (TOTEM_TIME_LABEL (totem->fs->time_label), TRUE);
-       }
 
        return FALSE;
 }
@@ -2495,11 +2457,11 @@ seek_slider_changed_cb (GtkAdjustment *adj, TotemObject *totem)
 
        pos = gtk_adjustment_get_value (adj) / 65535;
        _time = bacon_video_widget_get_stream_length (totem->bvw);
-       totem_statusbar_set_time_and_length (TOTEM_STATUSBAR (totem->statusbar),
-                       (int) (pos * _time / 1000), _time / 1000);
-       totem_time_label_set_time
-                       (TOTEM_TIME_LABEL (totem->fs->time_label),
-                        (int) (pos * _time), _time);
+
+       bacon_time_label_set_time (totem->time_label,
+                                  pos * _time, _time);
+       bacon_time_label_set_time (totem->time_rem_label,
+                                  pos * _time, _time);
 
        if (bacon_video_widget_can_direct_seek (totem->bvw) != FALSE)
                totem_action_seek (totem, pos);
@@ -2525,9 +2487,6 @@ seek_slider_released_cb (GtkWidget *widget, GdkEventButton *event, TotemObject *
        if (bacon_video_widget_can_direct_seek (totem->bvw) == FALSE)
                totem_action_seek (totem, val / 65535.0);
 
-       totem_statusbar_set_seeking (TOTEM_STATUSBAR (totem->statusbar), FALSE);
-       totem_time_label_set_seeking (TOTEM_TIME_LABEL (totem->fs->time_label),
-                       FALSE);
        return FALSE;
 }
 
@@ -2634,7 +2593,7 @@ totem_action_open_files_list (TotemObject *totem, GSList *list)
 void
 show_controls (TotemObject *totem, gboolean was_fullscreen)
 {
-       GtkWidget *menubar, *controlbar, *statusbar, *bvw_box, *widget;
+       GtkWidget *menubar, *bvw_box, *widget;
        GtkAllocation allocation;
        int width = 0, height = 0;
 
@@ -2642,8 +2601,6 @@ show_controls (TotemObject *totem, gboolean was_fullscreen)
                return;
 
        menubar = GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_menubar_box"));
-       controlbar = GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_controls_vbox"));
-       statusbar = GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_statusbar"));
        bvw_box = GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_bvw_box"));
        widget = GTK_WIDGET (totem->bvw);
 
@@ -2657,8 +2614,6 @@ show_controls (TotemObject *totem, gboolean was_fullscreen)
 
                gtk_widget_set_sensitive (menubar, TRUE);
                gtk_widget_show (menubar);
-               gtk_widget_show (controlbar);
-               gtk_widget_show (statusbar);
                if (totem_sidebar_is_visible (totem) != FALSE) {
                        /* This is uglier then you might expect because of the
                           resize handle between the video and sidebar. There
@@ -2687,15 +2642,9 @@ show_controls (TotemObject *totem, gboolean was_fullscreen)
 
                if (was_fullscreen == FALSE) {
                        GtkAllocation allocation_menubar;
-                       GtkAllocation allocation_controlbar;
-                       GtkAllocation allocation_statusbar;
 
                        gtk_widget_get_allocation (menubar, &allocation_menubar);
-                       gtk_widget_get_allocation (controlbar, &allocation_controlbar);
-                       gtk_widget_get_allocation (statusbar, &allocation_statusbar);
-                       height += allocation_menubar.height
-                               + allocation_controlbar.height
-                               + allocation_statusbar.height;
+                       height += allocation_menubar.height;
                        gtk_window_resize (GTK_WINDOW(totem->win),
                                        width, height);
                }
@@ -2704,8 +2653,6 @@ show_controls (TotemObject *totem, gboolean was_fullscreen)
                gtk_widget_set_sensitive (menubar, FALSE);
                gtk_widget_hide (menubar);
 
-               gtk_widget_hide (controlbar);
-               gtk_widget_hide (statusbar);
                gtk_widget_hide (totem->sidebar);
 
                 /* We won't show controls in fullscreen */
@@ -2892,10 +2839,12 @@ totem_object_action_remote (TotemObject *totem, TotemRemoteCommand cmd, const ch
                break;
        }
 
+#if 0
        if (handled != FALSE
            && gtk_window_is_active (GTK_WINDOW (totem->win))) {
                totem_fullscreen_show_popups_or_osd (totem->fs, icon_name, TRUE);
        }
+#endif
 }
 
 /**
@@ -3113,8 +3062,10 @@ totem_object_is_seekable (TotemObject *totem)
 static void
 on_mouse_click_fullscreen (GtkWidget *widget, TotemObject *totem)
 {
+#if 0
        if (totem_fullscreen_is_fullscreen (totem->fs) != FALSE)
                totem_fullscreen_show_popups (totem->fs, TRUE);
+#endif
 }
 
 static gboolean
@@ -3133,7 +3084,7 @@ on_video_button_press_event (BaconVideoWidget *bvw, GdkEventButton *event,
                        icon_name = "media-playback-start-symbolic";
                else
                        icon_name = "media-playback-pause-symbolic";
-               totem_fullscreen_show_popups_or_osd (totem->fs, icon_name, FALSE);
+               //totem_fullscreen_show_popups_or_osd (totem->fs, icon_name, FALSE);
                totem_object_action_play_pause (totem);
                return TRUE;
        } else if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
@@ -3185,24 +3136,6 @@ on_eos_event (GtkWidget *widget, TotemObject *totem)
        return FALSE;
 }
 
-static gboolean
-totem_action_handle_key_release (TotemObject *totem, GdkEventKey *event)
-{
-       gboolean retval = TRUE;
-
-       switch (event->keyval) {
-       case GDK_KEY_Left:
-       case GDK_KEY_Right:
-               totem_statusbar_set_seeking (TOTEM_STATUSBAR (totem->statusbar), FALSE);
-               totem_time_label_set_seeking (TOTEM_TIME_LABEL (totem->fs->time_label), FALSE);
-               break;
-       default:
-               retval = FALSE;
-       }
-
-       return retval;
-}
-
 static void
 totem_action_handle_seek (TotemObject *totem, GdkEventKey *event, gboolean is_forward)
 {
@@ -3471,11 +3404,12 @@ totem_action_handle_key_press (TotemObject *totem, GdkEventKey *event)
                retval = FALSE;
        }
 
+#if 0
        if (icon_name != NULL)
                totem_fullscreen_show_popups_or_osd (totem->fs,
                                                     icon_name,
                                                     FALSE);
-
+#endif
        return retval;
 }
 
@@ -3489,8 +3423,8 @@ totem_action_handle_scroll (TotemObject    *totem,
 
        direction = sevent->direction;
 
-       if (totem_fullscreen_is_fullscreen (totem->fs) != FALSE)
-               totem_fullscreen_show_popups (totem->fs, TRUE);
+//     if (totem_fullscreen_is_fullscreen (totem->fs) != FALSE)
+//             totem_fullscreen_show_popups (totem->fs, TRUE);
 
        if (direction == GDK_SCROLL_SMOOTH) {
                gdouble y;
@@ -3560,8 +3494,6 @@ window_key_press_event_cb (GtkWidget *win, GdkEventKey *event, TotemObject *tote
                case GDK_KEY_hyphen:
                        if (event->type == GDK_KEY_PRESS)
                                return totem_action_handle_key_press (totem, event);
-                       else
-                               return totem_action_handle_key_release (totem, event);
                default:
                        break;
                }
@@ -3572,8 +3504,6 @@ window_key_press_event_cb (GtkWidget *win, GdkEventKey *event, TotemObject *tote
                case GDK_KEY_Escape:
                        if (event->type == GDK_KEY_PRESS)
                                return totem_action_handle_key_press (totem, event);
-                       else
-                               return totem_action_handle_key_release (totem, event);
                default:
                        break;
                }
@@ -3590,11 +3520,10 @@ window_key_press_event_cb (GtkWidget *win, GdkEventKey *event, TotemObject *tote
                        || (event->state & GDK_MOD4_MASK)))
                return FALSE;
 
-       if (event->type == GDK_KEY_PRESS) {
+       if (event->type == GDK_KEY_PRESS)
                return totem_action_handle_key_press (totem, event);
-       } else {
-               return totem_action_handle_key_release (totem, event);
-       }
+
+       return FALSE;
 }
 
 gboolean
@@ -3748,6 +3677,46 @@ totem_setup_window (TotemObject *totem)
        return page_id;
 }
 
+static gboolean
+fullscreen_button_image_sync (GBinding     *binding,
+                             const GValue *source_value,
+                             GValue       *target_value,
+                             gpointer      user_data)
+{
+       gboolean state;
+
+       state = g_value_get_boolean (source_value);
+       g_value_set_string (target_value, state ? "view-restore-symbolic" : "view-fullscreen-symbolic");
+
+       return TRUE;
+}
+
+static GtkWidget *
+create_control_button (TotemObject *totem,
+                      const gchar *action_name,
+                      const gchar *tooltip_text)
+{
+       GtkWidget *button, *image;
+       GtkAction *action;
+
+       button = gtk_button_new ();
+       image = gtk_image_new ();
+       gtk_button_set_image (GTK_BUTTON (button), image);
+       gtk_style_context_add_class (gtk_widget_get_style_context (button), "image-button");
+
+       action = gtk_action_group_get_action (totem->main_action_group,
+                                             action_name);
+       gtk_activatable_set_related_action (GTK_ACTIVATABLE (button), action);
+
+       gtk_button_set_label (GTK_BUTTON (button), NULL);
+       gtk_widget_set_tooltip_text (button, tooltip_text);
+       atk_object_set_name (gtk_widget_get_accessible (button), tooltip_text);
+
+       gtk_widget_show_all (button);
+
+       return button;
+}
+
 void
 totem_callback_connect (TotemObject *totem)
 {
@@ -3767,54 +3736,44 @@ totem_callback_connect (TotemObject *totem)
                                   g_variant_new_boolean (totem_playlist_get_shuffle (totem->playlist)));
 
        /* Controls */
-       box = GTK_BOX (gtk_builder_get_object (totem->xml, "tmw_buttons_hbox"));
+       box = g_object_get_data (totem->controls, "controls_box");
 
        /* Previous */
-       action = gtk_action_group_get_action (totem->main_action_group,
-                       "previous-chapter");
-       item = gtk_action_create_tool_item (action);
-       gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (item), 
-                                       _("Previous Chapter/Movie"));
-       atk_object_set_name (gtk_widget_get_accessible (item),
-                       _("Previous Chapter/Movie"));
+       item = create_control_button (totem, "previous-chapter",
+                                     _("Previous Chapter/Movie"));
        gtk_box_pack_start (box, item, FALSE, FALSE, 0);
 
        /* Play/Pause */
-       action = gtk_action_group_get_action (totem->main_action_group, "play");
-       item = gtk_action_create_tool_item (action);
-       atk_object_set_name (gtk_widget_get_accessible (item),
-                       _("Play / Pause"));
-       gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (item),
-                                       _("Play / Pause"));
+       item = create_control_button (totem, "play",
+                                     _("Play / Pause"));
        gtk_box_pack_start (box, item, FALSE, FALSE, 0);
 
        /* Next */
-       action = gtk_action_group_get_action (totem->main_action_group,
-                       "next-chapter");
-       item = gtk_action_create_tool_item (action);
-       gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (item), 
-                                       _("Next Chapter/Movie"));
-       atk_object_set_name (gtk_widget_get_accessible (item),
-                       _("Next Chapter/Movie"));
-       gtk_box_pack_start (box, item, FALSE, FALSE, 0);
-
-       /* Separator */
-       item = GTK_WIDGET(gtk_separator_tool_item_new ());
+       item = create_control_button (totem, "next-chapter",
+                                     _("Next Chapter/Movie"));
        gtk_box_pack_start (box, item, FALSE, FALSE, 0);
 
        /* Fullscreen button */
-       /* Translators: this is the tooltip text for the fullscreen button in the controls box in Totem's 
main window. */
-       item = GTK_WIDGET (gtk_toggle_tool_button_new ());
-       gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), "view-fullscreen-symbolic");
-       gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (item), _("Fullscreen"));
-       /* Translators: this is the accessibility text for the fullscreen button in the controls box in 
Totem's main window. */
-       atk_object_set_name (gtk_widget_get_accessible (item), _("Fullscreen"));
-       gtk_actionable_set_action_name (GTK_ACTIONABLE (item), "app.fullscreen");
-       gtk_widget_show (item);
-       gtk_box_pack_start (box, item, FALSE, FALSE, 0);
+       item = g_object_get_data (totem->controls, "fullscreen_button");
+       image = gtk_image_new ();
+       gtk_button_set_image (GTK_BUTTON (item), image);
+       g_object_bind_property_full (totem, "fullscreen",
+                                    image, "icon-name",
+                                    G_BINDING_SYNC_CREATE,
+                                    fullscreen_button_image_sync,
+                                    NULL, NULL, NULL);
+
+       /* Seekbar */
+       g_signal_connect (totem->seek, "button-press-event",
+                         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 (window_scroll_event_cb), totem);
+       g_signal_connect (totem->seekadj, "value-changed",
+                         G_CALLBACK (seek_slider_changed_cb), totem);
 
        /* Sidebar button (Drag'n'Drop) */
-       box = GTK_BOX (gtk_builder_get_object (totem->xml, "tmw_sidebar_button_hbox"));
        action = gtk_action_group_get_action (totem->main_action_group, "sidebar");
        item = gtk_toggle_button_new ();
        gtk_activatable_set_related_action (GTK_ACTIVATABLE (item), action);
@@ -3829,7 +3788,7 @@ totem_callback_connect (TotemObject *totem)
        image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_BUTTON);
        gtk_widget_show (image);
        gtk_container_add (GTK_CONTAINER (item), image);
-       gtk_box_pack_start (box, item, FALSE, FALSE, 0);
+       gtk_header_bar_pack_end (GTK_HEADER_BAR (totem->header), item);
        g_signal_connect (G_OBJECT (item), "drag_data_received",
                        G_CALLBACK (drop_playlist_cb), totem);
        g_signal_connect (G_OBJECT (item), "drag_motion",
@@ -3838,44 +3797,12 @@ totem_callback_connect (TotemObject *totem)
                        target_table, G_N_ELEMENTS (target_table),
                        GDK_ACTION_COPY | GDK_ACTION_MOVE);
 
-       /* Fullscreen window buttons */
-       g_signal_connect (G_OBJECT (totem->fs->exit_button), "clicked",
-                         G_CALLBACK (fs_exit1_activate_cb), totem);
-
-       action = gtk_action_group_get_action (totem->main_action_group, "play");
-       item = gtk_action_create_tool_item (action);
-       gtk_box_pack_start (GTK_BOX (totem->fs->buttons_box), item, FALSE, FALSE, 0);
-       g_signal_connect (G_OBJECT (item), "clicked",
-                       G_CALLBACK (on_mouse_click_fullscreen), totem);
-
-       action = gtk_action_group_get_action (totem->main_action_group, "previous-chapter");
-       item = gtk_action_create_tool_item (action);
-       gtk_box_pack_start (GTK_BOX (totem->fs->buttons_box), item, FALSE, FALSE, 0);
-       g_signal_connect (G_OBJECT (item), "clicked",
-                       G_CALLBACK (on_mouse_click_fullscreen), totem);
-
-       action = gtk_action_group_get_action (totem->main_action_group, "next-chapter");
-       item = gtk_action_create_tool_item (action);
-       gtk_box_pack_start (GTK_BOX (totem->fs->buttons_box), item, FALSE, FALSE, 0);
-       g_signal_connect (G_OBJECT (item), "clicked",
-                       G_CALLBACK (on_mouse_click_fullscreen), totem);
-
        /* Connect the keys */
        gtk_widget_add_events (totem->win, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
 
        /* Connect the mouse wheel */
        gtk_widget_add_events (GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_main_vbox")), 
GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK);
        gtk_widget_add_events (totem->seek, GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK);
-       gtk_widget_add_events (totem->fs->seek, GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK);
-
-       /* FIXME Hack to fix bug #462286 and #563894 */
-       g_signal_connect (G_OBJECT (totem->fs->seek), "button-press-event",
-                       G_CALLBACK (seek_slider_pressed_cb), totem);
-       g_signal_connect (G_OBJECT (totem->fs->seek), "button-release-event",
-                       G_CALLBACK (seek_slider_released_cb), totem);
-       g_signal_connect (G_OBJECT (totem->fs->seek), "scroll-event",
-                         G_CALLBACK (window_scroll_event_cb), totem);
-
 
        /* Set sensitivity of the toolbar buttons */
        totem_action_set_sensitivity ("play", FALSE);
@@ -3893,6 +3820,14 @@ totem_callback_connect (TotemObject *totem)
 
        action = gtk_action_group_get_action (action_group, "skip-backwards");
        gtk_action_set_sensitive (action, FALSE);
+
+       /* Volume */
+       g_signal_connect (G_OBJECT (totem->bvw), "notify::volume",
+                       G_CALLBACK (property_notify_cb_volume), totem);
+       g_signal_connect (G_OBJECT (totem->bvw), "notify::seekable",
+                       G_CALLBACK (property_notify_cb_seekable), totem);
+       update_volume_sliders (totem);
+
 }
 
 void
@@ -3935,6 +3870,7 @@ video_widget_create (TotemObject *totem)
        GError *err = NULL;
        GtkContainer *container;
        BaconVideoWidget **bvw;
+       GObject *header;
 
        totem->bvw = BACON_VIDEO_WIDGET (bacon_video_widget_new (&err));
 
@@ -3944,6 +3880,10 @@ video_widget_create (TotemObject *totem)
                        g_error_free (err);
        }
 
+       totem->controls = bacon_video_widget_get_controls_object (totem->bvw);
+       header = bacon_video_widget_get_header_object (totem->bvw);
+       totem->header = g_object_get_data (G_OBJECT (header), "header");
+
        g_signal_connect_after (G_OBJECT (totem->bvw),
                        "button-press-event",
                        G_CALLBACK (on_video_button_press_event),
@@ -4012,12 +3952,6 @@ video_widget_create (TotemObject *totem)
        gtk_widget_show (GTK_WIDGET (totem->bvw));
 
        totem_preferences_visuals_setup (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::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 0952052..6fbf5e5 100644
--- a/src/totem-private.h
+++ b/src/totem-private.h
@@ -33,8 +33,8 @@
 
 #include "totem-playlist.h"
 #include "backend/bacon-video-widget.h"
+#include "backend/bacon-time-label.h"
 #include "totem-open-location.h"
-#include "totem-fullscreen.h"
 #include "totem-plugins-engine.h"
 
 #define totem_signal_block_by_data(obj, data) (g_signal_handlers_block_matched (obj, G_SIGNAL_MATCH_DATA, 0, 
0, NULL, NULL, data))
@@ -46,7 +46,7 @@
                widget = GTK_WIDGET (gtk_builder_get_object (xml, name));       \
                gtk_widget_set_sensitive (widget, state);                       \
        }
-#define totem_main_set_sensitivity(name, state) totem_set_sensitivity (totem->xml, name, state)
+#define totem_controls_set_sensitivity(name, state) gtk_widget_set_sensitive (g_object_get_data 
(totem->controls, name), state)
 
 #define totem_action_set_sensitivity(name, state)                                      \
        {                                                                               \
@@ -76,7 +76,11 @@ struct _TotemObject {
        BaconVideoWidget *bvw;
        GtkWidget *prefs;
        GtkBuilder *prefs_xml;
-       GtkWidget *statusbar;
+
+       GObject *controls;
+       BaconTimeLabel *time_label;
+       BaconTimeLabel *time_rem_label;
+       GtkWidget *header;
 
        /* UI manager */
        GtkActionGroup *main_action_group;
@@ -118,9 +122,6 @@ struct _TotemObject {
        GList *subtitles_list;
        GList *language_list;
 
-       /* Fullscreen */
-       TotemFullscreen *fs;
-
        /* controls management */
        ControlsVisibility controls_visibility;
 
diff --git a/src/totem-sidebar.c b/src/totem-sidebar.c
index d607c7e..b77ecec 100644
--- a/src/totem-sidebar.c
+++ b/src/totem-sidebar.c
@@ -107,7 +107,7 @@ has_popup (void)
 gboolean
 totem_sidebar_is_focused (Totem *totem, gboolean *handles_kbd)
 {
-       GtkWidget *focused, *sidebar_button;
+       GtkWidget *focused;
 
        if (handles_kbd != NULL)
                *handles_kbd = has_popup ();
@@ -117,9 +117,6 @@ totem_sidebar_is_focused (Totem *totem, gboolean *handles_kbd)
                return FALSE;
        if (gtk_widget_is_ancestor (focused, GTK_WIDGET (totem->sidebar)) != FALSE)
                return TRUE;
-       sidebar_button = GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_sidebar_button_hbox"));
-       if (gtk_widget_is_ancestor (focused, sidebar_button) != FALSE)
-               return TRUE;
 
        return FALSE;
 }
diff --git a/src/totem.c b/src/totem.c
index 72300e9..ca317d0 100644
--- a/src/totem.c
+++ b/src/totem.c
@@ -104,20 +104,13 @@ app_init (Totem *totem, char **argv)
 
        /* The rest of the widgets */
        totem->state = STATE_STOPPED;
-       totem->seek = GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_seek_hscale"));
-       totem->seekadj = gtk_range_get_adjustment (GTK_RANGE (totem->seek));
-       totem->volume = GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_volume_button"));
-       totem->statusbar = GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_statusbar"));
+
        totem->seek_lock = FALSE;
-       totem->fs = totem_fullscreen_new (GTK_WINDOW (totem->win));
-       gtk_scale_button_set_adjustment (GTK_SCALE_BUTTON (totem->fs->volume),
-                                        gtk_scale_button_get_adjustment (GTK_SCALE_BUTTON (totem->volume)));
-       gtk_range_set_adjustment (GTK_RANGE (totem->fs->seek), totem->seekadj);
 
        totem_setup_file_monitoring (totem);
        totem_setup_file_filters ();
        totem_app_menu_setup (totem);
-       totem_callback_connect (totem);
+       /* totem_callback_connect (totem); XXX we do this later now, so it might look ugly for a short while 
*/
 
        sidebar_pageid = totem_setup_window (totem);
 
@@ -133,8 +126,16 @@ app_init (Totem *totem, char **argv)
 
        /* Show ! (again) the video widget this time. */
        video_widget_create (totem);
+
+       totem->seek = g_object_get_data (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_callback_connect (totem);
+
        gtk_widget_grab_focus (GTK_WIDGET (totem->bvw));
-       totem_fullscreen_set_video_widget (totem->fs, totem->bvw);
 
        if (optionstate.fullscreen != FALSE) {
                gtk_widget_show (totem->win);
@@ -174,7 +175,7 @@ app_init (Totem *totem, char **argv)
 
 static void
 app_startup (GApplication *application,
-               Totem        *totem)
+            Totem        *totem)
 {
        /* We don't do anything here, as we need to know the options
         * when we set everything up.


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