3
Copyright (C) 2004-2005 Bastien Nocera
5
The Gnome Library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Library General Public License as
7
published by the Free Software Foundation; either version 2 of the
8
License, or (at your option) any later version.
10
The Gnome Library is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Library General Public License for more details.
15
You should have received a copy of the GNU Library General Public
16
License along with the Gnome Library; see the file COPYING.LIB. If not,
17
write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18
Boston, MA 02110-1301 USA.
20
Author: Bastien Nocera <hadess@hadess.net>
26
#include <glib/gi18n.h>
27
#include <gst/tag/tag.h>
29
#include <libpeas-gtk/peas-gtk-plugin-manager.h>
31
#include "totem-menu.h"
33
#include "totem-interface.h"
34
#include "totem-private.h"
35
#include "totem-sidebar.h"
36
#include "totem-statusbar.h"
37
#include "bacon-video-widget.h"
38
#include "totem-uri.h"
40
#include "totem-profile.h"
42
#define TOTEM_MAX_RECENT_ITEM_LEN 40
44
/* Callback functions for GtkBuilder */
45
G_MODULE_EXPORT void open_action_callback (GtkAction *action, Totem *totem);
46
G_MODULE_EXPORT void open_location_action_callback (GtkAction *action, Totem *totem);
47
G_MODULE_EXPORT void eject_action_callback (GtkAction *action, Totem *totem);
48
G_MODULE_EXPORT void properties_action_callback (GtkAction *action, Totem *totem);
49
G_MODULE_EXPORT void play_action_callback (GtkAction *action, Totem *totem);
50
G_MODULE_EXPORT void quit_action_callback (GtkAction *action, Totem *totem);
51
G_MODULE_EXPORT void preferences_action_callback (GtkAction *action, Totem *totem);
52
G_MODULE_EXPORT void fullscreen_action_callback (GtkAction *action, Totem *totem);
53
G_MODULE_EXPORT void zoom_1_2_action_callback (GtkAction *action, Totem *totem);
54
G_MODULE_EXPORT void zoom_1_1_action_callback (GtkAction *action, Totem *totem);
55
G_MODULE_EXPORT void zoom_2_1_action_callback (GtkAction *action, Totem *totem);
56
G_MODULE_EXPORT void zoom_in_action_callback (GtkAction *action, Totem *totem);
57
G_MODULE_EXPORT void zoom_reset_action_callback (GtkAction *action, Totem *totem);
58
G_MODULE_EXPORT void zoom_out_action_callback (GtkAction *action, Totem *totem);
59
G_MODULE_EXPORT void next_angle_action_callback (GtkAction *action, Totem *totem);
60
G_MODULE_EXPORT void dvd_root_menu_action_callback (GtkAction *action, Totem *totem);
61
G_MODULE_EXPORT void dvd_title_menu_action_callback (GtkAction *action, Totem *totem);
62
G_MODULE_EXPORT void dvd_audio_menu_action_callback (GtkAction *action, Totem *totem);
63
G_MODULE_EXPORT void dvd_angle_menu_action_callback (GtkAction *action, Totem *totem);
64
G_MODULE_EXPORT void dvd_chapter_menu_action_callback (GtkAction *action, Totem *totem);
65
G_MODULE_EXPORT void next_chapter_action_callback (GtkAction *action, Totem *totem);
66
G_MODULE_EXPORT void previous_chapter_action_callback (GtkAction *action, Totem *totem);
67
G_MODULE_EXPORT void skip_forward_action_callback (GtkAction *action, Totem *totem);
68
G_MODULE_EXPORT void skip_backwards_action_callback (GtkAction *action, Totem *totem);
69
G_MODULE_EXPORT void volume_up_action_callback (GtkAction *action, Totem *totem);
70
G_MODULE_EXPORT void volume_down_action_callback (GtkAction *action, Totem *totem);
71
G_MODULE_EXPORT void contents_action_callback (GtkAction *action, Totem *totem);
72
G_MODULE_EXPORT void about_action_callback (GtkAction *action, Totem *totem);
73
G_MODULE_EXPORT void plugins_action_callback (GtkAction *action, Totem *totem);
74
G_MODULE_EXPORT void repeat_mode_action_callback (GtkToggleAction *action, Totem *totem);
75
G_MODULE_EXPORT void shuffle_mode_action_callback (GtkToggleAction *action, Totem *totem);
76
G_MODULE_EXPORT void show_controls_action_callback (GtkToggleAction *action, Totem *totem);
77
G_MODULE_EXPORT void show_sidebar_action_callback (GtkToggleAction *action, Totem *totem);
78
G_MODULE_EXPORT void aspect_ratio_changed_callback (GtkRadioAction *action, GtkRadioAction *current, Totem *totem);
79
G_MODULE_EXPORT void select_subtitle_action_callback (GtkAction *action, Totem *totem);
80
G_MODULE_EXPORT void clear_playlist_action_callback (GtkAction *action, Totem *totem);
82
/* Helper function to escape underscores in labels
83
* before putting them in menu items */
85
escape_label_for_menu (const char *name)
89
a = g_strsplit (name, "_", -1);
90
new = g_strjoinv ("__", a);
96
/* Subtitle and language menus */
98
totem_g_list_deep_free (GList *list)
102
for (l = list; l != NULL; l = l->next)
108
subtitles_changed_callback (GtkRadioAction *action, GtkRadioAction *current,
113
rank = gtk_radio_action_get_current_value (current);
115
bacon_video_widget_set_subtitle (totem->bvw, rank);
120
languages_changed_callback (GtkRadioAction *action, GtkRadioAction *current,
125
rank = gtk_radio_action_get_current_value (current);
127
bacon_video_widget_set_language (totem->bvw, rank);
131
add_lang_action (Totem *totem, GtkActionGroup *action_group, guint ui_id,
132
const char **paths, const char *prefix, const char *lang,
133
int lang_id, int lang_index, GSList **group)
135
const char *full_lang;
141
full_lang = gst_tag_get_language_name (lang);
143
if (lang_index > 1) {
146
num_lang = g_strdup_printf ("%s #%u",
147
full_lang ? full_lang : lang,
149
label = escape_label_for_menu (num_lang);
152
label = escape_label_for_menu (full_lang ? full_lang : lang);
155
name = g_strdup_printf ("%s-%d", prefix, lang_id);
157
action = g_object_new (GTK_TYPE_RADIO_ACTION,
164
gtk_radio_action_set_group (GTK_RADIO_ACTION (action), *group);
165
*group = gtk_radio_action_get_group (GTK_RADIO_ACTION (action));
166
gtk_action_group_add_action (action_group, action);
167
g_object_unref (action);
168
for (i = 0; paths[i] != NULL; i++) {
169
gtk_ui_manager_add_ui (totem->ui_manager, ui_id,
170
paths[i], name, name, GTK_UI_MANAGER_MENUITEM, FALSE);
178
create_lang_actions (Totem *totem, GtkActionGroup *action_group, guint ui_id,
179
const char **paths, const char *prefix, GList *list,
182
GtkAction *action = NULL;
183
unsigned int i, *hash_value;
185
GSList *group = NULL;
189
if (is_lang == FALSE) {
190
add_lang_action (totem, action_group, ui_id, paths, prefix,
191
/* Translators: an entry in the "Languages" menu, used to choose the audio language of a DVD */
192
_("None"), -2, 0, &group);
195
action = add_lang_action (totem, action_group, ui_id, paths, prefix,
196
/* Translators: an entry in the "Languages" menu, used to choose the audio language of a DVD */
197
C_("Language", "Auto"), -1, 0, &group);
200
lookup = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
202
for (l = list; l != NULL; l = l->next)
206
hash_value = g_hash_table_lookup (lookup, l->data);
207
if (hash_value == NULL) {
209
action_data = g_strdup (l->data);
210
g_hash_table_insert (lookup, l->data, GINT_TO_POINTER (1));
212
num = GPOINTER_TO_INT (hash_value);
213
action_data = g_strdup (l->data);
214
g_hash_table_replace (lookup, l->data, GINT_TO_POINTER (num + 1));
217
add_lang_action (totem, action_group, ui_id, paths, prefix,
218
action_data, i, num + 1, &group);
219
g_free (action_data);
223
g_hash_table_destroy (lookup);
229
totem_sublang_equal_lists (GList *orig, GList *new)
234
if ((orig == NULL && new != NULL) || (orig != NULL && new == NULL))
236
if (orig == NULL && new == NULL)
239
if (g_list_length (orig) != g_list_length (new))
245
while (o != NULL && n != NULL && retval != FALSE)
247
if (g_str_equal (o->data, n->data) == FALSE)
257
totem_languages_update (Totem *totem, GList *list)
260
const char *paths[3] = { "/tmw-menubar/sound/languages/placeholder", "/totem-main-popup/popup-languages/placeholder", NULL };
264
gtk_ui_manager_remove_ui (totem->ui_manager, totem->languages_ui_id);
265
gtk_ui_manager_ensure_update (totem->ui_manager);
267
/* Create new ActionGroup */
268
if (totem->languages_action_group) {
269
gtk_ui_manager_remove_action_group (totem->ui_manager,
270
totem->languages_action_group);
271
g_object_unref (totem->languages_action_group);
273
totem->languages_action_group = gtk_action_group_new ("languages-action-group");
274
gtk_ui_manager_insert_action_group (totem->ui_manager,
275
totem->languages_action_group, -1);
278
action = create_lang_actions (totem, totem->languages_action_group,
279
totem->languages_ui_id,
281
"languages", list, TRUE);
282
gtk_ui_manager_ensure_update (totem->ui_manager);
284
current = bacon_video_widget_get_language (totem->bvw);
285
gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action),
287
g_signal_connect (G_OBJECT (action), "changed",
288
G_CALLBACK (languages_changed_callback), totem);
291
totem_g_list_deep_free (totem->language_list);
292
totem->language_list = list;
296
totem_subtitles_update (Totem *totem, GList *list)
300
const char *paths[3] = { "/tmw-menubar/view/subtitles/placeholder", "/totem-main-popup/popup-subtitles/placeholder", NULL };
303
gtk_ui_manager_remove_ui (totem->ui_manager, totem->subtitles_ui_id);
304
gtk_ui_manager_ensure_update (totem->ui_manager);
306
/* Create new ActionGroup */
307
if (totem->subtitles_action_group) {
308
gtk_ui_manager_remove_action_group (totem->ui_manager,
309
totem->subtitles_action_group);
310
g_object_unref (totem->subtitles_action_group);
312
totem->subtitles_action_group = gtk_action_group_new ("subtitles-action-group");
313
gtk_ui_manager_insert_action_group (totem->ui_manager,
314
totem->subtitles_action_group, -1);
318
action = create_lang_actions (totem, totem->subtitles_action_group,
319
totem->subtitles_ui_id,
321
"subtitles", list, FALSE);
322
gtk_ui_manager_ensure_update (totem->ui_manager);
324
current = bacon_video_widget_get_subtitle (totem->bvw);
325
gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action),
327
g_signal_connect (G_OBJECT (action), "changed",
328
G_CALLBACK (subtitles_changed_callback), totem);
331
totem_g_list_deep_free (totem->subtitles_list);
332
totem->subtitles_list = list;
336
totem_sublang_update (Totem *totem)
340
list = bacon_video_widget_get_languages (totem->bvw);
341
if (totem_sublang_equal_lists (totem->language_list, list) == TRUE) {
342
totem_g_list_deep_free (list);
344
totem_languages_update (totem, list);
347
list = bacon_video_widget_get_subtitles (totem->bvw);
348
if (totem_sublang_equal_lists (totem->subtitles_list, list) == TRUE) {
349
totem_g_list_deep_free (list);
351
totem_subtitles_update (totem, list);
356
totem_sublang_exit (Totem *totem)
358
totem_g_list_deep_free (totem->subtitles_list);
359
totem_g_list_deep_free (totem->language_list);
364
connect_proxy_cb (GtkActionGroup *action_group,
371
if (!GTK_IS_MENU_ITEM (proxy))
374
label = GTK_LABEL (gtk_bin_get_child (GTK_BIN (proxy)));
376
gtk_label_set_ellipsize (label, PANGO_ELLIPSIZE_MIDDLE);
377
gtk_label_set_max_width_chars (label,TOTEM_MAX_RECENT_ITEM_LEN);
381
on_recent_file_item_activated (GtkAction *action,
384
GtkRecentInfo *recent_info;
385
const gchar *uri, *display_name;
387
recent_info = g_object_get_data (G_OBJECT (action), "recent-info");
388
uri = gtk_recent_info_get_uri (recent_info);
389
display_name = gtk_recent_info_get_display_name (recent_info);
391
totem_add_to_playlist_and_play (totem, uri, display_name, FALSE);
395
totem_compare_recent_items (GtkRecentInfo *a, GtkRecentInfo *b)
397
gboolean has_totem_a, has_totem_b;
399
has_totem_a = gtk_recent_info_has_group (a, "Totem");
400
has_totem_b = gtk_recent_info_has_group (b, "Totem");
402
if (has_totem_a && has_totem_b) {
403
time_t time_a, time_b;
405
time_a = gtk_recent_info_get_modified (a);
406
time_b = gtk_recent_info_get_modified (b);
408
return (time_b - time_a);
409
} else if (has_totem_a) {
411
} else if (has_totem_b) {
419
totem_recent_manager_changed_callback (GtkRecentManager *recent_manager, Totem *totem)
421
GList *items, *totem_items, *l;
424
if (totem->recent_ui_id != 0) {
425
gtk_ui_manager_remove_ui (totem->ui_manager, totem->recent_ui_id);
426
gtk_ui_manager_ensure_update (totem->ui_manager);
429
if (totem->recent_action_group) {
430
gtk_ui_manager_remove_action_group (totem->ui_manager,
431
totem->recent_action_group);
434
totem->recent_action_group = gtk_action_group_new ("recent-action-group");
435
g_signal_connect (totem->recent_action_group, "connect-proxy",
436
G_CALLBACK (connect_proxy_cb), NULL);
437
gtk_ui_manager_insert_action_group (totem->ui_manager,
438
totem->recent_action_group, -1);
439
g_object_unref (totem->recent_action_group);
441
totem->recent_ui_id = gtk_ui_manager_new_merge_id (totem->ui_manager);
442
items = gtk_recent_manager_get_items (recent_manager);
444
/* Remove the non-Totem items */
446
for (l = items; l && l->data; l = l->next) {
449
info = (GtkRecentInfo *) l->data;
451
if (gtk_recent_info_has_group (info, "Totem")) {
452
gtk_recent_info_ref (info);
453
totem_items = g_list_prepend (totem_items, info);
456
g_list_foreach (items, (GFunc) gtk_recent_info_unref, NULL);
459
totem_items = g_list_sort (totem_items, (GCompareFunc) totem_compare_recent_items);
461
for (l = totem_items; l && l->data; l = l->next) {
464
char action_name[32];
465
const char *display_name;
468
const gchar *mime_type;
472
info = (GtkRecentInfo *) l->data;
474
if (!gtk_recent_info_has_group (info, "Totem"))
477
g_snprintf (action_name, sizeof (action_name), "RecentFile%u", n_items);
479
display_name = gtk_recent_info_get_display_name (info);
480
escaped_label = escape_label_for_menu (display_name);
482
label = g_strdup_printf ("_%d. %s", n_items + 1, escaped_label);
483
g_free (escaped_label);
485
action = gtk_action_new (action_name, label, NULL, NULL);
486
g_object_set_data_full (G_OBJECT (action), "recent-info",
487
gtk_recent_info_ref (info),
488
(GDestroyNotify) gtk_recent_info_unref);
489
g_signal_connect (G_OBJECT (action), "activate",
490
G_CALLBACK (on_recent_file_item_activated),
493
mime_type = gtk_recent_info_get_mime_type (info);
494
content_type = g_content_type_from_mime_type (mime_type);
495
if (content_type != NULL) {
496
icon = g_content_type_get_icon (content_type);
497
g_free (content_type);
500
gtk_action_set_gicon (action, icon);
501
gtk_action_set_always_show_image (action, TRUE);
502
g_object_unref (icon);
505
gtk_action_group_add_action (totem->recent_action_group,
507
g_object_unref (action);
509
gtk_ui_manager_add_ui (totem->ui_manager, totem->recent_ui_id,
510
"/tmw-menubar/movie/recent-placeholder",
511
label, action_name, GTK_UI_MANAGER_MENUITEM,
519
g_list_foreach (totem_items, (GFunc) gtk_recent_info_unref, NULL);
520
g_list_free (totem_items);
524
totem_setup_recent (Totem *totem)
526
totem->recent_manager = gtk_recent_manager_get_default ();
527
totem->recent_action_group = NULL;
528
totem->recent_ui_id = 0;
530
g_signal_connect (G_OBJECT (totem->recent_manager), "changed",
531
G_CALLBACK (totem_recent_manager_changed_callback),
534
totem_recent_manager_changed_callback (totem->recent_manager, totem);
538
recent_info_cb (GFile *file,
543
char *groups[] = { NULL, NULL };
544
GFileInfo *file_info;
545
const char *uri, *display_name;
547
memset (&data, 0, sizeof (data));
549
file_info = g_file_query_info_finish (file, res, NULL);
550
uri = g_object_get_data (G_OBJECT (file), "uri");
551
display_name = g_object_get_data (G_OBJECT (file), "display_name");
553
/* Probably an unsupported URI scheme */
554
if (file_info == NULL) {
555
data.display_name = g_strdup (display_name);
556
/* Bogus mime-type, we just want it added */
557
data.mime_type = g_strdup ("video/x-totem-stream");
558
groups[0] = (gchar*) "TotemStreams";
560
data.mime_type = g_strdup (g_file_info_get_content_type (file_info));
561
data.display_name = g_strdup (g_file_info_get_display_name (file_info));
562
g_object_unref (file_info);
563
groups[0] = (gchar*) "Totem";
566
data.app_name = g_strdup (g_get_application_name ());
567
data.app_exec = g_strjoin (" ", g_get_prgname (), "%u", NULL);
568
data.groups = groups;
569
if (gtk_recent_manager_add_full (totem->recent_manager,
570
uri, &data) == FALSE) {
571
g_warning ("Couldn't add recent file for '%s'", uri);
574
g_free (data.display_name);
575
g_free (data.mime_type);
576
g_free (data.app_name);
577
g_free (data.app_exec);
579
g_object_unref (file);
583
totem_action_add_recent (Totem *totem,
585
const char *display_name,
586
const char *content_type)
590
if (totem_is_special_mrl (uri) != FALSE)
593
/* If we already have a content-type, the display_name is
594
* probably decent as well */
595
if (content_type != NULL) {
597
char *groups[] = { NULL, NULL };
599
memset (&data, 0, sizeof (data));
601
data.mime_type = (char *) content_type;
602
data.display_name = (char *) display_name;
603
groups[0] = (char*) "Totem";
604
data.app_name = (char *) g_get_application_name ();
605
data.app_exec = g_strjoin (" ", g_get_prgname (), "%u", NULL);
606
data.groups = groups;
608
if (gtk_recent_manager_add_full (totem->recent_manager,
609
uri, &data) == FALSE) {
610
g_warning ("Couldn't add recent file for '%s'", uri);
612
g_free (data.app_exec);
617
file = g_file_new_for_uri (uri);
618
g_object_set_data_full (G_OBJECT (file), "uri", g_strdup (uri), g_free);
619
g_object_set_data_full (G_OBJECT (file), "display_name", g_strdup (display_name), g_free);
620
g_file_query_info_async (file,
621
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
622
G_FILE_QUERY_INFO_NONE, 0, NULL, (GAsyncReadyCallback) recent_info_cb, totem);
625
/* Play Disc menu items */
628
on_play_disc_activate (GtkAction *action, Totem *totem)
632
device_path = g_object_get_data (G_OBJECT (action), "device_path");
633
totem_action_play_media_device (totem, device_path);
637
get_icon_name_for_gicon (GtkIconTheme *theme,
640
const char * const *icon_names;
641
const char *icon_name;
646
if (G_IS_EMBLEMED_ICON (icon) != FALSE) {
648
new_icon = g_emblemed_icon_get_icon (G_EMBLEMED_ICON (icon));
649
g_object_unref (icon);
650
icon = g_object_ref (new_icon);
653
if (G_IS_THEMED_ICON (icon)) {
654
icon_names = g_themed_icon_get_names (G_THEMED_ICON (icon));
656
for (j = 0; icon_names[j] != NULL; j++) {
657
icon_name = icon_names[j];
658
if (gtk_icon_theme_has_icon (theme, icon_name) != FALSE)
667
unescape_archive_name (GFile *root)
671
char *escape1, *escape2;
673
uri = g_file_get_uri (root);
675
/* Remove trailing slash */
677
if (uri[len - 1] == '/')
680
/* Unescape the path */
681
escape1 = g_uri_unescape_string (uri + strlen ("archive://"), NULL);
682
escape2 = g_uri_unescape_string (escape1, NULL);
690
add_mount_to_menu (GMount *mount,
695
char *name, *escaped_name, *label;
698
const char *icon_name;
703
char **content_types;
704
gboolean has_content;
707
/* Check whether we have an archive mount */
708
volume = g_mount_get_volume (mount);
709
if (volume != NULL) {
710
g_object_unref (volume);
714
root = g_mount_get_root (mount);
715
if (g_file_has_uri_scheme (root, "archive") == FALSE) {
716
g_object_unref (root);
720
/* Check whether it's a DVD or VCD image */
721
content_types = g_content_type_guess_for_tree (root);
722
if (content_types == NULL ||
723
g_strv_length (content_types) == 0) {
724
g_strfreev (content_types);
725
g_object_unref (root);
730
for (i = 0; content_types[i] != NULL; i++) {
731
/* XXX: Keep in sync with mime-type-list.txt */
732
if (g_str_equal (content_types[i], "x-content/video-dvd") ||
733
g_str_equal (content_types[i], "x-content/video-vcd") ||
734
g_str_equal (content_types[i], "x-content/video-svcd")) {
739
g_strfreev (content_types);
741
if (has_content == FALSE) {
742
g_object_unref (root);
746
device_path = unescape_archive_name (root);
747
g_object_unref (root);
749
/* And ensure it's a local path */
750
iso = g_file_new_for_uri (device_path);
751
g_free (device_path);
752
device_path = g_file_get_path (iso);
753
g_object_unref (iso);
755
/* Work out an icon to display */
756
icon = g_mount_get_icon (mount);
757
icon_name = get_icon_name_for_gicon (theme, icon);
759
/* Get the mount's pretty name for the menu label */
760
name = g_mount_get_name (mount);
762
escaped_name = escape_label_for_menu (name);
765
* This is not a JPEG image, but a disc image, for example,
767
label = g_strdup_printf (_("Play Image '%s'"), escaped_name);
768
g_free (escaped_name);
770
name = g_strdup_printf (_("device%d"), position);
772
action = gtk_action_new (name, label, NULL, NULL);
773
g_object_set (G_OBJECT (action),
774
"icon-name", icon_name, NULL);
775
gtk_action_set_always_show_image (action, TRUE);
776
gtk_action_group_add_action (totem->devices_action_group, action);
777
g_object_unref (action);
779
gtk_ui_manager_add_ui (totem->ui_manager, totem->devices_ui_id,
780
"/tmw-menubar/movie/devices-placeholder", name, name,
781
GTK_UI_MANAGER_MENUITEM, FALSE);
785
g_object_unref (icon);
787
g_object_set_data_full (G_OBJECT (action),
788
"device_path", device_path,
789
(GDestroyNotify) g_free);
791
g_signal_connect (G_OBJECT (action), "activate",
792
G_CALLBACK (on_play_disc_activate), totem);
796
add_volume_to_menu (GVolume *volume,
802
char *name, *escaped_name, *label;
806
const char *icon_name;
808
GtkWidget *menu_item;
809
char *menu_item_path;
814
/* Add devices with blank CDs and audio CDs in them, but disable them */
816
device_path = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
817
if (device_path == NULL)
821
/* Check whether we have a media... */
823
g_drive_has_media (drive) == FALSE) {
826
/* ... Or an audio CD or a blank media */
830
mount = g_volume_get_mount (volume);
832
root = g_mount_get_root (mount);
833
g_object_unref (mount);
835
if (g_file_has_uri_scheme (root, "burn") != FALSE || g_file_has_uri_scheme (root, "cdda") != FALSE)
837
g_object_unref (root);
841
/* Work out an icon to display */
842
icon = g_volume_get_icon (volume);
843
icon_name = get_icon_name_for_gicon (theme, icon);
845
/* Get the volume's pretty name for the menu label */
846
name = g_volume_get_name (volume);
848
escaped_name = escape_label_for_menu (name);
850
label = g_strdup_printf (_("Play Disc '%s'"), escaped_name);
851
g_free (escaped_name);
853
name = g_strdup_printf (_("device%d"), position);
855
action = gtk_action_new (name, label, NULL, NULL);
856
g_object_set (G_OBJECT (action),
857
"icon-name", icon_name,
858
"sensitive", !disabled, NULL);
859
gtk_action_group_add_action (totem->devices_action_group, action);
860
g_object_unref (action);
862
gtk_ui_manager_add_ui (totem->ui_manager, totem->devices_ui_id,
863
"/tmw-menubar/movie/devices-placeholder", name, name,
864
GTK_UI_MANAGER_MENUITEM, FALSE);
866
/* TODO: This can be made cleaner once bug #589842 is fixed */
867
menu_item_path = g_strdup_printf ("/tmw-menubar/movie/devices-placeholder/%s", name);
868
menu_item = gtk_ui_manager_get_widget (totem->ui_manager, menu_item_path);
869
g_free (menu_item_path);
871
if (menu_item != NULL)
872
gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menu_item), TRUE);
876
g_object_unref (icon);
878
if (disabled != FALSE) {
879
g_free (device_path);
883
g_object_set_data_full (G_OBJECT (action),
884
"device_path", device_path,
885
(GDestroyNotify) g_free);
887
g_signal_connect (G_OBJECT (action), "activate",
888
G_CALLBACK (on_play_disc_activate), totem);
892
add_drive_to_menu (GDrive *drive,
899
/* FIXME: We used to explicitly check whether it was a CD/DVD drive
901
* udi = g_volume_get_identifier (i->data, G_VOLUME_IDENTIFIER_KIND_HAL_UDI); */
902
if (g_drive_can_eject (drive) == FALSE)
905
/* Repeat for all the drive's volumes */
906
volumes = g_drive_get_volumes (drive);
908
for (i = volumes; i != NULL; i = i->next) {
909
GVolume *volume = i->data;
910
add_volume_to_menu (volume, drive, theme, position, totem);
911
g_object_unref (volume);
914
g_list_free (volumes);
918
update_drive_menu_items (GtkMenuItem *movie_menuitem, Totem *totem)
920
GList *drives, *mounts, *i;
924
/* Add any suitable devices to the menu */
927
theme = gtk_icon_theme_get_default ();
929
drives = g_volume_monitor_get_connected_drives (totem->monitor);
930
for (i = drives; i != NULL; i = i->next) {
931
GDrive *drive = i->data;
934
add_drive_to_menu (drive, theme, position, totem);
935
g_object_unref (drive);
937
g_list_free (drives);
939
/* Look for mounted archives */
940
mounts = g_volume_monitor_get_mounts (totem->monitor);
941
for (i = mounts; i != NULL; i = i->next) {
942
GMount *mount = i->data;
945
add_mount_to_menu (mount, theme, position, totem);
946
g_object_unref (mount);
948
g_list_free (mounts);
950
totem->drives_changed = FALSE;
954
on_movie_menu_select (GtkMenuItem *movie_menuitem, Totem *totem)
956
if (totem->drives_changed == FALSE)
960
gtk_ui_manager_remove_ui (totem->ui_manager, totem->devices_ui_id);
961
gtk_ui_manager_ensure_update (totem->ui_manager);
963
/* Create new ActionGroup */
964
if (totem->devices_action_group) {
965
gtk_ui_manager_remove_action_group (totem->ui_manager,
966
totem->devices_action_group);
967
g_object_unref (totem->devices_action_group);
969
totem->devices_action_group = gtk_action_group_new ("devices-action-group");
970
gtk_ui_manager_insert_action_group (totem->ui_manager,
971
totem->devices_action_group, -1);
973
update_drive_menu_items (movie_menuitem, totem);
975
gtk_ui_manager_ensure_update (totem->ui_manager);
979
on_g_volume_monitor_event (GVolumeMonitor *monitor,
983
totem->drives_changed = TRUE;
987
totem_setup_play_disc (Totem *totem)
991
item = gtk_ui_manager_get_widget (totem->ui_manager, "/tmw-menubar/movie");
992
g_signal_connect (G_OBJECT (item), "select",
993
G_CALLBACK (on_movie_menu_select), totem);
995
g_signal_connect (G_OBJECT (totem->monitor),
997
G_CALLBACK (on_g_volume_monitor_event), totem);
998
g_signal_connect (G_OBJECT (totem->monitor),
1000
G_CALLBACK (on_g_volume_monitor_event), totem);
1001
g_signal_connect (G_OBJECT (totem->monitor),
1003
G_CALLBACK (on_g_volume_monitor_event), totem);
1004
g_signal_connect (G_OBJECT (totem->monitor),
1006
G_CALLBACK (on_g_volume_monitor_event), totem);
1008
totem->drives_changed = TRUE;
1012
open_action_callback (GtkAction *action, Totem *totem)
1014
totem_action_open (totem);
1018
open_location_action_callback (GtkAction *action, Totem *totem)
1020
totem_action_open_location (totem);
1024
eject_action_callback (GtkAction *action, Totem *totem)
1026
totem_action_eject (totem);
1030
properties_action_callback (GtkAction *action, Totem *totem)
1032
totem_action_show_properties (totem);
1036
play_action_callback (GtkAction *action, Totem *totem)
1038
totem_action_play_pause (totem);
1041
G_GNUC_NORETURN void
1042
quit_action_callback (GtkAction *action, Totem *totem)
1044
totem_action_exit (totem);
1048
preferences_action_callback (GtkAction *action, Totem *totem)
1050
gtk_widget_show (totem->prefs);
1054
fullscreen_action_callback (GtkAction *action, Totem *totem)
1056
totem_action_fullscreen_toggle (totem);
1060
zoom_1_2_action_callback (GtkAction *action, Totem *totem)
1062
totem_action_set_scale_ratio (totem, 0.5);
1066
zoom_1_1_action_callback (GtkAction *action, Totem *totem)
1068
totem_action_set_scale_ratio (totem, 1);
1072
zoom_2_1_action_callback (GtkAction *action, Totem *totem)
1074
totem_action_set_scale_ratio (totem, 2);
1078
zoom_in_action_callback (GtkAction *action, Totem *totem)
1080
totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
1084
zoom_reset_action_callback (GtkAction *action, Totem *totem)
1086
totem_action_zoom_reset (totem);
1090
zoom_out_action_callback (GtkAction *action, Totem *totem)
1092
totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
1096
select_subtitle_action_callback (GtkAction *action, Totem *totem)
1098
totem_playlist_select_subtitle_dialog (totem->playlist,
1099
TOTEM_PLAYLIST_DIALOG_PLAYING);
1103
next_angle_action_callback (GtkAction *action, Totem *totem)
1105
totem_action_next_angle (totem);
1109
dvd_root_menu_action_callback (GtkAction *action, Totem *totem)
1111
bacon_video_widget_dvd_event (totem->bvw, BVW_DVD_ROOT_MENU);
1115
dvd_title_menu_action_callback (GtkAction *action, Totem *totem)
1117
bacon_video_widget_dvd_event (totem->bvw, BVW_DVD_TITLE_MENU);
1121
dvd_audio_menu_action_callback (GtkAction *action, Totem *totem)
1123
bacon_video_widget_dvd_event (totem->bvw, BVW_DVD_AUDIO_MENU);
1127
dvd_angle_menu_action_callback (GtkAction *action, Totem *totem)
1129
bacon_video_widget_dvd_event (totem->bvw, BVW_DVD_ANGLE_MENU);
1133
dvd_chapter_menu_action_callback (GtkAction *action, Totem *totem)
1135
bacon_video_widget_dvd_event (totem->bvw, BVW_DVD_CHAPTER_MENU);
1139
next_chapter_action_callback (GtkAction *action, Totem *totem)
1141
TOTEM_PROFILE (totem_action_next (totem));
1145
previous_chapter_action_callback (GtkAction *action, Totem *totem)
1147
TOTEM_PROFILE (totem_action_previous (totem));
1151
skip_forward_action_callback (GtkAction *action, Totem *totem)
1153
totem_action_seek_relative (totem, SEEK_FORWARD_OFFSET * 1000, FALSE);
1157
skip_backwards_action_callback (GtkAction *action, Totem *totem)
1159
totem_action_seek_relative (totem, SEEK_BACKWARD_OFFSET * 1000, FALSE);
1163
volume_up_action_callback (GtkAction *action, Totem *totem)
1165
totem_action_volume_relative (totem, VOLUME_UP_OFFSET);
1169
volume_down_action_callback (GtkAction *action, Totem *totem)
1171
totem_action_volume_relative (totem, VOLUME_DOWN_OFFSET);
1175
contents_action_callback (GtkAction *action, Totem *totem)
1177
totem_action_show_help (totem);
1181
about_action_callback (GtkAction *action, Totem *totem)
1183
char *backend_version, *description;
1185
const char *authors[] =
1187
"Bastien Nocera <hadess@hadess.net>",
1188
"Ronald Bultje <rbultje@ronald.bitfreak.net>",
1189
"Julien Moutte <julien@moutte.net> (GStreamer backend)",
1190
"Tim-Philipp M\303\274ller <tim\100centricular\056net> (GStreamer backend)",
1191
"Philip Withnall <philip@tecnocode.co.uk>",
1194
const char *artists[] = { "Jakub Steiner <jimmac@ximian.com>", NULL };
1195
#include "../help/totem-docs.h"
1196
char *license = totem_interface_get_license ();
1198
backend_version = bacon_video_widget_get_backend_name (totem->bvw);
1199
/* This lists the back-end type and version, such as
1200
* Movie Player using GStreamer 0.10.1 */
1201
description = g_strdup_printf (_("Movie Player using %s"), backend_version);
1203
gtk_show_about_dialog (GTK_WINDOW (totem->win),
1205
"copyright", _("Copyright \xc2\xa9 2002-2009 Bastien Nocera"),
1206
"comments", description,
1208
"documenters", documentation_credits,
1210
"translator-credits", _("translator-credits"),
1211
"logo-icon-name", "totem",
1213
"wrap-license", TRUE,
1214
"website-label", _("Totem Website"),
1215
"website", "http://projects.gnome.org/totem/",
1218
g_free (backend_version);
1219
g_free (description);
1224
totem_plugins_window_delete_cb (GtkWidget *window,
1228
gtk_widget_hide (window);
1234
totem_plugins_response_cb (GtkDialog *dialog,
1238
gtk_widget_hide (GTK_WIDGET (dialog));
1243
plugins_action_callback (GtkAction *action, Totem *totem)
1245
if (totem->plugins == NULL) {
1248
totem->plugins = gtk_dialog_new_with_buttons (_("Configure Plugins"),
1249
GTK_WINDOW (totem->win),
1250
GTK_DIALOG_DESTROY_WITH_PARENT,
1254
gtk_container_set_border_width (GTK_CONTAINER (totem->plugins), 5);
1255
gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (totem->plugins))), 2);
1257
g_signal_connect_object (G_OBJECT (totem->plugins),
1259
G_CALLBACK (totem_plugins_window_delete_cb),
1261
g_signal_connect_object (G_OBJECT (totem->plugins),
1263
G_CALLBACK (totem_plugins_response_cb),
1266
manager = peas_gtk_plugin_manager_new (NULL);
1267
gtk_widget_show_all (GTK_WIDGET (manager));
1268
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (totem->plugins))),
1269
manager, TRUE, TRUE, 0);
1270
gtk_window_set_default_size (GTK_WINDOW (totem->plugins), 600, 400);
1273
gtk_window_present (GTK_WINDOW (totem->plugins));
1277
repeat_mode_action_callback (GtkToggleAction *action, Totem *totem)
1279
totem_playlist_set_repeat (totem->playlist,
1280
gtk_toggle_action_get_active (action));
1284
shuffle_mode_action_callback (GtkToggleAction *action, Totem *totem)
1286
totem_playlist_set_shuffle (totem->playlist,
1287
gtk_toggle_action_get_active (action));
1291
show_controls_action_callback (GtkToggleAction *action, Totem *totem)
1295
show = gtk_toggle_action_get_active (action);
1297
/* Let's update our controls visibility */
1299
totem->controls_visibility = TOTEM_CONTROLS_VISIBLE;
1301
totem->controls_visibility = TOTEM_CONTROLS_HIDDEN;
1303
show_controls (totem, FALSE);
1307
show_sidebar_action_callback (GtkToggleAction *action, Totem *totem)
1309
if (totem_is_fullscreen (totem))
1312
totem_sidebar_toggle (totem, gtk_toggle_action_get_active (action));
1316
aspect_ratio_changed_callback (GtkRadioAction *action, GtkRadioAction *current, Totem *totem)
1318
totem_action_set_aspect_ratio (totem, gtk_radio_action_get_current_value (current));
1322
clear_playlist_action_callback (GtkAction *action, Totem *totem)
1324
totem_playlist_clear (totem->playlist);
1325
totem_action_set_mrl (totem, NULL, NULL);
1328
/* Show help in status bar when selecting (hovering over) a menu item. */
1330
menu_item_select_cb (GtkMenuItem *proxy, Totem *totem)
1333
const gchar *message;
1335
action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (proxy));
1336
g_return_if_fail (action != NULL);
1338
message = gtk_action_get_tooltip (action);
1340
totem_statusbar_push_help (TOTEM_STATUSBAR (totem->statusbar), message);
1344
menu_item_deselect_cb (GtkMenuItem *proxy, Totem *totem)
1346
totem_statusbar_pop_help (TOTEM_STATUSBAR (totem->statusbar));
1350
setup_action (Totem *totem, GtkAction *action)
1353
for (proxies = gtk_action_get_proxies (action); proxies != NULL; proxies = proxies->next) {
1354
if (GTK_IS_MENU_ITEM (proxies->data)) {
1355
g_signal_connect (proxies->data, "select", G_CALLBACK (menu_item_select_cb), totem);
1356
g_signal_connect (proxies->data, "deselect", G_CALLBACK (menu_item_deselect_cb), totem);
1363
setup_menu_items (Totem *totem)
1365
GList *action_groups;
1367
/* FIXME: We can remove this once GTK+ bug #574001 is fixed */
1368
for (action_groups = gtk_ui_manager_get_action_groups (totem->ui_manager);
1369
action_groups != NULL; action_groups = action_groups->next) {
1370
GtkActionGroup *action_group = GTK_ACTION_GROUP (action_groups->data);
1372
for (actions = gtk_action_group_list_actions (action_group); actions != NULL; actions = actions->next) {
1373
setup_action (totem, GTK_ACTION (actions->data));
1379
totem_ui_manager_setup (Totem *totem)
1381
totem->main_action_group = GTK_ACTION_GROUP (gtk_builder_get_object (totem->xml, "main-action-group"));
1382
totem->zoom_action_group = GTK_ACTION_GROUP (gtk_builder_get_object (totem->xml, "zoom-action-group"));
1384
/* FIXME: Moving these to GtkBuilder depends on bug #457631 */
1385
if (gtk_widget_get_direction (totem->win) == GTK_TEXT_DIR_RTL) {
1386
GtkActionGroup *action_group = GTK_ACTION_GROUP (gtk_builder_get_object (totem->xml, "skip-action-group"));
1389
action = gtk_action_group_get_action (action_group, "skip-forward");
1390
gtk_action_set_accel_path (action, "Left");
1392
action = gtk_action_group_get_action (action_group, "skip-backwards");
1393
gtk_action_set_accel_path (action, "Right");
1396
totem->ui_manager = GTK_UI_MANAGER (gtk_builder_get_object (totem->xml, "totem-ui-manager"));
1398
setup_menu_items (totem);
1400
totem->devices_action_group = NULL;
1401
totem->devices_ui_id = gtk_ui_manager_new_merge_id (totem->ui_manager);
1402
totem->languages_action_group = NULL;
1403
totem->languages_ui_id = gtk_ui_manager_new_merge_id (totem->ui_manager);
1404
totem->subtitles_action_group = NULL;
1405
totem->subtitles_ui_id = gtk_ui_manager_new_merge_id (totem->ui_manager);