~ubuntu-branches/ubuntu/utopic/rhythmbox/utopic-proposed

« back to all changes in this revision

Viewing changes to widgets/rb-header.c

Tags: upstream-0.9.2
ImportĀ upstreamĀ versionĀ 0.9.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
#include "rb-stock-icons.h"
38
38
#include "rb-header.h"
39
39
#include "rb-debug.h"
40
 
#include "rb-ellipsizing-label.h"
41
40
#include "rb-preferences.h"
42
41
#include "eel-gconf-extensions.h"
43
42
 
55
54
static long rb_header_get_duration (RBHeader *player);
56
55
static void rb_header_set_show_timeline (RBHeader *player,
57
56
                                         gboolean show);
58
 
static gboolean rb_header_sync_time_locked (RBHeader *player);
59
57
static void rb_header_update_elapsed (RBHeader *player);
60
58
static gboolean slider_press_callback (GtkWidget *widget, GdkEventButton *event, RBHeader *player);
61
59
static gboolean slider_moved_callback (GtkWidget *widget, GdkEventMotion *event, RBHeader *player);
62
60
static gboolean slider_release_callback (GtkWidget *widget, GdkEventButton *event, RBHeader *player);
63
61
static void slider_changed_callback (GtkWidget *widget, RBHeader *player);
64
62
 
 
63
static void rb_header_tick_cb (RBPlayer *mmplayer, long time, RBHeader *header);
 
64
 
65
65
typedef struct
66
66
{
67
67
        long elapsed;
77
77
        char *urltext, *urllink;
78
78
 
79
79
        RBPlayer *mmplayer;
 
80
        gulong tick_id;
80
81
 
81
82
        GtkWidget *image;
82
83
        GtkWidget *song;
83
84
 
84
85
        GtkWidget *timeframe;
85
86
        GtkWidget *timeline;
86
 
        gboolean timeline_shown;
87
87
        GtkWidget *scale;
88
88
        GtkAdjustment *adjustment;
89
89
        gboolean slider_dragging;
102
102
        gboolean urlline_shown;
103
103
        GnomeHRef *url;
104
104
 
105
 
        guint timeout;
106
 
        
107
105
        RBHeaderState *state;
108
106
};
109
107
 
111
109
{
112
110
        PROP_0,
113
111
        PROP_DB,
114
 
        PROP_HEADER,
 
112
        PROP_PLAYER,
115
113
        PROP_ENTRY,
116
114
        PROP_TITLE,
117
115
        PROP_URLTEXT,
176
174
                                                               "RhythmDBEntry pointer",
177
175
                                                               G_PARAM_READWRITE));
178
176
        g_object_class_install_property (object_class,
179
 
                                         PROP_HEADER,
 
177
                                         PROP_PLAYER,
180
178
                                         g_param_spec_object ("player",
181
179
                                                              "Player",
182
 
                                                              "MonkeyMediaPlayer",
 
180
                                                              "RBPlayer object",
183
181
                                                              RB_TYPE_PLAYER,
184
182
                                                              G_PARAM_READWRITE));
185
183
        g_object_class_install_property (object_class,
216
214
         *     GtkVBox
217
215
         *       GtkAlignment
218
216
         *         GtkVBox
219
 
         *           RBEllipsizingLabel (priv->song)
 
217
         *           GtkLabel           (priv->song)
220
218
         *           GtkHBox            (priv->textframe)
221
219
         *             RBSongDisplayBox (priv->displaybox)
222
220
         *               GtkLabel       ("from")
253
251
        textvbox = gtk_vbox_new (FALSE, 0);
254
252
        gtk_container_add (GTK_CONTAINER (align), textvbox);
255
253
        
256
 
        player->priv->song = rb_ellipsizing_label_new ("");
257
 
        rb_ellipsizing_label_set_mode (RB_ELLIPSIZING_LABEL (player->priv->song), RB_ELLIPSIZE_END);
 
254
        player->priv->song = gtk_label_new ("");
 
255
        gtk_label_set_ellipsize (GTK_LABEL (player->priv->song), PANGO_ELLIPSIZE_END);
258
256
        gtk_label_set_use_markup (GTK_LABEL (player->priv->song), TRUE);
259
257
        gtk_label_set_selectable (GTK_LABEL (player->priv->song), TRUE);        
260
258
        gtk_misc_set_alignment (GTK_MISC (player->priv->song), 0, 0);
313
311
        gtk_container_add (GTK_CONTAINER (align), player->priv->elapsed);
314
312
        gtk_box_pack_start (GTK_BOX (scalebox), align, FALSE, TRUE, 0);
315
313
        align = player->priv->timeframe = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
 
314
        gtk_container_add (GTK_CONTAINER (player->priv->timeframe), player->priv->timeline);
 
315
        gtk_widget_set_sensitive (player->priv->timeline, FALSE);
316
316
 
317
317
        gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
318
318
 
319
319
        gtk_box_pack_start (GTK_BOX (player), hbox, TRUE, TRUE, 0);
320
320
        gtk_box_pack_end (GTK_BOX (player), align, FALSE, FALSE, 0);
321
 
 
322
 
        player->priv->timeout = g_timeout_add (1000, (GSourceFunc) rb_header_sync_time_locked, player);
323
321
}
324
322
 
325
323
static void
334
332
 
335
333
        g_return_if_fail (player->priv != NULL);
336
334
 
337
 
        g_source_remove (player->priv->timeout);
338
 
 
339
335
        g_object_unref (G_OBJECT (player->priv->urlline));
340
336
        g_object_unref (G_OBJECT (player->priv->displaybox));
341
337
        g_object_unref (G_OBJECT (player->priv->timeline));
361
357
        case PROP_ENTRY:
362
358
                player->priv->entry = g_value_get_pointer (value);
363
359
                break;
364
 
        case PROP_HEADER:
 
360
        case PROP_PLAYER:
 
361
                if (player->priv->mmplayer) {
 
362
                        g_signal_handler_disconnect (player->priv->mmplayer,
 
363
                                                     player->priv->tick_id);
 
364
                        player->priv->tick_id = 0;
 
365
                }
365
366
                player->priv->mmplayer = g_value_get_object (value);
 
367
                player->priv->tick_id = g_signal_connect (G_OBJECT (player->priv->mmplayer),
 
368
                                                          "tick", 
 
369
                                                          (GCallback) rb_header_tick_cb,
 
370
                                                          player);
366
371
                break;
367
372
        case PROP_TITLE:
368
373
                g_free (player->priv->title);
397
402
        case PROP_ENTRY:
398
403
                g_value_set_object (value, player->priv->entry);
399
404
                break;
400
 
        case PROP_HEADER:
 
405
        case PROP_PLAYER:
401
406
                g_value_set_object (value, player->priv->mmplayer);
402
407
                break;
403
408
        case PROP_TITLE:
444
449
static long
445
450
rb_header_get_duration (RBHeader *player)
446
451
{
447
 
        long ret;
448
452
        if (player->priv->entry) {
449
 
                rhythmdb_read_lock (player->priv->db);
450
 
                ret = rhythmdb_entry_get_long (player->priv->db,
451
 
                                               player->priv->entry,
452
 
                                               RHYTHMDB_PROP_DURATION);
453
 
                rhythmdb_read_unlock (player->priv->db);
454
 
                return ret;
 
453
                return player->priv->entry->duration;
455
454
        }
456
455
        return -1;
457
456
}
458
457
 
459
458
static char *
460
 
info_url (guint opt, const char *data)
461
 
{
462
 
        char * ret, *p;
463
 
 
464
 
        ret = g_strdup_printf ("http://www.allmusic.com/cg/amg.dll?p=amg&opt1=%d&sql=%s", opt, data);
465
 
 
466
 
        for (p = ret; *p; p++)
467
 
                if (*p == ' ')
468
 
                        *p = '+';
 
459
sanitize_string (const char *data)
 
460
{
 
461
        char *ret;
 
462
        
 
463
        /*
 
464
         * netlabels often put URLs (or domain names) in the 'album' field
 
465
         * of their releases; since there are no artist names in AMG that
 
466
         * start with 'http://' or 'www.' (there is a 'www', from the 70s,
 
467
         * strangely enough), we can safely assume anything that looks 
 
468
         * like a URL or domain name is one.
 
469
         *
 
470
         * There's sometimes some trailing junk, usually after a space,
 
471
         * so it's probably sensible to strip that off.
 
472
         */
 
473
        if (g_str_has_prefix (data, "http://")) {
 
474
                char *end = strchr (data, ' ');
 
475
                if (end != NULL)
 
476
                        ret = g_strndup (data, end - data);
 
477
                else
 
478
                        ret = g_strdup (data);
 
479
        } else if (g_str_has_prefix (data, "www.")) {
 
480
                char *end = strchr (data, ' ');
 
481
                if (end != NULL)
 
482
                        ret = g_strdup_printf ("http://%*s",
 
483
                                               (int) (end-data), data);
 
484
                else
 
485
                        ret = g_strdup_printf ("http://%s", data);
 
486
        } else {
 
487
                ret = g_strdup (data);
 
488
        }
 
489
        return g_strstrip (ret);
 
490
}
 
491
 
 
492
static char *
 
493
info_url (const char *artist, const char *album)
 
494
{
 
495
        char *escaped_artist;
 
496
        char *sanitized_artist;
 
497
        char *ret;
 
498
 
 
499
        sanitized_artist = sanitize_string (artist);
 
500
        escaped_artist = gnome_vfs_escape_string (sanitized_artist);
 
501
        g_free (sanitized_artist);
 
502
        if (album) {
 
503
                char *sanitized_album;
 
504
                char *escaped_album;
 
505
                sanitized_album = sanitize_string (album);
 
506
                escaped_album = gnome_vfs_escape_string (sanitized_album);
 
507
                g_free (sanitized_album);
 
508
                ret = g_strdup_printf ("http://www.last.fm/music/%s/%s",
 
509
                                       escaped_artist, escaped_album);
 
510
                g_free (escaped_album);
 
511
        } else {
 
512
                ret = g_strdup_printf ("http://www.last.fm/music/%s", escaped_artist);
 
513
        }
 
514
        g_free (escaped_artist);
 
515
 
469
516
        return ret;
470
517
}
471
518
 
472
 
static char *
473
 
album_info_url (const char *album)
474
 
{
475
 
        return info_url (2, album);
476
 
}
477
 
 
478
 
static char *
479
 
artist_info_url (const char *album)
480
 
{
481
 
        return info_url (1, album);
482
 
}
483
 
 
484
519
void
485
520
rb_header_sync (RBHeader *player)
486
521
{
489
524
        rb_debug ("syncing with node = %p", player->priv->entry);
490
525
        if (player->priv->entry != NULL) {
491
526
                const char *song = player->priv->title;
492
 
                char *escaped, *s;
 
527
                char *escaped;
493
528
                gboolean have_duration = rb_header_get_duration (player) > 0;
494
529
                const char *album; 
495
530
                const char *artist; 
496
531
                GtkTooltips *artist_href_tips, *album_href_tips;
497
532
 
498
 
                rhythmdb_read_lock (player->priv->db);
499
 
 
500
 
                album = rhythmdb_entry_get_string (player->priv->db,
501
 
                                                   player->priv->entry,
502
 
                                                   RHYTHMDB_PROP_ALBUM);
503
 
 
504
 
                artist = rhythmdb_entry_get_string (player->priv->db,
505
 
                                                    player->priv->entry,
506
 
                                                    RHYTHMDB_PROP_ARTIST);
507
 
 
508
 
                rhythmdb_read_unlock (player->priv->db);
 
533
 
 
534
                album = rb_refstring_get (player->priv->entry->album);
 
535
                artist = rb_refstring_get (player->priv->entry->artist);
509
536
 
510
537
                escaped = g_markup_escape_text (song, -1);
511
538
                tmp = SONG_MARKUP (escaped);
512
539
                g_free (escaped);
513
 
                rb_ellipsizing_label_set_markup (RB_ELLIPSIZING_LABEL (player->priv->song), tmp);
 
540
                gtk_label_set_markup (GTK_LABEL (player->priv->song), tmp);
514
541
                g_free (tmp);
515
542
 
516
543
                rb_header_set_show_artist_album (player, (album != NULL && artist != NULL)
523
550
 
524
551
                        rb_debug ("artist: %s album: %s", artist, album);
525
552
 
526
 
                        s = tmp = g_strdup (album);
527
 
                        while ((tmp = strstr (tmp, " ")) != NULL)
528
 
                                *tmp = '|';
529
 
                        tmp = album_info_url (s);
530
 
                        g_free (s);
531
 
 
 
553
                        tmp = info_url (artist, album);
532
554
                        gnome_href_set_url (player->priv->displaybox->album, tmp);
533
555
                        escaped = g_markup_escape_text (album, -1);
534
556
                        gnome_href_set_text (player->priv->displaybox->album, escaped);
541
563
                                              _("Get information on this album from the web"), 
542
564
                                              NULL);
543
565
                        
544
 
                        s = tmp = g_strdup (artist);
545
 
                        while ((tmp = strstr (tmp, " ")) != NULL)
546
 
                        {
547
 
                                *tmp = '|';
548
 
                        }
549
 
                        tmp = artist_info_url (s);
550
 
                        g_free (s);
 
566
                        tmp = info_url (artist, NULL);
551
567
                        gnome_href_set_url (player->priv->displaybox->artist, tmp);
552
568
                        escaped = g_markup_escape_text (artist, -1);
553
569
                        gnome_href_set_text (player->priv->displaybox->artist, escaped);
578
594
                GtkTooltips *iradio_href_tips;
579
595
 
580
596
                rb_debug ("not playing");
581
 
                tmp = SONG_MARKUP (_("Not playing"));
582
 
                rb_ellipsizing_label_set_markup (RB_ELLIPSIZING_LABEL (player->priv->song), tmp);
 
597
                tmp = SONG_MARKUP (_("Not Playing"));
 
598
                gtk_label_set_markup (GTK_LABEL (player->priv->song), tmp);
583
599
                g_free (tmp);
584
600
 
585
601
                iradio_href_tips = gtk_tooltips_new ();
591
607
                rb_header_set_urldata (player, NULL, NULL);
592
608
                rb_header_set_show_artist_album (player, FALSE);
593
609
                rb_header_set_show_timeline (player, FALSE);
 
610
 
 
611
                player->priv->slider_locked = TRUE;
 
612
                gtk_adjustment_set_value (player->priv->adjustment, 0.0);
 
613
                player->priv->slider_locked = FALSE;
 
614
                gtk_widget_set_sensitive (player->priv->scale, FALSE);
 
615
                gtk_label_set_text (GTK_LABEL (player->priv->elapsed), "0:00");
594
616
        }
595
617
 
596
618
#if 0
644
666
rb_header_set_show_timeline (RBHeader *player,
645
667
                             gboolean show)
646
668
{
647
 
        if (player->priv->timeline_shown == show)
648
 
                return;
649
 
 
650
 
        player->priv->timeline_shown = show;
651
 
 
652
 
        if (show == FALSE)
653
 
                gtk_container_remove (GTK_CONTAINER (player->priv->timeframe), player->priv->timeline);
654
 
        else {
655
 
                gtk_container_add (GTK_CONTAINER (player->priv->timeframe), player->priv->timeline);
656
 
                gtk_widget_show_all (player->priv->timeline);
657
 
        }
658
 
}
659
 
 
660
 
gboolean
661
 
rb_header_sync_time_locked (RBHeader *player)
662
 
{
663
 
        gboolean ret;
664
 
 
665
 
        GDK_THREADS_ENTER ();
666
 
 
667
 
        ret = rb_header_sync_time (player);
668
 
 
669
 
        GDK_THREADS_LEAVE ();
670
 
 
671
 
        return ret;
 
669
        gtk_widget_set_sensitive (player->priv->timeline, show);
672
670
}
673
671
 
674
672
gboolean
687
685
 
688
686
        player->priv->state->duration = duration =
689
687
                rb_header_get_duration (player);
690
 
        player->priv->state->elapsed = seconds =
691
 
                rb_player_get_time (player->priv->mmplayer);
 
688
        seconds = player->priv->state->elapsed;
692
689
 
693
690
        if (duration > -1) {
694
691
                double progress = 0.0;
847
844
char *
848
845
rb_header_get_elapsed_string (RBHeader *player)
849
846
{
850
 
        int seconds = 0, minutes = 0, seconds2 = -1, minutes2 = -1;
851
 
        guint elapsed = rb_player_get_time (player->priv->mmplayer);
 
847
        int seconds = 0, minutes = 0, hours = 0, seconds2 = -1, minutes2 = -1, hours2 = -1;
852
848
 
853
 
        if (elapsed > 0) {
854
 
                minutes = elapsed / 60;
855
 
                seconds = elapsed % 60;
 
849
        if (player->priv->state->elapsed > 0) {
 
850
                hours = player->priv->state->elapsed / (60 * 60);
 
851
                minutes = (player->priv->state->elapsed - (hours * 60 * 60)) / 60;
 
852
                seconds = player->priv->state->elapsed % 60;
856
853
        }
857
854
 
858
855
        if (player->priv->state->duration > 0) {
859
 
                minutes2 = player->priv->state->duration / 60;
 
856
                hours2 = player->priv->state->duration / (60 * 60);
 
857
                minutes2 = (player->priv->state->duration - (hours2 * 60 * 60)) / 60;
860
858
                seconds2 = player->priv->state->duration % 60;
861
859
                if (eel_gconf_get_boolean (CONF_UI_TIME_DISPLAY)) {
862
 
                        return g_strdup_printf (_("%d:%02d of %d:%02d"), minutes, seconds, minutes2, seconds2);
 
860
                        if (hours == 0 && hours2 == 0)
 
861
                                return g_strdup_printf (_("%d:%02d of %d:%02d"),
 
862
                                                        minutes, seconds,
 
863
                                                        minutes2, seconds2);
 
864
                        else
 
865
                                return g_strdup_printf (_("%d:%02d:%02d of %d:%02d:%02d"),
 
866
                                                        hours, minutes, seconds,
 
867
                                                        hours2, minutes2, seconds2);
863
868
                } else {
864
 
                        int remaining = player->priv->state->duration - elapsed;
865
 
                        int remaining_minutes = remaining / 60;
 
869
                        int remaining = player->priv->state->duration - player->priv->state->elapsed;
 
870
                        int remaining_hours = remaining / (60 * 60);
 
871
                        int remaining_minutes = (remaining - (remaining_hours * 60 * 60)) / 60;
866
872
                        /* remaining could conceivably be negative. This would
867
873
                         * be a bug, but the elapsed time will display right
868
874
                         * with the abs(). */
869
875
                        int remaining_seconds = abs (remaining % 60);
870
 
                        return g_strdup_printf (_("%d:%02d of %d:%02d remaining"), remaining_minutes, remaining_seconds, minutes2, seconds2);
 
876
                        if (hours2 == 0)
 
877
                                return g_strdup_printf (_("%d:%02d of %d:%02d remaining"),
 
878
                                                        remaining_minutes, remaining_seconds,
 
879
                                                        minutes2, seconds2);
 
880
                        else
 
881
                                return g_strdup_printf (_("%d:%02d:%02d of %d:%02d:%02d remaining"),
 
882
                                                        remaining_hours, remaining_minutes, remaining_seconds,
 
883
                                                        hours2, minutes2, seconds2);
871
884
                }
872
885
        } else {
873
 
                return g_strdup_printf (_("%d:%02d"), minutes, seconds);
 
886
                if (hours == 0)
 
887
                        return g_strdup_printf (_("%d:%02d"), minutes, seconds);
 
888
                else
 
889
                        return g_strdup_printf (_("%d:%02d:%02d"), hours, minutes, seconds);
874
890
        }
875
891
}
876
892
 
888
904
        gtk_label_set_text (GTK_LABEL (player->priv->elapsed), elapsed_text);
889
905
        g_free (elapsed_text);
890
906
}
 
907
 
 
908
static void rb_header_tick_cb (RBPlayer *mmplayer, long elapsed, RBHeader *header)
 
909
{
 
910
        gboolean sync = (elapsed != header->priv->state->elapsed);
 
911
        header->priv->state->elapsed = elapsed;
 
912
        
 
913
        if (sync) {
 
914
                GDK_THREADS_ENTER ();
 
915
 
 
916
                rb_header_sync_time (header);
 
917
 
 
918
                GDK_THREADS_LEAVE ();
 
919
        }
 
920
}