1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * Goo
5 *
6 * Copyright (C) 2004-2009 Free Software Foundation, Inc.
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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23 #include <math.h>
24 #include <string.h>
25 #include <glib/gi18n.h>
26 #include <gdk/gdkkeysyms.h>
27 #include <gtk/gtk.h>
28 #include <gst/gst.h>
29 #include "gio-utils.h"
30 #include "dlg-cover-chooser.h"
31 #include "goo-marshal.h"
32 #include "goo-player.h"
33 #include "goo-player-info.h"
34 #include "goo-player-progress.h"
35 #include "goo-window.h"
36 #include "goo-window-actions-entries.h"
37 #include "gth-user-dir.h"
38 #include "gtk-utils.h"
39 #include "gtk-file-chooser-preview.h"
40 #include "glib-utils.h"
41 #include "main.h"
42 #include "preferences.h"
43 #include "typedefs.h"
44
45 #define FILES_TO_PROCESS_AT_ONCE 500
46 #define PLAYER_CHECK_RATE 100
47 #define COVER_SIZE 80
48 #define IDLE_TIMEOUT 200
49 #define FALLBACK_ICON_SIZE 16
50 #define CONFIG_KEY_AUTOFETCH_GROUP "AutoFetch"
51 #define ACTIONS_MENU_BUTTON_POSITION 6
52 #define TRAY_TOOLTIP_DELAY 500
53 #define AUTOPLAY_DELAY 250
54 #define MAX_WINDOW_HEIGHT_PERCENTAGE 0.80
55 #define MESSAGE_BAR_RESPONSE_PROPERTIES 1
56
57 struct _GooWindowPrivate {
58 GtkWidget *list_view;
59 GtkListStore *list_store;
60 GtkWidget *list_scrolled_window;
61
62 GtkTreeViewColumn *author_column;
63 WindowSortMethod sort_method;
64 GtkSortType sort_type;
65
66 GtkWidget *file_popup_menu;
67 GtkWidget *cover_popup_menu;
68
69 GtkWidget *message_bar;
70 GtkWidget *message_label;
71 GtkWidget *message_bar_properties_button;
72 GtkWidget *info;
73 GtkWidget *play_button;
74 GtkWidget *progress;
75
76 guint first_time_event;
77 guint next_timeout_handle;
78 gint activity_ref; /* when > 0 some activity
79 * is present. */
80 GtkAccelGroup *accel_group;
81 GSettings *settings_general;
82 GSettings *settings_ui;
83 GSettings *settings_playlist;
84 GSettings *settings_encoder;
85
86 guint update_timeout_handle; /* update list timeout
87 * handle. */
88
89 GooPlayer *player;
90 AlbumInfo *album;
91 TrackInfo *current_track;
92 GList *playlist; /* int list. */
93
94 gboolean exiting;
95 guint check_id;
96 GList *url_list;
97 GtkWidget *preview;
98 int pos_x, pos_y;
99 gboolean hibernate;
100 gboolean resizable_playlist;
101
102 GDBusProxy *media_keys_proxy;
103 gulong focus_in_event;
104 gulong media_key_event;
105 gulong notify_event;
106 };
107
108 enum {
109 UPDATE_COVER,
110 LAST_SIGNAL
111 };
112
113 static guint goo_window_signals[LAST_SIGNAL] = { 0 };
114 static int icon_size = 0;
115
116
117 enum {
118 COLUMN_TRACK_INFO,
119 COLUMN_NUMBER,
120 COLUMN_ICON,
121 COLUMN_TIME,
122 COLUMN_TITLE,
123 COLUMN_ARTIST,
124 NUMBER_OF_COLUMNS
125 };
126
127
G_DEFINE_TYPE_WITH_CODE(GooWindow,goo_window,GTK_TYPE_APPLICATION_WINDOW,G_ADD_PRIVATE (GooWindow))128 G_DEFINE_TYPE_WITH_CODE (GooWindow, goo_window, GTK_TYPE_APPLICATION_WINDOW,
129 G_ADD_PRIVATE (GooWindow))
130
131
132 static void
133 window_update_sensitivity (GooWindow *window)
134 {
135 int n_selected;
136 gboolean one_file_selected;
137 GooPlayerState state;
138 gboolean error;
139 gboolean audio_cd;
140 gboolean playing;
141 gboolean paused;
142
143 n_selected = _gtk_count_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view)));
144 one_file_selected = n_selected == 1;
145 state = goo_player_get_state (window->priv->player);
146 error = ! goo_player_is_audio_cd (window->priv->player) || window->priv->hibernate;
147 playing = state == GOO_PLAYER_STATE_PLAYING;
148 paused = state == GOO_PLAYER_STATE_PAUSED;
149 audio_cd = (! error) && (goo_player_get_discid (window->priv->player) != NULL);
150
151 gtk_widget_set_sensitive (window->priv->list_view, audio_cd);
152
153 _g_action_map_enable_action (G_ACTION_MAP (window), "play", audio_cd && ! playing);
154 _g_action_map_enable_action (G_ACTION_MAP (window), "play-selected", audio_cd && one_file_selected);
155 _g_action_map_enable_action (G_ACTION_MAP (window), "pause", audio_cd && playing);
156 _g_action_map_enable_action (G_ACTION_MAP (window), "stop", audio_cd && (playing || paused));
157 _g_action_map_enable_action (G_ACTION_MAP (window), "toggle-play", audio_cd);
158 _g_action_map_enable_action (G_ACTION_MAP (window), "next-track", audio_cd);
159 _g_action_map_enable_action (G_ACTION_MAP (window), "previous-track", audio_cd);
160 _g_action_map_enable_action (G_ACTION_MAP (window), "extract", audio_cd && (window->priv->album->n_tracks > 0));
161 _g_action_map_enable_action (G_ACTION_MAP (window), "copy-disc", audio_cd && (window->priv->album->n_tracks > 0));
162 _g_action_map_enable_action (G_ACTION_MAP (window), "properties", audio_cd);
163 _g_action_map_enable_action (G_ACTION_MAP (window), "pick-cover-from-disk", audio_cd);
164 _g_action_map_enable_action (G_ACTION_MAP (window), "remove-cover", audio_cd);
165 _g_action_map_enable_action (G_ACTION_MAP (window), "search-cover", audio_cd);
166 _g_action_map_enable_action (G_ACTION_MAP (window), "eject", ! window->priv->hibernate);
167 }
168
169
170 static int
get_icon_size_from_settings(GtkIconSize gtk_icon_size)171 get_icon_size_from_settings (GtkIconSize gtk_icon_size)
172 {
173 int width;
174 int height;
175 int icon_size;
176
177 if (gtk_icon_size_lookup (gtk_icon_size, &width, &height))
178 icon_size = MAX (width, height);
179 else
180 icon_size = FALLBACK_ICON_SIZE;
181
182 return icon_size;
183 }
184
185
186 static GdkPixbuf *
create_void_icon(GooWindow * window)187 create_void_icon (GooWindow *window)
188 {
189 int icon_size;
190 GdkPixbuf *icon;
191
192 icon_size = get_icon_size_from_settings (GTK_ICON_SIZE_MENU);
193 icon = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, icon_size, icon_size);
194 gdk_pixbuf_fill (icon, 0x00000000);
195
196 return icon;
197 }
198
199
200 static gboolean
get_iter_from_track_number(GooWindow * window,int track_number,GtkTreeIter * iter)201 get_iter_from_track_number (GooWindow *window,
202 int track_number,
203 GtkTreeIter *iter)
204 {
205
206 GtkTreeModel *model = GTK_TREE_MODEL (window->priv->list_store);
207
208 if (! gtk_tree_model_get_iter_first (model, iter))
209 return FALSE;
210
211 do {
212 TrackInfo *track;
213
214 gtk_tree_model_get (model, iter, COLUMN_TRACK_INFO, &track, -1);
215 if (track->number == track_number) {
216 track_info_unref (track);
217 return TRUE;
218 }
219 track_info_unref (track);
220 }
221 while (gtk_tree_model_iter_next (model, iter));
222
223 return FALSE;
224 }
225
226
227 static void
set_track_icon(GooWindow * window,int track_number,const char * icon_name)228 set_track_icon (GooWindow *window,
229 int track_number,
230 const char *icon_name)
231 {
232 GtkTreeIter iter;
233 GdkPixbuf *icon;
234
235 if (! get_iter_from_track_number (window, track_number, &iter))
236 return;
237
238 if (icon_name != NULL)
239 icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (window))),
240 icon_name,
241 get_icon_size_from_settings (GTK_ICON_SIZE_MENU),
242 0,
243 NULL);
244 else
245 icon = create_void_icon (window);
246 gtk_list_store_set (window->priv->list_store, &iter,
247 COLUMN_ICON, icon,
248 -1);
249 g_object_unref (icon);
250 }
251
252
253 static void
set_current_track_icon(GooWindow * window,const char * icon_name)254 set_current_track_icon (GooWindow *window,
255 const char *icon_name)
256 {
257 if (window->priv->current_track != NULL)
258 set_track_icon (window, window->priv->current_track->number, icon_name);
259 }
260
261
262 void
goo_window_update(GooWindow * window)263 goo_window_update (GooWindow *window)
264 {
265 goo_window_stop (window);
266 goo_player_update (window->priv->player);
267 }
268
269
270 static void
goo_window_update_list(GooWindow * window)271 goo_window_update_list (GooWindow *window)
272 {
273 GdkPixbuf *icon;
274 GList *scan;
275
276 if (gtk_widget_get_realized (window->priv->list_view))
277 gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (window->priv->list_view), 0, 0);
278
279 /**/
280
281 track_info_unref (window->priv->current_track);
282 window->priv->current_track = NULL;
283
284 if (window->priv->playlist != NULL)
285 g_list_free (window->priv->playlist);
286 window->priv->playlist = NULL;
287
288 /**/
289
290 gtk_widget_set_visible (window->priv->list_scrolled_window, (window->priv->album->tracks != NULL));
291
292 /**/
293
294 icon = create_void_icon (window);
295 gtk_list_store_clear (window->priv->list_store);
296 for (scan = window->priv->album->tracks; scan; scan = scan->next) {
297 TrackInfo *track = scan->data;
298 GtkTreeIter iter;
299 char *time_s;
300
301 gtk_list_store_prepend (window->priv->list_store, &iter);
302
303 time_s = _g_format_duration_for_display (track->length * 1000);
304 gtk_list_store_set (window->priv->list_store, &iter,
305 COLUMN_TRACK_INFO, track,
306 COLUMN_NUMBER, track->number + 1,
307 COLUMN_ICON, icon,
308 COLUMN_TIME, time_s,
309 COLUMN_TITLE, track->title,
310 COLUMN_ARTIST, track->artist,
311 -1);
312 g_free (time_s);
313 }
314
315 window_update_sensitivity (window);
316
317 {
318 GdkGeometry hints;
319
320 hints.max_height = -1;
321 hints.max_width = G_MAXINT;
322 gtk_window_set_geometry_hints (GTK_WINDOW (window),
323 GTK_WIDGET (window),
324 &hints,
325 GDK_HINT_MAX_SIZE);
326
327 window->priv->resizable_playlist = FALSE;
328 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (window->priv->list_scrolled_window),
329 GTK_POLICY_NEVER,
330 GTK_POLICY_NEVER);
331 }
332
333 g_object_unref (icon);
334 }
335
336
337 /**/
338
339
340 static void
goo_window_update_titles(GooWindow * window)341 goo_window_update_titles (GooWindow *window)
342 {
343 GtkTreeModel *model = GTK_TREE_MODEL (window->priv->list_store);
344 GtkTreeIter iter;
345
346 if (! gtk_tree_model_get_iter_first (model, &iter))
347 return;
348
349 do {
350 TrackInfo *track;
351 TrackInfo *new_track;
352
353 gtk_tree_model_get (model, &iter, COLUMN_TRACK_INFO, &track, -1);
354 new_track = album_info_get_track (window->priv->album, track->number);
355 track_info_unref (track);
356
357 if (new_track == NULL)
358 continue;
359
360 gtk_list_store_set (window->priv->list_store, &iter,
361 COLUMN_TRACK_INFO, new_track,
362 COLUMN_TITLE, new_track->title,
363 COLUMN_ARTIST, new_track->artist,
364 -1);
365
366 /* Update the current track info. */
367
368 if ((window->priv->current_track != NULL)
369 && (new_track->number == window->priv->current_track->number))
370 {
371 track_info_unref (window->priv->current_track);
372 track_info_ref (new_track);
373 window->priv->current_track = new_track;
374 }
375 track_info_unref (new_track);
376 }
377 while (gtk_tree_model_iter_next (model, &iter));
378 }
379
380
381 static void
goo_window_finalize(GObject * object)382 goo_window_finalize (GObject *object)
383 {
384 GooWindow *window = GOO_WINDOW (object);
385
386 debug (DEBUG_INFO, "[FINALIZE]\n");
387
388 if (window->priv != NULL) {
389 if (window->priv->media_keys_proxy != NULL) {
390 g_dbus_proxy_call_sync (window->priv->media_keys_proxy,
391 "ReleaseMediaPlayerKeys",
392 g_variant_new ("(s)", g_get_application_name ()),
393 G_DBUS_CALL_FLAGS_NONE,
394 -1,
395 NULL,
396 NULL);
397 g_object_unref (window->priv->media_keys_proxy);
398 }
399
400 /* Save preferences */
401
402 g_settings_set_int (window->priv->settings_general, PREF_GENERAL_VOLUME, goo_player_get_audio_volume (window->priv->player));
403
404 /**/
405
406 _g_object_unref (window->priv->accel_group);
407 _g_object_unref (window->priv->settings_ui);
408 _g_object_unref (window->priv->settings_general);
409 _g_object_unref (window->priv->settings_playlist);
410 _g_object_unref (window->priv->settings_encoder);
411
412 g_object_unref (window->priv->list_store);
413
414 if (window->priv->notify_event != 0) {
415 g_source_remove (window->priv->notify_event);
416 window->priv->notify_event = 0;
417 }
418
419 if (window->priv->next_timeout_handle != 0) {
420 g_source_remove (window->priv->next_timeout_handle);
421 window->priv->next_timeout_handle = 0;
422 }
423
424 if (window->priv->update_timeout_handle != 0) {
425 g_source_remove (window->priv->update_timeout_handle);
426 window->priv->update_timeout_handle = 0;
427 }
428
429 if (window->priv->playlist != NULL)
430 g_list_free (window->priv->playlist);
431
432 g_signal_handlers_disconnect_by_data (window->priv->player, window);
433 g_object_unref (window->priv->player);
434
435 track_info_unref (window->priv->current_track);
436 album_info_unref (window->priv->album);
437
438 _g_string_list_free (window->priv->url_list);
439 window->priv->url_list = NULL;
440
441 window->priv = NULL;
442 }
443
444 G_OBJECT_CLASS (goo_window_parent_class)->finalize (object);
445 }
446
447
448 static void
add_columns(GooWindow * window,GtkTreeView * treeview)449 add_columns (GooWindow *window,
450 GtkTreeView *treeview)
451 {
452 GtkCellRenderer *renderer;
453 GtkTreeViewColumn *column;
454 GValue value = { 0, };
455
456 /* The Number column. */
457
458 column = gtk_tree_view_column_new ();
459 /*gtk_tree_view_column_set_title (column, _("#"));*/
460
461 renderer = gtk_cell_renderer_text_new ();
462 gtk_tree_view_column_pack_start (column,
463 renderer,
464 TRUE);
465 gtk_tree_view_column_set_attributes (column, renderer,
466 "text", COLUMN_NUMBER,
467 NULL);
468
469 renderer = gtk_cell_renderer_pixbuf_new ();
470 gtk_tree_view_column_pack_start (column, renderer, FALSE);
471 gtk_tree_view_column_set_attributes (column, renderer,
472 "pixbuf", COLUMN_ICON,
473 NULL);
474
475 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
476 gtk_tree_view_column_set_resizable (column, TRUE);
477
478 gtk_tree_view_column_set_sort_column_id (column, COLUMN_NUMBER);
479 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
480
481 /* Title */
482
483 column = gtk_tree_view_column_new ();
484 /*gtk_tree_view_column_set_title (column, _("Title"));*/
485 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
486 gtk_tree_view_column_set_resizable (column, TRUE);
487 gtk_tree_view_column_set_expand (column, TRUE);
488 gtk_tree_view_column_set_sort_column_id (column, COLUMN_TITLE);
489
490 renderer = gtk_cell_renderer_text_new ();
491
492 g_value_init (&value, PANGO_TYPE_ELLIPSIZE_MODE);
493 g_value_set_enum (&value, PANGO_ELLIPSIZE_END);
494 g_object_set_property (G_OBJECT (renderer), "ellipsize", &value);
495 g_value_unset (&value);
496
497 gtk_tree_view_column_pack_start (column, renderer, TRUE);
498 gtk_tree_view_column_set_attributes (column, renderer,
499 "text", COLUMN_TITLE,
500 NULL);
501
502 gtk_tree_view_append_column (treeview, column);
503
504 /* Author */
505
506 window->priv->author_column = column = gtk_tree_view_column_new ();
507 /*gtk_tree_view_column_set_title (column, _("Artist"));*/
508 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
509 gtk_tree_view_column_set_resizable (column, FALSE);
510 gtk_tree_view_column_set_expand (column, TRUE);
511 gtk_tree_view_column_set_sort_column_id (column, COLUMN_ARTIST);
512
513 renderer = gtk_cell_renderer_text_new ();
514
515 g_value_init (&value, PANGO_TYPE_ELLIPSIZE_MODE);
516 g_value_set_enum (&value, PANGO_ELLIPSIZE_END);
517 g_object_set_property (G_OBJECT (renderer), "ellipsize", &value);
518 g_value_unset (&value);
519
520 gtk_tree_view_column_pack_start (column, renderer, TRUE);
521 gtk_tree_view_column_set_attributes (column, renderer,
522 "text", COLUMN_ARTIST,
523 NULL);
524
525 gtk_tree_view_append_column (treeview, column);
526 gtk_tree_view_column_set_visible (column, FALSE);
527
528 /* Time */
529
530 column = gtk_tree_view_column_new ();
531 /*gtk_tree_view_column_set_title (column, _("Length"));*/
532 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
533 gtk_tree_view_column_set_resizable (column, FALSE);
534 gtk_tree_view_column_set_sort_column_id (column, COLUMN_TIME);
535
536 renderer = gtk_cell_renderer_text_new ();
537
538 gtk_tree_view_column_pack_start (column, renderer, TRUE);
539 gtk_tree_view_column_set_attributes (column, renderer,
540 "text", COLUMN_TIME,
541 NULL);
542
543 gtk_tree_view_append_column (treeview, column);
544 }
545
546
547 static void
print_playlist(GooWindow * window)548 print_playlist (GooWindow *window)
549 {
550 #ifdef DEBUG
551 GList *scan;
552
553 debug (DEBUG_INFO, "PLAYLIST: ");
554 for (scan = window->priv->playlist; scan; scan = scan->next)
555 debug (DEBUG_INFO, "%d, ", GPOINTER_TO_INT (scan->data));
556 debug (DEBUG_INFO, "\n");
557 #endif
558 }
559
560
561 static int
get_track_number_from_position(GooWindow * window,int pos)562 get_track_number_from_position (GooWindow *window,
563 int pos)
564 {
565
566 GtkTreeModel *model = GTK_TREE_MODEL (window->priv->list_store);
567 GtkTreeIter iter;
568 int i = 0;
569
570 if (! gtk_tree_model_get_iter_first (model, &iter))
571 return -1;
572
573 do {
574 TrackInfo *track;
575 int n;
576 gtk_tree_model_get (model, &iter, COLUMN_TRACK_INFO, &track, -1);
577 n = track->number;
578 track_info_unref (track);
579 if (i == pos)
580 return n;
581 i++;
582 }
583 while (gtk_tree_model_iter_next (model, &iter));
584
585 return -1;
586 }
587
588
589 static int
get_position_from_track_number(GooWindow * window,int track_number)590 get_position_from_track_number (GooWindow *window,
591 int track_number)
592 {
593
594 GtkTreeModel *model = GTK_TREE_MODEL (window->priv->list_store);
595 GtkTreeIter iter;
596 int pos = 0;
597
598 if (! gtk_tree_model_get_iter_first (model, &iter))
599 return -1;
600
601 do {
602 TrackInfo *track;
603 int n;
604 gtk_tree_model_get (model, &iter, COLUMN_TRACK_INFO, &track, -1);
605 n = track->number;
606 track_info_unref (track);
607 if (n == track_number)
608 return pos;
609 pos++;
610 } while (gtk_tree_model_iter_next (model, &iter));
611
612 return -1;
613 }
614
615
616 static void
add_selected_track(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)617 add_selected_track (GtkTreeModel *model,
618 GtkTreePath *path,
619 GtkTreeIter *iter,
620 gpointer data)
621 {
622 GList **list = data;
623 TrackInfo *track;
624
625 gtk_tree_model_get (model, iter, COLUMN_TRACK_INFO, &track, -1);
626 *list = g_list_prepend (*list, track);
627 }
628
629
630 static gboolean
set_selected_track_if_unique(GooWindow * window,int * n_track)631 set_selected_track_if_unique (GooWindow *window,
632 int *n_track)
633 {
634 GtkTreeSelection *list_selection;
635 GList *tracks;
636 gboolean result;
637
638 if (window->priv->album->tracks == NULL)
639 return FALSE;
640
641 list_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
642 if (list_selection == NULL)
643 return FALSE;
644
645 tracks = NULL;
646 gtk_tree_selection_selected_foreach (list_selection, add_selected_track, &tracks);
647
648 if ((tracks != NULL) && (tracks->next == NULL)) {
649 TrackInfo *track;
650
651 track = tracks->data;
652 *n_track = track->number;
653 result = TRUE;
654 }
655 else
656 result = FALSE;
657
658 track_list_free (tracks);
659
660 return result;
661 }
662
663
664 static void
create_playlist(GooWindow * window,gboolean play_all,gboolean shuffle)665 create_playlist (GooWindow *window,
666 gboolean play_all,
667 gboolean shuffle)
668 {
669
670 GList *playlist;
671 int selected_track_number;
672 int pos;
673
674 debug (DEBUG_INFO, "PLAY ALL: %d\n", play_all);
675 debug (DEBUG_INFO, "SHUFFLE: %d\n", shuffle);
676
677 if (window->priv->playlist != NULL)
678 g_list_free (window->priv->playlist);
679 window->priv->playlist = NULL;
680
681 playlist = NULL;
682
683 if (window->priv->current_track != NULL) {
684
685 /* ignore the currently playing track */
686
687 selected_track_number = window->priv->current_track->number;
688 pos = get_position_from_track_number (window, window->priv->current_track->number);
689 }
690 else if (set_selected_track_if_unique (window, &selected_track_number)) {
691
692 /* put the selected track first */
693
694 playlist = g_list_prepend (playlist, GINT_TO_POINTER (selected_track_number));
695 pos = get_position_from_track_number (window, selected_track_number);
696 }
697 else {
698 selected_track_number = -1;
699 pos = 0;
700 }
701
702 if (play_all) {
703 int i;
704
705 for (i = 0;
706 i < window->priv->album->n_tracks;
707 i++, pos = (pos + 1) % window->priv->album->n_tracks)
708 {
709 int track_number;
710
711 track_number = get_track_number_from_position (window, pos);
712 if (track_number == selected_track_number)
713 /* skip the selected track */
714 continue;
715
716 playlist = g_list_prepend (playlist, GINT_TO_POINTER (track_number));
717 }
718
719 playlist = g_list_reverse (playlist);
720
721 if (shuffle) {
722 GRand *grand = g_rand_new ();
723 GList *random_list = NULL;
724 int len = g_list_length (playlist);
725
726 while (playlist != NULL) {
727 GList *item;
728
729 pos = g_rand_int_range (grand, 0, len--);
730 item = g_list_nth (playlist, pos);
731 playlist = g_list_remove_link (playlist, item);
732 random_list = g_list_concat (random_list, item);
733 }
734 playlist = random_list;
735
736 g_rand_free (grand);
737 }
738 }
739
740 window->priv->playlist = playlist;
741
742 print_playlist (window);
743 }
744
745
746 static void
update_playlist_after_started_next(GooWindow * window)747 update_playlist_after_started_next (GooWindow *window)
748 {
749 GList *current;
750
751 if (window->priv->playlist == NULL)
752 return;
753
754 current = window->priv->playlist;
755 window->priv->playlist = g_list_remove_link (window->priv->playlist, current);
756
757 g_list_free (current);
758 }
759
760
761 static void
update_next_track_to_play(GooWindow * window)762 update_next_track_to_play (GooWindow *window)
763 {
764 GList *track;
765 int next_track_to_play;
766
767 for (track = window->priv->playlist; track; track = track->next)
768 if (GPOINTER_TO_INT (track->data) == goo_player_get_current_track (window->priv->player))
769 break;
770
771 if (track != NULL) {
772 if (track->next != NULL)
773 next_track_to_play = GPOINTER_TO_INT (track->next->data);
774 else
775 next_track_to_play = -1;
776 }
777 else if (window->priv->playlist != NULL)
778 next_track_to_play = GPOINTER_TO_INT (window->priv->playlist->data);
779 else
780 next_track_to_play = -1;
781
782 goo_player_set_next_track (window->priv->player, next_track_to_play);
783 }
784
785
786 static void
play_track(GooWindow * window,int track_to_play)787 play_track (GooWindow *window,
788 int track_to_play)
789 {
790 goo_player_seek_track (window->priv->player, track_to_play);
791 update_next_track_to_play (window);
792 }
793
794
795 static gboolean
play_next_track_in_playlist(GooWindow * window)796 play_next_track_in_playlist (GooWindow *window)
797 {
798 gboolean play_all;
799 gboolean shuffle;
800 gboolean repeat;
801 GList *next = NULL;
802
803 play_all = g_settings_get_boolean (window->priv->settings_playlist, PREF_PLAYLIST_PLAYALL);
804 shuffle = g_settings_get_boolean (window->priv->settings_playlist, PREF_PLAYLIST_SHUFFLE);
805 repeat = g_settings_get_boolean (window->priv->settings_playlist, PREF_PLAYLIST_REPEAT);
806
807 next = window->priv->playlist;
808
809 if ((next == NULL) && repeat) {
810 track_info_unref (window->priv->current_track);
811 window->priv->current_track = NULL;
812 create_playlist (window, play_all, shuffle);
813 next = window->priv->playlist;
814 }
815
816 if (next != NULL) {
817 int pos;
818
819 pos = GPOINTER_TO_INT (next->data);
820 window->priv->playlist = g_list_remove_link (window->priv->playlist, next);
821 g_list_free (next);
822
823 play_track (window, pos);
824 }
825 else
826 goo_window_stop (window);
827
828 return (next != NULL);
829 }
830
831
832 static void
pref_playlist_playall_changed(GSettings * settings,const char * key,gpointer user_data)833 pref_playlist_playall_changed (GSettings *settings,
834 const char *key,
835 gpointer user_data)
836 {
837 GooWindow *window = user_data;
838 gboolean play_all;
839 gboolean shuffle;
840
841 g_return_if_fail (window != NULL);
842
843 play_all = g_settings_get_boolean (window->priv->settings_playlist, PREF_PLAYLIST_PLAYALL);
844 shuffle = g_settings_get_boolean (window->priv->settings_playlist, PREF_PLAYLIST_SHUFFLE);
845 create_playlist (window, play_all, shuffle);
846 update_next_track_to_play (window);
847
848 window_update_sensitivity (window);
849 }
850
851
852 static void
pref_playlist_shuffle_changed(GSettings * settings,const char * key,gpointer user_data)853 pref_playlist_shuffle_changed (GSettings *settings,
854 const char *key,
855 gpointer user_data)
856 {
857 GooWindow *window = user_data;
858 gboolean play_all;
859 gboolean shuffle;
860
861 g_return_if_fail (window != NULL);
862
863 play_all = g_settings_get_boolean (window->priv->settings_playlist, PREF_PLAYLIST_PLAYALL);
864 shuffle = g_settings_get_boolean (window->priv->settings_playlist, PREF_PLAYLIST_SHUFFLE);
865 create_playlist (window, play_all, shuffle);
866 update_next_track_to_play (window);
867 }
868
869
870 static void
save_window_size(GooWindow * window)871 save_window_size (GooWindow *window)
872 {
873 int width, height;
874
875 gtk_window_get_size (GTK_WINDOW (window), &width, &height);
876 g_settings_set_int (window->priv->settings_ui, PREF_UI_WINDOW_WIDTH, width);
877 g_settings_set_int (window->priv->settings_ui, PREF_UI_WINDOW_HEIGHT, height);
878 }
879
880
881 static void
goo_window_unrealize(GtkWidget * widget)882 goo_window_unrealize (GtkWidget *widget)
883 {
884 GooWindow *window;
885
886 window = GOO_WINDOW (widget);
887
888 /* save ui preferences. */
889
890 if (gtk_widget_get_visible (window->priv->list_scrolled_window))
891 save_window_size (window);
892
893 g_settings_set_enum (window->priv->settings_playlist, PREF_PLAYLIST_SORT_METHOD, window->priv->sort_method);
894 g_settings_set_enum (window->priv->settings_playlist, PREF_PLAYLIST_SORT_TYPE, window->priv->sort_type);
895
896 GTK_WIDGET_CLASS (goo_window_parent_class)->unrealize (widget);
897 }
898
899
900 static gboolean
first_time_idle(gpointer callback_data)901 first_time_idle (gpointer callback_data)
902 {
903 GooWindow *window = callback_data;
904
905 g_source_remove (window->priv->first_time_event);
906 window->priv->first_time_event = 0;
907 goo_player_update (window->priv->player);
908
909 return FALSE;
910 }
911
912
913 static void
goo_window_show(GtkWidget * widget)914 goo_window_show (GtkWidget *widget)
915 {
916 GooWindow *window = GOO_WINDOW (widget);
917
918 if (! arg_toggle_visibility)
919 GTK_WIDGET_CLASS (goo_window_parent_class)->show (widget);
920 else
921 arg_toggle_visibility = FALSE;
922
923 if (window->priv->first_time_event == 0)
924 window->priv->first_time_event = g_timeout_add (IDLE_TIMEOUT, first_time_idle, window);
925 }
926
927
928 static void
goo_window_class_init(GooWindowClass * class)929 goo_window_class_init (GooWindowClass *class)
930 {
931 GObjectClass *gobject_class;
932 GtkWidgetClass *widget_class;
933
934 gobject_class = (GObjectClass*) class;
935 gobject_class->finalize = goo_window_finalize;
936
937 widget_class = (GtkWidgetClass*) class;
938 widget_class->unrealize = goo_window_unrealize;
939 widget_class->show = goo_window_show;
940
941 goo_window_signals[UPDATE_COVER] =
942 g_signal_new ("update-cover",
943 G_TYPE_FROM_CLASS (class),
944 G_SIGNAL_RUN_LAST,
945 G_STRUCT_OFFSET (GooWindowClass, update_cover),
946 NULL, NULL,
947 goo_marshal_VOID__VOID,
948 G_TYPE_NONE,
949 0);
950 }
951
952
953 static gboolean
window_delete_event_cb(GtkWidget * caller,GdkEvent * event,GooWindow * window)954 window_delete_event_cb (GtkWidget *caller,
955 GdkEvent *event,
956 GooWindow *window)
957 {
958 if (goo_player_get_state (window->priv->player) == GOO_PLAYER_STATE_PLAYING)
959 gtk_window_iconify (GTK_WINDOW (window));
960 else
961 goo_window_close (GOO_WINDOW (window));
962
963 return TRUE;
964 }
965
966
967 static int
sort_by_number(int i1,int i2)968 sort_by_number (int i1,
969 int i2)
970 {
971 if (i1 == i2)
972 return 0;
973 else if (i1 > i2)
974 return 1;
975 else
976 return -1;
977 }
978
979
980 static int
sort_by_name(const char * s1,const char * s2)981 sort_by_name (const char *s1,
982 const char *s2)
983 {
984 if ((s1 == NULL) && (s2 == NULL))
985 return 0;
986 else if (s1 == NULL)
987 return 1;
988 else if (s2 == NULL)
989 return -1;
990 else
991 return g_utf8_collate (s1, s2);
992 }
993
994
995 static int
title_column_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)996 title_column_sort_func (GtkTreeModel *model,
997 GtkTreeIter *a,
998 GtkTreeIter *b,
999 gpointer user_data)
1000 {
1001 TrackInfo *track1 = NULL, *track2 = NULL;
1002 int retval = -1;
1003
1004 gtk_tree_model_get (model, a, COLUMN_TRACK_INFO, &track1, -1);
1005 gtk_tree_model_get (model, b, COLUMN_TRACK_INFO, &track2, -1);
1006
1007 if ((track1 == NULL) && (track2 == NULL))
1008 retval = 0;
1009 else if (track1 == NULL)
1010 retval = 1;
1011 else if (track2 == NULL)
1012 retval = -1;
1013 else
1014 retval = sort_by_name (track1->title, track2->title);
1015
1016 track_info_unref (track1);
1017 track_info_unref (track2);
1018
1019 return retval;
1020 }
1021
1022
1023 static int
artist_column_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)1024 artist_column_sort_func (GtkTreeModel *model,
1025 GtkTreeIter *a,
1026 GtkTreeIter *b,
1027 gpointer user_data)
1028 {
1029 TrackInfo *track1 = NULL, *track2 = NULL;
1030 int retval = -1;
1031
1032 gtk_tree_model_get (model, a, COLUMN_TRACK_INFO, &track1, -1);
1033 gtk_tree_model_get (model, b, COLUMN_TRACK_INFO, &track2, -1);
1034
1035 if ((track1 == NULL) && (track2 == NULL))
1036 retval = 0;
1037 else if (track1 == NULL)
1038 retval = 1;
1039 else if (track2 == NULL)
1040 retval = -1;
1041 else {
1042 int result = sort_by_name (track1->artist, track2->artist);
1043 if (result == 0)
1044 retval = sort_by_number (track1->number, track2->number);
1045 else
1046 retval = result;
1047 }
1048
1049 track_info_unref (track1);
1050 track_info_unref (track2);
1051
1052 return retval;
1053 }
1054
1055
1056 static int
time_column_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)1057 time_column_sort_func (GtkTreeModel *model,
1058 GtkTreeIter *a,
1059 GtkTreeIter *b,
1060 gpointer user_data)
1061 {
1062 TrackInfo *track1 = NULL, *track2 = NULL;
1063 int retval = -1;
1064
1065 gtk_tree_model_get (model, a, COLUMN_TRACK_INFO, &track1, -1);
1066 gtk_tree_model_get (model, b, COLUMN_TRACK_INFO, &track2, -1);
1067
1068 if ((track1 == NULL) && (track2 == NULL))
1069 retval = 0;
1070 else if (track1 == NULL)
1071 retval = 1;
1072 else if (track2 == NULL)
1073 retval = -1;
1074 else
1075 retval = sort_by_number (track1->length, track2->length);
1076
1077 track_info_unref (track1);
1078 track_info_unref (track2);
1079
1080 return retval;
1081 }
1082
1083
1084 static char *
get_action_name(GooPlayerAction action)1085 get_action_name (GooPlayerAction action)
1086 {
1087 char *name;
1088
1089 switch (action) {
1090 case GOO_PLAYER_ACTION_NONE:
1091 name = "NONE";
1092 break;
1093 case GOO_PLAYER_ACTION_LIST:
1094 name = "LIST";
1095 break;
1096 case GOO_PLAYER_ACTION_SEEK_SONG:
1097 name = "SEEK_SONG";
1098 break;
1099 case GOO_PLAYER_ACTION_SEEK:
1100 name = "SEEK";
1101 break;
1102 case GOO_PLAYER_ACTION_PLAY:
1103 name = "PLAY";
1104 break;
1105 case GOO_PLAYER_ACTION_PAUSE:
1106 name = "PAUSE";
1107 break;
1108 case GOO_PLAYER_ACTION_STOP:
1109 name = "STOP";
1110 break;
1111 case GOO_PLAYER_ACTION_MEDIUM_ADDED:
1112 name = "MEDIUM ADDED";
1113 break;
1114 case GOO_PLAYER_ACTION_MEDIUM_REMOVED:
1115 name = "MEDIUM REMOVED";
1116 break;
1117 case GOO_PLAYER_ACTION_UPDATE:
1118 name = "UPDATE";
1119 break;
1120 case GOO_PLAYER_ACTION_METADATA:
1121 name = "METADATA";
1122 break;
1123 case GOO_PLAYER_ACTION_STARTED_NEXT:
1124 name = "STARTED_NEXT";
1125 break;
1126 default:
1127 name = "???";
1128 break;
1129 }
1130
1131 return name;
1132 }
1133
1134
1135 static gboolean
notify_current_state_cb(gpointer user_data)1136 notify_current_state_cb (gpointer user_data)
1137 {
1138 GooWindow *window = user_data;
1139 GString *info;
1140 GooPlayerState state;
1141
1142 if (window->priv->notify_event != 0) {
1143 g_source_remove (window->priv->notify_event);
1144 window->priv->notify_event = 0;
1145 }
1146
1147 state = goo_player_get_state (window->priv->player);
1148
1149 if ((state == GOO_PLAYER_STATE_ERROR) || (state == GOO_PLAYER_STATE_NO_DISC)) {
1150 system_notify (window, "no-disc", _("No disc"), NULL);
1151 return FALSE;
1152 }
1153
1154 if (state == GOO_PLAYER_STATE_DATA_DISC) {
1155 system_notify (window, "data-disc", _("Data disc"), NULL);
1156 return FALSE;
1157 }
1158
1159 if (window->priv->album == NULL) {
1160 system_notify (window, "no-album", "", NULL);
1161 return FALSE;
1162 }
1163
1164 if (window->priv->current_track == NULL) {
1165 if ((window->priv->album != NULL) && (window->priv->album->title != NULL))
1166 system_notify (window, "new-album", window->priv->album->title , NULL);
1167 else
1168 system_notify (window, "audio-cd", _("Audio CD"), NULL);
1169 return FALSE;
1170 }
1171
1172 info = g_string_new ("");
1173
1174 if (window->priv->album->artist != NULL) {
1175 char *e_artist = g_markup_escape_text (window->priv->album->artist, -1);
1176
1177 g_string_append_printf (info, "%s", e_artist);
1178 g_free (e_artist);
1179 }
1180
1181 if (window->priv->album->title != NULL) {
1182 g_string_append (info, " - ");
1183 g_string_append_printf (info, "%s", window->priv->album->title);
1184 }
1185
1186 if (goo_player_get_state (goo_window_get_player (window)) == GOO_PLAYER_STATE_PLAYING)
1187 system_notify (window,
1188 "new-track",
1189 window->priv->current_track->title,
1190 (strlen (info->str) > 0) ? info->str : NULL);
1191
1192 g_string_free (info, TRUE);
1193
1194 return FALSE;
1195 }
1196
1197
1198 static void
notify_current_state(GooWindow * window,GooPlayerAction action)1199 notify_current_state (GooWindow *window,
1200 GooPlayerAction action)
1201 {
1202 if (window->priv->notify_event != 0)
1203 g_source_remove (window->priv->notify_event);
1204 window->priv->notify_event = g_idle_add (notify_current_state_cb, window);
1205 }
1206
1207
1208 static void
goo_window_show_message_bar_action(GooWindow * window,const char * message)1209 goo_window_show_message_bar_action (GooWindow *window,
1210 const char *message)
1211 {
1212 gtk_label_set_text (GTK_LABEL (window->priv->message_label), message);
1213 gtk_info_bar_set_message_type (GTK_INFO_BAR (window->priv->message_bar), GTK_MESSAGE_INFO);
1214 gtk_widget_hide (window->priv->message_bar_properties_button);
1215 gtk_widget_show (window->priv->message_bar);
1216 }
1217
1218
1219 static void
goo_window_show_message_bar_result(GooWindow * window,const char * message,GtkMessageType message_type)1220 goo_window_show_message_bar_result (GooWindow *window,
1221 const char *message,
1222 GtkMessageType message_type)
1223 {
1224 gtk_label_set_text (GTK_LABEL (window->priv->message_label), message);
1225 gtk_info_bar_set_message_type (GTK_INFO_BAR (window->priv->message_bar), message_type);
1226 gtk_widget_hide (window->priv->message_bar_properties_button);
1227 gtk_widget_show (window->priv->message_bar);
1228 }
1229
1230
1231 static void
goo_window_hide_message_bar(GooWindow * window)1232 goo_window_hide_message_bar (GooWindow *window)
1233 {
1234 gtk_widget_hide (window->priv->message_bar);
1235 }
1236
1237
1238 static void
player_start_cb(GooPlayer * player,GooPlayerAction action,GooWindow * window)1239 player_start_cb (GooPlayer *player,
1240 GooPlayerAction action,
1241 GooWindow *window)
1242 {
1243 debug (DEBUG_INFO, "START [%s]\n", get_action_name (action));
1244
1245 switch (action) {
1246 case GOO_PLAYER_ACTION_PLAY:
1247 notify_current_state (window, action);
1248 break;
1249
1250 case GOO_PLAYER_ACTION_METADATA:
1251 goo_window_show_message_bar_action (window, _("Searching disc information…"));
1252 break;
1253
1254 default:
1255 break;
1256 }
1257 }
1258
1259
1260 static void
goo_window_select_current_track(GooWindow * window)1261 goo_window_select_current_track (GooWindow *window)
1262 {
1263 GtkTreeSelection *selection;
1264 GtkTreePath *path;
1265 int pos;
1266
1267 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
1268 gtk_tree_selection_unselect_all (selection);
1269
1270 pos = get_position_from_track_number (window, window->priv->current_track->number);
1271 if (pos == -1)
1272 return;
1273
1274 path = gtk_tree_path_new_from_indices (pos, -1);
1275 gtk_tree_selection_select_path (selection, path);
1276 gtk_tree_path_free (path);
1277 }
1278
1279
1280 static gboolean
next_time_idle(gpointer callback_data)1281 next_time_idle (gpointer callback_data)
1282 {
1283 GooWindow *window = callback_data;
1284
1285 if (window->priv->next_timeout_handle != 0) {
1286 g_source_remove (window->priv->next_timeout_handle);
1287 window->priv->next_timeout_handle = 0;
1288 }
1289
1290 play_next_track_in_playlist (window);
1291
1292 return FALSE;
1293 }
1294
1295
1296 static void
goo_window_set_current_track(GooWindow * window,int n)1297 goo_window_set_current_track (GooWindow *window,
1298 int n)
1299 {
1300 if (window->priv->hibernate)
1301 return;
1302
1303 if (window->priv->current_track != NULL) {
1304 set_current_track_icon (window, NULL);
1305 track_info_unref (window->priv->current_track);
1306 window->priv->current_track = NULL;
1307 }
1308
1309 window->priv->current_track = album_info_get_track (window->priv->album, n);
1310 }
1311
1312
1313 static void
window_update_title(GooWindow * window)1314 window_update_title (GooWindow *window)
1315 {
1316 goo_player_progress_set_title (GOO_PLAYER_PROGRESS (window->priv->progress), _("CD Player"));
1317
1318 #if 0
1319 GooPlayerState state;
1320 GString *title;
1321
1322 title = g_string_new ("");
1323
1324 state = goo_player_get_state (window->priv->player);
1325 switch (state) {
1326 case GOO_PLAYER_STATE_NO_DISC:
1327 case GOO_PLAYER_STATE_DATA_DISC:
1328 case GOO_PLAYER_STATE_ERROR:
1329 g_string_append (title, _("CD Player"));
1330 break;
1331
1332 default:
1333 if ((window->priv->album != NULL) && (window->priv->album->title != NULL))
1334 g_string_append (title, window->priv->album->title);
1335 else
1336 g_string_append (title, _("Audio CD"));
1337 break;
1338 }
1339
1340 goo_player_progress_set_title (GOO_PLAYER_PROGRESS (window->priv->progress), title->str);
1341
1342 g_string_free (title, TRUE);
1343 #endif
1344 }
1345
1346
1347 char *
goo_window_get_cover_filename(GooWindow * window)1348 goo_window_get_cover_filename (GooWindow *window)
1349 {
1350 const char *discid;
1351 char *filename;
1352 char *path;
1353
1354 discid = goo_player_get_discid (window->priv->player);
1355 if (discid == NULL)
1356 return NULL;
1357
1358 filename = g_strconcat (discid, ".png", NULL);
1359 gth_user_dir_make_dir_for_file (GTH_DIR_CONFIG, "goobox", "covers", filename, NULL);
1360 path = gth_user_dir_get_file (GTH_DIR_CONFIG, "goobox", "covers", filename, NULL);
1361
1362 g_free (filename);
1363
1364 return path;
1365 }
1366
1367
1368 void
goo_window_update_cover(GooWindow * window)1369 goo_window_update_cover (GooWindow *window)
1370 {
1371 g_signal_emit (G_OBJECT (window),
1372 goo_window_signals[UPDATE_COVER],
1373 0,
1374 NULL);
1375 }
1376
1377
1378 static void
save_config_file(GKeyFile * kv_file,char * config_filename)1379 save_config_file (GKeyFile *kv_file,
1380 char *config_filename)
1381 {
1382 GFile *file;
1383 char *buffer;
1384 gsize buffer_size;
1385
1386 file = g_file_new_for_path (config_filename);
1387 buffer = g_key_file_to_data (kv_file,
1388 &buffer_size,
1389 NULL);
1390 if (buffer != NULL)
1391 g_write_file (file,
1392 FALSE,
1393 G_FILE_CREATE_NONE,
1394 buffer,
1395 buffer_size,
1396 NULL,
1397 NULL);
1398
1399 g_free (buffer);
1400 g_object_unref (file);
1401 }
1402
1403
1404 void
goo_window_set_current_cd_autofetch(GooWindow * window,gboolean autofetch)1405 goo_window_set_current_cd_autofetch (GooWindow *window,
1406 gboolean autofetch)
1407 {
1408 GKeyFile *kv_file;
1409 char *config_filename;
1410 const char *discid;
1411
1412 kv_file = g_key_file_new ();
1413
1414 config_filename = gth_user_dir_get_file (GTH_DIR_CONFIG, "goobox", "config", NULL);
1415 g_key_file_load_from_file (kv_file,
1416 config_filename,
1417 G_KEY_FILE_NONE,
1418 NULL);
1419 discid = goo_player_get_discid (window->priv->player);
1420 g_key_file_set_boolean (kv_file,
1421 CONFIG_KEY_AUTOFETCH_GROUP,
1422 discid,
1423 autofetch);
1424
1425 gth_user_dir_make_dir_for_file (GTH_DIR_CONFIG, "goobox", "config", NULL);
1426 save_config_file (kv_file, config_filename);
1427
1428 g_free (config_filename);
1429 g_key_file_free (kv_file);
1430 }
1431
1432
1433 gboolean
goo_window_get_current_cd_autofetch(GooWindow * window)1434 goo_window_get_current_cd_autofetch (GooWindow *window)
1435 {
1436 gboolean autofetch = TRUE;
1437 GKeyFile *kv_file;
1438 char *config_filename;
1439
1440 kv_file = g_key_file_new ();
1441 config_filename = gth_user_dir_get_file (GTH_DIR_CONFIG, "goobox", "config", NULL);
1442 if (g_key_file_load_from_file (kv_file,
1443 config_filename,
1444 G_KEY_FILE_NONE,
1445 NULL))
1446 {
1447 const char *discid;
1448 GError *error = NULL;
1449
1450 discid = goo_player_get_discid (window->priv->player);
1451 autofetch = g_key_file_get_boolean (kv_file,
1452 CONFIG_KEY_AUTOFETCH_GROUP,
1453 discid,
1454 &error);
1455 if (error != NULL) {
1456 autofetch = TRUE;
1457 g_error_free (error);
1458 }
1459 }
1460
1461 g_free (config_filename);
1462 g_key_file_free (kv_file);
1463
1464 return autofetch;
1465 }
1466
1467
1468 static void
auto_fetch_cover_image(GooWindow * window)1469 auto_fetch_cover_image (GooWindow *window)
1470 {
1471 char *filename;
1472
1473 if (window->priv->hibernate)
1474 return;
1475
1476 if (! goo_window_get_current_cd_autofetch (window))
1477 return;
1478 goo_window_set_current_cd_autofetch (window, FALSE);
1479
1480 filename = goo_window_get_cover_filename (window);
1481 if (filename == NULL)
1482 return;
1483
1484 if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
1485 g_free (filename);
1486 return;
1487 }
1488 g_free (filename);
1489
1490 fetch_cover_image_from_album_info (window, window->priv->album, FETCH_COVER_STAGE_0, NULL);
1491 }
1492
1493
1494 static gboolean
autoplay_cb(gpointer data)1495 autoplay_cb (gpointer data)
1496 {
1497 GooWindow *window = data;
1498
1499 if (window->priv->album->n_tracks > 0)
1500 goo_window_play (window);
1501
1502 return FALSE;
1503 }
1504
1505
1506 static void
goo_window_update_album(GooWindow * window)1507 goo_window_update_album (GooWindow *window)
1508 {
1509 album_info_unref (window->priv->album);
1510 window->priv->album = album_info_copy (goo_player_get_album (window->priv->player));
1511
1512 gtk_tree_view_column_set_visible (window->priv->author_column,
1513 window->priv->album->various_artist);
1514 }
1515
1516
1517 static void
window_update_play_button_state(GooWindow * window)1518 window_update_play_button_state (GooWindow *window)
1519 {
1520 gboolean playing = (goo_player_get_state (window->priv->player) == GOO_PLAYER_STATE_PLAYING);
1521 gtk_button_set_image (GTK_BUTTON (window->priv->play_button),
1522 gtk_image_new_from_icon_name (playing ? GOO_ICON_NAME_PAUSE : GOO_ICON_NAME_PLAY, GTK_ICON_SIZE_MENU));
1523 }
1524
1525
1526 static void
player_done_cb(GooPlayer * player,GooPlayerAction action,GError * error,GooWindow * window)1527 player_done_cb (GooPlayer *player,
1528 GooPlayerAction action,
1529 GError *error,
1530 GooWindow *window)
1531 {
1532 debug (DEBUG_INFO, "DONE [%s]\n", get_action_name (action));
1533
1534 switch (action) {
1535 case GOO_PLAYER_ACTION_LIST:
1536 goo_window_update_album (window);
1537 goo_window_update_list (window);
1538 goo_window_update_cover (window);
1539 window_update_title (window);
1540 set_current_track_icon (window, NULL);
1541 if (arg_auto_play || g_settings_get_boolean (window->priv->settings_general, PREF_GENERAL_AUTOPLAY)) {
1542 arg_auto_play = FALSE;
1543 g_timeout_add (AUTOPLAY_DELAY, autoplay_cb, window);
1544 }
1545 break;
1546
1547 case GOO_PLAYER_ACTION_METADATA:
1548 goo_window_update_album (window);
1549 goo_window_update_titles (window);
1550 window_update_title (window);
1551 if (window->priv->album->title == NULL) {
1552 goo_window_show_message_bar_result (window, _("No information found for this disc"), GTK_MESSAGE_WARNING);
1553 gtk_widget_show (window->priv->message_bar_properties_button);
1554 }
1555 else
1556 goo_window_hide_message_bar (window);
1557 notify_current_state (window, action);
1558 auto_fetch_cover_image (window);
1559 break;
1560
1561 case GOO_PLAYER_ACTION_SEEK_SONG:
1562 goo_window_set_current_track (window, goo_player_get_current_track (window->priv->player));
1563 goo_window_select_current_track (window);
1564 set_current_track_icon (window, GOO_ICON_NAME_PLAY);
1565 break;
1566
1567 case GOO_PLAYER_ACTION_PLAY:
1568 case GOO_PLAYER_ACTION_STOP:
1569 case GOO_PLAYER_ACTION_MEDIUM_REMOVED:
1570 if (action == GOO_PLAYER_ACTION_PLAY) {
1571 set_current_track_icon (window, GOO_ICON_NAME_PLAY);
1572 window->priv->next_timeout_handle = g_idle_add (next_time_idle, window);
1573 }
1574 else if (action == GOO_PLAYER_ACTION_STOP)
1575 set_current_track_icon (window, GOO_ICON_NAME_STOP);
1576 notify_current_state (window, action);
1577 window_update_play_button_state (window);
1578 break;
1579
1580 case GOO_PLAYER_ACTION_PAUSE:
1581 set_current_track_icon (window, GOO_ICON_NAME_PAUSE);
1582 notify_current_state (window, action);
1583 window_update_play_button_state (window);
1584 break;
1585
1586 case GOO_PLAYER_ACTION_STARTED_NEXT:
1587 notify_current_state (window, GOO_PLAYER_ACTION_PLAY);
1588 update_playlist_after_started_next (window);
1589 update_next_track_to_play (window);
1590 break;
1591
1592 default:
1593 break;
1594 }
1595 }
1596
1597
1598 static void
player_state_changed_cb(GooPlayer * player,GooWindow * window)1599 player_state_changed_cb (GooPlayer *player,
1600 GooWindow *window)
1601 {
1602 window_update_sensitivity (window);
1603 window_update_title (window);
1604 window_update_play_button_state (window);
1605 }
1606
1607
1608 static void
row_activated_cb(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column,gpointer data)1609 row_activated_cb (GtkTreeView *tree_view,
1610 GtkTreePath *path,
1611 GtkTreeViewColumn *column,
1612 gpointer data)
1613 {
1614 GooWindow *window = data;
1615 GtkTreeIter iter;
1616 TrackInfo *track;
1617
1618 if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store),
1619 &iter,
1620 path))
1621 return;
1622
1623 gtk_tree_model_get (GTK_TREE_MODEL (window->priv->list_store), &iter,
1624 COLUMN_TRACK_INFO, &track,
1625 -1);
1626
1627 goo_window_stop (window);
1628 goo_window_set_current_track (window, track->number);
1629 goo_window_play (window);
1630
1631 track_info_unref (track);
1632 }
1633
1634
1635 static void
selection_changed_cb(GtkTreeSelection * selection,gpointer user_data)1636 selection_changed_cb (GtkTreeSelection *selection,
1637 gpointer user_data)
1638 {
1639 GooWindow *window = user_data;
1640
1641 window_update_sensitivity (window);
1642 window_update_title (window);
1643 }
1644
1645
1646 static int
file_button_press_cb(GtkWidget * widget,GdkEventButton * event,gpointer data)1647 file_button_press_cb (GtkWidget *widget,
1648 GdkEventButton *event,
1649 gpointer data)
1650 {
1651 GooWindow *window = data;
1652 GtkTreeSelection *selection;
1653
1654 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
1655 if (selection == NULL)
1656 return FALSE;
1657
1658 if (event->type != GDK_BUTTON_PRESS)
1659 return FALSE;
1660
1661 if (event->button == 3) {
1662 GtkTreePath *path;
1663 GtkTreeIter iter;
1664
1665 if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (window->priv->list_view),
1666 event->x, event->y,
1667 &path, NULL, NULL, NULL))
1668 {
1669 if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store), &iter, path)) {
1670 gtk_tree_path_free (path);
1671 return FALSE;
1672 }
1673 gtk_tree_path_free (path);
1674
1675 if (! gtk_tree_selection_iter_is_selected (selection, &iter)) {
1676 gtk_tree_selection_unselect_all (selection);
1677 gtk_tree_selection_select_iter (selection, &iter);
1678 }
1679 }
1680 else
1681 gtk_tree_selection_unselect_all (selection);
1682
1683 gtk_menu_popup_at_pointer (GTK_MENU (window->priv->file_popup_menu), (GdkEvent *) event);
1684 return TRUE;
1685 }
1686 else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 1)) {
1687 GtkTreePath *path;
1688
1689 if (! gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (window->priv->list_view),
1690 event->x, event->y,
1691 &path, NULL, NULL, NULL))
1692 {
1693 gtk_tree_selection_unselect_all (selection);
1694 }
1695 }
1696
1697 return FALSE;
1698 }
1699
1700
1701 static int
get_column_from_sort_method(WindowSortMethod sort_method)1702 get_column_from_sort_method (WindowSortMethod sort_method)
1703 {
1704 switch (sort_method) {
1705 case WINDOW_SORT_BY_NUMBER: return COLUMN_NUMBER;
1706 case WINDOW_SORT_BY_TIME: return COLUMN_TIME;
1707 case WINDOW_SORT_BY_TITLE: return COLUMN_TITLE;
1708 default:
1709 break;
1710 }
1711
1712 return COLUMN_NUMBER;
1713 }
1714
1715
1716 static int
get_sort_method_from_column(int column_id)1717 get_sort_method_from_column (int column_id)
1718 {
1719 switch (column_id) {
1720 case COLUMN_NUMBER: return WINDOW_SORT_BY_NUMBER;
1721 case COLUMN_TIME: return WINDOW_SORT_BY_TIME;
1722 case COLUMN_TITLE: return WINDOW_SORT_BY_TITLE;
1723 default:
1724 break;
1725 }
1726
1727 return WINDOW_SORT_BY_NUMBER;
1728 }
1729
1730
1731 static void
sort_column_changed_cb(GtkTreeSortable * sortable,gpointer user_data)1732 sort_column_changed_cb (GtkTreeSortable *sortable,
1733 gpointer user_data)
1734 {
1735 GooWindow *window = user_data;
1736 GtkSortType order;
1737 int column_id;
1738 GooPlayerState state;
1739
1740 if (! gtk_tree_sortable_get_sort_column_id (sortable,
1741 &column_id,
1742 &order))
1743 {
1744 return;
1745 }
1746
1747 window->priv->sort_method = get_sort_method_from_column (column_id);
1748 window->priv->sort_type = order;
1749
1750 /* Recreate the playlist if not already playing. */
1751
1752 state = goo_player_get_state (window->priv->player);
1753 if ((state != GOO_PLAYER_STATE_PLAYING) && (state != GOO_PLAYER_STATE_PAUSED))
1754 create_playlist (window,
1755 g_settings_get_boolean (window->priv->settings_playlist, PREF_PLAYLIST_PLAYALL),
1756 g_settings_get_boolean (window->priv->settings_playlist, PREF_PLAYLIST_SHUFFLE));
1757 }
1758
1759
1760 static void
update_ui_from_expander_state(GooWindow * window)1761 update_ui_from_expander_state (GooWindow *window)
1762 {
1763 GdkGeometry hints;
1764
1765 if (gtk_widget_get_realized (GTK_WIDGET (window)))
1766 gtk_window_resize (GTK_WINDOW (window),
1767 g_settings_get_int (window->priv->settings_ui, PREF_UI_WINDOW_WIDTH),
1768 g_settings_get_int (window->priv->settings_ui, PREF_UI_WINDOW_HEIGHT));
1769
1770 hints.max_height = window->priv->resizable_playlist ? G_MAXINT : -1;
1771 hints.max_width = G_MAXINT;
1772 gtk_window_set_geometry_hints (GTK_WINDOW (window),
1773 GTK_WIDGET (window),
1774 &hints,
1775 GDK_HINT_MAX_SIZE);
1776 }
1777
1778
1779 static void
player_info_cover_clicked_cb(GooPlayerInfo * info,GooWindow * window)1780 player_info_cover_clicked_cb (GooPlayerInfo *info,
1781 GooWindow *window)
1782 {
1783 debug (DEBUG_INFO, "[Window] cover clicked\n");
1784 gtk_menu_popup_at_widget (GTK_MENU (window->priv->cover_popup_menu),
1785 GTK_WIDGET (info),
1786 GDK_GRAVITY_SOUTH_WEST,
1787 GDK_GRAVITY_NORTH_WEST,
1788 NULL);
1789 }
1790
1791
1792 static void
player_info_update_status_cb(GooPlayerInfo * info,GooWindow * window)1793 player_info_update_status_cb (GooPlayerInfo *info,
1794 GooWindow *window)
1795 {
1796 BraseroDrive *drive;
1797
1798 debug (DEBUG_INFO, "[Window] update status\n");
1799
1800 drive = goo_player_get_drive (window->priv->player);
1801 if (drive != NULL)
1802 brasero_drive_reprobe (drive);
1803 }
1804
1805
1806 static void
window_sync_ui_with_preferences(GooWindow * window)1807 window_sync_ui_with_preferences (GooWindow *window)
1808 {
1809 update_ui_from_expander_state (window);
1810 }
1811
1812
1813 static gboolean
window_key_press_cb(GtkWidget * widget,GdkEventKey * event,gpointer data)1814 window_key_press_cb (GtkWidget *widget,
1815 GdkEventKey *event,
1816 gpointer data)
1817 {
1818 GooWindow *window = data;
1819 gboolean retval = FALSE;
1820 int new_track = -1;
1821
1822 if (window->priv->album->n_tracks == 0)
1823 return FALSE;
1824
1825 switch (event->keyval) {
1826 case GDK_KEY_1:
1827 case GDK_KEY_2:
1828 case GDK_KEY_3:
1829 case GDK_KEY_4:
1830 case GDK_KEY_5:
1831 case GDK_KEY_6:
1832 case GDK_KEY_7:
1833 case GDK_KEY_8:
1834 case GDK_KEY_9:
1835 new_track = event->keyval - GDK_KEY_1;
1836 retval = TRUE;
1837 break;
1838 case GDK_KEY_0:
1839 new_track = 10 - 1;
1840 retval = TRUE;
1841 break;
1842 default:
1843 break;
1844 }
1845
1846 if ((new_track >= 0) && (new_track <= window->priv->album->n_tracks - 1)) {
1847 goo_window_stop (window);
1848 goo_window_set_current_track (window, new_track);
1849 goo_window_play (window);
1850 }
1851
1852
1853 return retval;
1854 }
1855
1856
1857 /* -- fr_window_add_accelerators -- */
1858
1859
1860 static GtkAccelGroup *
goo_window_get_accel_group(GooWindow * window)1861 goo_window_get_accel_group (GooWindow *window)
1862 {
1863 if (window->priv->accel_group == NULL) {
1864 window->priv->accel_group = gtk_accel_group_new ();
1865 gtk_window_add_accel_group (GTK_WINDOW (window), window->priv->accel_group);
1866 }
1867
1868 return window->priv->accel_group;
1869 }
1870
1871
1872 static void
goo_window_add_accelerators(GooWindow * window,const _GtkAccelerator * accelerators,int n_accelerators)1873 goo_window_add_accelerators (GooWindow *window,
1874 const _GtkAccelerator *accelerators,
1875 int n_accelerators)
1876 {
1877 GtkAccelGroup *accel_group;
1878 int i;
1879
1880 accel_group = goo_window_get_accel_group (window);
1881 for (i = 0; i < n_accelerators; i++) {
1882 const _GtkAccelerator *acc = accelerators + i;
1883
1884 _gtk_window_add_accelerator_for_action (GTK_WINDOW (window),
1885 accel_group,
1886 acc->action_name,
1887 acc->accelerator,
1888 NULL);
1889 }
1890 }
1891
1892
1893 static void
window_size_allocate_cb(GtkWidget * widget,GdkRectangle * allocation,gpointer user_data)1894 window_size_allocate_cb (GtkWidget *widget,
1895 GdkRectangle *allocation,
1896 gpointer user_data)
1897 {
1898 GooWindow *window = user_data;
1899 GdkRectangle geometry;
1900 int max_window_height;
1901
1902 if (window->priv->resizable_playlist)
1903 return;
1904
1905 if (!_gtk_widget_get_monitor_geometry (GTK_WIDGET (window), &geometry))
1906 return;
1907
1908 max_window_height = (float) geometry.height * MAX_WINDOW_HEIGHT_PERCENTAGE;
1909 if (allocation->height > max_window_height) {
1910 GdkGeometry hints;
1911
1912 hints.max_height = G_MAXINT;
1913 hints.max_width = G_MAXINT;
1914 gtk_window_set_geometry_hints (GTK_WINDOW (window),
1915 GTK_WIDGET (window),
1916 &hints,
1917 GDK_HINT_MAX_SIZE);
1918
1919 window->priv->resizable_playlist = TRUE;
1920
1921 gtk_window_resize (GTK_WINDOW (window),
1922 g_settings_get_int (window->priv->settings_ui, PREF_UI_WINDOW_WIDTH),
1923 max_window_height);
1924 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (window->priv->list_scrolled_window),
1925 GTK_POLICY_NEVER,
1926 GTK_POLICY_AUTOMATIC);
1927 }
1928 }
1929
1930
1931 static void
_gtk_menu_button_set_style_for_header_bar(GtkWidget * button)1932 _gtk_menu_button_set_style_for_header_bar (GtkWidget *button)
1933 {
1934 GtkStyleContext *context;
1935
1936 gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
1937 context = gtk_widget_get_style_context (button);
1938 gtk_style_context_add_class (context, "image-button");
1939 gtk_style_context_remove_class (context, "text-button");
1940 }
1941
1942
1943 static GtkWidget *
_gtk_image_button_new_for_header_bar(const char * icon_name)1944 _gtk_image_button_new_for_header_bar (const char *icon_name)
1945 {
1946 GtkWidget *button;
1947
1948 button = gtk_button_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
1949 _gtk_menu_button_set_style_for_header_bar (button);
1950
1951 return button;
1952 }
1953
1954
1955 static void
goo_window_init(GooWindow * window)1956 goo_window_init (GooWindow *window)
1957 {
1958 window->priv = goo_window_get_instance_private (window);
1959 window->priv->exiting = FALSE;
1960 window->priv->check_id = 0;
1961 window->priv->url_list = NULL;
1962 window->priv->hibernate = FALSE;
1963 window->priv->album = album_info_new ();
1964 window->priv->resizable_playlist = FALSE;
1965 window->priv->accel_group = gtk_accel_group_new ();
1966
1967 gtk_window_add_accel_group (GTK_WINDOW (window), window->priv->accel_group);
1968
1969
1970 g_action_map_add_action_entries (G_ACTION_MAP (window),
1971 goo_window_actions,
1972 G_N_ELEMENTS (goo_window_actions),
1973 window);
1974 goo_window_add_accelerators (window,
1975 goo_window_accelerators,
1976 G_N_ELEMENTS (goo_window_accelerators));
1977
1978 gtk_window_set_application (GTK_WINDOW (window), Main_Application);
1979
1980 g_signal_connect (window,
1981 "size-allocate",
1982 G_CALLBACK (window_size_allocate_cb),
1983 window);
1984 }
1985
1986
1987 static void
media_player_key_pressed_cb(GDBusProxy * proxy,char * sender_name,char * signal_name,GVariant * parameters,gpointer user_data)1988 media_player_key_pressed_cb (GDBusProxy *proxy,
1989 char *sender_name,
1990 char *signal_name,
1991 GVariant *parameters,
1992 gpointer user_data)
1993 {
1994 GooWindow *window = user_data;
1995 char *application;
1996 char *key;
1997
1998 if (g_strcmp0 (signal_name, "MediaPlayerKeyPressed") != 0)
1999 return;
2000
2001 g_variant_get (parameters, "(ss)", &application, &key);
2002
2003 if (g_strcmp0 (application, PACKAGE_NAME) == 0) {
2004 if (g_strcmp0 (key, "Play") == 0)
2005 goo_window_toggle_play (window);
2006 else if (g_strcmp0 (key, "Previous") == 0)
2007 goo_window_prev (window);
2008 else if (g_strcmp0 (key, "Next") == 0)
2009 goo_window_next (window);
2010 else if (g_strcmp0 (key, "Stop") == 0)
2011 goo_window_stop (window);
2012 }
2013
2014 g_free (application);
2015 g_free (key);
2016 }
2017
2018
2019 static gboolean
window_focus_in_event_cb(GtkWidget * widget,GdkEventFocus * event,gpointer user_data)2020 window_focus_in_event_cb (GtkWidget *widget,
2021 GdkEventFocus *event,
2022 gpointer user_data)
2023 {
2024 GooWindow *window = user_data;
2025
2026 g_dbus_proxy_call_sync (window->priv->media_keys_proxy,
2027 "GrabMediaPlayerKeys",
2028 g_variant_new ("(su)", PACKAGE_NAME, 0),
2029 G_DBUS_CALL_FLAGS_NONE,
2030 -1,
2031 NULL,
2032 NULL);
2033
2034 return FALSE;
2035 }
2036
2037
2038 static void
_goo_window_enable_media_keys(GooWindow * window)2039 _goo_window_enable_media_keys (GooWindow *window)
2040 {
2041 GDBusConnection *connection;
2042
2043 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
2044 if (connection == NULL)
2045 return;
2046
2047 window->priv->media_keys_proxy = g_dbus_proxy_new_sync (connection,
2048 G_DBUS_PROXY_FLAGS_NONE,
2049 NULL,
2050 "org.gnome.SettingsDaemon",
2051 "/org/gnome/SettingsDaemon/MediaKeys",
2052 "org.gnome.SettingsDaemon.MediaKeys",
2053 NULL,
2054 NULL);
2055 if (window->priv->media_keys_proxy == NULL)
2056 window->priv->media_keys_proxy = g_dbus_proxy_new_sync (connection,
2057 G_DBUS_PROXY_FLAGS_NONE,
2058 NULL,
2059 "org.gnome.SettingsDaemon",
2060 "/org/gnome/SettingsDaemon",
2061 "org.gnome.SettingsDaemon",
2062 NULL,
2063 NULL);
2064 g_object_unref (connection);
2065
2066 if (window->priv->media_keys_proxy == NULL)
2067 return;
2068
2069 g_dbus_proxy_call_sync (window->priv->media_keys_proxy,
2070 "GrabMediaPlayerKeys",
2071 g_variant_new ("(su)", PACKAGE_NAME, 0),
2072 G_DBUS_CALL_FLAGS_NONE,
2073 -1,
2074 NULL,
2075 NULL);
2076
2077 window->priv->media_key_event = g_signal_connect (window->priv->media_keys_proxy,
2078 "g-signal",
2079 G_CALLBACK (media_player_key_pressed_cb),
2080 window);
2081 window->priv->focus_in_event = g_signal_connect (window,
2082 "focus-in-event",
2083 G_CALLBACK (window_focus_in_event_cb),
2084 window);
2085 }
2086
2087
2088 static void
message_bar_response_cb(GtkInfoBar * info_bar,int response_id,gpointer user_data)2089 message_bar_response_cb (GtkInfoBar *info_bar,
2090 int response_id,
2091 gpointer user_data)
2092 {
2093 GooWindow *window = user_data;
2094
2095 switch (response_id) {
2096 case GTK_RESPONSE_CLOSE:
2097 goo_window_hide_message_bar (window);
2098 break;
2099 case MESSAGE_BAR_RESPONSE_PROPERTIES:
2100 goo_window_activate_properties (NULL, NULL, window);
2101 goo_window_hide_message_bar (window);
2102 break;
2103 }
2104 }
2105
2106
2107 static void
progress_skip_to_cb(GooPlayerProgress * progress,int seconds,GooWindow * window)2108 progress_skip_to_cb (GooPlayerProgress *progress,
2109 int seconds,
2110 GooWindow *window)
2111 {
2112 debug (DEBUG_INFO, "[Window] skip to %d\n", seconds);
2113 goo_player_skip_to (window->priv->player, (guint) seconds);
2114 }
2115
2116
2117 static void
volume_button_value_changed_cb(GtkScaleButton * button,gdouble value,gpointer user_data)2118 volume_button_value_changed_cb (GtkScaleButton *button,
2119 gdouble value,
2120 gpointer user_data)
2121 {
2122 GooWindow *window = user_data;
2123 goo_player_set_audio_volume (window->priv->player, value);
2124 }
2125
2126
2127 static void
goo_window_construct(GooWindow * window,BraseroDrive * drive)2128 goo_window_construct (GooWindow *window,
2129 BraseroDrive *drive)
2130 {
2131
2132 GtkWidget *scrolled_window;
2133 GtkWidget *vbox;
2134 GtkWidget *hbox;
2135 GtkTreeSelection *selection;
2136 GtkWidget *headerbar;
2137
2138 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window)), "goobox-main-window");
2139 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window)), GTK_STYLE_CLASS_VIEW);
2140
2141 g_signal_connect (G_OBJECT (window),
2142 "delete_event",
2143 G_CALLBACK (window_delete_event_cb),
2144 window);
2145 g_signal_connect (G_OBJECT (window),
2146 "key_press_event",
2147 G_CALLBACK (window_key_press_cb),
2148 window);
2149
2150 if (icon_size == 0)
2151 icon_size = get_icon_size_from_settings (GTK_ICON_SIZE_LARGE_TOOLBAR);
2152
2153 /* Create the settings objects */
2154
2155 window->priv->settings_general = g_settings_new (GOOBOX_SCHEMA_GENERAL);
2156 window->priv->settings_ui = g_settings_new (GOOBOX_SCHEMA_UI);
2157 window->priv->settings_playlist = g_settings_new (GOOBOX_SCHEMA_PLAYLIST);
2158 window->priv->settings_encoder = g_settings_new (GOOBOX_SCHEMA_ENCODER);
2159
2160 /* Create the data */
2161
2162 window->priv->player = goo_player_new (drive);
2163 goo_player_set_audio_volume (window->priv->player, g_settings_get_int (window->priv->settings_general, PREF_GENERAL_VOLUME));
2164
2165 g_signal_connect (window->priv->player,
2166 "start",
2167 G_CALLBACK (player_start_cb),
2168 window);
2169 g_signal_connect (window->priv->player,
2170 "done",
2171 G_CALLBACK (player_done_cb),
2172 window);
2173 g_signal_connect (window->priv->player,
2174 "state_changed",
2175 G_CALLBACK (player_state_changed_cb),
2176 window);
2177
2178 window->priv->playlist = NULL;
2179
2180 /* Create the widgets. */
2181
2182 /* * File list. */
2183
2184 window->priv->list_store = gtk_list_store_new (NUMBER_OF_COLUMNS,
2185 GOO_TYPE_TRACK_INFO,
2186 G_TYPE_INT,
2187 GDK_TYPE_PIXBUF,
2188 G_TYPE_STRING,
2189 G_TYPE_STRING,
2190 G_TYPE_STRING);
2191 window->priv->list_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (window->priv->list_store));
2192
2193 add_columns (window, GTK_TREE_VIEW (window->priv->list_view));
2194 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (window->priv->list_view), TRUE);
2195 gtk_tree_view_set_search_column (GTK_TREE_VIEW (window->priv->list_view), COLUMN_TITLE);
2196 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (window->priv->list_view), FALSE);
2197
2198 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store),
2199 COLUMN_TITLE, title_column_sort_func,
2200 NULL, NULL);
2201 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store),
2202 COLUMN_ARTIST, artist_column_sort_func,
2203 NULL, NULL);
2204 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store),
2205 COLUMN_TIME, time_column_sort_func,
2206 NULL, NULL);
2207
2208 window->priv->sort_method = g_settings_get_enum (window->priv->settings_playlist, PREF_PLAYLIST_SORT_METHOD);
2209 window->priv->sort_type = g_settings_get_enum (window->priv->settings_playlist, PREF_PLAYLIST_SORT_TYPE);
2210
2211 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (window->priv->list_store), get_column_from_sort_method (window->priv->sort_method), window->priv->sort_type);
2212
2213 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
2214 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
2215
2216 g_signal_connect (G_OBJECT (window->priv->list_view),
2217 "row_activated",
2218 G_CALLBACK (row_activated_cb),
2219 window);
2220 g_signal_connect (selection,
2221 "changed",
2222 G_CALLBACK (selection_changed_cb),
2223 window);
2224 g_signal_connect (G_OBJECT (window->priv->list_view),
2225 "button_press_event",
2226 G_CALLBACK (file_button_press_cb),
2227 window);
2228
2229 g_signal_connect (G_OBJECT (window->priv->list_store),
2230 "sort_column_changed",
2231 G_CALLBACK (sort_column_changed_cb),
2232 window);
2233
2234 window->priv->list_scrolled_window = scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2235 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
2236 GTK_POLICY_NEVER,
2237 GTK_POLICY_NEVER);
2238 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_NONE);
2239 gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 15);
2240 gtk_widget_set_hexpand (scrolled_window, TRUE);
2241 gtk_container_add (GTK_CONTAINER (scrolled_window), window->priv->list_view);
2242
2243 /* popup menus */
2244 {
2245 GtkBuilder *builder;
2246
2247 builder = _gtk_builder_new_from_resource ("menus.ui");
2248
2249 window->priv->file_popup_menu = gtk_menu_new_from_model (G_MENU_MODEL (gtk_builder_get_object (builder, "track-list-popup")));
2250 gtk_menu_attach_to_widget (GTK_MENU (window->priv->file_popup_menu), GTK_WIDGET (window), NULL);
2251
2252 window->priv->cover_popup_menu = gtk_menu_new_from_model (G_MENU_MODEL (gtk_builder_get_object (builder, "cover-popup")));
2253 gtk_menu_attach_to_widget (GTK_MENU (window->priv->cover_popup_menu), GTK_WIDGET (window), NULL);
2254
2255 g_object_unref (builder);
2256 }
2257
2258 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
2259
2260 /* message bar */
2261
2262 window->priv->message_bar = gtk_info_bar_new ();
2263 gtk_widget_set_no_show_all (window->priv->message_bar, TRUE);
2264 window->priv->message_label = gtk_label_new ("");
2265 gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (window->priv->message_bar))), window->priv->message_label);
2266 window->priv->message_bar_properties_button = gtk_button_new_with_mnemonic (_("_Properties"));
2267 gtk_info_bar_add_action_widget (GTK_INFO_BAR (window->priv->message_bar), window->priv->message_bar_properties_button, MESSAGE_BAR_RESPONSE_PROPERTIES);
2268 gtk_info_bar_add_button (GTK_INFO_BAR (window->priv->message_bar), _GTK_LABEL_CLOSE, GTK_RESPONSE_CLOSE);
2269 g_signal_connect (window->priv->message_bar,
2270 "response",
2271 G_CALLBACK (message_bar_response_cb),
2272 window);
2273 gtk_widget_show (window->priv->message_label);
2274 gtk_box_pack_start (GTK_BOX (vbox), window->priv->message_bar, FALSE, FALSE, 0);
2275
2276 /**/
2277
2278 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
2279 gtk_widget_set_vexpand (hbox, FALSE);
2280 gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
2281 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
2282
2283 window->priv->info = goo_player_info_new (window);
2284 gtk_container_set_border_width (GTK_CONTAINER (window->priv->info), 0);
2285 g_signal_connect (window->priv->info,
2286 "cover_clicked",
2287 G_CALLBACK (player_info_cover_clicked_cb),
2288 window);
2289 g_signal_connect (window->priv->info,
2290 "update-status",
2291 G_CALLBACK (player_info_update_status_cb),
2292 window);
2293 gtk_box_pack_start (GTK_BOX (hbox), window->priv->info, TRUE, TRUE, 0);
2294
2295 /**/
2296
2297 gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
2298
2299 /**/
2300
2301 gtk_widget_show_all (vbox);
2302 gtk_widget_hide (window->priv->list_scrolled_window);
2303
2304 gtk_container_add (GTK_CONTAINER (window), vbox);
2305
2306 gtk_widget_grab_focus (window->priv->list_view);
2307
2308 window_sync_ui_with_preferences (window);
2309
2310 gtk_window_set_default_size (GTK_WINDOW (window),
2311 g_settings_get_int (window->priv->settings_ui, PREF_UI_WINDOW_WIDTH),
2312 g_settings_get_int (window->priv->settings_ui, PREF_UI_WINDOW_HEIGHT));
2313
2314 headerbar = gtk_header_bar_new ();
2315 gtk_widget_show (headerbar);
2316 gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (headerbar), TRUE);
2317
2318 /* play buttons */
2319
2320 {
2321 GtkWidget *button;
2322 GtkWidget *button_box;
2323
2324 window->priv->play_button = button = _gtk_image_button_new_for_header_bar (GOO_ICON_NAME_PLAY);
2325 gtk_actionable_set_action_name (GTK_ACTIONABLE (button), "win.toggle-play");
2326 gtk_widget_show_all (button);
2327 gtk_header_bar_pack_start (GTK_HEADER_BAR (headerbar), button);
2328
2329 button_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
2330 gtk_style_context_add_class (gtk_widget_get_style_context (button_box), GTK_STYLE_CLASS_LINKED);
2331 gtk_widget_show (button_box);
2332 gtk_header_bar_pack_start (GTK_HEADER_BAR (headerbar), button_box);
2333
2334 button = _gtk_image_button_new_for_header_bar (GOO_ICON_NAME_PREV);
2335 gtk_actionable_set_action_name (GTK_ACTIONABLE (button), "win.previous-track");
2336 gtk_widget_show_all (button);
2337 gtk_box_pack_start (GTK_BOX (button_box), button, FALSE, FALSE, 0);
2338
2339 button = _gtk_image_button_new_for_header_bar (GOO_ICON_NAME_NEXT);
2340 gtk_actionable_set_action_name (GTK_ACTIONABLE (button), "win.next-track");
2341 gtk_widget_show_all (button);
2342 gtk_box_pack_start (GTK_BOX (button_box), button, FALSE, FALSE, 0);
2343
2344 button = gtk_volume_button_new ();
2345 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NORMAL);
2346 gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
2347 gtk_scale_button_set_adjustment (GTK_SCALE_BUTTON (button),
2348 gtk_adjustment_new (0.0,
2349 0.0,
2350 100.0,
2351 1.0,
2352 10.0,
2353 0.0));
2354 gtk_scale_button_set_value (GTK_SCALE_BUTTON (button), goo_player_get_audio_volume (window->priv->player));
2355 gtk_widget_show (button);
2356 gtk_header_bar_pack_start (GTK_HEADER_BAR (headerbar), button);
2357
2358 g_signal_connect (button,
2359 "value-changed",
2360 G_CALLBACK (volume_button_value_changed_cb),
2361 window);
2362 }
2363
2364 /* gears menu button */
2365
2366 {
2367 GtkBuilder *builder;
2368 GMenuModel *menu;
2369 GtkWidget *button;
2370
2371 builder = _gtk_builder_new_from_resource ("gears-menu.ui");
2372 menu = G_MENU_MODEL (gtk_builder_get_object (builder, "gears-menu"));
2373 button = gtk_menu_button_new ();
2374 _gtk_menu_button_set_style_for_header_bar (button);
2375 gtk_menu_button_set_direction (GTK_MENU_BUTTON (button), GTK_ARROW_NONE);
2376 gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (button), menu);
2377 gtk_menu_button_set_use_popover (GTK_MENU_BUTTON (button), FALSE);
2378 gtk_widget_show_all (button);
2379 gtk_header_bar_pack_end (GTK_HEADER_BAR (headerbar), button);
2380
2381 _gtk_window_add_accelerators_from_menu ((GTK_WINDOW (window)), menu);
2382
2383 g_object_unref (builder);
2384 }
2385
2386 /* extract button */
2387
2388 {
2389 GtkWidget *button;
2390
2391 button = _gtk_image_button_new_for_header_bar (GOO_ICON_NAME_EXTRACT);
2392 gtk_widget_set_tooltip_text (button, _("Extract Tracks"));
2393 gtk_actionable_set_action_name (GTK_ACTIONABLE (button), "win.extract");
2394 gtk_widget_show_all (button);
2395 gtk_header_bar_pack_end (GTK_HEADER_BAR (headerbar), button);
2396 }
2397
2398 /* custom title */
2399
2400 window->priv->progress = goo_player_progress_new (window->priv->player);
2401 gtk_widget_show (window->priv->progress);
2402 gtk_header_bar_set_custom_title (GTK_HEADER_BAR (headerbar), window->priv->progress);
2403
2404 g_signal_connect (window->priv->progress,
2405 "skip-to",
2406 G_CALLBACK (progress_skip_to_cb),
2407 window);
2408
2409 gtk_window_set_titlebar (GTK_WINDOW (window), headerbar);
2410
2411 goo_player_progress_set_title (GOO_PLAYER_PROGRESS (window->priv->progress), _("CD Player"));
2412
2413 /* Add notification callbacks. */
2414
2415 g_signal_connect (window->priv->settings_playlist,
2416 "changed::" PREF_PLAYLIST_PLAYALL,
2417 G_CALLBACK (pref_playlist_playall_changed),
2418 window);
2419 g_signal_connect (window->priv->settings_playlist,
2420 "changed::" PREF_PLAYLIST_SHUFFLE,
2421 G_CALLBACK (pref_playlist_shuffle_changed),
2422 window);
2423
2424 /* Media keys*/
2425
2426 _goo_window_enable_media_keys (window);
2427 }
2428
2429
2430 GtkWidget *
goo_window_new(BraseroDrive * drive)2431 goo_window_new (BraseroDrive *drive)
2432 {
2433 GooWindow *window;
2434
2435 if (drive == NULL) {
2436 GSettings *settings;
2437 char *default_device;
2438
2439 settings = g_settings_new (GOOBOX_SCHEMA_GENERAL);
2440 default_device = g_settings_get_string (settings, PREF_GENERAL_DEVICE);
2441 g_object_unref (settings);
2442
2443 if (default_device != NULL)
2444 drive = main_get_drive_for_device (default_device);
2445 if (drive == NULL)
2446 drive = main_get_most_likely_drive ();
2447
2448 g_free (default_device);
2449 }
2450
2451 window = (GooWindow*) g_object_new (GOO_TYPE_WINDOW, NULL);
2452 goo_window_construct (window, drive);
2453
2454 return (GtkWidget *) window;
2455 }
2456
2457
2458 /* -- goo_window_close -- */
2459
2460
2461 static gboolean
check_state_for_closing_cb(gpointer data)2462 check_state_for_closing_cb (gpointer data)
2463 {
2464 GooWindow *self = data;
2465
2466 g_source_remove (self->priv->check_id);
2467 self->priv->check_id = 0;
2468
2469 if (! goo_player_get_is_busy (self->priv->player)) {
2470 gtk_widget_destroy (GTK_WIDGET (self));
2471 return FALSE;
2472 }
2473
2474 self->priv->check_id = g_timeout_add (PLAYER_CHECK_RATE,
2475 check_state_for_closing_cb,
2476 self);
2477
2478 return FALSE;
2479 }
2480
2481
2482 void
goo_window_close(GooWindow * base)2483 goo_window_close (GooWindow *base)
2484 {
2485 GooWindow *self = GOO_WINDOW (base);
2486
2487 self->priv->exiting = TRUE;
2488 if (goo_player_get_is_busy (self->priv->player)) {
2489 gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
2490
2491 if (self->priv->check_id != 0)
2492 g_source_remove (self->priv->check_id);
2493 self->priv->check_id = g_timeout_add (PLAYER_CHECK_RATE,
2494 check_state_for_closing_cb,
2495 self);
2496 }
2497 else
2498 gtk_widget_destroy (GTK_WIDGET (self));
2499 }
2500
2501
2502 void
goo_window_play(GooWindow * window)2503 goo_window_play (GooWindow *window)
2504 {
2505 if (window->priv->hibernate)
2506 return;
2507
2508 if (! goo_player_is_audio_cd (window->priv->player))
2509 return;
2510
2511 if (goo_player_get_state (window->priv->player) == GOO_PLAYER_STATE_PLAYING)
2512 return;
2513
2514 if (goo_player_get_state (window->priv->player) != GOO_PLAYER_STATE_PAUSED) {
2515 gboolean play_all;
2516 gboolean shuffle;
2517
2518 play_all = g_settings_get_boolean (window->priv->settings_playlist, PREF_PLAYLIST_PLAYALL);
2519 shuffle = g_settings_get_boolean (window->priv->settings_playlist, PREF_PLAYLIST_SHUFFLE);
2520 create_playlist (window, play_all, shuffle);
2521
2522 if (window->priv->current_track != NULL)
2523 play_track (window, window->priv->current_track->number);
2524 else if (window->priv->playlist != NULL)
2525 play_next_track_in_playlist (window);
2526 else
2527 play_track (window, 0);
2528 }
2529 else {
2530 set_current_track_icon (window, GOO_ICON_NAME_PLAY);
2531 goo_player_play (window->priv->player);
2532 }
2533 }
2534
2535
2536 void
goo_window_play_selected(GooWindow * window)2537 goo_window_play_selected (GooWindow *window)
2538 {
2539 int track_n;
2540
2541 if (set_selected_track_if_unique (window, &track_n)) {
2542 goo_window_stop (window);
2543 goo_window_set_current_track (window, track_n);
2544 goo_window_play (window);
2545 }
2546 }
2547
2548
2549 void
goo_window_stop(GooWindow * window)2550 goo_window_stop (GooWindow *window)
2551 {
2552 if (window->priv->hibernate)
2553 return;
2554 if (! goo_player_is_audio_cd (window->priv->player))
2555 return;
2556 goo_player_stop (window->priv->player);
2557 }
2558
2559
2560 void
goo_window_pause(GooWindow * window)2561 goo_window_pause (GooWindow *window)
2562 {
2563 if (window->priv->hibernate)
2564 return;
2565 goo_player_pause (window->priv->player);
2566 }
2567
2568
2569 void
goo_window_toggle_play(GooWindow * window)2570 goo_window_toggle_play (GooWindow *window)
2571 {
2572 if (goo_player_get_state (window->priv->player) != GOO_PLAYER_STATE_PLAYING)
2573 goo_window_play (window);
2574 else
2575 goo_window_pause (window);
2576 }
2577
2578
2579 void
goo_window_next(GooWindow * window)2580 goo_window_next (GooWindow *window)
2581 {
2582 if (window->priv->album->n_tracks == 0)
2583 return;
2584
2585 if (! goo_player_is_audio_cd (window->priv->player))
2586 return;
2587
2588 if (play_next_track_in_playlist (window))
2589 return;
2590
2591 if (window->priv->current_track != NULL) {
2592 int current_track = window->priv->current_track->number;
2593 int current_pos;
2594 int new_pos, new_track;
2595
2596 goo_window_stop (window);
2597
2598 current_pos = get_position_from_track_number (window, current_track);
2599 new_pos = MIN (current_pos + 1, window->priv->album->n_tracks - 1);
2600 new_track = get_track_number_from_position (window, new_pos);
2601 goo_window_set_current_track (window, new_track);
2602 goo_window_play (window);
2603 }
2604 else
2605 goo_window_play (window);
2606 }
2607
2608
2609 void
goo_window_prev(GooWindow * window)2610 goo_window_prev (GooWindow *window)
2611 {
2612 int new_pos;
2613
2614 if (! goo_player_is_audio_cd (window->priv->player))
2615 return;
2616
2617 if (window->priv->album->n_tracks == 0)
2618 return;
2619
2620 if (window->priv->current_track != NULL) {
2621 int current_track, current_pos;
2622
2623 goo_window_stop (window);
2624
2625 current_track = window->priv->current_track->number;
2626 current_pos = get_position_from_track_number (window, current_track);
2627 new_pos = MAX (current_pos - 1, 0);
2628 goo_window_set_current_track (window, get_track_number_from_position (window, new_pos));
2629 goo_window_play (window);
2630 }
2631 else
2632 goo_window_play (window);
2633
2634 }
2635
2636
2637 void
goo_window_eject(GooWindow * window)2638 goo_window_eject (GooWindow *window)
2639 {
2640 if (window->priv->hibernate)
2641 return;
2642 goo_player_eject (window->priv->player);
2643 }
2644
2645
2646 void
goo_window_set_drive(GooWindow * window,BraseroDrive * drive)2647 goo_window_set_drive (GooWindow *window,
2648 BraseroDrive *drive)
2649 {
2650 BraseroDrive *current_drive;
2651
2652 current_drive = goo_player_get_drive (window->priv->player);
2653 if ((drive == NULL) && (current_drive == NULL))
2654 return;
2655 if ((drive != NULL) && (current_drive != NULL) && (g_strcmp0 (brasero_drive_get_device (drive), brasero_drive_get_device (current_drive)) == 0))
2656 return;
2657
2658 goo_player_set_drive (window->priv->player, drive);
2659 goo_player_update (window->priv->player);
2660 }
2661
2662
2663 AlbumInfo *
goo_window_get_album(GooWindow * window)2664 goo_window_get_album (GooWindow *window)
2665 {
2666 return window->priv->album;
2667 }
2668
2669
2670 GList *
goo_window_get_tracks(GooWindow * window,gboolean selection)2671 goo_window_get_tracks (GooWindow *window,
2672 gboolean selection)
2673 {
2674 GtkTreeSelection *list_selection;
2675 GList *tracks;
2676
2677 if (window->priv->album->tracks == NULL)
2678 return NULL;
2679
2680 if (! selection)
2681 return track_list_dup (window->priv->album->tracks);
2682
2683 /* return selected track list */
2684
2685 list_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
2686 if (list_selection == NULL)
2687 return NULL;
2688
2689 tracks = NULL;
2690 gtk_tree_selection_selected_foreach (list_selection, add_selected_track, &tracks);
2691
2692 return g_list_reverse (tracks);
2693 }
2694
2695
2696 GooPlayer *
goo_window_get_player(GooWindow * window)2697 goo_window_get_player (GooWindow *window)
2698 {
2699 return window->priv->player;
2700 }
2701
2702
2703 GtkWidget *
goo_window_get_player_info(GooWindow * window)2704 goo_window_get_player_info (GooWindow *window)
2705 {
2706 return window->priv->info;
2707 }
2708
2709
2710 #define MIN_COVER_SIZE 10
2711
2712
2713 gboolean
goo_window_set_cover_image_from_pixbuf(GooWindow * window,GdkPixbuf * image)2714 goo_window_set_cover_image_from_pixbuf (GooWindow *window,
2715 GdkPixbuf *image)
2716 {
2717 GError *error = NULL;
2718 GdkPixbuf *frame;
2719 char *cover_filename;
2720 gboolean image_saved;
2721
2722 if (image == NULL)
2723 return FALSE;
2724
2725 if ((gdk_pixbuf_get_width (image) < MIN_COVER_SIZE) || (gdk_pixbuf_get_height (image) < MIN_COVER_SIZE))
2726 return FALSE;
2727
2728 frame = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (image),
2729 gdk_pixbuf_get_has_alpha (image),
2730 gdk_pixbuf_get_bits_per_sample (image),
2731 gdk_pixbuf_get_width (image) + 2,
2732 gdk_pixbuf_get_height (image) + 2);
2733 gdk_pixbuf_fill (frame, 0x00000000);
2734 gdk_pixbuf_copy_area (image,
2735 0, 0,
2736 gdk_pixbuf_get_width (image),
2737 gdk_pixbuf_get_height (image),
2738 frame,
2739 1, 1);
2740
2741 cover_filename = goo_window_get_cover_filename (window);
2742 debug (DEBUG_INFO, "SAVE IMAGE %s\n", cover_filename);
2743
2744 image_saved = gdk_pixbuf_save (frame, cover_filename, "png", &error, NULL);
2745 if (image_saved) {
2746 goo_window_set_current_cd_autofetch (window, FALSE);
2747 goo_window_update_cover (window);
2748 }
2749 else
2750 _gtk_error_dialog_from_gerror_run (GTK_WINDOW (window),
2751 _("Could not save cover image"),
2752 &error);
2753
2754 g_free (cover_filename);
2755 g_object_unref (frame);
2756
2757 return image_saved;
2758 }
2759
2760
2761 gboolean
goo_window_set_cover_image(GooWindow * window,const char * filename)2762 goo_window_set_cover_image (GooWindow *window,
2763 const char *filename)
2764 {
2765 GdkPixbuf *image;
2766 GError *error = NULL;
2767 gboolean result;
2768
2769 if (window->priv->hibernate)
2770 return FALSE;
2771
2772 image = gdk_pixbuf_new_from_file (filename, &error);
2773 if (image == NULL) {
2774 _gtk_error_dialog_from_gerror_run (GTK_WINDOW (window),
2775 _("Could not load image"),
2776 &error);
2777 return FALSE;
2778 }
2779
2780 result = goo_window_set_cover_image_from_pixbuf (window, image);
2781
2782 g_object_unref (image);
2783
2784 return result;
2785 }
2786
2787
2788 gboolean
goo_window_set_cover_image_from_data(GooWindow * window,void * buffer,gsize count)2789 goo_window_set_cover_image_from_data (GooWindow *window,
2790 void *buffer,
2791 gsize count)
2792 {
2793 GInputStream *stream;
2794 GdkPixbuf *image;
2795 GError *error = NULL;
2796 gboolean result;
2797
2798 if (window->priv->hibernate)
2799 return FALSE;
2800
2801 stream = g_memory_input_stream_new_from_data (buffer, count, NULL);
2802 image = gdk_pixbuf_new_from_stream (stream, NULL, &error);
2803
2804 if (image == NULL) {
2805 _gtk_error_dialog_from_gerror_run (GTK_WINDOW (window),
2806 _("Could not load image"),
2807 &error);
2808 g_object_unref (stream);
2809 return FALSE;
2810 }
2811
2812 result = goo_window_set_cover_image_from_pixbuf (window, image);
2813
2814 g_object_unref (image);
2815 g_object_unref (stream);
2816
2817 return result;
2818 }
2819
2820
2821 static void
open_update_preview_cb(GtkFileChooser * file_sel,gpointer user_data)2822 open_update_preview_cb (GtkFileChooser *file_sel,
2823 gpointer user_data)
2824 {
2825 GooWindow *window = user_data;
2826 char *uri;
2827
2828 uri = gtk_file_chooser_get_preview_uri (file_sel);
2829 debug (DEBUG_INFO, "PREVIEW: %s", uri);
2830 gtk_file_chooser_preview_set_uri (GTK_FILE_CHOOSER_PREVIEW (window->priv->preview), uri);
2831 g_free (uri);
2832 }
2833
2834
2835 static void
open_response_cb(GtkDialog * file_sel,int button_number,gpointer user_data)2836 open_response_cb (GtkDialog *file_sel,
2837 int button_number,
2838 gpointer user_data)
2839 {
2840 GooWindow *window = user_data;
2841 char *folder;
2842 char *filename;
2843
2844 if (button_number != GTK_RESPONSE_ACCEPT) {
2845 gtk_widget_destroy (GTK_WIDGET (file_sel));
2846 return;
2847 }
2848
2849 /* Save the folder */
2850
2851 folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (file_sel));
2852 g_settings_set_string (window->priv->settings_general, PREF_GENERAL_COVER_PATH, folder);
2853 g_free (folder);
2854
2855 /* Load the image. */
2856
2857 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_sel));
2858 goo_window_set_cover_image (window, filename);
2859 g_free (filename);
2860
2861 gtk_widget_destroy (GTK_WIDGET (file_sel));
2862 }
2863
2864
2865 void
goo_window_pick_cover_from_disk(GooWindow * window)2866 goo_window_pick_cover_from_disk (GooWindow *window)
2867 {
2868 GtkWidget *file_sel;
2869 GtkFileFilter *filter;
2870 char *path;
2871
2872 if (window->priv->hibernate)
2873 return;
2874
2875 goo_window_set_current_cd_autofetch (window, FALSE);
2876
2877 file_sel = gtk_file_chooser_dialog_new (_("Choose Disc Cover Image"),
2878 GTK_WINDOW (window),
2879 GTK_FILE_CHOOSER_ACTION_OPEN,
2880 _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
2881 _GTK_LABEL_OPEN, GTK_RESPONSE_ACCEPT,
2882 NULL);
2883 gtk_window_set_modal (GTK_WINDOW (file_sel), TRUE);
2884 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (file_sel), TRUE);
2885
2886 window->priv->preview = gtk_file_chooser_preview_new ();
2887 gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (file_sel), window->priv->preview);
2888 gtk_file_chooser_set_use_preview_label (GTK_FILE_CHOOSER (file_sel), FALSE);
2889 gtk_file_chooser_set_preview_widget_active (GTK_FILE_CHOOSER (file_sel), TRUE);
2890
2891 path = g_settings_get_string (window->priv->settings_general, PREF_GENERAL_COVER_PATH);
2892 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (file_sel), path);
2893 g_free (path);
2894
2895 filter = gtk_file_filter_new ();
2896 gtk_file_filter_set_name (filter, _("Images"));
2897 gtk_file_filter_add_mime_type (filter, "image/jpeg");
2898 gtk_file_filter_add_mime_type (filter, "image/png");
2899 gtk_file_filter_add_mime_type (filter, "image/gif");
2900 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (file_sel), filter);
2901 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (file_sel), filter);
2902
2903 filter = gtk_file_filter_new ();
2904 gtk_file_filter_set_name (filter, _("All files"));
2905 gtk_file_filter_add_pattern (filter, "*");
2906 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (file_sel), filter);
2907
2908 g_signal_connect (G_OBJECT (file_sel),
2909 "response",
2910 G_CALLBACK (open_response_cb),
2911 window);
2912 g_signal_connect (G_OBJECT (file_sel),
2913 "update-preview",
2914 G_CALLBACK (open_update_preview_cb),
2915 window);
2916 g_signal_connect_swapped (GTK_DIALOG (file_sel),
2917 "close",
2918 G_CALLBACK (gtk_widget_destroy),
2919 GTK_WIDGET (file_sel));
2920
2921 gtk_widget_show_all (GTK_WIDGET (file_sel));
2922 }
2923
2924
2925 void
goo_window_search_cover_on_internet(GooWindow * window)2926 goo_window_search_cover_on_internet (GooWindow *window)
2927 {
2928 if (window->priv->hibernate)
2929 return;
2930
2931 goo_window_set_current_cd_autofetch (window, FALSE);
2932
2933 debug (DEBUG_INFO, "SEARCH ON INTERNET\n");
2934
2935 if ((window->priv->album->title == NULL) || (window->priv->album->artist == NULL)) {
2936 GtkWidget *d;
2937
2938 d = _gtk_error_dialog_new (GTK_WINDOW (window),
2939 GTK_DIALOG_MODAL,
2940 NULL,
2941 _("Could not search for a cover on Internet"),
2942 "%s",
2943 _("You have to enter the artist and album names in order to find the album cover."));
2944 g_signal_connect (G_OBJECT (d), "response",
2945 G_CALLBACK (gtk_widget_destroy),
2946 NULL);
2947 gtk_widget_show (d);
2948 return;
2949 }
2950
2951 dlg_cover_chooser (window, window->priv->album->title, window->priv->album->artist);
2952 }
2953
2954
2955 void
goo_window_remove_cover(GooWindow * window)2956 goo_window_remove_cover (GooWindow *window)
2957 {
2958 char *cover_filename;
2959 GFile *file;
2960
2961 if (window->priv->hibernate)
2962 return;
2963
2964 goo_window_set_current_cd_autofetch (window, FALSE);
2965
2966 cover_filename = goo_window_get_cover_filename (window);
2967 if (cover_filename == NULL)
2968 return;
2969
2970 file = g_file_new_for_path (cover_filename);
2971 g_file_delete (file, NULL, NULL);
2972
2973 g_free (cover_filename);
2974
2975 goo_window_update_cover (window);
2976 }
2977
2978
2979 void
goo_window_toggle_visibility(GooWindow * window)2980 goo_window_toggle_visibility (GooWindow *window)
2981 {
2982 if (gtk_widget_get_visible (GTK_WIDGET (window))) {
2983 gtk_window_get_position (GTK_WINDOW (window),
2984 &window->priv->pos_x,
2985 &window->priv->pos_y);
2986 gtk_widget_hide (GTK_WIDGET (window));
2987 }
2988 else {
2989 gtk_window_move (GTK_WINDOW (window),
2990 window->priv->pos_x,
2991 window->priv->pos_y);
2992 gtk_window_present (GTK_WINDOW (window));
2993 }
2994 }
2995
2996
2997 void
goo_window_set_hibernate(GooWindow * window,gboolean hibernate)2998 goo_window_set_hibernate (GooWindow *window,
2999 gboolean hibernate)
3000 {
3001 window->priv->hibernate = hibernate;
3002 goo_player_hibernate (window->priv->player, hibernate);
3003 if (! hibernate)
3004 goo_window_update (window);
3005 }
3006