1 /*
2 * * Copyright (C) 2009-2011 Ali <aliov@xfce.org>
3 * * Copyright (C) 2012-2017 Simon Steinbeiß <ochosi@xfce.org>
4 * * Copyright (C) 2012-2020 Sean Davis <bluesabre@xfce.org>
5 *
6 * Licensed under the GNU General Public License Version 2
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #ifdef HAVE_XF86_KEYSYM
32 #include <X11/XF86keysym.h>
33 #endif
34
35 #include <X11/Xatom.h>
36
37 #include <gdk/gdkx.h>
38 #include <gdk/gdkkeysyms.h>
39 #include <gtk/gtk.h>
40
41 #ifdef XFCE_DISABLE_DEPRECATED
42 #undef XFCE_DISABLE_DEPRECATED
43 #endif
44 #include <libxfce4util/libxfce4util.h>
45 #include <libxfce4ui/libxfce4ui.h>
46
47 #include <dbus/dbus-glib.h>
48
49 #include "src/common/parole-common.h"
50 #include "src/common/parole-rc-utils.h"
51 #include "src/common/parole-screensaver.h"
52 #include "src/common/parole-powermanager.h"
53
54 #include "src/dbus/parole-dbus.h"
55
56 #include "src/gst/gst-enum-types.h"
57 #include "src/gst/parole-gst.h"
58
59 #include "src/misc/parole-debug.h"
60 #include "src/misc/parole-file.h"
61 #include "src/misc/parole-filters.h"
62
63 #include "src/enum-gtypes.h"
64 #include "src/parole-about.h"
65 #include "src/parole-builder.h"
66 #include "src/parole-button.h"
67
68 #ifdef HAVE_CLUTTER
69 #include "src/parole-clutter.h"
70 #endif
71
72 #include "src/parole-conf.h"
73 #include "src/parole-conf-dialog.h"
74 #include "src/parole-disc.h"
75 #include "src/parole-mediachooser.h"
76 #include "src/parole-medialist.h"
77 #include "src/parole-shortcuts.h"
78 #include "src/parole-utils.h"
79
80 #include "src/parole-player.h"
81
82 int GTK_ICON_SIZE_ARTWORK_FALLBACK;
83
84 GSimpleAction *playpause_action;
85 GSimpleAction *previous_action;
86 GSimpleAction *next_action;
87 gboolean block_playlist_updates = FALSE;
88
89 /* Temporary reference to ParolePlayer to cover for GSimpleAction. */
90 ParolePlayer *parole_player = NULL;
91
92 static void
get_time_string(gchar * timestring,gint total_seconds)93 get_time_string(gchar *timestring, gint total_seconds) {
94 gint hours;
95 gint minutes;
96 gint seconds;
97
98 minutes = total_seconds / 60;
99 seconds = total_seconds % 60;
100 hours = minutes / 60;
101 minutes = minutes % 60;
102
103 if ( hours == 0 ) {
104 g_snprintf(timestring, 128, "%02i:%02i", minutes, seconds);
105 } else {
106 g_snprintf(timestring, 128, "%i:%02i:%02i", hours, minutes, seconds);
107 }
108 }
109
110 /*
111 * DBus Glib init
112 */
113 static void parole_player_dbus_class_init(ParolePlayerClass *klass);
114 static void parole_player_dbus_init(ParolePlayer *player);
115
116 static void parole_player_disc_selected_cb(ParoleDisc *disc,
117 const gchar *uri,
118 const gchar *device,
119 ParolePlayer *player);
120
121 static void parole_player_select_custom_subtitle(GtkMenuItem *widget, gpointer data);
122
123 static gboolean parole_overlay_expose_event(GtkWidget *widget, cairo_t *cr, gpointer user_data);
124
125 static gboolean parole_audiobox_expose_event(GtkWidget *w, GdkEventExpose *ev, ParolePlayer *player);
126
127 /*
128 * GtkBuilder Callbacks
129 */
130 void on_content_area_size_allocate(GtkWidget *widget,
131 GtkAllocation *allocation,
132 ParolePlayer *player);
133
134
135 gboolean parole_player_configure_event_cb(GtkWidget *widget,
136 GdkEventConfigure *ev,
137 ParolePlayer *player);
138
139 gboolean parole_player_range_button_press(GtkWidget *widget,
140 GdkEventButton *ev,
141 ParolePlayer *player);
142
143 gboolean parole_player_range_button_release(GtkWidget *widget,
144 GdkEventButton *ev,
145 ParolePlayer *player);
146
147 void parole_player_range_value_changed(GtkRange *range,
148 ParolePlayer *player);
149
150 void parole_player_playpause_action_cb(GSimpleAction *action);
151
152 void parole_player_pause_clicked(GtkButton *button,
153 ParolePlayer *player);
154
155 void parole_player_playlist_toggled_cb(GtkWidget *button,
156 ParolePlayer *player);
157
158 void parole_player_playlist_menu_toggled_cb(GtkWidget *button,
159 ParolePlayer *player);
160
161 void parole_player_next_action_cb(GSimpleAction *action);
162
163 void parole_player_previous_action_cb(GSimpleAction *action);
164
165 void parole_player_fullscreen_action_cb(GSimpleAction *action);
166
167 void parole_player_seekf_cb(GtkWidget *widget,
168 ParolePlayer *player,
169 gdouble seek);
170
171 void parole_player_seekb_cb(GtkWidget *widget,
172 ParolePlayer *player,
173 gdouble seek);
174
175 gboolean parole_player_window_state_event(GtkWidget *widget,
176 GdkEventWindowState *event,
177 ParolePlayer *player);
178
179 void parole_player_destroy_cb(GObject *window,
180 ParolePlayer *player);
181
182 gboolean parole_player_delete_event_cb(GtkWidget *widget,
183 GdkEvent *ev,
184 ParolePlayer *player);
185
186 void parole_player_reset_controls(ParolePlayer *player,
187 gboolean fullscreen);
188
189 /*Menu items callbacks*/
190 void parole_player_menu_open_location_cb(GtkWidget *widget,
191 ParolePlayer *player);
192
193 void parole_player_menu_add_cb(GtkWidget *widget,
194 ParolePlayer *player);
195
196 void parole_player_media_menu_select_cb(GtkMenuItem *widget,
197 ParolePlayer *player);
198
199 void parole_player_save_playlist_cb(GtkWidget *widget,
200 ParolePlayer *player);
201
202 void parole_player_menu_exit_cb(GtkWidget *widget,
203 ParolePlayer *player);
204
205 void parole_player_volume_up(GtkWidget *widget,
206 ParolePlayer *player);
207
208 void parole_player_volume_down(GtkWidget *widget,
209 ParolePlayer *player);
210
211 void parole_player_volume_mute(GtkWidget *widget,
212 ParolePlayer *player);
213
214 void parole_player_open_preferences_cb(GtkWidget *widget,
215 ParolePlayer *player);
216
217 void parole_player_volume_value_changed_cb(GtkScaleButton *widget,
218 gdouble value,
219 ParolePlayer *player);
220
221 gboolean parole_player_volume_scroll_event_cb(GtkWidget *widget,
222 GdkEventScroll *ev,
223 ParolePlayer *player);
224
225 static void parole_player_volume_popdown_cb(GtkWidget *widget,
226 ParolePlayer *player);
227
228 static void parole_player_clear_subtitles(ParolePlayer *player);
229
230 static void parole_player_clear_audio_tracks(ParolePlayer *player);
231
232 /*
233 * Aspect ratio
234 */
235 void ratio_none_toggled_cb(GtkWidget *widget,
236 ParolePlayer *player);
237
238 void ratio_auto_toggled_cb(GtkWidget *widget,
239 ParolePlayer *player);
240
241 void ratio_square_toggled_cb(GtkWidget *widget,
242 ParolePlayer *player);
243
244 void ratio_4_3_toggled_cb(GtkWidget *widget,
245 ParolePlayer *player);
246
247 void ratio_16_9_toggled_cb(GtkWidget *widget,
248 ParolePlayer *player);
249
250 void ratio_20_9_toggled_cb(GtkWidget *widget,
251 ParolePlayer *player);
252
253 void parole_player_set_playlist_visible(ParolePlayer *player,
254 gboolean visibility);
255
256 gboolean parole_player_gst_widget_button_press(GtkWidget *widget,
257 GdkEventButton *ev,
258 ParolePlayer *player);
259
260 gboolean parole_player_gst_widget_button_release(GtkWidget *widget,
261 GdkEventButton *ev,
262 ParolePlayer *player);
263
264 void
265 parole_player_schedule_hide_controls (ParolePlayer *player,
266 gint seconds);
267
268 gboolean
269 parole_player_gst_widget_motion_notify_event(GtkWidget *widget,
270 GdkEventMotion *ev,
271 ParolePlayer *player);
272
273 void parole_show_about(GtkWidget *widget,
274 ParolePlayer *player);
275
276 void parole_show_shortcuts(GtkWidget *widget,
277 ParolePlayer *player);
278
279 void parole_player_set_audiotrack_radio_menu_item_selected(
280 ParolePlayer *player,
281 gint audio_index);
282
283 void parole_player_set_subtitle_radio_menu_item_selected(
284 ParolePlayer *player,
285 gint sub_index);
286
287 void
288 parole_player_combo_box_audiotrack_changed_cb(GtkWidget *widget,
289 ParolePlayer *player);
290
291 void
292 parole_player_combo_box_subtitles_changed_cb(GtkWidget *widget,
293 ParolePlayer *player);
294
295 static void
296 parole_player_audiotrack_radio_menu_item_changed_cb(GtkWidget *widget,
297 ParolePlayer *player);
298
299 static void
300 parole_player_subtitles_radio_menu_item_changed_cb(GtkWidget *widget,
301 ParolePlayer *player);
302
303 static void
304 parole_player_dvd_chapter_count_change_cb(ParoleGst *gst,
305 gint chapter_count,
306 ParolePlayer *player);
307
308 static void parole_player_dvd_chapter_change_cb(ParoleGst *gst,
309 gint chapter_count,
310 ParolePlayer *player);
311
312 void parole_player_dvd_menu_activated(GtkMenuItem *widget,
313 ParolePlayer *player);
314
315 void parole_player_dvd_title_activated(GtkMenuItem *widget,
316 ParolePlayer *player);
317
318 void parole_player_dvd_subpicture_activated(GtkMenuItem *widget,
319 ParolePlayer *player);
320
321 void parole_player_dvd_audio_activated(GtkMenuItem *widget,
322 ParolePlayer *player);
323
324 void parole_player_dvd_angle_activated(GtkMenuItem *widget,
325 ParolePlayer *player);
326
327 void parole_player_dvd_chapter_activated(GtkMenuItem *widget,
328 ParolePlayer *player);
329
330 gboolean parole_player_key_press(GtkWidget *widget,
331 GdkEventKey *ev,
332 ParolePlayer *player);
333
334 void parole_player_widget_activate_action(GtkWidget *widget,
335 GSimpleAction *action);
336
337 static void parole_player_set_cursor_visible(ParolePlayer *player,
338 gboolean visible);
339
340 static gboolean
341 parole_player_handle_key_value (guint keyval,
342 guint state,
343 ParolePlayer *player);
344
345 gboolean parole_player_hide_controls(gpointer data);
346
347 static GtkTargetEntry target_entry[] = {
348 { "STRING", 0, 0 },
349 { "text/uri-list", 0, 1 },
350 };
351
352 /*
353 * End of GtkBuilder Callbacks
354 */
355
356 struct ParolePlayerPrivate {
357 DBusGConnection *bus;
358 ParoleMediaList *list;
359 ParoleDisc *disc;
360 ParoleScreenSaver *screen_saver;
361 GDBusConnection *connection;
362 guint32 inhibit_cookie;
363
364 ParoleConf *conf;
365 ParoleConfDialog *settings_dialog;
366
367 XfceSMClient *sm_client;
368 gchar *client_id;
369
370 #ifdef HAVE_XF86_KEYSYM
371 ParoleButton *button;
372 #endif
373
374 GtkFileFilter *video_filter;
375 GtkRecentManager *recent;
376
377 gdouble last_volume;
378
379 GtkWidget *window;
380 GtkWidget *playlist_nt;
381 GtkWidget *playlist_popover;
382 /* Parole Player layouts */
383 gboolean embedded;
384 gboolean full_screen;
385 gboolean mini_mode;
386 /* Remembered window sizes */
387 gint last_h, last_w;
388
389 /* Menubar */
390 GtkWidget *menu_bar;
391 GtkWidget *recent_menu;
392 GtkWidget *save_playlist;
393 GtkWidget *dvd_menu;
394 GtkWidget *chapters_menu;
395 GtkWidget *goto_position;
396 gboolean show_menubar;
397
398 /* Media Controls */
399 GtkWidget *control;
400 GtkWidget *previous_button;
401 GtkWidget *next_button;
402 GtkWidget *playpause_button;
403 GtkWidget *playpause_image;
404 GtkWidget *fullscreen_button;
405 GtkWidget *fullscreen_image;
406 GtkWidget *fullscreen_menu_item;
407 GtkWidget *label_elapsed;
408 GtkWidget *label_duration;
409 GtkWidget *label_divider;
410 GtkWidget *range;
411 GtkWidget *progressbar_buffering;
412 GtkWidget *volume;
413 GtkWidget *mute;
414 GtkWidget *showhide_playlist_menu_item;
415 GtkWidget *showhide_playlist_button;
416 GtkWidget *repeat_menu_item;
417 GtkWidget *shuffle_menu_item;
418 GtkWidget *revealer;
419
420 /* Infobar */
421 GtkWidget *infobar;
422 /* Audio Track */
423 GtkWidget *combobox_audiotrack;
424 GtkListStore *liststore_audiotrack;
425 GList *audio_list;
426 gboolean update_languages;
427 GtkWidget *audio_group;
428 GtkWidget *languages_menu;
429 /* Subtitle Track */
430 GtkWidget *combobox_subtitles;
431 GtkListStore *liststore_subtitles;
432 GList *subtitle_list;
433 gboolean updated_subs;
434 GtkWidget *subtitles_group;
435 GtkWidget *subtitles_menu_custom;
436 GtkWidget *subtitles_menu;
437
438 /* Output Widgets */
439 GtkWidget *eventbox_output;
440 /* Idle Logo */
441 GtkWidget *logo_image;
442 /* VideoBox (Gst Video Output) Widget */
443 GtkWidget *videobox;
444 /* AudioBox (Artwork, Title, Track, Album) Widgets */
445 GtkWidget *audiobox;
446 GtkWidget *audiobox_cover;
447 GtkWidget *audiobox_text;
448 GtkWidget *audiobox_title;
449 GtkWidget *audiobox_album;
450 GtkWidget *audiobox_artist;
451
452 /* Current media-list row reference */
453 GtkTreeRowReference *row;
454
455 /* GStreamer */
456 GtkWidget *gst;
457 ParoleMediaType current_media_type;
458 ParoleState state;
459 gboolean user_seeking;
460 gboolean internal_range_change;
461 gboolean buffering;
462 gboolean wait_for_gst_disc_info;
463
464 #ifdef HAVE_CLUTTER
465 GtkWidget *clutter;
466 gboolean use_clutter;
467 #endif
468
469 /* Actions */
470 GSimpleAction *media_next_action;
471 GSimpleAction *media_playpause_action;
472 GSimpleAction *media_previous_action;
473 GSimpleAction *media_fullscreen_action;
474 GSimpleAction *toggle_repeat_action;
475 GSimpleAction *toggle_shuffle_action;
476
477 gboolean exit;
478 };
479
480 enum {
481 PROP_0,
482 PROP_CLIENT_ID
483 };
484
G_DEFINE_TYPE_WITH_PRIVATE(ParolePlayer,parole_player,G_TYPE_OBJECT)485 G_DEFINE_TYPE_WITH_PRIVATE(ParolePlayer, parole_player, G_TYPE_OBJECT)
486
487 void parole_show_about(GtkWidget *widget, ParolePlayer *player) {
488 parole_about(GTK_WINDOW(player->priv->window));
489 }
490
parole_show_shortcuts(GtkWidget * widget,ParolePlayer * player)491 void parole_show_shortcuts(GtkWidget *widget, ParolePlayer *player) {
492 parole_shortcuts(GTK_WIDGET(player->priv->window));
493 }
494
ratio_none_toggled_cb(GtkWidget * widget,ParolePlayer * player)495 void ratio_none_toggled_cb(GtkWidget *widget, ParolePlayer *player) {
496 g_object_set(G_OBJECT(player->priv->conf),
497 "aspect-ratio", PAROLE_ASPECT_RATIO_NONE,
498 NULL);
499 }
500
ratio_auto_toggled_cb(GtkWidget * widget,ParolePlayer * player)501 void ratio_auto_toggled_cb(GtkWidget *widget, ParolePlayer *player) {
502 g_object_set(G_OBJECT(player->priv->conf),
503 "aspect-ratio", PAROLE_ASPECT_RATIO_AUTO,
504 NULL);
505 }
506
ratio_square_toggled_cb(GtkWidget * widget,ParolePlayer * player)507 void ratio_square_toggled_cb(GtkWidget *widget, ParolePlayer *player) {
508 g_object_set(G_OBJECT(player->priv->conf),
509 "aspect-ratio", PAROLE_ASPECT_RATIO_SQUARE,
510 NULL);
511 }
512
ratio_4_3_toggled_cb(GtkWidget * widget,ParolePlayer * player)513 void ratio_4_3_toggled_cb(GtkWidget *widget, ParolePlayer *player) {
514 g_object_set(G_OBJECT(player->priv->conf),
515 "aspect-ratio", PAROLE_ASPECT_RATIO_4_3,
516 NULL);
517 }
518
ratio_16_9_toggled_cb(GtkWidget * widget,ParolePlayer * player)519 void ratio_16_9_toggled_cb(GtkWidget *widget, ParolePlayer *player) {
520 g_object_set(G_OBJECT(player->priv->conf),
521 "aspect-ratio", PAROLE_ASPECT_RATIO_16_9,
522 NULL);
523 }
524
ratio_20_9_toggled_cb(GtkWidget * widget,ParolePlayer * player)525 void ratio_20_9_toggled_cb(GtkWidget *widget, ParolePlayer *player) {
526 g_object_set(G_OBJECT(player->priv->conf),
527 "aspect-ratio", PAROLE_ASPECT_RATIO_DVB,
528 NULL);
529 }
530
parole_player_widget_activate_action(GtkWidget * widget,GSimpleAction * action)531 void parole_player_widget_activate_action(GtkWidget *widget, GSimpleAction *action) {
532 g_action_activate(G_ACTION(action), NULL);
533 }
534
toggle_action_cb(GtkWidget * widget,GSimpleAction * action)535 static void toggle_action_cb(GtkWidget *widget, GSimpleAction *action) {
536 if (!block_playlist_updates)
537 g_simple_toggle_action_set_active(action,
538 !g_simple_toggle_action_get_active(action));
539 }
540
parole_player_get_playlist_visible(ParolePlayer * player)541 static gboolean parole_player_get_playlist_visible(ParolePlayer *player) {
542 return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(player->priv->showhide_playlist_button));
543 }
544
parole_player_get_volume_visible(ParolePlayer * player)545 static gboolean parole_player_get_volume_visible(ParolePlayer *player) {
546 GtkWidget *popup;
547
548 popup = gtk_scale_button_get_popup (GTK_SCALE_BUTTON (player->priv->volume));
549
550 return gtk_widget_get_visible (popup);
551 }
552
parole_player_set_playlist_visible(ParolePlayer * player,gboolean visibility)553 void parole_player_set_playlist_visible(ParolePlayer *player, gboolean visibility) {
554 if (visibility && player->priv->control != NULL) {
555 gtk_widget_show(gtk_widget_get_parent(player->priv->control));
556 gtk_revealer_set_reveal_child(GTK_REVEALER(player->priv->revealer), TRUE);
557 parole_player_set_cursor_visible(player, TRUE);
558 }
559
560 if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(player->priv->showhide_playlist_menu_item)) != visibility)
561 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(player->priv->showhide_playlist_menu_item), visibility);
562
563 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(player->priv->showhide_playlist_button)) != visibility)
564 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(player->priv->showhide_playlist_button), visibility);
565
566 if (!visibility)
567 parole_player_schedule_hide_controls (player, 1);
568 }
569
parole_player_playlist_menu_toggled_cb(GtkWidget * menu_item,ParolePlayer * player)570 void parole_player_playlist_menu_toggled_cb(GtkWidget *menu_item, ParolePlayer *player) {
571 parole_player_set_playlist_visible(player, gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_item)));
572 }
573
parole_player_playlist_toggled_cb(GtkWidget * button,ParolePlayer * player)574 void parole_player_playlist_toggled_cb(GtkWidget *button, ParolePlayer *player) {
575 parole_player_set_playlist_visible(player, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
576 }
577
578 static void
parole_player_change_range_value(ParolePlayer * player,gdouble value)579 parole_player_change_range_value(ParolePlayer *player, gdouble value) {
580 gchar pos_text[128];
581
582 if ( !player->priv->user_seeking ) {
583 player->priv->internal_range_change = TRUE;
584
585 gtk_range_set_value(GTK_RANGE(player->priv->range), value);
586
587 player->priv->internal_range_change = FALSE;
588 }
589
590 get_time_string(pos_text, value);
591 gtk_label_set_text(GTK_LABEL(player->priv->label_elapsed), pos_text);
592 }
593
594 static void
parole_player_reset(ParolePlayer * player)595 parole_player_reset(ParolePlayer *player) {
596 parole_gst_stop(PAROLE_GST(player->priv->gst));
597 player->priv->update_languages = TRUE;
598 gtk_window_set_title(GTK_WINDOW(player->priv->window), _("Parole Media Player"));
599 gtk_widget_hide(GTK_WIDGET(player->priv->dvd_menu));
600 player->priv->audio_list = NULL;
601 player->priv->subtitle_list = NULL;
602
603 gtk_widget_hide(GTK_WIDGET(player->priv->infobar));
604 parole_player_change_range_value(player, 0);
605
606 if ( player->priv->row ) {
607 parole_media_list_set_row_playback_state(player->priv->list, player->priv->row, PAROLE_MEDIA_STATE_NONE);
608 gtk_tree_row_reference_free(player->priv->row);
609 player->priv->row = NULL;
610 }
611
612 if (player->priv->current_media_type == PAROLE_MEDIA_TYPE_DVD) {
613 TRACE("CLEAR DVD LIST");
614 parole_media_list_clear_disc_list(player->priv->list);
615 TRACE("END CLEAR DVD LIST");
616 }
617 player->priv->current_media_type = PAROLE_MEDIA_TYPE_UNKNOWN;
618
619 parole_media_list_set_playlist_view(player->priv->list, PAROLE_MEDIA_LIST_PLAYLIST_VIEW_STANDARD);
620
621 g_simple_action_set_enabled(player->priv->toggle_repeat_action, TRUE);
622 g_simple_action_set_enabled(player->priv->toggle_shuffle_action, TRUE);
623 }
624
625 static void
parole_player_dvd_reset(ParolePlayer * player)626 parole_player_dvd_reset(ParolePlayer *player) {
627 if ( player->priv->row ) {
628 parole_media_list_set_row_playback_state(player->priv->list, player->priv->row, PAROLE_MEDIA_STATE_NONE);
629 gtk_tree_row_reference_free(player->priv->row);
630 player->priv->row = NULL;
631 }
632 }
633
634 void
parole_player_dvd_menu_activated(GtkMenuItem * widget,ParolePlayer * player)635 parole_player_dvd_menu_activated(GtkMenuItem *widget, ParolePlayer *player) {
636 parole_gst_send_navigation_command(PAROLE_GST(player->priv->gst), GST_DVD_ROOT_MENU);
637 }
638
639 void
parole_player_dvd_title_activated(GtkMenuItem * widget,ParolePlayer * player)640 parole_player_dvd_title_activated(GtkMenuItem *widget, ParolePlayer *player) {
641 parole_gst_send_navigation_command(PAROLE_GST(player->priv->gst), GST_DVD_TITLE_MENU);
642 }
643
644 void
parole_player_dvd_subpicture_activated(GtkMenuItem * widget,ParolePlayer * player)645 parole_player_dvd_subpicture_activated(GtkMenuItem *widget, ParolePlayer *player) {
646 parole_gst_send_navigation_command(PAROLE_GST(player->priv->gst), GST_DVD_SUBPICTURE_MENU);
647 }
648
649 void
parole_player_dvd_audio_activated(GtkMenuItem * widget,ParolePlayer * player)650 parole_player_dvd_audio_activated(GtkMenuItem *widget, ParolePlayer *player) {
651 parole_gst_send_navigation_command(PAROLE_GST(player->priv->gst), GST_DVD_AUDIO_MENU);
652 }
653
654 void
parole_player_dvd_angle_activated(GtkMenuItem * widget,ParolePlayer * player)655 parole_player_dvd_angle_activated(GtkMenuItem *widget, ParolePlayer *player) {
656 parole_gst_send_navigation_command(PAROLE_GST(player->priv->gst), GST_DVD_ANGLE_MENU);
657 }
658
659 void
parole_player_dvd_chapter_activated(GtkMenuItem * widget,ParolePlayer * player)660 parole_player_dvd_chapter_activated(GtkMenuItem *widget, ParolePlayer *player) {
661 parole_gst_send_navigation_command(PAROLE_GST(player->priv->gst), GST_DVD_CHAPTER_MENU);
662 }
663
664 static gboolean
parole_sublang_equal_lists(GList * orig,GList * new)665 parole_sublang_equal_lists (GList *orig, GList *new) {
666 GList *o, *n;
667 gboolean retval;
668
669 if ((orig == NULL && new != NULL) || (orig != NULL && new == NULL))
670 return FALSE;
671 if (orig == NULL && new == NULL)
672 return TRUE;
673
674 if (g_list_length (orig) != g_list_length (new))
675 return FALSE;
676
677 retval = TRUE;
678 o = orig;
679 n = new;
680 while (o != NULL && n != NULL && retval != FALSE) {
681 if (g_str_equal(o->data, n->data) == FALSE) {
682 retval = FALSE;
683 }
684 o = g_list_next(o);
685 n = g_list_next(n);
686 }
687
688 return retval;
689 }
690
691 static void
parole_player_clear_chapters(ParolePlayer * player)692 parole_player_clear_chapters(ParolePlayer *player) {
693 GList *menu_items, *menu_iter;
694 gint counter = 0;
695
696 /* Clear the chapter menu options */
697 menu_items = gtk_container_get_children(GTK_CONTAINER(player->priv->chapters_menu));
698
699 for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next(menu_iter)) {
700 if (counter >= 2)
701 gtk_widget_destroy(GTK_WIDGET(menu_iter->data));
702 counter++;
703 }
704 g_list_free(menu_items);
705 }
706
707 static void
parole_player_chapter_selection_changed_cb(GtkWidget * widget,ParolePlayer * player)708 parole_player_chapter_selection_changed_cb(GtkWidget *widget, ParolePlayer *player) {
709 gint chapter_id = atoi((char*)g_object_get_data(G_OBJECT(widget), "chapter-id"));
710 parole_gst_set_dvd_chapter(PAROLE_GST(player->priv->gst) , chapter_id);
711 }
712
713 static void
parole_player_update_chapters(ParolePlayer * player,gint chapter_count)714 parole_player_update_chapters(ParolePlayer *player, gint chapter_count) {
715 int chapter_id;
716 GtkWidget *menu_item;
717 parole_player_clear_chapters(player);
718
719 for (chapter_id=0; chapter_id < chapter_count; chapter_id++) {
720 menu_item = GTK_WIDGET(gtk_menu_item_new_with_label(g_strdup_printf(_("Chapter %i"), chapter_id+1)));
721 gtk_widget_show(menu_item);
722
723 g_object_set_data(G_OBJECT(menu_item), "chapter-id", g_strdup_printf("%i", chapter_id+1));
724
725 gtk_menu_shell_append(GTK_MENU_SHELL(player->priv->chapters_menu), menu_item);
726 g_signal_connect(menu_item, "activate",
727 G_CALLBACK(parole_player_chapter_selection_changed_cb), player);
728 }
729 }
730
731 static void
parole_player_clear_subtitles(ParolePlayer * player)732 parole_player_clear_subtitles(ParolePlayer *player) {
733 GtkTreeIter iter;
734 GList *menu_items, *menu_iter;
735 gint counter = 0;
736
737 /* Clear the InfoBar Combobox */
738 gtk_list_store_clear(player->priv->liststore_subtitles);
739 gtk_list_store_append(GTK_LIST_STORE(player->priv->liststore_subtitles), &iter);
740 gtk_list_store_set(GTK_LIST_STORE(player->priv->liststore_subtitles), &iter, 0, _("None"), -1);
741 gtk_combo_box_set_active(GTK_COMBO_BOX(player->priv->combobox_subtitles), 0);
742
743 /* Clear the subtitle menu options */
744 menu_items = gtk_container_get_children(GTK_CONTAINER(player->priv->subtitles_menu));
745 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(player->priv->subtitles_group), TRUE);
746
747 for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next(menu_iter)) {
748 if (counter >= 4)
749 gtk_widget_destroy(GTK_WIDGET(menu_iter->data));
750 counter++;
751 }
752 g_list_free(menu_items);
753 }
754
755 static void
parole_player_set_subtitles_list(ParolePlayer * player,GList * subtitle_list)756 parole_player_set_subtitles_list(ParolePlayer *player, GList *subtitle_list) {
757 GList *l;
758 gchar* language;
759
760 GtkTreeIter iter;
761 gint counter = 0;
762
763 GtkWidget *menu_item;
764
765 parole_player_clear_subtitles(player);
766
767 player->priv->subtitle_list = subtitle_list;
768
769 for (l = subtitle_list; l != NULL; l = l->next) {
770 language = g_strdup(l->data);
771
772 gtk_list_store_append(GTK_LIST_STORE(player->priv->liststore_subtitles), &iter);
773 gtk_list_store_set(GTK_LIST_STORE(player->priv->liststore_subtitles), &iter, 0, language, -1);
774
775 menu_item = gtk_radio_menu_item_new_with_label_from_widget(
776 GTK_RADIO_MENU_ITEM(player->priv->subtitles_group), language);
777 gtk_widget_show(menu_item);
778
779 gtk_menu_shell_append(GTK_MENU_SHELL(player->priv->subtitles_menu), menu_item);
780 g_signal_connect(menu_item, "activate",
781 G_CALLBACK(parole_player_subtitles_radio_menu_item_changed_cb), player);
782
783 g_free(language);
784
785 counter++;
786 }
787
788 if (g_list_length(subtitle_list) != 1) {
789 gtk_widget_show(player->priv->infobar);
790 }
791 }
792
793 static void
parole_player_clear_audio_tracks(ParolePlayer * player)794 parole_player_clear_audio_tracks(ParolePlayer *player) {
795 GList *menu_items, *menu_iter;
796 GtkWidget *empty_item;
797
798 gtk_list_store_clear(player->priv->liststore_audiotrack);
799 player->priv->audio_group = NULL;
800
801 /* Clear the subtitle menu options */
802
803 menu_items = gtk_container_get_children(GTK_CONTAINER(player->priv->languages_menu));
804
805 for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next(menu_iter))
806 gtk_widget_destroy(GTK_WIDGET(menu_iter->data));
807 g_list_free(menu_items);
808
809 empty_item = gtk_menu_item_new_with_label(_("Empty"));
810 gtk_widget_set_sensitive(empty_item, FALSE);
811 gtk_widget_show(empty_item);
812
813 gtk_menu_shell_append(GTK_MENU_SHELL(player->priv->languages_menu), empty_item);
814 }
815
816 static void
parole_player_set_audio_list(ParolePlayer * player,GList * audio_list)817 parole_player_set_audio_list(ParolePlayer *player, GList *audio_list) {
818 GList *menu_iter;
819 GList *l;
820 gchar* language;
821
822 GtkTreeIter iter;
823
824 GtkWidget *menu_item;
825
826 parole_player_clear_audio_tracks(player);
827
828 menu_iter = gtk_container_get_children(GTK_CONTAINER(player->priv->languages_menu));
829
830 gtk_widget_destroy(GTK_WIDGET(menu_iter->data));
831 g_list_free(menu_iter);
832
833 player->priv->audio_list = audio_list;
834
835 for (l = audio_list; l != NULL; l = l->next) {
836 language = g_strdup(l->data);
837
838 gtk_list_store_append(GTK_LIST_STORE(player->priv->liststore_audiotrack), &iter);
839 gtk_list_store_set(GTK_LIST_STORE(player->priv->liststore_audiotrack), &iter, 0, language, -1);
840
841 if (player->priv->audio_group == NULL) {
842 player->priv->audio_group = GTK_WIDGET(gtk_radio_menu_item_new_with_label(NULL, language));
843 gtk_widget_show(GTK_WIDGET(player->priv->audio_group));
844 gtk_menu_shell_append(GTK_MENU_SHELL(player->priv->languages_menu), GTK_WIDGET(player->priv->audio_group));
845 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(player->priv->audio_group), TRUE);
846
847 g_signal_connect(player->priv->audio_group, "activate",
848 G_CALLBACK(parole_player_audiotrack_radio_menu_item_changed_cb), player);
849 } else {
850 menu_item = gtk_radio_menu_item_new_with_label_from_widget(
851 GTK_RADIO_MENU_ITEM(player->priv->audio_group), language);
852 gtk_widget_show(menu_item);
853 gtk_menu_shell_append(GTK_MENU_SHELL(player->priv->languages_menu), menu_item);
854
855 g_signal_connect(menu_item, "activate",
856 G_CALLBACK(parole_player_audiotrack_radio_menu_item_changed_cb), player);
857 }
858
859 g_free(language);
860 }
861
862 gtk_combo_box_set_active(GTK_COMBO_BOX(player->priv->combobox_audiotrack), 0);
863
864 if (g_list_length(audio_list) >= 2) {
865 gtk_widget_set_sensitive(GTK_WIDGET(player->priv->combobox_audiotrack), TRUE);
866 gtk_widget_show(player->priv->infobar);
867 } else {
868 gtk_widget_set_sensitive(GTK_WIDGET(player->priv->combobox_audiotrack), FALSE);
869 }
870 }
871
872 static void
parole_player_update_audio_tracks(ParolePlayer * player,ParoleGst * gst)873 parole_player_update_audio_tracks(ParolePlayer *player, ParoleGst *gst) {
874 GList * list = gst_get_lang_list_for_type(gst, "AUDIO");
875
876 if (parole_sublang_equal_lists(player->priv->audio_list, list) == TRUE) {
877 return;
878 }
879
880 parole_player_set_audio_list(player, list);
881
882 g_free(list->data);
883 g_list_free(list);
884 list = NULL;
885 }
886
887 static void
parole_player_update_subtitles(ParolePlayer * player,ParoleGst * gst)888 parole_player_update_subtitles(ParolePlayer *player, ParoleGst *gst) {
889 GList * list = gst_get_lang_list_for_type(gst, "TEXT");
890
891 guint64 sub_index;
892 gboolean sub_enabled;
893
894 sub_index = 0;
895
896 g_object_get(G_OBJECT(player->priv->conf),
897 "enable-subtitle", &sub_enabled,
898 NULL);
899
900 if (sub_enabled)
901 sub_index = 1;
902
903 if (parole_sublang_equal_lists(player->priv->subtitle_list, list) == TRUE) {
904 if (g_list_length(list) == 0) {
905 parole_player_clear_subtitles(player);
906 }
907 return;
908 }
909
910 parole_player_set_subtitles_list(player, list);
911
912 gtk_combo_box_set_active(GTK_COMBO_BOX(player->priv->combobox_subtitles), sub_index);
913
914 if (g_list_length(list) != 1) {
915 gtk_widget_show(player->priv->infobar);
916 }
917 g_free(list->data);
918 g_list_free(list);
919 list = NULL;
920 }
921
922 static void
parole_player_update_languages(ParolePlayer * player,ParoleGst * gst)923 parole_player_update_languages(ParolePlayer *player, ParoleGst *gst) {
924 if (player->priv->update_languages == TRUE) {
925 if (gst_get_has_video(PAROLE_GST(player->priv->gst))) {
926 parole_player_update_audio_tracks(player, gst);
927 parole_player_update_subtitles(player, gst);
928
929 /* Enable custom subtitles for video as long as its not a DVD. */
930 gtk_widget_set_sensitive(player->priv->subtitles_menu_custom,
931 player->priv->current_media_type != PAROLE_MEDIA_TYPE_DVD);
932 } else {
933 gtk_widget_set_sensitive(player->priv->subtitles_menu_custom, FALSE);
934 }
935
936 player->priv->update_languages = FALSE;
937 }
938 }
939
940 static void
parole_player_show_audiobox(ParolePlayer * player)941 parole_player_show_audiobox(ParolePlayer *player) {
942 /* Only show the audiobox if we're sure there's no video playing and
943 visualizations are disabled. */
944 gtk_widget_hide(player->priv->logo_image);
945 if (!gst_get_has_video(PAROLE_GST(player->priv->gst)) &&
946 !gst_get_has_vis(PAROLE_GST(player->priv->gst))) {
947 gtk_widget_show(player->priv->audiobox);
948 gtk_widget_hide(player->priv->videobox);
949 } else {
950 gtk_widget_hide(player->priv->audiobox);
951 gtk_widget_show(player->priv->videobox);
952 }
953 }
954
955 /**
956 * parole_player_select_custom_subtitle:
957 * @widget : The #GtkMenuItem for selecting a custom subtitle file
958 * @data : The #ParolePlayer instance passed by the callback function
959 *
960 * Display the #FileChooserDialog for selecting a custom subtitle file and load
961 * the subtitles selected.
962 **/
963 static void
parole_player_select_custom_subtitle(GtkMenuItem * widget,gpointer data)964 parole_player_select_custom_subtitle(GtkMenuItem *widget, gpointer data) {
965 ParolePlayer *player;
966 ParoleFile *file;
967
968 GtkWidget *chooser;
969 GtkFileFilter *filter, *all_files;
970 gint response;
971
972 const gchar *folder;
973 gchar *sub = NULL;
974 gchar *uri = NULL;
975
976 player = PAROLE_PLAYER(data);
977
978 /* Build the FileChooser dialog for subtitle selection. */
979 chooser = gtk_file_chooser_dialog_new(_("Select Subtitle File"), NULL,
980 GTK_FILE_CHOOSER_ACTION_OPEN,
981 NULL,
982 NULL);
983 gtk_window_set_icon_name(GTK_WINDOW(chooser), "org.xfce.parole");
984 gtk_dialog_add_buttons(GTK_DIALOG(chooser),
985 _("Cancel"), GTK_RESPONSE_CANCEL,
986 _("Open"), GTK_RESPONSE_OK,
987 NULL);
988 gtk_dialog_set_default_response(GTK_DIALOG(chooser), GTK_RESPONSE_OK);
989
990 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(chooser), FALSE);
991 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(chooser), FALSE);
992
993 g_object_get(G_OBJECT(player->priv->conf),
994 "media-chooser-folder", &folder,
995 NULL);
996
997 if ( folder )
998 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), folder);
999
1000 /* Subtitle format filter */
1001 filter = gtk_file_filter_new();
1002 gtk_file_filter_set_name(filter, _("Subtitle Files"));
1003 gtk_file_filter_add_pattern(filter, "*.asc");
1004 gtk_file_filter_add_pattern(filter, "*.txt");
1005 gtk_file_filter_add_pattern(filter, "*.sub");
1006 gtk_file_filter_add_pattern(filter, "*.srt");
1007 gtk_file_filter_add_pattern(filter, "*.smi");
1008 gtk_file_filter_add_pattern(filter, "*.ssa");
1009 gtk_file_filter_add_pattern(filter, "*.ass");
1010 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter);
1011
1012 /* All files filter */
1013 all_files = gtk_file_filter_new();
1014 gtk_file_filter_set_name(all_files, _("All files"));
1015 gtk_file_filter_add_pattern(all_files, "*");
1016 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), all_files);
1017
1018 gtk_window_set_default_size(GTK_WINDOW(chooser), 680, 480);
1019
1020 /* Run the dialog, get the selected filename. */
1021 response = gtk_dialog_run(GTK_DIALOG(chooser));
1022 if ( response == GTK_RESPONSE_OK )
1023 sub = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser));
1024
1025 gtk_widget_destroy(chooser);
1026
1027 if ( sub ) {
1028 /* Get the current playing file uri. */
1029 uri = parole_gst_get_file_uri(PAROLE_GST(player->priv->gst));
1030
1031 /* Reset the player. */
1032 parole_player_reset(player);
1033
1034 if (g_str_has_prefix(uri, "file:/")) {
1035 TRACE("Trying to play media file %s", uri);
1036 TRACE("Trying to use subtitle file %s", sub);
1037 player->priv->updated_subs = TRUE;
1038
1039 file = parole_media_list_get_selected_file(player->priv->list);
1040
1041 /* Set the subtitles in gst as well as in the media list, for later
1042 retrieval. */
1043 if ( file ) {
1044 parole_file_set_custom_subtitles(file, sub);
1045 parole_gst_set_custom_subtitles(PAROLE_GST(player->priv->gst), sub);
1046 parole_gst_play_uri(PAROLE_GST(player->priv->gst), uri, sub);
1047 }
1048 }
1049
1050 g_free(sub);
1051 g_free(uri);
1052 }
1053 }
1054
1055 static void
parole_player_media_activated_cb(ParoleMediaList * list,GtkTreeRowReference * row,ParolePlayer * player)1056 parole_player_media_activated_cb(ParoleMediaList *list, GtkTreeRowReference *row, ParolePlayer *player) {
1057 ParoleFile *file;
1058 GtkTreeIter iter;
1059 GtkTreeModel *model;
1060
1061 model = gtk_tree_row_reference_get_model(row);
1062
1063 if (gtk_tree_model_get_iter(model, &iter, gtk_tree_row_reference_get_path(row))) {
1064 gtk_tree_model_get(model, &iter, DATA_COL, &file, -1);
1065
1066 if ( file ) {
1067 const gchar *sub = NULL;
1068 const gchar *uri;
1069 const gchar *directory = NULL;
1070 gint dvd_chapter;
1071
1072 uri = parole_file_get_uri(file);
1073 directory = parole_file_get_directory(file);
1074
1075 if (g_str_has_prefix(uri, "dvd")) {
1076 parole_player_dvd_reset(player);
1077 player->priv->row = gtk_tree_row_reference_copy(row);
1078 dvd_chapter = parole_file_get_dvd_chapter(file);
1079 parole_gst_set_dvd_chapter(PAROLE_GST(player->priv->gst), dvd_chapter);
1080 g_object_unref(file);
1081 return;
1082 }
1083 parole_player_reset(player);
1084 player->priv->row = gtk_tree_row_reference_copy(row);
1085
1086 if (g_str_has_prefix(uri, "file:/")) {
1087 if (parole_file_filter(player->priv->video_filter, file)) {
1088 sub = parole_file_get_custom_subtitles(file);
1089 parole_gst_set_custom_subtitles(PAROLE_GST(player->priv->gst), sub);
1090 if (sub == NULL)
1091 sub = parole_get_subtitle_path(uri);
1092 }
1093 }
1094 TRACE("Trying to play media file %s", uri);
1095 TRACE("File content type %s", parole_file_get_content_type(file));
1096
1097
1098 parole_gst_play_uri(PAROLE_GST(player->priv->gst),
1099 parole_file_get_uri(file),
1100 sub);
1101
1102 gtk_window_set_title(GTK_WINDOW(player->priv->window),
1103 parole_media_list_get_row_name(player->priv->list, player->priv->row));
1104
1105 if ( directory ) {
1106 g_object_set(G_OBJECT(player->priv->conf),
1107 "media-chooser-folder", directory,
1108 NULL);
1109 }
1110
1111 g_object_unref(file);
1112 }
1113 }
1114 }
1115
1116 static void
parole_player_disc_selected_cb(ParoleDisc * disc,const gchar * uri,const gchar * device,ParolePlayer * player)1117 parole_player_disc_selected_cb(ParoleDisc *disc, const gchar *uri, const gchar *device, ParolePlayer *player) {
1118 parole_player_reset(player);
1119 parole_gst_play_device_uri(PAROLE_GST(player->priv->gst), uri, device);
1120 player->priv->current_media_type = parole_gst_get_current_stream_type(PAROLE_GST(player->priv->gst));
1121
1122 if ( player->priv->current_media_type == PAROLE_MEDIA_TYPE_CDDA ) {
1123 player->priv->wait_for_gst_disc_info = TRUE;
1124 if ( player->priv->row ) {
1125 parole_media_list_set_row_playback_state(player->priv->list, player->priv->row, PAROLE_MEDIA_STATE_NONE);
1126 gtk_tree_row_reference_free(player->priv->row);
1127 player->priv->row = NULL;
1128 }
1129 TRACE("CLEAR PLAYLIST");
1130 parole_media_list_clear_list(player->priv->list);
1131 TRACE("END CLEAR PLAYLIST");
1132 } else if ( player->priv->current_media_type == PAROLE_MEDIA_TYPE_DVD ) {
1133 parole_media_list_set_playlist_view(player->priv->list, PAROLE_MEDIA_LIST_PLAYLIST_VIEW_DISC);
1134 gtk_widget_show(GTK_WIDGET(player->priv->dvd_menu));
1135 g_simple_action_set_enabled(player->priv->toggle_repeat_action, FALSE);
1136 g_simple_action_set_enabled(player->priv->toggle_shuffle_action, FALSE);
1137 }
1138 }
1139
1140 static void
parole_player_uri_opened_cb(ParoleMediaList * list,const gchar * uri,ParolePlayer * player)1141 parole_player_uri_opened_cb(ParoleMediaList *list, const gchar *uri, ParolePlayer *player) {
1142 parole_player_reset(player);
1143 parole_gst_play_uri(PAROLE_GST(player->priv->gst), uri, NULL);
1144 }
1145
1146 static void
parole_player_iso_opened_cb(ParoleMediaList * list,const gchar * uri,ParolePlayer * player)1147 parole_player_iso_opened_cb(ParoleMediaList *list, const gchar *uri, ParolePlayer *player) {
1148 parole_player_reset(player);
1149 parole_player_disc_selected_cb(NULL, uri, NULL, player);
1150 }
1151
1152 static void
parole_player_key_forward_cb(ParoleMediaList * list,GdkEventKey * event,ParolePlayer * player)1153 parole_player_key_forward_cb(ParoleMediaList *list, GdkEventKey *event, ParolePlayer *player) {
1154 parole_player_handle_key_value(event->keyval, event->state, player);
1155 gdk_event_free ((GdkEvent *)event);
1156 }
1157
1158 static void
parole_player_recent_menu_clear_activated_cb(GtkWidget * widget,ParolePlayer * player)1159 parole_player_recent_menu_clear_activated_cb(GtkWidget *widget, ParolePlayer *player) {
1160 GtkWidget *dlg;
1161 GtkWidget *clear_button;
1162 gint response;
1163
1164 dlg = gtk_message_dialog_new(GTK_WINDOW(player->priv->window),
1165 GTK_DIALOG_DESTROY_WITH_PARENT,
1166 GTK_MESSAGE_QUESTION,
1167 GTK_BUTTONS_NONE,
1168 NULL);
1169
1170 gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(dlg),
1171 g_strdup_printf("<big><b>%s</b></big>",
1172 _("Clear Recent Items")));
1173 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dlg),
1174 _("Are you sure you wish to clear your recent items history? This cannot be undone."));
1175
1176 gtk_dialog_add_button(GTK_DIALOG(dlg), _("Cancel"), 0);
1177 clear_button = gtk_dialog_add_button(GTK_DIALOG(dlg),
1178 "edit-clear",
1179 1);
1180 gtk_button_set_label(GTK_BUTTON(clear_button), _("Clear Recent Items"));
1181
1182 gtk_widget_show_all(dlg);
1183
1184 response = gtk_dialog_run(GTK_DIALOG(dlg));
1185 if (response == 1) {
1186 GList *items, *l;
1187
1188 items = gtk_recent_manager_get_items(player->priv->recent);
1189 for (l = items; l != NULL; l = l->next) {
1190 GtkRecentInfo *info = l->data;
1191
1192 if (gtk_recent_info_has_application(info, "parole"))
1193 gtk_recent_manager_remove_item(player->priv->recent,
1194 gtk_recent_info_get_uri(info),
1195 NULL);
1196 }
1197
1198 g_list_free_full(items, (GDestroyNotify)gtk_recent_info_unref);
1199 }
1200 gtk_widget_destroy(dlg);
1201 }
1202
1203 static void
parole_player_recent_menu_item_activated_cb(GtkWidget * widget,ParolePlayer * player)1204 parole_player_recent_menu_item_activated_cb(GtkWidget *widget, ParolePlayer *player) {
1205 gchar *uri;
1206 gchar *filename;
1207 gchar *filenames[] = {NULL, NULL};
1208 ParoleMediaList *list;
1209
1210 uri = gtk_recent_chooser_get_current_uri(GTK_RECENT_CHOOSER(widget));
1211
1212 filename = g_filename_from_uri(uri, NULL, NULL);
1213
1214 if (g_file_test(filename, G_FILE_TEST_EXISTS)) {
1215 gtk_recent_manager_add_item(player->priv->recent, uri);
1216
1217 filenames[0] = g_strdup(filename);
1218
1219 list = parole_player_get_media_list(player);
1220 parole_media_list_add_files(list, filenames, FALSE);
1221
1222 g_free(filenames[0]);
1223 }
1224
1225 g_free(filename);
1226 g_free(uri);
1227 }
1228
1229 static void
parole_player_media_cursor_changed_cb(ParoleMediaList * list,gboolean media_selected,ParolePlayer * player)1230 parole_player_media_cursor_changed_cb(ParoleMediaList *list, gboolean media_selected, ParolePlayer *player) {
1231 gboolean enabled;
1232
1233 /* Play/Pause */
1234 if (player->priv->state < PAROLE_STATE_PAUSED) {
1235 enabled = media_selected || !parole_media_list_is_empty(player->priv->list);
1236 gtk_widget_set_sensitive(player->priv->playpause_button, enabled);
1237 g_simple_action_set_enabled(player->priv->media_playpause_action, enabled);
1238 }
1239
1240 enabled = parole_media_list_get_playlist_count(player->priv->list) > 1;
1241
1242 /* Previous */
1243 gtk_widget_set_sensitive(player->priv->previous_button, enabled);
1244 g_simple_action_set_enabled(player->priv->media_previous_action, enabled);
1245
1246 /* Next */
1247 gtk_widget_set_sensitive(player->priv->next_button, enabled);
1248 g_simple_action_set_enabled(player->priv->media_next_action, enabled);
1249 }
1250
1251 static void
parole_player_media_progressed_cb(ParoleGst * gst,const ParoleStream * stream,gint64 value,ParolePlayer * player)1252 parole_player_media_progressed_cb(ParoleGst *gst, const ParoleStream *stream, gint64 value, ParolePlayer *player) {
1253 #ifdef DEBUG
1254 g_return_if_fail(value > 0);
1255 #endif
1256
1257 if (!player->priv->user_seeking) {
1258 parole_player_change_range_value(player, value);
1259 }
1260 }
1261
1262 static void
parole_player_seekable_notify(ParoleStream * stream,GParamSpec * spec,ParolePlayer * player)1263 parole_player_seekable_notify(ParoleStream *stream, GParamSpec *spec, ParolePlayer *player) {
1264 gboolean seekable;
1265
1266 g_object_get(G_OBJECT(stream),
1267 "seekable", &seekable,
1268 NULL);
1269
1270 gtk_widget_set_tooltip_text(GTK_WIDGET(player->priv->range), seekable ? NULL : _("Media stream is not seekable"));
1271 gtk_widget_set_sensitive(GTK_WIDGET(player->priv->range), seekable);
1272 }
1273
1274 static void
parole_player_set_playpause_button_from_stock(ParolePlayer * player,const gchar * stock_id)1275 parole_player_set_playpause_button_from_stock(ParolePlayer *player, const gchar *stock_id) {
1276 gchar *icon_name = NULL, *tooltip = NULL;
1277
1278 if (g_strcmp0(stock_id, "gtk-media-play") == 0) {
1279 icon_name = g_strdup("media-playback-start-symbolic");
1280 tooltip = _("Play");
1281 } else if (g_strcmp0(stock_id, "gtk-media-pause") == 0) {
1282 icon_name = g_strdup("media-playback-pause-symbolic");
1283 tooltip = _("Pause");
1284 }
1285
1286 gtk_image_set_from_icon_name(GTK_IMAGE(player->priv->playpause_image), icon_name, 24);
1287 gtk_widget_set_tooltip_text(GTK_WIDGET(player->priv->playpause_button), tooltip);
1288 }
1289
1290 static void
parole_player_save_uri(ParolePlayer * player,const ParoleStream * stream)1291 parole_player_save_uri(ParolePlayer *player, const ParoleStream *stream) {
1292 ParoleMediaType media_type;
1293 gchar *uri;
1294 gboolean save = TRUE;
1295 gchar **lines = NULL;
1296 guint i;
1297
1298 g_object_get(G_OBJECT(stream),
1299 "uri", &uri,
1300 NULL);
1301
1302 g_object_get(G_OBJECT(stream),
1303 "media-type", &media_type,
1304 NULL);
1305
1306 if ( media_type == PAROLE_MEDIA_TYPE_LOCAL_FILE ) {
1307 gtk_recent_manager_add_item(player->priv->recent, uri);
1308 goto out;
1309 }
1310
1311 lines = parole_get_history();
1312
1313 if (lines) {
1314 for (i = 0; lines[i]; i++) {
1315 if (!g_strcmp0(lines[i], uri)) {
1316 save = FALSE;
1317 break;
1318 }
1319 }
1320 }
1321
1322 if ( media_type != PAROLE_MEDIA_TYPE_CDDA && media_type != PAROLE_MEDIA_TYPE_DVD ) {
1323 if ( save ) {
1324 parole_insert_line_history(uri);
1325 }
1326 }
1327
1328 g_strfreev(lines);
1329 out:
1330 g_free(uri);
1331 }
1332
1333 static void
parole_player_playing(ParolePlayer * player,const ParoleStream * stream)1334 parole_player_playing(ParolePlayer *player, const ParoleStream *stream) {
1335 gint64 duration;
1336 gboolean seekable;
1337 gboolean live;
1338 gint height, width;
1339
1340 gtk_widget_set_sensitive(player->priv->playpause_button, TRUE);
1341
1342 parole_media_list_set_row_playback_state(player->priv->list, player->priv->row, PAROLE_MEDIA_STATE_PLAYING);
1343
1344 g_object_get(G_OBJECT(stream),
1345 "seekable", &seekable,
1346 "duration", &duration,
1347 "video-width", &width,
1348 "video-height", &height,
1349 "live", &live,
1350 NULL);
1351
1352 #ifdef HAVE_CLUTTER
1353 if (player->priv->use_clutter)
1354 parole_clutter_set_video_dimensions(PAROLE_CLUTTER(player->priv->clutter), width, height);
1355 #endif
1356
1357 if (player->priv->wait_for_gst_disc_info == TRUE) {
1358 parole_media_list_add_cdda_tracks(player->priv->list, parole_gst_get_num_tracks(PAROLE_GST(player->priv->gst)));
1359 player->priv->wait_for_gst_disc_info = FALSE;
1360 }
1361
1362 g_simple_action_set_enabled(player->priv->media_playpause_action, TRUE);
1363
1364 parole_player_set_playpause_button_from_stock(player, "gtk-media-pause");
1365
1366 gtk_widget_set_sensitive(player->priv->range, seekable);
1367
1368 player->priv->internal_range_change = TRUE;
1369 if (live || duration == 0) {
1370 parole_player_change_range_value(player, 0);
1371 gtk_widget_set_visible(player->priv->label_duration, FALSE);
1372 gtk_widget_set_visible(player->priv->label_divider, FALSE);
1373 gtk_widget_set_visible(player->priv->label_elapsed, FALSE);
1374 } else {
1375 gtk_range_set_range(GTK_RANGE(player->priv->range), 0, duration);
1376 gtk_widget_set_visible(player->priv->label_duration, TRUE);
1377 gtk_widget_set_visible(player->priv->label_divider, player->priv->mini_mode);
1378 gtk_widget_set_visible(player->priv->label_elapsed, TRUE);
1379 }
1380
1381 if (duration != 0) {
1382 gchar dur_text[128];
1383 get_time_string(dur_text, duration);
1384
1385 gtk_label_set_text(GTK_LABEL(player->priv->label_duration), dur_text);
1386 if ( player->priv->current_media_type != PAROLE_MEDIA_TYPE_DVD ) {
1387 parole_media_list_set_row_length(player->priv->list,
1388 player->priv->row,
1389 dur_text);
1390 }
1391 }
1392
1393 player->priv->internal_range_change = FALSE;
1394
1395 gtk_widget_set_tooltip_text(GTK_WIDGET(player->priv->range), seekable ? NULL : _("Media stream is not seekable"));
1396
1397 parole_player_save_uri(player, stream);
1398 parole_media_list_select_row(player->priv->list, player->priv->row);
1399 if (!parole_player_get_playlist_visible (player)) {
1400 gtk_widget_grab_focus(player->priv->gst);
1401 }
1402 parole_player_update_languages(player, PAROLE_GST(player->priv->gst));
1403
1404 parole_player_schedule_hide_controls(player, -1);
1405 }
1406
1407 static void
parole_player_paused(ParolePlayer * player)1408 parole_player_paused(ParolePlayer *player) {
1409 TRACE("Player paused");
1410
1411 parole_media_list_set_row_playback_state(player->priv->list, player->priv->row, PAROLE_MEDIA_STATE_PAUSED);
1412
1413 g_simple_action_set_enabled(player->priv->media_playpause_action, TRUE);
1414
1415 if (player->priv->user_seeking == FALSE) {
1416 parole_player_set_playpause_button_from_stock(player, "gtk-media-play");
1417 }
1418 }
1419
1420 static void
parole_player_quit(ParolePlayer * player)1421 parole_player_quit(ParolePlayer *player) {
1422 parole_media_list_save_list(player->priv->list);
1423 parole_gst_shutdown(PAROLE_GST(player->priv->gst));
1424 gtk_widget_destroy(player->priv->window);
1425 g_object_unref(player);
1426 gtk_main_quit();
1427 }
1428
1429 static void
parole_player_stopped(ParolePlayer * player)1430 parole_player_stopped(ParolePlayer *player) {
1431 GdkPixbuf *logo;
1432 gchar dur_text[128];
1433 TRACE("Player stopped");
1434
1435 g_simple_action_set_enabled(player->priv->media_playpause_action,
1436 parole_media_list_is_selected_row(player->priv->list) ||
1437 !parole_media_list_is_empty(player->priv->list));
1438
1439 gtk_window_set_title(GTK_WINDOW(player->priv->window), _("Parole Media Player"));
1440
1441 gtk_widget_hide(player->priv->videobox);
1442 gtk_widget_hide(player->priv->audiobox);
1443
1444 logo = gdk_pixbuf_new_from_file(g_strdup_printf("%s/replay.png", PIXMAPS_DIR), NULL);
1445 gtk_image_set_from_pixbuf(GTK_IMAGE(player->priv->logo_image), logo);
1446 gtk_widget_show(player->priv->logo_image);
1447
1448 get_time_string(dur_text, 0);
1449 gtk_label_set_text(GTK_LABEL(player->priv->label_duration), dur_text);
1450
1451 parole_player_change_range_value(player, 0);
1452 gtk_widget_set_sensitive(player->priv->range, FALSE);
1453
1454 parole_player_set_playpause_button_from_stock(player, "gtk-media-play");
1455
1456 parole_media_list_set_row_playback_state(player->priv->list, player->priv->row, PAROLE_MEDIA_STATE_NONE);
1457
1458 if ( player->priv->exit ) {
1459 parole_player_quit(player);
1460 }
1461 }
1462
1463 static void
parole_player_play_selected_row(ParolePlayer * player)1464 parole_player_play_selected_row(ParolePlayer *player) {
1465 GtkTreeRowReference *row;
1466
1467 row = parole_media_list_get_selected_row(player->priv->list);
1468
1469 if ( row == NULL )
1470 row = parole_media_list_get_first_row(player->priv->list);
1471
1472 if ( row )
1473 parole_player_media_activated_cb(player->priv->list, row, player);
1474 }
1475
1476 static void
parole_player_play_next(ParolePlayer * player,gboolean allow_shuffle)1477 parole_player_play_next(ParolePlayer *player, gboolean allow_shuffle) {
1478 gboolean repeat, shuffle;
1479 GtkTreeRowReference *row;
1480
1481 if ( player->priv->current_media_type == PAROLE_MEDIA_TYPE_DVD ) {
1482 parole_gst_next_dvd_chapter(PAROLE_GST(player->priv->gst));
1483 return;
1484 }
1485
1486 g_object_get(G_OBJECT(player->priv->conf),
1487 "shuffle", &shuffle,
1488 "repeat", &repeat,
1489 NULL);
1490
1491 if ( player->priv->row ) {
1492 parole_media_list_set_row_playback_state(player->priv->list, player->priv->row, PAROLE_MEDIA_STATE_NONE);
1493
1494 row = parole_media_list_get_next_row(player->priv->list, player->priv->row, repeat);
1495
1496 if ( row ) {
1497 parole_player_media_activated_cb(player->priv->list, row, player);
1498 return;
1499 } else {
1500 TRACE("No remaining media in the list");
1501 gtk_tree_row_reference_free(player->priv->row);
1502 player->priv->row = NULL;
1503 }
1504 }
1505
1506 parole_gst_stop(PAROLE_GST(player->priv->gst));
1507 }
1508
1509 static void
parole_player_play_prev(ParolePlayer * player)1510 parole_player_play_prev(ParolePlayer *player) {
1511 gboolean repeat;
1512 GtkTreeRowReference *row;
1513
1514 if ( player->priv->current_media_type == PAROLE_MEDIA_TYPE_DVD ) {
1515 parole_gst_prev_dvd_chapter(PAROLE_GST(player->priv->gst));
1516 return;
1517 }
1518
1519 g_object_get(G_OBJECT(player->priv->conf),
1520 "repeat", &repeat,
1521 NULL);
1522
1523 if ( player->priv->row ) {
1524 parole_media_list_set_row_playback_state(player->priv->list, player->priv->row, PAROLE_MEDIA_STATE_NONE);
1525
1526 row = parole_media_list_get_prev_row(player->priv->list, player->priv->row, repeat);
1527
1528 if ( row ) {
1529 parole_player_media_activated_cb(player->priv->list, row, player);
1530 return;
1531 } else {
1532 TRACE("No remaining media in the list");
1533 gtk_tree_row_reference_free(player->priv->row);
1534 player->priv->row = NULL;
1535 }
1536 }
1537
1538 parole_gst_stop(PAROLE_GST(player->priv->gst));
1539 }
1540
1541 static void
parole_player_reset_saver_changed(ParolePlayer * player,const ParoleStream * stream)1542 parole_player_reset_saver_changed(ParolePlayer *player, const ParoleStream *stream) {
1543 gboolean reset_saver;
1544
1545 TRACE("Start");
1546
1547 g_object_get(G_OBJECT(player->priv->conf),
1548 "reset-saver", &reset_saver,
1549 NULL);
1550
1551 if ( !reset_saver ) {
1552 parole_screen_saver_uninhibit(player->priv->screen_saver, GTK_WINDOW(player->priv->window));
1553 if (player->priv->inhibit_cookie > 0)
1554 parole_power_manager_uninhibit (player->priv->connection, player->priv->inhibit_cookie);
1555 player->priv->inhibit_cookie = 0;
1556 } else if ( player->priv->state == PAROLE_STATE_PLAYING ) {
1557 gboolean has_video;
1558
1559 g_object_get(G_OBJECT(stream),
1560 "has-video", &has_video,
1561 NULL);
1562
1563 if ( has_video ) {
1564 parole_screen_saver_inhibit (player->priv->screen_saver, GTK_WINDOW(player->priv->window));
1565 if (player->priv->inhibit_cookie == 0)
1566 player->priv->inhibit_cookie = parole_power_manager_inhibit (player->priv->connection);
1567 }
1568 } else {
1569 parole_screen_saver_uninhibit(player->priv->screen_saver, GTK_WINDOW(player->priv->window));
1570 if (player->priv->inhibit_cookie > 0)
1571 parole_power_manager_uninhibit (player->priv->connection, player->priv->inhibit_cookie);
1572 player->priv->inhibit_cookie = 0;
1573 }
1574 }
1575
1576 static void
parole_player_media_state_cb(ParoleGst * gst,const ParoleStream * stream,ParoleState state,ParolePlayer * player)1577 parole_player_media_state_cb(ParoleGst *gst, const ParoleStream *stream, ParoleState state, ParolePlayer *player) {
1578 PAROLE_DEBUG_ENUM("State callback", state, PAROLE_ENUM_TYPE_STATE);
1579
1580 player->priv->state = state;
1581 parole_player_reset_saver_changed(player, stream);
1582
1583 if ( state == PAROLE_STATE_PLAYING ) {
1584 parole_player_playing(player, stream);
1585 parole_player_show_audiobox(player);
1586 } else if ( state == PAROLE_STATE_PAUSED ) {
1587 parole_player_paused(player);
1588 } else if ( state == PAROLE_STATE_STOPPED ) {
1589 parole_player_stopped(player);
1590 /* PAROLE_STATE_ABOUT_TO_FINISH is used for continuous playback of audio CDs */
1591 } else if ( state == PAROLE_STATE_ABOUT_TO_FINISH ) {
1592 #ifdef DEBUG
1593 TRACE("***Playback about to finish***");
1594 #endif
1595 if ( player->priv->current_media_type == PAROLE_MEDIA_TYPE_DVD )
1596 parole_player_play_next(player, TRUE);
1597 } else if ( state == PAROLE_STATE_PLAYBACK_FINISHED ) {
1598 #ifdef DEBUG
1599 TRACE("***Playback finished***");
1600 #endif
1601 parole_player_play_next(player, TRUE);
1602 }
1603 }
1604
1605 static void
on_infobar_close_clicked(GtkButton * button,ParolePlayer * player)1606 on_infobar_close_clicked(GtkButton *button, ParolePlayer *player) {
1607 gtk_widget_hide(player->priv->infobar);
1608 }
1609
1610 static void
parole_player_repeat_state_changed(GSimpleAction * simple,GVariant * value,ParolePlayer * player)1611 parole_player_repeat_state_changed(GSimpleAction *simple, GVariant *value, ParolePlayer *player) {
1612 gboolean active = g_simple_toggle_action_get_active(simple);
1613 block_playlist_updates = TRUE;
1614
1615 if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(player->priv->repeat_menu_item)) != active) {
1616 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(player->priv->repeat_menu_item), active);
1617 }
1618
1619 block_playlist_updates = FALSE;
1620 }
1621
1622 static void
parole_player_shuffle_state_changed(GSimpleAction * simple,GVariant * value,ParolePlayer * player)1623 parole_player_shuffle_state_changed(GSimpleAction *simple, GVariant *value, ParolePlayer *player) {
1624 gboolean active = g_simple_toggle_action_get_active(simple);
1625 block_playlist_updates = TRUE;
1626
1627 if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(player->priv->shuffle_menu_item)) != active) {
1628 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(player->priv->shuffle_menu_item), active);
1629 }
1630
1631 block_playlist_updates = FALSE;
1632 }
1633
1634 static void
parole_player_toggle_playpause(ParolePlayer * player)1635 parole_player_toggle_playpause(ParolePlayer *player) {
1636 if ( player->priv->state == PAROLE_STATE_PLAYING )
1637 parole_gst_pause(PAROLE_GST(player->priv->gst));
1638 else if ( player->priv->state == PAROLE_STATE_PAUSED )
1639 parole_gst_resume(PAROLE_GST(player->priv->gst));
1640 else
1641 parole_player_play_selected_row(player);
1642 }
1643
1644 void
parole_player_playpause_action_cb(GSimpleAction * action)1645 parole_player_playpause_action_cb(GSimpleAction *action) {
1646 parole_player_toggle_playpause(parole_player);
1647 }
1648
1649 void
parole_player_pause_clicked(GtkButton * button,ParolePlayer * player)1650 parole_player_pause_clicked(GtkButton *button, ParolePlayer *player) {
1651 parole_gst_pause(PAROLE_GST(player->priv->gst));
1652 }
1653
parole_player_next_action_cb(GSimpleAction * action)1654 void parole_player_next_action_cb(GSimpleAction *action) {
1655 parole_player_play_next(parole_player, TRUE);
1656 }
1657
parole_player_previous_action_cb(GSimpleAction * action)1658 void parole_player_previous_action_cb(GSimpleAction *action) {
1659 parole_player_play_prev(parole_player);
1660 }
1661
parole_player_get_action(ParolePlayerAction action)1662 GSimpleAction *parole_player_get_action(ParolePlayerAction action) {
1663 switch (action) {
1664 case PAROLE_PLAYER_ACTION_PLAYPAUSE:
1665 return playpause_action;
1666 break;
1667 case PAROLE_PLAYER_ACTION_PREVIOUS:
1668 return previous_action;
1669 break;
1670 case PAROLE_PLAYER_ACTION_NEXT:
1671 return next_action;
1672 break;
1673 default:
1674 return NULL;
1675 }
1676 }
1677
parole_player_seekf_cb(GtkWidget * widget,ParolePlayer * player,gdouble seek)1678 void parole_player_seekf_cb(GtkWidget *widget, ParolePlayer *player, gdouble seek) {
1679 seek = parole_gst_get_stream_position(PAROLE_GST(player->priv->gst) ) + seek;
1680 parole_gst_seek(PAROLE_GST(player->priv->gst), seek);
1681 parole_player_change_range_value(player, seek);
1682 }
1683
parole_player_seekb_cb(GtkWidget * widget,ParolePlayer * player,gdouble seek)1684 void parole_player_seekb_cb(GtkWidget *widget, ParolePlayer *player, gdouble seek) {
1685 seek = parole_gst_get_stream_position(PAROLE_GST(player->priv->gst) ) - seek;
1686 if ( seek < 0 ) { seek = 0; }
1687 parole_gst_seek(PAROLE_GST(player->priv->gst), seek);
1688 parole_player_change_range_value(player, seek);
1689 }
1690
1691 gboolean
parole_player_range_button_release(GtkWidget * widget,GdkEventButton * ev,ParolePlayer * player)1692 parole_player_range_button_release(GtkWidget *widget, GdkEventButton *ev, ParolePlayer *player) {
1693 ev->button = 2;
1694
1695 player->priv->user_seeking = FALSE;
1696
1697 return FALSE;
1698 }
1699
1700 gboolean
parole_player_range_button_press(GtkWidget * widget,GdkEventButton * ev,ParolePlayer * player)1701 parole_player_range_button_press(GtkWidget *widget, GdkEventButton *ev, ParolePlayer *player) {
1702 ev->button = 2;
1703
1704 player->priv->user_seeking = TRUE;
1705
1706 return FALSE;
1707 }
1708
1709 void
parole_player_range_value_changed(GtkRange * range,ParolePlayer * player)1710 parole_player_range_value_changed(GtkRange *range, ParolePlayer *player) {
1711 gdouble value;
1712
1713 if ( !player->priv->internal_range_change ) {
1714 value = gtk_range_get_value(GTK_RANGE(range));
1715 player->priv->user_seeking = TRUE;
1716 TRACE("Sending a seek request with value :%e", value);
1717 parole_gst_seek(PAROLE_GST(player->priv->gst), value);
1718 player->priv->user_seeking = FALSE;
1719 }
1720 }
1721
1722 static void
parole_player_error_cb(ParoleGst * gst,const gchar * error,ParolePlayer * player)1723 parole_player_error_cb(ParoleGst *gst, const gchar *error, ParolePlayer *player) {
1724 parole_dialog_error(GTK_WINDOW(player->priv->window), _("GStreamer backend error"), error);
1725 parole_screen_saver_uninhibit(player->priv->screen_saver, GTK_WINDOW(player->priv->window));
1726 parole_player_stopped(player);
1727 }
1728
1729 static gchar *
parole_player_get_filename_from_uri(gchar * uri)1730 parole_player_get_filename_from_uri(gchar *uri) {
1731 gchar *filename = NULL;
1732 gchar *scheme;
1733
1734 scheme = g_uri_parse_scheme(uri);
1735 if (strcmp(scheme, "http") == 0 || strcmp(scheme, "https") == 0 || strcmp(scheme, "ftp") == 0) {
1736 GRegex *regex;
1737 GMatchInfo *match_info;
1738
1739 regex = g_regex_new("^.*://.*/(?<filename>[^?#/]+)", 0, 0, NULL);
1740 g_regex_match(regex, uri, 0, &match_info);
1741 if (g_match_info_matches(match_info)) {
1742 gchar *word = g_match_info_fetch_named(match_info, "filename");
1743 filename = g_strdup(word);
1744 g_free(word);
1745 }
1746 g_match_info_free(match_info);
1747 g_regex_unref(regex);
1748 } else {
1749 gchar *decoded;
1750 decoded = g_filename_from_uri(uri, NULL, NULL);
1751 filename = g_path_get_basename(decoded);
1752 g_free(decoded);
1753 }
1754
1755 g_free(scheme);
1756
1757 return filename;
1758 }
1759
1760 static void
parole_player_media_tag_cb(ParoleGst * gst,const ParoleStream * stream,ParolePlayer * player)1761 parole_player_media_tag_cb(ParoleGst *gst, const ParoleStream *stream, ParolePlayer *player) {
1762 gchar *title;
1763 gchar *album;
1764 gchar *artist;
1765 gchar *year;
1766 gchar *uri;
1767 gchar *filename;
1768 GdkPixbuf *image = NULL;
1769
1770 if ( player->priv->row ) {
1771 g_object_get(G_OBJECT(stream),
1772 "title", &title,
1773 "album", &album,
1774 "artist", &artist,
1775 "year", &year,
1776 "uri", &uri,
1777 NULL);
1778
1779 if ( title ) {
1780 parole_media_list_set_row_name(player->priv->list, player->priv->row, title);
1781 gtk_window_set_title(GTK_WINDOW(player->priv->window), title);
1782 gtk_label_set_markup(
1783 GTK_LABEL(player->priv->audiobox_title),
1784 g_markup_printf_escaped(
1785 "<span color='#F4F4F4'><b><big>%s</big></b></span>",
1786 title));
1787 g_free(title);
1788 } else {
1789 /* No ID3, no problem! Show the filename instead */
1790 filename = parole_player_get_filename_from_uri(uri);
1791 if ( filename ) {
1792 gtk_window_set_title(GTK_WINDOW(player->priv->window), filename);
1793 gtk_label_set_markup(
1794 GTK_LABEL(player->priv->audiobox_title),
1795 g_markup_printf_escaped(
1796 "<span color='#F4F4F4'><b><big>%s</big></b></span>",
1797 filename));
1798 g_free(filename);
1799 } else {
1800 gtk_window_set_title(GTK_WINDOW(player->priv->window), _("Parole Media Player"));
1801 gtk_label_set_markup(
1802 GTK_LABEL(player->priv->audiobox_title),
1803 g_markup_printf_escaped(
1804 "<span color='#F4F4F4'><b><big>%s</big></b></span>",
1805 _("Unknown Song")));
1806 }
1807 }
1808 g_free(uri);
1809
1810 if ( album ) {
1811 if (year)
1812 gtk_label_set_markup(
1813 GTK_LABEL(player->priv->audiobox_album),
1814 g_markup_printf_escaped(
1815 "<big><span color='#BBBBBB'><i>%s</i></span> <span color='#F4F4F4'>%s (%s)</span></big>",
1816 _("on"), album, year));
1817 else
1818 gtk_label_set_markup(
1819 GTK_LABEL(player->priv->audiobox_album),
1820 g_markup_printf_escaped(
1821 "<big><span color='#BBBBBB'><i>%s</i></span> <span color='#F4F4F4'>%s</span></big>",
1822 _("on"), album));
1823
1824 g_free(album);
1825 } else {
1826 gtk_label_set_markup(
1827 GTK_LABEL(player->priv->audiobox_album),
1828 g_markup_printf_escaped(
1829 "<big><span color='#BBBBBB'><i>%s</i></span> <span color='#F4F4F4'>%s</span></big>",
1830 _("on"), _("Unknown Album")));
1831 }
1832
1833 if (year)
1834 g_free(year);
1835
1836 if ( artist ) {
1837 gtk_label_set_markup(
1838 GTK_LABEL(player->priv->audiobox_artist),
1839 g_markup_printf_escaped(
1840 "<big><span color='#BBBBBB'><i>%s</i></span> <span color='#F4F4F4'>%s</span></big>",
1841 _("by"), artist));
1842 g_free(artist);
1843 } else {
1844 gtk_label_set_markup(
1845 GTK_LABEL(player->priv->audiobox_artist),
1846 g_markup_printf_escaped(
1847 "<big><span color='#BBBBBB'><i>%s</i></span> <span color='#F4F4F4'>%s</span></big>",
1848 _("by"), _("Unknown Artist")));
1849 }
1850
1851 image = parole_stream_get_image(G_OBJECT(stream));
1852 if (image) {
1853 gtk_image_set_from_pixbuf(GTK_IMAGE(player->priv->audiobox_cover), image);
1854 g_object_unref(image);
1855 } else {
1856 gtk_image_set_from_icon_name(GTK_IMAGE(player->priv->audiobox_cover),
1857 "audio-x-generic-symbolic",
1858 GTK_ICON_SIZE_ARTWORK_FALLBACK);
1859 }
1860 }
1861 }
1862
1863 static void
parole_player_buffering_cb(ParoleGst * gst,const ParoleStream * stream,gint percentage,ParolePlayer * player)1864 parole_player_buffering_cb(ParoleGst *gst, const ParoleStream *stream, gint percentage, ParolePlayer *player) {
1865 gchar *buff;
1866
1867 if ( percentage == 100 ) {
1868 player->priv->buffering = FALSE;
1869 parole_gst_resume(PAROLE_GST(player->priv->gst));
1870 gtk_widget_hide(player->priv->progressbar_buffering);
1871 gtk_widget_show(player->priv->label_duration);
1872 if ( player->priv->mini_mode )
1873 gtk_widget_show(player->priv->label_divider);
1874 else
1875 gtk_widget_show(player->priv->range);
1876 gtk_widget_show(player->priv->label_elapsed);
1877 } else {
1878 player->priv->buffering = TRUE;
1879
1880 if ( player->priv->state == PAROLE_STATE_PLAYING )
1881 parole_gst_pause(PAROLE_GST(player->priv->gst));
1882
1883 buff = g_strdup_printf("%s(%d%%)", _("Buffering"), percentage);
1884
1885 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(player->priv->progressbar_buffering), buff);
1886 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(player->priv->progressbar_buffering), (gdouble)percentage / 100);
1887 gtk_widget_hide(player->priv->label_duration);
1888 gtk_widget_hide(player->priv->label_divider);
1889 gtk_widget_hide(player->priv->range);
1890 gtk_widget_hide(player->priv->label_elapsed);
1891 gtk_widget_show(player->priv->progressbar_buffering);
1892 g_free(buff);
1893 }
1894 }
1895
1896 static void
parole_player_dvd_chapter_count_change_cb(ParoleGst * gst,gint chapter_count,ParolePlayer * player)1897 parole_player_dvd_chapter_count_change_cb(ParoleGst *gst, gint chapter_count, ParolePlayer *player) {
1898 gtk_tree_row_reference_free(player->priv->row);
1899 player->priv->row = NULL;
1900
1901 /* FIXME Cannot clear list prior to adding new chapters. */
1902 // parole_media_list_clear_list (player->priv->list);
1903
1904 parole_media_list_add_dvd_chapters(player->priv->list, chapter_count);
1905 parole_player_update_chapters(player, chapter_count);
1906 }
1907
1908 static void
parole_player_dvd_chapter_change_cb(ParoleGst * gst,gint chapter_count,ParolePlayer * player)1909 parole_player_dvd_chapter_change_cb(ParoleGst *gst, gint chapter_count, ParolePlayer *player) {
1910 parole_media_list_set_row_playback_state(player->priv->list, player->priv->row, PAROLE_MEDIA_STATE_NONE);
1911
1912 player->priv->row = parole_media_list_get_row_n(player->priv->list, chapter_count-1);
1913
1914 parole_media_list_set_row_playback_state(player->priv->list, player->priv->row, PAROLE_MEDIA_STATE_PLAYING);
1915 parole_media_list_select_row(player->priv->list, player->priv->row);
1916 }
1917
parole_player_delete_event_cb(GtkWidget * widget,GdkEvent * ev,ParolePlayer * player)1918 gboolean parole_player_delete_event_cb(GtkWidget *widget, GdkEvent *ev, ParolePlayer *player) {
1919 parole_window_busy_cursor(gtk_widget_get_window(GTK_WIDGET(player->priv->window)));
1920
1921 player->priv->exit = TRUE;
1922 parole_gst_terminate(PAROLE_GST(player->priv->gst));
1923
1924 return TRUE;
1925 }
1926
1927 void
parole_player_destroy_cb(GObject * window,ParolePlayer * player)1928 parole_player_destroy_cb(GObject *window, ParolePlayer *player) {
1929 }
1930
1931 gboolean
parole_player_window_state_event(GtkWidget * widget,GdkEventWindowState * event,ParolePlayer * player)1932 parole_player_window_state_event(GtkWidget *widget,
1933 GdkEventWindowState *event,
1934 ParolePlayer *player) {
1935 gboolean fullscreen = FALSE;
1936
1937 if (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
1938 /* Restore the previously saved window size if maximized */
1939 g_object_set(G_OBJECT(player->priv->conf),
1940 "window-width", player->priv->last_w,
1941 "window-height", player->priv->last_h,
1942 "window-maximized", TRUE,
1943 NULL);
1944 } else {
1945 g_object_set(G_OBJECT(player->priv->conf),
1946 "window-maximized", FALSE,
1947 NULL);
1948 }
1949
1950 if (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)
1951 fullscreen = TRUE;
1952
1953 if (player->priv->full_screen != fullscreen)
1954 parole_player_reset_controls(player, fullscreen);
1955
1956 return TRUE;
1957 }
1958
1959 /**
1960 * parole_player_reset_controls:
1961 * @player : the #ParolePlayer instance
1962 * @fullscreen : %TRUE if player should be fullscreen, else %FALSE
1963 *
1964 * Reset the player controls based on existing conditions.
1965 **/
1966 void
parole_player_reset_controls(ParolePlayer * player,gboolean fullscreen)1967 parole_player_reset_controls(ParolePlayer *player, gboolean fullscreen) {
1968 static gint current_page = 0;
1969
1970 gboolean always_hide_menubar = FALSE;
1971
1972 gint h, w;
1973
1974 g_object_get(G_OBJECT(player->priv->conf),
1975 "always-hide-menubar", &always_hide_menubar,
1976 "window-height", &h,
1977 "window-width", &w,
1978 NULL);
1979
1980 if ( player->priv->full_screen != fullscreen ) {
1981 /* If the player is in fullscreen mode, change to windowed mode. */
1982 if ( player->priv->full_screen ) {
1983 if (player->priv->show_menubar == TRUE)
1984 gtk_widget_show(player->priv->menu_bar);
1985 else if (always_hide_menubar == TRUE)
1986 gtk_widget_hide(player->priv->menu_bar);
1987
1988 gtk_menu_item_set_label(GTK_MENU_ITEM(player->priv->fullscreen_menu_item), _("_Fullscreen"));
1989 gtk_widget_set_tooltip_text(player->priv->fullscreen_button, _("Fullscreen"));
1990 gtk_image_set_from_icon_name(GTK_IMAGE(player->priv->fullscreen_image), "view-fullscreen-symbolic", 24);
1991
1992 gtk_window_unfullscreen(GTK_WINDOW(player->priv->window));
1993 gtk_notebook_set_current_page(GTK_NOTEBOOK(player->priv->playlist_nt), current_page);
1994 player->priv->full_screen = FALSE;
1995 } else {
1996 gtk_widget_hide(player->priv->menu_bar);
1997 gtk_menu_item_set_label(GTK_MENU_ITEM(player->priv->fullscreen_menu_item), _("Leave _Fullscreen"));
1998 gtk_widget_set_tooltip_text(player->priv->fullscreen_button, _("Leave Fullscreen"));
1999 gtk_image_set_from_icon_name(GTK_IMAGE(player->priv->fullscreen_image), "view-restore-symbolic", 24);
2000
2001 current_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(player->priv->playlist_nt));
2002
2003 gtk_window_fullscreen(GTK_WINDOW(player->priv->window));
2004 player->priv->full_screen = TRUE;
2005 }
2006 }
2007
2008 if ( player->priv->embedded ) {
2009 gtk_widget_hide(player->priv->menu_bar);
2010 gtk_widget_hide(player->priv->fullscreen_button);
2011 gtk_widget_hide(player->priv->showhide_playlist_button);
2012 } else {
2013 if ( player->priv->mini_mode ) {
2014 gtk_widget_hide(player->priv->menu_bar);
2015 gtk_widget_hide(player->priv->fullscreen_button);
2016 gtk_widget_hide(player->priv->audiobox_text);
2017 gtk_widget_hide(player->priv->showhide_playlist_button);
2018 gtk_widget_set_halign(player->priv->audiobox_cover, GTK_ALIGN_CENTER);
2019
2020 gtk_widget_hide(player->priv->range);
2021 gtk_widget_show(player->priv->label_divider);
2022
2023 gtk_window_resize(GTK_WINDOW(player->priv->window), 256, 256);
2024 gtk_widget_set_size_request(GTK_WIDGET(player->priv->window), 256, 256);
2025 gtk_window_set_default_size(GTK_WINDOW(player->priv->window), 256, 256);
2026 gtk_window_set_resizable(GTK_WINDOW(player->priv->window), FALSE);
2027 } else {
2028 gtk_widget_set_size_request(GTK_WIDGET(player->priv->window), -1, -1);
2029 gtk_window_set_default_size(GTK_WINDOW(player->priv->window), -1, -1);
2030 gtk_window_set_resizable(GTK_WINDOW(player->priv->window), TRUE);
2031
2032 gtk_widget_show(player->priv->audiobox_text);
2033 gtk_widget_show(player->priv->fullscreen_button);
2034 gtk_widget_hide(player->priv->label_divider);
2035 gtk_widget_show(player->priv->range);
2036 gtk_widget_show(player->priv->showhide_playlist_button);
2037 gtk_widget_set_halign(player->priv->audiobox_cover, GTK_ALIGN_END);
2038
2039 if ( !player->priv->full_screen ) {
2040 gtk_widget_show(player->priv->menu_bar);
2041 gtk_window_resize(GTK_WINDOW(player->priv->window), w, h);
2042 }
2043 }
2044 }
2045 }
2046
2047 void
parole_player_embedded(ParolePlayer * player)2048 parole_player_embedded(ParolePlayer *player) {
2049 if ( player->priv->embedded == TRUE )
2050 return;
2051
2052 player->priv->embedded = TRUE;
2053
2054 parole_player_reset_controls(player, player->priv->full_screen);
2055 }
2056
2057 void
parole_player_full_screen(ParolePlayer * player,gboolean fullscreen)2058 parole_player_full_screen(ParolePlayer *player, gboolean fullscreen) {
2059 if ( player->priv->full_screen == fullscreen )
2060 return;
2061
2062 parole_player_reset_controls(player, fullscreen);
2063 }
2064
parole_player_fullscreen_action_cb(GSimpleAction * action)2065 void parole_player_fullscreen_action_cb(GSimpleAction *action) {
2066 parole_player_full_screen(parole_player, !parole_player->priv->full_screen);
2067 }
2068
parole_player_hide_menubar_cb(GtkWidget * widget,ParolePlayer * player)2069 static void parole_player_hide_menubar_cb(GtkWidget *widget, ParolePlayer *player) {
2070 player->priv->show_menubar = !gtk_widget_get_visible(player->priv->menu_bar);
2071 if (!player->priv->full_screen)
2072 gtk_widget_set_visible(player->priv->menu_bar, player->priv->show_menubar);
2073 }
2074
parole_player_toggle_mini_mode_cb(GtkWidget * widget,ParolePlayer * player)2075 static void parole_player_toggle_mini_mode_cb(GtkWidget *widget, ParolePlayer *player) {
2076 gboolean active = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
2077 player->priv->mini_mode = active;
2078 parole_player_reset_controls(player, FALSE);
2079 }
2080
2081 static void
parole_player_show_menu(ParolePlayer * player,guint button,guint activate_time)2082 parole_player_show_menu(ParolePlayer *player, guint button, guint activate_time) {
2083 GtkWidget *menu, *mi;
2084 gboolean sensitive;
2085 GtkAccelGroup *accels = gtk_accel_group_new();
2086
2087 gtk_window_add_accel_group(GTK_WINDOW(player->priv->window), accels);
2088
2089 player->priv->current_media_type = parole_gst_get_current_stream_type(PAROLE_GST(player->priv->gst));
2090
2091 menu = gtk_menu_new();
2092
2093 /*Play menu item
2094 */
2095 mi = gtk_menu_item_new_with_mnemonic(player->priv->state == PAROLE_STATE_PLAYING ? _("_Pause"):_("_Play"));
2096
2097 g_object_get(G_OBJECT(player->priv->playpause_button),
2098 "sensitive", &sensitive,
2099 NULL);
2100
2101 gtk_widget_set_sensitive(mi, sensitive);
2102 gtk_widget_show(mi);
2103 g_signal_connect(G_OBJECT(mi), "activate",
2104 G_CALLBACK(parole_player_widget_activate_action),
2105 player->priv->media_playpause_action);
2106 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2107
2108 /*
2109 * Previous item in playlist.
2110 */
2111 mi = gtk_menu_item_new_with_mnemonic(_("_Previous"));
2112 gtk_widget_set_sensitive(mi, (player->priv->state >= PAROLE_STATE_PAUSED));
2113 gtk_widget_show(mi);
2114 g_signal_connect(G_OBJECT(mi), "activate",
2115 G_CALLBACK(parole_player_widget_activate_action),
2116 player->priv->media_previous_action);
2117 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2118
2119 /*
2120 * Next item in playlist.
2121 */
2122 mi = gtk_menu_item_new_with_mnemonic(_("_Next"));
2123 gtk_widget_set_sensitive(mi, (player->priv->state >= PAROLE_STATE_PAUSED));
2124 gtk_widget_show(mi);
2125 g_signal_connect(G_OBJECT(mi), "activate",
2126 G_CALLBACK(parole_player_widget_activate_action),
2127 player->priv->media_next_action);
2128 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2129
2130 /*
2131 * Un/Full screen
2132 */
2133 mi = gtk_menu_item_new_with_mnemonic(player->priv->full_screen ? _("_Leave Fullscreen"):_("_Fullscreen"));
2134 gtk_widget_show(mi);
2135 g_signal_connect(G_OBJECT(mi), "activate",
2136 G_CALLBACK(parole_player_widget_activate_action),
2137 player->priv->media_fullscreen_action);
2138 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2139
2140 if (!player->priv->full_screen) {
2141 mi = gtk_separator_menu_item_new();
2142 gtk_widget_show(GTK_WIDGET(mi));
2143 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2144
2145 /*
2146 * Un/Hide menubar
2147 */
2148 mi = gtk_check_menu_item_new_with_label(_("Show menubar"));
2149 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi), gtk_widget_get_visible(player->priv->menu_bar));
2150 g_signal_connect(mi, "activate",
2151 G_CALLBACK(parole_player_hide_menubar_cb), player);
2152 gtk_widget_add_accelerator(mi, "activate", accels,
2153 GDK_KEY_m, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
2154 gtk_widget_show(mi);
2155 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2156
2157 if ( player->priv->mini_mode ) {
2158 gtk_widget_set_sensitive(GTK_WIDGET(mi), FALSE);
2159 }
2160
2161 mi = gtk_separator_menu_item_new();
2162 gtk_widget_show(GTK_WIDGET(mi));
2163 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2164
2165 mi = gtk_check_menu_item_new_with_label(_("Mini Mode"));
2166 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi), player->priv->mini_mode);
2167 g_signal_connect(mi, "activate",
2168 G_CALLBACK(parole_player_toggle_mini_mode_cb), player);
2169 gtk_widget_show(mi);
2170 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2171 }
2172
2173 g_signal_connect_swapped(menu, "selection-done",
2174 G_CALLBACK(gtk_widget_destroy), menu);
2175
2176 #if GTK_CHECK_VERSION(3, 22, 0)
2177 gtk_menu_popup_at_pointer(GTK_MENU(menu), NULL);
2178 #else
2179 gtk_menu_popup(GTK_MENU(menu),
2180 NULL, NULL,
2181 NULL, NULL,
2182 button, activate_time);
2183 #endif
2184 }
2185
2186 gboolean
parole_player_gst_widget_button_press(GtkWidget * widget,GdkEventButton * ev,ParolePlayer * player)2187 parole_player_gst_widget_button_press(GtkWidget *widget, GdkEventButton *ev, ParolePlayer *player) {
2188 gboolean ret_val = FALSE;
2189 gboolean sensitive = FALSE;
2190 gint w, h;
2191
2192 if ( ev->type == GDK_2BUTTON_PRESS ) {
2193 g_action_activate(G_ACTION(player->priv->media_fullscreen_action), NULL);
2194 ret_val = TRUE;
2195 } else if (ev->button == 1 && gtk_widget_get_visible(player->priv->logo_image)) {
2196 /* Clicking on the play or replay logo will activate appropriate functionality */
2197 h = gtk_widget_get_allocated_height(widget);
2198 w = gtk_widget_get_allocated_width(widget);
2199
2200 if ( (ev->x > ((w / 2) - 128) && ev->x < ((w / 2) + 128)) &&
2201 (ev->y > ((h / 2) - 128) && ev->y < ((h / 2) + 128)) ) {
2202 g_object_get(G_OBJECT(player->priv->playpause_button),
2203 "sensitive", &sensitive,
2204 NULL);
2205
2206 if (sensitive)
2207 parole_player_toggle_playpause(player);
2208 else
2209 parole_media_list_open(player->priv->list);
2210 }
2211 }
2212
2213 return ret_val;
2214 }
2215
2216 gboolean
parole_player_gst_widget_button_release(GtkWidget * widget,GdkEventButton * ev,ParolePlayer * player)2217 parole_player_gst_widget_button_release(GtkWidget *widget, GdkEventButton *ev, ParolePlayer *player) {
2218 gboolean ret_val = FALSE;
2219
2220 if ( ev->button == 3 ) {
2221 parole_player_show_menu(player, ev->button, ev->time);
2222 gtk_widget_grab_focus(widget);
2223 ret_val = TRUE;
2224 } else if ( ev->button == 1 ) {
2225 gtk_widget_grab_focus(widget);
2226 ret_val = TRUE;
2227 }
2228
2229 return ret_val;
2230 }
2231
parole_player_hide_controls(gpointer data)2232 gboolean parole_player_hide_controls(gpointer data) {
2233 ParolePlayer *player;
2234
2235 TRACE("start");
2236
2237 player = PAROLE_PLAYER(data);
2238
2239 if (parole_player_get_playlist_visible (player))
2240 return FALSE;
2241
2242 if (parole_player_get_volume_visible (player))
2243 return FALSE;
2244
2245 gtk_revealer_set_reveal_child(GTK_REVEALER(player->priv->revealer), FALSE);
2246
2247 parole_player_set_cursor_visible(player, FALSE);
2248
2249 return FALSE;
2250 }
2251
2252 void
parole_player_schedule_hide_controls(ParolePlayer * player,gint seconds)2253 parole_player_schedule_hide_controls (ParolePlayer *player, gint seconds) {
2254 static gulong hide_timeout;
2255 int hide_controls_timeout;
2256
2257 if (hide_timeout != 0) {
2258 g_source_remove_by_user_data(player);
2259 hide_timeout = 0;
2260 }
2261
2262 if (player->priv->revealer == NULL)
2263 return;
2264 if (!gtk_revealer_get_reveal_child(GTK_REVEALER(player->priv->revealer)))
2265 return;
2266 if ( player->priv->state != PAROLE_STATE_PLAYING )
2267 return;
2268
2269 g_object_get(G_OBJECT(player->priv->conf),
2270 "hide-controls-timeout", &hide_controls_timeout,
2271 NULL);
2272 if (hide_controls_timeout == 0)
2273 return;
2274
2275 if (seconds < 0) {
2276 seconds = (gint)hide_controls_timeout;
2277 }
2278
2279 hide_timeout = g_timeout_add_seconds((guint)seconds,
2280 (GSourceFunc) parole_player_hide_controls, player);
2281
2282 return;
2283 }
2284
2285 gboolean
parole_player_gst_widget_motion_notify_event(GtkWidget * widget,GdkEventMotion * ev,ParolePlayer * player)2286 parole_player_gst_widget_motion_notify_event(GtkWidget *widget, GdkEventMotion *ev, ParolePlayer *player) {
2287 gtk_widget_show(gtk_widget_get_parent(player->priv->control));
2288
2289 parole_player_set_cursor_visible(player, TRUE);
2290
2291 if (!gtk_revealer_get_reveal_child(GTK_REVEALER(player->priv->revealer))) {
2292 gtk_revealer_set_reveal_child(GTK_REVEALER(player->priv->revealer), TRUE);
2293 }
2294
2295 parole_player_schedule_hide_controls (player, -1);
2296
2297 return FALSE;
2298 }
2299
2300 void
parole_player_menu_open_location_cb(GtkWidget * widget,ParolePlayer * player)2301 parole_player_menu_open_location_cb(GtkWidget *widget, ParolePlayer *player) {
2302 parole_media_list_open_location(player->priv->list);
2303 }
2304
2305 void
parole_player_menu_add_cb(GtkWidget * widget,ParolePlayer * player)2306 parole_player_menu_add_cb(GtkWidget *widget, ParolePlayer *player) {
2307 parole_media_list_open(player->priv->list);
2308 }
2309
2310 void
parole_player_save_playlist_cb(GtkWidget * widget,ParolePlayer * player)2311 parole_player_save_playlist_cb(GtkWidget *widget, ParolePlayer *player) {
2312 parole_media_list_save_cb(widget, player->priv->list);
2313 }
2314
2315 void
parole_player_media_menu_select_cb(GtkMenuItem * widget,ParolePlayer * player)2316 parole_player_media_menu_select_cb(GtkMenuItem *widget, ParolePlayer *player) {
2317 gtk_widget_set_sensitive(player->priv->save_playlist,
2318 !parole_media_list_is_empty(player->priv->list));
2319 }
2320
2321 static void
parole_player_playback_menu_select_cb(GtkMenuItem * widget,ParolePlayer * player)2322 parole_player_playback_menu_select_cb(GtkMenuItem *widget, ParolePlayer *player) {
2323 gtk_widget_set_sensitive(player->priv->goto_position,
2324 !parole_media_list_is_empty(player->priv->list));
2325 }
2326
parole_player_open_preferences_cb(GtkWidget * widget,ParolePlayer * player)2327 void parole_player_open_preferences_cb(GtkWidget *widget, ParolePlayer *player) {
2328 parole_conf_dialog_open(player->priv->settings_dialog, player->priv->window);
2329 }
2330
2331 void
parole_player_menu_exit_cb(GtkWidget * widget,ParolePlayer * player)2332 parole_player_menu_exit_cb(GtkWidget *widget, ParolePlayer *player) {
2333 parole_player_delete_event_cb(NULL, NULL, player);
2334 }
2335
2336 static void
parole_property_notify_cb_volume(ParoleGst * gst,GParamSpec * spec,ParolePlayer * player)2337 parole_property_notify_cb_volume(ParoleGst *gst, GParamSpec *spec, ParolePlayer *player) {
2338 gdouble volume;
2339 volume = parole_gst_get_volume(PAROLE_GST(player->priv->gst));
2340 gtk_scale_button_set_value(GTK_SCALE_BUTTON(player->priv->volume), volume);
2341 }
2342
2343 static void
parole_player_change_volume(ParolePlayer * player,gdouble value)2344 parole_player_change_volume(ParolePlayer *player, gdouble value) {
2345 parole_gst_set_volume(PAROLE_GST(player->priv->gst), value);
2346 }
2347
parole_player_volume_popdown_cb(GtkWidget * widget,ParolePlayer * player)2348 static void parole_player_volume_popdown_cb(GtkWidget *widget, ParolePlayer *player) {
2349 parole_player_schedule_hide_controls (player, 1);
2350 }
2351
2352 gboolean
parole_player_volume_scroll_event_cb(GtkWidget * widget,GdkEventScroll * ev,ParolePlayer * player)2353 parole_player_volume_scroll_event_cb(GtkWidget *widget, GdkEventScroll *ev, ParolePlayer *player) {
2354 gboolean ret_val = FALSE;
2355
2356 if ( ev->direction == GDK_SCROLL_UP ) {
2357 parole_player_volume_up(NULL, player);
2358 ret_val = TRUE;
2359 } else if ( ev->direction == GDK_SCROLL_DOWN ) {
2360 parole_player_volume_down(NULL, player);
2361 ret_val = TRUE;
2362 }
2363
2364 return ret_val;
2365 }
2366
2367 void
parole_player_volume_value_changed_cb(GtkScaleButton * widget,gdouble value,ParolePlayer * player)2368 parole_player_volume_value_changed_cb(GtkScaleButton *widget, gdouble value, ParolePlayer *player) {
2369 parole_player_change_volume(player, value);
2370
2371 /* Do not update the value unless it has changed! */
2372 if ((int)(value*100) != (int)(player->priv->last_volume*100)) {
2373 player->priv->last_volume = value;
2374 if ( value > 0.0 )
2375 g_object_set(G_OBJECT(player->priv->conf),
2376 "volume", (gint)(value * 100),
2377 NULL);
2378 }
2379 }
2380
2381 void
parole_player_volume_up(GtkWidget * widget,ParolePlayer * player)2382 parole_player_volume_up(GtkWidget *widget, ParolePlayer *player) {
2383 gdouble value;
2384 value = gtk_scale_button_get_value(GTK_SCALE_BUTTON(player->priv->volume));
2385 gtk_scale_button_set_value(GTK_SCALE_BUTTON(player->priv->volume), value + 0.05);
2386 }
2387
2388 void
parole_player_volume_down(GtkWidget * widget,ParolePlayer * player)2389 parole_player_volume_down(GtkWidget *widget, ParolePlayer *player) {
2390 gdouble value;
2391 value = gtk_scale_button_get_value(GTK_SCALE_BUTTON(player->priv->volume));
2392 gtk_scale_button_set_value(GTK_SCALE_BUTTON(player->priv->volume), value - 0.05);
2393 }
2394
parole_player_volume_mute(GtkWidget * widget,ParolePlayer * player)2395 void parole_player_volume_mute(GtkWidget *widget, ParolePlayer *player) {
2396 gint value;
2397 if (gtk_scale_button_get_value(GTK_SCALE_BUTTON(player->priv->volume)) == 0.0) {
2398 g_object_get(G_OBJECT(player->priv->conf),
2399 "volume", &value,
2400 NULL);
2401 gtk_menu_item_set_label(GTK_MENU_ITEM(player->priv->mute), _("Mute"));
2402 } else {
2403 value = 0;
2404 gtk_menu_item_set_label(GTK_MENU_ITEM(player->priv->mute), _("Unmute"));
2405 }
2406 gtk_scale_button_set_value (GTK_SCALE_BUTTON (player->priv->volume), (gdouble)(value)/100);
2407 }
2408
2409 static void
parole_player_sm_quit_requested_cb(ParolePlayer * player)2410 parole_player_sm_quit_requested_cb(ParolePlayer *player) {
2411 player->priv->exit = TRUE;
2412 parole_gst_terminate(PAROLE_GST(player->priv->gst));
2413 }
2414
2415 static void
parole_player_finalize(GObject * object)2416 parole_player_finalize(GObject *object) {
2417 ParolePlayer *player;
2418
2419 player = PAROLE_PLAYER(object);
2420
2421 TRACE("start");
2422
2423 dbus_g_connection_unref(player->priv->bus);
2424
2425 g_object_unref(player->priv->conf);
2426 g_object_unref(player->priv->video_filter);
2427 g_object_unref(player->priv->disc);
2428 g_object_unref(player->priv->screen_saver);
2429 g_object_unref(player->priv->connection);
2430
2431 if ( player->priv->client_id )
2432 g_free(player->priv->client_id);
2433
2434 g_object_unref(player->priv->sm_client);
2435
2436 #ifdef HAVE_XF86_KEYSYM
2437 if (player->priv->button)
2438 g_object_unref(player->priv->button);
2439 #endif
2440
2441 G_OBJECT_CLASS(parole_player_parent_class)->finalize(object);
2442 }
2443
parole_player_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)2444 static void parole_player_set_property(GObject *object,
2445 guint prop_id,
2446 const GValue *value,
2447 GParamSpec *pspec) {
2448 ParolePlayer *player;
2449 player = PAROLE_PLAYER(object);
2450
2451 switch (prop_id) {
2452 case PROP_CLIENT_ID:
2453 player->priv->client_id = g_value_dup_string(value);
2454 break;
2455 default:
2456 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
2457 break;
2458 }
2459 }
2460
parole_player_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)2461 static void parole_player_get_property(GObject *object,
2462 guint prop_id,
2463 GValue *value,
2464 GParamSpec *pspec) {
2465 ParolePlayer *player;
2466 player = PAROLE_PLAYER(object);
2467
2468 switch (prop_id) {
2469 case PROP_CLIENT_ID:
2470 g_value_set_string(value, player->priv->client_id);
2471 break;
2472 default:
2473 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
2474 break;
2475 }
2476 }
2477
2478 /**
2479 * Get the SM client
2480 **/
2481 static void
parole_player_constructed(GObject * object)2482 parole_player_constructed(GObject *object) {
2483 ParolePlayer *player;
2484 gchar *current_dir;
2485
2486 const gchar *restart_command[] = {
2487 "parole",
2488 "--new-instance",
2489 NULL
2490 };
2491
2492 player = PAROLE_PLAYER(object);
2493
2494 current_dir = g_get_current_dir();
2495
2496 player->priv->sm_client = xfce_sm_client_get_full(XFCE_SM_CLIENT_RESTART_NORMAL,
2497 XFCE_SM_CLIENT_PRIORITY_DEFAULT,
2498 player->priv->client_id,
2499 current_dir,
2500 restart_command,
2501 DESKTOPDIR "/org.xfce.Parole.desktop");
2502
2503 if (xfce_sm_client_connect(player->priv->sm_client, NULL)) {
2504 g_signal_connect_swapped(player->priv->sm_client, "quit-requested",
2505 G_CALLBACK(parole_player_sm_quit_requested_cb), player);
2506 }
2507
2508 g_free(current_dir);
2509 }
2510
2511 static void
parole_player_class_init(ParolePlayerClass * klass)2512 parole_player_class_init(ParolePlayerClass *klass) {
2513 GObjectClass *object_class = G_OBJECT_CLASS(klass);
2514
2515 object_class->constructed = parole_player_constructed;
2516 object_class->finalize = parole_player_finalize;
2517 object_class->set_property = parole_player_set_property;
2518 object_class->get_property = parole_player_get_property;
2519
2520
2521 /**
2522 * ParolePlayer:client-id:
2523 *
2524 * Sm Manager client ID
2525 * Since: 0.2.2
2526 **/
2527 g_object_class_install_property(object_class,
2528 PROP_CLIENT_ID,
2529 g_param_spec_string("client-id",
2530 NULL,
2531 NULL,
2532 NULL,
2533 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
2534
2535 parole_player_dbus_class_init(klass);
2536 }
2537
2538 /**
2539 * Configuration changed regarding
2540 * whether to Reset the screen saver counter
2541 * while playing movies or not.
2542 *
2543 */
2544 static void
parole_player_reset_saver_changed_cb(ParolePlayer * player)2545 parole_player_reset_saver_changed_cb(ParolePlayer *player) {
2546 const ParoleStream *stream;
2547
2548 stream = parole_gst_get_stream(PAROLE_GST(player->priv->gst));
2549 TRACE("Reset saver configuration changed");
2550 parole_player_reset_saver_changed(player, stream);
2551 }
2552
2553 static gboolean
parole_player_handle_key_value(guint keyval,guint state,ParolePlayer * player)2554 parole_player_handle_key_value(guint keyval, guint state, ParolePlayer *player) {
2555 /* Seek duration in seconds */
2556 gdouble seek_short = 10, seek_medium = 60, seek_long = 600;
2557
2558 gboolean ret_val = FALSE;
2559
2560 if (state & GDK_MOD1_MASK)
2561 return FALSE;
2562
2563 switch (keyval) {
2564 case GDK_KEY_f:
2565 case GDK_KEY_F:
2566 if ( player->priv->embedded != TRUE ) {
2567 g_action_activate(G_ACTION(player->priv->media_fullscreen_action), NULL);
2568 }
2569 ret_val = TRUE;
2570 break;
2571 case GDK_KEY_space:
2572 case GDK_KEY_p:
2573 case GDK_KEY_P:
2574 parole_player_toggle_playpause(player);
2575 ret_val = TRUE;
2576 break;
2577 case GDK_KEY_Right:
2578 /* Media seekable ?*/
2579 if (gtk_widget_get_sensitive(player->priv->range)) {
2580 if (state & GDK_CONTROL_MASK) {
2581 parole_player_seekf_cb(NULL, player, seek_medium);
2582 } else {
2583 parole_player_seekf_cb(NULL, player, seek_short);
2584 }
2585 }
2586 ret_val = TRUE;
2587 break;
2588 case GDK_KEY_Left:
2589 if (gtk_widget_get_sensitive(player->priv->range)) {
2590 if (state & GDK_CONTROL_MASK) {
2591 parole_player_seekb_cb(NULL, player, seek_medium);
2592 } else {
2593 parole_player_seekb_cb(NULL, player, seek_short);
2594 }
2595 }
2596 ret_val = TRUE;
2597 break;
2598 case GDK_KEY_Page_Down:
2599 if ( gtk_widget_get_sensitive(player->priv->range) ) {
2600 parole_player_seekb_cb(NULL, player, seek_long);
2601 }
2602 ret_val = TRUE;
2603 break;
2604 case GDK_KEY_Page_Up:
2605 if ( gtk_widget_get_sensitive(player->priv->range) ) {
2606 parole_player_seekf_cb(NULL, player, seek_long);
2607 }
2608 ret_val = TRUE;
2609 break;
2610 case GDK_KEY_Escape:
2611 parole_player_full_screen(player, FALSE);
2612 break;
2613 case GDK_KEY_m:
2614 if (state & GDK_CONTROL_MASK) {
2615 parole_player_hide_menubar_cb(NULL, player);
2616 }
2617 ret_val = TRUE;
2618 break;
2619 case GDK_KEY_n:
2620 case GDK_KEY_N:
2621 parole_player_play_next(player, TRUE);
2622 ret_val = TRUE;
2623 break;
2624 case GDK_KEY_b:
2625 case GDK_KEY_B:
2626 parole_player_play_prev(player);
2627 ret_val = TRUE;
2628 break;
2629 case GDK_KEY_q:
2630 case GDK_KEY_Q:
2631 if (state & GDK_CONTROL_MASK) {
2632 parole_player_quit(player);
2633 ret_val = TRUE;
2634 }
2635 break;
2636 #ifdef HAVE_XF86_KEYSYM
2637 case XF86XK_OpenURL:
2638 parole_player_full_screen(player, FALSE);
2639 parole_media_list_open_location(player->priv->list);
2640 break;
2641 #endif
2642 /*
2643 * Pass these to the media list and tell it to
2644 * grab the focus
2645 */
2646 case GDK_KEY_Up:
2647 case GDK_KEY_Down:
2648 if (!player->priv->full_screen && gtk_widget_get_visible(player->priv->playlist_nt)) {
2649 parole_media_list_grab_focus(player->priv->list);
2650 }
2651 break;
2652 case GDK_KEY_plus:
2653 case GDK_KEY_equal:
2654 parole_player_volume_up(NULL, player);
2655 break;
2656 case GDK_KEY_minus:
2657 parole_player_volume_down(NULL, player);
2658 break;
2659 case GDK_KEY_0:
2660 parole_player_volume_mute(NULL, player);
2661 break;
2662 default:
2663 break;
2664 }
2665
2666 return ret_val;
2667 }
2668
2669 static gboolean
parole_player_handle_key_press(GdkEventKey * ev,ParolePlayer * player)2670 parole_player_handle_key_press(GdkEventKey *ev, ParolePlayer *player) {
2671 GtkWidget *focused;
2672
2673 focused = gtk_window_get_focus(GTK_WINDOW(player->priv->window));
2674
2675 if ( focused ) {
2676 if (gtk_widget_is_ancestor(focused, player->priv->playlist_nt)) {
2677 return FALSE;
2678 }
2679 }
2680
2681 return parole_player_handle_key_value(ev->keyval, ev->state, player);
2682 }
2683
2684 gboolean
parole_player_key_press(GtkWidget * widget,GdkEventKey * ev,ParolePlayer * player)2685 parole_player_key_press(GtkWidget *widget, GdkEventKey *ev, ParolePlayer *player) {
2686 gboolean enabled;
2687
2688 switch (ev->keyval) {
2689 case GDK_KEY_F11:
2690 if ( player->priv->embedded != TRUE ) {
2691 g_action_activate(G_ACTION(player->priv->media_fullscreen_action), NULL);
2692 }
2693 return TRUE;
2694 case GDK_KEY_F9:
2695 if ( player->priv->full_screen == TRUE ) {
2696 enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(player->priv->showhide_playlist_button));
2697 parole_player_set_playlist_visible(player, !enabled);
2698 return TRUE;
2699 }
2700 default:
2701 break;
2702 }
2703
2704 #ifdef HAVE_XF86_KEYSYM
2705 g_object_get(G_OBJECT(player->priv->conf),
2706 "multimedia-keys", &enabled,
2707 NULL);
2708 if (enabled) {
2709 switch (ev->keyval) {
2710 case XF86XK_AudioPlay:
2711 parole_player_toggle_playpause(player);
2712 return TRUE;
2713 case XF86XK_AudioStop:
2714 parole_player_pause_clicked(NULL, player);
2715 return TRUE;
2716 case XF86XK_AudioRaiseVolume:
2717 parole_player_volume_up(NULL, player);
2718 return TRUE;
2719 case XF86XK_AudioLowerVolume:
2720 parole_player_volume_down(NULL, player);
2721 return TRUE;
2722 case XF86XK_AudioMute:
2723 parole_player_volume_mute(NULL, player);
2724 return TRUE;
2725 case XF86XK_AudioPrev:
2726 parole_player_play_prev(player);
2727 return TRUE;
2728 case XF86XK_AudioNext:
2729 parole_player_play_next(player, TRUE);
2730 return TRUE;
2731 default:
2732 break;
2733 }
2734 }
2735 #endif /* HAVE_XF86_KEYSYM */
2736
2737 return parole_player_handle_key_press (ev, player);
2738 }
2739
2740 #ifdef HAVE_XF86_KEYSYM
2741 static void
parole_player_button_pressed_cb(ParoleButton * button,ParoleButtonKey key,ParolePlayer * player)2742 parole_player_button_pressed_cb(ParoleButton *button, ParoleButtonKey key, ParolePlayer *player) {
2743 gboolean enabled;
2744
2745 g_object_get(G_OBJECT(player->priv->conf),
2746 "multimedia-keys", &enabled,
2747 NULL);
2748
2749 if (!enabled)
2750 return;
2751
2752 PAROLE_DEBUG_ENUM("Button Press:", key, ENUM_GTYPE_BUTTON_KEY);
2753
2754 switch (key) {
2755 case PAROLE_KEY_AUDIO_PLAY:
2756 parole_player_toggle_playpause(player);
2757 break;
2758 case PAROLE_KEY_AUDIO_STOP:
2759 parole_player_pause_clicked(NULL, player);
2760 break;
2761 case PAROLE_KEY_AUDIO_PREV:
2762 parole_player_play_prev(player);
2763 break;
2764 case PAROLE_KEY_AUDIO_NEXT:
2765 parole_player_play_next(player, TRUE);
2766 break;
2767 default:
2768 break;
2769 }
2770 }
2771 #endif
2772
2773 static void
parole_gst_set_default_aspect_ratio(ParolePlayer * player,GtkBuilder * builder)2774 parole_gst_set_default_aspect_ratio(ParolePlayer *player, GtkBuilder *builder) {
2775 ParoleAspectRatio ratio;
2776 const gchar *widget_name;
2777
2778 g_object_get(G_OBJECT(player->priv->conf),
2779 "aspect-ratio", &ratio,
2780 NULL);
2781
2782 switch (ratio) {
2783 case PAROLE_ASPECT_RATIO_NONE:
2784 widget_name = "ratio_none";
2785 break;
2786 case PAROLE_ASPECT_RATIO_AUTO:
2787 widget_name = "ratio_auto";
2788 break;
2789 case PAROLE_ASPECT_RATIO_SQUARE:
2790 widget_name = "ratio_square";
2791 break;
2792 case PAROLE_ASPECT_RATIO_16_9:
2793 widget_name = "ratio_16_9";
2794 break;
2795 case PAROLE_ASPECT_RATIO_4_3:
2796 widget_name = "ratio_4_3";
2797 break;
2798 case PAROLE_ASPECT_RATIO_DVB:
2799 widget_name = "ratio_20_9";
2800 break;
2801 default:
2802 g_warn_if_reached();
2803 return;
2804 }
2805
2806 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(builder, widget_name)), TRUE);
2807 }
2808
2809 static void
on_bug_report_clicked(GtkWidget * w,ParolePlayer * player)2810 on_bug_report_clicked(GtkWidget *w, ParolePlayer *player) {
2811 GtkWidget *dialog;
2812 #if GTK_CHECK_VERSION(3, 22, 0)
2813 if (!gtk_show_uri_on_window(GTK_WINDOW(player->priv->window),
2814 "https://docs.xfce.org/apps/parole/bugs",
2815 GDK_CURRENT_TIME,
2816 NULL)) {
2817 #else
2818 if (!gtk_show_uri(NULL, "https://docs.xfce.org/apps/parole/bugs", GDK_CURRENT_TIME, NULL)) {
2819 #endif
2820 dialog = gtk_message_dialog_new(GTK_WINDOW(player->priv->window),
2821 GTK_DIALOG_DESTROY_WITH_PARENT,
2822 GTK_MESSAGE_ERROR,
2823 GTK_BUTTONS_CLOSE,
2824 _("Unable to open default web browser"));
2825 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
2826 _("Please go to https://docs.xfce.org/apps/parole/bugs to report your bug."));
2827 gtk_dialog_run(GTK_DIALOG(dialog));
2828 gtk_widget_destroy(dialog);
2829 }
2830 }
2831
2832 static void
2833 on_contents_clicked(GtkWidget *w, ParolePlayer *player) {
2834 xfce_dialog_show_help_with_version(NULL, "parole", "start", NULL, PAROLE_VERSION_SHORT);
2835 }
2836
2837 static gboolean
2838 on_goto_position_clicked(GtkWidget *w, ParolePlayer *player) {
2839 GtkWidget *dialog;
2840 GtkWidget *vbox, *hbox, *cbox;
2841 GtkWidget *spin_hrs, *spin_mins, *spin_secs;
2842 GtkAdjustment *adjustment;
2843 gint response;
2844 gdouble position, duration = 0, current_position = 0;
2845 int hrs, mins, secs;
2846 int max_hrs, max_mins = 59;
2847 int cur_hrs, cur_mins, cur_secs;
2848
2849 /* Create dialog */
2850 dialog = gtk_dialog_new_with_buttons(_("Go to position"),
2851 GTK_WINDOW(player->priv->window),
2852 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_USE_HEADER_BAR,
2853 _("Cancel"), GTK_RESPONSE_CANCEL,
2854 _("Go"), GTK_RESPONSE_OK,
2855 NULL);
2856 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
2857 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
2858
2859 /* pack boxes and spinbutton */
2860 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
2861 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), vbox, TRUE, TRUE, 0);
2862 gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
2863
2864 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
2865 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
2866
2867 cbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
2868 gtk_box_set_center_widget(GTK_BOX(hbox), cbox);
2869
2870 /* Get the stream length and set that as maximum for hours and minutes */
2871 adjustment = gtk_range_get_adjustment(GTK_RANGE(player->priv->range));
2872 duration = gtk_adjustment_get_upper(adjustment);
2873 current_position = gtk_range_get_value(GTK_RANGE(player->priv->range));
2874 max_hrs = (int) duration/3600;
2875 if ( duration/60 <= 59 )
2876 max_mins = (int) duration/60;
2877
2878 spin_hrs = gtk_spin_button_new_with_range(0, max_hrs, 1);
2879 gtk_orientable_set_orientation (GTK_ORIENTABLE(spin_hrs), GTK_ORIENTATION_VERTICAL);
2880 gtk_entry_set_activates_default (GTK_ENTRY(spin_hrs), TRUE);
2881 spin_mins = gtk_spin_button_new_with_range(0, max_mins, 1);
2882 gtk_orientable_set_orientation (GTK_ORIENTABLE(spin_mins), GTK_ORIENTATION_VERTICAL);
2883 gtk_entry_set_activates_default (GTK_ENTRY(spin_mins), TRUE);
2884 spin_secs = gtk_spin_button_new_with_range(0, 59, 1);
2885 gtk_orientable_set_orientation (GTK_ORIENTABLE(spin_secs), GTK_ORIENTATION_VERTICAL);
2886 gtk_entry_set_activates_default (GTK_ENTRY(spin_secs), TRUE);
2887 gtk_box_pack_start(GTK_BOX(cbox), spin_hrs, FALSE, FALSE, 0);
2888 gtk_box_pack_start(GTK_BOX(cbox), gtk_label_new(":"), FALSE, FALSE, 0);
2889 gtk_box_pack_start(GTK_BOX(cbox), spin_mins, FALSE, FALSE, 0);
2890 gtk_box_pack_start(GTK_BOX(cbox), gtk_label_new(":"), FALSE, FALSE, 0);
2891 gtk_box_pack_start(GTK_BOX(cbox), spin_secs, FALSE, FALSE, 0);
2892
2893 if ( duration < 3600 )
2894 gtk_widget_set_sensitive(GTK_WIDGET(spin_hrs), FALSE);
2895 if ( duration < 60 )
2896 gtk_widget_set_sensitive(GTK_WIDGET(spin_mins), FALSE);
2897 if ( duration == 0 )
2898 gtk_widget_set_sensitive(GTK_WIDGET(spin_secs), FALSE);
2899
2900 if ( current_position != 0 ) {
2901 cur_hrs = (int) current_position/3600;
2902 cur_mins = (int) current_position/60 - cur_hrs*60;
2903 cur_secs = (int) current_position - cur_hrs*3600 - cur_mins*60;
2904 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_hrs), cur_hrs);
2905 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_mins), cur_mins);
2906 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_secs), cur_secs);
2907 }
2908
2909 // FIXME: Prevent the mouse-cursor and controls from hiding
2910 /* show dialog */
2911 gtk_widget_show_all(dialog);
2912 response = gtk_dialog_run(GTK_DIALOG(dialog));
2913 if (response == GTK_RESPONSE_OK) {
2914 /* update range according to the value */
2915 hrs = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_hrs));
2916 mins = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_mins));
2917 secs = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin_secs));
2918 position = hrs*3600 + mins*60 + secs;
2919 parole_gst_seek(PAROLE_GST(player->priv->gst), position);
2920 parole_player_change_range_value(player, position);
2921 }
2922
2923 gtk_widget_destroy(GTK_WIDGET(dialog));
2924
2925 return (response == GTK_RESPONSE_OK);
2926 }
2927
2928 /**
2929 *
2930 * Draw a simple rectangular GtkOverlay
2931 * using the theme's background and border-color
2932 * to keep it on top of the gst-video-widget with Gtk3.8 and above
2933 *
2934 * NOTE: Transparency is not supported, so there's also no fadeout.
2935 **/
2936 static gboolean
2937 parole_overlay_expose_event(GtkWidget *widget, cairo_t *cr, gpointer user_data) {
2938 GtkAllocation *allocation = g_new0(GtkAllocation, 1);
2939 GtkStyleContext *context;
2940
2941 gtk_widget_get_allocation(widget, allocation);
2942 cairo_rectangle(cr, 0, 0, allocation->width, allocation->height);
2943 g_free(allocation);
2944
2945 context = gtk_widget_get_style_context(GTK_WIDGET(widget));
2946 gtk_style_context_add_class(context, "background");
2947 gtk_style_context_add_class(context, "osd");
2948
2949 return FALSE;
2950 }
2951
2952 /* This function allows smoothly adjusting the window alignment with coverart */
2953 static gboolean
2954 parole_audiobox_expose_event(GtkWidget *w, GdkEventExpose *ev, ParolePlayer *player) {
2955 GtkAllocation *allocation = g_new0(GtkAllocation, 1);
2956 gboolean homogeneous;
2957
2958 /* Float the cover and text together in the middle if there is space */
2959 gtk_widget_get_allocation(w, allocation);
2960 homogeneous = allocation->width > 536;
2961 g_free(allocation);
2962
2963 /* Nothing to do if the homogeneous setting is already good */
2964 if (gtk_box_get_homogeneous(GTK_BOX(w)) == homogeneous)
2965 return FALSE;
2966
2967 gtk_box_set_homogeneous(GTK_BOX(w), homogeneous);
2968
2969 /* Expand the coverart if the parent box packing is homogeneous */
2970 gtk_box_set_child_packing(GTK_BOX(w),
2971 player->priv->audiobox_cover,
2972 homogeneous,
2973 TRUE,
2974 0,
2975 GTK_PACK_START);
2976
2977 return FALSE;
2978 }
2979
2980 void
2981 on_content_area_size_allocate(GtkWidget *widget, GtkAllocation *allocation, ParolePlayer *player) {
2982 g_return_if_fail(allocation != NULL);
2983
2984 gtk_widget_set_allocation(widget, allocation);
2985
2986 if (gtk_widget_get_realized(widget)) {
2987 gtk_widget_queue_draw(widget);
2988 }
2989 }
2990
2991 gboolean
2992 parole_player_configure_event_cb(GtkWidget *widget, GdkEventConfigure *ev, ParolePlayer *player) {
2993 gint old_w, old_h, new_w, new_h;
2994
2995 /* Get the current window size */
2996 gtk_window_get_size(GTK_WINDOW(widget), &new_w, &new_h);
2997
2998 if ( !player->priv->full_screen ) {
2999 /* Store the previously saved window size in case of maximize */
3000 g_object_get(G_OBJECT(player->priv->conf),
3001 "window-width", &old_w,
3002 "window-height", &old_h,
3003 NULL);
3004
3005 /* Configure gets run twice, only change on update */
3006 if (old_w != new_w || old_h != new_h) {
3007 player->priv->last_w = old_w;
3008 player->priv->last_h = old_h;
3009
3010 if ( !player->priv->mini_mode )
3011 g_object_set(G_OBJECT(player->priv->conf),
3012 "window-width", new_w,
3013 "window-height", new_h,
3014 NULL);
3015 }
3016 }
3017
3018 gtk_widget_set_size_request(player->priv->playlist_popover, -1, new_h - 60);
3019
3020 return FALSE;
3021 }
3022
3023 static void
3024 parole_player_drag_data_received_cb(GtkWidget *widget,
3025 GdkDragContext *drag_context,
3026 gint x,
3027 gint y,
3028 GtkSelectionData *data,
3029 guint info,
3030 guint drag_time,
3031 ParolePlayer *player) {
3032 gchar **uri_list;
3033 guint added = 0;
3034 guint i;
3035
3036 parole_window_busy_cursor(gtk_widget_get_window(widget));
3037
3038 uri_list = g_uri_list_extract_uris((const gchar *)gtk_selection_data_get_data(data));
3039 for (i = 0; uri_list[i] != NULL; i++) {
3040 gchar *path;
3041 path = g_filename_from_uri(uri_list[i], NULL, NULL);
3042 added += parole_media_list_add_by_path(player->priv->list, path, i == 0 ? TRUE : FALSE);
3043
3044 g_free(path);
3045 }
3046
3047 g_strfreev(uri_list);
3048
3049 parole_player_set_cursor_visible(player, TRUE);
3050 gtk_drag_finish(drag_context, added == i ? TRUE : FALSE, FALSE, drag_time);
3051 }
3052
3053 static void
3054 parole_player_set_cursor_visible(ParolePlayer *player, gboolean visible) {
3055 GdkWindow *gdkwindow;
3056 gdkwindow = gtk_widget_get_window(GTK_WIDGET(player->priv->eventbox_output));
3057
3058 if (visible) {
3059 parole_gst_set_cursor_visible(PAROLE_GST(player->priv->gst), TRUE);
3060 parole_window_normal_cursor(gdkwindow);
3061 } else if (gtk_window_is_active(GTK_WINDOW(player->priv->window))) {
3062 parole_gst_set_cursor_visible(PAROLE_GST(player->priv->gst), FALSE);
3063 parole_window_invisible_cursor(gdkwindow);
3064 }
3065 }
3066
3067 static void
3068 parole_player_window_notify_is_active(ParolePlayer *player) {
3069 if (!gtk_window_is_active(GTK_WINDOW(player->priv->window))) {
3070 parole_player_set_cursor_visible(player, TRUE);
3071 } else {
3072 parole_player_set_cursor_visible(player, FALSE);
3073 }
3074 }
3075
3076 /**
3077 *
3078 * Sets the _NET_WM_WINDOW_OPACITY_LOCKED wm hint
3079 * so window manager keep us opaque.
3080 *
3081 * Currently it is only supported by xfwm.
3082 *
3083 * NOTE: The widget has to be realized first.
3084 **/
3085 static void
3086 parole_player_set_wm_opacity_hint(GtkWidget *widget) {
3087 GdkScreen *gdkscreen;
3088 GdkDisplay *gdkdisplay;
3089 GdkWindow *gdkwindow;
3090 Display *xdisplay;
3091 Atom atom;
3092 char mode = 1;
3093
3094 gdkscreen = gtk_widget_get_screen(widget);
3095 gdkdisplay = gdk_screen_get_display(gdkscreen);
3096
3097 xdisplay = GDK_DISPLAY_XDISPLAY(gdkdisplay);
3098
3099 atom = XInternAtom(xdisplay, "_NET_WM_WINDOW_OPACITY_LOCKED", TRUE);
3100
3101 if ( atom == None )
3102 return;
3103
3104 gdkwindow = gtk_widget_get_window(widget);
3105
3106 XChangeProperty(xdisplay, gdk_x11_window_get_xid(gdkwindow),
3107 atom, XA_CARDINAL,
3108 32, PropModeAppend,
3109 (guchar *) &mode,
3110 1);
3111 }
3112
3113 static void
3114 parole_player_init(ParolePlayer *player) {
3115 /* Builder */
3116 GtkBuilder *builder;
3117
3118 /* Recent Menu */
3119 GtkRecentFilter *recent_filter;
3120 GtkWidget *recent_menu;
3121 GtkWidget *recent_separator;
3122 GtkWidget *clear_recent;
3123
3124 /* Help Menu */
3125 GtkWidget *bug_report, *contents;
3126
3127 /* Language Infobar */
3128 GtkWidget *hbox_infobar;
3129 GtkWidget *content_area;
3130 GtkWidget *audiotrack_box, *audiotrack_label;
3131 GtkWidget *subtitle_box, *subtitle_label;
3132 GtkWidget *infobar_close, *close_icon;
3133 GtkCellRenderer *cell, *sub_cell;
3134
3135 /* Content Area */
3136 GtkWidget *controls_overlay;
3137 GtkWidget *controls_parent;
3138 GtkWidget *play_box;
3139 GdkPixbuf *logo;
3140
3141 /* Player Controls */
3142 GList *widgets;
3143
3144 /* Properties */
3145 gchar *videosink = NULL;
3146 gint w, h;
3147 gboolean maximized;
3148 gboolean always_hide_menubar = FALSE;
3149 gint volume;
3150
3151
3152 g_setenv("PULSE_PROP_media.role", "video", TRUE);
3153
3154 player->priv = parole_player_get_instance_private(player);
3155
3156 player->priv->client_id = NULL;
3157 player->priv->sm_client = NULL;
3158
3159 player->priv->bus = parole_g_session_bus_get();
3160
3161 player->priv->current_media_type = PAROLE_MEDIA_TYPE_UNKNOWN;
3162
3163 player->priv->video_filter = parole_get_supported_video_filter();
3164 g_object_ref_sink(player->priv->video_filter);
3165
3166 builder = parole_builder_get_main_interface();
3167
3168 /* ParoleConf */
3169 player->priv->conf = parole_conf_new();
3170 player->priv->settings_dialog = parole_conf_dialog_new();
3171
3172 g_signal_connect_swapped(player->priv->conf, "notify::reset-saver",
3173 G_CALLBACK(parole_player_reset_saver_changed_cb), player);
3174
3175 /* ParoleGst */
3176 player->priv->gst = parole_gst_new(player->priv->conf);
3177
3178 /* ParoleDisc */
3179 player->priv->disc = parole_disc_new();
3180 g_signal_connect(player->priv->disc, "disc-selected",
3181 G_CALLBACK(parole_player_disc_selected_cb), player);
3182
3183 /* ParoleButton */
3184 #ifdef HAVE_XF86_KEYSYM
3185 player->priv->button = parole_button_new();
3186 g_signal_connect(player->priv->button, "button-pressed",
3187 G_CALLBACK(parole_player_button_pressed_cb), player);
3188 #endif
3189
3190 /* ParoleScreenSaver */
3191 player->priv->screen_saver = parole_screen_saver_new();
3192
3193 /* PowerManagement Inhibit cookie */
3194 player->priv->connection = parole_power_manager_dbus_init ();
3195 player->priv->inhibit_cookie = 0;
3196
3197 /* ParoleMediaList */
3198 player->priv->list = PAROLE_MEDIA_LIST(parole_media_list_get());
3199
3200 player->priv->state = PAROLE_STATE_STOPPED;
3201 player->priv->user_seeking = FALSE;
3202 player->priv->internal_range_change = FALSE;
3203 player->priv->exit = FALSE;
3204 player->priv->full_screen = FALSE;
3205 player->priv->buffering = FALSE;
3206 player->priv->row = NULL;
3207 player->priv->wait_for_gst_disc_info = FALSE;
3208
3209 player->priv->recent = gtk_recent_manager_get_default();
3210
3211 /* Get properties from ParoleConf */
3212 g_object_get(G_OBJECT(player->priv->conf),
3213 "videosink", &videosink,
3214 "volume", &volume,
3215 "window-width", &w,
3216 "window-height", &h,
3217 "window-maximized", &maximized,
3218 NULL);
3219
3220 player->priv->last_w = w;
3221 player->priv->last_h = h;
3222
3223 /*
3224 * GTK Widgets
3225 */
3226 /* ParolePlayer Window */
3227 player->priv->window = GTK_WIDGET(gtk_builder_get_object(builder, "main-window"));
3228 g_signal_connect_after(G_OBJECT(player->priv->window),
3229 "window-state-event",
3230 G_CALLBACK(parole_player_window_state_event),
3231 PAROLE_PLAYER(player));
3232
3233 // Playlist notebook
3234 player->priv->playlist_nt = GTK_WIDGET(gtk_builder_get_object(builder, "notebook-playlist"));
3235 gtk_notebook_append_page(GTK_NOTEBOOK(player->priv->playlist_nt),
3236 GTK_WIDGET(player->priv->list),
3237 gtk_label_new(_("Playlist")));
3238
3239 player->priv->playlist_popover = GTK_WIDGET(gtk_builder_get_object(builder, "notebook-playlist-popover"));
3240
3241 /* Menu Bar */
3242 player->priv->menu_bar = GTK_WIDGET(gtk_builder_get_object(builder, "menubar"));
3243
3244 /* Media Menu */
3245 // Save Playlist
3246 player->priv->save_playlist = GTK_WIDGET(gtk_builder_get_object(builder, "menu-save-playlist"));
3247 g_signal_connect(player->priv->save_playlist,
3248 "activate",
3249 G_CALLBACK(parole_player_save_playlist_cb),
3250 PAROLE_PLAYER(player));
3251 g_signal_connect(gtk_builder_get_object(builder, "media-menu"), "select",
3252 G_CALLBACK(parole_player_media_menu_select_cb), player);
3253
3254 /* Recent Submenu */
3255 recent_menu = GTK_WIDGET(gtk_builder_get_object(builder, "recent_menu"));
3256
3257 // Initialize the Recent Menu settings
3258 player->priv->recent_menu = gtk_recent_chooser_menu_new_for_manager(player->priv->recent);
3259 gtk_recent_chooser_menu_set_show_numbers(GTK_RECENT_CHOOSER_MENU(player->priv->recent_menu), TRUE);
3260 gtk_recent_chooser_set_sort_type(GTK_RECENT_CHOOSER(player->priv->recent_menu), GTK_RECENT_SORT_MRU);
3261 gtk_recent_chooser_set_show_private(GTK_RECENT_CHOOSER(player->priv->recent_menu), FALSE);
3262 gtk_recent_chooser_set_show_not_found(GTK_RECENT_CHOOSER(player->priv->recent_menu), FALSE);
3263 gtk_recent_chooser_set_local_only(GTK_RECENT_CHOOSER(player->priv->recent_menu), TRUE);
3264
3265 // Recent Menu file filter
3266 recent_filter = parole_get_supported_recent_media_filter();
3267 gtk_recent_filter_add_application(recent_filter, "parole");
3268 gtk_recent_chooser_set_filter(GTK_RECENT_CHOOSER(player->priv->recent_menu), recent_filter);
3269
3270 // Recent Menu Separator
3271 recent_separator = gtk_separator_menu_item_new();
3272 gtk_menu_shell_append(GTK_MENU_SHELL(player->priv->recent_menu), recent_separator);
3273
3274 // Clear Recent Menu Item
3275 clear_recent = gtk_menu_item_new_with_mnemonic(_("_Clear recent items..."));
3276 gtk_menu_shell_append(GTK_MENU_SHELL(player->priv->recent_menu), clear_recent);
3277
3278 // Recent Menu signals
3279 g_signal_connect(player->priv->recent_menu, "item-activated",
3280 G_CALLBACK(parole_player_recent_menu_item_activated_cb), player);
3281 g_signal_connect(clear_recent, "activate",
3282 G_CALLBACK(parole_player_recent_menu_clear_activated_cb), player);
3283
3284 /* Attach the Recent Menu */
3285 gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent_menu), player->priv->recent_menu);
3286
3287 /* DVD Menu */
3288 player->priv->dvd_menu = GTK_WIDGET(gtk_builder_get_object(builder, "dvd-menu"));
3289 player->priv->chapters_menu = GTK_WIDGET(gtk_builder_get_object(builder, "chapters-menu"));
3290
3291 /* Language Menus */
3292 player->priv->subtitles_menu = GTK_WIDGET(gtk_builder_get_object(builder, "subtitles-menu"));
3293 player->priv->languages_menu = GTK_WIDGET(gtk_builder_get_object(builder, "languages-menu"));
3294
3295 player->priv->subtitles_group = GTK_WIDGET(gtk_builder_get_object(builder, "subtitles-menu-none"));
3296 player->priv->subtitles_menu_custom = GTK_WIDGET(gtk_builder_get_object(builder, "subtitles-menu-custom"));
3297
3298 g_signal_connect(player->priv->subtitles_menu_custom, "activate",
3299 G_CALLBACK(parole_player_select_custom_subtitle), player);
3300
3301 player->priv->audio_group = NULL;
3302
3303 /* Additional Menu Items */
3304 bug_report = GTK_WIDGET(gtk_builder_get_object(builder, "bug-report"));
3305 g_signal_connect(bug_report, "activate",
3306 G_CALLBACK(on_bug_report_clicked), player);
3307
3308 contents = GTK_WIDGET(gtk_builder_get_object(builder, "contents"));
3309 g_signal_connect(contents, "activate",
3310 G_CALLBACK(on_contents_clicked), player);
3311
3312 player->priv->goto_position = GTK_WIDGET(gtk_builder_get_object(builder, "goto_position"));
3313 g_signal_connect(player->priv->goto_position, "activate",
3314 G_CALLBACK(on_goto_position_clicked), player);
3315
3316 g_signal_connect(gtk_builder_get_object(builder, "playback-menu"), "select",
3317 G_CALLBACK(parole_player_playback_menu_select_cb), player);
3318
3319 player->priv->show_menubar = TRUE;
3320 /* End Menu Bar */
3321
3322
3323 /* Content Area (Background, Audio, Video) */
3324 player->priv->eventbox_output = GTK_WIDGET(gtk_builder_get_object(builder, "content_area"));
3325
3326 // Enable motion-notify event to show/hide controls on mouseover
3327 gtk_widget_add_events(GTK_WIDGET(player->priv->eventbox_output),
3328 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
3329
3330 // Enable DND for files onto output widget
3331 gtk_drag_dest_set(player->priv->eventbox_output, GTK_DEST_DEFAULT_ALL,
3332 target_entry, G_N_ELEMENTS(target_entry),
3333 GDK_ACTION_COPY | GDK_ACTION_MOVE);
3334 g_signal_connect(player->priv->eventbox_output, "drag-data-received",
3335 G_CALLBACK(parole_player_drag_data_received_cb), player);
3336
3337 // Background Image
3338 logo = gdk_pixbuf_new_from_file(g_strdup_printf("%s/play.png", PIXMAPS_DIR), NULL);
3339 player->priv->logo_image = GTK_WIDGET(gtk_builder_get_object(builder, "logo"));
3340 gtk_image_set_from_pixbuf(GTK_IMAGE(player->priv->logo_image), logo);
3341
3342 // Video Box
3343 player->priv->videobox = GTK_WIDGET(gtk_builder_get_object(builder, "video_output"));
3344
3345 // Audio Box
3346 player->priv->audiobox = GTK_WIDGET(gtk_builder_get_object(builder, "audio_output"));
3347 player->priv->audiobox_cover = GTK_WIDGET(gtk_builder_get_object(builder, "audio_cover"));
3348 player->priv->audiobox_text = GTK_WIDGET(gtk_builder_get_object(builder, "audio_text"));
3349 player->priv->audiobox_title = GTK_WIDGET(gtk_builder_get_object(builder, "audio_title"));
3350 player->priv->audiobox_album = GTK_WIDGET(gtk_builder_get_object(builder, "audio_album"));
3351 player->priv->audiobox_artist = GTK_WIDGET(gtk_builder_get_object(builder, "audio_artist"));
3352
3353 g_signal_connect(player->priv->audiobox, "draw",
3354 G_CALLBACK(parole_audiobox_expose_event), player);
3355 /* End Content Area */
3356
3357
3358 /* Play / Pause */
3359 // GSimpleAction
3360 player->priv->media_playpause_action = g_simple_action_new("playpause_action", NULL);
3361 g_simple_action_set_enabled(player->priv->media_playpause_action, FALSE);
3362 playpause_action = player->priv->media_playpause_action;
3363
3364 // Button & Image
3365 player->priv->playpause_button = GTK_WIDGET(gtk_builder_get_object(builder, "media_playpause"));
3366 player->priv->playpause_image = GTK_WIDGET(gtk_builder_get_object(builder, "image_media_playpause"));
3367
3368 // Signals
3369 g_signal_connect(G_OBJECT(player->priv->media_playpause_action), "activate",
3370 G_CALLBACK(parole_player_playpause_action_cb), NULL);
3371 g_signal_connect(G_OBJECT(player->priv->playpause_button), "clicked",
3372 G_CALLBACK(parole_player_widget_activate_action), player->priv->media_playpause_action);
3373
3374
3375 /* Previous Track */
3376 // GSimpleAction
3377 player->priv->media_previous_action = g_simple_action_new("previous_action", NULL);
3378 g_simple_action_set_enabled(player->priv->media_previous_action, FALSE);
3379 previous_action = player->priv->media_previous_action;
3380
3381 // Button
3382 player->priv->previous_button = GTK_WIDGET(gtk_builder_get_object(builder, "media_previous"));
3383 gtk_widget_set_tooltip_text(GTK_WIDGET(player->priv->previous_button), _("Previous Track"));
3384 gtk_widget_set_sensitive(GTK_WIDGET(player->priv->previous_button), FALSE);
3385
3386 // Signals
3387 g_signal_connect(G_OBJECT(player->priv->media_previous_action), "activate",
3388 G_CALLBACK(parole_player_previous_action_cb), NULL);
3389 g_signal_connect(G_OBJECT(player->priv->previous_button), "clicked",
3390 G_CALLBACK(parole_player_widget_activate_action), player->priv->media_previous_action);
3391
3392
3393 /* Next Track */
3394 // GSimpleAction
3395 player->priv->media_next_action = g_simple_action_new("next_action", NULL);
3396 g_simple_action_set_enabled(player->priv->media_next_action, FALSE);
3397 next_action = player->priv->media_next_action;
3398
3399 // Button
3400 player->priv->next_button = GTK_WIDGET(gtk_builder_get_object(builder, "media_next"));
3401 gtk_widget_set_tooltip_text(GTK_WIDGET(player->priv->next_button), _("Next Track"));
3402 gtk_widget_set_sensitive(GTK_WIDGET(player->priv->next_button), FALSE);
3403
3404 // Signals
3405 g_signal_connect(G_OBJECT(player->priv->media_next_action), "activate",
3406 G_CALLBACK(parole_player_next_action_cb), NULL);
3407 g_signal_connect(G_OBJECT(player->priv->next_button), "clicked",
3408 G_CALLBACK(parole_player_widget_activate_action), player->priv->media_next_action);
3409
3410
3411 /* Fullscreen */
3412 // GSimpleAction
3413 player->priv->media_fullscreen_action = g_simple_action_new("fullscreen_action", NULL);
3414 g_simple_action_set_enabled(player->priv->media_fullscreen_action, TRUE);
3415
3416 // Button
3417 player->priv->fullscreen_button = GTK_WIDGET(gtk_builder_get_object(builder, "media_fullscreen"));
3418 gtk_widget_set_tooltip_text(GTK_WIDGET(player->priv->fullscreen_button), _("Fullscreen"));
3419
3420 // Menu Item
3421 player->priv->fullscreen_menu_item = GTK_WIDGET(gtk_builder_get_object(builder, "fullscreen-menu"));
3422 player->priv->fullscreen_image = GTK_WIDGET(gtk_builder_get_object(builder, "image_media_fullscreen"));
3423
3424 // Signals
3425 g_signal_connect(G_OBJECT(player->priv->media_fullscreen_action), "activate",
3426 G_CALLBACK(parole_player_fullscreen_action_cb), NULL);
3427 g_signal_connect(G_OBJECT(player->priv->fullscreen_button), "clicked",
3428 G_CALLBACK(parole_player_widget_activate_action), player->priv->media_fullscreen_action);
3429 g_signal_connect(G_OBJECT(player->priv->fullscreen_menu_item), "activate",
3430 G_CALLBACK(parole_player_widget_activate_action), player->priv->media_fullscreen_action);
3431
3432
3433 /* Toggle Playlist */
3434
3435 // Menu Item
3436 player->priv->showhide_playlist_menu_item = GTK_WIDGET(gtk_builder_get_object(builder, "show-hide-list"));
3437
3438 // Button
3439 player->priv->showhide_playlist_button = GTK_WIDGET(gtk_builder_get_object(builder, "media_playlist"));
3440
3441 // Signals
3442 g_signal_connect(G_OBJECT(player->priv->showhide_playlist_menu_item), "activate",
3443 G_CALLBACK(parole_player_playlist_menu_toggled_cb), player);
3444 g_signal_connect(G_OBJECT(player->priv->showhide_playlist_button), "toggled",
3445 G_CALLBACK(parole_player_playlist_toggled_cb), player);
3446
3447 /* Toggle Repeat */
3448 // GSimpleAction
3449 player->priv->toggle_repeat_action = g_simple_toggle_action_new("toggle_repeat_action", NULL);
3450 g_simple_action_set_enabled(player->priv->toggle_repeat_action, TRUE);
3451
3452 // Menu Item
3453 player->priv->repeat_menu_item = GTK_WIDGET(gtk_builder_get_object(builder, "repeat"));
3454
3455 // Signals
3456 g_signal_connect(G_OBJECT(player->priv->repeat_menu_item), "activate",
3457 G_CALLBACK(toggle_action_cb), player->priv->toggle_repeat_action);
3458 g_signal_connect(G_OBJECT(player->priv->toggle_repeat_action), "notify::state",
3459 G_CALLBACK(parole_player_repeat_state_changed), player);
3460 parole_media_list_connect_repeat_action(player->priv->list, player->priv->toggle_repeat_action);
3461 g_object_bind_property(G_OBJECT(player->priv->conf), "repeat",
3462 player->priv->repeat_menu_item, "active",
3463 G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
3464
3465
3466 /* Toggle Shuffle */
3467 // GSimpleAction
3468 player->priv->toggle_shuffle_action = g_simple_toggle_action_new("toggle_shuffle_action", NULL);
3469 g_simple_action_set_enabled(player->priv->toggle_shuffle_action, TRUE);
3470
3471 // Menu Item
3472 player->priv->shuffle_menu_item = GTK_WIDGET(gtk_builder_get_object(builder, "shuffle"));
3473
3474 // Signals
3475 g_signal_connect(G_OBJECT(player->priv->shuffle_menu_item), "activate",
3476 G_CALLBACK(toggle_action_cb), player->priv->toggle_shuffle_action);
3477 g_signal_connect(G_OBJECT(player->priv->toggle_shuffle_action), "notify::state",
3478 G_CALLBACK(parole_player_shuffle_state_changed), player);
3479 parole_media_list_connect_shuffle_action(player->priv->list, player->priv->toggle_shuffle_action);
3480 g_object_bind_property(G_OBJECT(player->priv->conf), "shuffle",
3481 player->priv->shuffle_menu_item, "active",
3482 G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
3483
3484
3485
3486 /* Media Controls */
3487 controls_overlay = GTK_WIDGET(gtk_overlay_new());
3488
3489 player->priv->control = GTK_WIDGET(gtk_builder_get_object(builder, "control"));
3490
3491 play_box = GTK_WIDGET(gtk_builder_get_object(builder, "media_controls"));
3492 controls_parent = GTK_WIDGET(gtk_builder_get_object(builder, "box2"));
3493 gtk_box_pack_start(GTK_BOX(controls_parent), controls_overlay, TRUE, TRUE, 0);
3494
3495 parole_widget_reparent(GTK_WIDGET(player->priv->eventbox_output), controls_overlay);
3496
3497 player->priv->revealer = gtk_revealer_new();
3498 gtk_widget_set_vexpand(GTK_WIDGET(player->priv->revealer), FALSE);
3499 gtk_widget_set_hexpand(GTK_WIDGET(player->priv->revealer), FALSE);
3500 gtk_revealer_set_transition_duration(GTK_REVEALER(player->priv->revealer), 250);
3501 gtk_revealer_set_transition_type(GTK_REVEALER(player->priv->revealer), GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP);
3502 gtk_revealer_set_reveal_child(GTK_REVEALER(player->priv->revealer), TRUE);
3503 gtk_widget_set_valign(player->priv->revealer, GTK_ALIGN_END);
3504
3505 parole_widget_reparent(GTK_WIDGET(player->priv->control), player->priv->revealer);
3506
3507 gtk_overlay_add_overlay(GTK_OVERLAY(controls_overlay), player->priv->revealer);
3508 gtk_widget_show_all(player->priv->revealer);
3509
3510 gtk_box_set_child_packing(GTK_BOX(player->priv->control), GTK_WIDGET(play_box), TRUE, TRUE, 2, GTK_PACK_START);
3511 gtk_container_set_border_width(GTK_CONTAINER(play_box), 3);
3512 gtk_widget_show_all(controls_parent);
3513
3514 /* Enable motion-notify event to prevent hiding controls on mouseover */
3515 gtk_widget_add_events(GTK_WIDGET(player->priv->control), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
3516 g_signal_connect(G_OBJECT(player->priv->control), "motion-notify-event",
3517 G_CALLBACK(parole_player_gst_widget_motion_notify_event), player);
3518
3519 gtk_widget_add_events(GTK_WIDGET(play_box), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
3520 g_signal_connect(G_OBJECT(play_box), "motion-notify-event",
3521 G_CALLBACK(parole_player_gst_widget_motion_notify_event), player);
3522 for (widgets = gtk_container_get_children(GTK_CONTAINER(play_box));
3523 widgets != NULL;
3524 widgets = g_list_next(widgets)) {
3525 gtk_widget_add_events(GTK_WIDGET(widgets->data), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
3526 g_signal_connect(G_OBJECT(widgets->data), "motion-notify-event",
3527 G_CALLBACK(parole_player_gst_widget_motion_notify_event), player);
3528 }
3529
3530 /* Elapsed/Duration labels */
3531 player->priv->label_duration = GTK_WIDGET(gtk_builder_get_object(builder, "media_time_duration"));
3532 player->priv->label_elapsed = GTK_WIDGET(gtk_builder_get_object(builder, "media_time_elapsed"));
3533 player->priv->label_divider = GTK_WIDGET(gtk_builder_get_object(builder, "media_time_divider"));
3534 gtk_widget_hide (player->priv->label_divider);
3535
3536 /* Time Slider */
3537 player->priv->range = GTK_WIDGET(gtk_builder_get_object(builder, "media_progress_slider"));
3538 gtk_widget_set_name(player->priv->range, "ParoleScale");
3539
3540 /* Buffering Progressbar */
3541 player->priv->progressbar_buffering = GTK_WIDGET(gtk_builder_get_object(builder, "media_buffering_progressbar"));
3542
3543 /* Volume Button */
3544 player->priv->volume = GTK_WIDGET(gtk_builder_get_object(builder, "media_volumebutton"));
3545 player->priv->mute = GTK_WIDGET(gtk_builder_get_object(builder, "volume-mute-menu"));
3546 parole_player_change_volume(player, (gdouble)(volume/100.));
3547
3548 g_signal_connect(gtk_scale_button_get_popup(GTK_SCALE_BUTTON(player->priv->volume)), "hide", G_CALLBACK(parole_player_volume_popdown_cb), player);
3549
3550 gtk_widget_set_direction(GTK_WIDGET(gtk_builder_get_object(builder, "ltrbox")), GTK_TEXT_DIR_LTR);
3551 g_signal_connect(player->priv->control, "draw", G_CALLBACK(parole_overlay_expose_event), NULL);
3552 /* End Media Controls */
3553
3554 /* Info Bar */
3555 // Placeholder widget
3556 hbox_infobar = GTK_WIDGET(gtk_builder_get_object(builder, "infobar_placeholder"));
3557
3558 // Initialize the InfoBar
3559 player->priv->infobar = gtk_info_bar_new();
3560 gtk_info_bar_set_message_type(GTK_INFO_BAR(player->priv->infobar),
3561 GTK_MESSAGE_QUESTION);
3562
3563 gtk_widget_set_no_show_all(player->priv->infobar, TRUE);
3564
3565 content_area = gtk_info_bar_get_content_area(GTK_INFO_BAR(player->priv->infobar));
3566 g_signal_connect(content_area, "size-allocate",
3567 G_CALLBACK(on_content_area_size_allocate), player);
3568
3569 gtk_box_pack_start(GTK_BOX(hbox_infobar), player->priv->infobar, TRUE, TRUE, 0);
3570
3571 // Initialize the Audio Track combobox
3572 player->priv->liststore_audiotrack = gtk_list_store_new(1, G_TYPE_STRING);
3573 player->priv->combobox_audiotrack = gtk_combo_box_new_with_model(
3574 GTK_TREE_MODEL(player->priv->liststore_audiotrack));
3575 player->priv->audio_list = NULL;
3576
3577 cell = gtk_cell_renderer_text_new();
3578 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(player->priv->combobox_audiotrack), cell, TRUE);
3579 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(player->priv->combobox_audiotrack), cell, "text", 0, NULL);
3580
3581 g_signal_connect(player->priv->combobox_audiotrack, "changed",
3582 G_CALLBACK(parole_player_combo_box_audiotrack_changed_cb), player);
3583
3584 // Humanize and pack the Audio Track combobox
3585 audiotrack_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
3586 audiotrack_label = gtk_label_new(_("Audio Track:"));
3587 gtk_box_pack_start(GTK_BOX(audiotrack_box), audiotrack_label, FALSE, FALSE, 0);
3588 gtk_box_pack_end(GTK_BOX(audiotrack_box), player->priv->combobox_audiotrack, FALSE, FALSE, 0);
3589 gtk_container_add(GTK_CONTAINER(content_area), audiotrack_box);
3590
3591 // Initialize the Subtitles combobox
3592 player->priv->liststore_subtitles = gtk_list_store_new(1, G_TYPE_STRING);
3593 player->priv->combobox_subtitles = gtk_combo_box_new_with_model(GTK_TREE_MODEL(player->priv->liststore_subtitles));
3594 player->priv->subtitle_list = NULL;
3595
3596 sub_cell = gtk_cell_renderer_text_new();
3597 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(player->priv->combobox_subtitles), sub_cell, TRUE);
3598 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(player->priv->combobox_subtitles), sub_cell, "text", 0, NULL);
3599
3600 g_signal_connect(player->priv->combobox_subtitles, "changed",
3601 G_CALLBACK(parole_player_combo_box_subtitles_changed_cb), player);
3602
3603 // Humanize and pack the Subtitles combobox
3604 subtitle_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
3605 subtitle_label = gtk_label_new(_("Subtitles:"));
3606 gtk_box_pack_start(GTK_BOX(subtitle_box), subtitle_label, FALSE, FALSE, 0);
3607 gtk_box_pack_end(GTK_BOX(subtitle_box), player->priv->combobox_subtitles, FALSE, FALSE, 0);
3608 gtk_container_add(GTK_CONTAINER(content_area), subtitle_box);
3609
3610 // Add a close button to the Infobar
3611 infobar_close = gtk_button_new_with_label(_("Close"));
3612 close_icon = gtk_image_new_from_icon_name("gtk-close", GTK_ICON_SIZE_BUTTON);
3613 gtk_button_set_image(GTK_BUTTON(infobar_close), close_icon);
3614 g_signal_connect(infobar_close, "clicked",
3615 G_CALLBACK(on_infobar_close_clicked), player);
3616 gtk_box_pack_end(GTK_BOX(content_area), infobar_close, FALSE, FALSE, 0);
3617
3618 gtk_widget_show_all(content_area);
3619
3620 player->priv->update_languages = FALSE;
3621 player->priv->updated_subs = FALSE;
3622 /* End Info Bar */
3623
3624 #ifdef HAVE_CLUTTER
3625 player->priv->use_clutter = g_strcmp0(videosink, "cluttersink") == 0;
3626 if (player->priv->use_clutter) {
3627 GtkWidget *clutterbox;
3628 GstElement *video_sink;
3629
3630 player->priv->clutter = parole_clutter_new(player->priv->conf);
3631 clutterbox = parole_clutter_get_embed_widget(PAROLE_CLUTTER(player->priv->clutter));
3632
3633 gtk_box_pack_start(GTK_BOX(player->priv->videobox),
3634 clutterbox,
3635 TRUE, TRUE, 0);
3636
3637 video_sink = parole_gst_video_sink(PAROLE_GST(player->priv->gst));
3638 parole_clutter_apply_texture(PAROLE_CLUTTER(player->priv->clutter), &video_sink);
3639
3640 gtk_widget_show(player->priv->clutter);
3641 gtk_widget_grab_focus(player->priv->clutter);
3642 } else {
3643 gtk_box_pack_start(GTK_BOX(player->priv->videobox),
3644 player->priv->gst,
3645 TRUE, TRUE, 0);
3646
3647 gtk_widget_realize(player->priv->gst);
3648 gtk_widget_show(player->priv->gst);
3649
3650 gtk_widget_grab_focus(player->priv->gst);
3651 }
3652 #else
3653 gtk_box_pack_start(GTK_BOX(player->priv->videobox),
3654 player->priv->gst,
3655 TRUE, TRUE, 0);
3656
3657 gtk_widget_realize(player->priv->gst);
3658 gtk_widget_show(player->priv->gst);
3659
3660 gtk_widget_grab_focus(player->priv->gst);
3661 #endif
3662
3663 parole_gst_set_default_aspect_ratio(player, builder);
3664
3665 /*
3666 * Gst signals
3667 */
3668 g_signal_connect(G_OBJECT(player->priv->gst), "media-state",
3669 G_CALLBACK(parole_player_media_state_cb), player);
3670
3671 g_signal_connect(G_OBJECT(player->priv->gst), "media-progressed",
3672 G_CALLBACK(parole_player_media_progressed_cb), player);
3673
3674 g_signal_connect(G_OBJECT(player->priv->gst), "media-tag",
3675 G_CALLBACK(parole_player_media_tag_cb), player);
3676
3677 g_signal_connect(G_OBJECT(player->priv->gst), "error",
3678 G_CALLBACK(parole_player_error_cb), player);
3679
3680 g_signal_connect(G_OBJECT(player->priv->gst), "buffering",
3681 G_CALLBACK(parole_player_buffering_cb), player);
3682
3683 g_signal_connect(G_OBJECT(player->priv->gst), "dvd-chapter-count-change",
3684 G_CALLBACK(parole_player_dvd_chapter_count_change_cb), player);
3685
3686 g_signal_connect(G_OBJECT(player->priv->gst), "dvd-chapter-change",
3687 G_CALLBACK(parole_player_dvd_chapter_change_cb), player);
3688
3689 g_signal_connect(G_OBJECT(player->priv->gst), "notify::volume",
3690 G_CALLBACK(parole_property_notify_cb_volume), player);
3691
3692 g_signal_connect(G_OBJECT(parole_gst_get_stream(PAROLE_GST(player->priv->gst))), "notify::seekable",
3693 G_CALLBACK(parole_player_seekable_notify), player);
3694
3695 /*
3696 * Media List Signals
3697 */
3698 g_signal_connect(player->priv->list, "media_activated",
3699 G_CALLBACK(parole_player_media_activated_cb), player);
3700
3701 g_signal_connect(player->priv->list, "media_cursor_changed",
3702 G_CALLBACK(parole_player_media_cursor_changed_cb), player);
3703
3704 g_signal_connect(player->priv->list, "uri-opened",
3705 G_CALLBACK(parole_player_uri_opened_cb), player);
3706
3707 g_signal_connect(player->priv->list, "iso-opened",
3708 G_CALLBACK(parole_player_iso_opened_cb), player);
3709
3710 g_signal_connect(player->priv->list, "key-forward",
3711 G_CALLBACK(parole_player_key_forward_cb), player);
3712
3713 /*
3714 * Load auto saved media list.
3715 */
3716 parole_media_list_load(player->priv->list);
3717
3718 /*
3719 * Connect remaining signals.
3720 */
3721 gtk_builder_connect_signals(builder, player);
3722 g_object_unref(builder);
3723
3724
3725
3726 /* Set up DBUS */
3727 parole_player_dbus_init(player);
3728
3729 /* Finish preparing the window. */
3730 g_signal_connect_swapped(player->priv->window, "notify::is-active",
3731 G_CALLBACK(parole_player_window_notify_is_active), player);
3732
3733 gtk_window_set_default_size(GTK_WINDOW(player->priv->window), w, h);
3734 gtk_window_resize(GTK_WINDOW(player->priv->window), w, h);
3735 if (maximized)
3736 gtk_window_maximize(GTK_WINDOW(player->priv->window));
3737
3738 gtk_widget_show_all(player->priv->window);
3739
3740 g_object_get(G_OBJECT(player->priv->conf),
3741 "always-hide-menubar", &always_hide_menubar,
3742 NULL);
3743 if (always_hide_menubar == TRUE)
3744 parole_player_hide_menubar_cb(NULL, player);
3745
3746 parole_player_set_wm_opacity_hint(player->priv->window);
3747 }
3748
3749 ParolePlayer *
3750 parole_player_new(const gchar *client_id) {
3751 parole_player = g_object_new(PAROLE_TYPE_PLAYER, "client-id", client_id, NULL);
3752 return parole_player;
3753 }
3754
3755 ParoleMediaList *parole_player_get_media_list(ParolePlayer *player) {
3756 return player->priv->list;
3757 }
3758
3759 void parole_player_play_uri_disc(ParolePlayer *player, const gchar *uri, const gchar *device) {
3760 if ( uri ) {
3761 parole_player_disc_selected_cb(NULL, uri, device, player);
3762 } else if (device) {
3763 gchar *uri_local = parole_get_uri_from_unix_device(device);
3764 if ( uri_local ) {
3765 parole_player_disc_selected_cb(NULL, uri_local, device, player);
3766 g_free(uri_local);
3767 }
3768 }
3769 }
3770
3771 void parole_player_set_audiotrack_radio_menu_item_selected(ParolePlayer *player, gint audio_index) {
3772 GList *menu_items, *menu_iter;
3773 gint counter = 0;
3774
3775 menu_items = gtk_container_get_children(GTK_CONTAINER(player->priv->languages_menu));
3776
3777 for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next(menu_iter)) {
3778 if (counter == audio_index) {
3779 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_iter->data), TRUE);
3780 break;
3781 }
3782 counter++;
3783 }
3784 g_list_free(menu_items);
3785 }
3786
3787 void parole_player_set_subtitle_radio_menu_item_selected(ParolePlayer *player, gint sub_index) {
3788 GList *menu_items, *menu_iter;
3789 menu_items = gtk_container_get_children(GTK_CONTAINER(player->priv->subtitles_menu));
3790
3791 if (sub_index <= 0) {
3792 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_items->data), TRUE);
3793 } else {
3794 gint counter = -3;
3795 for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next(menu_iter)) {
3796 if (counter == sub_index) {
3797 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_iter->data), TRUE);
3798 break;
3799 }
3800 counter++;
3801 }
3802 }
3803 g_list_free(menu_items);
3804 }
3805
3806 void parole_player_audiotrack_radio_menu_item_changed_cb(GtkWidget *widget, ParolePlayer *player) {
3807 gint radio_index = 0;
3808 GList *menu_items, *menu_iter;
3809 gint counter = 0;
3810 gint combobox_index;
3811
3812 menu_items = gtk_container_get_children(GTK_CONTAINER(player->priv->languages_menu));
3813
3814 for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next(menu_iter)) {
3815 if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_iter->data)) == TRUE) {
3816 radio_index = counter;
3817 break;
3818 }
3819 counter++;
3820 }
3821 g_list_free(menu_items);
3822
3823 combobox_index = gtk_combo_box_get_active(GTK_COMBO_BOX(player->priv->combobox_audiotrack));
3824 if (radio_index != combobox_index)
3825 gtk_combo_box_set_active(GTK_COMBO_BOX(player->priv->combobox_audiotrack), radio_index);
3826 }
3827
3828 void parole_player_subtitles_radio_menu_item_changed_cb(GtkWidget *widget, ParolePlayer *player) {
3829 gint radio_index = 0;
3830 gint combobox_index = 0;
3831 gint counter = 0;
3832
3833 GList *menu_items, *menu_iter;
3834 menu_items = gtk_container_get_children(GTK_CONTAINER(player->priv->subtitles_menu));
3835
3836 for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next(menu_iter)) {
3837 if (counter == 0 || counter > 3) {
3838 if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_iter->data)) == TRUE) {
3839 radio_index = counter;
3840 break;
3841 }
3842 }
3843 counter++;
3844 }
3845 g_list_free(menu_items);
3846
3847 if (radio_index != 0)
3848 radio_index -= 3;
3849
3850 combobox_index = gtk_combo_box_get_active(GTK_COMBO_BOX(player->priv->combobox_subtitles));
3851 if (radio_index != combobox_index)
3852 gtk_combo_box_set_active(GTK_COMBO_BOX(player->priv->combobox_subtitles), radio_index);
3853 }
3854
3855 void parole_player_combo_box_audiotrack_changed_cb(GtkWidget *widget, ParolePlayer *player) {
3856 gint audio_index = gtk_combo_box_get_active(GTK_COMBO_BOX(player->priv->combobox_audiotrack));
3857 if (player->priv->update_languages == FALSE)
3858 gst_set_current_audio_track(PAROLE_GST(player->priv->gst), audio_index);
3859 parole_player_set_audiotrack_radio_menu_item_selected(player, audio_index);
3860 }
3861
3862 static gboolean
3863 get_has_file_extension(gchar* filename, gchar* extension) {
3864 gchar *lowercase = NULL;
3865 gboolean has_ext;
3866
3867 lowercase = g_utf8_strdown(filename, g_utf8_strlen(filename, -1));
3868
3869 has_ext = g_str_has_suffix(lowercase, extension);
3870
3871 g_free(lowercase);
3872
3873 return has_ext;
3874 }
3875
3876 void parole_player_combo_box_subtitles_changed_cb(GtkWidget *widget, ParolePlayer *player) {
3877 gchar *uri = parole_gst_get_file_uri(PAROLE_GST(player->priv->gst));
3878 gint sub_index = gtk_combo_box_get_active(GTK_COMBO_BOX(player->priv->combobox_subtitles));
3879
3880 if (get_has_file_extension(uri, "mkv")) {
3881 gst_set_current_subtitle_track(PAROLE_GST(player->priv->gst), sub_index);
3882 } else {
3883 if (player->priv->update_languages == FALSE)
3884 gst_set_current_subtitle_track(PAROLE_GST(player->priv->gst), sub_index);
3885 }
3886 parole_player_set_subtitle_radio_menu_item_selected(player, sub_index);
3887 }
3888
3889 void parole_player_terminate(ParolePlayer *player) {
3890 parole_player_delete_event_cb(NULL, NULL, player);
3891 }
3892
3893
3894 static gboolean parole_player_dbus_play(ParolePlayer *player,
3895 GError *error);
3896
3897 static gboolean parole_player_dbus_next_track(ParolePlayer *player,
3898 GError *error);
3899
3900 static gboolean parole_player_dbus_prev_track(ParolePlayer *player,
3901 GError *error);
3902
3903 static gboolean parole_player_dbus_raise_volume(ParolePlayer *player,
3904 GError *error);
3905
3906 static gboolean parole_player_dbus_lower_volume(ParolePlayer *player,
3907 GError *error);
3908
3909 static gboolean parole_player_dbus_mute(ParolePlayer *player,
3910 GError *error);
3911
3912 static gboolean parole_player_dbus_unmute(ParolePlayer *player,
3913 GError *error);
3914
3915 static gboolean parole_player_dbus_play_disc(ParolePlayer *player,
3916 gchar *in_uri,
3917 gchar *in_device,
3918 GError **error);
3919
3920 #include "src/org.parole.media.player.h"
3921
3922 /*
3923 * DBus server implementation
3924 */
3925 static void
3926 parole_player_dbus_class_init(ParolePlayerClass *klass) {
3927 dbus_g_object_type_install_info(G_TYPE_FROM_CLASS(klass),
3928 &dbus_glib_parole_player_object_info);
3929 }
3930
3931 static void
3932 parole_player_dbus_init(ParolePlayer *player) {
3933 dbus_g_connection_register_g_object(player->priv->bus,
3934 PAROLE_DBUS_PATH,
3935 G_OBJECT(player));
3936 }
3937
3938 static gboolean parole_player_dbus_play(ParolePlayer *player, GError *error) {
3939 parole_player_toggle_playpause(player);
3940 return TRUE;
3941 }
3942
3943 static gboolean parole_player_dbus_next_track(ParolePlayer *player, GError *error) {
3944 parole_player_play_next(player, TRUE);
3945 return TRUE;
3946 }
3947
3948 static gboolean parole_player_dbus_prev_track(ParolePlayer *player, GError *error) {
3949 parole_player_play_prev(player);
3950 return TRUE;
3951 }
3952
3953 static gboolean parole_player_dbus_raise_volume(ParolePlayer *player, GError *error) {
3954 parole_player_volume_up(NULL, player);
3955 return TRUE;
3956 }
3957
3958 static gboolean parole_player_dbus_lower_volume(ParolePlayer *player, GError *error) {
3959 parole_player_volume_down(NULL, player);
3960 return TRUE;
3961 }
3962
3963 static gboolean parole_player_dbus_mute(ParolePlayer *player, GError *error) {
3964 if (gtk_scale_button_get_value(GTK_SCALE_BUTTON(player->priv->volume)) != 0.0) {
3965 parole_player_volume_mute(NULL, player);
3966 }
3967 return TRUE;
3968 }
3969
3970 static gboolean parole_player_dbus_unmute(ParolePlayer *player, GError *error) {
3971 if (gtk_scale_button_get_value(GTK_SCALE_BUTTON(player->priv->volume)) == 0.0) {
3972 parole_player_volume_mute(NULL, player);
3973 }
3974 return TRUE;
3975 }
3976
3977 static gboolean parole_player_dbus_play_disc(ParolePlayer *player,
3978 gchar *in_uri,
3979 gchar *in_device,
3980 GError **error) {
3981 TRACE("uri : %s", in_uri);
3982
3983 gtk_window_present(GTK_WINDOW(player->priv->window));
3984
3985 if ( parole_is_uri_disc (in_uri) )
3986 parole_player_disc_selected_cb(NULL, in_uri, in_device, player);
3987
3988 return TRUE;
3989 }
3990