totem r5948 - in trunk: . src src/plugins



Author: pwithnall
Date: Sat Feb  7 15:28:03 2009
New Revision: 5948
URL: http://svn.gnome.org/viewvc/totem?rev=5948&view=rev

Log:
2009-02-07  Philip Withnall  <philip tecnocode co uk>

	* src/Makefile.am:
	* src/plugins/totem-plugin.c:
	* src/plugins/totem-plugin.h:
	* src/totem-object.c (reset_seek_status), (totem_action_error),
	(totem_action_error_and_exit), (totem_action_save_size),
	(totem_action_save_state), (totem_action_wait_force_exit),
	(totem_action_exit), (totem_action_menu_popup),
	(main_window_destroy_cb), (play_pause_set_label),
	(totem_action_eject), (totem_action_show_properties),
	(totem_action_play), (totem_action_seek),
	(totem_action_set_mrl_and_play), (totem_action_open_dialog),
	(totem_dvb_setup_result), (totem_action_load_media),
	(totem_action_load_media_device), 
(totem_action_play_media_device),
	(totem_action_play_media), (totem_action_stop),
	(totem_action_play_pause), (totem_action_pause),
	(window_state_event_cb), (totem_action_fullscreen_toggle),
	(totem_action_fullscreen), (fs_exit1_activate_cb),
	(totem_action_open), (totem_open_location_destroy),
	(totem_open_location_response_cb), (totem_action_open_location),
	(totem_get_nice_name_for_stream), (update_mrl_label),
	(totem_action_set_mrl_with_warning), (totem_action_set_mrl),
	(totem_time_within_seconds), (totem_action_direction),
	(totem_action_previous), (totem_action_next),
	(totem_seek_time_rel), (totem_action_seek_relative),
	(totem_action_seek_time), (totem_action_zoom),
	(totem_action_zoom_relative), (totem_action_zoom_reset),
	(totem_action_volume_relative), 
(totem_action_volume_toggle_mute),
	(totem_action_toggle_aspect_ratio),
	(totem_action_set_aspect_ratio), 
(totem_action_get_aspect_ratio),
	(totem_action_set_scale_ratio), (totem_action_show_help),
	(totem_action_drop_files), (drop_video_cb), 
(drag_motion_video_cb),
	(drop_playlist_cb), (drag_motion_playlist_cb), (drag_video_cb),
	(on_got_redirect), (on_title_change_event),
	(on_channels_change_event), (on_playlist_change_name),
	(on_got_metadata_event), (on_error_event), (on_buffering_event),
	(update_seekable), (update_current_time),
	(volume_button_value_changed_cb), (update_volume_sliders),
	(property_notify_cb_volume), (property_notify_cb_logo_mode),
	(property_notify_cb_seekable), (seek_slider_pressed_cb),
	(seek_slider_changed_cb), (seek_slider_released_cb),
	(totem_action_open_files), (totem_action_open_files_list),
	(show_controls), (totem_action_toggle_controls),
	(totem_action_next_angle), (totem_action_set_playlist_index),
	(totem_action_remote), (totem_action_remote_set_setting),
	(totem_action_remote_get_setting), (playlist_changed_cb),
	(item_activated_cb), (current_removed_cb), 
(subtitle_changed_cb),
	(playlist_repeat_toggle_cb), (playlist_shuffle_toggle_cb),
	(totem_is_fullscreen), (totem_is_playing), (totem_is_paused),
	(totem_is_seekable), (on_mouse_click_fullscreen),
	(on_video_button_press_event), (on_eos_event),
	(totem_action_handle_key_release), (totem_action_handle_seek),
	(totem_action_handle_key_press), (totem_action_handle_scroll),
	(window_key_press_event_cb), (window_scroll_event_cb),
	(update_media_menu_items), (update_buttons),
	(main_pane_size_allocated), (totem_setup_window),
	(totem_callback_connect), (playlist_widget_setup),
	(video_widget_create):
	* src/totem-private.h:
	* src/totem.c: Move most of totem.c into totem-object.c and 
break
	the core of Totem out to a noinst library, libtotem_main.la.
	This allows gtk-doc to be run on it. (Helps: #570861)



Modified:
   trunk/ChangeLog
   trunk/src/Makefile.am
   trunk/src/plugins/totem-plugin.c
   trunk/src/plugins/totem-plugin.h
   trunk/src/totem-object.c
   trunk/src/totem-private.h
   trunk/src/totem.c

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Sat Feb  7 15:28:03 2009
@@ -4,7 +4,8 @@
 libexec_PROGRAMS =
 noinst_LTLIBRARIES =				\
 	libbaconmessageconnection.la		\
-	libtotem_player.la
+	libtotem_player.la			\
+	libtotem_main.la
 
 common_defines = \
 	-D_REENTRANT					\
@@ -46,16 +47,16 @@
 regenerate-built-sources:
 	EGGFILES="$(BACON_MESSAGE_CONNECTION)" EGGDIR="$(BACONDIR)" $(srcdir)/update-from-egg.sh || true
 
-# Totem UI ltlibrary
+# Totem UI ltlibrary (used by browser plugins)
 
-libtotem_player_la_SOURCES =		\
-	totem-statusbar.c		\
-	totem-statusbar.h		\
-	totem-interface.c		\
-	totem-interface.h		\
-	totem-fullscreen.c		\
-	totem-fullscreen.h		\
-	totem-time-label.c		\
+libtotem_player_la_SOURCES = \
+	totem-statusbar.c	\
+	totem-statusbar.h	\
+	totem-interface.c	\
+	totem-interface.h	\
+	totem-fullscreen.c	\
+	totem-fullscreen.h	\
+	totem-time-label.c	\
 	totem-time-label.h
 
 libtotem_player_la_CPPFLAGS = \
@@ -70,8 +71,103 @@
 	$(AM_CFLAGS)
 
 libtotem_player_la_LDFLAGS = \
+	$(AM_LDFLAGS) 
+
+# Totem main library (used for main player; separate to allow gtk-doc to be used)
+
+libtotem_main_la_SOURCES = \
+	$(TOTEMMARSHALFILES)		\
+	totem-object.c			\
+	totem.h				\
+	totem-private.h			\
+	totem-cell-renderer-video.c	\
+	totem-cell-renderer-video.h	\
+	totem-video-list.c		\
+	totem-video-list.h		\
+	totem-preferences.c		\
+	totem-preferences.h		\
+	totem-dnd-menu.c		\
+	totem-dnd-menu.h 		\
+	totem-options.c			\
+	totem-options.h			\
+	totem-playlist.c		\
+	totem-playlist.h		\
+	eggfileformatchooser.c		\
+	eggfileformatchooser.h		\
+	totem-session.c			\
+	totem-session.h			\
+	totem-sidebar.c			\
+	totem-sidebar.h 		\
+	totem-open-location.c		\
+	totem-open-location.h 		\
+	totem-menu.c			\
+	totem-menu.h			\
+	totem-uri.c			\
+	totem-uri.h			\
+	ev-sidebar.c			\
+	ev-sidebar.h			\
+	totem-subtitle-encoding.c	\
+	totem-subtitle-encoding.h	\
+	totem-dvb-setup.c		\
+	totem-dvb-setup.h
+
+libtotem_main_la_CPPFLAGS = \
+	-I$(top_srcdir)/		\
+	-I$(srcdir)/backend		\
+	-I$(srcdir)/plugins		\
+	-I$(top_builddir)/data		\
+	$(common_defines)		\
+	$(AM_CPPFLAGS)
+
+libtotem_main_la_CFLAGS = \
+	$(DEPENDENCY_CFLAGS)		\
+	$(WARN_CFLAGS)			\
+	$(DBUS_CFLAGS)			\
+	$(MISSING_PLUGINS_CFLAGS)	\
+	$(AM_CFLAGS)
+
+libtotem_main_la_LDFLAGS = \
 	$(AM_LDFLAGS)
 
+libtotem_main_la_LIBADD = \
+	libtotem_player.la		\
+	backend/libbaconvideowidget.la	\
+	plugins/libtotemmodule.la	\
+	libbaconmessageconnection.la	\
+	$(DBUS_LIBS)			\
+	$(XVIDMODE_LIBS)		\
+	$(XTEST_LIBS)			\
+	$(X_LIBS)
+
+if WITH_SMCLIENT
+libtotem_main_la_SOURCES += \
+	eggdesktopfile.c \
+	eggdesktopfile.h \
+	eggsmclient.c \
+	eggsmclient.h \
+	eggsmclient-private.h \
+	$(NULL)
+libtotem_main_la_CFLAGS += $(SMCLIENT_CFLAGS)
+libtotem_main_la_LIBADD += $(SMCLIENT_LIBS)
+
+if WITH_SMCLIENT_XSMP
+libtotem_main_la_SOURCES += eggsmclient-xsmp.c
+libtotem_main_la_CPPFLAGS += -DEGG_SM_CLIENT_BACKEND_XSMP
+endif
+if WITH_SMCLIENT_WIN32
+libtotem_main_la_SOURCES += eggsmclient-win32.c
+endif
+if WITH_SMCLIENT_QUARTZ
+libtotem_main_la_SOURCES += eggsmclient-osx.c
+endif
+endif
+
+if ENABLE_PYTHON
+libtotem_main_la_LIBADD += \
+	$(PYTHON_LIBS)						\
+	$(top_builddir)/bindings/python/totem-python.la
+endif
+
 # Totem
 
 TOTEMMARSHALFILES = 						\
@@ -94,89 +190,29 @@
 totemvideolist-marshal.c: totemvideolist-marshal.h Makefile
 	( $(GLIB_GENMARSHAL) --prefix=totemvideolist_marshal $(srcdir)/totemvideolist-marshal.list --header --body > totemvideolist-marshal.c )
 
-totem_SOURCES = 					\
-	totem.c totem.h					\
-	totem-object.c					\
-	$(TOTEMMARSHALFILES)				\
-	totem-private.h					\
-	totem-preferences.c totem-preferences.h		\
-	totem-dnd-menu.c totem-dnd-menu.h 		\
-	totem-options.c totem-options.h			\
-	totem-playlist.c totem-playlist.h		\
-	eggfileformatchooser.c eggfileformatchooser.h	\
-	totem-session.c totem-session.h	\
-	totem-sidebar.c totem-sidebar.h \
-	totem-open-location.c totem-open-location.h \
-	totem-menu.c totem-menu.h	\
-	totem-uri.c totem-uri.h		\
-	ev-sidebar.c ev-sidebar.h	\
-	totem-subtitle-encoding.c	\
-	totem-subtitle-encoding.h	\
-	totem-cell-renderer-video.c	\
-	totem-cell-renderer-video.h	\
-	totem-video-list.c		\
-	totem-video-list.h		\
-	totem-dvb-setup.c		\
-	totem-dvb-setup.h
+totem_SOURCES = totem.c
 
 totem_CPPFLAGS = \
 	-I$(top_srcdir)/		\
 	-I$(srcdir)/backend		\
-	-I$(srcdir)/plugins		\
-	-I$(top_builddir)/data		\
 	$(common_defines)		\
 	$(AM_CPPFLAGS)
 
 totem_CFLAGS = \
 	$(WARN_CFLAGS)			\
 	$(DEPENDENCY_CFLAGS)		\
-	$(DBUS_CFLAGS)			\
-	$(MISSING_PLUGINS_CFLAGS) \
 	$(AM_CFLAGS)
 
 totem_LDFLAGS = \
 	$(AM_LDFLAGS)
 
 totem_LDADD =						\
-	backend/libbaconvideowidget.la			\
-	plugins/libtotemmodule.la			\
-	libbaconmessageconnection.la			\
-	libtotem_player.la				\
+	libtotem_main.la				\
 	$(DEPENDENCY_LIBS)				\
 	$(XVIDMODE_LIBS)				\
-	$(DBUS_LIBS)					\
 	$(XTEST_LIBS)					\
 	$(X_LIBS)
 
-if WITH_SMCLIENT
-totem_SOURCES += \
-	eggdesktopfile.c \
-	eggdesktopfile.h \
-	eggsmclient.c \
-	eggsmclient.h \
-	eggsmclient-private.h \
-	$(NULL)
-totem_CFLAGS += $(SMCLIENT_CFLAGS)
-totem_LDADD += $(SMCLIENT_LIBS)
-
-if WITH_SMCLIENT_XSMP
-totem_SOURCES += eggsmclient-xsmp.c
-totem_CPPFLAGS += -DEGG_SM_CLIENT_BACKEND_XSMP
-endif
-if WITH_SMCLIENT_WIN32
-totem_SOURCES += eggsmclient-win32.c
-endif
-if WITH_SMCLIENT_QUARTZ
-totem_SOURCES += eggsmclient-osx.c
-endif
-endif
-
-if ENABLE_PYTHON
-totem_LDADD += \
-	$(PYTHON_LIBS)			\
-	$(top_builddir)/bindings/python/totem-python.la
-endif
-
 # Totem video thumbnailer
 
 totem_video_thumbnailer_SOURCES =	\

Modified: trunk/src/plugins/totem-plugin.c
==============================================================================
--- trunk/src/plugins/totem-plugin.c	(original)
+++ trunk/src/plugins/totem-plugin.c	Sat Feb  7 15:28:03 2009
@@ -60,9 +60,9 @@
 				       GValue *value,
 				       GParamSpec *pspec);
 
-typedef struct {
+struct TotemPluginPrivate {
 	char *name;
-} TotemPluginPrivate;
+};
 
 enum
 {

Modified: trunk/src/plugins/totem-plugin.h
==============================================================================
--- trunk/src/plugins/totem-plugin.h	(original)
+++ trunk/src/plugins/totem-plugin.h	Sat Feb  7 15:28:03 2009
@@ -49,8 +49,7 @@
 /*
  * Main object structure
  */
-typedef struct
-{
+typedef struct {
 	GObject parent;
 } TotemPlugin;
 
@@ -63,8 +62,7 @@
 /*
  * Class definition
  */
-typedef struct
-{
+typedef struct {
 	GObjectClass parent_class;
 
 	/* Virtual public methods */
@@ -88,6 +86,8 @@
 	TOTEM_PLUGIN_ERROR_ACTIVATION
 } TotemPluginError;
 
+typedef struct TotemPluginPrivate	TotemPluginPrivate;
+
 GType totem_plugin_error_get_type	(void);
 GQuark totem_plugin_error_quark 	(void);
 #define TOTEM_TYPE_PLUGIN_ERROR		(totem_remote_command_get_type())

Modified: trunk/src/totem-object.c
==============================================================================
--- trunk/src/totem-object.c	(original)
+++ trunk/src/totem-object.c	Sat Feb  7 15:28:03 2009
@@ -30,7 +30,7 @@
  * SECTION:totem-object
  * @short_description: main object
  * @stability: Unstable
- * @include: totem-object.h
+ * @include: totem.h
  *
  * #TotemObject is the core object of Totem; a singleton which controls all Totem's main functions.
  **/
@@ -39,6 +39,23 @@
 
 #include <glib-object.h>
 #include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include <totem-disc.h>
+#include <stdlib.h>
+#include <math.h>
+#include <gio/gio.h>
+
+#include <string.h>
+
+#ifdef GDK_WINDOWING_X11
+/* X11 headers */
+#include <gdk/gdkx.h>
+#include <X11/Xlib.h>
+#ifdef HAVE_XFREE
+#include <X11/XF86keysym.h>
+#endif
+#endif
 
 #include "totem.h"
 #include "totemobject-marshal.h"
@@ -47,6 +64,63 @@
 #include "ev-sidebar.h"
 #include "totem-playlist.h"
 #include "bacon-video-widget.h"
+#include "totem-dvb-setup.h"
+#include "totem-statusbar.h"
+#include "totem-time-label.h"
+#include "totem-sidebar.h"
+#include "totem-menu.h"
+#include "totem-uri.h"
+#include "totem-interface.h"
+#include "video-utils.h"
+#include "totem-dnd-menu.h"
+#include "totem-preferences.h"
+
+#include "debug.h"
+
+#define REWIND_OR_PREVIOUS 4000
+
+#define SEEK_FORWARD_SHORT_OFFSET 15
+#define SEEK_BACKWARD_SHORT_OFFSET -5
+
+#define SEEK_FORWARD_LONG_OFFSET 10*60
+#define SEEK_BACKWARD_LONG_OFFSET -3*60
+
+#define ZOOM_UPPER 200
+#define ZOOM_RESET 100
+#define ZOOM_LOWER 10
+#define ZOOM_DISABLE (ZOOM_LOWER - 1)
+#define ZOOM_ENABLE (ZOOM_UPPER + 1)
+
+#define DEFAULT_WINDOW_W 650
+#define DEFAULT_WINDOW_H 500
+
+#define VOLUME_EPSILON (1e-10)
+
+#define BVW_VBOX_BORDER_WIDTH 1
+
+static const GtkTargetEntry target_table[] = {
+	{ "text/uri-list", 0, 0 },
+	{ "_NETSCAPE_URL", 0, 1 }
+};
+
+static gboolean totem_action_open_files_list (Totem *totem, GSList *list);
+static gboolean totem_action_load_media (Totem *totem, TotemDiscMediaType type, const char *device);
+static void update_buttons (Totem *totem);
+static void update_media_menu_items (Totem *totem);
+static void playlist_changed_cb (GtkWidget *playlist, Totem *totem);
+static void play_pause_set_label (Totem *totem, TotemStates state);
+
+/* Callback functions for GtkBuilder */
+gboolean main_window_destroy_cb (GtkWidget *widget, GdkEvent *event, Totem *totem);
+gboolean window_state_event_cb (GtkWidget *window, GdkEventWindowState *event, Totem *totem);
+gboolean seek_slider_pressed_cb (GtkWidget *widget, GdkEventButton *event, Totem *totem);
+void seek_slider_changed_cb (GtkAdjustment *adj, Totem *totem);
+gboolean seek_slider_released_cb (GtkWidget *widget, GdkEventButton *event, Totem *totem);
+void volume_button_value_changed_cb (GtkScaleButton *button, gdouble value, Totem *totem);
+int window_key_press_event_cb (GtkWidget *win, GdkEventKey *event, Totem *totem);
+int window_scroll_event_cb (GtkWidget *win, GdkEventScroll *event, Totem *totem);
+void main_pane_size_allocated (GtkWidget *main_pane, GtkAllocation *allocation, Totem *totem);
+void fs_exit1_activate_cb (GtkButton *button, Totem *totem);
 
 enum {
 	PROP_0,
@@ -646,3 +720,3316 @@
 
 	return etype;
 }
+
+static void
+reset_seek_status (Totem *totem)
+{
+	/* Release the lock and reset everything so that we
+	 * 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_action_stop (totem);
+	}
+}
+
+/**
+ * totem_action_error:
+ * @title: the error dialog title
+ * @reason: the error dialog text
+ * @totem: a #TotemObject
+ *
+ * Displays a non-blocking error dialog with the
+ * given @title and @reason.
+ **/
+void
+totem_action_error (const char *title, const char *reason, Totem *totem)
+{
+	reset_seek_status (totem);
+	totem_interface_error (title, reason,
+			GTK_WINDOW (totem->win));
+}
+
+G_GNUC_NORETURN void
+totem_action_error_and_exit (const char *title,
+		const char *reason, Totem *totem)
+{
+	reset_seek_status (totem);
+	totem_interface_error_blocking (title, reason,
+			GTK_WINDOW (totem->win));
+	totem_action_exit (totem);
+}
+
+static void
+totem_action_save_size (Totem *totem)
+{
+	GtkPaned *item;
+
+	if (totem->bvw == NULL)
+		return;
+
+	if (totem_is_fullscreen (totem) != FALSE)
+		return;
+
+	/* Save the size of the video widget */
+	item = GTK_PANED (gtk_builder_get_object (totem->xml, "tmw_main_pane"));
+	gtk_window_get_size (GTK_WINDOW (totem->win), &totem->window_w,
+			&totem->window_h);
+	totem->sidebar_w = totem->window_w
+		- gtk_paned_get_position (item);
+}
+
+static void
+totem_action_save_state (Totem *totem, const char *page_id)
+{
+	GKeyFile *keyfile;
+	char *contents, *filename;
+
+	if (totem->win == NULL)
+		return;
+	if (totem->window_w == 0
+	    || totem->window_h == 0)
+		return;
+
+	keyfile = g_key_file_new ();
+	g_key_file_set_integer (keyfile, "State",
+				"window_w", totem->window_w);
+	g_key_file_set_integer (keyfile, "State",
+			"window_h", totem->window_h);
+	g_key_file_set_boolean (keyfile, "State",
+			"show_sidebar", totem_sidebar_is_visible (totem));
+	g_key_file_set_boolean (keyfile, "State",
+			"maximised", totem->maximised);
+	g_key_file_set_integer (keyfile, "State",
+			"sidebar_w", totem->sidebar_w);
+
+	g_key_file_set_string (keyfile, "State",
+			"sidebar_page", page_id);
+
+	contents = g_key_file_to_data (keyfile, NULL, NULL);
+	g_key_file_free (keyfile);
+	filename = g_build_filename (totem_dot_dir (), "state.ini", NULL);
+	g_file_set_contents (filename, contents, -1, NULL);
+
+	g_free (filename);
+	g_free (contents);
+}
+
+G_GNUC_NORETURN static void
+totem_action_wait_force_exit (gpointer user_data)
+{
+	g_usleep (10 * G_USEC_PER_SEC);
+	exit (1);
+}
+
+/**
+ * totem_action_exit:
+ * @totem: a #TotemObject
+ *
+ * Closes Totem.
+ **/
+void
+totem_action_exit (Totem *totem)
+{
+	GdkDisplay *display = NULL;
+	char *page_id;
+
+	/* Exit forcefully if we can't do the shutdown in 10 seconds */
+	g_thread_create ((GThreadFunc) totem_action_wait_force_exit,
+			 NULL, FALSE, NULL);
+
+	if (gtk_main_level () > 0)
+		gtk_main_quit ();
+
+	if (totem == NULL)
+		exit (0);
+
+	if (totem->win != NULL) {
+		gtk_widget_hide (totem->win);
+		display = gtk_widget_get_display (totem->win);
+	}
+
+	if (totem->prefs != NULL)
+		gtk_widget_hide (totem->prefs);
+
+	/* Save the page ID before we close the plugins, otherwise
+	 * we'll never save it properly */
+	page_id = totem_sidebar_get_current_page (totem);
+	totem_object_plugins_shutdown ();
+
+	if (display != NULL)
+		gdk_display_sync (display);
+
+	if (totem->bvw) {
+		int vol;
+
+		if (totem->muted != FALSE)
+			vol = totem->prev_volume * 100.0 + 0.5;
+		else
+			vol = bacon_video_widget_get_volume (totem->bvw) * 100.0 + 0.5;
+		/* FIXME move the volume to the static file? */
+		gconf_client_set_int (totem->gc,
+				GCONF_PREFIX"/volume",
+				CLAMP (vol, 0, 100),
+				NULL);
+		totem_action_save_size (totem);
+	}
+
+	if (totem->conn != NULL)
+		bacon_message_connection_free (totem->conn);
+	totem_action_save_state (totem, page_id);
+	g_free (page_id);
+
+	totem_sublang_exit (totem);
+	totem_destroy_file_filters ();
+
+	if (totem->gc)
+		g_object_unref (G_OBJECT (totem->gc));
+
+	if (totem->fs)
+		g_object_unref (totem->fs);
+
+	if (totem->win)
+		gtk_widget_destroy (GTK_WIDGET (totem->win));
+
+	g_object_unref (totem);
+
+	exit (0);
+}
+
+static void
+totem_action_menu_popup (Totem *totem, guint button)
+{
+	GtkWidget *menu;
+
+	menu = gtk_ui_manager_get_widget (totem->ui_manager,
+			"/totem-main-popup");
+	gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
+			button, gtk_get_current_event_time ());
+	gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
+}
+
+G_GNUC_NORETURN gboolean
+main_window_destroy_cb (GtkWidget *widget, GdkEvent *event, Totem *totem)
+{
+	totem_action_exit (totem);
+}
+
+static void
+play_pause_set_label (Totem *totem, TotemStates state)
+{
+	GtkAction *action;
+	const char *id, *tip;
+	GSList *l, *proxies;
+
+	if (state == totem->state)
+		return;
+
+	switch (state)
+	{
+	case STATE_PLAYING:
+		totem_statusbar_set_text (TOTEM_STATUSBAR (totem->statusbar),
+				_("Playing"));
+		id = GTK_STOCK_MEDIA_PAUSE;
+		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 = GTK_STOCK_MEDIA_PLAY;
+		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);
+		id = GTK_STOCK_MEDIA_PLAY;
+		totem_playlist_set_playing (totem->playlist, TOTEM_PLAYLIST_STATUS_NONE);
+		tip = N_("Play");
+		break;
+	default:
+		g_assert_not_reached ();
+		return;
+	}
+
+	action = gtk_action_group_get_action (totem->main_action_group, "play");
+	g_object_set (G_OBJECT (action),
+			"tooltip", _(tip),
+			"stock-id", id, NULL);
+
+	proxies = gtk_action_get_proxies (action);
+	for (l = proxies; l != NULL; l = l->next) {
+		atk_object_set_name (gtk_widget_get_accessible (l->data),
+				_(tip));
+	}
+
+	totem->state = state;
+
+	g_object_notify (G_OBJECT (totem), "playing");
+}
+
+void
+totem_action_eject (Totem *totem)
+{
+	GMount *mount;
+
+	mount = totem_get_mount_for_media (totem->mrl);
+	if (mount == NULL)
+		return;
+
+	g_free (totem->mrl);
+	totem->mrl = NULL;
+	bacon_video_widget_close (totem->bvw);
+	totem_file_closed (totem);
+
+	/* The volume monitoring will take care of removing the items */
+	g_mount_eject (mount, G_MOUNT_UNMOUNT_NONE, NULL, NULL, NULL);
+	g_object_unref (mount);
+}
+
+void
+totem_action_show_properties (Totem *totem)
+{
+	if (totem_is_fullscreen (totem) == FALSE)
+		totem_sidebar_set_current_page (totem, "properties", TRUE);
+}
+
+/**
+ * totem_action_play:
+ * @totem: a #TotemObject
+ *
+ * Plays the current stream. If Totem is already playing, it continues
+ * to play. If the stream cannot be played, and error dialog is displayed.
+ **/
+void
+totem_action_play (Totem *totem)
+{
+	GError *err = NULL;
+	int retval;
+	char *msg, *disp;
+
+	if (totem->mrl == NULL)
+		return;
+
+	if (bacon_video_widget_is_playing (totem->bvw) != FALSE)
+		return;
+
+	retval = bacon_video_widget_play (totem->bvw,  &err);
+	play_pause_set_label (totem, retval ? STATE_PLAYING : STATE_STOPPED);
+
+	if (retval != FALSE)
+		return;
+
+	disp = totem_uri_escape_for_display (totem->mrl);
+	msg = g_strdup_printf(_("Totem could not play '%s'."), disp);
+	g_free (disp);
+
+	totem_action_error (msg, err->message, totem);
+	totem_action_stop (totem);
+	g_free (msg);
+	g_error_free (err);
+}
+
+static void
+totem_action_seek (Totem *totem, double pos)
+{
+	GError *err = NULL;
+	int retval;
+
+	if (totem->mrl == NULL)
+		return;
+	if (bacon_video_widget_is_seekable (totem->bvw) == FALSE)
+		return;
+
+	retval = bacon_video_widget_seek (totem->bvw, pos, &err);
+
+	if (retval == FALSE)
+	{
+		char *msg, *disp;
+
+		disp = totem_uri_escape_for_display (totem->mrl);
+		msg = g_strdup_printf(_("Totem could not play '%s'."), disp);
+		g_free (disp);
+
+		reset_seek_status (totem);
+
+		totem_action_error (msg, err->message, totem);
+		g_free (msg);
+		g_error_free (err);
+	}
+}
+
+/**
+ * totem_action_set_mrl_and_play:
+ * @totem: a #TotemObject
+ * @mrl: the MRL to play
+ * @subtitle: a subtitle file to load, or %NULL
+ *
+ * Loads the specified @mrl and plays it, if possible.
+ * Calls totem_action_set_mrl() then totem_action_play().
+ * For more information, see the documentation for totem_action_set_mrl_with_warning().
+ **/
+void
+totem_action_set_mrl_and_play (Totem *totem, const char *mrl, const char *subtitle)
+{
+	if (totem_action_set_mrl (totem, mrl, subtitle) != FALSE)
+		totem_action_play (totem);
+}
+
+static gboolean
+totem_action_open_dialog (Totem *totem, const char *path, gboolean play)
+{
+	GSList *filenames;
+	gboolean playlist_modified;
+
+	filenames = totem_add_files (GTK_WINDOW (totem->win), path);
+
+	if (filenames == NULL)
+		return FALSE;
+
+	playlist_modified = totem_action_open_files_list (totem,
+			filenames);
+
+	if (playlist_modified == FALSE) {
+		g_slist_foreach (filenames, (GFunc) g_free, NULL);
+		g_slist_free (filenames);
+		return FALSE;
+	}
+
+	g_slist_foreach (filenames, (GFunc) g_free, NULL);
+	g_slist_free (filenames);
+
+	if (play != FALSE) {
+		char *mrl, *subtitle;
+
+		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
+		totem_action_set_mrl_and_play (totem, mrl, subtitle);
+		g_free (mrl);
+		g_free (subtitle);
+	}
+
+	return TRUE;
+}
+
+static void
+totem_dvb_setup_result (int result, const char *device, gpointer user_data)
+{
+	Totem *totem = (Totem *) user_data;
+
+	totem_action_play_media (totem, MEDIA_TYPE_DVB, device);
+}
+
+static gboolean
+totem_action_load_media (Totem *totem, TotemDiscMediaType type, const char *device)
+{
+	char **mrls, *msg;
+	GError *error = NULL;
+	const char *link, *link_text, *secondary;
+	gboolean retval;
+
+	mrls = bacon_video_widget_get_mrls (totem->bvw, type, device, &error);
+	if (mrls == NULL) {
+		/* No errors? Weird */
+		if (error == NULL) {
+			msg = g_strdup_printf (_("Totem could not play this media (%s) although a plugin is present to handle it."), _(totem_cd_get_human_readable_name (type)));
+			totem_action_error (msg, _("You might want to check that a disc is present in the drive and that it is correctly configured."), totem);
+			g_free (msg);
+			return FALSE;
+		}
+		/* No plugin for the media type */
+		if (g_error_matches (error, BVW_ERROR, BVW_ERROR_NO_PLUGIN_FOR_FILE) != FALSE) {
+			link = "http://www.gnome.org/projects/totem/#codecs";;
+			link_text = _("More information about media plugins");
+			secondary = _("Please install the necessary plugins and restart Totem to be able to play this media.");
+			if (type == MEDIA_TYPE_DVD || type == MEDIA_TYPE_VCD)
+				msg = g_strdup_printf (_("Totem cannot play this type of media (%s) because it does not have the appropriate plugins to be able to read from the disc."), _(totem_cd_get_human_readable_name (type)));
+			else
+				msg = g_strdup_printf (_("Totem cannot play this type of media (%s) because you do not have the appropriate plugins to handle it."), _(totem_cd_get_human_readable_name (type)));
+		/* Device doesn't exist */
+		} else if (g_error_matches (error, BVW_ERROR, BVW_ERROR_INVALID_DEVICE) != FALSE) {
+			g_assert (type == MEDIA_TYPE_DVB);
+			msg = N_("Totem cannot play TV, because no TV adapters are present or they are not supported.");
+			totem_action_error (_(msg), _("Please insert a supported TV adapter."), totem);
+			return FALSE;
+		/* No channels.conf file */
+		} else if (g_error_matches (error, BVW_ERROR, BVW_ERROR_FILE_NOT_FOUND) != FALSE) {
+			g_assert (type == MEDIA_TYPE_DVB);
+
+			if (totem_dvb_setup_device (device, GTK_WINDOW (totem->win), totem_dvb_setup_result, totem) == TOTEM_DVB_SETUP_STARTED_OK)
+				return FALSE;
+
+			link = "http://www.gnome.org/projects/totem/#dvb";;
+			link_text = _("More information about watching TV");
+			msg = g_strdup (_("Totem is missing a channels listing to be able to tune the receiver."));
+			secondary = _("Please follow the instructions provided in the link to create a channels listing.");
+		} else if (g_error_matches (error, BVW_ERROR, BVW_ERROR_DEVICE_BUSY) != FALSE) {
+			g_assert (type == MEDIA_TYPE_DVB);
+			msg = g_strdup_printf(_("Totem cannot play this type of media (%s) because the TV device is busy."), _(totem_cd_get_human_readable_name (type)));
+			totem_action_error (msg, _("Please try again later."), totem);
+			g_free (msg);
+			return FALSE;
+		/* Unsupported type (ie. CDDA) */
+		} else if (g_error_matches (error, BVW_ERROR, BVW_ERROR_UNVALID_LOCATION) != FALSE) {
+			msg = g_strdup_printf(_("Totem cannot play this type of media (%s) because it is not supported."), _(totem_cd_get_human_readable_name (type)));
+			totem_action_error (msg, _("Please insert another disc to play back."), totem);
+			g_free (msg);
+			return FALSE;
+		} else {
+			g_assert_not_reached ();
+		}
+		totem_interface_error_with_link (msg, secondary, link, link_text, GTK_WINDOW (totem->win), totem);
+		g_free (msg);
+		return FALSE;
+	}
+
+	retval = totem_action_open_files (totem, mrls);
+	g_strfreev (mrls);
+
+	return retval;
+}
+
+static gboolean
+totem_action_load_media_device (Totem *totem, const char *device)
+{
+	TotemDiscMediaType type;
+	GError *error = NULL;
+	char *device_path, *url;
+	gboolean retval;
+
+	if (g_str_has_prefix (device, "file://") != FALSE)
+		device_path = g_filename_from_uri (device, NULL, NULL);
+	else
+		device_path = g_strdup (device);
+
+	type = totem_cd_detect_type_with_url (device_path, &url, &error);
+
+	switch (type) {
+		case MEDIA_TYPE_ERROR:
+			totem_action_error (_("Totem was not able to play this disc."),
+					    error ? error->message : _("No reason."),
+					    totem);
+			retval = FALSE;
+			break;
+		case MEDIA_TYPE_DATA:
+			/* Set default location to the mountpoint of
+			 * this device */
+			retval = totem_action_open_dialog (totem, url, FALSE);
+			break;
+		case MEDIA_TYPE_DVD:
+		case MEDIA_TYPE_VCD:
+			retval = totem_action_load_media (totem, type, device_path);
+			break;
+		case MEDIA_TYPE_CDDA:
+			totem_action_error (_("Totem does not support playback of Audio CDs"),
+					    _("Please consider using a music player or a CD extractor to play this CD"),
+					    totem);
+			retval = FALSE;
+			break;
+		default:
+			g_assert_not_reached ();
+	}
+
+	g_free (url);
+	g_free (device_path);
+
+	return retval;
+}
+
+/**
+ * totem_action_play_media_device:
+ * @totem: a #TotemObject
+ * @device: the media device's path
+ *
+ * Attempts to play the media device (for example, a DVD drive or CD drive)
+ * with the given @device path by first adding it to the playlist, then
+ * playing it.
+ *
+ * An error dialog will be displayed if Totem cannot read or play what's on
+ * the media device.
+ **/
+void
+totem_action_play_media_device (Totem *totem, const char *device)
+{
+	char *mrl;
+
+	if (totem_action_load_media_device (totem, device) != FALSE) {
+		mrl = totem_playlist_get_current_mrl (totem->playlist, NULL);
+		totem_action_set_mrl_and_play (totem, mrl, NULL);
+		g_free (mrl);
+	}
+}
+
+/**
+ * totem_action_play_media:
+ * @totem: a #TotemObject
+ * @type: the type of disc media
+ * @device: the media's device path
+ *
+ * Attempts to play the media found on @device (for example, a DVD in a drive or a DVB
+ * tuner) by first adding it to the playlist, then playing it.
+ *
+ * An error dialog will be displayed if Totem cannot support media of @type.
+ **/
+void
+totem_action_play_media (Totem *totem, TotemDiscMediaType type, const char *device)
+{
+	char *mrl;
+
+	if (totem_action_load_media (totem, type, device) != FALSE) {
+		mrl = totem_playlist_get_current_mrl (totem->playlist, NULL);
+		totem_action_set_mrl_and_play (totem, mrl, NULL);
+		g_free (mrl);
+	}
+}
+
+/**
+ * totem_action_stop:
+ * @totem: a #TotemObject
+ *
+ * Stops the current stream.
+ **/
+void
+totem_action_stop (Totem *totem)
+{
+	bacon_video_widget_stop (totem->bvw);
+	play_pause_set_label (totem, STATE_STOPPED);
+}
+
+/**
+ * totem_action_play_pause:
+ * @totem: a #TotemObject
+ *
+ * Gets the current MRL from the playlist and attempts to play it.
+ * If the stream is already playing, playback is paused.
+ **/
+void
+totem_action_play_pause (Totem *totem)
+{
+	if (totem->mrl == NULL)
+	{
+		char *mrl, *subtitle;
+
+		/* Try to pull an mrl from the playlist */
+		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
+		if (mrl == NULL) {
+			play_pause_set_label (totem, STATE_STOPPED);
+			return;
+		} else {
+			totem_action_set_mrl_and_play (totem, mrl, subtitle);
+			g_free (mrl);
+			g_free (subtitle);
+			return;
+		}
+	}
+
+	if (bacon_video_widget_is_playing (totem->bvw) == FALSE)
+	{
+		bacon_video_widget_play (totem->bvw, NULL);
+		play_pause_set_label (totem, STATE_PLAYING);
+	} else {
+		bacon_video_widget_pause (totem->bvw);
+		play_pause_set_label (totem, STATE_PAUSED);
+	}
+}
+
+/**
+ * totem_action_pause:
+ * @totem: a #TotemObject
+ *
+ * Pauses the current stream. If Totem is already paused, it continues
+ * to be paused.
+ **/
+void
+totem_action_pause (Totem *totem)
+{
+	if (bacon_video_widget_is_playing (totem->bvw) != FALSE) {
+		bacon_video_widget_pause (totem->bvw);
+		play_pause_set_label (totem, STATE_PAUSED);
+	}
+}
+
+gboolean
+window_state_event_cb (GtkWidget *window, GdkEventWindowState *event,
+		       Totem *totem)
+{
+	if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) {
+		totem->maximised = (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0;
+                gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (totem->statusbar),
+                                                   !totem->maximised);
+		totem_action_set_sensitivity ("zoom-1-2", !totem->maximised);
+		totem_action_set_sensitivity ("zoom-1-1", !totem->maximised);
+		totem_action_set_sensitivity ("zoom-2-1", !totem->maximised);
+		return FALSE;
+	}
+
+	if ((event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) == 0)
+		return FALSE;
+
+	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);
+		totem_action_set_sensitivity ("fullscreen", FALSE);
+	} else {
+		GtkAction *action;
+
+		totem_fullscreen_set_fullscreen (totem->fs, FALSE);
+
+		action = gtk_action_group_get_action (totem->main_action_group,
+				"show-controls");
+
+		if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
+			totem->controls_visibility = TOTEM_CONTROLS_VISIBLE;
+		} else {
+			totem->controls_visibility = TOTEM_CONTROLS_HIDDEN;
+		}
+
+		show_controls (totem, TRUE);
+		totem_action_set_sensitivity ("fullscreen", TRUE);
+	}
+
+	g_object_notify (G_OBJECT (totem), "fullscreen");
+
+	return FALSE;
+}
+
+/**
+ * totem_action_fullscreen_toggle:
+ * @totem: a #TotemObject
+ *
+ * Toggles Totem's fullscreen state; if Totem is fullscreened, calling
+ * this makes it unfullscreened and vice-versa.
+ **/
+void
+totem_action_fullscreen_toggle (Totem *totem)
+{
+	if (totem_is_fullscreen (totem) != FALSE)
+		gtk_window_unfullscreen (GTK_WINDOW (totem->win));
+	else
+		gtk_window_fullscreen (GTK_WINDOW (totem->win));
+}
+
+/**
+ * totem_action_fullscreen:
+ * @totem: a #TotemObject
+ * @state: %TRUE if Totem should be fullscreened
+ *
+ * Sets Totem's fullscreen state according to @state.
+ **/
+void
+totem_action_fullscreen (Totem *totem, gboolean state)
+{
+	if (totem_is_fullscreen (totem) == state)
+		return;
+
+	totem_action_fullscreen_toggle (totem);
+}
+
+void
+fs_exit1_activate_cb (GtkButton *button, Totem *totem)
+{
+	totem_action_fullscreen (totem, FALSE);
+}
+
+void
+totem_action_open (Totem *totem)
+{
+	totem_action_open_dialog (totem, NULL, TRUE);
+}
+
+static void
+totem_open_location_destroy (Totem *totem)
+{
+	if (totem->open_location != NULL) {
+		g_object_remove_weak_pointer (G_OBJECT (totem->open_location), (gpointer *)&(totem->open_location));
+		gtk_widget_destroy (GTK_WIDGET (totem->open_location));
+		totem->open_location = NULL;
+	}
+}
+
+static void
+totem_open_location_response_cb (GtkDialog *dialog, gint response, Totem *totem)
+{
+	char *uri;
+
+	if (response != GTK_RESPONSE_OK) {
+		totem_open_location_destroy (totem);
+		return;
+	}
+
+	gtk_widget_hide (GTK_WIDGET (dialog));
+
+	/* Open the specified URI */
+	uri = totem_open_location_get_uri (totem->open_location);
+
+	if (uri != NULL)
+	{
+		char *mrl, *subtitle;
+		const char *filenames[2];
+
+		filenames[0] = uri;
+		filenames[1] = NULL;
+		totem_action_open_files (totem, (char **) filenames);
+
+		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
+		totem_action_set_mrl_and_play (totem, mrl, subtitle);
+		g_free (mrl);
+		g_free (subtitle);
+	}
+ 	g_free (uri);
+
+	totem_open_location_destroy (totem);
+}
+
+void
+totem_action_open_location (Totem *totem)
+{
+	if (totem->open_location != NULL) {
+		gtk_window_present (GTK_WINDOW (totem->open_location));
+		return;
+	}
+
+	totem->open_location = TOTEM_OPEN_LOCATION (totem_open_location_new (totem));
+
+	g_signal_connect (G_OBJECT (totem->open_location), "delete-event",
+			G_CALLBACK (gtk_widget_destroy), NULL);
+	g_signal_connect (G_OBJECT (totem->open_location), "response",
+			G_CALLBACK (totem_open_location_response_cb), totem);
+	g_object_add_weak_pointer (G_OBJECT (totem->open_location), (gpointer *)&(totem->open_location));
+
+	gtk_window_set_transient_for (GTK_WINDOW (totem->open_location),
+			GTK_WINDOW (totem->win));
+	gtk_widget_show (GTK_WIDGET (totem->open_location));
+}
+
+static char *
+totem_get_nice_name_for_stream (Totem *totem)
+{
+	GValue title_value = { 0, };
+	GValue album_value = { 0, };
+	GValue artist_value = { 0, };
+	GValue value = { 0, };
+	char *retval;
+	int tracknum;
+
+	bacon_video_widget_get_metadata (totem->bvw, BVW_INFO_TITLE, &title_value);
+	bacon_video_widget_get_metadata (totem->bvw, BVW_INFO_ARTIST, &artist_value);
+	bacon_video_widget_get_metadata (totem->bvw, BVW_INFO_ALBUM, &album_value);
+	bacon_video_widget_get_metadata (totem->bvw,
+					 BVW_INFO_TRACK_NUMBER,
+					 &value);
+
+	tracknum = g_value_get_int (&value);
+	g_value_unset (&value);
+
+	totem_metadata_updated (totem,
+				g_value_get_string (&artist_value),
+				g_value_get_string (&title_value),
+				g_value_get_string (&album_value),
+				tracknum);
+
+	if (g_value_get_string (&title_value) == NULL) {
+		retval = NULL;
+		goto bail;
+	}
+	if (g_value_get_string (&artist_value) == NULL) {
+		retval = g_value_dup_string (&title_value);
+		goto bail;
+	}
+
+	if (tracknum != 0) {
+		retval = g_strdup_printf ("%02d. %s - %s",
+					  tracknum,
+					  g_value_get_string (&artist_value),
+					  g_value_get_string (&title_value));
+	} else {
+		retval = g_strdup_printf ("%s - %s",
+					  g_value_get_string (&artist_value),
+					  g_value_get_string (&title_value));
+	}
+
+bail:
+	g_value_unset (&album_value);
+	g_value_unset (&artist_value);
+	g_value_unset (&title_value);
+
+	return retval;
+}
+
+static void
+update_mrl_label (Totem *totem, const char *name)
+{
+	if (name != NULL)
+	{
+		/* Update the mrl label */
+		totem_fullscreen_set_title (totem->fs, name);
+
+		/* Title */
+		gtk_window_set_title (GTK_WINDOW (totem->win), name);
+	} else {
+		totem_statusbar_set_time_and_length (TOTEM_STATUSBAR
+				(totem->statusbar), 0, 0);
+		totem_statusbar_set_text (TOTEM_STATUSBAR (totem->statusbar),
+				_("Stopped"));
+
+		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), _("Movie Player"));
+	}
+}
+
+/**
+ * totem_action_set_mrl_with_warning:
+ * @totem: a #TotemObject
+ * @mrl: the MRL to play
+ * @subtitle: a subtitle file to load, or %NULL
+ * @warn: %TRUE if error dialogs should be displayed
+ *
+ * Loads the specified @mrl and optionally the specified subtitle
+ * file. If @subtitle is %NULL Totem will attempt to auto-locate
+ * any subtitle files for @mrl.
+ *
+ * If a stream is already playing, it will be stopped and closed.
+ *
+ * If any errors are encountered, error dialogs will only be displayed
+ * if @warn is %TRUE.
+ *
+ * Return value: %TRUE on success
+ **/
+gboolean
+totem_action_set_mrl_with_warning (Totem *totem,
+				   const char *mrl, 
+				   const char *subtitle,
+				   gboolean warn)
+{
+	gboolean retval = TRUE;
+
+	if (totem->mrl != NULL)
+	{
+		g_free (totem->mrl);
+		totem->mrl = NULL;
+		bacon_video_widget_close (totem->bvw);
+		totem_file_closed (totem);
+		play_pause_set_label (totem, STATE_STOPPED);
+	}
+
+	if (mrl == NULL)
+	{
+		retval = FALSE;
+
+		play_pause_set_label (totem, STATE_STOPPED);
+
+		/* Play/Pause */
+		totem_action_set_sensitivity ("play", FALSE);
+
+		/* Volume */
+		totem_main_set_sensitivity ("tmw_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);
+
+		/* Clear the playlist */
+		totem_action_set_sensitivity ("clear-playlist", FALSE);
+
+		/* Subtitle selection */
+		totem_action_set_sensitivity ("select-subtitle", FALSE);
+
+		/* Set the logo */
+		bacon_video_widget_set_logo_mode (totem->bvw, TRUE);
+		update_mrl_label (totem, NULL);
+	} else {
+		gboolean caps;
+		gdouble volume;
+		char *autoload_sub = NULL;
+		GError *err = NULL;
+
+		bacon_video_widget_set_logo_mode (totem->bvw, FALSE);
+
+		if (subtitle == NULL && totem->autoload_subs != FALSE)
+			autoload_sub = totem_uri_get_subtitle_uri (mrl);
+
+		totem_gdk_window_set_waiting_cursor (totem->win->window);
+		retval = bacon_video_widget_open_with_subtitle (totem->bvw, mrl,
+								subtitle ? subtitle : autoload_sub, &err);
+		g_free (autoload_sub);
+		gdk_window_set_cursor (totem->win->window, NULL);
+		totem->mrl = g_strdup (mrl);
+
+		/* Play/Pause */
+		totem_action_set_sensitivity ("play", TRUE);
+
+		/* 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);
+		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);
+		totem->volume_sensitive = caps;
+
+		/* Clear the playlist */
+		totem_action_set_sensitivity ("clear-playlist", retval);
+
+		/* Subtitle selection */
+		totem_action_set_sensitivity ("select-subtitle", !totem_is_special_mrl (mrl) && retval);
+	
+		/* Set the playlist */
+		play_pause_set_label (totem, retval ? STATE_PAUSED : STATE_STOPPED);
+
+		if (retval == FALSE && warn != FALSE)
+		{
+			char *msg, *disp;
+
+			disp = totem_uri_escape_for_display (totem->mrl);
+			msg = g_strdup_printf(_("Totem could not play '%s'."), disp);
+			g_free (disp);
+			if (err && err->message) {
+				totem_action_error (msg, err->message, totem);
+			}
+			else {
+				totem_action_error (msg, _("No error message"), totem);
+			}
+			g_free (msg);
+		}
+
+		if (retval == FALSE)
+		{
+			if (err)
+				g_error_free (err);
+			g_free (totem->mrl);
+			totem->mrl = NULL;
+			bacon_video_widget_set_logo_mode (totem->bvw, TRUE);
+		} else {
+			totem_file_opened (totem, totem->mrl);
+		}
+	}
+	update_buttons (totem);
+	update_media_menu_items (totem);
+
+	return retval;
+}
+
+/**
+ * totem_action_set_mrl:
+ * @totem: a #TotemObject
+ * @mrl: the MRL to load
+ * @subtitle: a subtitle file to load, or %NULL
+ *
+ * Calls totem_action_set_mrl_with_warning() with warnings enabled.
+ * For more information, see the documentation for totem_action_set_mrl_with_warning().
+ *
+ * Return value: %TRUE on success
+ **/
+gboolean
+totem_action_set_mrl (Totem *totem, const char *mrl, const char *subtitle)
+{
+	return totem_action_set_mrl_with_warning (totem, mrl, subtitle, TRUE);
+}
+
+static gboolean
+totem_time_within_seconds (Totem *totem)
+{
+	gint64 time;
+
+	time = bacon_video_widget_get_current_time (totem->bvw);
+
+	return (time < REWIND_OR_PREVIOUS);
+}
+
+static void
+totem_action_direction (Totem *totem, TotemPlaylistDirection dir)
+{
+	if (totem_playing_dvd (totem->mrl) == FALSE &&
+		totem_playlist_has_direction (totem->playlist, dir) == FALSE
+		&& totem_playlist_get_repeat (totem->playlist) == FALSE)
+		return;
+
+	if (totem_playing_dvd (totem->mrl) != FALSE)
+	{
+		bacon_video_widget_dvd_event (totem->bvw,
+				dir == TOTEM_PLAYLIST_DIRECTION_NEXT ?
+				BVW_DVD_NEXT_CHAPTER :
+				BVW_DVD_PREV_CHAPTER);
+		return;
+	}
+	
+	if (dir == TOTEM_PLAYLIST_DIRECTION_NEXT
+			|| bacon_video_widget_is_seekable (totem->bvw) == FALSE
+			|| totem_time_within_seconds (totem) != FALSE)
+	{
+		char *mrl, *subtitle;
+
+		totem_playlist_set_direction (totem->playlist, dir);
+		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
+		totem_action_set_mrl_and_play (totem, mrl, subtitle);
+
+		g_free (subtitle);
+		g_free (mrl);
+	} else {
+		totem_action_seek (totem, 0);
+	}
+}
+
+/**
+ * totem_action_previous:
+ * @totem: a #TotemObject
+ *
+ * If a DVD is being played, goes to the previous chapter. If a normal stream
+ * is being played, goes to the start of the stream if possible. If seeking is
+ * not possible, plays the previous entry in the playlist.
+ **/
+void
+totem_action_previous (Totem *totem)
+{
+	totem_action_direction (totem, TOTEM_PLAYLIST_DIRECTION_PREVIOUS);
+}
+
+/**
+ * totem_action_next:
+ * @totem: a #TotemObject
+ *
+ * If a DVD is being played, goes to the next chapter. If a normal stream
+ * is being played, plays the next entry in the playlist.
+ **/
+void
+totem_action_next (Totem *totem)
+{
+	totem_action_direction (totem, TOTEM_PLAYLIST_DIRECTION_NEXT);
+}
+
+static void
+totem_seek_time_rel (Totem *totem, gint64 time, gboolean relative)
+{
+	GError *err = NULL;
+	gint64 sec;
+
+	if (totem->mrl == NULL)
+		return;
+	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);
+		sec = MAX (0, oldmsec + time);
+	} else {
+		sec = time;
+	}
+
+	bacon_video_widget_seek_time (totem->bvw, sec, &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;
+
+		disp = totem_uri_escape_for_display (totem->mrl);
+		msg = g_strdup_printf(_("Totem could not play '%s'."), disp);
+		g_free (disp);
+
+		totem_action_stop (totem);
+		totem_action_error (msg, err->message, totem);
+		g_free (msg);
+		g_error_free (err);
+	}
+}
+
+/**
+ * totem_action_seek_relative:
+ * @totem: a #TotemObject
+ * @offset: the time offset to seek to
+ *
+ * Seeks to an @offset from the current position in the stream,
+ * or displays an error dialog if that's not possible.
+ **/
+void
+totem_action_seek_relative (Totem *totem, gint64 offset)
+{
+	totem_seek_time_rel (totem, offset, TRUE);
+}
+
+/**
+ * totem_action_seek_time:
+ * @totem: a #TotemObject
+ * @sec: the time to seek to
+ *
+ * Seeks to an absolute time in the stream, or displays an
+ * error dialog if that's not possible.
+ **/
+void
+totem_action_seek_time (Totem *totem, gint64 sec)
+{
+	totem_seek_time_rel (totem, sec, FALSE);
+}
+
+static void
+totem_action_zoom (Totem *totem, int zoom)
+{
+	GtkAction *action;
+	gboolean zoom_reset, zoom_in, zoom_out;
+
+	if (zoom == ZOOM_ENABLE)
+		zoom = bacon_video_widget_get_zoom (totem->bvw);
+
+	if (zoom == ZOOM_DISABLE) {
+		zoom_reset = zoom_in = zoom_out = FALSE;
+	} else if (zoom < ZOOM_LOWER || zoom > ZOOM_UPPER) {
+		return;
+	} else {
+		bacon_video_widget_set_zoom (totem->bvw, zoom);
+		zoom_reset = (zoom != ZOOM_RESET);
+		zoom_out = zoom != ZOOM_LOWER;
+		zoom_in = zoom != ZOOM_UPPER;
+	}
+
+	action = gtk_action_group_get_action (totem->zoom_action_group,
+			"zoom-in");
+	gtk_action_set_sensitive (action, zoom_in);
+
+	action = gtk_action_group_get_action (totem->zoom_action_group,
+			"zoom-out");
+	gtk_action_set_sensitive (action, zoom_out);
+
+	action = gtk_action_group_get_action (totem->zoom_action_group,
+			"zoom-reset");
+	gtk_action_set_sensitive (action, zoom_reset);
+}
+
+void
+totem_action_zoom_relative (Totem *totem, int off_pct)
+{
+	int zoom;
+
+	zoom = bacon_video_widget_get_zoom (totem->bvw);
+	totem_action_zoom (totem, zoom + off_pct);
+}
+
+void
+totem_action_zoom_reset (Totem *totem)
+{
+	totem_action_zoom (totem, ZOOM_RESET);
+}
+
+/**
+ * totem_action_volume_relative:
+ * @totem: a #TotemObject
+ * @off_pct: the value by which to increase or decrease the volume
+ *
+ * Sets the volume relative to its current level, with 1.0 being the
+ * maximum, and 0.0 being the minimum level.
+ **/
+void
+totem_action_volume_relative (Totem *totem, double off_pct)
+{
+	double vol;
+
+	if (bacon_video_widget_can_set_volume (totem->bvw) == FALSE)
+		return;
+	if (totem->muted != FALSE)
+		totem_action_volume_toggle_mute (totem);
+
+	vol = bacon_video_widget_get_volume (totem->bvw);
+	bacon_video_widget_set_volume (totem->bvw, vol + off_pct);
+}
+
+/**
+ * totem_action_volume_toggle_mute:
+ * @totem: a #TotemObject
+ *
+ * Toggles the mute status.
+ **/
+void
+totem_action_volume_toggle_mute (Totem *totem)
+{
+	if (totem->muted == FALSE) {
+		totem->muted = TRUE;
+		totem->prev_volume = bacon_video_widget_get_volume (totem->bvw);
+		bacon_video_widget_set_volume (totem->bvw, 0.0);
+	} else {
+		totem->muted = FALSE;
+		bacon_video_widget_set_volume (totem->bvw, totem->prev_volume);
+	}
+}
+
+/**
+ * totem_action_toggle_aspect_ratio:
+ * @totem: a #TotemObject
+ *
+ * Toggles the aspect ratio selected in the menu to the
+ * next one in the list.
+ **/
+void
+totem_action_toggle_aspect_ratio (Totem *totem)
+{
+	GtkAction *action;
+	int tmp;
+
+	tmp = totem_action_get_aspect_ratio (totem);
+	tmp++;
+	if (tmp > BVW_RATIO_DVB)
+		tmp = BVW_RATIO_AUTO;
+
+	action = gtk_action_group_get_action (totem->main_action_group, "aspect-ratio-auto");
+	gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), tmp);
+}
+
+/**
+ * totem_action_set_aspect_ratio:
+ * @totem: a #TotemObject
+ * @ratio: the aspect ratio to use
+ *
+ * Sets the aspect ratio selected in the menu to @ratio,
+ * as defined in #BaconVideoWidgetAspectRatio.
+ **/
+void
+totem_action_set_aspect_ratio (Totem *totem, int ratio)
+{
+	bacon_video_widget_set_aspect_ratio (totem->bvw, ratio);
+}
+
+/**
+ * totem_action_get_aspect_ratio:
+ * @totem: a #TotemObject
+ *
+ * Gets the current aspect ratio as defined in #BaconVideoWidgetAspectRatio.
+ *
+ * Return value: the current aspect ratio
+ **/
+int
+totem_action_get_aspect_ratio (Totem *totem)
+{
+	return (bacon_video_widget_get_aspect_ratio (totem->bvw));
+}
+
+/**
+ * totem_action_set_scale_ratio:
+ * @totem: a #TotemObject
+ * @ratio: the scale ratio to use
+ *
+ * Sets the video scale ratio, as a float where, for example,
+ * 1.0 is 1:1 and 2.0 is 2:1.
+ **/
+void
+totem_action_set_scale_ratio (Totem *totem, gfloat ratio)
+{
+	bacon_video_widget_set_scale_ratio (totem->bvw, ratio);
+}
+
+void
+totem_action_show_help (Totem *totem)
+{
+	GError *error = NULL;
+
+	if (gtk_show_uri (gtk_widget_get_screen (totem->win), "ghelp:totem", gtk_get_current_event_time (), &error) == FALSE) {
+		totem_action_error (_("Totem could not display the help contents."), error->message, totem);
+		g_error_free (error);
+	}
+}
+
+static gboolean
+totem_action_drop_files (Totem *totem, GtkSelectionData *data,
+		int drop_type, gboolean empty_pl)
+{
+	char **list;
+	guint i, len;
+	GList *p, *file_list;
+	gboolean cleared = FALSE;
+
+	list = g_uri_list_extract_uris ((const char *)data->data);
+	file_list = NULL;
+
+	for (i = 0; list[i] != NULL; i++) {
+		char *filename;
+
+		if (list[i] == NULL)
+			continue;
+
+		filename = totem_create_full_path (list[i]);
+		file_list = g_list_prepend (file_list,
+					    filename ? filename : g_strdup (list[i]));
+	}
+	g_strfreev (list);
+
+	if (file_list == NULL)
+		return FALSE;
+
+	totem_gdk_window_set_waiting_cursor (totem->win->window);
+
+	if (drop_type != 1)
+		file_list = g_list_sort (file_list, (GCompareFunc) strcmp);
+	else
+		file_list = g_list_reverse (file_list);
+
+	/* How many files? Check whether those could be subtitles */
+	len = g_list_length (file_list);
+	if (len == 1 || (len == 2 && drop_type == 1)) {
+		if (totem_uri_is_subtitle (file_list->data) != FALSE) {
+			totem_playlist_set_current_subtitle (totem->playlist, file_list->data);
+			goto bail;
+		}
+	}
+
+	for (p = file_list; p != NULL; p = p->next) {
+		const char *filename;
+		char *title;
+
+		filename = p->data;
+		title = NULL;
+
+		if (empty_pl != FALSE && cleared == FALSE) {
+			/* The function that calls us knows better
+			 * if we should be doing something with the 
+			 * changed playlist ... */
+			g_signal_handlers_disconnect_by_func
+				(G_OBJECT (totem->playlist),
+				 playlist_changed_cb, totem);
+			totem_playlist_clear (totem->playlist);
+			cleared = TRUE;
+		}
+
+		/* Super _NETSCAPE_URL trick */
+		if (drop_type == 1) {
+			p = p->next;
+			if (p != NULL) {
+				if (g_str_has_prefix (p->data, "File:") != FALSE)
+					title = (char *)p->data + 5;
+				else
+					title = p->data;
+			}
+		}
+
+		totem_playlist_add_mrl (totem->playlist, filename, title);
+	}
+
+bail:
+	g_list_foreach (file_list, (GFunc) g_free, NULL);
+	g_list_free (file_list);
+	gdk_window_set_cursor (totem->win->window, NULL);
+
+	/* ... and reconnect because we're nice people */
+	if (cleared != FALSE)
+	{
+		char *mrl, *subtitle;
+
+		g_signal_connect (G_OBJECT (totem->playlist),
+				"changed", G_CALLBACK (playlist_changed_cb),
+				totem);
+		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
+		totem_action_set_mrl_and_play (totem, mrl, subtitle);
+		g_free (mrl);
+		g_free (subtitle);
+	}
+
+	return TRUE;
+}
+
+static void
+drop_video_cb (GtkWidget     *widget,
+	 GdkDragContext     *context,
+	 gint                x,
+	 gint                y,
+	 GtkSelectionData   *data,
+	 guint               info,
+	 guint               time,
+	 Totem              *totem)
+{
+	gboolean empty_pl;
+
+	if (context->suggested_action == GDK_ACTION_ASK)
+		context->action = totem_drag_ask (totem_get_playlist_length (totem) > 0);
+
+	if (context->action != GDK_ACTION_DEFAULT) {
+		empty_pl = (context->action == GDK_ACTION_MOVE);
+		totem_action_drop_files (totem, data, info, empty_pl);
+		gtk_drag_finish (context, TRUE, FALSE, time);
+		return;
+	}
+	gtk_drag_finish (context, FALSE, FALSE, time);
+}
+
+static void
+drag_motion_video_cb (GtkWidget      *widget,
+                      GdkDragContext *context,
+                      gint            x,
+                      gint            y,
+                      guint           time,
+                      Totem          *totem)
+{
+	GdkModifierType mask;
+
+	gdk_window_get_pointer (widget->window, NULL, NULL, &mask);
+	if (mask & GDK_CONTROL_MASK) {
+		gdk_drag_status (context, GDK_ACTION_COPY, time);
+	} else if (mask & GDK_MOD1_MASK || context->suggested_action == GDK_ACTION_ASK) {
+		gdk_drag_status (context, GDK_ACTION_ASK, time);
+	} else {
+		gdk_drag_status (context, GDK_ACTION_MOVE, time);
+	}
+}
+
+static void
+drop_playlist_cb (GtkWidget     *widget,
+	       GdkDragContext     *context,
+	       gint                x,
+	       gint                y,
+	       GtkSelectionData   *data,
+	       guint               info,
+	       guint               time,
+	       Totem              *totem)
+{
+	gboolean empty_pl;
+
+	if (context->suggested_action == GDK_ACTION_ASK)
+		context->action = totem_drag_ask (totem_get_playlist_length (totem) > 0);
+
+	if (context->action == GDK_ACTION_DEFAULT) {
+		gtk_drag_finish (context, FALSE, FALSE, time);
+		return;
+	}
+
+	empty_pl = (context->action == GDK_ACTION_MOVE);
+
+	totem_action_drop_files (totem, data, info, empty_pl);
+	gtk_drag_finish (context, TRUE, FALSE, time);
+}
+
+static void
+drag_motion_playlist_cb (GtkWidget      *widget,
+			 GdkDragContext *context,
+			 gint            x,
+			 gint            y,
+			 guint           time,
+			 Totem          *totem)
+{
+	GdkModifierType mask;
+
+	gdk_window_get_pointer (widget->window, NULL, NULL, &mask);
+
+	if (mask & GDK_MOD1_MASK || context->suggested_action == GDK_ACTION_ASK) {
+		gdk_drag_status (context, GDK_ACTION_ASK, time);
+	}
+}
+static void
+drag_video_cb (GtkWidget *widget,
+	       GdkDragContext *context,
+	       GtkSelectionData *selection_data,
+	       guint info,
+	       guint32 time,
+	       gpointer callback_data)
+{
+	Totem *totem = (Totem *) callback_data;
+	char *text;
+	int len;
+	GFile *file;
+
+	g_assert (selection_data != NULL);
+
+	if (totem->mrl == NULL)
+		return;
+
+	/* Canonicalise the MRL as a proper URI */
+	file = g_file_new_for_commandline_arg (totem->mrl);
+	text = g_file_get_uri (file);
+	g_object_unref (file);
+
+	g_return_if_fail (text != NULL);
+
+	len = strlen (text);
+
+	gtk_selection_data_set (selection_data, selection_data->target,
+				8, (guchar *) text, len);
+
+	g_free (text);
+}
+
+static void
+on_got_redirect (BaconVideoWidget *bvw, const char *mrl, Totem *totem)
+{
+	char *new_mrl;
+
+	if (strstr (mrl, "://") != NULL) {
+		new_mrl = NULL;
+	} else {
+		GFile *old_file, *parent, *new_file;
+		char *old_mrl;
+
+		/* Get the parent for the current MRL, that's our base */
+		old_mrl = totem_playlist_get_current_mrl (TOTEM_PLAYLIST (totem->playlist), NULL);
+		old_file = g_file_new_for_uri (old_mrl);
+		g_free (old_mrl);
+		parent = g_file_get_parent (old_file);
+		g_object_unref (old_file);
+
+		/* Resolve the URL */
+		new_file = g_file_get_child (parent, mrl);
+		g_object_unref (parent);
+
+		new_mrl = g_file_get_uri (new_file);
+		g_object_unref (new_file);
+	}
+
+	bacon_video_widget_close (totem->bvw);
+	totem_file_closed (totem);
+	totem_gdk_window_set_waiting_cursor (totem->win->window);
+	bacon_video_widget_open (totem->bvw, new_mrl ? new_mrl : mrl, NULL);
+	totem_file_opened (totem, new_mrl ? new_mrl : mrl);
+	gdk_window_set_cursor (totem->win->window, NULL);
+	bacon_video_widget_play (bvw, NULL);
+	g_free (new_mrl);
+}
+
+/* This is only called when we are playing a DVD or a radio */
+static void
+on_title_change_event (BaconVideoWidget *bvw, const char *string, Totem *totem)
+{
+	update_mrl_label (totem, string);
+	update_buttons (totem);
+	totem_playlist_set_title (TOTEM_PLAYLIST (totem->playlist),
+				  string, TRUE);
+}
+
+static void
+on_channels_change_event (BaconVideoWidget *bvw, Totem *totem)
+{
+	gchar *name;
+
+	totem_sublang_update (totem);
+
+	/* updated stream info (new song) */
+	name = totem_get_nice_name_for_stream (totem);
+
+	if (name != NULL) {
+		update_mrl_label (totem, name);
+		totem_playlist_set_title
+			(TOTEM_PLAYLIST (totem->playlist), name, TRUE);
+		g_free (name);
+	}
+}
+
+static void
+on_playlist_change_name (TotemPlaylist *playlist, Totem *totem)
+{
+	char *name;
+	gboolean cur;
+
+	if ((name = totem_playlist_get_current_title (playlist,
+						      &cur)) != NULL) {
+		update_mrl_label (totem, name);
+		g_free (name);
+	}
+}
+
+static void
+on_got_metadata_event (BaconVideoWidget *bvw, Totem *totem)
+{
+        char *name = NULL;
+	
+	name = totem_get_nice_name_for_stream (totem);
+
+	if (name != NULL) {
+		totem_playlist_set_title
+			(TOTEM_PLAYLIST (totem->playlist), name, FALSE);
+		g_free (name);
+	}
+	
+	on_playlist_change_name (TOTEM_PLAYLIST (totem->playlist), totem);
+}
+
+static void
+on_error_event (BaconVideoWidget *bvw, char *message,
+                gboolean playback_stopped, gboolean fatal, Totem *totem)
+{
+	/* Clear the seek if it's there, we only want to try and seek
+	 * the first file, even if it's not there */
+	totem->seek_to = 0;
+
+	if (playback_stopped)
+		play_pause_set_label (totem, STATE_STOPPED);
+
+	if (fatal == FALSE) {
+		totem_action_error (_("An error occurred"), message, totem);
+	} else {
+		totem_action_error_and_exit (_("An error occurred"),
+				message, totem);
+	}
+}
+
+static void
+on_buffering_event (BaconVideoWidget *bvw, int percentage, Totem *totem)
+{
+	totem_statusbar_push (TOTEM_STATUSBAR (totem->statusbar), percentage);
+}
+
+static void
+update_seekable (Totem *totem)
+{
+	GtkAction *action;
+	GtkActionGroup *action_group;
+	gboolean seekable;
+
+	seekable = bacon_video_widget_is_seekable (totem->bvw);
+	if (totem->seekable == seekable)
+		return;
+	totem->seekable = seekable;
+
+	/* 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);
+	totem_action_set_sensitivity ("skip-backwards", seekable);*/
+	action_group = GTK_ACTION_GROUP (gtk_builder_get_object (totem->xml, "skip-action-group"));
+
+	action = gtk_action_group_get_action (action_group, "skip-forward");
+	gtk_action_set_sensitive (action, seekable);
+
+	action = gtk_action_group_get_action (action_group, "skip-backwards");
+	gtk_action_set_sensitive (action, seekable);
+
+	/* This is for the session restore to seek */
+	if (seekable != FALSE && totem->seek_to != 0) {
+		bacon_video_widget_seek_time (totem->bvw,
+				totem->seek_to, NULL);
+		totem_action_pause (totem);
+	}
+	totem->seek_to = 0;
+
+	g_object_notify (G_OBJECT (totem), "seekable");
+}
+
+static void
+update_current_time (BaconVideoWidget *bvw,
+		gint64 current_time,
+		gint64 stream_length,
+		double current_position,
+		gboolean seekable, Totem *totem)
+{
+	if (totem->seek_lock == FALSE)
+	{
+		gtk_adjustment_set_value (totem->seekadj,
+				current_position * 65535);
+
+		if (stream_length == 0 && totem->mrl != NULL)
+		{
+			totem_statusbar_set_time_and_length
+				(TOTEM_STATUSBAR (totem->statusbar),
+				(int) (current_time / 1000), -1);
+		} else {
+			totem_statusbar_set_time_and_length
+				(TOTEM_STATUSBAR (totem->statusbar),
+				(int) (current_time / 1000),
+				(int) (stream_length / 1000));
+		}
+
+		totem_time_label_set_time
+			(TOTEM_TIME_LABEL (totem->fs->time_label),
+			 current_time, stream_length);
+	}
+
+	if (totem->stream_length != stream_length) {
+		g_object_notify (G_OBJECT (totem), "stream-length");
+		totem->stream_length = stream_length;
+	}
+}
+
+void
+volume_button_value_changed_cb (GtkScaleButton *button, gdouble value, Totem *totem)
+{
+	totem->muted = FALSE;
+	bacon_video_widget_set_volume (totem->bvw, value);
+}
+
+static void
+update_volume_sliders (Totem *totem)
+{
+	double volume;
+	GtkAction *action;
+
+	volume = bacon_video_widget_get_volume (totem->bvw);
+
+	g_signal_handlers_block_by_func (totem->volume, volume_button_value_changed_cb, totem);
+	gtk_scale_button_set_value (GTK_SCALE_BUTTON (totem->volume), volume);
+	g_signal_handlers_unblock_by_func (totem->volume, volume_button_value_changed_cb, totem);
+  
+	action = gtk_action_group_get_action (totem->main_action_group, "volume-down");
+	gtk_action_set_sensitive (action, volume > VOLUME_EPSILON && totem->volume_sensitive);
+
+	action = gtk_action_group_get_action (totem->main_action_group, "volume-up");
+	gtk_action_set_sensitive (action, volume < (1.0 - VOLUME_EPSILON) && totem->volume_sensitive);
+}
+
+static void
+property_notify_cb_volume (BaconVideoWidget *bvw, GParamSpec *spec, Totem *totem)
+{
+	update_volume_sliders (totem);
+}
+
+static void
+property_notify_cb_logo_mode (BaconVideoWidget *bvw, GParamSpec *spec, Totem *totem)
+{
+	gboolean enabled;
+	enabled = bacon_video_widget_get_logo_mode (totem->bvw);
+	totem_action_zoom (totem, enabled ? ZOOM_DISABLE : ZOOM_ENABLE);
+}
+
+static void
+property_notify_cb_seekable (BaconVideoWidget *bvw, GParamSpec *spec, Totem *totem)
+{
+	update_seekable (totem);
+}
+
+gboolean
+seek_slider_pressed_cb (GtkWidget *widget, GdkEventButton *event, Totem *totem)
+{
+	/* HACK: we want the behaviour you get with the middle button, so we
+	 * mangle the event.  clicking with other buttons moves the slider in
+	 * step increments, clicking with the middle button moves the slider to
+	 * the location of the click.
+	 */
+	event->button = 2;
+
+	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;
+}
+
+void
+seek_slider_changed_cb (GtkAdjustment *adj, Totem *totem)
+{
+	double pos;
+	gint time;
+
+	if (totem->seek_lock == FALSE)
+		return;
+
+	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);
+
+	if (bacon_video_widget_can_direct_seek (totem->bvw) != FALSE)
+		totem_action_seek (totem, pos);
+}
+
+gboolean
+seek_slider_released_cb (GtkWidget *widget, GdkEventButton *event, Totem *totem)
+{
+	GtkAdjustment *adj;
+	gdouble val;
+
+	/* HACK: see seek_slider_pressed_cb */
+	event->button = 2;
+
+	/* set to FALSE here to avoid triggering a final seek when
+	 * syncing the adjustments while being in direct seek mode */
+	totem->seek_lock = FALSE;
+
+	/* sync both adjustments */
+	adj = gtk_range_get_adjustment (GTK_RANGE (widget));
+	val = gtk_adjustment_get_value (adj);
+
+	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;
+}
+
+gboolean
+totem_action_open_files (Totem *totem, char **list)
+{
+	GSList *slist = NULL;
+	int i, retval;
+
+	for (i = 0 ; list[i] != NULL; i++)
+		slist = g_slist_prepend (slist, list[i]);
+
+	slist = g_slist_reverse (slist);
+	retval = totem_action_open_files_list (totem, slist);
+	g_slist_free (slist);
+
+	return retval;
+}
+
+static gboolean
+totem_action_open_files_list (Totem *totem, GSList *list)
+{
+	GSList *l;
+	gboolean changed;
+	gboolean cleared;
+
+	changed = FALSE;
+	cleared = FALSE;
+
+	if (list == NULL)
+		return changed;
+
+	totem_gdk_window_set_waiting_cursor (totem->win->window);
+
+	for (l = list ; l != NULL; l = l->next)
+	{
+		char *filename;
+		char *data = l->data;
+
+		if (data == NULL)
+			continue;
+
+		/* Ignore relatives paths that start with "--", tough luck */
+		if (data[0] == '-' && data[1] == '-')
+			continue;
+
+		/* Get the subtitle part out for our tests */
+		filename = totem_create_full_path (data);
+		if (filename == NULL)
+			filename = g_strdup (data);
+
+		if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)
+				|| strstr (filename, "#") != NULL
+				|| strstr (filename, "://") != NULL
+				|| g_str_has_prefix (filename, "dvd:") != FALSE
+				|| g_str_has_prefix (filename, "vcd:") != FALSE
+				|| g_str_has_prefix (filename, "dvb:") != FALSE)
+		{
+			if (cleared == FALSE)
+			{
+				/* The function that calls us knows better
+				 * if we should be doing something with the 
+				 * changed playlist ... */
+				g_signal_handlers_disconnect_by_func
+					(G_OBJECT (totem->playlist),
+					 playlist_changed_cb, totem);
+				changed = totem_playlist_clear (totem->playlist);
+				bacon_video_widget_close (totem->bvw);
+				totem_file_closed (totem);
+				cleared = TRUE;
+			}
+
+			if (totem_is_block_device (filename) != FALSE) {
+				totem_action_load_media_device (totem, data);
+				changed = TRUE;
+			} else if (g_str_has_prefix (filename, "dvb:/") != FALSE) {
+				totem_playlist_add_mrl (totem->playlist, data, NULL);
+				changed = TRUE;
+			} else if (g_str_equal (filename, "dvb:") != FALSE) {
+				totem_action_load_media (totem, MEDIA_TYPE_DVB, "0");
+				changed = TRUE;
+			} else if (totem_playlist_add_mrl (totem->playlist, filename, NULL) != FALSE) {
+				totem_action_add_recent (totem, filename);
+				changed = TRUE;
+			}
+		}
+
+		g_free (filename);
+	}
+
+	gdk_window_set_cursor (totem->win->window, NULL);
+
+	/* ... and reconnect because we're nice people */
+	if (cleared != FALSE)
+	{
+		g_signal_connect (G_OBJECT (totem->playlist),
+				"changed", G_CALLBACK (playlist_changed_cb),
+				totem);
+	}
+
+	return changed;
+}
+
+void
+show_controls (Totem *totem, gboolean was_fullscreen)
+{
+	GtkAction *action;
+	GtkWidget *menubar, *controlbar, *statusbar, *bvw_box, *widget;
+	int width = 0, height = 0;
+
+	if (totem->bvw == NULL)
+		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);
+
+	action = gtk_action_group_get_action (totem->main_action_group, "show-controls");
+	gtk_action_set_sensitive (action, !totem_is_fullscreen (totem));
+
+	if (totem->controls_visibility == TOTEM_CONTROLS_VISIBLE) {
+		if (was_fullscreen == FALSE) {
+			height = widget->allocation.height;
+			width =	widget->allocation.width;
+		}
+
+		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
+			   is no convenience method to get the handle's width.
+			   */
+			GValue value = { 0, };
+			GtkWidget *pane;
+			int handle_size;
+
+			g_value_init (&value, G_TYPE_INT);
+			pane = GTK_WIDGET (gtk_builder_get_object (totem->xml,
+					"tmw_main_pane"));
+			gtk_widget_style_get_property (pane, "handle-size",
+					&value);
+			handle_size = g_value_get_int (&value);
+			g_value_unset (&value);
+			
+			gtk_widget_show (totem->sidebar);
+			width += totem->sidebar->allocation.width
+				+ handle_size;
+		} else {
+			gtk_widget_hide (totem->sidebar);
+		}
+
+		gtk_container_set_border_width (GTK_CONTAINER (bvw_box),
+				BVW_VBOX_BORDER_WIDTH);
+
+		if (was_fullscreen == FALSE) {
+			height += menubar->allocation.height
+				+ controlbar->allocation.height
+				+ statusbar->allocation.height
+				+ 2 * BVW_VBOX_BORDER_WIDTH;
+			width += 2 * BVW_VBOX_BORDER_WIDTH;
+			gtk_window_resize (GTK_WINDOW(totem->win),
+					width, height);
+		}
+	} else {
+		if (totem->controls_visibility == TOTEM_CONTROLS_HIDDEN) {
+			width = widget->allocation.width;
+			height = widget->allocation.height;
+		}
+
+		/* Hide and make the menubar unsensitive */
+		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 */
+		gtk_container_set_border_width (GTK_CONTAINER (bvw_box), 0);
+
+		if (totem->controls_visibility == TOTEM_CONTROLS_HIDDEN) {
+			gtk_window_resize (GTK_WINDOW(totem->win),
+					width, height);
+		}
+	}
+}
+
+/**
+ * totem_action_toggle_controls:
+ * @totem: a #TotemObject
+ *
+ * If Totem's not fullscreened, this toggles the state of the "Show Controls"
+ * menu entry, and consequently shows or hides the controls in the UI.
+ **/
+void
+totem_action_toggle_controls (Totem *totem)
+{
+	GtkAction *action;
+	gboolean state;
+
+	if (totem_is_fullscreen (totem) != FALSE)
+		return;
+
+ 	action = gtk_action_group_get_action (totem->main_action_group,
+ 		"show-controls");
+ 	state = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+ 	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !state);
+}
+
+void
+totem_action_next_angle (Totem *totem)
+{
+	if (totem_playing_dvd (totem->mrl) != FALSE)
+		bacon_video_widget_dvd_event (totem->bvw, BVW_DVD_NEXT_ANGLE);
+}
+
+void
+totem_action_set_playlist_index (Totem *totem, guint index)
+{
+	char *mrl, *subtitle;
+
+	totem_playlist_set_current (totem->playlist, index);
+	mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
+	totem_action_set_mrl_and_play (totem, mrl, subtitle);
+	g_free (mrl);
+	g_free (subtitle);
+}
+
+/**
+ * totem_action_remote:
+ * @totem: a #TotemObject
+ * @cmd: a #TotemRemoteCommand
+ * @url: an MRL to play, or %NULL
+ *
+ * Executes the specified @cmd on this instance of Totem. If @cmd
+ * is an operation requiring an MRL, @url is required; it can be %NULL
+ * otherwise.
+ *
+ * If Totem's fullscreened and the operation is executed correctly,
+ * the controls will appear as if the user had moved the mouse.
+ **/
+void
+totem_action_remote (Totem *totem, TotemRemoteCommand cmd, const char *url)
+{
+	gboolean handled = TRUE;
+
+	switch (cmd) {
+	case TOTEM_REMOTE_COMMAND_PLAY:
+		totem_action_play (totem);
+		break;
+	case TOTEM_REMOTE_COMMAND_PLAYPAUSE:
+		totem_action_play_pause (totem);
+		break;
+	case TOTEM_REMOTE_COMMAND_PAUSE:
+		totem_action_pause (totem);
+		break;
+	case TOTEM_REMOTE_COMMAND_STOP: {
+		char *mrl, *subtitle;
+
+		totem_playlist_set_at_start (totem->playlist);
+		update_buttons (totem);
+		totem_action_stop (totem);
+		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
+		if (mrl != NULL) {
+			totem_action_set_mrl_with_warning (totem, mrl, subtitle, FALSE);
+			bacon_video_widget_pause (totem->bvw);
+			g_free (mrl);
+			g_free (subtitle);
+		}
+		break;
+	};
+	case TOTEM_REMOTE_COMMAND_SEEK_FORWARD: {
+		double offset = 0;
+
+		if (url != NULL)
+			offset = g_ascii_strtod (url, NULL);
+		if (offset == 0) {
+			totem_action_seek_relative (totem, SEEK_FORWARD_OFFSET * 1000);
+		} else {
+			totem_action_seek_relative (totem, offset * 1000);
+		}
+		break;
+	}
+	case TOTEM_REMOTE_COMMAND_SEEK_BACKWARD: {
+		double offset = 0;
+
+		if (url != NULL)
+			offset = g_ascii_strtod (url, NULL);
+		if (offset == 0)
+			totem_action_seek_relative (totem, SEEK_BACKWARD_OFFSET * 1000);
+		else
+			totem_action_seek_relative (totem,  - (offset * 1000));
+		break;
+	}
+	case TOTEM_REMOTE_COMMAND_VOLUME_UP:
+		totem_action_volume_relative (totem, VOLUME_UP_OFFSET);
+		break;
+	case TOTEM_REMOTE_COMMAND_VOLUME_DOWN:
+		totem_action_volume_relative (totem, VOLUME_DOWN_OFFSET);
+		break;
+	case TOTEM_REMOTE_COMMAND_NEXT:
+		totem_action_next (totem);
+		break;
+	case TOTEM_REMOTE_COMMAND_PREVIOUS:
+		totem_action_previous (totem);
+		break;
+	case TOTEM_REMOTE_COMMAND_FULLSCREEN:
+		totem_action_fullscreen_toggle (totem);
+		break;
+	case TOTEM_REMOTE_COMMAND_QUIT:
+		totem_action_exit (totem);
+		break;
+	case TOTEM_REMOTE_COMMAND_ENQUEUE:
+		g_assert (url != NULL);
+		if (totem_playlist_add_mrl_with_cursor (totem->playlist, url, NULL) != FALSE) {
+			totem_action_add_recent (totem, url);
+		}
+		break;
+	case TOTEM_REMOTE_COMMAND_REPLACE:
+		totem_playlist_clear (totem->playlist);
+		if (url == NULL) {
+			bacon_video_widget_close (totem->bvw);
+			totem_file_closed (totem);
+			totem_action_set_mrl (totem, NULL, NULL);
+			break;
+		}
+		if (strcmp (url, "dvd:") == 0) {
+			/* FIXME b0rked */
+			totem_action_play_media (totem, MEDIA_TYPE_DVD, NULL);
+		} else if (strcmp (url, "vcd:") == 0) {
+			/* FIXME b0rked */
+			totem_action_play_media (totem, MEDIA_TYPE_VCD, NULL);
+		} else if (g_str_has_prefix (url, "dvb:") != FALSE) {
+			totem_action_load_media (totem, MEDIA_TYPE_DVB, "0");
+		} else if (totem_playlist_add_mrl_with_cursor (totem->playlist, url, NULL) != FALSE) {
+			totem_action_add_recent (totem, url);
+		}
+		break;
+	case TOTEM_REMOTE_COMMAND_SHOW:
+		gtk_window_present (GTK_WINDOW (totem->win));
+		break;
+	case TOTEM_REMOTE_COMMAND_TOGGLE_CONTROLS:
+		if (totem->controls_visibility != TOTEM_CONTROLS_FULLSCREEN)
+		{
+			GtkToggleAction *action;
+			gboolean state;
+
+			action = GTK_TOGGLE_ACTION (gtk_action_group_get_action
+					(totem->main_action_group,
+					 "show-controls"));
+			state = gtk_toggle_action_get_active (action);
+			gtk_toggle_action_set_active (action, !state);
+		}
+		break;
+	case TOTEM_REMOTE_COMMAND_SHOW_PLAYING:
+		{
+			char *title;
+			gboolean custom;
+
+			title = totem_playlist_get_current_title
+				(totem->playlist, &custom);
+			bacon_message_connection_send (totem->conn,
+					title ? title : SHOW_PLAYING_NO_TRACKS);
+			g_free (title);
+		}
+		break;
+	case TOTEM_REMOTE_COMMAND_SHOW_VOLUME:
+		{
+			char *vol_str;
+			int vol;
+
+			if (bacon_video_widget_can_set_volume (totem->bvw) == FALSE)
+				vol = 0;
+			else
+				vol = bacon_video_widget_get_volume (totem->bvw);
+			vol_str = g_strdup_printf ("%d", vol);
+			bacon_message_connection_send (totem->conn, vol_str);
+			g_free (vol_str);
+		}
+		break;
+	case TOTEM_REMOTE_COMMAND_UP:
+		bacon_video_widget_dvd_event (totem->bvw,
+				BVW_DVD_ROOT_MENU_UP);
+		break;
+	case TOTEM_REMOTE_COMMAND_DOWN:
+		bacon_video_widget_dvd_event (totem->bvw,
+				BVW_DVD_ROOT_MENU_DOWN);
+		break;
+	case TOTEM_REMOTE_COMMAND_LEFT:
+		bacon_video_widget_dvd_event (totem->bvw,
+				BVW_DVD_ROOT_MENU_LEFT);
+		break;
+	case TOTEM_REMOTE_COMMAND_RIGHT:
+		bacon_video_widget_dvd_event (totem->bvw,
+				BVW_DVD_ROOT_MENU_RIGHT);
+		break;
+	case TOTEM_REMOTE_COMMAND_SELECT:
+		bacon_video_widget_dvd_event (totem->bvw,
+				BVW_DVD_ROOT_MENU_SELECT);
+		break;
+	case TOTEM_REMOTE_COMMAND_DVD_MENU:
+		bacon_video_widget_dvd_event (totem->bvw,
+				BVW_DVD_ROOT_MENU);
+		break;
+	case TOTEM_REMOTE_COMMAND_ZOOM_UP:
+		totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
+		break;
+	case TOTEM_REMOTE_COMMAND_ZOOM_DOWN:
+		totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
+		break;
+	case TOTEM_REMOTE_COMMAND_EJECT:
+		totem_action_eject (totem);
+		break;
+	case TOTEM_REMOTE_COMMAND_PLAY_DVD:
+		/* TODO - how to see if can, and play the DVD (like the menu item) */
+		break;
+	case TOTEM_REMOTE_COMMAND_MUTE:
+		totem_action_volume_toggle_mute (totem);
+		break;
+	case TOTEM_REMOTE_COMMAND_TOGGLE_ASPECT:
+		totem_action_toggle_aspect_ratio (totem);
+		break;
+	default:
+		handled = FALSE;
+		break;
+	}
+
+	if (handled != FALSE
+			&& gtk_window_is_active (GTK_WINDOW (totem->win))
+			&& totem_fullscreen_is_fullscreen (totem->fs) != FALSE) {
+		totem_fullscreen_show_popups (totem->fs, TRUE);
+	}
+}
+
+void totem_action_remote_set_setting (Totem *totem,
+				      TotemRemoteSetting setting,
+				      gboolean value)
+{
+	GtkAction *action;
+
+	action = NULL;
+
+	switch (setting) {
+	case TOTEM_REMOTE_SETTING_SHUFFLE:
+		action = gtk_action_group_get_action (totem->main_action_group, "shuffle-mode");
+		break;
+	case TOTEM_REMOTE_SETTING_REPEAT:
+		action = gtk_action_group_get_action (totem->main_action_group, "repeat-mode");
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+
+	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), value);
+}
+
+gboolean totem_action_remote_get_setting (Totem *totem,
+					  TotemRemoteSetting setting)
+{
+	GtkAction *action;
+
+	action = NULL;
+
+	switch (setting) {
+	case TOTEM_REMOTE_SETTING_SHUFFLE:
+		action = gtk_action_group_get_action (totem->main_action_group, "shuffle-mode");
+		break;
+	case TOTEM_REMOTE_SETTING_REPEAT:
+		action = gtk_action_group_get_action (totem->main_action_group, "repeat-mode");
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+
+	return gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+}
+
+static void
+playlist_changed_cb (GtkWidget *playlist, Totem *totem)
+{
+	char *mrl, *subtitle;
+
+	update_buttons (totem);
+	mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
+
+	if (mrl == NULL)
+		return;
+
+	if (totem_playlist_get_playing (totem->playlist) == TOTEM_PLAYLIST_STATUS_NONE)
+		totem_action_set_mrl_and_play (totem, mrl, subtitle);
+
+	g_free (mrl);
+	g_free (subtitle);
+}
+
+static void
+item_activated_cb (GtkWidget *playlist, Totem *totem)
+{
+	totem_action_seek (totem, 0);
+}
+
+static void
+current_removed_cb (GtkWidget *playlist, Totem *totem)
+{
+	char *mrl, *subtitle;
+
+	/* Set play button status */
+	play_pause_set_label (totem, STATE_STOPPED);
+	mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
+
+	if (mrl == NULL) {
+		g_free (subtitle);
+		subtitle = NULL;
+		totem_playlist_set_at_start (totem->playlist);
+		update_buttons (totem);
+		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
+	} else {
+		update_buttons (totem);
+	}
+
+	totem_action_set_mrl_and_play (totem, mrl, subtitle);
+	g_free (mrl);
+	g_free (subtitle);
+}
+
+static void
+subtitle_changed_cb (GtkWidget *playlist, Totem *totem)
+{
+	char *mrl, *subtitle;
+
+	totem_action_stop (totem);
+	mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
+	totem_action_set_mrl_and_play (totem, mrl, subtitle);
+
+	g_free (mrl);
+	g_free (subtitle);
+}
+
+static void
+playlist_repeat_toggle_cb (TotemPlaylist *playlist, gboolean repeat, Totem *totem)
+{
+	GtkAction *action;
+
+	action = gtk_action_group_get_action (totem->main_action_group, "repeat-mode");
+
+	g_signal_handlers_block_matched (G_OBJECT (action), G_SIGNAL_MATCH_DATA, 0, 0,
+			NULL, NULL, totem);
+
+	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), repeat);
+
+	g_signal_handlers_unblock_matched (G_OBJECT (action), G_SIGNAL_MATCH_DATA, 0, 0,
+			NULL, NULL, totem);
+}
+
+static void
+playlist_shuffle_toggle_cb (TotemPlaylist *playlist, gboolean shuffle, Totem *totem)
+{
+	GtkAction *action;
+
+	action = gtk_action_group_get_action (totem->main_action_group, "shuffle-mode");
+
+	g_signal_handlers_block_matched (G_OBJECT (action), G_SIGNAL_MATCH_DATA, 0, 0,
+			NULL, NULL, totem);
+
+	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), shuffle);
+
+	g_signal_handlers_unblock_matched (G_OBJECT (action), G_SIGNAL_MATCH_DATA, 0, 0,
+			NULL, NULL, totem);
+}
+
+/**
+ * totem_is_fullscreen:
+ * @totem: a #TotemObject
+ *
+ * Returns %TRUE if Totem is fullscreened.
+ *
+ * Return value: %TRUE if Totem is fullscreened
+ **/
+gboolean
+totem_is_fullscreen (Totem *totem)
+{
+	g_return_val_if_fail (TOTEM_IS_OBJECT (totem), FALSE);
+
+	return (totem->controls_visibility == TOTEM_CONTROLS_FULLSCREEN);
+}
+
+/**
+ * totem_is_playing:
+ * @totem: a #TotemObject
+ *
+ * Returns %TRUE if Totem is playing a stream.
+ *
+ * Return value: %TRUE if Totem is playing a stream
+ **/
+gboolean
+totem_is_playing (Totem *totem)
+{
+	g_return_val_if_fail (TOTEM_IS_OBJECT (totem), FALSE);
+
+	if (totem->bvw == NULL)
+		return FALSE;
+
+	return bacon_video_widget_is_playing (totem->bvw) != FALSE;
+}
+
+gboolean
+totem_is_paused (Totem *totem)
+{
+	g_return_val_if_fail (TOTEM_IS_OBJECT (totem), FALSE);
+
+	return totem->state == STATE_PAUSED;
+}
+
+/**
+ * totem_is_seekable:
+ * @totem: a #TotemObject
+ *
+ * Returns %TRUE if the current stream is seekable.
+ *
+ * Return value: %TRUE if the current stream is seekable
+ **/
+gboolean
+totem_is_seekable (Totem *totem)
+{
+	g_return_val_if_fail (TOTEM_IS_OBJECT (totem), FALSE);
+
+	if (totem->bvw == NULL)
+		return FALSE;
+
+	return bacon_video_widget_is_seekable (totem->bvw) != FALSE;
+}
+
+static void
+on_mouse_click_fullscreen (GtkWidget *widget, Totem *totem)
+{
+	if (totem_fullscreen_is_fullscreen (totem->fs) != FALSE)
+		totem_fullscreen_show_popups (totem->fs, TRUE);
+}
+
+static gboolean
+on_video_button_press_event (BaconVideoWidget *bvw, GdkEventButton *event,
+		Totem *totem)
+{
+	if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
+		totem_action_fullscreen_toggle(totem);
+		return TRUE;
+	} else if (event->type == GDK_BUTTON_PRESS && event->button == 2) {
+		totem_action_play_pause(totem);
+		return TRUE;
+	} else if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
+		totem_action_menu_popup (totem, event->button);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static gboolean
+on_eos_event (GtkWidget *widget, Totem *totem)
+{
+	if (bacon_video_widget_get_logo_mode (totem->bvw) != FALSE)
+		return FALSE;
+
+	/* EOS on DVB means that we lost the signal */
+	if (totem->mrl != NULL && g_str_has_prefix (totem->mrl, "dvb://") != FALSE) {
+		totem_action_stop (totem);
+		totem_action_error_and_exit (_("TV signal lost"),
+					     _("Please verify your hardware setup."),
+					     totem);
+		return FALSE;
+	}
+
+	if (totem_playlist_has_next_mrl (totem->playlist) == FALSE
+			&& totem_playlist_get_repeat (totem->playlist) == FALSE)
+	{
+		char *mrl, *subtitle;
+
+		/* Set play button status */
+		totem_playlist_set_at_start (totem->playlist);
+		update_buttons (totem);
+		totem_action_stop (totem);
+		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
+		totem_action_set_mrl_with_warning (totem, mrl, subtitle, FALSE);
+		bacon_video_widget_pause (totem->bvw);
+		g_free (mrl);
+		g_free (subtitle);
+	} else {
+		if (totem_playlist_get_repeat (totem->playlist)
+				&& totem_playlist_get_last  (totem->playlist) == 0
+				&& totem_is_seekable (totem))
+			totem_action_seek_time (totem, 0);
+		else
+			totem_action_next (totem);
+	}
+
+	return FALSE;
+}
+
+static gboolean
+totem_action_handle_key_release (Totem *totem, GdkEventKey *event)
+{
+	gboolean retval = TRUE;
+
+	switch (event->keyval) {
+	case GDK_Left:
+	case GDK_Right:
+		totem_statusbar_set_seeking (TOTEM_STATUSBAR (totem->statusbar), FALSE);
+		totem_time_label_set_seeking (TOTEM_TIME_LABEL (totem->fs->time_label), FALSE);
+		break;
+	}
+
+	return retval;
+}
+
+static void
+totem_action_handle_seek (Totem *totem, GdkEventKey *event, gboolean is_forward)
+{
+	if (is_forward != FALSE) {
+		if (event->state & GDK_SHIFT_MASK)
+			totem_action_seek_relative (totem, SEEK_FORWARD_SHORT_OFFSET * 1000);
+		else if (event->state & GDK_CONTROL_MASK)
+			totem_action_seek_relative (totem, SEEK_FORWARD_LONG_OFFSET * 1000);
+		else
+			totem_action_seek_relative (totem, SEEK_FORWARD_OFFSET * 1000);
+	} else {
+		if (event->state & GDK_SHIFT_MASK)
+			totem_action_seek_relative (totem, SEEK_BACKWARD_SHORT_OFFSET * 1000);
+		else if (event->state & GDK_CONTROL_MASK)
+			totem_action_seek_relative (totem, SEEK_BACKWARD_LONG_OFFSET * 1000);
+		else
+			totem_action_seek_relative (totem, SEEK_BACKWARD_OFFSET * 1000);
+	}
+}
+
+static gboolean
+totem_action_handle_key_press (Totem *totem, GdkEventKey *event)
+{
+	gboolean retval = TRUE;
+
+	switch (event->keyval) {
+	case GDK_A:
+	case GDK_a:
+		totem_action_toggle_aspect_ratio (totem);
+		break;
+#ifdef HAVE_XFREE
+	case XF86XK_AudioPrev:
+	case XF86XK_Back:
+#endif /* HAVE_XFREE */
+	case GDK_B:
+	case GDK_b:
+		totem_action_previous (totem);
+		break;
+	case GDK_C:
+	case GDK_c:
+		bacon_video_widget_dvd_event (totem->bvw,
+				BVW_DVD_CHAPTER_MENU);
+		break;
+	case GDK_F11:
+	case GDK_f:
+	case GDK_F:
+		totem_action_fullscreen_toggle (totem);
+		break;
+	case GDK_g:
+	case GDK_G:
+		totem_action_next_angle (totem);
+		break;
+	case GDK_h:
+	case GDK_H:
+		totem_action_toggle_controls (totem);
+		break;
+	case GDK_i:
+	case GDK_I:
+		{
+			GtkToggleAction *action;
+			gboolean state;
+
+			action = GTK_TOGGLE_ACTION (gtk_action_group_get_action
+					(totem->main_action_group,
+					 "deinterlace"));
+			state = gtk_toggle_action_get_active (action);
+			gtk_toggle_action_set_active (action, !state);
+		}
+		break;
+	case GDK_M:
+	case GDK_m:
+		bacon_video_widget_dvd_event (totem->bvw, BVW_DVD_ROOT_MENU);
+		break;
+#ifdef HAVE_XFREE
+	case XF86XK_AudioNext:
+	case XF86XK_Forward:
+#endif /* HAVE_XFREE */
+	case GDK_N:
+	case GDK_n:
+		totem_action_next (totem);
+		break;
+#ifdef HAVE_XFREE
+	case XF86XK_OpenURL:
+		totem_action_fullscreen (totem, FALSE);
+		totem_action_open_location (totem);
+		break;
+#endif /* HAVE_XFREE */
+	case GDK_O:
+	case GDK_o:
+#ifdef HAVE_XFREE
+	case XF86XK_Open:
+#endif /* HAVE_XFREE */
+		totem_action_fullscreen (totem, FALSE);
+		totem_action_open (totem);
+		break;
+#ifdef HAVE_XFREE
+	case XF86XK_AudioPlay:
+#endif /* HAVE_XFREE */
+	case GDK_p:
+	case GDK_P:
+		if (event->state & GDK_CONTROL_MASK)
+			totem_action_show_properties (totem);
+		else 
+			totem_action_play_pause (totem);
+		break;
+#ifdef HAVE_XFREE
+	case XF86XK_AudioPause:
+	case XF86XK_AudioStop:
+		totem_action_pause (totem);
+		break;
+#endif /* HAVE_XFREE */
+	case GDK_q:
+	case GDK_Q:
+		totem_action_exit (totem);
+		break;
+	case GDK_r:
+	case GDK_R:
+#ifdef HAVE_XFREE
+	case XF86XK_ZoomIn:
+#endif /* HAVE_XFREE */
+		totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
+		break;
+	case GDK_t:
+	case GDK_T:
+#ifdef HAVE_XFREE
+	case XF86XK_ZoomOut:
+#endif /* HAVE_XFREE */
+		totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
+		break;
+#ifdef HAVE_XFREE
+	case XF86XK_Eject:
+		totem_action_eject (totem);
+		break;
+#endif /* HAVE_XFREE */
+	case GDK_Escape:
+		if (event->state & GDK_SUPER_MASK)
+			bacon_video_widget_dvd_event (totem->bvw, BVW_DVD_ROOT_MENU);
+		else
+			totem_action_fullscreen (totem, FALSE);
+		break;
+	case GDK_Left:
+	case GDK_Right:
+		{
+			gboolean is_forward;
+
+			if (totem_is_fullscreen (totem) != FALSE)
+				totem_fullscreen_show_popups (totem->fs, FALSE);
+
+			is_forward = (event->keyval == GDK_Right);
+			/* Switch direction in RTL environment */
+			if (gtk_widget_get_direction (totem->win) == GTK_TEXT_DIR_RTL)
+				is_forward = !is_forward;
+			totem_action_handle_seek (totem, event, is_forward);
+		}
+		break;
+	case GDK_space:
+		if (totem_is_fullscreen (totem) != FALSE || gtk_widget_is_focus (GTK_WIDGET (totem->bvw)) != FALSE)
+			totem_action_play_pause (totem);
+		else
+			retval = FALSE;
+		break;
+	case GDK_Up:
+		totem_action_volume_relative (totem, VOLUME_UP_OFFSET);
+		break;
+	case GDK_Down:
+		totem_action_volume_relative (totem, VOLUME_DOWN_OFFSET);
+		break;
+	case GDK_0:
+		if (event->state & GDK_CONTROL_MASK)
+			totem_action_zoom_reset (totem);
+		else
+			totem_action_set_scale_ratio (totem, 0.5);
+		break;
+	case GDK_onehalf:
+		totem_action_set_scale_ratio (totem, 0.5);
+		break;
+	case GDK_1:
+		totem_action_set_scale_ratio (totem, 1);
+		break;
+	case GDK_2:
+		totem_action_set_scale_ratio (totem, 2);
+		break;
+	case GDK_Menu:
+		totem_action_menu_popup (totem, 0);
+		break;
+	case GDK_F10:
+		if (!(event->state & GDK_SHIFT_MASK))
+			return FALSE;
+
+		totem_action_menu_popup (totem, 0);
+		break;
+	case GDK_plus:
+	case GDK_KP_Add:
+		if (!(event->state & GDK_CONTROL_MASK)) {
+			totem_action_next (totem);
+		} else {
+			totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
+		}
+		break;
+	case GDK_minus:
+	case GDK_KP_Subtract:
+		if (!(event->state & GDK_CONTROL_MASK)) {
+			totem_action_previous (totem);
+		} else {
+			totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
+		}
+		break;
+	case GDK_KP_Up:
+	case GDK_KP_8:
+		bacon_video_widget_dvd_event (totem->bvw, 
+					      BVW_DVD_ROOT_MENU_UP);
+		break;
+	case GDK_KP_Down:
+	case GDK_KP_2:
+		bacon_video_widget_dvd_event (totem->bvw, 
+					      BVW_DVD_ROOT_MENU_DOWN);
+		break;
+	case GDK_KP_Right:
+	case GDK_KP_6:
+		bacon_video_widget_dvd_event (totem->bvw, 
+					      BVW_DVD_ROOT_MENU_RIGHT);
+		break;
+	case GDK_KP_Left:
+	case GDK_KP_4:
+		bacon_video_widget_dvd_event (totem->bvw, 
+					      BVW_DVD_ROOT_MENU_LEFT);
+		break;
+	case GDK_KP_Begin:
+	case GDK_KP_5:
+		bacon_video_widget_dvd_event (totem->bvw,
+					      BVW_DVD_ROOT_MENU_SELECT);
+	default:
+		retval = FALSE;
+	}
+
+	return retval;
+}
+
+static gboolean
+totem_action_handle_scroll (Totem *totem, GdkScrollDirection direction)
+{
+	gboolean retval = TRUE;
+
+	if (totem_fullscreen_is_fullscreen (totem->fs) != FALSE)
+		totem_fullscreen_show_popups (totem->fs, TRUE);
+
+	switch (direction) {
+	case GDK_SCROLL_UP:
+		totem_action_seek_relative (totem, SEEK_FORWARD_SHORT_OFFSET * 1000);
+		break;
+	case GDK_SCROLL_DOWN:
+		totem_action_seek_relative (totem, SEEK_BACKWARD_SHORT_OFFSET * 1000);
+		break;
+	default:
+		retval = FALSE;
+	}
+
+	return retval;
+}
+
+int
+window_key_press_event_cb (GtkWidget *win, GdkEventKey *event, Totem *totem)
+{
+	if (totem_sidebar_is_focused (totem) != FALSE)
+		return FALSE;
+
+	/* Special case Eject, Open, Open URI and
+	 * seeking keyboard shortcuts */
+	if (event->state != 0
+			&& (event->state & GDK_CONTROL_MASK))
+	{
+		switch (event->keyval)
+		case GDK_E:
+		case GDK_e:
+		case GDK_O:
+		case GDK_o:
+		case GDK_L:
+		case GDK_l:
+		case GDK_q:
+		case GDK_Q:
+		case GDK_S:
+		case GDK_s:
+		case GDK_Right:
+		case GDK_Left:
+		case GDK_plus:
+		case GDK_KP_Add:
+		case GDK_minus:
+		case GDK_KP_Subtract:
+		case GDK_0:
+			if (event->type == GDK_KEY_PRESS) {
+				return totem_action_handle_key_press (totem, event);
+			} else {
+				return totem_action_handle_key_release (totem, event);
+			}
+	}
+
+	if (event->state != 0
+			&& (event->state & GDK_SUPER_MASK)) {
+		switch (event->keyval)
+		case GDK_Escape:
+			if (event->type == GDK_KEY_PRESS) {
+				return totem_action_handle_key_press (totem, event);
+			} else {
+				return totem_action_handle_key_release (totem, event);
+			}
+	}
+
+
+	/* If we have modifiers, and either Ctrl, Mod1 (Alt), or any
+	 * of Mod3 to Mod5 (Mod2 is num-lock...) are pressed, we
+	 * let Gtk+ handle the key */
+	if (event->state != 0
+			&& ((event->state & GDK_CONTROL_MASK)
+			|| (event->state & GDK_MOD1_MASK)
+			|| (event->state & GDK_MOD3_MASK)
+			|| (event->state & GDK_MOD4_MASK)
+			|| (event->state & GDK_MOD5_MASK)))
+		return FALSE;
+
+	if (event->type == GDK_KEY_PRESS) {
+		return totem_action_handle_key_press (totem, event);
+	} else {
+		return totem_action_handle_key_release (totem, event);
+	}
+}
+
+gboolean
+window_scroll_event_cb (GtkWidget *win, GdkEventScroll *event, Totem *totem)
+{
+	return totem_action_handle_scroll (totem, event->direction);
+}
+
+static void
+update_media_menu_items (Totem *totem)
+{
+	GMount *mount;
+	gboolean playing;
+
+	playing = totem_playing_dvd (totem->mrl);
+
+	totem_action_set_sensitivity ("dvd-root-menu", playing);
+	totem_action_set_sensitivity ("dvd-title-menu", playing);
+	totem_action_set_sensitivity ("dvd-audio-menu", playing);
+	totem_action_set_sensitivity ("dvd-angle-menu", playing);
+	totem_action_set_sensitivity ("dvd-chapter-menu", playing);
+	/* FIXME we should only show that if we have multiple angles */
+	totem_action_set_sensitivity ("next-angle", playing);
+
+	mount = totem_get_mount_for_media (totem->mrl);
+	totem_action_set_sensitivity ("eject", mount != NULL);
+	if (mount != NULL)
+		g_object_unref (mount);
+}
+
+static void
+update_buttons (Totem *totem)
+{
+	gboolean has_item;
+
+	/* Previous */
+	if (totem_playing_dvd (totem->mrl) != FALSE)
+		has_item = bacon_video_widget_has_previous_track (totem->bvw);
+	else
+		has_item = totem_playlist_has_previous_mrl (totem->playlist);
+
+	totem_action_set_sensitivity ("previous-chapter", has_item);
+
+	/* Next */
+	if (totem_playing_dvd (totem->mrl) != FALSE)
+		has_item = bacon_video_widget_has_next_track (totem->bvw);
+	else
+		has_item = totem_playlist_has_next_mrl (totem->playlist);
+
+	totem_action_set_sensitivity ("next-chapter", has_item);
+}
+
+void
+main_pane_size_allocated (GtkWidget *main_pane, GtkAllocation *allocation, Totem *totem)
+{
+	gulong handler_id;
+
+	if (!totem->maximised || GTK_WIDGET_MAPPED (totem->win)) {
+		handler_id = g_signal_handler_find (main_pane, 
+				G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
+				0, 0, NULL,
+				main_pane_size_allocated, totem);
+		g_signal_handler_disconnect (main_pane, handler_id);
+
+		gtk_paned_set_position (GTK_PANED (main_pane), allocation->width - totem->sidebar_w);
+	}
+}
+
+char *
+totem_setup_window (Totem *totem)
+{
+	GKeyFile *keyfile;
+	int w, h, i;
+	gboolean show_sidebar;
+	char *filename, *page_id;
+	GError *err = NULL;
+	GtkWidget *vbox;
+	GdkColor black;
+
+	filename = g_build_filename (totem_dot_dir (), "state.ini", NULL);
+	keyfile = g_key_file_new ();
+	if (g_key_file_load_from_file (keyfile, filename,
+			G_KEY_FILE_NONE, NULL) == FALSE) {
+		totem->sidebar_w = 0;
+		w = DEFAULT_WINDOW_W;
+		h = DEFAULT_WINDOW_H;
+		show_sidebar = TRUE;
+		page_id = NULL;
+		g_free (filename);
+	} else {
+		g_free (filename);
+
+		w = g_key_file_get_integer (keyfile, "State", "window_w", &err);
+		if (err != NULL) {
+			w = 0;
+			g_error_free (err);
+			err = NULL;
+		}
+
+		h = g_key_file_get_integer (keyfile, "State", "window_h", &err);
+		if (err != NULL) {
+			h = 0;
+			g_error_free (err);
+			err = NULL;
+		}
+
+		show_sidebar = g_key_file_get_boolean (keyfile, "State",
+				"show_sidebar", &err);
+		if (err != NULL) {
+			show_sidebar = TRUE;
+			g_error_free (err);
+			err = NULL;
+		}
+
+		totem->maximised = g_key_file_get_boolean (keyfile, "State",
+				"maximised", &err);
+		if (err != NULL) {
+			g_error_free (err);
+			err = NULL;
+		}
+
+		page_id = g_key_file_get_string (keyfile, "State",
+				"sidebar_page", &err);
+		if (err != NULL) {
+			g_error_free (err);
+			page_id = NULL;
+			err = NULL;
+		}
+
+		totem->sidebar_w = g_key_file_get_integer (keyfile, "State",
+				"sidebar_w", &err);
+		if (err != NULL) {
+			g_error_free (err);
+			totem->sidebar_w = 0;
+		}
+		g_key_file_free (keyfile);
+	}
+
+	if (w > 0 && h > 0 && totem->maximised == FALSE) {
+		gtk_window_set_default_size (GTK_WINDOW (totem->win),
+				w, h);
+		totem->window_w = w;
+		totem->window_h = h;
+	} else if (totem->maximised != FALSE) {
+		gtk_window_maximize (GTK_WINDOW (totem->win));
+	}
+
+	/* Set the vbox to be completely black */
+	vbox = GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_bvw_box"));
+	gdk_color_parse ("Black", &black);
+	for (i = 0; i <= GTK_STATE_INSENSITIVE; i++)
+		gtk_widget_modify_bg (vbox, i, &black);
+
+	totem_sidebar_setup (totem, show_sidebar, page_id);
+	return page_id;
+}
+
+void
+totem_callback_connect (Totem *totem)
+{
+	GtkWidget *item, *arrow;
+	GtkAction *action;
+	GtkActionGroup *action_group;
+	GtkBox *box;
+
+	/* Menu items */
+	action = GTK_ACTION (gtk_builder_get_object (totem->xml, "deinterlace"));
+	gtk_action_set_visible (action, bacon_video_widget_can_deinterlace (totem->bvw));
+
+	action = gtk_action_group_get_action (totem->main_action_group, "repeat-mode");
+	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+		totem_playlist_get_repeat (totem->playlist));
+	action = gtk_action_group_get_action (totem->main_action_group, "shuffle-mode");
+	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
+		totem_playlist_get_shuffle (totem->playlist));
+
+	/* Controls */
+	box = GTK_BOX (gtk_builder_get_object (totem->xml, "tmw_buttons_hbox"));
+
+	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"));
+	gtk_box_pack_start (box, item, FALSE, FALSE, 0);
+
+	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"));
+	gtk_box_pack_start (box, item, FALSE, FALSE, 0);
+
+	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);
+
+	/* 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_action_connect_proxy (action, item);
+	arrow = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
+	g_object_set_data (G_OBJECT (box), "arrow", arrow);
+	gtk_button_set_image_position (GTK_BUTTON (item), GTK_POS_RIGHT);
+	gtk_button_set_image (GTK_BUTTON (item), arrow);
+	gtk_box_pack_start (box, item, FALSE, FALSE, 0);
+	g_signal_connect (G_OBJECT (item), "drag_data_received",
+			G_CALLBACK (drop_playlist_cb), totem);
+	g_signal_connect (G_OBJECT (item), "drag_motion",
+			G_CALLBACK (drag_motion_playlist_cb), totem);
+	gtk_drag_dest_set (item, GTK_DEST_DEFAULT_ALL,
+			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 (totem->win, GDK_SCROLL_MASK);
+	gtk_widget_add_events (totem->seek, GDK_SCROLL_MASK);
+	gtk_widget_add_events (totem->fs->seek, GDK_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);
+	totem_action_set_sensitivity ("next-chapter", FALSE);
+	totem_action_set_sensitivity ("previous-chapter", FALSE);
+	/* 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", FALSE);
+	totem_action_set_sensitivity ("skip-backwards", FALSE);*/
+
+	action_group = GTK_ACTION_GROUP (gtk_builder_get_object (totem->xml, "skip-action-group"));
+
+	action = gtk_action_group_get_action (action_group, "skip-forward");
+	gtk_action_set_sensitive (action, FALSE);
+
+	action = gtk_action_group_get_action (action_group, "skip-backwards");
+	gtk_action_set_sensitive (action, FALSE);
+}
+
+void
+playlist_widget_setup (Totem *totem)
+{
+	totem->playlist = TOTEM_PLAYLIST (totem_playlist_new ());
+
+	if (totem->playlist == NULL)
+		totem_action_exit (totem);
+
+	gtk_widget_show_all (GTK_WIDGET (totem->playlist));
+
+	g_signal_connect (G_OBJECT (totem->playlist), "active-name-changed",
+			  G_CALLBACK (on_playlist_change_name), totem);
+	g_signal_connect (G_OBJECT (totem->playlist), "item-activated",
+			  G_CALLBACK (item_activated_cb), totem);
+	g_signal_connect (G_OBJECT (totem->playlist),
+			  "changed", G_CALLBACK (playlist_changed_cb),
+			  totem);
+	g_signal_connect (G_OBJECT (totem->playlist),
+			  "current-removed", G_CALLBACK (current_removed_cb),
+			  totem);
+	g_signal_connect (G_OBJECT (totem->playlist),
+			  "repeat-toggled",
+			  G_CALLBACK (playlist_repeat_toggle_cb),
+			  totem);
+	g_signal_connect (G_OBJECT (totem->playlist),
+			  "shuffle-toggled",
+			  G_CALLBACK (playlist_shuffle_toggle_cb),
+			  totem);
+	g_signal_connect (G_OBJECT (totem->playlist),
+			  "subtitle-changed",
+			  G_CALLBACK (subtitle_changed_cb),
+			  totem);
+}
+
+void
+video_widget_create (Totem *totem)
+{
+	GError *err = NULL;
+	GtkContainer *container;
+	BaconVideoWidget **bvw;
+	const GtkTargetEntry source_table[] = {
+		{ "text/uri-list", 0, 0 }
+	};
+
+	totem->bvw = BACON_VIDEO_WIDGET
+		(bacon_video_widget_new (-1, -1, BVW_USE_TYPE_VIDEO, &err));
+
+	if (totem->bvw == NULL) {
+		totem_action_error_and_exit (_("Totem could not startup."), err != NULL ? err->message : _("No reason."), totem);
+		if (err != NULL)
+			g_error_free (err);
+	}
+
+	totem_action_zoom (totem, ZOOM_RESET);
+
+	g_signal_connect_after (G_OBJECT (totem->bvw),
+			"button-press-event",
+			G_CALLBACK (on_video_button_press_event),
+			totem);
+	g_signal_connect (G_OBJECT (totem->bvw),
+			"eos",
+			G_CALLBACK (on_eos_event),
+			totem);
+	g_signal_connect (G_OBJECT (totem->bvw),
+			"got-redirect",
+			G_CALLBACK (on_got_redirect),
+			totem);
+	g_signal_connect (G_OBJECT(totem->bvw),
+			"title-change",
+			G_CALLBACK (on_title_change_event),
+			totem);
+	g_signal_connect (G_OBJECT(totem->bvw),
+			"channels-change",
+			G_CALLBACK (on_channels_change_event),
+			totem);
+	g_signal_connect (G_OBJECT (totem->bvw),
+			"tick",
+			G_CALLBACK (update_current_time),
+			totem);
+	g_signal_connect (G_OBJECT (totem->bvw),
+			"got-metadata",
+			G_CALLBACK (on_got_metadata_event),
+			totem);
+	g_signal_connect (G_OBJECT (totem->bvw),
+			"buffering",
+			G_CALLBACK (on_buffering_event),
+			totem);
+	g_signal_connect (G_OBJECT (totem->bvw),
+			"error",
+			G_CALLBACK (on_error_event),
+			totem);
+
+	container = GTK_CONTAINER (gtk_builder_get_object (totem->xml, "tmw_bvw_box"));
+	gtk_container_add (container,
+			GTK_WIDGET (totem->bvw));
+
+	/* Events for the widget video window as well */
+	gtk_widget_add_events (GTK_WIDGET (totem->bvw),
+			GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
+	g_signal_connect (G_OBJECT(totem->bvw), "key_press_event",
+			G_CALLBACK (window_key_press_event_cb), totem);
+	g_signal_connect (G_OBJECT(totem->bvw), "key_release_event",
+			G_CALLBACK (window_key_press_event_cb), totem);
+
+	g_signal_connect (G_OBJECT (totem->bvw), "drag_data_received",
+			G_CALLBACK (drop_video_cb), totem);
+	g_signal_connect (G_OBJECT (totem->bvw), "drag_motion",
+			G_CALLBACK (drag_motion_video_cb), totem);
+	gtk_drag_dest_set (GTK_WIDGET (totem->bvw), GTK_DEST_DEFAULT_ALL,
+			target_table, G_N_ELEMENTS (target_table),
+			GDK_ACTION_COPY | GDK_ACTION_MOVE);
+
+	g_signal_connect (G_OBJECT (totem->bvw), "drag_data_get",
+			G_CALLBACK (drag_video_cb), totem);
+	gtk_drag_source_set (GTK_WIDGET (totem->bvw),
+			GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
+			source_table, G_N_ELEMENTS (source_table),
+			GDK_ACTION_LINK);
+
+	bvw = &(totem->bvw);
+	g_object_add_weak_pointer (G_OBJECT (totem->bvw),
+				   (gpointer *) bvw);
+
+	gtk_widget_realize (GTK_WIDGET (totem->bvw));
+	gtk_widget_show (GTK_WIDGET (totem->bvw));
+
+	totem_preferences_visuals_setup (totem);
+
+	bacon_video_widget_set_volume (totem->bvw,
+			((double) gconf_client_get_int (totem->gc,
+				GCONF_PREFIX"/volume", NULL)) / 100.0);
+	g_signal_connect (G_OBJECT (totem->bvw), "notify::volume",
+			G_CALLBACK (property_notify_cb_volume), totem);
+	g_signal_connect (G_OBJECT (totem->bvw), "notify::logo-mode",
+			G_CALLBACK (property_notify_cb_logo_mode), totem);
+	g_signal_connect (G_OBJECT (totem->bvw), "notify::seekable",
+			G_CALLBACK (property_notify_cb_seekable), totem);
+	update_volume_sliders (totem);
+}

Modified: trunk/src/totem-private.h
==============================================================================
--- trunk/src/totem-private.h	(original)
+++ trunk/src/totem-private.h	Sat Feb  7 15:28:03 2009
@@ -180,7 +180,14 @@
 void	totem_action_zoom_reset			(Totem *totem);
 void	totem_action_show_help			(Totem *totem);
 void	totem_action_show_properties		(Totem *totem);
+gboolean totem_action_open_files		(Totem *totem, char **list);
+G_GNUC_NORETURN void totem_action_error_and_exit (const char *title, const char *reason, Totem *totem);
 
 void	show_controls				(Totem *totem, gboolean was_fullscreen);
 
+char	*totem_setup_window			(Totem *totem);
+void	totem_callback_connect			(Totem *totem);
+void	playlist_widget_setup			(Totem *totem);
+void	video_widget_create			(Totem *totem);
+
 #endif /* __TOTEM_PRIVATE_H__ */

Modified: trunk/src/totem.c
==============================================================================
--- trunk/src/totem.c	(original)
+++ trunk/src/totem.c	Sat Feb  7 15:28:03 2009
@@ -28,89 +28,27 @@
 
 #include "config.h"
 
+#include <glib-object.h>
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
-#include <gdk/gdkkeysyms.h>
-#include <totem-disc.h>
-#include <stdlib.h>
-#include <math.h>
-#include <gio/gio.h>
-
 #include <string.h>
 
 #ifdef GDK_WINDOWING_X11
 /* X11 headers */
 #include <gdk/gdkx.h>
 #include <X11/Xlib.h>
-#ifdef HAVE_XFREE
-#include <X11/XF86keysym.h>
-#endif
 #endif
 
-#include "bacon-video-widget.h"
-#include "totem-dvb-setup.h"
-#include "totem-statusbar.h"
-#include "totem-time-label.h"
-#include "totem-session.h"
-#include "totem-sidebar.h"
-#include "totem-menu.h"
-#include "totem-options.h"
-#include "totem-uri.h"
-#include "totem-interface.h"
-#include "video-utils.h"
-#include "totem-dnd-menu.h"
-
 #include "totem.h"
 #include "totem-private.h"
+#include "totem-interface.h"
+#include "totem-options.h"
+#include "totem-menu.h"
+#include "totem-session.h"
+#include "totem-uri.h"
 #include "totem-preferences.h"
-
-#include "debug.h"
-
-#define REWIND_OR_PREVIOUS 4000
-
-#define SEEK_FORWARD_SHORT_OFFSET 15
-#define SEEK_BACKWARD_SHORT_OFFSET -5
-
-#define SEEK_FORWARD_LONG_OFFSET 10*60
-#define SEEK_BACKWARD_LONG_OFFSET -3*60
-
-#define ZOOM_UPPER 200
-#define ZOOM_RESET 100
-#define ZOOM_LOWER 10
-#define ZOOM_DISABLE (ZOOM_LOWER - 1)
-#define ZOOM_ENABLE (ZOOM_UPPER + 1)
-
-#define DEFAULT_WINDOW_W 650
-#define DEFAULT_WINDOW_H 500
-
-#define VOLUME_EPSILON (1e-10)
-
-#define BVW_VBOX_BORDER_WIDTH 1
-
-static const GtkTargetEntry target_table[] = {
-	{ "text/uri-list", 0, 0 },
-	{ "_NETSCAPE_URL", 0, 1 }
-};
-
-static gboolean totem_action_open_files (Totem *totem, char **list);
-static gboolean totem_action_open_files_list (Totem *totem, GSList *list);
-static gboolean totem_action_load_media (Totem *totem, TotemDiscMediaType type, const char *device);
-static void update_buttons (Totem *totem);
-static void update_media_menu_items (Totem *totem);
-static void playlist_changed_cb (GtkWidget *playlist, Totem *totem);
-static void play_pause_set_label (Totem *totem, TotemStates state);
-
-/* Callback functions for GtkBuilder */
-gboolean main_window_destroy_cb (GtkWidget *widget, GdkEvent *event, Totem *totem);
-gboolean window_state_event_cb (GtkWidget *window, GdkEventWindowState *event, Totem *totem);
-gboolean seek_slider_pressed_cb (GtkWidget *widget, GdkEventButton *event, Totem *totem);
-void seek_slider_changed_cb (GtkAdjustment *adj, Totem *totem);
-gboolean seek_slider_released_cb (GtkWidget *widget, GdkEventButton *event, Totem *totem);
-void volume_button_value_changed_cb (GtkScaleButton *button, gdouble value, Totem *totem);
-int window_key_press_event_cb (GtkWidget *win, GdkEventKey *event, Totem *totem);
-int window_scroll_event_cb (GtkWidget *win, GdkEventScroll *event, Totem *totem);
-void main_pane_size_allocated (GtkWidget *main_pane, GtkAllocation *allocation, Totem *totem);
-void fs_exit1_activate_cb (GtkButton *button, Totem *totem);
+#include "totem-sidebar.h"
+#include "video-utils.h"
 
 static void
 long_action (void)
@@ -120,3319 +58,6 @@
 }
 
 static void
-reset_seek_status (Totem *totem)
-{
-	/* Release the lock and reset everything so that we
-	 * 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_action_stop (totem);
-	}
-}
-
-/**
- * totem_action_error:
- * @title: the error dialog title
- * @reason: the error dialog text
- * @totem: a #TotemObject
- *
- * Displays a non-blocking error dialog with the
- * given @title and @reason.
- **/
-void
-totem_action_error (const char *title, const char *reason, Totem *totem)
-{
-	reset_seek_status (totem);
-	totem_interface_error (title, reason,
-			GTK_WINDOW (totem->win));
-}
-
-G_GNUC_NORETURN static void
-totem_action_error_and_exit (const char *title,
-		const char *reason, Totem *totem)
-{
-	reset_seek_status (totem);
-	totem_interface_error_blocking (title, reason,
-			GTK_WINDOW (totem->win));
-	totem_action_exit (totem);
-}
-
-static void
-totem_action_save_size (Totem *totem)
-{
-	GtkPaned *item;
-
-	if (totem->bvw == NULL)
-		return;
-
-	if (totem_is_fullscreen (totem) != FALSE)
-		return;
-
-	/* Save the size of the video widget */
-	item = GTK_PANED (gtk_builder_get_object (totem->xml, "tmw_main_pane"));
-	gtk_window_get_size (GTK_WINDOW (totem->win), &totem->window_w,
-			&totem->window_h);
-	totem->sidebar_w = totem->window_w
-		- gtk_paned_get_position (item);
-}
-
-static void
-totem_action_save_state (Totem *totem, const char *page_id)
-{
-	GKeyFile *keyfile;
-	char *contents, *filename;
-
-	if (totem->win == NULL)
-		return;
-	if (totem->window_w == 0
-	    || totem->window_h == 0)
-		return;
-
-	keyfile = g_key_file_new ();
-	g_key_file_set_integer (keyfile, "State",
-				"window_w", totem->window_w);
-	g_key_file_set_integer (keyfile, "State",
-			"window_h", totem->window_h);
-	g_key_file_set_boolean (keyfile, "State",
-			"show_sidebar", totem_sidebar_is_visible (totem));
-	g_key_file_set_boolean (keyfile, "State",
-			"maximised", totem->maximised);
-	g_key_file_set_integer (keyfile, "State",
-			"sidebar_w", totem->sidebar_w);
-
-	g_key_file_set_string (keyfile, "State",
-			"sidebar_page", page_id);
-
-	contents = g_key_file_to_data (keyfile, NULL, NULL);
-	g_key_file_free (keyfile);
-	filename = g_build_filename (totem_dot_dir (), "state.ini", NULL);
-	g_file_set_contents (filename, contents, -1, NULL);
-
-	g_free (filename);
-	g_free (contents);
-}
-
-G_GNUC_NORETURN static void
-totem_action_wait_force_exit (gpointer user_data)
-{
-	g_usleep (10 * G_USEC_PER_SEC);
-	exit (1);
-}
-
-/**
- * totem_action_exit:
- * @totem: a #TotemObject
- *
- * Closes Totem.
- **/
-void
-totem_action_exit (Totem *totem)
-{
-	GdkDisplay *display = NULL;
-	char *page_id;
-
-	/* Exit forcefully if we can't do the shutdown in 10 seconds */
-	g_thread_create ((GThreadFunc) totem_action_wait_force_exit,
-			 NULL, FALSE, NULL);
-
-	if (gtk_main_level () > 0)
-		gtk_main_quit ();
-
-	if (totem == NULL)
-		exit (0);
-
-	if (totem->win != NULL) {
-		gtk_widget_hide (totem->win);
-		display = gtk_widget_get_display (totem->win);
-	}
-
-	if (totem->prefs != NULL)
-		gtk_widget_hide (totem->prefs);
-
-	/* Save the page ID before we close the plugins, otherwise
-	 * we'll never save it properly */
-	page_id = totem_sidebar_get_current_page (totem);
-	totem_object_plugins_shutdown ();
-
-	if (display != NULL)
-		gdk_display_sync (display);
-
-	if (totem->bvw) {
-		int vol;
-
-		if (totem->muted != FALSE)
-			vol = totem->prev_volume * 100.0 + 0.5;
-		else
-			vol = bacon_video_widget_get_volume (totem->bvw) * 100.0 + 0.5;
-		/* FIXME move the volume to the static file? */
-		gconf_client_set_int (totem->gc,
-				GCONF_PREFIX"/volume",
-				CLAMP (vol, 0, 100),
-				NULL);
-		totem_action_save_size (totem);
-	}
-
-	if (totem->conn != NULL)
-		bacon_message_connection_free (totem->conn);
-	totem_action_save_state (totem, page_id);
-	g_free (page_id);
-
-	totem_sublang_exit (totem);
-	totem_destroy_file_filters ();
-
-	if (totem->gc)
-		g_object_unref (G_OBJECT (totem->gc));
-
-	if (totem->fs)
-		g_object_unref (totem->fs);
-
-	if (totem->win)
-		gtk_widget_destroy (GTK_WIDGET (totem->win));
-
-	g_object_unref (totem);
-
-	exit (0);
-}
-
-static void
-totem_action_menu_popup (Totem *totem, guint button)
-{
-	GtkWidget *menu;
-
-	menu = gtk_ui_manager_get_widget (totem->ui_manager,
-			"/totem-main-popup");
-	gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
-			button, gtk_get_current_event_time ());
-	gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
-}
-
-G_GNUC_NORETURN gboolean
-main_window_destroy_cb (GtkWidget *widget, GdkEvent *event, Totem *totem)
-{
-	totem_action_exit (totem);
-}
-
-static void
-play_pause_set_label (Totem *totem, TotemStates state)
-{
-	GtkAction *action;
-	const char *id, *tip;
-	GSList *l, *proxies;
-
-	if (state == totem->state)
-		return;
-
-	switch (state)
-	{
-	case STATE_PLAYING:
-		totem_statusbar_set_text (TOTEM_STATUSBAR (totem->statusbar),
-				_("Playing"));
-		id = GTK_STOCK_MEDIA_PAUSE;
-		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 = GTK_STOCK_MEDIA_PLAY;
-		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);
-		id = GTK_STOCK_MEDIA_PLAY;
-		totem_playlist_set_playing (totem->playlist, TOTEM_PLAYLIST_STATUS_NONE);
-		tip = N_("Play");
-		break;
-	default:
-		g_assert_not_reached ();
-		return;
-	}
-
-	action = gtk_action_group_get_action (totem->main_action_group, "play");
-	g_object_set (G_OBJECT (action),
-			"tooltip", _(tip),
-			"stock-id", id, NULL);
-
-	proxies = gtk_action_get_proxies (action);
-	for (l = proxies; l != NULL; l = l->next) {
-		atk_object_set_name (gtk_widget_get_accessible (l->data),
-				_(tip));
-	}
-
-	totem->state = state;
-
-	g_object_notify (G_OBJECT (totem), "playing");
-}
-
-void
-totem_action_eject (Totem *totem)
-{
-	GMount *mount;
-
-	mount = totem_get_mount_for_media (totem->mrl);
-	if (mount == NULL)
-		return;
-
-	g_free (totem->mrl);
-	totem->mrl = NULL;
-	bacon_video_widget_close (totem->bvw);
-	totem_file_closed (totem);
-
-	/* The volume monitoring will take care of removing the items */
-	g_mount_eject (mount, G_MOUNT_UNMOUNT_NONE, NULL, NULL, NULL);
-	g_object_unref (mount);
-}
-
-void
-totem_action_show_properties (Totem *totem)
-{
-	if (totem_is_fullscreen (totem) == FALSE)
-		totem_sidebar_set_current_page (totem, "properties", TRUE);
-}
-
-/**
- * totem_action_play:
- * @totem: a #TotemObject
- *
- * Plays the current stream. If Totem is already playing, it continues
- * to play. If the stream cannot be played, and error dialog is displayed.
- **/
-void
-totem_action_play (Totem *totem)
-{
-	GError *err = NULL;
-	int retval;
-	char *msg, *disp;
-
-	if (totem->mrl == NULL)
-		return;
-
-	if (bacon_video_widget_is_playing (totem->bvw) != FALSE)
-		return;
-
-	retval = bacon_video_widget_play (totem->bvw,  &err);
-	play_pause_set_label (totem, retval ? STATE_PLAYING : STATE_STOPPED);
-
-	if (retval != FALSE)
-		return;
-
-	disp = totem_uri_escape_for_display (totem->mrl);
-	msg = g_strdup_printf(_("Totem could not play '%s'."), disp);
-	g_free (disp);
-
-	totem_action_error (msg, err->message, totem);
-	totem_action_stop (totem);
-	g_free (msg);
-	g_error_free (err);
-}
-
-static void
-totem_action_seek (Totem *totem, double pos)
-{
-	GError *err = NULL;
-	int retval;
-
-	if (totem->mrl == NULL)
-		return;
-	if (bacon_video_widget_is_seekable (totem->bvw) == FALSE)
-		return;
-
-	retval = bacon_video_widget_seek (totem->bvw, pos, &err);
-
-	if (retval == FALSE)
-	{
-		char *msg, *disp;
-
-		disp = totem_uri_escape_for_display (totem->mrl);
-		msg = g_strdup_printf(_("Totem could not play '%s'."), disp);
-		g_free (disp);
-
-		reset_seek_status (totem);
-
-		totem_action_error (msg, err->message, totem);
-		g_free (msg);
-		g_error_free (err);
-	}
-}
-
-/**
- * totem_action_set_mrl_and_play:
- * @totem: a #TotemObject
- * @mrl: the MRL to play
- * @subtitle: a subtitle file to load, or %NULL
- *
- * Loads the specified @mrl and plays it, if possible.
- * Calls totem_action_set_mrl() then totem_action_play().
- * For more information, see the documentation for totem_action_set_mrl_with_warning().
- **/
-void
-totem_action_set_mrl_and_play (Totem *totem, const char *mrl, const char *subtitle)
-{
-	if (totem_action_set_mrl (totem, mrl, subtitle) != FALSE)
-		totem_action_play (totem);
-}
-
-static gboolean
-totem_action_open_dialog (Totem *totem, const char *path, gboolean play)
-{
-	GSList *filenames;
-	gboolean playlist_modified;
-
-	filenames = totem_add_files (GTK_WINDOW (totem->win), path);
-
-	if (filenames == NULL)
-		return FALSE;
-
-	playlist_modified = totem_action_open_files_list (totem,
-			filenames);
-
-	if (playlist_modified == FALSE) {
-		g_slist_foreach (filenames, (GFunc) g_free, NULL);
-		g_slist_free (filenames);
-		return FALSE;
-	}
-
-	g_slist_foreach (filenames, (GFunc) g_free, NULL);
-	g_slist_free (filenames);
-
-	if (play != FALSE) {
-		char *mrl, *subtitle;
-
-		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
-		totem_action_set_mrl_and_play (totem, mrl, subtitle);
-		g_free (mrl);
-		g_free (subtitle);
-	}
-
-	return TRUE;
-}
-
-static void
-totem_dvb_setup_result (int result, const char *device, gpointer user_data)
-{
-	Totem *totem = (Totem *) user_data;
-
-	totem_action_play_media (totem, MEDIA_TYPE_DVB, device);
-}
-
-static gboolean
-totem_action_load_media (Totem *totem, TotemDiscMediaType type, const char *device)
-{
-	char **mrls, *msg;
-	GError *error = NULL;
-	const char *link, *link_text, *secondary;
-	gboolean retval;
-
-	mrls = bacon_video_widget_get_mrls (totem->bvw, type, device, &error);
-	if (mrls == NULL) {
-		/* No errors? Weird */
-		if (error == NULL) {
-			msg = g_strdup_printf (_("Totem could not play this media (%s) although a plugin is present to handle it."), _(totem_cd_get_human_readable_name (type)));
-			totem_action_error (msg, _("You might want to check that a disc is present in the drive and that it is correctly configured."), totem);
-			g_free (msg);
-			return FALSE;
-		}
-		/* No plugin for the media type */
-		if (g_error_matches (error, BVW_ERROR, BVW_ERROR_NO_PLUGIN_FOR_FILE) != FALSE) {
-			link = "http://www.gnome.org/projects/totem/#codecs";;
-			link_text = _("More information about media plugins");
-			secondary = _("Please install the necessary plugins and restart Totem to be able to play this media.");
-			if (type == MEDIA_TYPE_DVD || type == MEDIA_TYPE_VCD)
-				msg = g_strdup_printf (_("Totem cannot play this type of media (%s) because it does not have the appropriate plugins to be able to read from the disc."), _(totem_cd_get_human_readable_name (type)));
-			else
-				msg = g_strdup_printf (_("Totem cannot play this type of media (%s) because you do not have the appropriate plugins to handle it."), _(totem_cd_get_human_readable_name (type)));
-		/* Device doesn't exist */
-		} else if (g_error_matches (error, BVW_ERROR, BVW_ERROR_INVALID_DEVICE) != FALSE) {
-			g_assert (type == MEDIA_TYPE_DVB);
-			msg = N_("Totem cannot play TV, because no TV adapters are present or they are not supported.");
-			totem_action_error (_(msg), _("Please insert a supported TV adapter."), totem);
-			return FALSE;
-		/* No channels.conf file */
-		} else if (g_error_matches (error, BVW_ERROR, BVW_ERROR_FILE_NOT_FOUND) != FALSE) {
-			g_assert (type == MEDIA_TYPE_DVB);
-
-			if (totem_dvb_setup_device (device, GTK_WINDOW (totem->win), totem_dvb_setup_result, totem) == TOTEM_DVB_SETUP_STARTED_OK)
-				return FALSE;
-
-			link = "http://www.gnome.org/projects/totem/#dvb";;
-			link_text = _("More information about watching TV");
-			msg = g_strdup (_("Totem is missing a channels listing to be able to tune the receiver."));
-			secondary = _("Please follow the instructions provided in the link to create a channels listing.");
-		} else if (g_error_matches (error, BVW_ERROR, BVW_ERROR_DEVICE_BUSY) != FALSE) {
-			g_assert (type == MEDIA_TYPE_DVB);
-			msg = g_strdup_printf(_("Totem cannot play this type of media (%s) because the TV device is busy."), _(totem_cd_get_human_readable_name (type)));
-			totem_action_error (msg, _("Please try again later."), totem);
-			g_free (msg);
-			return FALSE;
-		/* Unsupported type (ie. CDDA) */
-		} else if (g_error_matches (error, BVW_ERROR, BVW_ERROR_UNVALID_LOCATION) != FALSE) {
-			msg = g_strdup_printf(_("Totem cannot play this type of media (%s) because it is not supported."), _(totem_cd_get_human_readable_name (type)));
-			totem_action_error (msg, _("Please insert another disc to play back."), totem);
-			g_free (msg);
-			return FALSE;
-		} else {
-			g_assert_not_reached ();
-		}
-		totem_interface_error_with_link (msg, secondary, link, link_text, GTK_WINDOW (totem->win), totem);
-		g_free (msg);
-		return FALSE;
-	}
-
-	retval = totem_action_open_files (totem, mrls);
-	g_strfreev (mrls);
-
-	return retval;
-}
-
-static gboolean
-totem_action_load_media_device (Totem *totem, const char *device)
-{
-	TotemDiscMediaType type;
-	GError *error = NULL;
-	char *device_path, *url;
-	gboolean retval;
-
-	if (g_str_has_prefix (device, "file://") != FALSE)
-		device_path = g_filename_from_uri (device, NULL, NULL);
-	else
-		device_path = g_strdup (device);
-
-	type = totem_cd_detect_type_with_url (device_path, &url, &error);
-
-	switch (type) {
-		case MEDIA_TYPE_ERROR:
-			totem_action_error (_("Totem was not able to play this disc."),
-					    error ? error->message : _("No reason."),
-					    totem);
-			retval = FALSE;
-			break;
-		case MEDIA_TYPE_DATA:
-			/* Set default location to the mountpoint of
-			 * this device */
-			retval = totem_action_open_dialog (totem, url, FALSE);
-			break;
-		case MEDIA_TYPE_DVD:
-		case MEDIA_TYPE_VCD:
-			retval = totem_action_load_media (totem, type, device_path);
-			break;
-		case MEDIA_TYPE_CDDA:
-			totem_action_error (_("Totem does not support playback of Audio CDs"),
-					    _("Please consider using a music player or a CD extractor to play this CD"),
-					    totem);
-			retval = FALSE;
-			break;
-		default:
-			g_assert_not_reached ();
-	}
-
-	g_free (url);
-	g_free (device_path);
-
-	return retval;
-}
-
-/**
- * totem_action_play_media_device:
- * @totem: a #TotemObject
- * @device: the media device's path
- *
- * Attempts to play the media device (for example, a DVD drive or CD drive)
- * with the given @device path by first adding it to the playlist, then
- * playing it.
- *
- * An error dialog will be displayed if Totem cannot read or play what's on
- * the media device.
- **/
-void
-totem_action_play_media_device (Totem *totem, const char *device)
-{
-	char *mrl;
-
-	if (totem_action_load_media_device (totem, device) != FALSE) {
-		mrl = totem_playlist_get_current_mrl (totem->playlist, NULL);
-		totem_action_set_mrl_and_play (totem, mrl, NULL);
-		g_free (mrl);
-	}
-}
-
-/**
- * totem_action_play_media:
- * @totem: a #TotemObject
- * @type: the type of disc media
- * @device: the media's device path
- *
- * Attempts to play the media found on @device (for example, a DVD in a drive or a DVB
- * tuner) by first adding it to the playlist, then playing it.
- *
- * An error dialog will be displayed if Totem cannot support media of @type.
- **/
-void
-totem_action_play_media (Totem *totem, TotemDiscMediaType type, const char *device)
-{
-	char *mrl;
-
-	if (totem_action_load_media (totem, type, device) != FALSE) {
-		mrl = totem_playlist_get_current_mrl (totem->playlist, NULL);
-		totem_action_set_mrl_and_play (totem, mrl, NULL);
-		g_free (mrl);
-	}
-}
-
-/**
- * totem_action_stop:
- * @totem: a #TotemObject
- *
- * Stops the current stream.
- **/
-void
-totem_action_stop (Totem *totem)
-{
-	bacon_video_widget_stop (totem->bvw);
-	play_pause_set_label (totem, STATE_STOPPED);
-}
-
-/**
- * totem_action_play_pause:
- * @totem: a #TotemObject
- *
- * Gets the current MRL from the playlist and attempts to play it.
- * If the stream is already playing, playback is paused.
- **/
-void
-totem_action_play_pause (Totem *totem)
-{
-	if (totem->mrl == NULL)
-	{
-		char *mrl, *subtitle;
-
-		/* Try to pull an mrl from the playlist */
-		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
-		if (mrl == NULL) {
-			play_pause_set_label (totem, STATE_STOPPED);
-			return;
-		} else {
-			totem_action_set_mrl_and_play (totem, mrl, subtitle);
-			g_free (mrl);
-			g_free (subtitle);
-			return;
-		}
-	}
-
-	if (bacon_video_widget_is_playing (totem->bvw) == FALSE)
-	{
-		bacon_video_widget_play (totem->bvw, NULL);
-		play_pause_set_label (totem, STATE_PLAYING);
-	} else {
-		bacon_video_widget_pause (totem->bvw);
-		play_pause_set_label (totem, STATE_PAUSED);
-	}
-}
-
-/**
- * totem_action_pause:
- * @totem: a #TotemObject
- *
- * Pauses the current stream. If Totem is already paused, it continues
- * to be paused.
- **/
-void
-totem_action_pause (Totem *totem)
-{
-	if (bacon_video_widget_is_playing (totem->bvw) != FALSE) {
-		bacon_video_widget_pause (totem->bvw);
-		play_pause_set_label (totem, STATE_PAUSED);
-	}
-}
-
-gboolean
-window_state_event_cb (GtkWidget *window, GdkEventWindowState *event,
-		       Totem *totem)
-{
-	if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) {
-		totem->maximised = (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0;
-                gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (totem->statusbar),
-                                                   !totem->maximised);
-		totem_action_set_sensitivity ("zoom-1-2", !totem->maximised);
-		totem_action_set_sensitivity ("zoom-1-1", !totem->maximised);
-		totem_action_set_sensitivity ("zoom-2-1", !totem->maximised);
-		return FALSE;
-	}
-
-	if ((event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) == 0)
-		return FALSE;
-
-	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);
-		totem_action_set_sensitivity ("fullscreen", FALSE);
-	} else {
-		GtkAction *action;
-
-		totem_fullscreen_set_fullscreen (totem->fs, FALSE);
-
-		action = gtk_action_group_get_action (totem->main_action_group,
-				"show-controls");
-
-		if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
-			totem->controls_visibility = TOTEM_CONTROLS_VISIBLE;
-		} else {
-			totem->controls_visibility = TOTEM_CONTROLS_HIDDEN;
-		}
-
-		show_controls (totem, TRUE);
-		totem_action_set_sensitivity ("fullscreen", TRUE);
-	}
-
-	g_object_notify (G_OBJECT (totem), "fullscreen");
-
-	return FALSE;
-}
-
-/**
- * totem_action_fullscreen_toggle:
- * @totem: a #TotemObject
- *
- * Toggles Totem's fullscreen state; if Totem is fullscreened, calling
- * this makes it unfullscreened and vice-versa.
- **/
-void
-totem_action_fullscreen_toggle (Totem *totem)
-{
-	if (totem_is_fullscreen (totem) != FALSE)
-		gtk_window_unfullscreen (GTK_WINDOW (totem->win));
-	else
-		gtk_window_fullscreen (GTK_WINDOW (totem->win));
-}
-
-/**
- * totem_action_fullscreen:
- * @totem: a #TotemObject
- * @state: %TRUE if Totem should be fullscreened
- *
- * Sets Totem's fullscreen state according to @state.
- **/
-void
-totem_action_fullscreen (Totem *totem, gboolean state)
-{
-	if (totem_is_fullscreen (totem) == state)
-		return;
-
-	totem_action_fullscreen_toggle (totem);
-}
-
-void
-fs_exit1_activate_cb (GtkButton *button, Totem *totem)
-{
-	totem_action_fullscreen (totem, FALSE);
-}
-
-void
-totem_action_open (Totem *totem)
-{
-	totem_action_open_dialog (totem, NULL, TRUE);
-}
-
-static void
-totem_open_location_destroy (Totem *totem)
-{
-	if (totem->open_location != NULL) {
-		g_object_remove_weak_pointer (G_OBJECT (totem->open_location), (gpointer *)&(totem->open_location));
-		gtk_widget_destroy (GTK_WIDGET (totem->open_location));
-		totem->open_location = NULL;
-	}
-}
-
-static void
-totem_open_location_response_cb (GtkDialog *dialog, gint response, Totem *totem)
-{
-	char *uri;
-
-	if (response != GTK_RESPONSE_OK) {
-		totem_open_location_destroy (totem);
-		return;
-	}
-
-	gtk_widget_hide (GTK_WIDGET (dialog));
-
-	/* Open the specified URI */
-	uri = totem_open_location_get_uri (totem->open_location);
-
-	if (uri != NULL)
-	{
-		char *mrl, *subtitle;
-		const char *filenames[2];
-
-		filenames[0] = uri;
-		filenames[1] = NULL;
-		totem_action_open_files (totem, (char **) filenames);
-
-		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
-		totem_action_set_mrl_and_play (totem, mrl, subtitle);
-		g_free (mrl);
-		g_free (subtitle);
-	}
- 	g_free (uri);
-
-	totem_open_location_destroy (totem);
-}
-
-void
-totem_action_open_location (Totem *totem)
-{
-	if (totem->open_location != NULL) {
-		gtk_window_present (GTK_WINDOW (totem->open_location));
-		return;
-	}
-
-	totem->open_location = TOTEM_OPEN_LOCATION (totem_open_location_new (totem));
-
-	g_signal_connect (G_OBJECT (totem->open_location), "delete-event",
-			G_CALLBACK (gtk_widget_destroy), NULL);
-	g_signal_connect (G_OBJECT (totem->open_location), "response",
-			G_CALLBACK (totem_open_location_response_cb), totem);
-	g_object_add_weak_pointer (G_OBJECT (totem->open_location), (gpointer *)&(totem->open_location));
-
-	gtk_window_set_transient_for (GTK_WINDOW (totem->open_location),
-			GTK_WINDOW (totem->win));
-	gtk_widget_show (GTK_WIDGET (totem->open_location));
-}
-
-static char *
-totem_get_nice_name_for_stream (Totem *totem)
-{
-	GValue title_value = { 0, };
-	GValue album_value = { 0, };
-	GValue artist_value = { 0, };
-	GValue value = { 0, };
-	char *retval;
-	int tracknum;
-
-	bacon_video_widget_get_metadata (totem->bvw, BVW_INFO_TITLE, &title_value);
-	bacon_video_widget_get_metadata (totem->bvw, BVW_INFO_ARTIST, &artist_value);
-	bacon_video_widget_get_metadata (totem->bvw, BVW_INFO_ALBUM, &album_value);
-	bacon_video_widget_get_metadata (totem->bvw,
-					 BVW_INFO_TRACK_NUMBER,
-					 &value);
-
-	tracknum = g_value_get_int (&value);
-	g_value_unset (&value);
-
-	totem_metadata_updated (totem,
-				g_value_get_string (&artist_value),
-				g_value_get_string (&title_value),
-				g_value_get_string (&album_value),
-				tracknum);
-
-	if (g_value_get_string (&title_value) == NULL) {
-		retval = NULL;
-		goto bail;
-	}
-	if (g_value_get_string (&artist_value) == NULL) {
-		retval = g_value_dup_string (&title_value);
-		goto bail;
-	}
-
-	if (tracknum != 0) {
-		retval = g_strdup_printf ("%02d. %s - %s",
-					  tracknum,
-					  g_value_get_string (&artist_value),
-					  g_value_get_string (&title_value));
-	} else {
-		retval = g_strdup_printf ("%s - %s",
-					  g_value_get_string (&artist_value),
-					  g_value_get_string (&title_value));
-	}
-
-bail:
-	g_value_unset (&album_value);
-	g_value_unset (&artist_value);
-	g_value_unset (&title_value);
-
-	return retval;
-}
-
-static void
-update_mrl_label (Totem *totem, const char *name)
-{
-	if (name != NULL)
-	{
-		/* Update the mrl label */
-		totem_fullscreen_set_title (totem->fs, name);
-
-		/* Title */
-		gtk_window_set_title (GTK_WINDOW (totem->win), name);
-	} else {
-		totem_statusbar_set_time_and_length (TOTEM_STATUSBAR
-				(totem->statusbar), 0, 0);
-		totem_statusbar_set_text (TOTEM_STATUSBAR (totem->statusbar),
-				_("Stopped"));
-
-		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), _("Movie Player"));
-	}
-}
-
-/**
- * totem_action_set_mrl_with_warning:
- * @totem: a #TotemObject
- * @mrl: the MRL to play
- * @subtitle: a subtitle file to load, or %NULL
- * @warn: %TRUE if error dialogs should be displayed
- *
- * Loads the specified @mrl and optionally the specified subtitle
- * file. If @subtitle is %NULL Totem will attempt to auto-locate
- * any subtitle files for @mrl.
- *
- * If a stream is already playing, it will be stopped and closed.
- *
- * If any errors are encountered, error dialogs will only be displayed
- * if @warn is %TRUE.
- *
- * Return value: %TRUE on success
- **/
-gboolean
-totem_action_set_mrl_with_warning (Totem *totem,
-				   const char *mrl, 
-				   const char *subtitle,
-				   gboolean warn)
-{
-	gboolean retval = TRUE;
-
-	if (totem->mrl != NULL)
-	{
-		g_free (totem->mrl);
-		totem->mrl = NULL;
-		bacon_video_widget_close (totem->bvw);
-		totem_file_closed (totem);
-		play_pause_set_label (totem, STATE_STOPPED);
-	}
-
-	if (mrl == NULL)
-	{
-		retval = FALSE;
-
-		play_pause_set_label (totem, STATE_STOPPED);
-
-		/* Play/Pause */
-		totem_action_set_sensitivity ("play", FALSE);
-
-		/* Volume */
-		totem_main_set_sensitivity ("tmw_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);
-
-		/* Clear the playlist */
-		totem_action_set_sensitivity ("clear-playlist", FALSE);
-
-		/* Subtitle selection */
-		totem_action_set_sensitivity ("select-subtitle", FALSE);
-
-		/* Set the logo */
-		bacon_video_widget_set_logo_mode (totem->bvw, TRUE);
-		update_mrl_label (totem, NULL);
-	} else {
-		gboolean caps;
-		gdouble volume;
-		char *autoload_sub = NULL;
-		GError *err = NULL;
-
-		bacon_video_widget_set_logo_mode (totem->bvw, FALSE);
-
-		if (subtitle == NULL && totem->autoload_subs != FALSE)
-			autoload_sub = totem_uri_get_subtitle_uri (mrl);
-
-		totem_gdk_window_set_waiting_cursor (totem->win->window);
-		retval = bacon_video_widget_open_with_subtitle (totem->bvw, mrl,
-								subtitle ? subtitle : autoload_sub, &err);
-		g_free (autoload_sub);
-		gdk_window_set_cursor (totem->win->window, NULL);
-		totem->mrl = g_strdup (mrl);
-
-		/* Play/Pause */
-		totem_action_set_sensitivity ("play", TRUE);
-
-		/* 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);
-		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);
-		totem->volume_sensitive = caps;
-
-		/* Clear the playlist */
-		totem_action_set_sensitivity ("clear-playlist", retval);
-
-		/* Subtitle selection */
-		totem_action_set_sensitivity ("select-subtitle", !totem_is_special_mrl (mrl) && retval);
-	
-		/* Set the playlist */
-		play_pause_set_label (totem, retval ? STATE_PAUSED : STATE_STOPPED);
-
-		if (retval == FALSE && warn != FALSE)
-		{
-			char *msg, *disp;
-
-			disp = totem_uri_escape_for_display (totem->mrl);
-			msg = g_strdup_printf(_("Totem could not play '%s'."), disp);
-			g_free (disp);
-			if (err && err->message) {
-				totem_action_error (msg, err->message, totem);
-			}
-			else {
-				totem_action_error (msg, _("No error message"), totem);
-			}
-			g_free (msg);
-		}
-
-		if (retval == FALSE)
-		{
-			if (err)
-				g_error_free (err);
-			g_free (totem->mrl);
-			totem->mrl = NULL;
-			bacon_video_widget_set_logo_mode (totem->bvw, TRUE);
-		} else {
-			totem_file_opened (totem, totem->mrl);
-		}
-	}
-	update_buttons (totem);
-	update_media_menu_items (totem);
-
-	return retval;
-}
-
-/**
- * totem_action_set_mrl:
- * @totem: a #TotemObject
- * @mrl: the MRL to load
- * @subtitle: a subtitle file to load, or %NULL
- *
- * Calls totem_action_set_mrl_with_warning() with warnings enabled.
- * For more information, see the documentation for totem_action_set_mrl_with_warning().
- *
- * Return value: %TRUE on success
- **/
-gboolean
-totem_action_set_mrl (Totem *totem, const char *mrl, const char *subtitle)
-{
-	return totem_action_set_mrl_with_warning (totem, mrl, subtitle, TRUE);
-}
-
-static gboolean
-totem_time_within_seconds (Totem *totem)
-{
-	gint64 time;
-
-	time = bacon_video_widget_get_current_time (totem->bvw);
-
-	return (time < REWIND_OR_PREVIOUS);
-}
-
-static void
-totem_action_direction (Totem *totem, TotemPlaylistDirection dir)
-{
-	if (totem_playing_dvd (totem->mrl) == FALSE &&
-		totem_playlist_has_direction (totem->playlist, dir) == FALSE
-		&& totem_playlist_get_repeat (totem->playlist) == FALSE)
-		return;
-
-	if (totem_playing_dvd (totem->mrl) != FALSE)
-	{
-		bacon_video_widget_dvd_event (totem->bvw,
-				dir == TOTEM_PLAYLIST_DIRECTION_NEXT ?
-				BVW_DVD_NEXT_CHAPTER :
-				BVW_DVD_PREV_CHAPTER);
-		return;
-	}
-	
-	if (dir == TOTEM_PLAYLIST_DIRECTION_NEXT
-			|| bacon_video_widget_is_seekable (totem->bvw) == FALSE
-			|| totem_time_within_seconds (totem) != FALSE)
-	{
-		char *mrl, *subtitle;
-
-		totem_playlist_set_direction (totem->playlist, dir);
-		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
-		totem_action_set_mrl_and_play (totem, mrl, subtitle);
-
-		g_free (subtitle);
-		g_free (mrl);
-	} else {
-		totem_action_seek (totem, 0);
-	}
-}
-
-/**
- * totem_action_previous:
- * @totem: a #TotemObject
- *
- * If a DVD is being played, goes to the previous chapter. If a normal stream
- * is being played, goes to the start of the stream if possible. If seeking is
- * not possible, plays the previous entry in the playlist.
- **/
-void
-totem_action_previous (Totem *totem)
-{
-	totem_action_direction (totem, TOTEM_PLAYLIST_DIRECTION_PREVIOUS);
-}
-
-/**
- * totem_action_next:
- * @totem: a #TotemObject
- *
- * If a DVD is being played, goes to the next chapter. If a normal stream
- * is being played, plays the next entry in the playlist.
- **/
-void
-totem_action_next (Totem *totem)
-{
-	totem_action_direction (totem, TOTEM_PLAYLIST_DIRECTION_NEXT);
-}
-
-static void
-totem_seek_time_rel (Totem *totem, gint64 time, gboolean relative)
-{
-	GError *err = NULL;
-	gint64 sec;
-
-	if (totem->mrl == NULL)
-		return;
-	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);
-		sec = MAX (0, oldmsec + time);
-	} else {
-		sec = time;
-	}
-
-	bacon_video_widget_seek_time (totem->bvw, sec, &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;
-
-		disp = totem_uri_escape_for_display (totem->mrl);
-		msg = g_strdup_printf(_("Totem could not play '%s'."), disp);
-		g_free (disp);
-
-		totem_action_stop (totem);
-		totem_action_error (msg, err->message, totem);
-		g_free (msg);
-		g_error_free (err);
-	}
-}
-
-/**
- * totem_action_seek_relative:
- * @totem: a #TotemObject
- * @offset: the time offset to seek to
- *
- * Seeks to an @offset from the current position in the stream,
- * or displays an error dialog if that's not possible.
- **/
-void
-totem_action_seek_relative (Totem *totem, gint64 offset)
-{
-	totem_seek_time_rel (totem, offset, TRUE);
-}
-
-/**
- * totem_action_seek_time:
- * @totem: a #TotemObject
- * @sec: the time to seek to
- *
- * Seeks to an absolute time in the stream, or displays an
- * error dialog if that's not possible.
- **/
-void
-totem_action_seek_time (Totem *totem, gint64 sec)
-{
-	totem_seek_time_rel (totem, sec, FALSE);
-}
-
-static void
-totem_action_zoom (Totem *totem, int zoom)
-{
-	GtkAction *action;
-	gboolean zoom_reset, zoom_in, zoom_out;
-
-	if (zoom == ZOOM_ENABLE)
-		zoom = bacon_video_widget_get_zoom (totem->bvw);
-
-	if (zoom == ZOOM_DISABLE) {
-		zoom_reset = zoom_in = zoom_out = FALSE;
-	} else if (zoom < ZOOM_LOWER || zoom > ZOOM_UPPER) {
-		return;
-	} else {
-		bacon_video_widget_set_zoom (totem->bvw, zoom);
-		zoom_reset = (zoom != ZOOM_RESET);
-		zoom_out = zoom != ZOOM_LOWER;
-		zoom_in = zoom != ZOOM_UPPER;
-	}
-
-	action = gtk_action_group_get_action (totem->zoom_action_group,
-			"zoom-in");
-	gtk_action_set_sensitive (action, zoom_in);
-
-	action = gtk_action_group_get_action (totem->zoom_action_group,
-			"zoom-out");
-	gtk_action_set_sensitive (action, zoom_out);
-
-	action = gtk_action_group_get_action (totem->zoom_action_group,
-			"zoom-reset");
-	gtk_action_set_sensitive (action, zoom_reset);
-}
-
-void
-totem_action_zoom_relative (Totem *totem, int off_pct)
-{
-	int zoom;
-
-	zoom = bacon_video_widget_get_zoom (totem->bvw);
-	totem_action_zoom (totem, zoom + off_pct);
-}
-
-void
-totem_action_zoom_reset (Totem *totem)
-{
-	totem_action_zoom (totem, ZOOM_RESET);
-}
-
-/**
- * totem_action_volume_relative:
- * @totem: a #TotemObject
- * @off_pct: the value by which to increase or decrease the volume
- *
- * Sets the volume relative to its current level, with 1.0 being the
- * maximum, and 0.0 being the minimum level.
- **/
-void
-totem_action_volume_relative (Totem *totem, double off_pct)
-{
-	double vol;
-
-	if (bacon_video_widget_can_set_volume (totem->bvw) == FALSE)
-		return;
-	if (totem->muted != FALSE)
-		totem_action_volume_toggle_mute (totem);
-
-	vol = bacon_video_widget_get_volume (totem->bvw);
-	bacon_video_widget_set_volume (totem->bvw, vol + off_pct);
-}
-
-/**
- * totem_action_volume_toggle_mute:
- * @totem: a #TotemObject
- *
- * Toggles the mute status.
- **/
-void
-totem_action_volume_toggle_mute (Totem *totem)
-{
-	if (totem->muted == FALSE) {
-		totem->muted = TRUE;
-		totem->prev_volume = bacon_video_widget_get_volume (totem->bvw);
-		bacon_video_widget_set_volume (totem->bvw, 0.0);
-	} else {
-		totem->muted = FALSE;
-		bacon_video_widget_set_volume (totem->bvw, totem->prev_volume);
-	}
-}
-
-/**
- * totem_action_toggle_aspect_ratio:
- * @totem: a #TotemObject
- *
- * Toggles the aspect ratio selected in the menu to the
- * next one in the list.
- **/
-void
-totem_action_toggle_aspect_ratio (Totem *totem)
-{
-	GtkAction *action;
-	int tmp;
-
-	tmp = totem_action_get_aspect_ratio (totem);
-	tmp++;
-	if (tmp > BVW_RATIO_DVB)
-		tmp = BVW_RATIO_AUTO;
-
-	action = gtk_action_group_get_action (totem->main_action_group, "aspect-ratio-auto");
-	gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), tmp);
-}
-
-/**
- * totem_action_set_aspect_ratio:
- * @totem: a #TotemObject
- * @ratio: the aspect ratio to use
- *
- * Sets the aspect ratio selected in the menu to @ratio,
- * as defined in #BaconVideoWidgetAspectRatio.
- **/
-void
-totem_action_set_aspect_ratio (Totem *totem, int ratio)
-{
-	bacon_video_widget_set_aspect_ratio (totem->bvw, ratio);
-}
-
-/**
- * totem_action_get_aspect_ratio:
- * @totem: a #TotemObject
- *
- * Gets the current aspect ratio as defined in #BaconVideoWidgetAspectRatio.
- *
- * Return value: the current aspect ratio
- **/
-int
-totem_action_get_aspect_ratio (Totem *totem)
-{
-	return (bacon_video_widget_get_aspect_ratio (totem->bvw));
-}
-
-/**
- * totem_action_set_scale_ratio:
- * @totem: a #TotemObject
- * @ratio: the scale ratio to use
- *
- * Sets the video scale ratio, as a float where, for example,
- * 1.0 is 1:1 and 2.0 is 2:1.
- **/
-void
-totem_action_set_scale_ratio (Totem *totem, gfloat ratio)
-{
-	bacon_video_widget_set_scale_ratio (totem->bvw, ratio);
-}
-
-void
-totem_action_show_help (Totem *totem)
-{
-	GError *error = NULL;
-
-	if (gtk_show_uri (gtk_widget_get_screen (totem->win), "ghelp:totem", gtk_get_current_event_time (), &error) == FALSE) {
-		totem_action_error (_("Totem could not display the help contents."), error->message, totem);
-		g_error_free (error);
-	}
-}
-
-static gboolean
-totem_action_drop_files (Totem *totem, GtkSelectionData *data,
-		int drop_type, gboolean empty_pl)
-{
-	char **list;
-	guint i, len;
-	GList *p, *file_list;
-	gboolean cleared = FALSE;
-
-	list = g_uri_list_extract_uris ((const char *)data->data);
-	file_list = NULL;
-
-	for (i = 0; list[i] != NULL; i++) {
-		char *filename;
-
-		if (list[i] == NULL)
-			continue;
-
-		filename = totem_create_full_path (list[i]);
-		file_list = g_list_prepend (file_list,
-					    filename ? filename : g_strdup (list[i]));
-	}
-	g_strfreev (list);
-
-	if (file_list == NULL)
-		return FALSE;
-
-	totem_gdk_window_set_waiting_cursor (totem->win->window);
-
-	if (drop_type != 1)
-		file_list = g_list_sort (file_list, (GCompareFunc) strcmp);
-	else
-		file_list = g_list_reverse (file_list);
-
-	/* How many files? Check whether those could be subtitles */
-	len = g_list_length (file_list);
-	if (len == 1 || (len == 2 && drop_type == 1)) {
-		if (totem_uri_is_subtitle (file_list->data) != FALSE) {
-			totem_playlist_set_current_subtitle (totem->playlist, file_list->data);
-			goto bail;
-		}
-	}
-
-	for (p = file_list; p != NULL; p = p->next) {
-		const char *filename;
-		char *title;
-
-		filename = p->data;
-		title = NULL;
-
-		if (empty_pl != FALSE && cleared == FALSE) {
-			/* The function that calls us knows better
-			 * if we should be doing something with the 
-			 * changed playlist ... */
-			g_signal_handlers_disconnect_by_func
-				(G_OBJECT (totem->playlist),
-				 playlist_changed_cb, totem);
-			totem_playlist_clear (totem->playlist);
-			cleared = TRUE;
-		}
-
-		/* Super _NETSCAPE_URL trick */
-		if (drop_type == 1) {
-			p = p->next;
-			if (p != NULL) {
-				if (g_str_has_prefix (p->data, "File:") != FALSE)
-					title = (char *)p->data + 5;
-				else
-					title = p->data;
-			}
-		}
-
-		totem_playlist_add_mrl (totem->playlist, filename, title);
-	}
-
-bail:
-	g_list_foreach (file_list, (GFunc) g_free, NULL);
-	g_list_free (file_list);
-	gdk_window_set_cursor (totem->win->window, NULL);
-
-	/* ... and reconnect because we're nice people */
-	if (cleared != FALSE)
-	{
-		char *mrl, *subtitle;
-
-		g_signal_connect (G_OBJECT (totem->playlist),
-				"changed", G_CALLBACK (playlist_changed_cb),
-				totem);
-		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
-		totem_action_set_mrl_and_play (totem, mrl, subtitle);
-		g_free (mrl);
-		g_free (subtitle);
-	}
-
-	return TRUE;
-}
-
-static void
-drop_video_cb (GtkWidget     *widget,
-	 GdkDragContext     *context,
-	 gint                x,
-	 gint                y,
-	 GtkSelectionData   *data,
-	 guint               info,
-	 guint               time,
-	 Totem              *totem)
-{
-	gboolean empty_pl;
-
-	if (context->suggested_action == GDK_ACTION_ASK)
-		context->action = totem_drag_ask (totem_get_playlist_length (totem) > 0);
-
-	if (context->action != GDK_ACTION_DEFAULT) {
-		empty_pl = (context->action == GDK_ACTION_MOVE);
-		totem_action_drop_files (totem, data, info, empty_pl);
-		gtk_drag_finish (context, TRUE, FALSE, time);
-		return;
-	}
-	gtk_drag_finish (context, FALSE, FALSE, time);
-}
-
-static void
-drag_motion_video_cb (GtkWidget      *widget,
-                      GdkDragContext *context,
-                      gint            x,
-                      gint            y,
-                      guint           time,
-                      Totem          *totem)
-{
-	GdkModifierType mask;
-
-	gdk_window_get_pointer (widget->window, NULL, NULL, &mask);
-	if (mask & GDK_CONTROL_MASK) {
-		gdk_drag_status (context, GDK_ACTION_COPY, time);
-	} else if (mask & GDK_MOD1_MASK || context->suggested_action == GDK_ACTION_ASK) {
-		gdk_drag_status (context, GDK_ACTION_ASK, time);
-	} else {
-		gdk_drag_status (context, GDK_ACTION_MOVE, time);
-	}
-}
-
-static void
-drop_playlist_cb (GtkWidget     *widget,
-	       GdkDragContext     *context,
-	       gint                x,
-	       gint                y,
-	       GtkSelectionData   *data,
-	       guint               info,
-	       guint               time,
-	       Totem              *totem)
-{
-	gboolean empty_pl;
-
-	if (context->suggested_action == GDK_ACTION_ASK)
-		context->action = totem_drag_ask (totem_get_playlist_length (totem) > 0);
-
-	if (context->action == GDK_ACTION_DEFAULT) {
-		gtk_drag_finish (context, FALSE, FALSE, time);
-		return;
-	}
-
-	empty_pl = (context->action == GDK_ACTION_MOVE);
-
-	totem_action_drop_files (totem, data, info, empty_pl);
-	gtk_drag_finish (context, TRUE, FALSE, time);
-}
-
-static void
-drag_motion_playlist_cb (GtkWidget      *widget,
-			 GdkDragContext *context,
-			 gint            x,
-			 gint            y,
-			 guint           time,
-			 Totem          *totem)
-{
-	GdkModifierType mask;
-
-	gdk_window_get_pointer (widget->window, NULL, NULL, &mask);
-
-	if (mask & GDK_MOD1_MASK || context->suggested_action == GDK_ACTION_ASK) {
-		gdk_drag_status (context, GDK_ACTION_ASK, time);
-	}
-}
-static void
-drag_video_cb (GtkWidget *widget,
-	       GdkDragContext *context,
-	       GtkSelectionData *selection_data,
-	       guint info,
-	       guint32 time,
-	       gpointer callback_data)
-{
-	Totem *totem = (Totem *) callback_data;
-	char *text;
-	int len;
-	GFile *file;
-
-	g_assert (selection_data != NULL);
-
-	if (totem->mrl == NULL)
-		return;
-
-	/* Canonicalise the MRL as a proper URI */
-	file = g_file_new_for_commandline_arg (totem->mrl);
-	text = g_file_get_uri (file);
-	g_object_unref (file);
-
-	g_return_if_fail (text != NULL);
-
-	len = strlen (text);
-
-	gtk_selection_data_set (selection_data, selection_data->target,
-				8, (guchar *) text, len);
-
-	g_free (text);
-}
-
-static void
-on_got_redirect (BaconVideoWidget *bvw, const char *mrl, Totem *totem)
-{
-	char *new_mrl;
-
-	if (strstr (mrl, "://") != NULL) {
-		new_mrl = NULL;
-	} else {
-		GFile *old_file, *parent, *new_file;
-		char *old_mrl;
-
-		/* Get the parent for the current MRL, that's our base */
-		old_mrl = totem_playlist_get_current_mrl (TOTEM_PLAYLIST (totem->playlist), NULL);
-		old_file = g_file_new_for_uri (old_mrl);
-		g_free (old_mrl);
-		parent = g_file_get_parent (old_file);
-		g_object_unref (old_file);
-
-		/* Resolve the URL */
-		new_file = g_file_get_child (parent, mrl);
-		g_object_unref (parent);
-
-		new_mrl = g_file_get_uri (new_file);
-		g_object_unref (new_file);
-	}
-
-	bacon_video_widget_close (totem->bvw);
-	totem_file_closed (totem);
-	totem_gdk_window_set_waiting_cursor (totem->win->window);
-	bacon_video_widget_open (totem->bvw, new_mrl ? new_mrl : mrl, NULL);
-	totem_file_opened (totem, new_mrl ? new_mrl : mrl);
-	gdk_window_set_cursor (totem->win->window, NULL);
-	bacon_video_widget_play (bvw, NULL);
-	g_free (new_mrl);
-}
-
-/* This is only called when we are playing a DVD or a radio */
-static void
-on_title_change_event (BaconVideoWidget *bvw, const char *string, Totem *totem)
-{
-	update_mrl_label (totem, string);
-	update_buttons (totem);
-	totem_playlist_set_title (TOTEM_PLAYLIST (totem->playlist),
-				  string, TRUE);
-}
-
-static void
-on_channels_change_event (BaconVideoWidget *bvw, Totem *totem)
-{
-	gchar *name;
-
-	totem_sublang_update (totem);
-
-	/* updated stream info (new song) */
-	name = totem_get_nice_name_for_stream (totem);
-
-	if (name != NULL) {
-		update_mrl_label (totem, name);
-		totem_playlist_set_title
-			(TOTEM_PLAYLIST (totem->playlist), name, TRUE);
-		g_free (name);
-	}
-}
-
-static void
-on_playlist_change_name (TotemPlaylist *playlist, Totem *totem)
-{
-	char *name;
-	gboolean cur;
-
-	if ((name = totem_playlist_get_current_title (playlist,
-						      &cur)) != NULL) {
-		update_mrl_label (totem, name);
-		g_free (name);
-	}
-}
-
-static void
-on_got_metadata_event (BaconVideoWidget *bvw, Totem *totem)
-{
-        char *name = NULL;
-	
-	name = totem_get_nice_name_for_stream (totem);
-
-	if (name != NULL) {
-		totem_playlist_set_title
-			(TOTEM_PLAYLIST (totem->playlist), name, FALSE);
-		g_free (name);
-	}
-	
-	on_playlist_change_name (TOTEM_PLAYLIST (totem->playlist), totem);
-}
-
-static void
-on_error_event (BaconVideoWidget *bvw, char *message,
-                gboolean playback_stopped, gboolean fatal, Totem *totem)
-{
-	/* Clear the seek if it's there, we only want to try and seek
-	 * the first file, even if it's not there */
-	totem->seek_to = 0;
-
-	if (playback_stopped)
-		play_pause_set_label (totem, STATE_STOPPED);
-
-	if (fatal == FALSE) {
-		totem_action_error (_("An error occurred"), message, totem);
-	} else {
-		totem_action_error_and_exit (_("An error occurred"),
-				message, totem);
-	}
-}
-
-static void
-on_buffering_event (BaconVideoWidget *bvw, int percentage, Totem *totem)
-{
-	totem_statusbar_push (TOTEM_STATUSBAR (totem->statusbar), percentage);
-}
-
-static void
-update_seekable (Totem *totem)
-{
-	GtkAction *action;
-	GtkActionGroup *action_group;
-	gboolean seekable;
-
-	seekable = bacon_video_widget_is_seekable (totem->bvw);
-	if (totem->seekable == seekable)
-		return;
-	totem->seekable = seekable;
-
-	/* 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);
-	totem_action_set_sensitivity ("skip-backwards", seekable);*/
-	action_group = GTK_ACTION_GROUP (gtk_builder_get_object (totem->xml, "skip-action-group"));
-
-	action = gtk_action_group_get_action (action_group, "skip-forward");
-	gtk_action_set_sensitive (action, seekable);
-
-	action = gtk_action_group_get_action (action_group, "skip-backwards");
-	gtk_action_set_sensitive (action, seekable);
-
-	/* This is for the session restore to seek */
-	if (seekable != FALSE && totem->seek_to != 0) {
-		bacon_video_widget_seek_time (totem->bvw,
-				totem->seek_to, NULL);
-		totem_action_pause (totem);
-	}
-	totem->seek_to = 0;
-
-	g_object_notify (G_OBJECT (totem), "seekable");
-}
-
-static void
-update_current_time (BaconVideoWidget *bvw,
-		gint64 current_time,
-		gint64 stream_length,
-		double current_position,
-		gboolean seekable, Totem *totem)
-{
-	if (totem->seek_lock == FALSE)
-	{
-		gtk_adjustment_set_value (totem->seekadj,
-				current_position * 65535);
-
-		if (stream_length == 0 && totem->mrl != NULL)
-		{
-			totem_statusbar_set_time_and_length
-				(TOTEM_STATUSBAR (totem->statusbar),
-				(int) (current_time / 1000), -1);
-		} else {
-			totem_statusbar_set_time_and_length
-				(TOTEM_STATUSBAR (totem->statusbar),
-				(int) (current_time / 1000),
-				(int) (stream_length / 1000));
-		}
-
-		totem_time_label_set_time
-			(TOTEM_TIME_LABEL (totem->fs->time_label),
-			 current_time, stream_length);
-	}
-
-	if (totem->stream_length != stream_length) {
-		g_object_notify (G_OBJECT (totem), "stream-length");
-		totem->stream_length = stream_length;
-	}
-}
-
-void
-volume_button_value_changed_cb (GtkScaleButton *button, gdouble value, Totem *totem)
-{
-	totem->muted = FALSE;
-	bacon_video_widget_set_volume (totem->bvw, value);
-}
-
-static void
-update_volume_sliders (Totem *totem)
-{
-	double volume;
-	GtkAction *action;
-
-	volume = bacon_video_widget_get_volume (totem->bvw);
-
-	g_signal_handlers_block_by_func (totem->volume, volume_button_value_changed_cb, totem);
-	gtk_scale_button_set_value (GTK_SCALE_BUTTON (totem->volume), volume);
-	g_signal_handlers_unblock_by_func (totem->volume, volume_button_value_changed_cb, totem);
-  
-	action = gtk_action_group_get_action (totem->main_action_group, "volume-down");
-	gtk_action_set_sensitive (action, volume > VOLUME_EPSILON && totem->volume_sensitive);
-
-	action = gtk_action_group_get_action (totem->main_action_group, "volume-up");
-	gtk_action_set_sensitive (action, volume < (1.0 - VOLUME_EPSILON) && totem->volume_sensitive);
-}
-
-static void
-property_notify_cb_volume (BaconVideoWidget *bvw, GParamSpec *spec, Totem *totem)
-{
-	update_volume_sliders (totem);
-}
-
-static void
-property_notify_cb_logo_mode (BaconVideoWidget *bvw, GParamSpec *spec, Totem *totem)
-{
-	gboolean enabled;
-	enabled = bacon_video_widget_get_logo_mode (totem->bvw);
-	totem_action_zoom (totem, enabled ? ZOOM_DISABLE : ZOOM_ENABLE);
-}
-
-static void
-property_notify_cb_seekable (BaconVideoWidget *bvw, GParamSpec *spec, Totem *totem)
-{
-	update_seekable (totem);
-}
-
-gboolean
-seek_slider_pressed_cb (GtkWidget *widget, GdkEventButton *event, Totem *totem)
-{
-	/* HACK: we want the behaviour you get with the middle button, so we
-	 * mangle the event.  clicking with other buttons moves the slider in
-	 * step increments, clicking with the middle button moves the slider to
-	 * the location of the click.
-	 */
-	event->button = 2;
-
-	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;
-}
-
-void
-seek_slider_changed_cb (GtkAdjustment *adj, Totem *totem)
-{
-	double pos;
-	gint time;
-
-	if (totem->seek_lock == FALSE)
-		return;
-
-	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);
-
-	if (bacon_video_widget_can_direct_seek (totem->bvw) != FALSE)
-		totem_action_seek (totem, pos);
-}
-
-gboolean
-seek_slider_released_cb (GtkWidget *widget, GdkEventButton *event, Totem *totem)
-{
-	GtkAdjustment *adj;
-	gdouble val;
-
-	/* HACK: see seek_slider_pressed_cb */
-	event->button = 2;
-
-	/* set to FALSE here to avoid triggering a final seek when
-	 * syncing the adjustments while being in direct seek mode */
-	totem->seek_lock = FALSE;
-
-	/* sync both adjustments */
-	adj = gtk_range_get_adjustment (GTK_RANGE (widget));
-	val = gtk_adjustment_get_value (adj);
-
-	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;
-}
-
-static gboolean
-totem_action_open_files (Totem *totem, char **list)
-{
-	GSList *slist = NULL;
-	int i, retval;
-
-	for (i = 0 ; list[i] != NULL; i++)
-		slist = g_slist_prepend (slist, list[i]);
-
-	slist = g_slist_reverse (slist);
-	retval = totem_action_open_files_list (totem, slist);
-	g_slist_free (slist);
-
-	return retval;
-}
-
-static gboolean
-totem_action_open_files_list (Totem *totem, GSList *list)
-{
-	GSList *l;
-	gboolean changed;
-	gboolean cleared;
-
-	changed = FALSE;
-	cleared = FALSE;
-
-	if (list == NULL)
-		return changed;
-
-	totem_gdk_window_set_waiting_cursor (totem->win->window);
-
-	for (l = list ; l != NULL; l = l->next)
-	{
-		char *filename;
-		char *data = l->data;
-
-		if (data == NULL)
-			continue;
-
-		/* Ignore relatives paths that start with "--", tough luck */
-		if (data[0] == '-' && data[1] == '-')
-			continue;
-
-		/* Get the subtitle part out for our tests */
-		filename = totem_create_full_path (data);
-		if (filename == NULL)
-			filename = g_strdup (data);
-
-		if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)
-				|| strstr (filename, "#") != NULL
-				|| strstr (filename, "://") != NULL
-				|| g_str_has_prefix (filename, "dvd:") != FALSE
-				|| g_str_has_prefix (filename, "vcd:") != FALSE
-				|| g_str_has_prefix (filename, "dvb:") != FALSE)
-		{
-			if (cleared == FALSE)
-			{
-				/* The function that calls us knows better
-				 * if we should be doing something with the 
-				 * changed playlist ... */
-				g_signal_handlers_disconnect_by_func
-					(G_OBJECT (totem->playlist),
-					 playlist_changed_cb, totem);
-				changed = totem_playlist_clear (totem->playlist);
-				bacon_video_widget_close (totem->bvw);
-				totem_file_closed (totem);
-				cleared = TRUE;
-			}
-
-			if (totem_is_block_device (filename) != FALSE) {
-				totem_action_load_media_device (totem, data);
-				changed = TRUE;
-			} else if (g_str_has_prefix (filename, "dvb:/") != FALSE) {
-				totem_playlist_add_mrl (totem->playlist, data, NULL);
-				changed = TRUE;
-			} else if (g_str_equal (filename, "dvb:") != FALSE) {
-				totem_action_load_media (totem, MEDIA_TYPE_DVB, "0");
-				changed = TRUE;
-			} else if (totem_playlist_add_mrl (totem->playlist, filename, NULL) != FALSE) {
-				totem_action_add_recent (totem, filename);
-				changed = TRUE;
-			}
-		}
-
-		g_free (filename);
-	}
-
-	gdk_window_set_cursor (totem->win->window, NULL);
-
-	/* ... and reconnect because we're nice people */
-	if (cleared != FALSE)
-	{
-		g_signal_connect (G_OBJECT (totem->playlist),
-				"changed", G_CALLBACK (playlist_changed_cb),
-				totem);
-	}
-
-	return changed;
-}
-
-void
-show_controls (Totem *totem, gboolean was_fullscreen)
-{
-	GtkAction *action;
-	GtkWidget *menubar, *controlbar, *statusbar, *bvw_box, *widget;
-	int width = 0, height = 0;
-
-	if (totem->bvw == NULL)
-		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);
-
-	action = gtk_action_group_get_action (totem->main_action_group, "show-controls");
-	gtk_action_set_sensitive (action, !totem_is_fullscreen (totem));
-
-	if (totem->controls_visibility == TOTEM_CONTROLS_VISIBLE) {
-		if (was_fullscreen == FALSE) {
-			height = widget->allocation.height;
-			width =	widget->allocation.width;
-		}
-
-		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
-			   is no convenience method to get the handle's width.
-			   */
-			GValue value = { 0, };
-			GtkWidget *pane;
-			int handle_size;
-
-			g_value_init (&value, G_TYPE_INT);
-			pane = GTK_WIDGET (gtk_builder_get_object (totem->xml,
-					"tmw_main_pane"));
-			gtk_widget_style_get_property (pane, "handle-size",
-					&value);
-			handle_size = g_value_get_int (&value);
-			g_value_unset (&value);
-			
-			gtk_widget_show (totem->sidebar);
-			width += totem->sidebar->allocation.width
-				+ handle_size;
-		} else {
-			gtk_widget_hide (totem->sidebar);
-		}
-
-		gtk_container_set_border_width (GTK_CONTAINER (bvw_box),
-				BVW_VBOX_BORDER_WIDTH);
-
-		if (was_fullscreen == FALSE) {
-			height += menubar->allocation.height
-				+ controlbar->allocation.height
-				+ statusbar->allocation.height
-				+ 2 * BVW_VBOX_BORDER_WIDTH;
-			width += 2 * BVW_VBOX_BORDER_WIDTH;
-			gtk_window_resize (GTK_WINDOW(totem->win),
-					width, height);
-		}
-	} else {
-		if (totem->controls_visibility == TOTEM_CONTROLS_HIDDEN) {
-			width = widget->allocation.width;
-			height = widget->allocation.height;
-		}
-
-		/* Hide and make the menubar unsensitive */
-		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 */
-		gtk_container_set_border_width (GTK_CONTAINER (bvw_box), 0);
-
-		if (totem->controls_visibility == TOTEM_CONTROLS_HIDDEN) {
-			gtk_window_resize (GTK_WINDOW(totem->win),
-					width, height);
-		}
-	}
-}
-
-/**
- * totem_action_toggle_controls:
- * @totem: a #TotemObject
- *
- * If Totem's not fullscreened, this toggles the state of the "Show Controls"
- * menu entry, and consequently shows or hides the controls in the UI.
- **/
-void
-totem_action_toggle_controls (Totem *totem)
-{
-	GtkAction *action;
-	gboolean state;
-
-	if (totem_is_fullscreen (totem) != FALSE)
-		return;
-
- 	action = gtk_action_group_get_action (totem->main_action_group,
- 		"show-controls");
- 	state = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
- 	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !state);
-}
-
-void
-totem_action_next_angle (Totem *totem)
-{
-	if (totem_playing_dvd (totem->mrl) != FALSE)
-		bacon_video_widget_dvd_event (totem->bvw, BVW_DVD_NEXT_ANGLE);
-}
-
-void
-totem_action_set_playlist_index (Totem *totem, guint index)
-{
-	char *mrl, *subtitle;
-
-	totem_playlist_set_current (totem->playlist, index);
-	mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
-	totem_action_set_mrl_and_play (totem, mrl, subtitle);
-	g_free (mrl);
-	g_free (subtitle);
-}
-
-/**
- * totem_action_remote:
- * @totem: a #TotemObject
- * @cmd: a #TotemRemoteCommand
- * @url: an MRL to play, or %NULL
- *
- * Executes the specified @cmd on this instance of Totem. If @cmd
- * is an operation requiring an MRL, @url is required; it can be %NULL
- * otherwise.
- *
- * If Totem's fullscreened and the operation is executed correctly,
- * the controls will appear as if the user had moved the mouse.
- **/
-void
-totem_action_remote (Totem *totem, TotemRemoteCommand cmd, const char *url)
-{
-	gboolean handled = TRUE;
-
-	switch (cmd) {
-	case TOTEM_REMOTE_COMMAND_PLAY:
-		totem_action_play (totem);
-		break;
-	case TOTEM_REMOTE_COMMAND_PLAYPAUSE:
-		totem_action_play_pause (totem);
-		break;
-	case TOTEM_REMOTE_COMMAND_PAUSE:
-		totem_action_pause (totem);
-		break;
-	case TOTEM_REMOTE_COMMAND_STOP: {
-		char *mrl, *subtitle;
-
-		totem_playlist_set_at_start (totem->playlist);
-		update_buttons (totem);
-		totem_action_stop (totem);
-		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
-		if (mrl != NULL) {
-			totem_action_set_mrl_with_warning (totem, mrl, subtitle, FALSE);
-			bacon_video_widget_pause (totem->bvw);
-			g_free (mrl);
-			g_free (subtitle);
-		}
-		break;
-	};
-	case TOTEM_REMOTE_COMMAND_SEEK_FORWARD: {
-		double offset = 0;
-
-		if (url != NULL)
-			offset = g_ascii_strtod (url, NULL);
-		if (offset == 0) {
-			totem_action_seek_relative (totem, SEEK_FORWARD_OFFSET * 1000);
-		} else {
-			totem_action_seek_relative (totem, offset * 1000);
-		}
-		break;
-	}
-	case TOTEM_REMOTE_COMMAND_SEEK_BACKWARD: {
-		double offset = 0;
-
-		if (url != NULL)
-			offset = g_ascii_strtod (url, NULL);
-		if (offset == 0)
-			totem_action_seek_relative (totem, SEEK_BACKWARD_OFFSET * 1000);
-		else
-			totem_action_seek_relative (totem,  - (offset * 1000));
-		break;
-	}
-	case TOTEM_REMOTE_COMMAND_VOLUME_UP:
-		totem_action_volume_relative (totem, VOLUME_UP_OFFSET);
-		break;
-	case TOTEM_REMOTE_COMMAND_VOLUME_DOWN:
-		totem_action_volume_relative (totem, VOLUME_DOWN_OFFSET);
-		break;
-	case TOTEM_REMOTE_COMMAND_NEXT:
-		totem_action_next (totem);
-		break;
-	case TOTEM_REMOTE_COMMAND_PREVIOUS:
-		totem_action_previous (totem);
-		break;
-	case TOTEM_REMOTE_COMMAND_FULLSCREEN:
-		totem_action_fullscreen_toggle (totem);
-		break;
-	case TOTEM_REMOTE_COMMAND_QUIT:
-		totem_action_exit (totem);
-		break;
-	case TOTEM_REMOTE_COMMAND_ENQUEUE:
-		g_assert (url != NULL);
-		if (totem_playlist_add_mrl_with_cursor (totem->playlist, url, NULL) != FALSE) {
-			totem_action_add_recent (totem, url);
-		}
-		break;
-	case TOTEM_REMOTE_COMMAND_REPLACE:
-		totem_playlist_clear (totem->playlist);
-		if (url == NULL) {
-			bacon_video_widget_close (totem->bvw);
-			totem_file_closed (totem);
-			totem_action_set_mrl (totem, NULL, NULL);
-			break;
-		}
-		if (strcmp (url, "dvd:") == 0) {
-			/* FIXME b0rked */
-			totem_action_play_media (totem, MEDIA_TYPE_DVD, NULL);
-		} else if (strcmp (url, "vcd:") == 0) {
-			/* FIXME b0rked */
-			totem_action_play_media (totem, MEDIA_TYPE_VCD, NULL);
-		} else if (g_str_has_prefix (url, "dvb:") != FALSE) {
-			totem_action_load_media (totem, MEDIA_TYPE_DVB, "0");
-		} else if (totem_playlist_add_mrl_with_cursor (totem->playlist, url, NULL) != FALSE) {
-			totem_action_add_recent (totem, url);
-		}
-		break;
-	case TOTEM_REMOTE_COMMAND_SHOW:
-		gtk_window_present (GTK_WINDOW (totem->win));
-		break;
-	case TOTEM_REMOTE_COMMAND_TOGGLE_CONTROLS:
-		if (totem->controls_visibility != TOTEM_CONTROLS_FULLSCREEN)
-		{
-			GtkToggleAction *action;
-			gboolean state;
-
-			action = GTK_TOGGLE_ACTION (gtk_action_group_get_action
-					(totem->main_action_group,
-					 "show-controls"));
-			state = gtk_toggle_action_get_active (action);
-			gtk_toggle_action_set_active (action, !state);
-		}
-		break;
-	case TOTEM_REMOTE_COMMAND_SHOW_PLAYING:
-		{
-			char *title;
-			gboolean custom;
-
-			title = totem_playlist_get_current_title
-				(totem->playlist, &custom);
-			bacon_message_connection_send (totem->conn,
-					title ? title : SHOW_PLAYING_NO_TRACKS);
-			g_free (title);
-		}
-		break;
-	case TOTEM_REMOTE_COMMAND_SHOW_VOLUME:
-		{
-			char *vol_str;
-			int vol;
-
-			if (bacon_video_widget_can_set_volume (totem->bvw) == FALSE)
-				vol = 0;
-			else
-				vol = bacon_video_widget_get_volume (totem->bvw);
-			vol_str = g_strdup_printf ("%d", vol);
-			bacon_message_connection_send (totem->conn, vol_str);
-			g_free (vol_str);
-		}
-		break;
-	case TOTEM_REMOTE_COMMAND_UP:
-		bacon_video_widget_dvd_event (totem->bvw,
-				BVW_DVD_ROOT_MENU_UP);
-		break;
-	case TOTEM_REMOTE_COMMAND_DOWN:
-		bacon_video_widget_dvd_event (totem->bvw,
-				BVW_DVD_ROOT_MENU_DOWN);
-		break;
-	case TOTEM_REMOTE_COMMAND_LEFT:
-		bacon_video_widget_dvd_event (totem->bvw,
-				BVW_DVD_ROOT_MENU_LEFT);
-		break;
-	case TOTEM_REMOTE_COMMAND_RIGHT:
-		bacon_video_widget_dvd_event (totem->bvw,
-				BVW_DVD_ROOT_MENU_RIGHT);
-		break;
-	case TOTEM_REMOTE_COMMAND_SELECT:
-		bacon_video_widget_dvd_event (totem->bvw,
-				BVW_DVD_ROOT_MENU_SELECT);
-		break;
-	case TOTEM_REMOTE_COMMAND_DVD_MENU:
-		bacon_video_widget_dvd_event (totem->bvw,
-				BVW_DVD_ROOT_MENU);
-		break;
-	case TOTEM_REMOTE_COMMAND_ZOOM_UP:
-		totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
-		break;
-	case TOTEM_REMOTE_COMMAND_ZOOM_DOWN:
-		totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
-		break;
-	case TOTEM_REMOTE_COMMAND_EJECT:
-		totem_action_eject (totem);
-		break;
-	case TOTEM_REMOTE_COMMAND_PLAY_DVD:
-		/* TODO - how to see if can, and play the DVD (like the menu item) */
-		break;
-	case TOTEM_REMOTE_COMMAND_MUTE:
-		totem_action_volume_toggle_mute (totem);
-		break;
-	case TOTEM_REMOTE_COMMAND_TOGGLE_ASPECT:
-		totem_action_toggle_aspect_ratio (totem);
-		break;
-	default:
-		handled = FALSE;
-		break;
-	}
-
-	if (handled != FALSE
-			&& gtk_window_is_active (GTK_WINDOW (totem->win))
-			&& totem_fullscreen_is_fullscreen (totem->fs) != FALSE) {
-		totem_fullscreen_show_popups (totem->fs, TRUE);
-	}
-}
-
-void totem_action_remote_set_setting (Totem *totem,
-				      TotemRemoteSetting setting,
-				      gboolean value)
-{
-	GtkAction *action;
-
-	action = NULL;
-
-	switch (setting) {
-	case TOTEM_REMOTE_SETTING_SHUFFLE:
-		action = gtk_action_group_get_action (totem->main_action_group, "shuffle-mode");
-		break;
-	case TOTEM_REMOTE_SETTING_REPEAT:
-		action = gtk_action_group_get_action (totem->main_action_group, "repeat-mode");
-		break;
-	default:
-		g_assert_not_reached ();
-	}
-
-	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), value);
-}
-
-gboolean totem_action_remote_get_setting (Totem *totem,
-					  TotemRemoteSetting setting)
-{
-	GtkAction *action;
-
-	action = NULL;
-
-	switch (setting) {
-	case TOTEM_REMOTE_SETTING_SHUFFLE:
-		action = gtk_action_group_get_action (totem->main_action_group, "shuffle-mode");
-		break;
-	case TOTEM_REMOTE_SETTING_REPEAT:
-		action = gtk_action_group_get_action (totem->main_action_group, "repeat-mode");
-		break;
-	default:
-		g_assert_not_reached ();
-	}
-
-	return gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
-}
-
-static void
-playlist_changed_cb (GtkWidget *playlist, Totem *totem)
-{
-	char *mrl, *subtitle;
-
-	update_buttons (totem);
-	mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
-
-	if (mrl == NULL)
-		return;
-
-	if (totem_playlist_get_playing (totem->playlist) == TOTEM_PLAYLIST_STATUS_NONE)
-		totem_action_set_mrl_and_play (totem, mrl, subtitle);
-
-	g_free (mrl);
-	g_free (subtitle);
-}
-
-static void
-item_activated_cb (GtkWidget *playlist, Totem *totem)
-{
-	totem_action_seek (totem, 0);
-}
-
-static void
-current_removed_cb (GtkWidget *playlist, Totem *totem)
-{
-	char *mrl, *subtitle;
-
-	/* Set play button status */
-	play_pause_set_label (totem, STATE_STOPPED);
-	mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
-
-	if (mrl == NULL) {
-		g_free (subtitle);
-		subtitle = NULL;
-		totem_playlist_set_at_start (totem->playlist);
-		update_buttons (totem);
-		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
-	} else {
-		update_buttons (totem);
-	}
-
-	totem_action_set_mrl_and_play (totem, mrl, subtitle);
-	g_free (mrl);
-	g_free (subtitle);
-}
-
-static void
-subtitle_changed_cb (GtkWidget *playlist, Totem *totem)
-{
-	char *mrl, *subtitle;
-
-	totem_action_stop (totem);
-	mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
-	totem_action_set_mrl_and_play (totem, mrl, subtitle);
-
-	g_free (mrl);
-	g_free (subtitle);
-}
-
-static void
-playlist_repeat_toggle_cb (TotemPlaylist *playlist, gboolean repeat, Totem *totem)
-{
-	GtkAction *action;
-
-	action = gtk_action_group_get_action (totem->main_action_group, "repeat-mode");
-
-	g_signal_handlers_block_matched (G_OBJECT (action), G_SIGNAL_MATCH_DATA, 0, 0,
-			NULL, NULL, totem);
-
-	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), repeat);
-
-	g_signal_handlers_unblock_matched (G_OBJECT (action), G_SIGNAL_MATCH_DATA, 0, 0,
-			NULL, NULL, totem);
-}
-
-static void
-playlist_shuffle_toggle_cb (TotemPlaylist *playlist, gboolean shuffle, Totem *totem)
-{
-	GtkAction *action;
-
-	action = gtk_action_group_get_action (totem->main_action_group, "shuffle-mode");
-
-	g_signal_handlers_block_matched (G_OBJECT (action), G_SIGNAL_MATCH_DATA, 0, 0,
-			NULL, NULL, totem);
-
-	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), shuffle);
-
-	g_signal_handlers_unblock_matched (G_OBJECT (action), G_SIGNAL_MATCH_DATA, 0, 0,
-			NULL, NULL, totem);
-}
-
-/**
- * totem_is_fullscreen:
- * @totem: a #TotemObject
- *
- * Returns %TRUE if Totem is fullscreened.
- *
- * Return value: %TRUE if Totem is fullscreened
- **/
-gboolean
-totem_is_fullscreen (Totem *totem)
-{
-	g_return_val_if_fail (TOTEM_IS_OBJECT (totem), FALSE);
-
-	return (totem->controls_visibility == TOTEM_CONTROLS_FULLSCREEN);
-}
-
-/**
- * totem_is_playing:
- * @totem: a #TotemObject
- *
- * Returns %TRUE if Totem is playing a stream.
- *
- * Return value: %TRUE if Totem is playing a stream
- **/
-gboolean
-totem_is_playing (Totem *totem)
-{
-	g_return_val_if_fail (TOTEM_IS_OBJECT (totem), FALSE);
-
-	if (totem->bvw == NULL)
-		return FALSE;
-
-	return bacon_video_widget_is_playing (totem->bvw) != FALSE;
-}
-
-gboolean
-totem_is_paused (Totem *totem)
-{
-	g_return_val_if_fail (TOTEM_IS_OBJECT (totem), FALSE);
-
-	return totem->state == STATE_PAUSED;
-}
-
-/**
- * totem_is_seekable:
- * @totem: a #TotemObject
- *
- * Returns %TRUE if the current stream is seekable.
- *
- * Return value: %TRUE if the current stream is seekable
- **/
-gboolean
-totem_is_seekable (Totem *totem)
-{
-	g_return_val_if_fail (TOTEM_IS_OBJECT (totem), FALSE);
-
-	if (totem->bvw == NULL)
-		return FALSE;
-
-	return bacon_video_widget_is_seekable (totem->bvw) != FALSE;
-}
-
-static void
-on_mouse_click_fullscreen (GtkWidget *widget, Totem *totem)
-{
-	if (totem_fullscreen_is_fullscreen (totem->fs) != FALSE)
-		totem_fullscreen_show_popups (totem->fs, TRUE);
-}
-
-static gboolean
-on_video_button_press_event (BaconVideoWidget *bvw, GdkEventButton *event,
-		Totem *totem)
-{
-	if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
-		totem_action_fullscreen_toggle(totem);
-		return TRUE;
-	} else if (event->type == GDK_BUTTON_PRESS && event->button == 2) {
-		totem_action_play_pause(totem);
-		return TRUE;
-	} else if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
-		totem_action_menu_popup (totem, event->button);
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-static gboolean
-on_eos_event (GtkWidget *widget, Totem *totem)
-{
-	if (bacon_video_widget_get_logo_mode (totem->bvw) != FALSE)
-		return FALSE;
-
-	/* EOS on DVB means that we lost the signal */
-	if (totem->mrl != NULL && g_str_has_prefix (totem->mrl, "dvb://") != FALSE) {
-		totem_action_stop (totem);
-		totem_action_error_and_exit (_("TV signal lost"),
-					     _("Please verify your hardware setup."),
-					     totem);
-		return FALSE;
-	}
-
-	if (totem_playlist_has_next_mrl (totem->playlist) == FALSE
-			&& totem_playlist_get_repeat (totem->playlist) == FALSE)
-	{
-		char *mrl, *subtitle;
-
-		/* Set play button status */
-		totem_playlist_set_at_start (totem->playlist);
-		update_buttons (totem);
-		totem_action_stop (totem);
-		mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
-		totem_action_set_mrl_with_warning (totem, mrl, subtitle, FALSE);
-		bacon_video_widget_pause (totem->bvw);
-		g_free (mrl);
-		g_free (subtitle);
-	} else {
-		if (totem_playlist_get_repeat (totem->playlist)
-				&& totem_playlist_get_last  (totem->playlist) == 0
-				&& totem_is_seekable (totem))
-			totem_action_seek_time (totem, 0);
-		else
-			totem_action_next (totem);
-	}
-
-	return FALSE;
-}
-
-static gboolean
-totem_action_handle_key_release (Totem *totem, GdkEventKey *event)
-{
-	gboolean retval = TRUE;
-
-	switch (event->keyval) {
-	case GDK_Left:
-	case GDK_Right:
-		totem_statusbar_set_seeking (TOTEM_STATUSBAR (totem->statusbar), FALSE);
-		totem_time_label_set_seeking (TOTEM_TIME_LABEL (totem->fs->time_label), FALSE);
-		break;
-	}
-
-	return retval;
-}
-
-static void
-totem_action_handle_seek (Totem *totem, GdkEventKey *event, gboolean is_forward)
-{
-	if (is_forward != FALSE) {
-		if (event->state & GDK_SHIFT_MASK)
-			totem_action_seek_relative (totem, SEEK_FORWARD_SHORT_OFFSET * 1000);
-		else if (event->state & GDK_CONTROL_MASK)
-			totem_action_seek_relative (totem, SEEK_FORWARD_LONG_OFFSET * 1000);
-		else
-			totem_action_seek_relative (totem, SEEK_FORWARD_OFFSET * 1000);
-	} else {
-		if (event->state & GDK_SHIFT_MASK)
-			totem_action_seek_relative (totem, SEEK_BACKWARD_SHORT_OFFSET * 1000);
-		else if (event->state & GDK_CONTROL_MASK)
-			totem_action_seek_relative (totem, SEEK_BACKWARD_LONG_OFFSET * 1000);
-		else
-			totem_action_seek_relative (totem, SEEK_BACKWARD_OFFSET * 1000);
-	}
-}
-
-static gboolean
-totem_action_handle_key_press (Totem *totem, GdkEventKey *event)
-{
-	gboolean retval = TRUE;
-
-	switch (event->keyval) {
-	case GDK_A:
-	case GDK_a:
-		totem_action_toggle_aspect_ratio (totem);
-		break;
-#ifdef HAVE_XFREE
-	case XF86XK_AudioPrev:
-	case XF86XK_Back:
-#endif /* HAVE_XFREE */
-	case GDK_B:
-	case GDK_b:
-		totem_action_previous (totem);
-		break;
-	case GDK_C:
-	case GDK_c:
-		bacon_video_widget_dvd_event (totem->bvw,
-				BVW_DVD_CHAPTER_MENU);
-		break;
-	case GDK_F11:
-	case GDK_f:
-	case GDK_F:
-		totem_action_fullscreen_toggle (totem);
-		break;
-	case GDK_g:
-	case GDK_G:
-		totem_action_next_angle (totem);
-		break;
-	case GDK_h:
-	case GDK_H:
-		totem_action_toggle_controls (totem);
-		break;
-	case GDK_i:
-	case GDK_I:
-		{
-			GtkToggleAction *action;
-			gboolean state;
-
-			action = GTK_TOGGLE_ACTION (gtk_action_group_get_action
-					(totem->main_action_group,
-					 "deinterlace"));
-			state = gtk_toggle_action_get_active (action);
-			gtk_toggle_action_set_active (action, !state);
-		}
-		break;
-	case GDK_M:
-	case GDK_m:
-		bacon_video_widget_dvd_event (totem->bvw, BVW_DVD_ROOT_MENU);
-		break;
-#ifdef HAVE_XFREE
-	case XF86XK_AudioNext:
-	case XF86XK_Forward:
-#endif /* HAVE_XFREE */
-	case GDK_N:
-	case GDK_n:
-		totem_action_next (totem);
-		break;
-#ifdef HAVE_XFREE
-	case XF86XK_OpenURL:
-		totem_action_fullscreen (totem, FALSE);
-		totem_action_open_location (totem);
-		break;
-#endif /* HAVE_XFREE */
-	case GDK_O:
-	case GDK_o:
-#ifdef HAVE_XFREE
-	case XF86XK_Open:
-#endif /* HAVE_XFREE */
-		totem_action_fullscreen (totem, FALSE);
-		totem_action_open (totem);
-		break;
-#ifdef HAVE_XFREE
-	case XF86XK_AudioPlay:
-#endif /* HAVE_XFREE */
-	case GDK_p:
-	case GDK_P:
-		if (event->state & GDK_CONTROL_MASK)
-			totem_action_show_properties (totem);
-		else 
-			totem_action_play_pause (totem);
-		break;
-#ifdef HAVE_XFREE
-	case XF86XK_AudioPause:
-	case XF86XK_AudioStop:
-		totem_action_pause (totem);
-		break;
-#endif /* HAVE_XFREE */
-	case GDK_q:
-	case GDK_Q:
-		totem_action_exit (totem);
-		break;
-	case GDK_r:
-	case GDK_R:
-#ifdef HAVE_XFREE
-	case XF86XK_ZoomIn:
-#endif /* HAVE_XFREE */
-		totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
-		break;
-	case GDK_t:
-	case GDK_T:
-#ifdef HAVE_XFREE
-	case XF86XK_ZoomOut:
-#endif /* HAVE_XFREE */
-		totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
-		break;
-#ifdef HAVE_XFREE
-	case XF86XK_Eject:
-		totem_action_eject (totem);
-		break;
-#endif /* HAVE_XFREE */
-	case GDK_Escape:
-		if (event->state & GDK_SUPER_MASK)
-			bacon_video_widget_dvd_event (totem->bvw, BVW_DVD_ROOT_MENU);
-		else
-			totem_action_fullscreen (totem, FALSE);
-		break;
-	case GDK_Left:
-	case GDK_Right:
-		{
-			gboolean is_forward;
-
-			if (totem_is_fullscreen (totem) != FALSE)
-				totem_fullscreen_show_popups (totem->fs, FALSE);
-
-			is_forward = (event->keyval == GDK_Right);
-			/* Switch direction in RTL environment */
-			if (gtk_widget_get_direction (totem->win) == GTK_TEXT_DIR_RTL)
-				is_forward = !is_forward;
-			totem_action_handle_seek (totem, event, is_forward);
-		}
-		break;
-	case GDK_space:
-		if (totem_is_fullscreen (totem) != FALSE || gtk_widget_is_focus (GTK_WIDGET (totem->bvw)) != FALSE)
-			totem_action_play_pause (totem);
-		else
-			retval = FALSE;
-		break;
-	case GDK_Up:
-		totem_action_volume_relative (totem, VOLUME_UP_OFFSET);
-		break;
-	case GDK_Down:
-		totem_action_volume_relative (totem, VOLUME_DOWN_OFFSET);
-		break;
-	case GDK_0:
-		if (event->state & GDK_CONTROL_MASK)
-			totem_action_zoom_reset (totem);
-		else
-			totem_action_set_scale_ratio (totem, 0.5);
-		break;
-	case GDK_onehalf:
-		totem_action_set_scale_ratio (totem, 0.5);
-		break;
-	case GDK_1:
-		totem_action_set_scale_ratio (totem, 1);
-		break;
-	case GDK_2:
-		totem_action_set_scale_ratio (totem, 2);
-		break;
-	case GDK_Menu:
-		totem_action_menu_popup (totem, 0);
-		break;
-	case GDK_F10:
-		if (!(event->state & GDK_SHIFT_MASK))
-			return FALSE;
-
-		totem_action_menu_popup (totem, 0);
-		break;
-	case GDK_plus:
-	case GDK_KP_Add:
-		if (!(event->state & GDK_CONTROL_MASK)) {
-			totem_action_next (totem);
-		} else {
-			totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
-		}
-		break;
-	case GDK_minus:
-	case GDK_KP_Subtract:
-		if (!(event->state & GDK_CONTROL_MASK)) {
-			totem_action_previous (totem);
-		} else {
-			totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
-		}
-		break;
-	case GDK_KP_Up:
-	case GDK_KP_8:
-		bacon_video_widget_dvd_event (totem->bvw, 
-					      BVW_DVD_ROOT_MENU_UP);
-		break;
-	case GDK_KP_Down:
-	case GDK_KP_2:
-		bacon_video_widget_dvd_event (totem->bvw, 
-					      BVW_DVD_ROOT_MENU_DOWN);
-		break;
-	case GDK_KP_Right:
-	case GDK_KP_6:
-		bacon_video_widget_dvd_event (totem->bvw, 
-					      BVW_DVD_ROOT_MENU_RIGHT);
-		break;
-	case GDK_KP_Left:
-	case GDK_KP_4:
-		bacon_video_widget_dvd_event (totem->bvw, 
-					      BVW_DVD_ROOT_MENU_LEFT);
-		break;
-	case GDK_KP_Begin:
-	case GDK_KP_5:
-		bacon_video_widget_dvd_event (totem->bvw,
-					      BVW_DVD_ROOT_MENU_SELECT);
-	default:
-		retval = FALSE;
-	}
-
-	return retval;
-}
-
-static gboolean
-totem_action_handle_scroll (Totem *totem, GdkScrollDirection direction)
-{
-	gboolean retval = TRUE;
-
-	if (totem_fullscreen_is_fullscreen (totem->fs) != FALSE)
-		totem_fullscreen_show_popups (totem->fs, TRUE);
-
-	switch (direction) {
-	case GDK_SCROLL_UP:
-		totem_action_seek_relative (totem, SEEK_FORWARD_SHORT_OFFSET * 1000);
-		break;
-	case GDK_SCROLL_DOWN:
-		totem_action_seek_relative (totem, SEEK_BACKWARD_SHORT_OFFSET * 1000);
-		break;
-	default:
-		retval = FALSE;
-	}
-
-	return retval;
-}
-
-int
-window_key_press_event_cb (GtkWidget *win, GdkEventKey *event, Totem *totem)
-{
-	if (totem_sidebar_is_focused (totem) != FALSE)
-		return FALSE;
-
-	/* Special case Eject, Open, Open URI and
-	 * seeking keyboard shortcuts */
-	if (event->state != 0
-			&& (event->state & GDK_CONTROL_MASK))
-	{
-		switch (event->keyval)
-		case GDK_E:
-		case GDK_e:
-		case GDK_O:
-		case GDK_o:
-		case GDK_L:
-		case GDK_l:
-		case GDK_q:
-		case GDK_Q:
-		case GDK_S:
-		case GDK_s:
-		case GDK_Right:
-		case GDK_Left:
-		case GDK_plus:
-		case GDK_KP_Add:
-		case GDK_minus:
-		case GDK_KP_Subtract:
-		case GDK_0:
-			if (event->type == GDK_KEY_PRESS) {
-				return totem_action_handle_key_press (totem, event);
-			} else {
-				return totem_action_handle_key_release (totem, event);
-			}
-	}
-
-	if (event->state != 0
-			&& (event->state & GDK_SUPER_MASK)) {
-		switch (event->keyval)
-		case GDK_Escape:
-			if (event->type == GDK_KEY_PRESS) {
-				return totem_action_handle_key_press (totem, event);
-			} else {
-				return totem_action_handle_key_release (totem, event);
-			}
-	}
-
-
-	/* If we have modifiers, and either Ctrl, Mod1 (Alt), or any
-	 * of Mod3 to Mod5 (Mod2 is num-lock...) are pressed, we
-	 * let Gtk+ handle the key */
-	if (event->state != 0
-			&& ((event->state & GDK_CONTROL_MASK)
-			|| (event->state & GDK_MOD1_MASK)
-			|| (event->state & GDK_MOD3_MASK)
-			|| (event->state & GDK_MOD4_MASK)
-			|| (event->state & GDK_MOD5_MASK)))
-		return FALSE;
-
-	if (event->type == GDK_KEY_PRESS) {
-		return totem_action_handle_key_press (totem, event);
-	} else {
-		return totem_action_handle_key_release (totem, event);
-	}
-}
-
-gboolean
-window_scroll_event_cb (GtkWidget *win, GdkEventScroll *event, Totem *totem)
-{
-	return totem_action_handle_scroll (totem, event->direction);
-}
-
-static void
-update_media_menu_items (Totem *totem)
-{
-	GMount *mount;
-	gboolean playing;
-
-	playing = totem_playing_dvd (totem->mrl);
-
-	totem_action_set_sensitivity ("dvd-root-menu", playing);
-	totem_action_set_sensitivity ("dvd-title-menu", playing);
-	totem_action_set_sensitivity ("dvd-audio-menu", playing);
-	totem_action_set_sensitivity ("dvd-angle-menu", playing);
-	totem_action_set_sensitivity ("dvd-chapter-menu", playing);
-	/* FIXME we should only show that if we have multiple angles */
-	totem_action_set_sensitivity ("next-angle", playing);
-
-	mount = totem_get_mount_for_media (totem->mrl);
-	totem_action_set_sensitivity ("eject", mount != NULL);
-	if (mount != NULL)
-		g_object_unref (mount);
-}
-
-static void
-update_buttons (Totem *totem)
-{
-	gboolean has_item;
-
-	/* Previous */
-	if (totem_playing_dvd (totem->mrl) != FALSE)
-		has_item = bacon_video_widget_has_previous_track (totem->bvw);
-	else
-		has_item = totem_playlist_has_previous_mrl (totem->playlist);
-
-	totem_action_set_sensitivity ("previous-chapter", has_item);
-
-	/* Next */
-	if (totem_playing_dvd (totem->mrl) != FALSE)
-		has_item = bacon_video_widget_has_next_track (totem->bvw);
-	else
-		has_item = totem_playlist_has_next_mrl (totem->playlist);
-
-	totem_action_set_sensitivity ("next-chapter", has_item);
-}
-
-void
-main_pane_size_allocated (GtkWidget *main_pane, GtkAllocation *allocation, Totem *totem)
-{
-	gulong handler_id;
-
-	if (!totem->maximised || GTK_WIDGET_MAPPED (totem->win)) {
-		handler_id = g_signal_handler_find (main_pane, 
-				G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
-				0, 0, NULL,
-				main_pane_size_allocated, totem);
-		g_signal_handler_disconnect (main_pane, handler_id);
-
-		gtk_paned_set_position (GTK_PANED (main_pane), allocation->width - totem->sidebar_w);
-	}
-}
-
-static char *
-totem_setup_window (Totem *totem)
-{
-	GKeyFile *keyfile;
-	int w, h, i;
-	gboolean show_sidebar;
-	char *filename, *page_id;
-	GError *err = NULL;
-	GtkWidget *vbox;
-	GdkColor black;
-
-	filename = g_build_filename (totem_dot_dir (), "state.ini", NULL);
-	keyfile = g_key_file_new ();
-	if (g_key_file_load_from_file (keyfile, filename,
-			G_KEY_FILE_NONE, NULL) == FALSE) {
-		totem->sidebar_w = 0;
-		w = DEFAULT_WINDOW_W;
-		h = DEFAULT_WINDOW_H;
-		show_sidebar = TRUE;
-		page_id = NULL;
-		g_free (filename);
-	} else {
-		g_free (filename);
-
-		w = g_key_file_get_integer (keyfile, "State", "window_w", &err);
-		if (err != NULL) {
-			w = 0;
-			g_error_free (err);
-			err = NULL;
-		}
-
-		h = g_key_file_get_integer (keyfile, "State", "window_h", &err);
-		if (err != NULL) {
-			h = 0;
-			g_error_free (err);
-			err = NULL;
-		}
-
-		show_sidebar = g_key_file_get_boolean (keyfile, "State",
-				"show_sidebar", &err);
-		if (err != NULL) {
-			show_sidebar = TRUE;
-			g_error_free (err);
-			err = NULL;
-		}
-
-		totem->maximised = g_key_file_get_boolean (keyfile, "State",
-				"maximised", &err);
-		if (err != NULL) {
-			g_error_free (err);
-			err = NULL;
-		}
-
-		page_id = g_key_file_get_string (keyfile, "State",
-				"sidebar_page", &err);
-		if (err != NULL) {
-			g_error_free (err);
-			page_id = NULL;
-			err = NULL;
-		}
-
-		totem->sidebar_w = g_key_file_get_integer (keyfile, "State",
-				"sidebar_w", &err);
-		if (err != NULL) {
-			g_error_free (err);
-			totem->sidebar_w = 0;
-		}
-		g_key_file_free (keyfile);
-	}
-
-	if (w > 0 && h > 0 && totem->maximised == FALSE) {
-		gtk_window_set_default_size (GTK_WINDOW (totem->win),
-				w, h);
-		totem->window_w = w;
-		totem->window_h = h;
-	} else if (totem->maximised != FALSE) {
-		gtk_window_maximize (GTK_WINDOW (totem->win));
-	}
-
-	/* Set the vbox to be completely black */
-	vbox = GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_bvw_box"));
-	gdk_color_parse ("Black", &black);
-	for (i = 0; i <= GTK_STATE_INSENSITIVE; i++)
-		gtk_widget_modify_bg (vbox, i, &black);
-
-	totem_sidebar_setup (totem, show_sidebar, page_id);
-	return page_id;
-}
-
-static void
-totem_callback_connect (Totem *totem)
-{
-	GtkWidget *item, *arrow;
-	GtkAction *action;
-	GtkActionGroup *action_group;
-	GtkBox *box;
-
-	/* Menu items */
-	action = GTK_ACTION (gtk_builder_get_object (totem->xml, "deinterlace"));
-	gtk_action_set_visible (action, bacon_video_widget_can_deinterlace (totem->bvw));
-
-	action = gtk_action_group_get_action (totem->main_action_group, "repeat-mode");
-	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
-		totem_playlist_get_repeat (totem->playlist));
-	action = gtk_action_group_get_action (totem->main_action_group, "shuffle-mode");
-	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
-		totem_playlist_get_shuffle (totem->playlist));
-
-	/* Controls */
-	box = GTK_BOX (gtk_builder_get_object (totem->xml, "tmw_buttons_hbox"));
-
-	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"));
-	gtk_box_pack_start (box, item, FALSE, FALSE, 0);
-
-	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"));
-	gtk_box_pack_start (box, item, FALSE, FALSE, 0);
-
-	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);
-
-	/* 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_action_connect_proxy (action, item);
-	arrow = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
-	g_object_set_data (G_OBJECT (box), "arrow", arrow);
-	gtk_button_set_image_position (GTK_BUTTON (item), GTK_POS_RIGHT);
-	gtk_button_set_image (GTK_BUTTON (item), arrow);
-	gtk_box_pack_start (box, item, FALSE, FALSE, 0);
-	g_signal_connect (G_OBJECT (item), "drag_data_received",
-			G_CALLBACK (drop_playlist_cb), totem);
-	g_signal_connect (G_OBJECT (item), "drag_motion",
-			G_CALLBACK (drag_motion_playlist_cb), totem);
-	gtk_drag_dest_set (item, GTK_DEST_DEFAULT_ALL,
-			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 (totem->win, GDK_SCROLL_MASK);
-	gtk_widget_add_events (totem->seek, GDK_SCROLL_MASK);
-	gtk_widget_add_events (totem->fs->seek, GDK_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);
-	totem_action_set_sensitivity ("next-chapter", FALSE);
-	totem_action_set_sensitivity ("previous-chapter", FALSE);
-	/* 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", FALSE);
-	totem_action_set_sensitivity ("skip-backwards", FALSE);*/
-
-	action_group = GTK_ACTION_GROUP (gtk_builder_get_object (totem->xml, "skip-action-group"));
-
-	action = gtk_action_group_get_action (action_group, "skip-forward");
-	gtk_action_set_sensitive (action, FALSE);
-
-	action = gtk_action_group_get_action (action_group, "skip-backwards");
-	gtk_action_set_sensitive (action, FALSE);
-}
-
-static void
-playlist_widget_setup (Totem *totem)
-{
-	totem->playlist = TOTEM_PLAYLIST (totem_playlist_new ());
-
-	if (totem->playlist == NULL)
-		totem_action_exit (totem);
-
-	gtk_widget_show_all (GTK_WIDGET (totem->playlist));
-
-	g_signal_connect (G_OBJECT (totem->playlist), "active-name-changed",
-			  G_CALLBACK (on_playlist_change_name), totem);
-	g_signal_connect (G_OBJECT (totem->playlist), "item-activated",
-			  G_CALLBACK (item_activated_cb), totem);
-	g_signal_connect (G_OBJECT (totem->playlist),
-			  "changed", G_CALLBACK (playlist_changed_cb),
-			  totem);
-	g_signal_connect (G_OBJECT (totem->playlist),
-			  "current-removed", G_CALLBACK (current_removed_cb),
-			  totem);
-	g_signal_connect (G_OBJECT (totem->playlist),
-			  "repeat-toggled",
-			  G_CALLBACK (playlist_repeat_toggle_cb),
-			  totem);
-	g_signal_connect (G_OBJECT (totem->playlist),
-			  "shuffle-toggled",
-			  G_CALLBACK (playlist_shuffle_toggle_cb),
-			  totem);
-	g_signal_connect (G_OBJECT (totem->playlist),
-			  "subtitle-changed",
-			  G_CALLBACK (subtitle_changed_cb),
-			  totem);
-}
-
-static void
-video_widget_create (Totem *totem) 
-{
-	GError *err = NULL;
-	GtkContainer *container;
-	BaconVideoWidget **bvw;
-	const GtkTargetEntry source_table[] = {
-		{ "text/uri-list", 0, 0 }
-	};
-
-	totem->bvw = BACON_VIDEO_WIDGET
-		(bacon_video_widget_new (-1, -1, BVW_USE_TYPE_VIDEO, &err));
-
-	if (totem->bvw == NULL) {
-		totem_action_error_and_exit (_("Totem could not startup."), err != NULL ? err->message : _("No reason."), totem);
-		if (err != NULL)
-			g_error_free (err);
-	}
-
-	totem_action_zoom (totem, ZOOM_RESET);
-
-	g_signal_connect_after (G_OBJECT (totem->bvw),
-			"button-press-event",
-			G_CALLBACK (on_video_button_press_event),
-			totem);
-	g_signal_connect (G_OBJECT (totem->bvw),
-			"eos",
-			G_CALLBACK (on_eos_event),
-			totem);
-	g_signal_connect (G_OBJECT (totem->bvw),
-			"got-redirect",
-			G_CALLBACK (on_got_redirect),
-			totem);
-	g_signal_connect (G_OBJECT(totem->bvw),
-			"title-change",
-			G_CALLBACK (on_title_change_event),
-			totem);
-	g_signal_connect (G_OBJECT(totem->bvw),
-			"channels-change",
-			G_CALLBACK (on_channels_change_event),
-			totem);
-	g_signal_connect (G_OBJECT (totem->bvw),
-			"tick",
-			G_CALLBACK (update_current_time),
-			totem);
-	g_signal_connect (G_OBJECT (totem->bvw),
-			"got-metadata",
-			G_CALLBACK (on_got_metadata_event),
-			totem);
-	g_signal_connect (G_OBJECT (totem->bvw),
-			"buffering",
-			G_CALLBACK (on_buffering_event),
-			totem);
-	g_signal_connect (G_OBJECT (totem->bvw),
-			"error",
-			G_CALLBACK (on_error_event),
-			totem);
-
-	container = GTK_CONTAINER (gtk_builder_get_object (totem->xml, "tmw_bvw_box"));
-	gtk_container_add (container,
-			GTK_WIDGET (totem->bvw));
-
-	/* Events for the widget video window as well */
-	gtk_widget_add_events (GTK_WIDGET (totem->bvw),
-			GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
-	g_signal_connect (G_OBJECT(totem->bvw), "key_press_event",
-			G_CALLBACK (window_key_press_event_cb), totem);
-	g_signal_connect (G_OBJECT(totem->bvw), "key_release_event",
-			G_CALLBACK (window_key_press_event_cb), totem);
-
-	g_signal_connect (G_OBJECT (totem->bvw), "drag_data_received",
-			G_CALLBACK (drop_video_cb), totem);
-	g_signal_connect (G_OBJECT (totem->bvw), "drag_motion",
-			G_CALLBACK (drag_motion_video_cb), totem);
-	gtk_drag_dest_set (GTK_WIDGET (totem->bvw), GTK_DEST_DEFAULT_ALL,
-			target_table, G_N_ELEMENTS (target_table),
-			GDK_ACTION_COPY | GDK_ACTION_MOVE);
-
-	g_signal_connect (G_OBJECT (totem->bvw), "drag_data_get",
-			G_CALLBACK (drag_video_cb), totem);
-	gtk_drag_source_set (GTK_WIDGET (totem->bvw),
-			GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
-			source_table, G_N_ELEMENTS (source_table),
-			GDK_ACTION_LINK);
-
-	bvw = &(totem->bvw);
-	g_object_add_weak_pointer (G_OBJECT (totem->bvw),
-				   (gpointer *) bvw);
-
-	gtk_widget_realize (GTK_WIDGET (totem->bvw));
-	gtk_widget_show (GTK_WIDGET (totem->bvw));
-
-	totem_preferences_visuals_setup (totem);
-
-	bacon_video_widget_set_volume (totem->bvw,
-			((double) gconf_client_get_int (totem->gc,
-				GCONF_PREFIX"/volume", NULL)) / 100.0);
-	g_signal_connect (G_OBJECT (totem->bvw), "notify::volume",
-			G_CALLBACK (property_notify_cb_volume), totem);
-	g_signal_connect (G_OBJECT (totem->bvw), "notify::logo-mode",
-			G_CALLBACK (property_notify_cb_logo_mode), totem);
-	g_signal_connect (G_OBJECT (totem->bvw), "notify::seekable",
-			G_CALLBACK (property_notify_cb_seekable), totem);
-	update_volume_sliders (totem);
-}
-
-static void
 totem_message_connection_receive_cb (const char *msg, Totem *totem)
 {
 	char *command_str, *url;



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