1 /*
2  *  Copyright (C) 2005 Marc Pavot <marc.pavot@gmail.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2, or (at your option)
7  *  any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  */
19 
20 #include "widgets/ario-header.h"
21 #include <gtk/gtk.h>
22 #include <config.h>
23 #include <string.h>
24 #include <glib/gi18n.h>
25 
26 #include "ario-util.h"
27 #include "ario-debug.h"
28 #include "covers/ario-cover.h"
29 #include "covers/ario-cover-handler.h"
30 #include "covers/ario-cover-handler.h"
31 #include "shell/ario-shell-coverselect.h"
32 #include "widgets/ario-volume.h"
33 
34 static GObject* ario_header_constructor (GType type, guint n_construct_properties,
35                                          GObjectConstructParam *construct_properties);
36 static gboolean ario_header_image_press_cb (GtkWidget *widget,
37                                             GdkEventButton *event,
38                                             ArioHeader *header);
39 static gboolean ario_header_slider_press_cb (GtkWidget *widget,
40                                              GdkEventButton *event,
41                                              ArioHeader *header);
42 static gboolean ario_header_slider_release_cb (GtkWidget *widget,
43                                                GdkEventButton *event,
44                                                ArioHeader *header);
45 static void ario_header_slider_value_changed_cb (GtkWidget *widget,
46                                                  ArioHeader *header);
47 static void ario_header_song_changed_cb (ArioServer *server,
48                                          ArioHeader *header);
49 static void ario_header_album_changed_cb (ArioServer *server,
50                                           ArioHeader *header);
51 static void ario_header_state_changed_cb (ArioServer *server,
52                                           ArioHeader *header);
53 static void ario_header_cover_changed_cb (ArioCoverHandler *cover_handler,
54                                           ArioHeader *header);
55 static void ario_header_elapsed_changed_cb (ArioServer *server,
56                                             int elapsed,
57                                             ArioHeader *header);
58 static void ario_header_consume_changed_cb (ArioServer *server,
59                                            ArioHeader *header);
60 static void ario_header_random_changed_cb (ArioServer *server,
61                                            ArioHeader *header);
62 static void ario_header_repeat_changed_cb (ArioServer *server,
63                                            ArioHeader *header);
64 static void ario_header_do_consume (ArioHeader *header);
65 static void ario_header_do_random (ArioHeader *header);
66 static void ario_header_do_repeat (ArioHeader *header);
67 
68 #define SONG_MARKUP(xSONG) g_markup_printf_escaped ("<big><b>%s</b></big>", xSONG);
69 #define FROM_MARKUP(xALBUM, xARTIST) g_markup_printf_escaped (_("<i>from</i> %s <i>by</i> %s"), xALBUM, xARTIST);
70 
71 struct ArioHeaderPrivate
72 {
73         GtkWidget *prev_button;
74         GtkWidget *play_pause_button;
75         GtkWidget *consume_button;
76         GtkWidget *random_button;
77         GtkWidget *repeat_button;
78 
79         GtkWidget *stop_button;
80         GtkWidget *next_button;
81 
82         GtkWidget *play_image;
83         GtkWidget *pause_image;
84 
85         GtkWidget *image;
86 
87         GtkWidget *song;
88         GtkWidget *artist_album;
89 
90         GtkWidget *scale;
91         GtkAdjustment *adjustment;
92 
93         GtkWidget *elapsed;
94         GtkWidget *of;
95         GtkWidget *total;
96 
97         GtkWidget *volume_button;
98 
99         gboolean slider_dragging;
100 
101         gint image_width;
102         gint image_height;
103 };
104 
105 #define ARIO_HEADER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_ARIO_HEADER, ArioHeaderPrivate))
G_DEFINE_TYPE(ArioHeader,ario_header,GTK_TYPE_BOX)106 G_DEFINE_TYPE (ArioHeader, ario_header, GTK_TYPE_BOX)
107 
108 static void
109 ario_header_class_init (ArioHeaderClass *klass)
110 {
111         ARIO_LOG_FUNCTION_START;
112         GObjectClass *object_class = G_OBJECT_CLASS (klass);
113 
114         /* Virtual methods */
115         object_class->constructor = ario_header_constructor;
116 
117         /* Private attributes */
118         g_type_class_add_private (klass, sizeof (ArioHeaderPrivate));
119 }
120 
121 static void
ario_header_init(ArioHeader * header)122 ario_header_init (ArioHeader *header)
123 {
124         ARIO_LOG_FUNCTION_START;
125         header->priv = ARIO_HEADER_GET_PRIVATE (header);
126 }
127 
128 static void
ario_header_drag_leave_cb(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * data,guint info,guint time,ArioHeader * header)129 ario_header_drag_leave_cb (GtkWidget *widget,
130                            GdkDragContext *context,
131                            gint x,
132                            gint y,
133                            GtkSelectionData *data,
134                            guint info,
135                            guint time,
136                            ArioHeader *header)
137 {
138         ARIO_LOG_FUNCTION_START;
139         gchar *url;
140         gchar *contents;
141         gsize length;
142 
143         if (info == 1) {
144                 /* Image dropped */
145                 ARIO_LOG_INFO ("image  DND : TODO\n");
146         } else if (info == 2) {
147                 const guchar *udata = gtk_selection_data_get_data (data);
148                 /* URL dropped */
149                 url = g_strndup ((gchar *) udata + 7, gtk_selection_data_get_length (data) - 2 - 7);
150                 if (ario_util_uri_exists (url)) {
151                         /* Get file content and save it as the cover */
152                         if (ario_file_get_contents (url,
153                                                     &contents,
154                                                     &length,
155                                                     NULL)) {
156                                 ario_cover_save_cover (ario_server_get_current_artist (),
157                                                        ario_server_get_current_album (),
158                                                        contents, length,
159                                                        OVERWRITE_MODE_REPLACE);
160                                 g_free (contents);
161                                 ario_cover_handler_force_reload ();
162                         }
163                 }
164                 g_free (url);
165         }
166 
167         /* finish the drag */
168         gtk_drag_finish (context, TRUE, FALSE, time);
169 }
170 
171 static GObject *
ario_header_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)172 ario_header_constructor (GType type, guint n_construct_properties,
173                          GObjectConstructParam *construct_properties)
174 {
175         ARIO_LOG_FUNCTION_START;
176         ArioHeader *header;
177         ArioHeaderClass *klass;
178         GObjectClass *parent_class;
179         GtkWidget *cover_event_box;
180         GtkTargetList *targets;
181         GtkTargetEntry *target_entry;
182         gint n_elem;
183         GtkWidget *image, *hbox, *right_hbox, *vbox;
184         GList *focus = NULL;
185 
186         klass = ARIO_HEADER_CLASS (g_type_class_peek (TYPE_ARIO_HEADER));
187 
188         parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
189         header = ARIO_HEADER (parent_class->constructor (type, n_construct_properties,
190                                                          construct_properties));
191         gtk_orientable_set_orientation (GTK_ORIENTABLE (header), GTK_ORIENTATION_HORIZONTAL);
192 
193         /* Construct previous button */
194         image = gtk_image_new_from_icon_name ("media-skip-backward",
195                                           GTK_ICON_SIZE_LARGE_TOOLBAR);
196 
197         header->priv->prev_button = gtk_button_new ();
198         gtk_container_add (GTK_CONTAINER (header->priv->prev_button), image);
199         g_signal_connect_swapped (header->priv->prev_button,
200                                   "clicked",
201                                   G_CALLBACK (ario_header_do_previous),
202                                   header);
203         gtk_widget_set_tooltip_text (GTK_WIDGET (header->priv->prev_button),
204                                      _("Play previous song"));
205 
206         /* Construct button images */
207         header->priv->play_image = gtk_image_new_from_icon_name ("media-playback-start",
208                                                              GTK_ICON_SIZE_LARGE_TOOLBAR);
209         g_object_ref (header->priv->play_image);
210         gtk_widget_show (header->priv->play_image);
211         header->priv->pause_image = gtk_image_new_from_icon_name ("media-playback-pause",
212                                                               GTK_ICON_SIZE_LARGE_TOOLBAR);
213         g_object_ref (header->priv->pause_image);
214         gtk_widget_show (header->priv->pause_image);
215         header->priv->play_pause_button = gtk_button_new ();
216         gtk_container_add (GTK_CONTAINER (header->priv->play_pause_button), header->priv->pause_image);
217         g_signal_connect_swapped (header->priv->play_pause_button,
218                                   "clicked",
219                                   G_CALLBACK (ario_header_playpause),
220                                   header);
221         gtk_widget_set_tooltip_text (GTK_WIDGET (header->priv->play_pause_button),
222                                      _("Play/Pause the music"));
223 
224         /* Construct stop button */
225         image = gtk_image_new_from_icon_name ("media-playback-stop",
226                                           GTK_ICON_SIZE_LARGE_TOOLBAR);
227         header->priv->stop_button = gtk_button_new ();
228         gtk_container_add (GTK_CONTAINER (header->priv->stop_button), image);
229         g_signal_connect_swapped (header->priv->stop_button,
230                                   "clicked",
231                                   G_CALLBACK (ario_header_stop),
232                                   header);
233         gtk_widget_set_tooltip_text (GTK_WIDGET (header->priv->stop_button),
234                                      _("Stop the music"));
235 
236         /* Construct next button */
237         image = gtk_image_new_from_icon_name ("media-skip-forward",
238                                           GTK_ICON_SIZE_LARGE_TOOLBAR);
239         header->priv->next_button = gtk_button_new ();
240         gtk_container_add (GTK_CONTAINER (header->priv->next_button), image);
241         g_signal_connect_swapped (header->priv->next_button,
242                                   "clicked",
243                                   G_CALLBACK (ario_header_do_next),
244                                   header);
245         gtk_widget_set_tooltip_text (GTK_WIDGET (header->priv->next_button),
246                                      _("Play next song"));
247 
248         /* Construct cover display */
249         cover_event_box = gtk_event_box_new ();
250         header->priv->image = gtk_image_new ();
251         gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR,
252                               &header->priv->image_width,
253                               &header->priv->image_height);
254         header->priv->image_width += 18;
255         header->priv->image_height += 18;
256         gtk_container_add (GTK_CONTAINER (cover_event_box), header->priv->image);
257         g_signal_connect (cover_event_box,
258                           "button_press_event",
259                           G_CALLBACK (ario_header_image_press_cb),
260                           header);
261         targets = gtk_target_list_new (NULL, 0);
262         gtk_target_list_add_image_targets (targets, 1, TRUE);
263         gtk_target_list_add_uri_targets (targets, 2);
264         target_entry = gtk_target_table_new_from_list (targets, &n_elem);
265         gtk_target_list_unref (targets);
266 
267         gtk_drag_dest_set (cover_event_box,
268                            GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP,
269                            target_entry, n_elem,
270                            GDK_ACTION_COPY);
271         gtk_target_table_free (target_entry, n_elem);
272 
273         g_signal_connect (cover_event_box,
274                           "drag_data_received",
275                           G_CALLBACK (ario_header_drag_leave_cb),
276                           header);
277 
278         g_signal_connect_object (ario_cover_handler_get_instance (),
279                                  "cover_changed", G_CALLBACK (ario_header_cover_changed_cb),
280                                  header, 0);
281 
282         /* Construct Song/Artist/Album display */
283         header->priv->song = gtk_label_new ("");
284         gtk_label_set_ellipsize (GTK_LABEL (header->priv->song), PANGO_ELLIPSIZE_END);
285         gtk_label_set_use_markup (GTK_LABEL (header->priv->song), TRUE);
286 
287         header->priv->artist_album = gtk_label_new ("");
288         gtk_label_set_ellipsize (GTK_LABEL (header->priv->artist_album), PANGO_ELLIPSIZE_END);
289 
290         /* Construct time slider */
291         header->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 10.0, 1.0, 10.0, 0.0));
292         header->priv->scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, header->priv->adjustment);
293 
294         g_signal_connect (header->priv->scale,
295                           "button_press_event",
296                           G_CALLBACK (ario_header_slider_press_cb),
297                           header);
298         g_signal_connect (header->priv->scale,
299                           "button_release_event",
300                           G_CALLBACK (ario_header_slider_release_cb),
301                           header);
302         g_signal_connect (header->priv->scale,
303                           "value-changed",
304                           G_CALLBACK (ario_header_slider_value_changed_cb),
305                           header);
306 
307         gtk_scale_set_draw_value (GTK_SCALE (header->priv->scale), FALSE);
308         gtk_widget_set_size_request (header->priv->scale, 150, -1);
309 
310         header->priv->elapsed = gtk_label_new ("0:00");
311         /* Translators - This " of " is used to count the elapsed time
312            of a song like in "00:59 of 03:24" */
313         header->priv->of = gtk_label_new (_(" of "));
314         header->priv->total = gtk_label_new ("0:00");
315 
316         /* Construct consume button */
317         image = gtk_image_new_from_icon_name ("consume",
318                                           GTK_ICON_SIZE_LARGE_TOOLBAR);
319         header->priv->consume_button = gtk_toggle_button_new ();
320         gtk_container_add (GTK_CONTAINER (header->priv->consume_button), image);
321         g_signal_connect_swapped (header->priv->consume_button,
322                                   "clicked",
323                                   G_CALLBACK (ario_header_do_consume),
324                                   header);
325         gtk_widget_set_tooltip_text (GTK_WIDGET (header->priv->consume_button),
326                                      _("Toggle 'consume' (remove played song from playlist) on/off"));
327 
328         /* Construct random button */
329         image = gtk_image_new_from_icon_name ("shuffle",
330                                           GTK_ICON_SIZE_LARGE_TOOLBAR);
331         header->priv->random_button = gtk_toggle_button_new ();
332         gtk_container_add (GTK_CONTAINER (header->priv->random_button), image);
333         g_signal_connect_swapped (header->priv->random_button,
334                                   "clicked",
335                                   G_CALLBACK (ario_header_do_random),
336                                   header);
337         gtk_widget_set_tooltip_text (GTK_WIDGET (header->priv->random_button),
338                                      _("Toggle random on/off"));
339 
340         /* Construct repeat button */
341         image = gtk_image_new_from_icon_name ("repeat",
342                                           GTK_ICON_SIZE_LARGE_TOOLBAR);
343         header->priv->repeat_button = gtk_toggle_button_new ();
344         gtk_container_add (GTK_CONTAINER (header->priv->repeat_button), image);
345         g_signal_connect_swapped (header->priv->repeat_button,
346                                   "clicked",
347                                   G_CALLBACK (ario_header_do_repeat),
348                                   header);
349         gtk_widget_set_tooltip_text (GTK_WIDGET (header->priv->repeat_button),
350                                      _("Toggle repeat on/off"));
351 
352         /* Construct volume button */
353         header->priv->volume_button = GTK_WIDGET (ario_volume_new ());
354         gtk_widget_set_tooltip_text (header->priv->volume_button,
355                                      _("Change the music volume"));
356 
357         /* Add everything in header Hbox */
358         gtk_box_set_spacing (GTK_BOX (header), 12);
359 
360         /* Add command Buttons */
361         hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
362         gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
363 
364         gtk_box_pack_start (GTK_BOX (hbox), header->priv->prev_button, FALSE, TRUE, 0);
365         gtk_box_pack_start (GTK_BOX (hbox), header->priv->play_pause_button, FALSE, TRUE, 0);
366         gtk_box_pack_start (GTK_BOX (hbox), header->priv->stop_button, FALSE, TRUE, 0);
367         gtk_box_pack_start (GTK_BOX (hbox), header->priv->next_button, FALSE, TRUE, 0);
368 
369         gtk_box_pack_start (GTK_BOX (header), hbox, FALSE, TRUE, 0);
370 
371         /* Add cover */
372         gtk_box_pack_start (GTK_BOX (header), cover_event_box, FALSE, TRUE, 0);
373 
374         /* Add song labels */
375         vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
376         gtk_box_pack_start (GTK_BOX (vbox), header->priv->song, TRUE, TRUE, 0);
377         gtk_box_pack_start (GTK_BOX (vbox), header->priv->artist_album, TRUE, TRUE, 0);
378 
379         gtk_box_pack_start (GTK_BOX (header), vbox, TRUE, TRUE, 0);
380 
381         /* Add time slider */
382         vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
383         hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
384         right_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
385 
386         gtk_box_pack_start (GTK_BOX (hbox), header->priv->elapsed, FALSE, TRUE, 0);
387         gtk_box_pack_start (GTK_BOX (hbox), header->priv->of, FALSE, TRUE, 0);
388         gtk_box_pack_start (GTK_BOX (hbox), header->priv->total, FALSE, TRUE, 0);
389 
390         gtk_box_pack_start (GTK_BOX (vbox), header->priv->scale, FALSE, TRUE, 0);
391         gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
392         gtk_box_pack_start (GTK_BOX (right_hbox), vbox, FALSE, TRUE, 0);
393 
394         /* Add consume/random/repeat buttons */
395         gtk_box_pack_start (GTK_BOX (right_hbox), header->priv->consume_button, FALSE, TRUE, 0);
396         gtk_box_pack_start (GTK_BOX (right_hbox), header->priv->random_button, FALSE, TRUE, 0);
397         gtk_box_pack_start (GTK_BOX (right_hbox), header->priv->repeat_button, FALSE, TRUE, 0);
398 
399         /* Add volume button */
400         gtk_box_pack_start (GTK_BOX (right_hbox), header->priv->volume_button, FALSE, TRUE, 5);
401 
402         gtk_box_pack_end (GTK_BOX (header), right_hbox, FALSE, TRUE, 0);
403 
404         /* Set focus chain */
405         focus = g_list_append (focus, header->priv->scale);
406         gtk_container_set_focus_chain (GTK_CONTAINER (header), focus);
407 
408         return G_OBJECT (header);
409 }
410 
411 GtkWidget *
ario_header_new(void)412 ario_header_new (void)
413 {
414         ARIO_LOG_FUNCTION_START;
415         ArioHeader *header;
416         ArioServer *server = ario_server_get_instance ();
417 
418         header = ARIO_HEADER (g_object_new (TYPE_ARIO_HEADER,
419                                             NULL));
420 
421         g_return_val_if_fail (header->priv != NULL, NULL);
422 
423         /* Signals to synchronize the header with server */
424         g_signal_connect_object (server,
425                                  "song_changed", G_CALLBACK (ario_header_song_changed_cb),
426                                  header, 0);
427         g_signal_connect_object (server,
428                                  "album_changed", G_CALLBACK (ario_header_album_changed_cb),
429                                  header, 0);
430         g_signal_connect_object (server,
431                                  "state_changed", G_CALLBACK (ario_header_state_changed_cb),
432                                  header, 0);
433         g_signal_connect_object (server,
434                                  "elapsed_changed", G_CALLBACK (ario_header_elapsed_changed_cb),
435                                  header, 0);
436         g_signal_connect_object (server,
437                                  "consume_changed", G_CALLBACK (ario_header_consume_changed_cb),
438                                  header, 0);
439         g_signal_connect_object (server,
440                                  "random_changed", G_CALLBACK (ario_header_random_changed_cb),
441                                  header, 0);
442         g_signal_connect_object (server,
443                                  "repeat_changed", G_CALLBACK (ario_header_repeat_changed_cb),
444                                  header, 0);
445 
446         return GTK_WIDGET (header);
447 }
448 
449 static void
ario_header_change_total_time(ArioHeader * header)450 ario_header_change_total_time (ArioHeader *header)
451 {
452         ARIO_LOG_FUNCTION_START;
453         char *tmp;
454         int total_time;
455 
456         /* Get total song time from server */
457         if (!ario_server_is_connected ()) {
458                 total_time = 0;
459         } else {
460                 switch (ario_server_get_current_state ()) {
461                 case ARIO_STATE_PLAY:
462                 case ARIO_STATE_PAUSE:
463                         total_time = ario_server_get_current_total_time ();
464                         break;
465                 case ARIO_STATE_UNKNOWN:
466                 case ARIO_STATE_STOP:
467                 default:
468                         total_time = 0;
469                         break;
470                 }
471 
472         }
473 
474         /* Change label value with total time */
475         if (total_time > 0) {
476                 tmp = ario_util_format_time (total_time);
477                 gtk_label_set_text (GTK_LABEL (header->priv->total), tmp);
478                 g_free (tmp);
479                 gtk_widget_show (header->priv->total);
480                 gtk_widget_show (header->priv->of);
481         } else {
482                 gtk_widget_hide (header->priv->total);
483                 gtk_widget_hide (header->priv->of);
484         }
485 
486         /* Change slider higher value */
487         gtk_adjustment_set_upper (header->priv->adjustment, total_time);
488 }
489 
490 static void
ario_header_change_song_label(ArioHeader * header)491 ario_header_change_song_label (ArioHeader *header)
492 {
493         ARIO_LOG_FUNCTION_START;
494         char *title;
495         char *tmp;
496 
497         switch (ario_server_get_current_state ()) {
498         case ARIO_STATE_PLAY:
499         case ARIO_STATE_PAUSE:
500                 /* Set the label with formated title from server */
501                 title = ario_util_format_title (ario_server_get_current_song ());
502 
503                 tmp = SONG_MARKUP (title);
504                 gtk_label_set_markup (GTK_LABEL (header->priv->song), tmp);
505                 g_free (tmp);
506                 break;
507         case ARIO_STATE_UNKNOWN:
508         case ARIO_STATE_STOP:
509         default:
510                 /* Set default label value */
511                 gtk_label_set_label (GTK_LABEL (header->priv->song), "");
512                 break;
513         }
514 }
515 
516 static void
ario_header_change_artist_album_label(ArioHeader * header)517 ario_header_change_artist_album_label (ArioHeader *header)
518 {
519         ARIO_LOG_FUNCTION_START;
520         char *artist;
521         char *album;
522         char *tmp;
523 
524         switch (ario_server_get_current_state ()) {
525         case ARIO_STATE_PLAY:
526         case ARIO_STATE_PAUSE:
527                 /* Set label value with server values */
528                 artist = ario_server_get_current_artist ();
529                 album = ario_server_get_current_album ();
530 
531                 if (!album)
532                         album = ARIO_SERVER_UNKNOWN;
533 
534                 if (!artist)
535                         artist = ARIO_SERVER_UNKNOWN;
536 
537                 tmp = FROM_MARKUP (album, artist);
538                 gtk_label_set_markup (GTK_LABEL (header->priv->artist_album), tmp);
539                 g_free (tmp);
540                 break;
541         case ARIO_STATE_UNKNOWN:
542         case ARIO_STATE_STOP:
543         default:
544                 /* Set default label value */
545                 gtk_label_set_label (GTK_LABEL (header->priv->artist_album), "");
546                 break;
547         }
548 }
549 
550 static void
ario_header_change_cover(ArioHeader * header)551 ario_header_change_cover (ArioHeader *header)
552 {
553         ARIO_LOG_FUNCTION_START;
554         GdkPixbuf *cover;
555         GdkPixbuf *small_cover = NULL;
556 
557         switch (ario_server_get_current_state ()) {
558         case ARIO_STATE_PLAY:
559         case ARIO_STATE_PAUSE:
560                 /* Get cover from cover handler and display it */
561                 cover = ario_cover_handler_get_cover ();
562                 if (cover) {
563                         small_cover = gdk_pixbuf_scale_simple (cover,
564                                                                header->priv->image_width,
565                                                                header->priv->image_height,
566                                                                GDK_INTERP_BILINEAR);
567                 }
568 
569                 gtk_image_set_from_pixbuf (GTK_IMAGE (header->priv->image), small_cover);
570 
571                 if (small_cover)
572                         g_object_unref (small_cover);
573                 break;
574         case ARIO_STATE_UNKNOWN:
575         case ARIO_STATE_STOP:
576         default:
577                 /* Set default cover (empty) */
578                 gtk_image_set_from_pixbuf (GTK_IMAGE (header->priv->image), NULL);
579                 break;
580         }
581 }
582 
583 static void
ario_header_song_changed_cb(ArioServer * server,ArioHeader * header)584 ario_header_song_changed_cb (ArioServer *server,
585                              ArioHeader *header)
586 {
587         ARIO_LOG_FUNCTION_START;
588         /* Synchronize song label */
589         ario_header_change_song_label (header);
590 
591         /* Synchronize total time label */
592         ario_header_change_total_time (header);
593 }
594 
595 static void
ario_header_album_changed_cb(ArioServer * server,ArioHeader * header)596 ario_header_album_changed_cb (ArioServer *server,
597                               ArioHeader *header)
598 {
599         ARIO_LOG_FUNCTION_START;
600         /* Synchronize Artist-Album label */
601         ario_header_change_artist_album_label (header);
602 }
603 
604 static void
ario_header_cover_changed_cb(ArioCoverHandler * cover_handler,ArioHeader * header)605 ario_header_cover_changed_cb (ArioCoverHandler *cover_handler,
606                               ArioHeader *header)
607 {
608         ARIO_LOG_FUNCTION_START;
609         /* Synchronize cover art */
610         ario_header_change_cover (header);
611 }
612 
613 static void
ario_header_state_changed_cb(ArioServer * server,ArioHeader * header)614 ario_header_state_changed_cb (ArioServer *server,
615                               ArioHeader *header)
616 {
617         ARIO_LOG_FUNCTION_START;
618 
619         /* Synchronize song label */
620         ario_header_change_song_label (header);
621 
622         /* Synchronize Artist-Album label */
623         ario_header_change_artist_album_label (header);
624 
625         /* Synchronize total time label */
626         ario_header_change_total_time (header);
627 
628         /* Remove icon from play/pause button */
629         gtk_container_remove (GTK_CONTAINER (header->priv->play_pause_button),
630                               gtk_bin_get_child (GTK_BIN (header->priv->play_pause_button)));
631 
632         /* Set the appropriate icon in play/pause button */
633         if (ario_server_is_paused ())
634                 gtk_container_add (GTK_CONTAINER (header->priv->play_pause_button),
635                                    header->priv->play_image);
636         else
637                 gtk_container_add (GTK_CONTAINER (header->priv->play_pause_button),
638                                    header->priv->pause_image);
639 
640         if (!ario_server_is_connected ()) {
641                 /* Set button insensitive if Ario is not connected to a server */
642                 gtk_widget_set_sensitive (header->priv->prev_button, FALSE);
643                 gtk_widget_set_sensitive (header->priv->play_pause_button, FALSE);
644 
645                 gtk_widget_set_sensitive (header->priv->consume_button, FALSE);
646                 gtk_widget_set_sensitive (header->priv->random_button, FALSE);
647                 gtk_widget_set_sensitive (header->priv->repeat_button, FALSE);
648 
649                 gtk_widget_set_sensitive (header->priv->stop_button, FALSE);
650                 gtk_widget_set_sensitive (header->priv->next_button, FALSE);
651 
652                 gtk_widget_set_sensitive (header->priv->scale, FALSE);
653 
654                 gtk_widget_set_sensitive (header->priv->volume_button, FALSE);
655         } else {
656                 /* Set button sensitive if Ario is connected to a server */
657                 gtk_widget_set_sensitive (header->priv->prev_button, TRUE);
658                 gtk_widget_set_sensitive (header->priv->play_pause_button, TRUE);
659 
660                 gtk_widget_set_sensitive (header->priv->consume_button, TRUE);
661                 gtk_widget_set_sensitive (header->priv->random_button, TRUE);
662                 gtk_widget_set_sensitive (header->priv->repeat_button, TRUE);
663 
664                 gtk_widget_set_sensitive (header->priv->stop_button, TRUE);
665                 gtk_widget_set_sensitive (header->priv->next_button, TRUE);
666 
667                 gtk_widget_set_sensitive (header->priv->scale, TRUE);
668 
669                 gtk_widget_set_sensitive (header->priv->volume_button, TRUE);
670         }
671 }
672 
673 static void
ario_header_elapsed_changed_cb(ArioServer * server,int elapsed,ArioHeader * header)674 ario_header_elapsed_changed_cb (ArioServer *server,
675                                 int elapsed,
676                                 ArioHeader *header)
677 {
678         ARIO_LOG_FUNCTION_START;
679         gchar time[ARIO_MAX_TIME_SIZE];
680 
681         if (header->priv->slider_dragging)
682                 return;
683 
684         /* Update elapsed time label */
685         ario_util_format_time_buf (elapsed, time, ARIO_MAX_TIME_SIZE);
686         gtk_label_set_text (GTK_LABEL (header->priv->elapsed), time);
687 
688         /* Update slider value */
689         gtk_adjustment_set_value (header->priv->adjustment, (gdouble) elapsed);
690 }
691 
692 static void
ario_header_consume_changed_cb(ArioServer * server,ArioHeader * header)693 ario_header_consume_changed_cb (ArioServer *server,
694                                ArioHeader *header)
695 {
696         ARIO_LOG_FUNCTION_START;
697         gboolean consume;
698 
699         /* Get consume state on server */
700         consume = ario_server_get_current_consume ();
701 
702         /* Block consume button signal */
703         g_signal_handlers_block_by_func (G_OBJECT (header->priv->consume_button),
704                                          G_CALLBACK (ario_header_do_consume),
705                                          header);
706 
707         /* Change button state depending on consume value */
708         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (header->priv->consume_button),
709                                       consume);
710 
711         /* Unblock consume button signal */
712         g_signal_handlers_unblock_by_func (G_OBJECT (header->priv->consume_button),
713                                            G_CALLBACK (ario_header_do_consume),
714                                            header);
715 }
716 
717 static void
ario_header_random_changed_cb(ArioServer * server,ArioHeader * header)718 ario_header_random_changed_cb (ArioServer *server,
719                                ArioHeader *header)
720 {
721         ARIO_LOG_FUNCTION_START;
722         gboolean random;
723 
724         /* Get random state on server */
725         random = ario_server_get_current_random ();
726 
727         /* Block random button signal */
728         g_signal_handlers_block_by_func (G_OBJECT (header->priv->random_button),
729                                          G_CALLBACK (ario_header_do_random),
730                                          header);
731 
732         /* Change button state depending on random value */
733         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (header->priv->random_button),
734                                       random);
735 
736         /* Unblock random button signal */
737         g_signal_handlers_unblock_by_func (G_OBJECT (header->priv->random_button),
738                                            G_CALLBACK (ario_header_do_random),
739                                            header);
740 }
741 
742 static void
ario_header_repeat_changed_cb(ArioServer * server,ArioHeader * header)743 ario_header_repeat_changed_cb (ArioServer *server,
744                                ArioHeader *header)
745 {
746         ARIO_LOG_FUNCTION_START;
747         gboolean repeat;
748 
749         /* Get repeat state on server */
750         repeat = ario_server_get_current_repeat ();
751 
752         /* Block repeat button signal */
753         g_signal_handlers_block_by_func (G_OBJECT (header->priv->repeat_button),
754                                          G_CALLBACK (ario_header_do_repeat),
755                                          header);
756 
757         /* Change button state depending on repeat value */
758         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (header->priv->repeat_button),
759                                       repeat);
760 
761         /* Unblock repeat button signal */
762         g_signal_handlers_unblock_by_func (G_OBJECT (header->priv->repeat_button),
763                                            G_CALLBACK (ario_header_do_repeat),
764                                            header);
765 }
766 
767 static gboolean
ario_header_image_press_cb(GtkWidget * widget,GdkEventButton * event,ArioHeader * header)768 ario_header_image_press_cb (GtkWidget *widget,
769                             GdkEventButton *event,
770                             ArioHeader *header)
771 {
772         GtkWidget *coverselect;
773         ArioServerAlbum server_album;
774 
775         /* Double click on cover art launches the cover selection dialog */
776         if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) {
777                 server_album.artist = ario_server_get_current_artist ();
778                 server_album.album = ario_server_get_current_album ();
779                 server_album.path = g_path_get_dirname ((ario_server_get_current_song ())->file);
780 
781                 if (!server_album.album)
782                         server_album.album = ARIO_SERVER_UNKNOWN;
783 
784                 if (!server_album.artist)
785                         server_album.artist = ARIO_SERVER_UNKNOWN;
786 
787                 coverselect = ario_shell_coverselect_new (&server_album);
788                 gtk_dialog_run (GTK_DIALOG (coverselect));
789                 gtk_widget_destroy (coverselect);
790                 g_free (server_album.path);
791         }
792 
793         return FALSE;
794 }
795 
796 static gboolean
ario_header_slider_press_cb(GtkWidget * widget,GdkEventButton * event,ArioHeader * header)797 ario_header_slider_press_cb (GtkWidget *widget,
798                              GdkEventButton *event,
799                              ArioHeader *header)
800 {
801         ARIO_LOG_FUNCTION_START;
802         header->priv->slider_dragging = TRUE;
803         return FALSE;
804 }
805 
806 static gboolean
ario_header_slider_release_cb(GtkWidget * widget,GdkEventButton * event,ArioHeader * header)807 ario_header_slider_release_cb (GtkWidget *widget,
808                                GdkEventButton *event,
809                                ArioHeader *header)
810 {
811         ARIO_LOG_FUNCTION_START;
812         gdouble scale;
813 
814         header->priv->slider_dragging = FALSE;
815         /* Change elapsed time on server */
816         scale = gtk_range_get_value (GTK_RANGE (header->priv->scale));
817         ario_server_set_current_elapsed ((int) scale);
818         return FALSE;
819 }
820 
ario_header_slider_value_changed_cb(GtkWidget * widget,ArioHeader * header)821 static void ario_header_slider_value_changed_cb (GtkWidget *widget,
822                                                  ArioHeader *header)
823 {
824         ARIO_LOG_FUNCTION_START;
825         gchar time[ARIO_MAX_TIME_SIZE];
826         int elapsed;
827         gdouble scale;
828 
829         if (header->priv->slider_dragging) {
830                 /* If user is dragging the slider, we update displayed value */
831                 scale = gtk_range_get_value (GTK_RANGE (header->priv->scale));
832                 elapsed = (int) scale;
833                 ario_util_format_time_buf (elapsed, time, ARIO_MAX_TIME_SIZE);
834                 gtk_label_set_text (GTK_LABEL (header->priv->elapsed), time);
835         }
836 }
837 
838 void
ario_header_do_next(ArioHeader * header)839 ario_header_do_next (ArioHeader *header)
840 {
841         ARIO_LOG_FUNCTION_START;
842         g_return_if_fail (IS_ARIO_HEADER (header));
843         /* Change to next song */
844         ario_server_do_next ();
845 }
846 
847 void
ario_header_do_previous(ArioHeader * header)848 ario_header_do_previous (ArioHeader *header)
849 {
850         ARIO_LOG_FUNCTION_START;
851         g_return_if_fail (IS_ARIO_HEADER (header));
852         /* Change to previous song */
853         ario_server_do_prev ();
854 }
855 
856 void
ario_header_playpause(ArioHeader * header)857 ario_header_playpause (ArioHeader *header)
858 {
859         ARIO_LOG_FUNCTION_START;
860         g_return_if_fail (IS_ARIO_HEADER (header));
861         /* Play/pause on server */
862         if (ario_server_is_paused ())
863                 ario_server_do_play ();
864         else
865                 ario_server_do_pause ();
866 }
867 
868 void
ario_header_stop(ArioHeader * header)869 ario_header_stop (ArioHeader *header)
870 {
871         ARIO_LOG_FUNCTION_START;
872         g_return_if_fail (IS_ARIO_HEADER (header));
873         /* Stop music */
874         ario_server_do_stop ();
875 }
876 
877 static void
ario_header_do_consume(ArioHeader * header)878 ario_header_do_consume (ArioHeader *header)
879 {
880         ARIO_LOG_FUNCTION_START;
881         g_return_if_fail (IS_ARIO_HEADER (header));
882         /* Change consume on server */
883         ario_server_set_current_consume (!ario_server_get_current_consume ());
884 }
885 
886 static void
ario_header_do_random(ArioHeader * header)887 ario_header_do_random (ArioHeader *header)
888 {
889         ARIO_LOG_FUNCTION_START;
890         g_return_if_fail (IS_ARIO_HEADER (header));
891         /* Change random on server */
892         ario_server_set_current_random (!ario_server_get_current_random ());
893 }
894 
895 static void
ario_header_do_repeat(ArioHeader * header)896 ario_header_do_repeat (ArioHeader *header)
897 {
898         ARIO_LOG_FUNCTION_START;
899         g_return_if_fail (IS_ARIO_HEADER (header));
900         /* Change repeat on server */
901         ario_server_set_current_repeat (!ario_server_get_current_repeat ());
902 }
903