~matttbe/ubuntu/raring/rhythmbox/lp1010619_RB_2.98

« back to all changes in this revision

Viewing changes to .pc/git_scale_click.patch/widgets/rb-header.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2012-11-06 20:52:57 UTC
  • mfrom: (1.1.67) (214.1.1 quantal-proposed)
  • Revision ID: package-import@ubuntu.com-20121106205257-0btjh8jqley153el
Tags: 2.98-0ubuntu1
* New upstream release (LP: #1060601)
* debian/control.in:
  - Bump minimum glib, gtk, totem-plparser, clutter, and clutter-gst
  - Drop no longer needed musicbrainz dependency
* Refreshed 09_keywords.patch
* Updated 11_fix_cd_pausing.patch with fix from git
* Dropped patches applied in new version:
  - 00git_musicbrainz5.patch
  - 08_CVE-2012-3355.patch
  - dont_free_consumed_floating_gvariant.patch
  - git_scale_click.patch
  - git_crash_during_monitor.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2
 
 *
3
 
 *  Copyright (C) 2002, 2003 Jorn Baayen <jorn@nl.linux.org>
4
 
 *  Copyright (C) 2003 Colin Walters <walters@gnome.org>
5
 
 *
6
 
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation; either version 2 of the License, or
9
 
 *  (at your option) any later version.
10
 
 *
11
 
 *  The Rhythmbox authors hereby grant permission for non-GPL compatible
12
 
 *  GStreamer plugins to be used and distributed together with GStreamer
13
 
 *  and Rhythmbox. This permission is above and beyond the permissions granted
14
 
 *  by the GPL license by which Rhythmbox is covered. If you modify this code
15
 
 *  you may extend this exception to your version of the code, but you are not
16
 
 *  obligated to do so. If you do not wish to do so, delete this exception
17
 
 *  statement from your version.
18
 
 *
19
 
 *  This program is distributed in the hope that it will be useful,
20
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 
 *  GNU General Public License for more details.
23
 
 *
24
 
 *  You should have received a copy of the GNU General Public License
25
 
 *  along with this program; if not, write to the Free Software
26
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
27
 
 *
28
 
 */
29
 
 
30
 
#include <config.h>
31
 
 
32
 
#include <math.h>
33
 
#include <string.h>
34
 
 
35
 
#include <glib/gi18n.h>
36
 
#include <gtk/gtk.h>
37
 
 
38
 
#include "rb-stock-icons.h"
39
 
#include "rb-header.h"
40
 
#include "rb-debug.h"
41
 
#include "rb-shell-player.h"
42
 
#include "rb-util.h"
43
 
#include "rhythmdb.h"
44
 
#include "rb-player.h"
45
 
#include "rb-text-helpers.h"
46
 
#include "rb-fading-image.h"
47
 
#include "rb-file-helpers.h"
48
 
#include "rb-ext-db.h"
49
 
 
50
 
/**
51
 
 * SECTION:rb-header
52
 
 * @short_description: playback area widgetry
53
 
 *
54
 
 * The RBHeader widget displays information about the current playing track
55
 
 * (title, album, artist), the elapsed or remaining playback time, and a
56
 
 * position slider indicating the playback position.  It translates slider
57
 
 * move and drag events into seek requests for the player backend.
58
 
 *
59
 
 * For shoutcast-style streams, the title/artist/album display is supplemented
60
 
 * by metadata extracted from the stream.  See #RBStreamingSource for more information
61
 
 * on how the metadata is reported.
62
 
 */
63
 
 
64
 
static void rb_header_class_init (RBHeaderClass *klass);
65
 
static void rb_header_init (RBHeader *header);
66
 
static void rb_header_dispose (GObject *object);
67
 
static void rb_header_finalize (GObject *object);
68
 
static void rb_header_set_property (GObject *object,
69
 
                                    guint prop_id,
70
 
                                    const GValue *value,
71
 
                                    GParamSpec *pspec);
72
 
static void rb_header_get_property (GObject *object,
73
 
                                    guint prop_id,
74
 
                                    GValue *value,
75
 
                                    GParamSpec *pspec);
76
 
static GtkSizeRequestMode rb_header_get_request_mode (GtkWidget *widget);
77
 
static void rb_header_get_preferred_width (GtkWidget *widget,
78
 
                                           int *minimum_size,
79
 
                                           int *natural_size);
80
 
static void rb_header_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
81
 
static void rb_header_update_elapsed (RBHeader *header);
82
 
static void apply_slider_position (RBHeader *header);
83
 
static gboolean slider_press_callback (GtkWidget *widget, GdkEventButton *event, RBHeader *header);
84
 
static gboolean slider_moved_callback (GtkWidget *widget, GdkEventMotion *event, RBHeader *header);
85
 
static gboolean slider_release_callback (GtkWidget *widget, GdkEventButton *event, RBHeader *header);
86
 
static void slider_changed_callback (GtkWidget *widget, RBHeader *header);
87
 
static gboolean slider_scroll_callback (GtkWidget *widget, GdkEventScroll *event, RBHeader *header);
88
 
static void time_button_clicked_cb (GtkWidget *button, RBHeader *header);
89
 
 
90
 
static void rb_header_elapsed_changed_cb (RBShellPlayer *player, gint64 elapsed, RBHeader *header);
91
 
static void rb_header_extra_metadata_cb (RhythmDB *db, RhythmDBEntry *entry, const char *property_name, const GValue *metadata, RBHeader *header);
92
 
static void rb_header_sync (RBHeader *header);
93
 
static void rb_header_sync_time (RBHeader *header);
94
 
 
95
 
static void uri_dropped_cb (RBFadingImage *image, const char *uri, RBHeader *header);
96
 
static void pixbuf_dropped_cb (RBFadingImage *image, GdkPixbuf *pixbuf, RBHeader *header);
97
 
static void image_button_press_cb (GtkWidget *widget, GdkEvent *event, RBHeader *header);
98
 
static void art_added_cb (RBExtDB *db, RBExtDBKey *key, const char *filename, GValue *data, RBHeader *header);
99
 
 
100
 
struct RBHeaderPrivate
101
 
{
102
 
        RhythmDB *db;
103
 
        RhythmDBEntry *entry;
104
 
        RBExtDB *art_store;
105
 
 
106
 
        RBShellPlayer *shell_player;
107
 
 
108
 
        GtkWidget *songbox;
109
 
        GtkWidget *song;
110
 
        GtkWidget *details;
111
 
        GtkWidget *image;
112
 
 
113
 
        GtkWidget *scale;
114
 
        GtkAdjustment *adjustment;
115
 
        gboolean slider_dragging;
116
 
        gboolean slider_locked;
117
 
        guint slider_moved_timeout;
118
 
        long latest_set_time;
119
 
 
120
 
        GtkWidget *timebutton;
121
 
        GtkWidget *timelabel;
122
 
 
123
 
        gint64 elapsed_time;            /* nanoseconds */
124
 
        gboolean show_remaining;
125
 
        long duration;
126
 
        gboolean seekable;
127
 
        char *image_path;
128
 
        gboolean show_album_art;
129
 
        gboolean show_slider;
130
 
};
131
 
 
132
 
enum
133
 
{
134
 
        PROP_0,
135
 
        PROP_DB,
136
 
        PROP_SHELL_PLAYER,
137
 
        PROP_SEEKABLE,
138
 
        PROP_SLIDER_DRAGGING,
139
 
        PROP_SHOW_REMAINING,
140
 
        PROP_SHOW_POSITION_SLIDER,
141
 
        PROP_SHOW_ALBUM_ART
142
 
};
143
 
 
144
 
#define TITLE_FORMAT  "<big><b>%s</b></big>"
145
 
#define ALBUM_FORMAT  "<i>%s</i>"
146
 
#define ARTIST_FORMAT "<i>%s</i>"
147
 
#define STREAM_FORMAT "%s"
148
 
 
149
 
/* unicode graphic characters, encoded in UTF-8 */
150
 
static const char const *UNICODE_MIDDLE_DOT = "\xC2\xB7";
151
 
 
152
 
#define SCROLL_UP_SEEK_OFFSET   5
153
 
#define SCROLL_DOWN_SEEK_OFFSET -5
154
 
 
155
 
G_DEFINE_TYPE (RBHeader, rb_header, GTK_TYPE_GRID)
156
 
 
157
 
static void
158
 
rb_header_class_init (RBHeaderClass *klass)
159
 
{
160
 
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
161
 
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
162
 
 
163
 
        object_class->dispose = rb_header_dispose;
164
 
        object_class->finalize = rb_header_finalize;
165
 
 
166
 
        object_class->set_property = rb_header_set_property;
167
 
        object_class->get_property = rb_header_get_property;
168
 
 
169
 
        widget_class->get_request_mode = rb_header_get_request_mode;
170
 
        widget_class->get_preferred_width = rb_header_get_preferred_width;
171
 
        widget_class->size_allocate = rb_header_size_allocate;
172
 
        /* GtkGrid's get_preferred_height_for_width does all we need here */
173
 
 
174
 
        /**
175
 
         * RBHeader:db:
176
 
         *
177
 
         * #RhythmDB instance
178
 
         */
179
 
        g_object_class_install_property (object_class,
180
 
                                         PROP_DB,
181
 
                                         g_param_spec_object ("db",
182
 
                                                              "RhythmDB",
183
 
                                                              "RhythmDB object",
184
 
                                                              RHYTHMDB_TYPE,
185
 
                                                              G_PARAM_READWRITE));
186
 
 
187
 
        /**
188
 
         * RBHeader:shell-player:
189
 
         *
190
 
         * The #RBShellPlayer instance
191
 
         */
192
 
        g_object_class_install_property (object_class,
193
 
                                         PROP_SHELL_PLAYER,
194
 
                                         g_param_spec_object ("shell-player",
195
 
                                                              "shell player",
196
 
                                                              "RBShellPlayer object",
197
 
                                                              RB_TYPE_SHELL_PLAYER,
198
 
                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
199
 
        /**
200
 
         * RBHeader:seekable:
201
 
         *
202
 
         * If TRUE, the header should allow seeking by dragging the playback position slider
203
 
         */
204
 
        g_object_class_install_property (object_class,
205
 
                                         PROP_SEEKABLE,
206
 
                                         g_param_spec_boolean ("seekable",
207
 
                                                               "seekable",
208
 
                                                               "seekable",
209
 
                                                               TRUE,
210
 
                                                               G_PARAM_READWRITE));
211
 
 
212
 
        /**
213
 
         * RBHeader:slider-dragging:
214
 
         *
215
 
         * Whether the song position slider is currently being dragged.
216
 
         */
217
 
        g_object_class_install_property (object_class,
218
 
                                         PROP_SLIDER_DRAGGING,
219
 
                                         g_param_spec_boolean ("slider-dragging",
220
 
                                                               "slider dragging",
221
 
                                                               "slider dragging",
222
 
                                                               FALSE,
223
 
                                                               G_PARAM_READABLE));
224
 
        /**
225
 
         * RBHeader:show-remaining:
226
 
         *
227
 
         * Whether to show remaining time (as opposed to elapsed time) in the numeric
228
 
         * time display.
229
 
         */
230
 
        g_object_class_install_property (object_class,
231
 
                                         PROP_SHOW_REMAINING,
232
 
                                         g_param_spec_boolean ("show-remaining",
233
 
                                                               "show remaining",
234
 
                                                               "whether to show remaining or elapsed time",
235
 
                                                               FALSE,
236
 
                                                               G_PARAM_READWRITE));
237
 
 
238
 
        /**
239
 
         * RBHeader:show-position-slider:
240
 
         *
241
 
         * Whether to show the playback position slider.
242
 
         */
243
 
        g_object_class_install_property (object_class,
244
 
                                         PROP_SHOW_POSITION_SLIDER,
245
 
                                         g_param_spec_boolean ("show-position-slider",
246
 
                                                               "show position slider",
247
 
                                                               "whether to show the playback position slider",
248
 
                                                               TRUE,
249
 
                                                               G_PARAM_READWRITE));
250
 
        /**
251
 
         * RBHeader:show-album-art:
252
 
         *
253
 
         * Whether to show the album art display widget.
254
 
         */
255
 
        g_object_class_install_property (object_class,
256
 
                                         PROP_SHOW_ALBUM_ART,
257
 
                                         g_param_spec_boolean ("show-album-art",
258
 
                                                               "show album art",
259
 
                                                               "whether to show album art",
260
 
                                                               TRUE,
261
 
                                                               G_PARAM_READWRITE));
262
 
 
263
 
        g_type_class_add_private (klass, sizeof (RBHeaderPrivate));
264
 
}
265
 
 
266
 
static void
267
 
rb_header_init (RBHeader *header)
268
 
{
269
 
        header->priv = G_TYPE_INSTANCE_GET_PRIVATE (header, RB_TYPE_HEADER, RBHeaderPrivate);
270
 
 
271
 
        gtk_grid_set_column_spacing (GTK_GRID (header), 6);
272
 
        gtk_grid_set_column_homogeneous (GTK_GRID (header), TRUE);
273
 
        gtk_container_set_border_width (GTK_CONTAINER (header), 3);
274
 
 
275
 
        /* set up position slider */
276
 
        header->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 10.0, 1.0, 10.0, 0.0));
277
 
        header->priv->scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, header->priv->adjustment);
278
 
        gtk_widget_set_hexpand (header->priv->scale, TRUE);
279
 
        g_signal_connect_object (G_OBJECT (header->priv->scale),
280
 
                                 "button_press_event",
281
 
                                 G_CALLBACK (slider_press_callback),
282
 
                                 header, 0);
283
 
        g_signal_connect_object (G_OBJECT (header->priv->scale),
284
 
                                 "button_release_event",
285
 
                                 G_CALLBACK (slider_release_callback),
286
 
                                 header, 0);
287
 
        g_signal_connect_object (G_OBJECT (header->priv->scale),
288
 
                                 "motion_notify_event",
289
 
                                 G_CALLBACK (slider_moved_callback),
290
 
                                 header, 0);
291
 
        g_signal_connect_object (G_OBJECT (header->priv->scale),
292
 
                                 "value_changed",
293
 
                                 G_CALLBACK (slider_changed_callback),
294
 
                                 header, 0);
295
 
        g_signal_connect_object (G_OBJECT (header->priv->scale),
296
 
                                 "scroll_event",
297
 
                                 G_CALLBACK (slider_scroll_callback),
298
 
                                 header, 0);
299
 
        gtk_scale_set_draw_value (GTK_SCALE (header->priv->scale), FALSE);
300
 
        gtk_widget_set_size_request (header->priv->scale, 150, -1);
301
 
 
302
 
        /* set up song information labels */
303
 
        header->priv->songbox = gtk_grid_new ();
304
 
        gtk_widget_set_hexpand (header->priv->songbox, TRUE);
305
 
        gtk_widget_set_valign (header->priv->songbox, GTK_ALIGN_CENTER);
306
 
 
307
 
        header->priv->song = gtk_label_new (" ");
308
 
        gtk_label_set_use_markup (GTK_LABEL (header->priv->song), TRUE);
309
 
        gtk_label_set_selectable (GTK_LABEL (header->priv->song), TRUE);
310
 
        gtk_label_set_ellipsize (GTK_LABEL (header->priv->song), PANGO_ELLIPSIZE_END);
311
 
        gtk_misc_set_alignment (GTK_MISC (header->priv->song), 0.0, 0.5);
312
 
        gtk_grid_attach (GTK_GRID (header->priv->songbox), header->priv->song, 0, 0, 1, 1);
313
 
 
314
 
        header->priv->details = gtk_label_new ("");
315
 
        gtk_label_set_use_markup (GTK_LABEL (header->priv->details), TRUE);
316
 
        gtk_label_set_selectable (GTK_LABEL (header->priv->details), TRUE);
317
 
        gtk_label_set_ellipsize (GTK_LABEL (header->priv->details), PANGO_ELLIPSIZE_END);
318
 
        gtk_widget_set_hexpand (header->priv->details, TRUE);
319
 
        gtk_misc_set_alignment (GTK_MISC (header->priv->details), 0.0, 0.5);
320
 
        gtk_grid_attach (GTK_GRID (header->priv->songbox), header->priv->details, 0, 1, 1, 2);
321
 
 
322
 
        /* elapsed time / duration display */
323
 
        header->priv->timelabel = gtk_label_new ("");
324
 
        gtk_widget_set_halign (header->priv->timelabel, GTK_ALIGN_END);
325
 
 
326
 
        header->priv->timebutton = gtk_button_new ();
327
 
        gtk_container_add (GTK_CONTAINER (header->priv->timebutton), header->priv->timelabel);
328
 
        g_signal_connect_object (header->priv->timebutton,
329
 
                                 "clicked",
330
 
                                 G_CALLBACK (time_button_clicked_cb),
331
 
                                 header, 0);
332
 
 
333
 
        /* image display */
334
 
        header->priv->art_store = rb_ext_db_new ("album-art");
335
 
        g_signal_connect (header->priv->art_store,
336
 
                          "added",
337
 
                          G_CALLBACK (art_added_cb),
338
 
                          header);
339
 
        header->priv->image = GTK_WIDGET (g_object_new (RB_TYPE_FADING_IMAGE,
340
 
                                                        "fallback", RB_STOCK_MISSING_ARTWORK,
341
 
                                                        NULL));
342
 
        g_signal_connect (header->priv->image,
343
 
                          "pixbuf-dropped",
344
 
                          G_CALLBACK (pixbuf_dropped_cb),
345
 
                          header);
346
 
        g_signal_connect (header->priv->image,
347
 
                          "uri-dropped",
348
 
                          G_CALLBACK (uri_dropped_cb),
349
 
                          header);
350
 
        g_signal_connect (header->priv->image,
351
 
                          "button-press-event",
352
 
                          G_CALLBACK (image_button_press_cb),
353
 
                          header);
354
 
 
355
 
        gtk_grid_attach (GTK_GRID (header), header->priv->image, 0, 0, 1, 1);
356
 
        gtk_grid_attach (GTK_GRID (header), header->priv->songbox, 2, 0, 1, 1);
357
 
        gtk_grid_attach (GTK_GRID (header), header->priv->timebutton, 3, 0, 1, 1);
358
 
        gtk_grid_attach (GTK_GRID (header), header->priv->scale, 4, 0, 1, 1);
359
 
 
360
 
        /* currently, nothing sets this.  it should be set on track changes. */
361
 
        header->priv->seekable = TRUE;
362
 
 
363
 
        rb_header_sync (header);
364
 
}
365
 
 
366
 
static void
367
 
rb_header_dispose (GObject *object)
368
 
{
369
 
        RBHeader *header = RB_HEADER (object);
370
 
 
371
 
        if (header->priv->db != NULL) {
372
 
                g_object_unref (header->priv->db);
373
 
                header->priv->db = NULL;
374
 
        }
375
 
 
376
 
        if (header->priv->shell_player != NULL) {
377
 
                g_object_unref (header->priv->shell_player);
378
 
                header->priv->shell_player = NULL;
379
 
        }
380
 
 
381
 
        if (header->priv->art_store != NULL) {
382
 
                g_object_unref (header->priv->art_store);
383
 
                header->priv->art_store = NULL;
384
 
        }
385
 
 
386
 
        G_OBJECT_CLASS (rb_header_parent_class)->dispose (object);
387
 
}
388
 
 
389
 
static void
390
 
rb_header_finalize (GObject *object)
391
 
{
392
 
        RBHeader *header;
393
 
 
394
 
        g_return_if_fail (object != NULL);
395
 
        g_return_if_fail (RB_IS_HEADER (object));
396
 
 
397
 
        header = RB_HEADER (object);
398
 
        g_return_if_fail (header->priv != NULL);
399
 
 
400
 
        g_free (header->priv->image_path);
401
 
 
402
 
        G_OBJECT_CLASS (rb_header_parent_class)->finalize (object);
403
 
}
404
 
 
405
 
static void
406
 
art_cb (RBExtDBKey *key, const char *filename, GValue *data, RBHeader *header)
407
 
{
408
 
        RhythmDBEntry *entry;
409
 
 
410
 
        entry = rb_shell_player_get_playing_entry (header->priv->shell_player);
411
 
        if (entry == NULL) {
412
 
                return;
413
 
        }
414
 
 
415
 
        if (rhythmdb_entry_matches_ext_db_key (header->priv->db, entry, key)) {
416
 
                GdkPixbuf *pixbuf = NULL;
417
 
 
418
 
                if (data != NULL && G_VALUE_HOLDS (data, GDK_TYPE_PIXBUF)) {
419
 
                        pixbuf = GDK_PIXBUF (g_value_get_object (data));
420
 
                }
421
 
 
422
 
                rb_fading_image_set_pixbuf (RB_FADING_IMAGE (header->priv->image), pixbuf);
423
 
 
424
 
                g_free (header->priv->image_path);
425
 
                header->priv->image_path = g_strdup (filename);
426
 
        }
427
 
 
428
 
        rhythmdb_entry_unref (entry);
429
 
}
430
 
 
431
 
static void
432
 
art_added_cb (RBExtDB *db, RBExtDBKey *key, const char *filename, GValue *data, RBHeader *header)
433
 
{
434
 
        art_cb (key, filename, data, header);
435
 
}
436
 
 
437
 
 
438
 
static void
439
 
rb_header_playing_song_changed_cb (RBShellPlayer *player, RhythmDBEntry *entry, RBHeader *header)
440
 
{
441
 
        if (header->priv->entry == entry)
442
 
                return;
443
 
 
444
 
        header->priv->entry = entry;
445
 
        if (header->priv->entry) {
446
 
                RBExtDBKey *key;
447
 
 
448
 
                header->priv->duration = rhythmdb_entry_get_ulong (header->priv->entry,
449
 
                                                                   RHYTHMDB_PROP_DURATION);
450
 
 
451
 
                key = rhythmdb_entry_create_ext_db_key (entry, RHYTHMDB_PROP_ALBUM);
452
 
                rb_ext_db_request (header->priv->art_store,
453
 
                                   key,
454
 
                                   (RBExtDBRequestCallback) art_cb,
455
 
                                   g_object_ref (header),
456
 
                                   g_object_unref);
457
 
                rb_ext_db_key_free (key);
458
 
        } else {
459
 
                header->priv->duration = 0;
460
 
        }
461
 
 
462
 
        rb_header_sync (header);
463
 
 
464
 
        g_free (header->priv->image_path);
465
 
        header->priv->image_path = NULL;
466
 
 
467
 
        rb_fading_image_start (RB_FADING_IMAGE (header->priv->image), 2000);
468
 
}
469
 
 
470
 
static GtkSizeRequestMode
471
 
rb_header_get_request_mode (GtkWidget *widget)
472
 
{
473
 
        return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
474
 
}
475
 
 
476
 
static void
477
 
rb_header_get_preferred_width (GtkWidget *widget,
478
 
                               int *minimum_width,
479
 
                               int *natural_width)
480
 
{
481
 
        *minimum_width = 0;
482
 
        *natural_width = 0;
483
 
}
484
 
 
485
 
static void
486
 
rb_header_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
487
 
{
488
 
        int spacing;
489
 
        int scale_width;
490
 
        int info_width;
491
 
        int time_width;
492
 
        int image_width;
493
 
        GtkAllocation child_alloc;
494
 
        gboolean rtl;
495
 
 
496
 
        gtk_widget_set_allocation (widget, allocation);
497
 
        spacing = gtk_grid_get_column_spacing (GTK_GRID (widget));
498
 
        rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
499
 
 
500
 
        /* take some leading space for the image, which we always make square */
501
 
        if (RB_HEADER (widget)->priv->show_album_art) {
502
 
                image_width = allocation->height;
503
 
                if (rtl) {
504
 
                        child_alloc.x = allocation->x + allocation->width - image_width;
505
 
                        allocation->x -= image_width + spacing;
506
 
                } else {
507
 
                        child_alloc.x = allocation->x;
508
 
                        allocation->x += image_width + spacing;
509
 
                }
510
 
                allocation->width -= image_width + spacing;
511
 
                child_alloc.y = allocation->y;
512
 
                child_alloc.width = image_width;
513
 
                child_alloc.height = allocation->height;
514
 
                gtk_widget_size_allocate (RB_HEADER (widget)->priv->image, &child_alloc);
515
 
        } else {
516
 
                image_width = 0;
517
 
        }
518
 
 
519
 
        /* figure out how much space to allocate to the scale.
520
 
         * it gets at least its minimum size, at most 1/3 of the
521
 
         * space we have.
522
 
         */
523
 
        if (RB_HEADER (widget)->priv->show_slider) {
524
 
                gtk_widget_get_preferred_width (RB_HEADER (widget)->priv->scale, &scale_width, NULL);
525
 
                if (scale_width < allocation->width / 3)
526
 
                        scale_width = allocation->width / 3;
527
 
 
528
 
                if (scale_width + image_width > allocation->width)
529
 
                        scale_width = allocation->width - image_width;
530
 
 
531
 
                if (scale_width > 0) {
532
 
                        if (rtl) {
533
 
                                child_alloc.x = allocation->x;
534
 
                        } else {
535
 
                                child_alloc.x = allocation->x + (allocation->width - scale_width) + spacing;
536
 
                        }
537
 
                        child_alloc.y = allocation->y;
538
 
                        child_alloc.width = scale_width - spacing;
539
 
                        child_alloc.height = allocation->height;
540
 
                        gtk_widget_show (RB_HEADER (widget)->priv->scale);
541
 
                        gtk_widget_size_allocate (RB_HEADER (widget)->priv->scale, &child_alloc);
542
 
                } else {
543
 
                        gtk_widget_hide (RB_HEADER (widget)->priv->scale);
544
 
                }
545
 
        } else {
546
 
                scale_width = 0;
547
 
        }
548
 
 
549
 
        /* time button gets its minimum size */
550
 
        gtk_widget_get_preferred_width (RB_HEADER (widget)->priv->songbox, NULL, &info_width);
551
 
        gtk_widget_get_preferred_width (RB_HEADER (widget)->priv->timebutton, &time_width, NULL);
552
 
 
553
 
        info_width = allocation->width - (scale_width + time_width) - (2 * spacing);
554
 
 
555
 
        if (rtl) {
556
 
                child_alloc.x = allocation->x + allocation->width - info_width;
557
 
        } else {
558
 
                child_alloc.x = allocation->x;
559
 
        }
560
 
 
561
 
        if (info_width > 0) {
562
 
                child_alloc.y = allocation->y;
563
 
                child_alloc.width = info_width;
564
 
                child_alloc.height = allocation->height;
565
 
                gtk_widget_show (RB_HEADER (widget)->priv->songbox);
566
 
                gtk_widget_size_allocate (RB_HEADER (widget)->priv->songbox, &child_alloc);
567
 
        } else {
568
 
                gtk_widget_hide (RB_HEADER (widget)->priv->songbox);
569
 
                info_width = 0;
570
 
        }
571
 
 
572
 
        if (info_width + scale_width + (2 * spacing) + time_width > allocation->width) {
573
 
                gtk_widget_hide (RB_HEADER (widget)->priv->timebutton);
574
 
        } else {
575
 
                if (rtl) {
576
 
                        child_alloc.x = allocation->x + scale_width + spacing;
577
 
                } else {
578
 
                        child_alloc.x = allocation->x + info_width + spacing;
579
 
                }
580
 
                child_alloc.y = allocation->y;
581
 
                child_alloc.width = time_width;
582
 
                child_alloc.height = allocation->height;
583
 
                gtk_widget_show (RB_HEADER (widget)->priv->timebutton);
584
 
                gtk_widget_size_allocate (RB_HEADER (widget)->priv->timebutton, &child_alloc);
585
 
        }
586
 
}
587
 
 
588
 
static void
589
 
rb_header_set_property (GObject *object,
590
 
                        guint prop_id,
591
 
                        const GValue *value,
592
 
                        GParamSpec *pspec)
593
 
{
594
 
        RBHeader *header = RB_HEADER (object);
595
 
 
596
 
        switch (prop_id) {
597
 
        case PROP_DB:
598
 
                header->priv->db = g_value_get_object (value);
599
 
                g_signal_connect_object (header->priv->db,
600
 
                                         "entry-extra-metadata-notify",
601
 
                                         G_CALLBACK (rb_header_extra_metadata_cb),
602
 
                                         header, 0);
603
 
                break;
604
 
        case PROP_SHELL_PLAYER:
605
 
                header->priv->shell_player = g_value_get_object (value);
606
 
                g_signal_connect_object (header->priv->shell_player,
607
 
                                         "elapsed-nano-changed",
608
 
                                         G_CALLBACK (rb_header_elapsed_changed_cb),
609
 
                                         header, 0);
610
 
                g_signal_connect_object (header->priv->shell_player,
611
 
                                         "playing-song-changed",
612
 
                                         G_CALLBACK (rb_header_playing_song_changed_cb),
613
 
                                         header, 0);
614
 
                break;
615
 
        case PROP_SEEKABLE:
616
 
                header->priv->seekable = g_value_get_boolean (value);
617
 
                break;
618
 
        case PROP_SHOW_REMAINING:
619
 
                header->priv->show_remaining = g_value_get_boolean (value);
620
 
                rb_header_update_elapsed (header);
621
 
                break;
622
 
        case PROP_SHOW_POSITION_SLIDER:
623
 
                header->priv->show_slider = g_value_get_boolean (value);
624
 
                gtk_widget_set_visible (header->priv->scale, header->priv->show_slider);
625
 
                break;
626
 
        case PROP_SHOW_ALBUM_ART:
627
 
                header->priv->show_album_art = g_value_get_boolean (value);
628
 
                gtk_widget_set_visible (header->priv->image, header->priv->show_album_art);
629
 
                break;
630
 
        default:
631
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
632
 
                break;
633
 
        }
634
 
}
635
 
 
636
 
static void
637
 
rb_header_get_property (GObject *object,
638
 
                        guint prop_id,
639
 
                        GValue *value,
640
 
                        GParamSpec *pspec)
641
 
{
642
 
        RBHeader *header = RB_HEADER (object);
643
 
 
644
 
        switch (prop_id) {
645
 
        case PROP_DB:
646
 
                g_value_set_object (value, header->priv->db);
647
 
                break;
648
 
        case PROP_SHELL_PLAYER:
649
 
                g_value_set_object (value, header->priv->shell_player);
650
 
                break;
651
 
        case PROP_SEEKABLE:
652
 
                g_value_set_boolean (value, header->priv->seekable);
653
 
                break;
654
 
        case PROP_SLIDER_DRAGGING:
655
 
                g_value_set_boolean (value, header->priv->slider_dragging);
656
 
                break;
657
 
        case PROP_SHOW_REMAINING:
658
 
                g_value_set_boolean (value, header->priv->show_remaining);
659
 
                break;
660
 
        case PROP_SHOW_POSITION_SLIDER:
661
 
                g_value_set_boolean (value, header->priv->show_slider);
662
 
                break;
663
 
        case PROP_SHOW_ALBUM_ART:
664
 
                g_value_set_boolean (value, header->priv->show_album_art);
665
 
                break;
666
 
        default:
667
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
668
 
                break;
669
 
        }
670
 
}
671
 
 
672
 
/**
673
 
 * rb_header_new:
674
 
 * @shell_player: the #RBShellPlayer instance
675
 
 * @db: the #RhythmDB instance
676
 
 *
677
 
 * Creates a new header widget.
678
 
 *
679
 
 * Return value: the header widget
680
 
 */
681
 
RBHeader *
682
 
rb_header_new (RBShellPlayer *shell_player, RhythmDB *db)
683
 
{
684
 
        RBHeader *header;
685
 
 
686
 
        header = RB_HEADER (g_object_new (RB_TYPE_HEADER,
687
 
                                          "shell-player", shell_player,
688
 
                                          "db", db,
689
 
                                          NULL));
690
 
 
691
 
        g_return_val_if_fail (header->priv != NULL, NULL);
692
 
 
693
 
        return header;
694
 
}
695
 
 
696
 
static void
697
 
get_extra_metadata (RhythmDB *db, RhythmDBEntry *entry, const char *field, char **value)
698
 
{
699
 
        GValue *v;
700
 
 
701
 
        v = rhythmdb_entry_request_extra_metadata (db, entry, field);
702
 
        if (v != NULL) {
703
 
                *value = g_value_dup_string (v);
704
 
                g_value_unset (v);
705
 
                g_free (v);
706
 
        } else {
707
 
                *value = NULL;
708
 
        }
709
 
}
710
 
 
711
 
static void
712
 
rb_header_sync (RBHeader *header)
713
 
{
714
 
        char *label_text;
715
 
        const char *location = "<null>";
716
 
 
717
 
        if (header->priv->entry != NULL) {
718
 
                location = rhythmdb_entry_get_string (header->priv->entry, RHYTHMDB_PROP_LOCATION);
719
 
        }
720
 
        rb_debug ("syncing with entry = %s", location);
721
 
 
722
 
        if (header->priv->entry != NULL) {
723
 
                const char *title;
724
 
                const char *album;
725
 
                const char *artist;
726
 
                const char *stream_name = NULL;
727
 
                char *streaming_title;
728
 
                char *streaming_artist;
729
 
                char *streaming_album;
730
 
                PangoDirection widget_dir;
731
 
 
732
 
                gboolean have_duration = (header->priv->duration > 0);
733
 
 
734
 
                title = rhythmdb_entry_get_string (header->priv->entry, RHYTHMDB_PROP_TITLE);
735
 
                album = rhythmdb_entry_get_string (header->priv->entry, RHYTHMDB_PROP_ALBUM);
736
 
                artist = rhythmdb_entry_get_string (header->priv->entry, RHYTHMDB_PROP_ARTIST);
737
 
 
738
 
                get_extra_metadata (header->priv->db,
739
 
                                    header->priv->entry,
740
 
                                    RHYTHMDB_PROP_STREAM_SONG_TITLE,
741
 
                                    &streaming_title);
742
 
                if (streaming_title) {
743
 
                        /* use entry title as stream name */
744
 
                        stream_name = title;
745
 
                        title = streaming_title;
746
 
                }
747
 
 
748
 
                get_extra_metadata (header->priv->db,
749
 
                                    header->priv->entry,
750
 
                                    RHYTHMDB_PROP_STREAM_SONG_ARTIST,
751
 
                                    &streaming_artist);
752
 
                if (streaming_artist) {
753
 
                        /* override artist from entry */
754
 
                        artist = streaming_artist;
755
 
                }
756
 
 
757
 
                get_extra_metadata (header->priv->db,
758
 
                                    header->priv->entry,
759
 
                                    RHYTHMDB_PROP_STREAM_SONG_ALBUM,
760
 
                                    &streaming_album);
761
 
                if (streaming_album) {
762
 
                        /* override album from entry */
763
 
                        album = streaming_album;
764
 
                }
765
 
 
766
 
                widget_dir = (gtk_widget_get_direction (GTK_WIDGET (header->priv->song)) == GTK_TEXT_DIR_LTR) ?
767
 
                             PANGO_DIRECTION_LTR : PANGO_DIRECTION_RTL;
768
 
 
769
 
                char *t;
770
 
                t = rb_text_cat (widget_dir, title, TITLE_FORMAT, NULL);
771
 
                gtk_label_set_markup (GTK_LABEL (header->priv->song), t);
772
 
                g_free (t);
773
 
 
774
 
                if (artist == NULL || artist[0] == '\0') {      /* this is crap; should be up to the entry type */
775
 
                        if (stream_name != NULL) {
776
 
                                t = rb_text_cat (widget_dir, stream_name, STREAM_FORMAT, NULL);
777
 
                                gtk_label_set_markup (GTK_LABEL (header->priv->details), t);
778
 
                                g_free (t);
779
 
                        } else {
780
 
                                gtk_label_set_markup (GTK_LABEL (header->priv->details), "");
781
 
                        }
782
 
                } else {
783
 
                        const char *by;
784
 
                        const char *from;
785
 
                        PangoDirection dir;
786
 
                        PangoDirection native;
787
 
 
788
 
                        native = PANGO_DIRECTION_LTR;
789
 
                        if (gtk_widget_get_direction (GTK_WIDGET (header->priv->details)) != GTK_TEXT_DIR_LTR) {
790
 
                                native = PANGO_DIRECTION_RTL;
791
 
                        }
792
 
 
793
 
                        dir = rb_text_common_direction (artist, album, NULL);
794
 
                        if (!rb_text_direction_conflict (dir, native)) {
795
 
                                dir = native;
796
 
                                by = _("by");
797
 
                                from = _("from");
798
 
                        } else {
799
 
                                by = UNICODE_MIDDLE_DOT;
800
 
                                from = UNICODE_MIDDLE_DOT;
801
 
                        }
802
 
 
803
 
                        t = rb_text_cat (dir,
804
 
                                         by, "%s",
805
 
                                         artist, ARTIST_FORMAT,
806
 
                                         from, "%s",
807
 
                                         album, ALBUM_FORMAT,
808
 
                                         NULL);
809
 
                        gtk_label_set_markup (GTK_LABEL (header->priv->details), t);
810
 
                        g_free (t);
811
 
                }
812
 
 
813
 
                gtk_widget_set_sensitive (header->priv->scale, have_duration && header->priv->seekable);
814
 
                rb_header_sync_time (header);
815
 
 
816
 
                g_free (streaming_artist);
817
 
                g_free (streaming_album);
818
 
                g_free (streaming_title);
819
 
        } else {
820
 
                rb_debug ("not playing");
821
 
                label_text = g_markup_printf_escaped (TITLE_FORMAT, _("Not Playing"));
822
 
                gtk_label_set_markup (GTK_LABEL (header->priv->song), label_text);
823
 
                g_free (label_text);
824
 
 
825
 
                gtk_label_set_text (GTK_LABEL (header->priv->details), "");
826
 
 
827
 
                rb_header_sync_time (header);
828
 
        }
829
 
}
830
 
 
831
 
static void
832
 
rb_header_sync_time (RBHeader *header)
833
 
{
834
 
        if (header->priv->shell_player == NULL)
835
 
                return;
836
 
 
837
 
        if (header->priv->slider_dragging == TRUE) {
838
 
                rb_debug ("slider is dragging, not syncing");
839
 
                return;
840
 
        }
841
 
 
842
 
        if (header->priv->duration > 0) {
843
 
                double progress = ((double) header->priv->elapsed_time) / RB_PLAYER_SECOND;
844
 
 
845
 
                header->priv->slider_locked = TRUE;
846
 
 
847
 
                g_object_freeze_notify (G_OBJECT (header->priv->adjustment));
848
 
                gtk_adjustment_set_value (header->priv->adjustment, progress);
849
 
                gtk_adjustment_set_upper (header->priv->adjustment, header->priv->duration);
850
 
                g_object_thaw_notify (G_OBJECT (header->priv->adjustment));
851
 
 
852
 
                header->priv->slider_locked = FALSE;
853
 
                gtk_widget_set_sensitive (header->priv->scale, header->priv->seekable);
854
 
        } else {
855
 
                header->priv->slider_locked = TRUE;
856
 
 
857
 
                g_object_freeze_notify (G_OBJECT (header->priv->adjustment));
858
 
                gtk_adjustment_set_value (header->priv->adjustment, 0.0);
859
 
                gtk_adjustment_set_upper (header->priv->adjustment, 0.0);
860
 
                g_object_thaw_notify (G_OBJECT (header->priv->adjustment));
861
 
 
862
 
                header->priv->slider_locked = FALSE;
863
 
                gtk_widget_set_sensitive (header->priv->scale, FALSE);
864
 
        }
865
 
 
866
 
        rb_header_update_elapsed (header);
867
 
}
868
 
 
869
 
static gboolean
870
 
slider_press_callback (GtkWidget *widget,
871
 
                       GdkEventButton *event,
872
 
                       RBHeader *header)
873
 
{
874
 
        header->priv->slider_dragging = TRUE;
875
 
        header->priv->latest_set_time = -1;
876
 
        g_object_notify (G_OBJECT (header), "slider-dragging");
877
 
 
878
 
        /* HACK: we want the behaviour you get with the middle button, so we
879
 
         * mangle the event.  clicking with other buttons moves the slider in
880
 
         * step increments, clicking with the middle button moves the slider to
881
 
         * the location of the click.
882
 
         */
883
 
        event->button = 2;
884
 
 
885
 
 
886
 
        return FALSE;
887
 
}
888
 
 
889
 
static gboolean
890
 
slider_moved_timeout (RBHeader *header)
891
 
{
892
 
        GDK_THREADS_ENTER ();
893
 
 
894
 
        apply_slider_position (header);
895
 
        header->priv->slider_moved_timeout = 0;
896
 
 
897
 
        GDK_THREADS_LEAVE ();
898
 
 
899
 
        return FALSE;
900
 
}
901
 
 
902
 
static gboolean
903
 
slider_moved_callback (GtkWidget *widget,
904
 
                       GdkEventMotion *event,
905
 
                       RBHeader *header)
906
 
{
907
 
        double progress;
908
 
 
909
 
        if (header->priv->slider_dragging == FALSE) {
910
 
                rb_debug ("slider is not dragging");
911
 
                return FALSE;
912
 
        }
913
 
 
914
 
        progress = gtk_adjustment_get_value (header->priv->adjustment);
915
 
        header->priv->elapsed_time = (gint64) ((progress+0.5) * RB_PLAYER_SECOND);
916
 
 
917
 
        rb_header_update_elapsed (header);
918
 
 
919
 
        if (header->priv->slider_moved_timeout != 0) {
920
 
                rb_debug ("removing old timer");
921
 
                g_source_remove (header->priv->slider_moved_timeout);
922
 
                header->priv->slider_moved_timeout = 0;
923
 
        }
924
 
        header->priv->slider_moved_timeout =
925
 
                g_timeout_add (40, (GSourceFunc) slider_moved_timeout, header);
926
 
 
927
 
        return FALSE;
928
 
}
929
 
 
930
 
static void
931
 
apply_slider_position (RBHeader *header)
932
 
{
933
 
        double progress;
934
 
        long new;
935
 
 
936
 
        progress = gtk_adjustment_get_value (header->priv->adjustment);
937
 
        new = (long) (progress+0.5);
938
 
 
939
 
        if (new != header->priv->latest_set_time) {
940
 
                rb_debug ("setting time to %ld", new);
941
 
                rb_shell_player_set_playing_time (header->priv->shell_player, new, NULL);
942
 
                header->priv->latest_set_time = new;
943
 
        }
944
 
}
945
 
 
946
 
static gboolean
947
 
slider_release_callback (GtkWidget *widget,
948
 
                         GdkEventButton *event,
949
 
                         RBHeader *header)
950
 
{
951
 
        /* HACK: see slider_press_callback */
952
 
        event->button = 2;
953
 
 
954
 
        if (header->priv->slider_dragging == FALSE) {
955
 
                rb_debug ("slider is not dragging");
956
 
                return FALSE;
957
 
        }
958
 
 
959
 
        if (header->priv->slider_moved_timeout != 0) {
960
 
                g_source_remove (header->priv->slider_moved_timeout);
961
 
                header->priv->slider_moved_timeout = 0;
962
 
        }
963
 
 
964
 
        apply_slider_position (header);
965
 
        header->priv->slider_dragging = FALSE;
966
 
        g_object_notify (G_OBJECT (header), "slider-dragging");
967
 
        return FALSE;
968
 
}
969
 
 
970
 
static void
971
 
slider_changed_callback (GtkWidget *widget,
972
 
                         RBHeader *header)
973
 
{
974
 
        /* if the slider isn't being dragged, and nothing else is happening,
975
 
         * this indicates the position was adjusted with a keypress (page up/page down etc.),
976
 
         * so we should directly apply the change.
977
 
         */
978
 
        if (header->priv->slider_dragging == FALSE &&
979
 
            header->priv->slider_locked == FALSE) {
980
 
                apply_slider_position (header);
981
 
        }
982
 
}
983
 
 
984
 
static gboolean
985
 
slider_scroll_callback (GtkWidget *widget, GdkEventScroll *event, RBHeader *header)
986
 
{
987
 
        gboolean retval = TRUE;
988
 
        gdouble adj = gtk_adjustment_get_value (header->priv->adjustment);
989
 
 
990
 
        switch (event->direction) {
991
 
        case GDK_SCROLL_UP:
992
 
                rb_debug ("slider scrolling up");
993
 
                gtk_adjustment_set_value (header->priv->adjustment, adj + SCROLL_UP_SEEK_OFFSET);
994
 
                break;
995
 
 
996
 
        case GDK_SCROLL_DOWN:
997
 
                rb_debug ("slider scrolling down");
998
 
                gtk_adjustment_set_value (header->priv->adjustment, adj + SCROLL_DOWN_SEEK_OFFSET);
999
 
                break;
1000
 
 
1001
 
        default:
1002
 
                retval = FALSE;
1003
 
                break;
1004
 
        }
1005
 
 
1006
 
        return retval;
1007
 
}
1008
 
 
1009
 
static void
1010
 
rb_header_update_elapsed (RBHeader *header)
1011
 
{
1012
 
        long seconds;
1013
 
        char *elapsed;
1014
 
        char *duration;
1015
 
        char *label;
1016
 
 
1017
 
        if (header->priv->entry == NULL) {
1018
 
                gtk_label_set_text (GTK_LABEL (header->priv->timelabel), "");
1019
 
                return;
1020
 
        }
1021
 
 
1022
 
        seconds = header->priv->elapsed_time / RB_PLAYER_SECOND;
1023
 
        if (header->priv->duration == 0) {
1024
 
                label = rb_make_time_string (seconds);
1025
 
                gtk_label_set_text (GTK_LABEL (header->priv->timelabel), label);
1026
 
                g_free (label);
1027
 
        } else if (header->priv->show_remaining) {
1028
 
 
1029
 
                duration = rb_make_time_string (header->priv->duration);
1030
 
 
1031
 
                if (seconds > header->priv->duration) {
1032
 
                        elapsed = rb_make_time_string (0);
1033
 
                } else {
1034
 
                        elapsed = rb_make_time_string (header->priv->duration - seconds);
1035
 
                }
1036
 
 
1037
 
                /* Translators: remaining time / total time */
1038
 
                label = g_strdup_printf (_("-%s / %s"), elapsed, duration);
1039
 
                gtk_label_set_text (GTK_LABEL (header->priv->timelabel), label);
1040
 
 
1041
 
                g_free (elapsed);
1042
 
                g_free (duration);
1043
 
                g_free (label);
1044
 
        } else {
1045
 
                elapsed = rb_make_time_string (seconds);
1046
 
                duration = rb_make_time_string (header->priv->duration);
1047
 
 
1048
 
                /* Translators: elapsed time / total time */
1049
 
                label = g_strdup_printf (_("%s / %s"), elapsed, duration);
1050
 
                gtk_label_set_text (GTK_LABEL (header->priv->timelabel), label);
1051
 
 
1052
 
                g_free (elapsed);
1053
 
                g_free (duration);
1054
 
                g_free (label);
1055
 
        }
1056
 
}
1057
 
 
1058
 
static void
1059
 
rb_header_elapsed_changed_cb (RBShellPlayer *player,
1060
 
                              gint64 elapsed,
1061
 
                              RBHeader *header)
1062
 
{
1063
 
        header->priv->elapsed_time = elapsed;
1064
 
        rb_header_sync_time (header);
1065
 
}
1066
 
 
1067
 
static void
1068
 
rb_header_extra_metadata_cb (RhythmDB *db,
1069
 
                             RhythmDBEntry *entry,
1070
 
                             const char *property_name,
1071
 
                             const GValue *metadata,
1072
 
                             RBHeader *header)
1073
 
{
1074
 
        if (entry != header->priv->entry)
1075
 
                return;
1076
 
 
1077
 
        if (g_str_equal (property_name, RHYTHMDB_PROP_STREAM_SONG_TITLE) ||
1078
 
            g_str_equal (property_name, RHYTHMDB_PROP_STREAM_SONG_ARTIST) ||
1079
 
            g_str_equal (property_name, RHYTHMDB_PROP_STREAM_SONG_ALBUM)) {
1080
 
                rb_header_sync (header);
1081
 
        }
1082
 
}
1083
 
 
1084
 
static void
1085
 
pixbuf_dropped_cb (RBFadingImage *image, GdkPixbuf *pixbuf, RBHeader *header)
1086
 
{
1087
 
        RBExtDBKey *key;
1088
 
        const char *artist;
1089
 
        GValue v = G_VALUE_INIT;
1090
 
 
1091
 
        if (header->priv->entry == NULL || pixbuf == NULL)
1092
 
                return;
1093
 
 
1094
 
        /* maybe ignore tiny pixbufs? */
1095
 
 
1096
 
        key = rb_ext_db_key_create_storage ("album", rhythmdb_entry_get_string (header->priv->entry, RHYTHMDB_PROP_ALBUM));
1097
 
        artist = rhythmdb_entry_get_string (header->priv->entry, RHYTHMDB_PROP_ALBUM_ARTIST);
1098
 
        if (artist == NULL || artist[0] == '\0' || strcmp (artist, _("Unknown")) == 0) {
1099
 
                artist = rhythmdb_entry_get_string (header->priv->entry, RHYTHMDB_PROP_ARTIST);
1100
 
        }
1101
 
        rb_ext_db_key_add_field (key, "artist", artist);
1102
 
 
1103
 
        g_value_init (&v, GDK_TYPE_PIXBUF);
1104
 
        g_value_set_object (&v, image);
1105
 
        rb_ext_db_store (header->priv->art_store, key, RB_EXT_DB_SOURCE_USER_EXPLICIT, &v);
1106
 
        g_value_unset (&v);
1107
 
 
1108
 
        rb_ext_db_key_free (key);
1109
 
}
1110
 
 
1111
 
static void
1112
 
uri_dropped_cb (RBFadingImage *image, const char *uri, RBHeader *header)
1113
 
{
1114
 
        RBExtDBKey *key;
1115
 
        const char *artist;
1116
 
 
1117
 
        if (header->priv->entry == NULL || uri == NULL)
1118
 
                return;
1119
 
 
1120
 
        /* maybe ignore tiny pixbufs? */
1121
 
 
1122
 
        key = rb_ext_db_key_create_storage ("album", rhythmdb_entry_get_string (header->priv->entry, RHYTHMDB_PROP_ALBUM));
1123
 
        artist = rhythmdb_entry_get_string (header->priv->entry, RHYTHMDB_PROP_ALBUM_ARTIST);
1124
 
        if (artist == NULL || artist[0] == '\0' || strcmp (artist, _("Unknown")) == 0) {
1125
 
                artist = rhythmdb_entry_get_string (header->priv->entry, RHYTHMDB_PROP_ARTIST);
1126
 
        }
1127
 
        rb_ext_db_key_add_field (key, "artist", artist);
1128
 
 
1129
 
        rb_ext_db_store_uri (header->priv->art_store, key, RB_EXT_DB_SOURCE_USER_EXPLICIT, uri);
1130
 
 
1131
 
        rb_ext_db_key_free (key);
1132
 
}
1133
 
 
1134
 
static void
1135
 
image_button_press_cb (GtkWidget *widget, GdkEvent *event, RBHeader *header)
1136
 
{
1137
 
        if (event->button.type != GDK_2BUTTON_PRESS ||
1138
 
            event->button.button != 1)
1139
 
                return;
1140
 
 
1141
 
        if (header->priv->image_path != NULL) {
1142
 
                GAppInfo *app;
1143
 
                GAppLaunchContext *context;
1144
 
                GList *files = NULL;
1145
 
 
1146
 
                app = g_app_info_get_default_for_type ("image/jpeg", FALSE);
1147
 
                if (app == NULL) {
1148
 
                        return;
1149
 
                }
1150
 
 
1151
 
                files = g_list_append (NULL, g_file_new_for_path (header->priv->image_path));
1152
 
 
1153
 
                context = G_APP_LAUNCH_CONTEXT (gdk_display_get_app_launch_context (gtk_widget_get_display (widget)));
1154
 
                g_app_info_launch (app, files, context, NULL);
1155
 
                g_object_unref (context);
1156
 
                g_object_unref (app);
1157
 
                g_list_free_full (files, g_object_unref);
1158
 
        }
1159
 
}
1160
 
 
1161
 
static void
1162
 
time_button_clicked_cb (GtkWidget *widget, RBHeader *header)
1163
 
{
1164
 
        g_object_set (header, "show-remaining", !header->priv->show_remaining, NULL);
1165
 
}