totem r5948 - in trunk: . src src/plugins
- From: pwithnall svn gnome org
- To: svn-commits-list gnome org
- Subject: totem r5948 - in trunk: . src src/plugins
- Date: Sat, 7 Feb 2009 15:28:03 +0000 (UTC)
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]