~walkerlee/totem/pre-interview

« back to all changes in this revision

Viewing changes to src/totem-object.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2013-05-26 00:07:51 UTC
  • mfrom: (1.6.1) (24.1.4 experimental)
  • Revision ID: package-import@ubuntu.com-20130526000751-kv8ap3x1di4qq8j2
Tags: 3.8.2-0ubuntu1
* Sync with Debian. Remaining changes: 
* debian/control.in:
  - Drop build-depends on libepc-ui-dev and libgrilo-0.2-dev (in universe)
  - Drop libxtst-dev build-depends so that the (redundant) fake key presses
    for inhibiting the screensaver are disabled (LP: #1007438)
  - Build-depend on libzeitgeist-dev
  - Suggest rather than recommend gstreamer components in universe
  - Add totem-plugins-extra
  - Add XB-Npp-Description and XB-Npp-Filename header to the 
    totem-mozilla package to improve ubufox/ubuntu plugin db integration 
  - Refer to Firefox in totem-mozilla description instead of Iceweasel
  - Don't have totem-mozilla recommend any particular browser
  - Drop obsolete python library dependencies since iplayer is no longer
    included
* debian/totem-common.install, debian/source_totem.py:
  - Install Ubuntu apport debugging hook
* debian/totem-plugins-extra.install:
  - Universe plugins split out of totem-plugins (currently only gromit)
* debian/totem-plugins.install:    
  - Skip the plugins split to -extra and add the zeitgeist plugin
* debian/rules:
  - Build with --fail-missing, to ensure we install everything. 
    + Ignore libtotem.{,l}a since we delibrately don't install these.
  - Re-enable hardening, make sure both PIE and BINDNOW are used
    by setting hardening=+all. (LP: #1039604)
* debian/patches/91_quicklist_entries.patch:
  - Add static quicklist
* debian/patches/92_gst-plugins-good.patch:
  - Build without unnecessary gstreamer1.0-bad dependency
* debian/patches/93_grilo_optional.patch:
  - Allow building without grilo while grilo MIR is still pending
* debian/patches/correct_desktop_mimetypes.patch:
  - Don't list the mimetypes after the unity lists
* debian/patches/revert_shell_menu.patch: 
  - revert the use of a shell menu until indicator-appmenu can handle
    the mixed shell/traditional menus itself
* New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
41
41
#include <gtk/gtk.h>
42
42
#include <glib/gi18n.h>
43
43
#include <gdk/gdkkeysyms.h>
44
 
#include <totem-disc.h>
45
44
#include <stdlib.h>
46
45
#include <math.h>
47
46
#include <gio/gio.h>
48
47
 
49
48
#include <string.h>
50
49
 
51
 
#ifdef GDK_WINDOWING_X11
52
 
/* X11 headers */
53
 
#include <gdk/gdkx.h>
54
 
#include <X11/Xlib.h>
55
 
#endif
56
 
 
57
50
#include "totem.h"
58
 
#include "totemobject-marshal.h"
59
51
#include "totem-private.h"
 
52
#include "totem-options.h"
60
53
#include "totem-plugins-engine.h"
61
54
#include "totem-playlist.h"
62
55
#include "bacon-video-widget.h"
93
86
};
94
87
 
95
88
static gboolean totem_action_open_files_list (TotemObject *totem, GSList *list);
96
 
static gboolean totem_action_load_media (TotemObject *totem, TotemDiscMediaType type, const char *device);
97
89
static void update_buttons (TotemObject *totem);
98
90
static void update_fill (TotemObject *totem, gdouble level);
99
91
static void update_media_menu_items (TotemObject *totem);
108
100
G_MODULE_EXPORT gboolean seek_slider_released_cb (GtkWidget *widget, GdkEventButton *event, TotemObject *totem);
109
101
G_MODULE_EXPORT void volume_button_value_changed_cb (GtkScaleButton *button, gdouble value, TotemObject *totem);
110
102
G_MODULE_EXPORT gboolean window_key_press_event_cb (GtkWidget *win, GdkEventKey *event, TotemObject *totem);
111
 
G_MODULE_EXPORT int window_scroll_event_cb (GtkWidget *win, GdkEventScroll *event, TotemObject *totem);
 
103
G_MODULE_EXPORT int window_scroll_event_cb (GtkWidget *win, GdkEvent *event, TotemObject *totem);
112
104
G_MODULE_EXPORT void main_pane_size_allocated (GtkWidget *main_pane, GtkAllocation *allocation, TotemObject *totem);
113
105
G_MODULE_EXPORT void fs_exit1_activate_cb (GtkButton *button, TotemObject *totem);
114
106
 
120
112
        PROP_SEEKABLE,
121
113
        PROP_CURRENT_TIME,
122
114
        PROP_CURRENT_MRL,
123
 
        PROP_AUTOLOAD_SUBTITLES,
 
115
        PROP_CURRENT_CONTENT_TYPE,
 
116
        PROP_CURRENT_DISPLAY_NAME,
124
117
        PROP_REMEMBER_POSITION
125
118
};
126
119
 
127
120
enum {
128
121
        FILE_OPENED,
129
122
        FILE_CLOSED,
 
123
        FILE_HAS_PLAYED,
130
124
        METADATA_UPDATED,
 
125
        GET_USER_AGENT,
 
126
        GET_TEXT_SUBTITLE,
131
127
        LAST_SIGNAL
132
128
};
133
129
 
143
139
 
144
140
static int totem_table_signals[LAST_SIGNAL] = { 0 };
145
141
 
146
 
G_DEFINE_TYPE(TotemObject, totem_object, G_TYPE_OBJECT)
 
142
G_DEFINE_TYPE(TotemObject, totem_object, GTK_TYPE_APPLICATION)
 
143
 
 
144
static gboolean
 
145
totem_object_local_command_line (GApplication              *application,
 
146
                                 gchar                   ***arguments,
 
147
                                 int                       *exit_status)
 
148
{
 
149
        GOptionContext *context;
 
150
        GError *error = NULL;
 
151
        char **argv;
 
152
        int argc;
 
153
 
 
154
        /* Dupe so that the remote arguments are listed, but
 
155
         * not removed from the list */
 
156
        argv = g_strdupv (*arguments);
 
157
        argc = g_strv_length (argv);
 
158
 
 
159
        context = totem_options_get_context ();
 
160
        if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) {
 
161
                g_print (_("%s\nRun '%s --help' to see a full list of available command line options.\n"),
 
162
                                error->message, argv[0]);
 
163
                g_error_free (error);
 
164
                *exit_status = 1;
 
165
                goto bail;
 
166
        }
 
167
 
 
168
        /* Replace relative paths with absolute URIs */
 
169
        if (optionstate.filenames != NULL) {
 
170
                guint n_files;
 
171
                int i, n_args;
 
172
 
 
173
                n_args = g_strv_length (*arguments);
 
174
                n_files = g_strv_length (optionstate.filenames);
 
175
 
 
176
                i = n_args - n_files;
 
177
                for ( ; i < n_args; i++) {
 
178
                        char *new_path;
 
179
 
 
180
                        new_path = totem_create_full_path ((*arguments)[i]);
 
181
                        if (new_path == NULL)
 
182
                                continue;
 
183
 
 
184
                        g_free ((*arguments)[i]);
 
185
                        (*arguments)[i] = new_path;
 
186
                }
 
187
        }
 
188
 
 
189
        g_strfreev (optionstate.filenames);
 
190
        optionstate.filenames = NULL;
 
191
 
 
192
        *exit_status = 0;
 
193
bail:
 
194
        g_option_context_free (context);
 
195
        g_strfreev (argv);
 
196
 
 
197
        return FALSE;
 
198
}
 
199
 
 
200
static gboolean
 
201
accumulator_first_non_null_wins (GSignalInvocationHint *ihint,
 
202
                                 GValue *return_accu,
 
203
                                 const GValue *handler_return,
 
204
                                 gpointer data)
 
205
{
 
206
        const gchar *str;
 
207
 
 
208
        str = g_value_get_string (handler_return);
 
209
        if (str == NULL)
 
210
                return TRUE;
 
211
        g_value_set_string (return_accu, str);
 
212
 
 
213
        return FALSE;
 
214
}
147
215
 
148
216
static void
149
217
totem_object_class_init (TotemObjectClass *klass)
150
218
{
151
219
        GObjectClass *object_class;
 
220
        GApplicationClass *app_class;
152
221
 
153
222
        object_class = (GObjectClass *) klass;
 
223
        app_class = (GApplicationClass *) klass;
154
224
 
155
225
        object_class->set_property = totem_object_set_property;
156
226
        object_class->get_property = totem_object_get_property;
157
227
        object_class->finalize = totem_object_finalize;
158
228
 
 
229
        app_class->local_command_line = totem_object_local_command_line;
 
230
 
159
231
        /**
160
232
         * TotemObject:fullscreen:
161
233
         *
213
285
                                                              NULL, G_PARAM_READABLE));
214
286
 
215
287
        /**
216
 
         * TotemObject:autoload-subtitles:
217
 
         *
218
 
         * If %TRUE, Totem will automatically load any subtitle files it finds for each newly opened video.
219
 
         **/
220
 
        g_object_class_install_property (object_class, PROP_AUTOLOAD_SUBTITLES,
221
 
                                         g_param_spec_boolean ("autoload-subtitles", "Autoload subtitles?",
222
 
                                                               "Whether to automatically load any subtitle files Totem finds.",
223
 
                                                               FALSE, G_PARAM_READWRITE));
 
288
         * TotemObject:current-content-type:
 
289
         *
 
290
         * The content-type of the current stream.
 
291
         **/
 
292
        g_object_class_install_property (object_class, PROP_CURRENT_CONTENT_TYPE,
 
293
                                         g_param_spec_string ("current-content-type",
 
294
                                                              "Current stream's content-type",
 
295
                                                              "Current stream's content-type.",
 
296
                                                              NULL, G_PARAM_READABLE));
 
297
 
 
298
        /**
 
299
         * TotemObject:current-display-name:
 
300
         *
 
301
         * The display name of the current stream.
 
302
         **/
 
303
        g_object_class_install_property (object_class, PROP_CURRENT_DISPLAY_NAME,
 
304
                                         g_param_spec_string ("current-display-name",
 
305
                                                              "Current stream's display name",
 
306
                                                              "Current stream's display name.",
 
307
                                                              NULL, G_PARAM_READABLE));
224
308
 
225
309
        /**
226
310
         * TotemObject:remember-position:
249
333
                                G_TYPE_NONE, 1, G_TYPE_STRING);
250
334
 
251
335
        /**
 
336
         * TotemObject::file-has-played:
 
337
         * @totem: the #TotemObject which received the signal
 
338
         * @mrl: the MRL of the opened stream
 
339
         *
 
340
         * The #TotemObject::file-has-played signal is emitted when a new stream has started playing in Totem.
 
341
         */
 
342
        totem_table_signals[FILE_HAS_PLAYED] =
 
343
                g_signal_new ("file-has-played",
 
344
                                G_TYPE_FROM_CLASS (object_class),
 
345
                                G_SIGNAL_RUN_LAST,
 
346
                                G_STRUCT_OFFSET (TotemObjectClass, file_has_played),
 
347
                                NULL, NULL,
 
348
                                g_cclosure_marshal_VOID__STRING,
 
349
                                G_TYPE_NONE, 1, G_TYPE_STRING);
 
350
 
 
351
        /**
252
352
         * TotemObject::file-closed:
253
353
         * @totem: the #TotemObject which received the signal
254
354
         *
280
380
                                G_SIGNAL_RUN_LAST,
281
381
                                G_STRUCT_OFFSET (TotemObjectClass, metadata_updated),
282
382
                                NULL, NULL,
283
 
                                totemobject_marshal_VOID__STRING_STRING_STRING_UINT,
 
383
                                g_cclosure_marshal_generic,
284
384
                                G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT);
 
385
 
 
386
        /**
 
387
         * TotemObject::get-user-agent:
 
388
         * @totem: the #TotemObject which received the signal
 
389
         * @mrl: the MRL of the opened stream
 
390
         *
 
391
         * The #TotemObject::get-user-agent signal is emitted before opening a stream, so that plugins
 
392
         * have the opportunity to return the user-agent to be set.
 
393
         *
 
394
         * Return value: allocated string representing the user-agent to use for @mrl
 
395
         */
 
396
        totem_table_signals[GET_USER_AGENT] =
 
397
                g_signal_new ("get-user-agent",
 
398
                              G_TYPE_FROM_CLASS (object_class),
 
399
                              G_SIGNAL_RUN_LAST,
 
400
                              G_STRUCT_OFFSET (TotemObjectClass, get_user_agent),
 
401
                              accumulator_first_non_null_wins, NULL,
 
402
                              g_cclosure_marshal_generic,
 
403
                              G_TYPE_STRING, 1, G_TYPE_STRING);
 
404
 
 
405
        /**
 
406
         * TotemObject::get-text-subtitle:
 
407
         * @totem: the #TotemObject which received the signal
 
408
         * @mrl: the MRL of the opened stream
 
409
         *
 
410
         * The #TotemObject::get-text-subtitle signal is emitted before opening a stream, so that plugins
 
411
         * have the opportunity to detect or download text subtitles for the stream if necessary.
 
412
         *
 
413
         * Return value: allocated string representing the URI of the subtitle to use for @mrl
 
414
         */
 
415
        totem_table_signals[GET_TEXT_SUBTITLE] =
 
416
                g_signal_new ("get-text-subtitle",
 
417
                              G_TYPE_FROM_CLASS (object_class),
 
418
                              G_SIGNAL_RUN_LAST,
 
419
                              G_STRUCT_OFFSET (TotemObjectClass, get_text_subtitle),
 
420
                              accumulator_first_non_null_wins, NULL,
 
421
                              g_cclosure_marshal_generic,
 
422
                              G_TYPE_STRING, 1, G_TYPE_STRING);
285
423
}
286
424
 
287
425
static void
306
444
        TotemObject *totem = TOTEM_OBJECT (object);
307
445
 
308
446
        switch (property_id) {
309
 
                case PROP_AUTOLOAD_SUBTITLES:
310
 
                        totem->autoload_subs = g_value_get_boolean (value);
311
 
                        g_object_notify (object, "autoload-subtitles");
312
 
                        break;
313
447
                case PROP_REMEMBER_POSITION:
314
448
                        totem->remember_position = g_value_get_boolean (value);
315
 
                        g_object_notify (object, "remember-position");
316
449
                        break;
317
450
                default:
318
451
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
349
482
        case PROP_CURRENT_MRL:
350
483
                g_value_set_string (value, totem->mrl);
351
484
                break;
352
 
        case PROP_AUTOLOAD_SUBTITLES:
353
 
                g_value_set_boolean (value, totem->autoload_subs);
 
485
        case PROP_CURRENT_CONTENT_TYPE:
 
486
                g_value_take_string (value, totem_playlist_get_current_content_type (totem->playlist));
 
487
                break;
 
488
        case PROP_CURRENT_DISPLAY_NAME:
 
489
                g_value_take_string (value, totem_playlist_get_current_title (totem->playlist));
354
490
                break;
355
491
        case PROP_REMEMBER_POSITION:
356
492
                g_value_set_boolean (value, totem->remember_position);
384
520
void
385
521
totem_object_plugins_shutdown (TotemObject *totem)
386
522
{
387
 
        if (totem->engine != NULL) {
388
 
                g_object_unref (totem->engine);
389
 
                totem->engine = NULL;
390
 
        }
 
523
        g_clear_object (&totem->engine);
391
524
}
392
525
 
393
526
/**
425
558
}
426
559
 
427
560
/**
428
 
 * totem_get_video_widget:
 
561
 * totem_object_get_video_widget:
429
562
 * @totem: a #TotemObject
430
563
 *
431
564
 * Gets Totem's video widget and increments its reference count.
433
566
 * Return value: (transfer full): Totem's video widget
434
567
 **/
435
568
GtkWidget *
436
 
totem_get_video_widget (TotemObject *totem)
 
569
totem_object_get_video_widget (TotemObject *totem)
437
570
{
438
571
        g_return_val_if_fail (TOTEM_IS_OBJECT (totem), NULL);
439
572
 
443
576
}
444
577
 
445
578
/**
446
 
 * totem_get_video_widget_backend_name:
447
 
 * @totem: a #TotemObject
448
 
 *
449
 
 * Gets the name string of the backend video widget, typically the video library's
450
 
 * version string (e.g. what's returned by gst_version_string()). Free with g_free().
451
 
 *
452
 
 * Return value: a newly-allocated string of the name of the backend video widget
453
 
 **/
454
 
char *
455
 
totem_get_video_widget_backend_name (TotemObject *totem)
456
 
{
457
 
        return bacon_video_widget_get_backend_name (totem->bvw);
458
 
}
459
 
 
460
 
/**
461
579
 * totem_object_get_version:
462
580
 *
463
581
 * Gets the application name and version (e.g. "Totem 2.28.0").
491
609
        TotemObject *totem;
492
610
        gchar *uri;
493
611
        gchar *display_name;
494
 
        gboolean add_to_recent;
495
612
} AddToPlaylistData;
496
613
 
497
614
static void
502
619
 
503
620
        playlist_changed = totem_playlist_add_mrl_finish (playlist, async_result);
504
621
 
505
 
        if (data->add_to_recent != FALSE)
506
 
                totem_action_add_recent (data->totem, data->uri, data->display_name, NULL);
507
622
        end = totem_playlist_get_last (playlist);
508
623
 
509
624
        totem_signal_unblock_by_data (playlist, data->totem);
531
646
 * @totem: a #TotemObject
532
647
 * @uri: the URI to add to the playlist
533
648
 * @display_name: the display name of the URI
534
 
 * @add_to_recent: if %TRUE, add the URI to the recent items list
535
649
 *
536
650
 * Add @uri to the playlist and play it immediately.
537
651
 **/
538
652
void
539
653
totem_object_add_to_playlist_and_play (TotemObject *totem,
540
654
                                const char *uri,
541
 
                                const char *display_name,
542
 
                                gboolean add_to_recent)
 
655
                                const char *display_name)
543
656
{
544
657
        AddToPlaylistData *data;
545
658
 
552
665
        data->totem = g_object_ref (totem);
553
666
        data->uri = g_strdup (uri);
554
667
        data->display_name = g_strdup (display_name);
555
 
        data->add_to_recent = add_to_recent;
556
668
 
557
669
        totem_playlist_add_mrl (totem->playlist, uri, display_name, TRUE,
558
670
                                NULL, (GAsyncReadyCallback) add_to_playlist_and_play_cb, data);
633
745
char *
634
746
totem_get_short_title (TotemObject *totem)
635
747
{
636
 
        return totem_playlist_get_current_title (totem->playlist, NULL);
 
748
        return totem_playlist_get_current_title (totem->playlist);
637
749
}
638
750
 
639
751
/**
723
835
}
724
836
 
725
837
/**
 
838
 * totem_file_has_played:
 
839
 * @totem: a #TotemObject
 
840
 *
 
841
 * Emits the #TotemObject::file-played signal on @totem.
 
842
 **/
 
843
void
 
844
totem_file_has_played (TotemObject *totem,
 
845
                       const char  *mrl)
 
846
{
 
847
        g_signal_emit (G_OBJECT (totem),
 
848
                       totem_table_signals[FILE_HAS_PLAYED],
 
849
                       0, mrl);
 
850
}
 
851
 
 
852
/**
726
853
 * totem_metadata_updated:
727
854
 * @totem: a #TotemObject
728
855
 * @artist: the stream's artist, or %NULL
960
1087
                totem_object_plugins_shutdown (totem);
961
1088
 
962
1089
        /* Exit forcefully if we can't do the shutdown in 10 seconds */
963
 
#if GLIB_CHECK_VERSION (2, 31, 0)
964
1090
        g_thread_new ("force-exit", (GThreadFunc) totem_action_wait_force_exit, NULL);
965
 
#else
966
 
        g_thread_create ((GThreadFunc) totem_action_wait_force_exit,
967
 
                         NULL, FALSE, NULL);
968
 
#endif
969
1091
 
970
1092
        if (gtk_main_level () > 0)
971
1093
                gtk_main_quit ();
973
1095
        if (totem == NULL)
974
1096
                exit (0);
975
1097
 
 
1098
        if (totem->bvw)
 
1099
                totem_action_save_size (totem);
 
1100
 
976
1101
        if (totem->win != NULL) {
977
1102
                gtk_widget_hide (totem->win);
978
1103
                display = gtk_widget_get_display (totem->win);
985
1110
                gdk_display_sync (display);
986
1111
 
987
1112
        if (totem->bvw) {
988
 
                totem_action_save_size (totem);
989
1113
                totem_save_position (totem);
990
1114
                bacon_video_widget_close (totem->bvw);
991
1115
        }
992
1116
 
993
 
        if (totem->app != NULL)
994
 
                g_object_unref (totem->app);
995
1117
        totem_action_save_state (totem, page_id);
996
1118
        g_free (page_id);
997
1119
 
998
1120
        totem_sublang_exit (totem);
999
1121
        totem_destroy_file_filters ();
1000
1122
 
1001
 
        if (totem->settings)
1002
 
                g_object_unref (totem->settings);
1003
 
 
1004
 
        if (totem->fs)
1005
 
                g_object_unref (totem->fs);
 
1123
        g_clear_object (&totem->settings);
 
1124
        g_clear_object (&totem->fs);
1006
1125
 
1007
1126
        if (totem->win)
1008
1127
                gtk_widget_destroy (GTK_WIDGET (totem->win));
1099
1218
        totem->mrl = NULL;
1100
1219
        bacon_video_widget_close (totem->bvw);
1101
1220
        totem_file_closed (totem);
 
1221
        totem->has_played_emitted = FALSE;
1102
1222
 
1103
1223
        /* The volume monitoring will take care of removing the items */
1104
1224
        g_mount_eject_with_operation (mount, G_MOUNT_UNMOUNT_NONE, NULL, NULL, NULL, NULL);
1135
1255
        retval = bacon_video_widget_play (totem->bvw,  &err);
1136
1256
        play_pause_set_label (totem, retval ? STATE_PLAYING : STATE_STOPPED);
1137
1257
 
1138
 
        if (retval != FALSE)
 
1258
        if (retval != FALSE) {
 
1259
                if (totem->has_played_emitted == FALSE) {
 
1260
                        totem_file_has_played (totem, totem->mrl);
 
1261
                        totem->has_played_emitted = TRUE;
 
1262
                }
1139
1263
                return;
 
1264
        }
1140
1265
 
1141
1266
        disp = totem_uri_escape_for_display (totem->mrl);
1142
1267
        msg = g_strdup_printf(_("Totem could not play '%s'."), disp);
1229
1354
        return TRUE;
1230
1355
}
1231
1356
 
1232
 
static gboolean
1233
 
totem_action_load_media (TotemObject *totem, TotemDiscMediaType type, const char *device)
1234
 
{
1235
 
        char **mrls;
1236
 
        GError *error = NULL;
1237
 
        const char *uri, *link_text, *secondary;
1238
 
        gboolean retval;
1239
 
 
1240
 
        mrls = bacon_video_widget_get_mrls (totem->bvw, type, device, &error);
1241
 
        if (mrls == NULL) {
1242
 
                char *msg;
1243
 
 
1244
 
                /* No errors? Weird */
1245
 
                if (error == NULL) {
1246
 
                        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)));
1247
 
                        totem_action_error (totem, msg, _("You might want to check that a disc is present in the drive and that it is correctly configured."));
1248
 
                        g_free (msg);
1249
 
                        return FALSE;
1250
 
                }
1251
 
 
1252
 
                /* No plugin for the media type */
1253
 
                if (g_error_matches (error, BVW_ERROR, BVW_ERROR_NO_PLUGIN_FOR_FILE) != FALSE) {
1254
 
                        uri = "http://projects.gnome.org/totem/#codecs";
1255
 
                        link_text = _("More information about media plugins");
1256
 
                        secondary = _("Please install the necessary plugins and restart Totem to be able to play this media.");
1257
 
                        if (type == MEDIA_TYPE_DVD || type == MEDIA_TYPE_VCD)
1258
 
                                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)));
1259
 
                        else
1260
 
                                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)));
1261
 
                /* Unsupported type (ie. CDDA) */
1262
 
                } else if (g_error_matches (error, BVW_ERROR, BVW_ERROR_INVALID_LOCATION) != FALSE) {
1263
 
                        msg = g_strdup_printf(_("Totem cannot play this type of media (%s) because it is not supported."), _(totem_cd_get_human_readable_name (type)));
1264
 
                        totem_action_error (totem, msg, _("Please insert another disc to play back."));
1265
 
                        g_free (msg);
1266
 
                        return FALSE;
1267
 
                } else {
1268
 
                        g_assert_not_reached ();
1269
 
                }
1270
 
 
1271
 
                totem_interface_error_with_link (msg, secondary, uri, link_text, GTK_WINDOW (totem->win));
1272
 
                g_free (msg);
1273
 
                return FALSE;
1274
 
        }
1275
 
 
1276
 
        retval = totem_action_open_files (totem, mrls);
1277
 
        g_strfreev (mrls);
1278
 
 
1279
 
        return retval;
1280
 
}
1281
 
 
1282
 
static gboolean
1283
 
totem_action_load_media_device (TotemObject *totem, const char *device)
1284
 
{
1285
 
        TotemDiscMediaType type;
1286
 
        GError *error = NULL;
1287
 
        char *device_path, *url;
1288
 
        gboolean retval;
1289
 
 
1290
 
        if (g_str_has_prefix (device, "file://") != FALSE)
1291
 
                device_path = g_filename_from_uri (device, NULL, NULL);
1292
 
        else
1293
 
                device_path = g_strdup (device);
1294
 
 
1295
 
        type = totem_cd_detect_type_with_url (device_path, &url, &error);
1296
 
 
1297
 
        switch (type) {
1298
 
                case MEDIA_TYPE_ERROR:
1299
 
                        totem_action_error (totem,
1300
 
                                            _("Totem was not able to play this disc."),
1301
 
                                            error ? error->message : _("No reason."));
1302
 
                        retval = FALSE;
1303
 
                        break;
1304
 
                case MEDIA_TYPE_DATA:
1305
 
                        /* Set default location to the mountpoint of
1306
 
                         * this device */
1307
 
                        retval = totem_action_open_dialog (totem, url, FALSE);
1308
 
                        break;
1309
 
                case MEDIA_TYPE_DVD:
1310
 
                case MEDIA_TYPE_VCD:
1311
 
                        retval = totem_action_load_media (totem, type, device_path);
1312
 
                        break;
1313
 
                case MEDIA_TYPE_CDDA:
1314
 
                        totem_action_error (totem,
1315
 
                                            _("Totem does not support playback of Audio CDs"),
1316
 
                                            _("Please consider using a music player or a CD extractor to play this CD"));
1317
 
                        retval = FALSE;
1318
 
                        break;
1319
 
                case MEDIA_TYPE_DVB:
1320
 
                default:
1321
 
                        g_assert_not_reached ();
1322
 
        }
1323
 
 
1324
 
        g_free (url);
1325
 
        g_free (device_path);
1326
 
 
1327
 
        return retval;
1328
 
}
1329
 
 
1330
 
/**
1331
 
 * totem_action_play_media_device:
1332
 
 * @totem: a #TotemObject
1333
 
 * @device: the media device's path
1334
 
 *
1335
 
 * Attempts to play the media device (for example, a DVD drive or CD drive)
1336
 
 * with the given @device path by first adding it to the playlist, then
1337
 
 * playing it.
1338
 
 *
1339
 
 * An error dialog will be displayed if Totem cannot read or play what's on
1340
 
 * the media device.
1341
 
 **/
1342
 
void
1343
 
totem_action_play_media_device (TotemObject *totem, const char *device)
1344
 
{
1345
 
        char *mrl;
1346
 
 
1347
 
        if (totem_action_load_media_device (totem, device) != FALSE) {
1348
 
                mrl = totem_playlist_get_current_mrl (totem->playlist, NULL);
1349
 
                totem_action_set_mrl_and_play (totem, mrl, NULL);
1350
 
                g_free (mrl);
1351
 
        }
1352
 
}
1353
 
 
1354
 
/**
1355
 
 * totem_action_play_media:
1356
 
 * @totem: a #TotemObject
1357
 
 * @type: the type of disc media
1358
 
 * @device: the media's device path
1359
 
 *
1360
 
 * Attempts to play the media found on @device (for example, a DVD in a drive or a DVB
1361
 
 * tuner) by first adding it to the playlist, then playing it.
1362
 
 *
1363
 
 * An error dialog will be displayed if Totem cannot support media of @type.
1364
 
 **/
1365
 
void
1366
 
totem_action_play_media (TotemObject *totem, TotemDiscMediaType type, const char *device)
1367
 
{
1368
 
        char *mrl;
1369
 
 
1370
 
        if (totem_action_load_media (totem, type, device) != FALSE) {
1371
 
                mrl = totem_playlist_get_current_mrl (totem->playlist, NULL);
1372
 
                totem_action_set_mrl_and_play (totem, mrl, NULL);
1373
 
                g_free (mrl);
1374
 
        }
1375
 
}
1376
 
 
1377
1357
/**
1378
1358
 * totem_object_action_stop:
1379
1359
 * @totem: a #TotemObject
1414
1394
        }
1415
1395
 
1416
1396
        if (bacon_video_widget_is_playing (totem->bvw) == FALSE) {
1417
 
                bacon_video_widget_play (totem->bvw, NULL);
 
1397
                if (bacon_video_widget_play (totem->bvw, NULL) != FALSE &&
 
1398
                    totem->has_played_emitted == FALSE) {
 
1399
                        totem_file_has_played (totem, totem->mrl);
 
1400
                        totem->has_played_emitted = TRUE;
 
1401
                }
1418
1402
                play_pause_set_label (totem, STATE_PLAYING);
1419
1403
        } else {
1420
1404
                bacon_video_widget_pause (totem->bvw);
1664
1648
                totem_fullscreen_set_title (totem->fs, NULL);
1665
1649
 
1666
1650
                /* Title */
1667
 
                gtk_window_set_title (GTK_WINDOW (totem->win), _("Movie Player"));
 
1651
                gtk_window_set_title (GTK_WINDOW (totem->win), _("Videos"));
1668
1652
        }
1669
1653
}
1670
1654
 
1695
1679
        gboolean retval = TRUE;
1696
1680
 
1697
1681
        if (totem->mrl != NULL) {
 
1682
                totem->seek_to = 0;
 
1683
                totem->seek_to_start = 0;
 
1684
 
1698
1685
                totem_save_position (totem);
1699
1686
                g_free (totem->mrl);
1700
1687
                totem->mrl = NULL;
1701
1688
                bacon_video_widget_close (totem->bvw);
1702
1689
                totem_file_closed (totem);
 
1690
                totem->has_played_emitted = FALSE;
1703
1691
                play_pause_set_label (totem, STATE_STOPPED);
1704
1692
                update_fill (totem, -1.0);
1705
1693
        }
1744
1732
        } else {
1745
1733
                gboolean caps;
1746
1734
                gdouble volume;
1747
 
                char *autoload_sub = NULL;
 
1735
                char *user_agent;
 
1736
                char *autoload_sub;
1748
1737
                GdkWindowState window_state;
1749
1738
                GError *err = NULL;
1750
1739
 
1751
1740
                bacon_video_widget_set_logo_mode (totem->bvw, FALSE);
1752
1741
 
1753
 
                if (subtitle == NULL && totem->autoload_subs != FALSE)
1754
 
                        autoload_sub = totem_uri_get_subtitle_uri (mrl);
 
1742
                autoload_sub = NULL;
 
1743
                if (subtitle == NULL)
 
1744
                        g_signal_emit (G_OBJECT (totem), totem_table_signals[GET_TEXT_SUBTITLE], 0, mrl, &autoload_sub);
1755
1745
 
1756
 
                /* HACK: Bad bad Apple */
1757
 
                if (g_str_has_prefix (mrl, "http://movies.apple.com")
1758
 
                                || g_str_has_prefix (mrl, "http://trailers.apple.com"))
1759
 
                        bacon_video_widget_set_user_agent (totem->bvw, "Quicktime/7.2.0");
1760
 
                else
1761
 
                        bacon_video_widget_set_user_agent (totem->bvw, NULL);
 
1746
                user_agent = NULL;
 
1747
                g_signal_emit (G_OBJECT (totem), totem_table_signals[GET_USER_AGENT], 0, mrl, &user_agent);
 
1748
                bacon_video_widget_set_user_agent (totem->bvw, user_agent);
 
1749
                g_free (user_agent);
1762
1750
 
1763
1751
                totem_gdk_window_set_waiting_cursor (gtk_widget_get_window (totem->win));
1764
1752
                totem_try_restore_position (totem, mrl);
1765
 
                retval = bacon_video_widget_open (totem->bvw, mrl, subtitle ? subtitle : autoload_sub, &err);
 
1753
                retval = bacon_video_widget_open (totem->bvw, mrl, &err);
 
1754
                bacon_video_widget_set_text_subtitle (totem->bvw, subtitle ? subtitle : autoload_sub);
1766
1755
                g_free (autoload_sub);
1767
1756
                gdk_window_set_cursor (gtk_widget_get_window (totem->win), NULL);
1768
1757
                totem->mrl = g_strdup (mrl);
1814
1803
                        totem->mrl = NULL;
1815
1804
                        bacon_video_widget_set_logo_mode (totem->bvw, TRUE);
1816
1805
                } else {
1817
 
                        char *display_name, *content_type;
1818
1806
                        /* cast is to shut gcc up */
1819
1807
                        const GtkTargetEntry source_table[] = {
1820
1808
                                { (gchar*) "text/uri-list", 0, 0 }
1827
1815
                                             GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
1828
1816
                                             source_table, G_N_ELEMENTS (source_table),
1829
1817
                                             GDK_ACTION_COPY);
1830
 
 
1831
 
                        display_name = totem_playlist_get_current_title (totem->playlist, &content_type);
1832
 
                        totem_action_add_recent (totem, totem->mrl, display_name, content_type);
1833
 
                        g_free (display_name);
1834
 
                        g_free (content_type);
1835
1818
                }
1836
1819
        }
1837
1820
        update_buttons (totem);
1870
1853
static void
1871
1854
totem_action_direction (TotemObject *totem, TotemPlaylistDirection dir)
1872
1855
{
1873
 
        if (totem_playing_dvd (totem->mrl) == FALSE &&
1874
 
                totem_playlist_has_direction (totem->playlist, dir) == FALSE
1875
 
                && totem_playlist_get_repeat (totem->playlist) == FALSE)
 
1856
        if (bacon_video_widget_has_next_track (totem->bvw) == FALSE &&
 
1857
            totem_playlist_has_direction (totem->playlist, dir) == FALSE &&
 
1858
            totem_playlist_get_repeat (totem->playlist) == FALSE)
1876
1859
                return;
1877
1860
 
1878
 
        if (totem_playing_dvd (totem->mrl) != FALSE)
1879
 
        {
1880
 
                bacon_video_widget_dvd_event (totem->bvw,
1881
 
                                dir == TOTEM_PLAYLIST_DIRECTION_NEXT ?
1882
 
                                BVW_DVD_NEXT_CHAPTER :
1883
 
                                BVW_DVD_PREV_CHAPTER);
 
1861
        if (bacon_video_widget_has_next_track (totem->bvw) != FALSE) {
 
1862
                BvwDVDEvent event;
 
1863
                event = (dir == TOTEM_PLAYLIST_DIRECTION_NEXT ? BVW_DVD_NEXT_CHAPTER : BVW_DVD_PREV_CHAPTER);
 
1864
                bacon_video_widget_dvd_event (totem->bvw, event);
1884
1865
                return;
1885
1866
        }
1886
 
        
1887
 
        if (dir == TOTEM_PLAYLIST_DIRECTION_NEXT
1888
 
                        || bacon_video_widget_is_seekable (totem->bvw) == FALSE
1889
 
                        || totem_time_within_seconds (totem) != FALSE)
1890
 
        {
 
1867
 
 
1868
        if (dir == TOTEM_PLAYLIST_DIRECTION_NEXT ||
 
1869
            bacon_video_widget_is_seekable (totem->bvw) == FALSE ||
 
1870
            totem_time_within_seconds (totem) != FALSE) {
1891
1871
                char *mrl, *subtitle;
1892
1872
 
1893
1873
                totem_playlist_set_direction (totem->playlist, dir);
2150
2130
{
2151
2131
        GError *error = NULL;
2152
2132
 
2153
 
        if (gtk_show_uri (gtk_widget_get_screen (totem->win), "ghelp:totem", gtk_get_current_event_time (), &error) == FALSE) {
 
2133
        if (gtk_show_uri (gtk_widget_get_screen (totem->win), "help:totem", gtk_get_current_event_time (), &error) == FALSE) {
2154
2134
                totem_action_error (totem, _("Totem could not display the help contents."), error->message);
2155
2135
                g_error_free (error);
2156
2136
        }
2422
2402
 
2423
2403
        bacon_video_widget_close (totem->bvw);
2424
2404
        totem_file_closed (totem);
 
2405
        totem->has_played_emitted = FALSE;
2425
2406
        totem_gdk_window_set_waiting_cursor (gtk_widget_get_window (totem->win));
2426
 
        bacon_video_widget_open (totem->bvw, new_mrl ? new_mrl : mrl, NULL, NULL);
 
2407
        bacon_video_widget_open (totem->bvw, new_mrl ? new_mrl : mrl, NULL);
2427
2408
        totem_file_opened (totem, new_mrl ? new_mrl : mrl);
2428
2409
        gdk_window_set_cursor (gtk_widget_get_window (totem->win), NULL);
2429
 
        bacon_video_widget_play (bvw, NULL);
 
2410
        if (bacon_video_widget_play (bvw, NULL) != FALSE) {
 
2411
                totem_file_has_played (totem, totem->mrl);
 
2412
                totem->has_played_emitted = TRUE;
 
2413
        }
2430
2414
        g_free (new_mrl);
2431
2415
}
2432
2416
 
2454
2438
{
2455
2439
        char *name;
2456
2440
 
2457
 
        name = totem_playlist_get_current_title (playlist, NULL);
 
2441
        name = totem_playlist_get_current_title (playlist);
2458
2442
        if (name != NULL) {
2459
2443
                update_mrl_label (totem, name);
2460
2444
                g_free (name);
2479
2463
 
2480
2464
static void
2481
2465
on_error_event (BaconVideoWidget *bvw, char *message,
2482
 
                gboolean playback_stopped, gboolean fatal, TotemObject *totem)
 
2466
                gboolean playback_stopped, TotemObject *totem)
2483
2467
{
2484
2468
        /* Clear the seek if it's there, we only want to try and seek
2485
2469
         * the first file, even if it's not there */
2489
2473
        if (playback_stopped)
2490
2474
                play_pause_set_label (totem, STATE_STOPPED);
2491
2475
 
2492
 
        if (fatal == FALSE) {
2493
 
                totem_action_error (totem, _("An error occurred"), message);
2494
 
        } else {
2495
 
                totem_action_error_and_exit (_("An error occurred"),
2496
 
                                message, totem);
2497
 
        }
 
2476
        totem_action_error (totem, _("An error occurred"), message);
2498
2477
}
2499
2478
 
2500
2479
static void
2501
 
on_buffering_event (BaconVideoWidget *bvw, int percentage, TotemObject *totem)
 
2480
on_buffering_event (BaconVideoWidget *bvw, gdouble percentage, TotemObject *totem)
2502
2481
{
2503
2482
        totem_statusbar_push (TOTEM_STATUSBAR (totem->statusbar), percentage);
2504
2483
}
2668
2647
gboolean
2669
2648
seek_slider_pressed_cb (GtkWidget *widget, GdkEventButton *event, TotemObject *totem)
2670
2649
{
2671
 
        /* HACK: we want the behaviour you get with the middle button, so we
 
2650
        /* HACK: we want the behaviour you get with the left button, so we
2672
2651
         * mangle the event.  clicking with other buttons moves the slider in
2673
 
         * step increments, clicking with the middle button moves the slider to
 
2652
         * step increments, clicking with the left button moves the slider to
2674
2653
         * the location of the click.
2675
2654
         */
2676
 
        event->button = 2;
 
2655
        event->button = GDK_BUTTON_PRIMARY;
2677
2656
 
2678
2657
        totem->seek_lock = TRUE;
2679
2658
        if (bacon_video_widget_can_direct_seek (totem->bvw) == FALSE) {
2712
2691
        gdouble val;
2713
2692
 
2714
2693
        /* HACK: see seek_slider_pressed_cb */
2715
 
        event->button = 2;
 
2694
        event->button = GDK_BUTTON_PRIMARY;
2716
2695
 
2717
2696
        /* set to FALSE here to avoid triggering a final seek when
2718
2697
         * syncing the adjustments while being in direct seek mode */
2798
2777
                                changed = totem_playlist_clear (totem->playlist);
2799
2778
                                bacon_video_widget_close (totem->bvw);
2800
2779
                                totem_file_closed (totem);
 
2780
                                totem->has_played_emitted = FALSE;
2801
2781
                                cleared = TRUE;
2802
2782
                        }
2803
2783
 
2804
 
                        if (totem_is_block_device (filename) != FALSE) {
2805
 
                                totem_action_load_media_device (totem, data);
2806
 
                                changed = TRUE;
2807
 
                        } else if (g_str_has_prefix (filename, "dvb:/") != FALSE) {
 
2784
                        if (g_str_has_prefix (filename, "dvb:/") != FALSE) {
2808
2785
                                mrl_list = g_list_prepend (mrl_list, totem_playlist_mrl_data_new (data, NULL));
2809
2786
                                changed = TRUE;
2810
2787
                        } else {
2886
2863
                        gtk_widget_get_allocation (totem->sidebar, &allocation_sidebar);
2887
2864
                        width += allocation_sidebar.width + handle_size;
2888
2865
                } else {
 
2866
                        totem_action_save_size (totem);
2889
2867
                        gtk_widget_hide (totem->sidebar);
2890
2868
                }
2891
2869
 
3093
3071
                if (url == NULL) {
3094
3072
                        bacon_video_widget_close (totem->bvw);
3095
3073
                        totem_file_closed (totem);
 
3074
                        totem->has_played_emitted = FALSE;
3096
3075
                        totem_action_set_mrl (totem, NULL, NULL);
3097
3076
                        break;
3098
3077
                }
3099
 
                if (strcmp (url, "dvd:") == 0) {
3100
 
                        /* FIXME b0rked */
3101
 
                        totem_action_play_media (totem, MEDIA_TYPE_DVD, NULL);
3102
 
                } else if (strcmp (url, "vcd:") == 0) {
3103
 
                        /* FIXME b0rked */
3104
 
                        totem_action_play_media (totem, MEDIA_TYPE_VCD, NULL);
3105
 
                } else {
3106
 
                        totem_playlist_add_mrl (totem->playlist, url, NULL, TRUE, NULL, NULL, NULL);
3107
 
                }
 
3078
                totem_playlist_add_mrl (totem->playlist, url, NULL, TRUE, NULL, NULL, NULL);
3108
3079
                break;
3109
3080
        case TOTEM_REMOTE_COMMAND_SHOW:
3110
 
                gtk_window_present (GTK_WINDOW (totem->win));
 
3081
                gtk_window_present_with_time (GTK_WINDOW (totem->win), GDK_CURRENT_TIME);
3111
3082
                break;
3112
3083
        case TOTEM_REMOTE_COMMAND_TOGGLE_CONTROLS:
3113
3084
                if (totem->controls_visibility != TOTEM_CONTROLS_FULLSCREEN)
3157
3128
                icon_name = "media-eject";
3158
3129
                break;
3159
3130
        case TOTEM_REMOTE_COMMAND_PLAY_DVD:
3160
 
                /* TODO - how to see if can, and play the DVD (like the menu item) */
 
3131
                /* FIXME - focus the "Optical Media" section in Grilo */
3161
3132
                break;
3162
3133
        case TOTEM_REMOTE_COMMAND_MUTE:
3163
3134
                totem_action_volume_toggle_mute (totem);
3172
3143
        }
3173
3144
 
3174
3145
        if (handled != FALSE
3175
 
                        && gtk_window_is_active (GTK_WINDOW (totem->win))
3176
 
                        && totem_fullscreen_is_fullscreen (totem->fs) != FALSE) {
 
3146
            && gtk_window_is_active (GTK_WINDOW (totem->win))) {
3177
3147
                totem_fullscreen_show_popups_or_osd (totem->fs, icon_name, TRUE);
3178
3148
        }
3179
3149
}
3291
3261
{
3292
3262
        char *mrl, *subtitle;
3293
3263
 
3294
 
        totem_action_stop (totem);
3295
3264
        mrl = totem_playlist_get_current_mrl (totem->playlist, &subtitle);
3296
 
        totem_action_set_mrl_and_play (totem, mrl, subtitle);
 
3265
        bacon_video_widget_set_text_subtitle (totem->bvw, subtitle);
3297
3266
 
3298
3267
        g_free (mrl);
3299
3268
        g_free (subtitle);
3419
3388
                totem_action_fullscreen_toggle(totem);
3420
3389
                return TRUE;
3421
3390
        } else if (event->type == GDK_BUTTON_PRESS && event->button == 2) {
3422
 
                if (totem_is_fullscreen (totem) != FALSE) {
3423
 
                        const char *icon_name;
3424
 
                        if (bacon_video_widget_is_playing (totem->bvw) == FALSE)
3425
 
                                icon_name = "media-playback-start-symbolic";
3426
 
                        else
3427
 
                                icon_name = "media-playback-pause-symbolic";
3428
 
                        totem_fullscreen_show_popups_or_osd (totem->fs, icon_name, FALSE);
3429
 
                }
 
3391
                const char *icon_name;
 
3392
                if (bacon_video_widget_is_playing (totem->bvw) == FALSE)
 
3393
                        icon_name = "media-playback-start-symbolic";
 
3394
                else
 
3395
                        icon_name = "media-playback-pause-symbolic";
 
3396
                totem_fullscreen_show_popups_or_osd (totem->fs, icon_name, FALSE);
3430
3397
                totem_action_play_pause (totem);
3431
3398
                return TRUE;
3432
3399
        } else if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
3599
3566
                bacon_video_widget_step (totem->bvw, TRUE, NULL);
3600
3567
                break;
3601
3568
        case GDK_KEY_AudioPause:
 
3569
        case GDK_KEY_Pause:
3602
3570
        case GDK_KEY_AudioStop:
3603
3571
                totem_action_pause (totem);
3604
3572
                icon_name = "media-playback-pause-symbolic";
3761
3729
                retval = FALSE;
3762
3730
        }
3763
3731
 
3764
 
        if (totem_is_fullscreen (totem) != FALSE && icon_name != NULL)
 
3732
        if (icon_name != NULL)
3765
3733
                totem_fullscreen_show_popups_or_osd (totem->fs,
3766
3734
                                                     icon_name,
3767
3735
                                                     FALSE);
3770
3738
}
3771
3739
 
3772
3740
static gboolean
3773
 
totem_action_handle_scroll (TotemObject *totem, GdkScrollDirection direction)
 
3741
totem_action_handle_scroll (TotemObject    *totem,
 
3742
                            const GdkEvent *event)
3774
3743
{
3775
3744
        gboolean retval = TRUE;
 
3745
        GdkEventScroll *sevent = (GdkEventScroll *) event;
 
3746
        GdkScrollDirection direction;
 
3747
 
 
3748
        direction = sevent->direction;
3776
3749
 
3777
3750
        if (totem_fullscreen_is_fullscreen (totem->fs) != FALSE)
3778
3751
                totem_fullscreen_show_popups (totem->fs, TRUE);
3779
3752
 
 
3753
        if (direction == GDK_SCROLL_SMOOTH) {
 
3754
                gdouble y;
 
3755
                gdk_event_get_scroll_deltas (event, NULL, &y);
 
3756
                direction = y >= 0.0 ? GDK_SCROLL_DOWN : GDK_SCROLL_UP;
 
3757
        }
 
3758
 
3780
3759
        switch (direction) {
3781
3760
        case GDK_SCROLL_UP:
3782
3761
                totem_action_seek_relative (totem, SEEK_FORWARD_SHORT_OFFSET * 1000, FALSE);
3784
3763
        case GDK_SCROLL_DOWN:
3785
3764
                totem_action_seek_relative (totem, SEEK_BACKWARD_SHORT_OFFSET * 1000, FALSE);
3786
3765
                break;
3787
 
        case GDK_SCROLL_LEFT:
3788
 
        case GDK_SCROLL_RIGHT:
3789
3766
        default:
3790
3767
                retval = FALSE;
3791
3768
        }
3830
3807
                case GDK_KEY_l:
3831
3808
                case GDK_KEY_q:
3832
3809
                case GDK_KEY_Q:
3833
 
//              case GDK_KEY_S:
3834
 
//              case GDK_KEY_s:
3835
3810
                case GDK_KEY_Right:
3836
3811
                case GDK_KEY_Left:
3837
3812
                case GDK_KEY_plus:
3881
3856
}
3882
3857
 
3883
3858
gboolean
3884
 
window_scroll_event_cb (GtkWidget *win, GdkEventScroll *event, TotemObject *totem)
 
3859
window_scroll_event_cb (GtkWidget *win, GdkEvent *event, TotemObject *totem)
3885
3860
{
3886
 
        return totem_action_handle_scroll (totem, event->direction);
 
3861
        return totem_action_handle_scroll (totem, event);
3887
3862
}
3888
3863
 
3889
3864
static void
3915
3890
        gboolean has_item;
3916
3891
 
3917
3892
        /* Previous */
3918
 
        if (totem_playing_dvd (totem->mrl) != FALSE)
3919
 
                has_item = bacon_video_widget_has_previous_track (totem->bvw);
3920
 
        else
3921
 
                has_item = totem_playlist_has_previous_mrl (totem->playlist);
3922
 
 
 
3893
        has_item = bacon_video_widget_has_previous_track (totem->bvw) ||
 
3894
                totem_playlist_has_previous_mrl (totem->playlist) ||
 
3895
                totem_playlist_get_repeat (totem->playlist);
3923
3896
        totem_action_set_sensitivity ("previous-chapter", has_item);
3924
3897
 
3925
3898
        /* Next */
3926
 
        if (totem_playing_dvd (totem->mrl) != FALSE)
3927
 
                has_item = bacon_video_widget_has_next_track (totem->bvw);
3928
 
        else
3929
 
                has_item = totem_playlist_has_next_mrl (totem->playlist);
3930
 
 
 
3899
        has_item = bacon_video_widget_has_next_track (totem->bvw) ||
 
3900
                totem_playlist_has_next_mrl (totem->playlist) ||
 
3901
                totem_playlist_get_repeat (totem->playlist);
3931
3902
        totem_action_set_sensitivity ("next-chapter", has_item);
3932
3903
}
3933
3904
 
4031
4002
        gdk_rgba_parse (&black, "Black");
4032
4003
        gtk_widget_override_background_color (vbox, (GTK_STATE_FLAG_FOCUSED << 1), &black);
4033
4004
 
4034
 
        totem_sidebar_setup (totem, show_sidebar, page_id);
 
4005
        totem_sidebar_setup (totem, show_sidebar);
4035
4006
        return page_id;
4036
4007
}
4037
4008
 
4149
4120
        gtk_widget_add_events (totem->win, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
4150
4121
 
4151
4122
        /* Connect the mouse wheel */
4152
 
        gtk_widget_add_events (totem->win, GDK_SCROLL_MASK);
4153
 
        gtk_widget_add_events (totem->seek, GDK_SCROLL_MASK);
4154
 
        gtk_widget_add_events (totem->fs->seek, GDK_SCROLL_MASK);
 
4123
        gtk_widget_add_events (GTK_WIDGET (gtk_builder_get_object (totem->xml, "tmw_main_vbox")), GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK);
 
4124
        gtk_widget_add_events (totem->seek, GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK);
 
4125
        gtk_widget_add_events (totem->fs->seek, GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK);
4155
4126
 
4156
4127
        /* FIXME Hack to fix bug #462286 and #563894 */
4157
4128
        g_signal_connect (G_OBJECT (totem->fs->seek), "button-press-event",