3
3
* Copyright © 2004-2006 Bastien Nocera <hadess@hadess.net>
4
4
* Copyright © 2002 David A. Schleef <ds@schleef.org>
5
* Copyright © 2006 Christian Persch
5
* Copyright © 2006, 2009 Christian Persch
7
7
* This library is free software; you can redistribute it and/or
8
8
* modify it under the terms of the GNU Library General Public
289
totem_embedded_save_volume (TotemEmbedded *emb, double volume)
297
totem_embedded_volume_changed (TotemEmbedded *emb, double volume)
292
299
GValue value = { 0, };
294
gc = gconf_client_get_default ();
295
gconf_client_set_int (gc, GCONF_PREFIX"/volume", (int) (volume * 100.0), NULL);
296
g_object_unref (G_OBJECT (gc));
298
301
g_value_init (&value, G_TYPE_DOUBLE);
299
302
g_value_set_double (&value, volume);
300
303
g_signal_emit (emb, signals[PROPERTY_CHANGE], 0,
423
g_message ("totem_embedded_open_internal '%s' is-browser-stream %d start-play %d", uri, emb->is_browser_stream, start_play);
425
g_message ("totem_embedded_open_internal '%s' subtitle '%s' is-browser-stream %d start-play %d",
426
uri, emb->current_subtitle_uri, emb->is_browser_stream, start_play);
425
428
bacon_video_widget_set_logo_mode (emb->bvw, FALSE);
427
/* FIXME: remove |err| and rely on async on_error? */
428
g_message ("BEFORE _open");
429
retval = bacon_video_widget_open (emb->bvw, uri, NULL, &err);
430
g_message ("AFTER _open (ret: %d)", retval);
435
/* FIXME we haven't even started sending yet! */
436
//g_signal_emit (emb, signals[STOP_STREAM], 0);
438
totem_embedded_set_state (emb, TOTEM_STATE_STOPPED);
439
totem_embedded_set_error_logo (emb, NULL);
441
errint = g_error_new (TOTEM_EMBEDDED_ERROR_QUARK,
442
TOTEM_EMBEDDED_OPEN_FAILED,
443
_("Totem could not play '%s'"),
446
totem_embedded_set_error (emb, err->code, err->message);;
448
g_propagate_error (error, err);
450
totem_embedded_set_pp_state (emb, FALSE);
452
/* FIXME we shouldn't even do that here */
454
totem_embedded_play (emb, NULL);
456
totem_glow_button_set_glow (TOTEM_GLOW_BUTTON (emb->pp_button), TRUE);
430
retval = bacon_video_widget_open (emb->bvw, uri, emb->current_subtitle_uri, NULL);
431
/* FIXME we shouldn't even do that here */
433
totem_embedded_play (emb, NULL);
435
totem_glow_button_set_glow (TOTEM_GLOW_BUTTON (emb->pp_button), TRUE);
459
437
totem_embedded_update_menu (emb);
460
438
if (emb->href_uri != NULL)
524
502
g_return_val_if_fail (command != NULL, FALSE);
504
g_message ("totem_embedded_do_command: %s", command);
526
506
if (strcmp (command, TOTEM_COMMAND_PLAY) == 0) {
527
507
return totem_embedded_play (embedded, error);
575
558
g_message ("totem_embedded_set_volume: %f", volume);
576
559
bacon_video_widget_set_volume (embedded->bvw, volume);
577
totem_embedded_save_volume (embedded, volume);
560
totem_embedded_volume_changed (embedded, volume);
617
600
totem_embedded_set_uri (TotemEmbedded *emb,
619
602
const char *base_uri,
603
const char *subtitle,
620
604
gboolean is_browser_stream)
622
606
GFile *base_gfile;
623
char *old_uri, *old_base, *old_href;
607
char *old_uri, *old_base, *old_href, *old_subtitle;
625
609
base_gfile = NULL;
626
610
old_uri = emb->current_uri;
611
old_subtitle = emb->current_subtitle_uri;
627
612
old_base = emb->base_uri;
628
613
old_href = emb->href_uri;
632
617
base_gfile = g_file_new_for_uri (base_uri);
633
618
emb->current_uri = totem_pl_parser_resolve_uri (base_gfile, uri);
619
if (subtitle != NULL)
620
emb->current_subtitle_uri = totem_pl_parser_resolve_uri (base_gfile, subtitle);
622
emb->current_subtitle_uri = NULL;
635
624
g_object_unref (base_gfile);
636
625
emb->is_browser_stream = (is_browser_stream != FALSE);
637
626
emb->href_uri = NULL;
640
g_print ("totem_embedded_set_uri uri %s base %s => resolved %s\n", uri, base_uri, emb->current_uri);
629
g_print ("totem_embedded_set_uri uri %s base %s => resolved %s (subtitle %s => resolved %s)\n",
630
uri, base_uri, emb->current_uri, subtitle, emb->current_subtitle_uri);
642
632
g_print ("Emptying current_uri\n");
634
if (old_uri != NULL &&
635
g_str_has_prefix (old_uri, "fd://") != FALSE) {
637
fd = strtol (old_uri + strlen ("fd://"), NULL, 0);
644
640
g_free (old_uri);
645
641
g_free (old_base);
646
642
g_free (old_href);
643
g_free (old_subtitle);
647
644
g_free (emb->stream_uri);
648
645
emb->stream_uri = NULL;
668
665
g_free (item->uri);
669
666
g_free (item->title);
667
g_free (item->subtitle);
668
g_slice_free (TotemPlItem, item);
674
672
totem_embedded_clear_playlist (TotemEmbedded *emb, GError *error)
674
g_message ("totem_embedded_clear_playlist");
676
676
g_list_foreach (emb->playlist, (GFunc) totem_pl_item_free, NULL);
677
677
g_list_free (emb->playlist);
680
680
emb->current = NULL;
681
681
emb->num_items = 0;
683
totem_embedded_set_uri (emb, NULL, NULL, FALSE);
683
totem_embedded_set_uri (emb, NULL, NULL, NULL, FALSE);
685
685
bacon_video_widget_close (emb->bvw);
686
update_fill (emb, -1.0);
686
687
totem_embedded_update_title (emb, NULL);
692
totem_embedded_add_item (TotemEmbedded *embedded, const char *uri, GError *error)
693
totem_embedded_add_item (TotemEmbedded *embedded,
694
const char *base_uri,
697
const char *subtitle,
694
700
TotemPlItem *item;
696
g_message ("totem_embedded_add_item: %s", uri);
702
g_message ("totem_embedded_add_item: %s (base: %s title: %s subtitle: %s)",
703
uri, base_uri, title, subtitle);
698
item = g_new0 (TotemPlItem, 1);
705
item = g_slice_new0 (TotemPlItem);
699
706
item->uri = g_strdup (uri);
707
item->title = g_strdup (title);
708
item->subtitle = g_strdup (subtitle);
700
709
item->duration = -1;
701
710
item->starttime = -1;
707
716
embedded->current = embedded->playlist;
708
717
totem_embedded_set_uri (embedded,
709
718
(const char *) uri,
710
embedded->base_uri /* FIXME? */,
712
722
totem_embedded_open_internal (embedded, FALSE, NULL /* FIXME */);
782
792
totem_embedded_clear_playlist (emb, NULL);
784
totem_embedded_set_uri (emb, uri, base_uri, FALSE);
794
totem_embedded_set_uri (emb, uri, base_uri, NULL, FALSE);
785
795
/* We can only have one item in the "playlist" when
786
796
* we open a particular URI like this */
787
797
emb->num_items = 1;
800
810
totem_embedded_clear_playlist (emb, NULL);
802
totem_embedded_set_uri (emb, uri, base_uri, TRUE);
812
totem_embedded_set_uri (emb, uri, base_uri, NULL, TRUE);
803
813
/* We can only have one item in the "playlist" when
804
814
* we open a browser stream */
805
815
emb->num_items = 1;
847
860
totem_embedded_set_uri (emb,
848
861
(const char *) plitem->uri,
849
862
emb->base_uri /* FIXME? */,
852
866
bacon_video_widget_close (emb->bvw);
867
update_fill (emb, -1.0);
869
//FIXME set the title from the URI if possible
853
870
totem_embedded_update_title (emb, plitem->title);
854
871
if (totem_embedded_open_internal (emb, FALSE, NULL /* FIXME */)) {
855
872
if (plitem->starttime > 0) {
891
909
/* FIXME what about |uri| param?!! */
892
totem_embedded_set_uri (emb, file_uri, base_uri, FALSE);
910
totem_embedded_set_uri (emb, file_uri, base_uri, emb->current_subtitle_uri, FALSE);
893
911
g_free (file_uri);
895
913
return totem_embedded_open_internal (emb, TRUE, error);
900
918
const char *path,
923
g_message ("totem_embedded_set_local_cache: %s", path);
905
925
/* FIXME Should also handle playlists */
906
926
if (!emb->is_browser_stream)
909
file_uri = g_filename_to_uri (path, NULL, error);
929
/* Keep the temporary file open, so that StreamAsFile
930
* doesn't remove it from under us */
931
fd = open (path, O_RDONLY);
933
g_message ("Failed to open local cache file '%s': %s",
934
path, g_strerror (errno));
913
938
emb->stream_uri = emb->current_uri;
914
emb->current_uri = file_uri;
939
emb->current_uri = g_strdup_printf ("fd://%d", fd);
928
g_message ("Setting the current playlist to %s (base: %s)",
957
g_message ("Setting the current playlist to %s (uri: %s base: %s)",
958
path, uri, base_uri);
931
960
totem_embedded_clear_playlist (emb, NULL);
933
file_uri = g_filename_to_uri (path, NULL, error);
937
totem_embedded_set_uri (emb, file_uri, base_uri, FALSE);
962
/* FIXME, we should remove that when we can
963
* parse from memory or
964
* https://bugzilla.gnome.org/show_bug.cgi?id=598702 is fixed */
965
fd = g_file_open_tmp ("totem-browser-plugin-playlist-XXXXXX",
969
g_warning ("Couldn't open temporary file for playlist: %s",
974
src = g_file_new_for_path (path);
975
dst = g_file_new_for_path (tmpfile);
976
if (g_file_copy (src, dst, G_FILE_COPY_OVERWRITE | G_FILE_COPY_TARGET_DEFAULT_PERMS, NULL, NULL, NULL, &err) == FALSE) {
977
g_warning ("Failed to copy playlist '%s' to '%s': %s",
978
path, tmpfile, err->message);
980
g_object_unref (src);
981
g_object_unref (dst);
988
file_uri = g_file_get_uri (dst);
990
g_object_unref (src);
991
g_object_unref (dst);
994
totem_embedded_set_uri (emb, file_uri, base_uri, NULL, FALSE);
938
995
g_free (file_uri);
940
997
/* Schedule parsing on idle */
1275
on_popup_menu_unmap (GtkWidget *menu,
1280
button = GTK_WIDGET (gtk_builder_get_object (emb->xml, "popup_button"));
1281
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE);
1218
1285
resolve_redirect (const char *old_mrl, const char *mrl)
1239
1306
on_got_redirect (GtkWidget *bvw, const char *mrl, TotemEmbedded *emb)
1308
char *new_uri = NULL;
1243
1310
g_message ("stream uri: %s", emb->stream_uri ? emb->stream_uri : "(null)");
1244
1311
g_message ("current uri: %s", emb->current_uri ? emb->current_uri : "(null)");
1246
1313
g_message ("redirect: %s", mrl);
1248
1315
bacon_video_widget_close (emb->bvw);
1316
update_fill (emb, -1.0);
1250
1318
/* If we don't have a relative URI */
1251
1319
if (strstr (mrl, "://") != NULL)
1252
1320
new_uri = NULL;
1253
1321
/* We are using a local cache, so we resolve against the stream_uri */
1254
if (emb->stream_uri)
1322
else if (emb->stream_uri)
1255
1323
new_uri = resolve_redirect (emb->stream_uri, mrl);
1256
1324
/* We don't have a local cache, so resolve against the URI */
1257
1325
else if (emb->current_uri)
1265
1333
/* FIXME: clear playlist? or replace current entry? or add a new entry? */
1266
1334
/* FIXME: use totem_embedded_open_uri? */
1268
totem_embedded_set_uri (emb, new_uri ? new_uri : mrl , emb->base_uri /* FIXME? */, FALSE);
1336
totem_embedded_set_uri (emb, new_uri ? new_uri : mrl , emb->base_uri /* FIXME? */, emb->current_subtitle_uri, FALSE);
1270
1338
totem_embedded_set_state (emb, TOTEM_STATE_STOPPED);
1400
1468
emb->num_items = 1;
1401
1469
emb->is_browser_stream = FALSE;
1402
1470
bacon_video_widget_close (emb->bvw);
1471
update_fill (emb, -1.0);
1403
1472
totem_embedded_open_internal (emb, start_play, NULL /* FIXME? */);
1405
1474
/* FIXME: should find a way to enable playback of the stream again without re-requesting it */
1415
1484
totem_embedded_play (emb, NULL);
1417
1486
bacon_video_widget_close (emb->bvw);
1487
update_fill (emb, -1.0);
1418
1488
totem_embedded_open_internal (emb, start_play, NULL /* FIXME? */);
1421
1491
bacon_video_widget_close (emb->bvw);
1492
update_fill (emb, -1.0);
1422
1493
totem_embedded_open_internal (emb, start_play, NULL /* FIXME? */);
1424
1495
} else if (emb->current) {
1479
1550
cb_vol (GtkWidget *val, gdouble value, TotemEmbedded *emb)
1481
1552
bacon_video_widget_set_volume (emb->bvw, value);
1482
totem_embedded_save_volume (emb, value);
1553
totem_embedded_volume_changed (emb, value);
1597
update_fill (TotemEmbedded *emb, gdouble level)
1600
gtk_range_set_show_fill_level (GTK_RANGE (emb->seek), FALSE);
1601
gtk_range_set_show_fill_level (GTK_RANGE (emb->fs->seek), FALSE);
1603
gtk_range_set_fill_level (GTK_RANGE (emb->seek), level * 65535.0f);
1604
gtk_range_set_show_fill_level (GTK_RANGE (emb->seek), TRUE);
1606
gtk_range_set_fill_level (GTK_RANGE (emb->fs->seek), level * 65535.0f);
1607
gtk_range_set_show_fill_level (GTK_RANGE (emb->fs->seek), TRUE);
1612
on_download_buffering (BaconVideoWidget *bvw, gdouble level, TotemEmbedded *emb)
1614
update_fill (emb, level);
1526
1618
property_notify_cb_volume (BaconVideoWidget *bvw,
1527
1619
GParamSpec *spec,
1528
1620
TotemEmbedded *emb)
1534
1626
g_signal_handlers_block_by_func (emb->volume, cb_vol, emb);
1535
1627
gtk_scale_button_set_value (GTK_SCALE_BUTTON (emb->volume), volume);
1536
totem_embedded_save_volume (emb, volume);
1628
totem_embedded_volume_changed (emb, volume);
1537
1629
g_signal_handlers_unblock_by_func (emb->volume, cb_vol, emb);
1590
1682
vol = bacon_video_widget_get_volume (emb->bvw);
1591
1683
bacon_video_widget_set_volume (emb->bvw, vol + off_pct);
1592
totem_embedded_save_volume (emb, vol + off_pct);
1684
totem_embedded_volume_changed (emb, vol + off_pct);
1595
1687
static gboolean
1696
1789
(-1, -1, type, &err));
1700
if (emb->bvw == NULL) {
1702
/* FIXME construct and show error message */
1703
totem_embedded_error_and_exit (_("The Totem plugin could not be started."), err != NULL ? err->message : _("No reason."), emb);
1792
/* FIXME: check the UA strings of the legacy plugins themselves */
1793
/* FIXME: at least hxplayer seems to send different UAs depending on the protocol!? */
1794
if (emb->user_agent != NULL) {
1795
bacon_video_widget_set_user_agent (emb->bvw, emb->user_agent);
1796
g_free (emb->user_agent);
1797
emb->user_agent = NULL;
1800
/* FIXMEchpe: this is just the initial value. I think in case e.g. we're doing
1801
* a playlist, the playlist's URI should become the referrer?
1803
g_print ("Referrer URI: %s\n", emb->referrer_uri);
1804
if (emb->referrer_uri != NULL) {
1805
bacon_video_widget_set_referrer (emb->bvw, emb->referrer_uri);
1806
g_free (emb->referrer_uri);
1807
emb->referrer_uri = NULL;
1709
1810
/* Fullscreen setup */
1710
1811
emb->fs_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1711
1812
gtk_widget_realize (emb->fs_window);
1751
1852
G_CALLBACK (on_tick), emb);
1752
1853
g_signal_connect (G_OBJECT (emb->bvw), "buffering",
1753
1854
G_CALLBACK (on_buffering), emb);
1855
g_signal_connect (G_OBJECT (emb->bvw), "download-buffering",
1856
G_CALLBACK (on_download_buffering), emb);
1755
1858
g_signal_connect (G_OBJECT (emb->bvw), "notify::volume",
1756
1859
G_CALLBACK (property_notify_cb_volume), emb);
1792
1895
G_CALLBACK (on_popup_button_toggled), emb);
1793
1896
g_signal_connect (G_OBJECT (popup_button), "button-press-event",
1794
1897
G_CALLBACK (on_popup_button_button_pressed), emb);
1898
menu = GTK_WIDGET (gtk_builder_get_object (emb->menuxml, "menu"));
1899
g_signal_connect (G_OBJECT (menu), "unmap",
1900
G_CALLBACK (on_popup_menu_unmap), emb);
1796
1902
gc = gconf_client_get_default ();
1797
1903
volume = ((double) gconf_client_get_int (gc, GCONF_PREFIX"/volume", NULL)) / 100.0;
1806
1912
g_signal_connect (G_OBJECT (emb->volume), "value-changed",
1807
1913
G_CALLBACK (cb_vol), emb);
1808
1914
bacon_video_widget_set_volume (emb->bvw, volume);
1809
totem_embedded_save_volume (emb, volume);
1915
totem_embedded_volume_changed (emb, volume);
1811
1917
emb->statusbar = TOTEM_STATUSBAR (gtk_builder_get_object (emb->xml, "statusbar"));
1812
1918
gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (emb->statusbar), FALSE);
1881
1987
static gboolean
1882
totem_embedded_construct_placeholder (TotemEmbedded *emb,
1883
GdkNativeWindow xid,
1887
GtkWidget *window, *label;
1892
window = gtk_plug_new (xid);
1894
gtk_widget_realize (window);
1896
label = gtk_label_new ("Not yet supported");
1897
gtk_container_add (GTK_CONTAINER (window), label);
1899
gtk_widget_show_all (window);
1905
1988
totem_embedded_set_window (TotemEmbedded *embedded,
1906
1989
const char *controls,
1912
1995
g_print ("Viewer: SetWindow XID %u size %d:%d\n", window, width, height);
1914
if (embedded->type == TOTEM_PLUGIN_TYPE_COMPLEX) {
1916
if (strcmp (controls, "All") != 0 &&
1917
strcmp (controls, "ImageWindow") != 0) {
1918
totem_embedded_construct_placeholder (embedded, (GdkNativeWindow) window, width, height);
1922
if (strcmp (controls, "All") != 0 &&
1923
strcmp (controls, "ImageWindow") != 0) {
1925
TOTEM_EMBEDDED_ERROR_QUARK,
1926
TOTEM_EMBEDDED_SETWINDOW_UNSUPPORTED_CONTROLS,
1927
"Unsupported controls '%s'", controls);
1997
if (strcmp (controls, "All") != 0 &&
1998
strcmp (controls, "ImageWindow") != 0) {
2000
TOTEM_EMBEDDED_ERROR_QUARK,
2001
TOTEM_EMBEDDED_SETWINDOW_UNSUPPORTED_CONTROLS,
2002
"Unsupported controls '%s'", controls);
1932
2006
if (embedded->window != NULL) {
1999
2073
if (duration == 0)
2002
item = g_new0 (TotemPlItem, 1);
2076
item = g_slice_new0 (TotemPlItem);
2003
2077
item->uri = g_strdup (uri);
2004
2078
item->title = g_strdup (g_hash_table_lookup (metadata, TOTEM_PL_PARSER_FIELD_TITLE));
2005
2079
item->duration = duration;
2026
2101
emb->base_uri, FALSE);
2027
2102
g_object_unref (parser);
2104
/* Delete the temporary file created in
2105
* totem_embedded_set_playlist */
2106
file = g_file_new_for_uri (emb->current_uri);
2107
g_file_delete (file, NULL, NULL);
2108
g_object_unref (file);
2029
2110
if (res != TOTEM_PL_PARSER_RESULT_SUCCESS) {
2030
2111
//FIXME show a proper error message
2070
2151
static char *arg_user_agent = NULL;
2071
2152
static char *arg_mime_type = NULL;
2072
2153
static char **arg_remaining = NULL;
2154
static char *arg_referrer = NULL;
2073
2155
static gboolean arg_no_controls = FALSE;
2074
2156
static gboolean arg_statusbar = FALSE;
2075
2157
static gboolean arg_hidden = FALSE;
2117
2198
{ TOTEM_OPTION_REPEAT, 0, 0, G_OPTION_ARG_NONE, &arg_repeat, NULL, NULL },
2118
2199
{ TOTEM_OPTION_NOAUTOSTART, 0, 0, G_OPTION_ARG_NONE, &arg_no_autostart, NULL, NULL },
2119
2200
{ TOTEM_OPTION_AUDIOONLY, 0, 0, G_OPTION_ARG_NONE, &arg_audioonly, NULL, NULL },
2201
{ TOTEM_OPTION_REFERRER, 0, 0, G_OPTION_ARG_STRING, &arg_referrer, NULL, NULL },
2120
2202
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY /* STRING? */, &arg_remaining, NULL },
2217
/* FIXME: check the UA strings of the legacy plugins themselves */
2218
/* FIXME: at least hxplayer seems to send different UAs depending on the protocol!? */
2219
if (arg_user_agent != NULL) {
2220
g_setenv ("BACON_VIDEO_WIDGET_HTTP_USER_AGENT", arg_user_agent, TRUE);
2221
g_free (arg_user_agent);
2222
arg_user_agent = NULL;
2225
2299
bacon_video_widget_init_backend (NULL, NULL);
2227
2301
dbus_g_object_type_install_info (TOTEM_TYPE_EMBEDDED,
2269
2343
emb->autostart = !arg_no_autostart;
2270
2344
emb->audioonly = arg_audioonly;
2271
2345
emb->type = arg_plugin_type;
2346
emb->user_agent = arg_user_agent;
2347
emb->referrer_uri = arg_referrer;
2273
2349
/* FIXME: register this BEFORE requesting the service name? */
2274
2350
dbus_g_connection_register_g_object