Move first stuff to gtk3
[gmpc.git] / src / gmpc-metaimage.gob
blob5f30dea6410aff495c4b62b757650ba22fb89aa5
1 /* Gnome Music Player Client (GMPC)
2  * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3  * Project homepage: http://gmpclient.org/
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 requires 2.0.0
22 %ph{
23 #include "main.h"
24 #include "misc.h"
25 #define LOG_DOMAIN "MetaImage"
28 %headertop{
29 #include <gtk/gtk.h>
30 #include <metadata.h>
31 #include <libmpd/libmpd.h>
32 #include "gmpc-extras.h"
36 static unsigned int num_drag_targets = 4; /* skip hyperlinks for now */
37 static GtkTargetEntry data_image_drag_target[] =
39     { (gchar *)"image/jpeg", 0, 0 },
40     { (gchar *)"image/png",  0, 1 },
41     { (gchar *)"image/gif",  0, 2 },
42         { (gchar *)"text/uri-list", 0, 3},
43     { (gchar *)"_NETSCAPE_URL", 0,4},
44     { (gchar *)"x-url/http", 0,5}
49 %ph{
50 /**
51  * Indicate the state
52  */
53 typedef enum _GmpcMetaImageState{
54         STATE_NA,
55         STATE_FETCHING,
56         STATE_IMAGE,
57     STATE_EMPTY,
58     STATE_INVALID_QUERY,
59         NUM_STATES
60 }GmpcMetaImageState;
68 class Gmpc:MetaImage from Gtk:Event:Box{
69         private GmpcMetaImageState state = {STATE_EMPTY};
70         private int refresh = FALSE;
71         private gulong status_signal = {0};
72         private gulong connect_signal = {0};
73         private gulong meta_id = {0};
75         private gulong metadata_force_reload = {0};
77         private gchar *image_url = {NULL};
79         private mpd_Song *song = {NULL} destroywith mpd_freeSong;
81         /** Public */
83         public int size = {48};
84         public MetaDataType image_type = {META_ALBUM_ART};
85         public MpdObj *connection= {NULL};
86         public gboolean hide_on_na = {FALSE};
87         public gboolean squared = {TRUE};
88         public gchar *no_cover_icon = {g_strdup("gmpc-no-cover")} destroywith g_free;
89         public gchar *loading_cover_icon = {g_strdup("gmpc-loading-cover")} destroywith g_free;
91         private gulong expose_id = {0};
92         public gboolean scale_up = FALSE;
93         /**
94          * I want fully set/get control,so I don't use property stuff,
95          * is there a way around this?
96          */
97         public gboolean is_visible = {TRUE};
99         property INT image_type
100                 (nick = "Image type",
101                 blurb = "Type of the image, like artist art",
102                 default_value = META_ALBUM_ART,
103                 export,
104                 link);
106         property INT size
107                 (nick = "Size",
108                 blurb = "Size of the image",
109                 default_value = 48,
110                 export,
111                 link);
113         property BOOLEAN hide_on_na
114                 (nick = "HideOnNA",
115                 blurb = "Hide the image when not available",
116                 default_value = FALSE,
117                 export,
118                 link);
120     property BOOLEAN scale_up
121         (nick = "Scale image up",
122         blurb = "Scale cover art up",
123         default_value = FALSE,
124         export,
125         link);
127         property BOOLEAN squared
128                 (nick = "Squared",
129                         blurb = "Keep the widget squared",
130                         default_value = TRUE,
131                         link);
132     public void set_no_cover_icon (self, const gchar *name)
133     {
134         if(self->no_cover_icon) {
135             q_free(self->no_cover_icon);
136         }
137         self->no_cover_icon = g_strdup(name);
138     }
139     public void set_loading_cover_icon (self, const gchar *name)
140     {
141         if(self->loading_cover_icon) {
142             q_free(self->loading_cover_icon);
143         }
144         self->loading_cover_icon = g_strdup(name);
145     }
146     public void set_squared (self, const gboolean item)
147     {
148         self->squared = item;
149     }
150     public void set_connection(self, MpdObj *conn)
151     {
152         self->connection = conn;
153         if(conn)
154         {
155             self->_priv->status_signal = g_signal_connect_swapped(G_OBJECT(gmpcconn),
156                     "status_changed",
157                     G_CALLBACK(self_update_cover),
158                     G_OBJECT(self));
160             self->_priv->connect_signal = g_signal_connect_swapped(G_OBJECT(gmpcconn),
161                     "connection_changed",
162                     G_CALLBACK(self_connection_changed),
163                     G_OBJECT(self));
164         }
165     }
166     private GtkWidget *image = { (GtkWidget *)gmpc_meta_image_async_new()} ;
167     private GtkWidget *tooltip_image = { (GtkWidget *)gmpc_meta_image_async_new()} ;
169     init (self)
170     {
171             GtkWidget *win = NULL;
172             gtk_container_add(GTK_CONTAINER(self), self->_priv->image);
173             gtk_container_set_resize_mode(GTK_CONTAINER(self), GTK_RESIZE_IMMEDIATE);
174             gtk_widget_show_all(GTK_WIDGET(self));
176             g_signal_connect_swapped(G_OBJECT(self/*->_priv->image*/), "button-press-event", G_CALLBACK(self_menu_populate_callback), self);
177             self->_priv->meta_id = g_signal_connect(G_OBJECT(gmw), "data-changed", G_CALLBACK(self_meta_callback), self);
178             gtk_widget_add_events(GTK_WIDGET(self->_priv->image), GDK_POINTER_MOTION_MASK);
179             gtk_widget_set_no_show_all(GTK_WIDGET(self),TRUE);
181             win = gtk_window_new(GTK_WINDOW_POPUP);
182             gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
183             gtk_widget_modify_bg(win, GTK_STATE_NORMAL, &(GTK_WIDGET(self)->style->black));
184             gtk_container_set_border_width(GTK_CONTAINER(win), 6);
185             gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(self->_priv->tooltip_image));
187             gtk_widget_set_tooltip_window(GTK_WIDGET(self), GTK_WINDOW(win));
188             g_signal_connect(G_OBJECT(self), "query-tooltip", G_CALLBACK(self_tooltip_query), win);
189     }
190     private
191     gboolean tooltip_query(self, gint x, gint y,gboolean keyboard_mode, GtkTooltip *tip, GtkWidget *win)
192     {
193         if(self->_priv->state == STATE_IMAGE)
194         {
195                         gtk_widget_show(self->_priv->tooltip_image);
196                         return TRUE;
197                 }
198         return FALSE;
199     }
201         override (G:Object)
202                 void
203                 dispose(G:Object *obj)
204                 {
205                         Self *self = GMPC_METAIMAGE(obj);
206             if(self->_priv->meta_id)
207                         {
208                                 g_signal_handler_disconnect(G_OBJECT(gmw),self->_priv->meta_id);
209                                 self->_priv->meta_id =  0;
210                         }
211             if(self->_priv->metadata_force_reload)
212             {
213                 g_signal_handler_disconnect(G_OBJECT(gmw),self->_priv->metadata_force_reload);
214                 self->_priv->metadata_force_reload =  0;
215             }
216                         if(self->_priv->image_url) {
217                                 q_free(self->_priv->image_url);
218                         }
219                         if(self->_priv->status_signal){
220                                 g_signal_handler_disconnect(G_OBJECT(gmpcconn), self->_priv->status_signal);
221                                 self->_priv->status_signal =0;
222                         }
223                         if(self->_priv->connect_signal){
224                                 g_signal_handler_disconnect(G_OBJECT(gmpcconn), self->_priv->connect_signal);
225                                 self->_priv->connect_signal=0;
226                         }
227                         PARENT_HANDLER(obj);
228                 }
229     private
230         void
231         drag_data_recieved (self,
232                 GdkDragContext     *context,
233                 gint                x,
234                 gint                y,
235                 GtkSelectionData   *data,
236                 guint               info,
237                 guint               dnd_time,
238                 GtkWidget          *widget
239                 )
240         {
241             int found = FALSE;
242             if(self->_priv->song)
243             {
244                 if(info < num_drag_targets)
245                 {
246                     gchar **uri =  gtk_selection_data_get_uris(data);
247                     /* Only one uri is interresting */
248                     if(uri && uri[0])
249                     {
250                         gchar *path = g_filename_from_uri(uri[0], NULL, NULL);
252                         /* try to open it */
253                         if(path && gdk_pixbuf_get_file_info(path, NULL,NULL))
254                                                 {
255                                                         /* Create MetaData object */
256                                                         MetaData* met = meta_data_new();
257                                                         met->type = self->image_type;
258                                                         met->plugin_name = g_strdup("User set");
259                                                         met->content_type = META_DATA_CONTENT_URI;
260                                                         meta_data_set_uri(met, path);
262                                                         meta_data_set_entry(self->_priv->song, met);
263                                                         /* free Metadata object */
264                                                         meta_data_free(met);
265                                                 }
266                         g_free(path);
267                     }
268                     g_strfreev(uri);
269                 }
270             }
272             gtk_drag_finish(context, found, FALSE, dnd_time);
273         }
274         /* hack to make the "delayed" image load when it gets visible"
275          */
276         private
277         gboolean
278         expose_event(self, GdkEventExpose *event, gpointer data)
279         {
280             g_signal_handler_disconnect(G_OBJECT(self), self->_priv->expose_id);
281             self->_priv->expose_id = 0;
282             self_update_cover_from_song_delayed_real(self);
283             return FALSE;
284         }
286         public
287         Gmpc:Meta:Image *new_size(int type, int size)
288         {
289             Self *gmi =  GET_NEW;
290             gmi->image_type = type;
291             gmi->size = size;//pixbuf_cache_get_closest_size(size);
294             gtk_event_box_set_visible_window(GTK_EVENT_BOX(gmi), FALSE);
295             gtk_drag_dest_set(GTK_WIDGET(gmi),
296                     GTK_DEST_DEFAULT_ALL,
297                     data_image_drag_target, num_drag_targets,
298                     GDK_ACTION_COPY|GDK_ACTION_LINK|GDK_ACTION_DEFAULT|GDK_ACTION_MOVE);
300             g_signal_connect_swapped (G_OBJECT (gmi),"drag-data-received",
301                     GTK_SIGNAL_FUNC (self_drag_data_recieved),gmi);
303             gmi->_priv->metadata_force_reload = g_signal_connect_swapped(G_OBJECT(gmw), "force-reload", G_CALLBACK(self_reload_image), gmi);
305             return gmi;
306         }
307         public
308                 GtkWidget * new (int type)
309                 {
310                         Self *gmi =  GET_NEW;
311                         gmi->image_type = type;
313             gtk_event_box_set_visible_window(GTK_EVENT_BOX(gmi), FALSE);
314             gtk_drag_dest_set(GTK_WIDGET(gmi),
315                     GTK_DEST_DEFAULT_ALL,
316                 data_image_drag_target, num_drag_targets,
317                 GDK_ACTION_COPY|GDK_ACTION_LINK|GDK_ACTION_DEFAULT|GDK_ACTION_MOVE);
318         g_signal_connect_swapped (G_OBJECT (gmi),"drag-data-received",
319                 GTK_SIGNAL_FUNC (self_drag_data_recieved),gmi);
320             gmi->_priv->metadata_force_reload = g_signal_connect_swapped(G_OBJECT(gmw), "force-reload", G_CALLBACK(self_reload_image), gmi);
321             return (GtkWidget *)gmi;
322                 }
324         public
325                 void
326                 update_cover(self, MpdObj *mi, ChangedStatusType what, GmpcConnection *gc)
327                 {
329                         if(self->connection && what&(MPD_CST_STATE|MPD_CST_SONGID|MPD_CST_SONGPOS|MPD_CST_PLAYLIST) && self->is_visible)
330                         {
331                                 int state = mpd_player_get_state(self->connection);
332                                 if(state == MPD_PLAYER_STOP || state == MPD_PLAYER_UNKNOWN)
333                                 {
334                     self->_priv->refresh = TRUE;
335                                         self_set_cover_na(self);
336                                 }
337                                 else {
338                                         mpd_Song *song = mpd_playlist_get_current_song(self->connection);
339                                         if(song)
340                                         {
341                         if( self->_priv->refresh == FALSE &&
342                             self->_priv->song &&
343                             self->_priv->song->artist &&
344                             song->artist &&
345                             strcmp(song->artist, self->_priv->song->artist) == 0)
346                         {
347                             /* If we are artist iamge, don't update, same artist */
348                             if(self->image_type == META_ARTIST_ART ) return;
349                             /* If we are album, check if album matches too */
350                             else if(self->image_type == META_ALBUM_ART &&
351                                 self->_priv->song->album && song->album &&
352                                 strcmp(self->_priv->song->album, song->album) == 0){
353                                 return;
354                             }
355                         }
356                                                 self_update_cover_from_song(self, song);
357                                         }
358                                         else
359                                         {
360                                                 self_set_cover_na(self);
361                                         }
362                     self->_priv->refresh = FALSE;
363                                 }
365                         }
366                 }
367         private
368                 void
369                 connection_changed(self,MpdObj *mi, int connect, GmpcConnection *gmpconn)
370                 {
371                         if(!connect)
372                         {
373                                 self_set_cover_na(self);
374                         }
375             else
376             {
377                 if(self->connection)
378                 {
379                     int state = mpd_player_get_state(self->connection);
380                     if(state != MPD_PLAYER_STOP && state != MPD_PLAYER_UNKNOWN)
381                     {
382                         mpd_Song *song = mpd_playlist_get_current_song(self->connection);
383                         if(song){
384                             self_update_cover_from_song(self, song);
385                         }
386                     }
387                 }
389             }
391                 }
393         public
394                 void
395                 update_cover_from_song(self, const mpd_Song *song)
396                 {
397                         MetaDataResult ret;
398             MetaData *met= NULL;
401                         if(self->_priv->song)
402                                 mpd_freeSong(self->_priv->song);
403             self->_priv->song = NULL;
405                         if(!song)
406                         {
407                                 self_set_cover_na(self);
408                                 return;
409                         }
410             self->_priv->song = mpd_songDup(song);
412                         ret = meta_data_get_path(self->_priv->song, self->image_type, &met, NULL, NULL);
413                         if(ret == META_DATA_FETCHING)
414                         {
415                                 self_set_cover_fetching(self);
416                         }else if (ret == META_DATA_AVAILABLE) {
417                                 if (met->content_type == META_DATA_CONTENT_RAW) {
418                     self_set_cover_raw(self, met->content, met->size,met->md5sum);
419                 }else{
420                     self_set_cover_na(self);
421                 }
422                         } else if (ret == META_DATA_INVALID_QUERY) {
423                 self_set_cover_invalid_query(self);
424             }else {
425                                 self_set_cover_na(self);
426                         }
427                         if(met)
428                         {
429                             meta_data_free(met);
430                         }
431                 }
432         private
433         gboolean
434         update_cover_from_song_delayed_real(self)
435         {
436             MetaData *met= NULL;
437             int ret = meta_data_get_path(self->_priv->song, self->image_type, &met, NULL, NULL);
438             if(ret == META_DATA_FETCHING)
439             {
440                 self_set_cover_fetching(self);
441             }else if (ret == META_DATA_AVAILABLE) {
442                                 if (met->content_type == META_DATA_CONTENT_RAW) {
443                                         self_set_cover_raw(self, met->content, met->size,met->md5sum);
444                 } else {
445                     self_set_cover_na(self);
446                 }
447                         } else if (ret == META_DATA_INVALID_QUERY) {
448                 self_set_cover_invalid_query(self);
449             }else{
450                 self_set_cover_na(self);
451             }
452             if(met)
453             {
454                 meta_data_free(met);
455             }
456             return FALSE;
457         }
458         public
459                 void
460                 update_cover_from_song_delayed(self, mpd_Song *song)
461         {
462             if(self->_priv->song)
463                 mpd_freeSong(self->_priv->song);
465             gtk_widget_set_size_request(GTK_WIDGET(self), self->size, self->size);
466             self->_priv->song = mpd_songDup(song);
467             /* hack to make it load when it gets visible */
468             self->_priv->expose_id = g_signal_connect(G_OBJECT(self), "expose-event", G_CALLBACK(self_expose_event) , NULL);
469         }
471         private
472         void
473         meta_callback(GmpcMetaWatcher *gmv, mpd_Song *song, MetaDataType type, MetaDataResult ret, MetaData *met,gpointer data)
474     {
475         Self *self = data;
476         if(!song || !self || !self->_priv || !self->_priv->song)
477             return;
479         /**
480          * Check for fields
481          */
482         if(self->image_type != type)
483             return;
485         // Compare if callback is about 'our' song.
486         // TODO: optimize, by keeping checksum of current song around?
487         {
488             char *ck_a = mpd_song_checksum_type(self->_priv->song, self->image_type);
489             char *ck_b = mpd_song_checksum_type(song, self->image_type);
490             if(ck_a == NULL || ck_b == NULL || strcmp(ck_a, ck_b) != 0) {
491                 g_free(ck_a);
492                 g_free(ck_b);
493                 return;
494             }
495             g_free(ck_a);
496             g_free(ck_b);
497         }
499         /**
500          * If mpd is stopped before the result is back, set the cover to na, and ignore the result
501          */
502         if(self->connection && mpd_player_get_state(self->connection) == MPD_PLAYER_STOP)
503         {
504             self_set_cover_na(self);
505         }
506         else
507         {
508             if(ret == META_DATA_AVAILABLE) {
509                                 if (met->content_type == META_DATA_CONTENT_RAW) {
510                                         self_set_cover_raw(self, met->content, met->size,met->md5sum);
511                 }else{
512                     self_set_cover_na(self);
513                     g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Method not implemented: %i", met->content_type);
514                 }
515             } else if (ret == META_DATA_FETCHING) {
516                 self_set_cover_fetching(self);
517             } else if (ret == META_DATA_INVALID_QUERY) {
518                 self_set_cover_invalid_query(self);
519             } else {
520                 self_set_cover_na(self);
521             }
522         }
523     }
526         public
527                 void
528                 set_cover_invalid_query(self)
529         {
530             int border = FALSE;
531             GError *error = NULL;
532             GdkPixbuf *pb2 = NULL;
535             if(self->_priv->state == STATE_INVALID_QUERY) {
536                 return;
537             }
538             self->_priv->state = STATE_INVALID_QUERY;
539             gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image));
541             if(self->_priv->image_url)
542             {
543                 q_free(self->_priv->image_url);
544                 self->_priv->image_url = NULL;
545             }
546             if(self->hide_on_na)
547             {
548                 gtk_widget_hide(GTK_WIDGET(self));
549                 return;
550             }
552             if(cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART){
553                 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "stylized-invalid-tags-cover", self->size, 0,&error);
554                 border = TRUE;
555                 if(error) {
556                     g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
557                     g_error_free(error);
558                     error = NULL;
559                 }
560             }
561             if(!pb2){
562                 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), self->no_cover_icon, self->size, 0,&error);
563                 if(error) {
564                     g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
565                     g_error_free(error);
566                     error = NULL;
567                 }
568                 border = FALSE;
569             }
571             if(pb2) {
572                 if(self->squared) {
573                     gtk_widget_set_size_request(GTK_WIDGET(self), self->size, self->size);
574                 } else {
575                     //    gtk_widget_set_size_request(GTK_WIDGET(self), gdk_pixbuf_get_width(pb2), gdk_pixbuf_get_height(pb2));
576                 }
577                 gmpc_meta_image_async_set_pixbuf(GMPC_META_IMAGE_ASYNC(self->_priv->image), pb2);
578                 g_object_unref(pb2);
579             } else {
580                 /* If failed to load an image, clear it */
581                 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
582             }
583         }
584         public
585                 void
586                 set_cover_na(self)
587         {
588             int border = FALSE;
589             GError *error = NULL;
590             GdkPixbuf *pb2 = NULL;
593             if(self->_priv->state == STATE_NA) {
594                 return;
595             }
596             self->_priv->state = STATE_NA;
597             gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image));
599             if(self->_priv->image_url)
600             {
601                 q_free(self->_priv->image_url);
602                 self->_priv->image_url = NULL;
603             }
604             if(self->hide_on_na)
605             {
606                 gtk_widget_hide(GTK_WIDGET(self));
607                 return;
608             }
610             if(cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART){
611                 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "stylized-no-cover", self->size, 0,&error);
612                 border = TRUE;
613                 if(error) {
614                     g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
615                     g_error_free(error);
616                     error = NULL;
617                 }
618             }
619             if(!pb2){
620                 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), self->no_cover_icon, self->size, 0,&error);
621                 if(error) {
622                     g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
623                     g_error_free(error);
624                     error = NULL;
625                 }
626                 border = FALSE;
627             }
629             if(pb2) {
630                 if(self->squared) {
631                     gtk_widget_set_size_request(GTK_WIDGET(self), self->size, self->size);
632                 } else {
633                     //    gtk_widget_set_size_request(GTK_WIDGET(self), gdk_pixbuf_get_width(pb2), gdk_pixbuf_get_height(pb2));
634                 }
635                 gmpc_meta_image_async_set_pixbuf(GMPC_META_IMAGE_ASYNC(self->_priv->image), pb2);
636                 g_object_unref(pb2);
637             } else {
638                 /* If failed to load an image, clear it */
639                 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
640             }
641         }
642         public
643                 void
644                 set_cover_fetching(self)
645         {
646             int border = FALSE;
647             GError *error = NULL;
648             GdkPixbuf *pb2 = NULL;
650             if(self->_priv->state == STATE_FETCHING) {
651                 return;
652             }
653             self->_priv->state = STATE_FETCHING;
654                         gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image));
655                         if(self->_priv->image_url)
656             {
657                 q_free(self->_priv->image_url);
658                 self->_priv->image_url = NULL;
659             }
660             if(self->hide_on_na)
661             {
662                 gtk_widget_hide(GTK_WIDGET(self));
663             }
666             if(cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART){
667                 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "stylized-fetching-cover", self->size, 0,&error);
668                 if(error) {
669                     g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
670                     g_error_free(error);
671                     error = NULL;
672                 }
673                 border=TRUE;
674             }
675             if(!pb2){
676                 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), self->loading_cover_icon, self->size, 0,&error);
677                 if(error) {
678                     g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
679                     g_error_free(error);
680                     error = NULL;
681                 }
682                 border = FALSE;
684             }
686             if(self->squared) {
687                 gtk_widget_set_size_request(GTK_WIDGET(self), self->size, self->size);
688             } else {
689                 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
690             }
692             if(pb2) {
693                 gmpc_meta_image_async_set_pixbuf(GMPC_META_IMAGE_ASYNC(self->_priv->image), pb2);
694                 g_object_unref(pb2);
695             } else {
696                 /* If failed to load an image, clear it */
697                 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
698             }
699         }
701     public
702         void
703         set_cover_raw(self, unsigned char *data, unsigned int size, unsigned char *md5sum)
704                 {
705                         self->_priv->state = STATE_IMAGE;
706                         gmpc_meta_image_async_set_from_raw(GMPC_META_IMAGE_ASYNC(self->_priv->image),data, size, self->size,
707                                         ((cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART))?
708                                         GMPC_MODIFICATION_TYPE_CASING:GMPC_MODIFICATION_TYPE_BORDER,
709                                         md5sum
710                                         );
711                         if(self->squared) {
712                                 gtk_widget_set_size_request(GTK_WIDGET(self), self->size, self->size);
713                         }
714                         // Update tooltip.
715                         if(gtk_widget_get_has_tooltip(GTK_WIDGET(self)))
716                         {
717                                 gmpc_meta_image_async_set_from_raw(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image),
718                                         data, size, 350,
719                                         0,
720                                         md5sum
721                                         );
722                         }
723                 }
725         public
726                 void
727                 set_is_visible(self, gboolean is_visible)
728                 {
729                         self->is_visible = is_visible;
730                         if(self->is_visible)
731                         {
732                                 if(self->connection)
733                                 {
734                                         self_update_cover(self,self->connection, MPD_CST_STATE, NULL);
735                                 }
736                         } else {
737                                 gtk_widget_hide(GTK_WIDGET(self));
738                         }
739                 }
741         public
742         void
743         query_refetch(self)
744         {
745                 if(self->_priv->song)
746                 {
747                         MetaDataResult ret;
748                         MetaData *met = NULL;
750                         ret = meta_data_get_path(self->_priv->song, self->image_type|META_QUERY_NO_CACHE, &met, NULL, NULL);
751                         if(ret == META_DATA_FETCHING)
752                         {
753                                 self_set_cover_fetching(self);
754                         }else if (ret == META_DATA_AVAILABLE) {
755                                 if (met->content_type == META_DATA_CONTENT_RAW) {
756                                         self_set_cover_raw(self, met->content, met->size,met->md5sum);
757                                 }else{
758                                         g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Not implemented");
759                                         self_set_cover_na(self);
760                                 }
761             } else if (ret == META_DATA_INVALID_QUERY) {
762                 self_set_cover_invalid_query(self);
763                         } else {
764                                 self_set_cover_na(self);
765                         }
766                         if(met)
767                         {
768                                 meta_data_free(met);
769                         }
770                 }
771         }
773     signal last NONE (POINTER)
774     void menu_populate_client(self, GtkMenu *menu)
775     {
777     }
779         private
780         gboolean
781         menu_populate_callback(self,GdkEventButton *event,  gpointer data)
782         {
783                 if(self->_priv->song && event->button == 3 && self->_priv->state != STATE_INVALID_QUERY)
784                 {
785                         GtkWidget *menu = gtk_menu_new();
786                         GtkWidget *item = NULL;
788             self_menu_populate_client(self,GTK_MENU(menu));
790                         item = gtk_image_menu_item_new_with_label(_("Refetch"));
791                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU));
792                         g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_query_refetch),self);
793                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
795                         item = gtk_image_menu_item_new_with_label(_("Select file"));
796                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU));
797                         g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_select_file),self);
798                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
800                         item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR, NULL);
801                         g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_clear_entry),self);
802                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
804                         item = gtk_image_menu_item_new_with_label(_("Metadata selector"));
805                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
806                         g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_select_metadata_editor),self);
807                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
809                         gtk_widget_show_all(menu);
810                         gtk_menu_popup(GTK_MENU(menu), NULL, NULL,NULL, NULL, event->button, event->time);
811                         return TRUE;
812                 }
813         else if (self->_priv->state == STATE_INVALID_QUERY)
814         {
815             playlist3_show_error_message(_("Insufficient tags available to get image."), ERROR_WARNING);
816             return TRUE;
817         }
818                 return FALSE;
819         }
821         private
822         void
823         clear_entry(self)
824         {
825                 meta_data_clear_entry(self->_priv->song, self->image_type);
826         }
828     private void
829     select_metadata_editor(self)
830     {
831                 gmpc_meta_data_edit_window_new(self->_priv->song,self->image_type);
832     }
834         public
835         void
836         select_file(self)
837         {
838         gchar *p;
839                 mpd_Song *song = mpd_songDup(self->_priv->song);
840                 GtkFileFilter *gff = gtk_file_filter_new();
841                 GtkWidget *fcd = gtk_file_chooser_dialog_new(_("Select File"),NULL,
842                                          GTK_FILE_CHOOSER_ACTION_OPEN,
843                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
844                                       GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
845                                       NULL);
846                 gtk_file_filter_set_name(gff, _("Images"));
847                 gtk_file_filter_add_pixbuf_formats(gff);
848                 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fcd), gff);
850                 gff = gtk_file_filter_new();
851                 gtk_file_filter_set_name(gff, _("All"));
852                 gtk_file_filter_add_pattern(gff, "*");
853                 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fcd), gff);
855                 gtk_widget_show_all(fcd);
857         p = cfg_get_single_value_as_string(config, "MetaData", "image-file-chooser");
858         if(p) {
859             gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fcd), p);
860             g_free(p);
861         }
862         switch(gtk_dialog_run(GTK_DIALOG(fcd)))
863                 {
864                         case GTK_RESPONSE_ACCEPT:
865                                 {
866                                         gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fcd));
867                                         {
868                                                 /* Create MetaData object */
869                                                 MetaData* met = meta_data_new();
870                                                 met->type = self->image_type;
871                                                 met->plugin_name = g_strdup("User set");
872                                                 met->content_type = META_DATA_CONTENT_URI;
873                                                 meta_data_set_uri(met, filename);
875                                                 meta_data_set_entry(self->_priv->song, met);
876                                                 /* free Metadata object */
877                                                 meta_data_free(met);
879                                                 cfg_set_single_value_as_string(config, "MetaData", "image-file-chooser", filename);
880                                         }
882                                 }
883                         default:
884                                 break;
885                 }
886                 gtk_widget_destroy(fcd);
887                 mpd_freeSong(song);
888         }
890         public
891         void
892         reload_image(self)
893         {
894         gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
895         switch(self->_priv->state)
896                 {
897                         case STATE_NA:
898                     self->_priv->state = STATE_EMPTY;
899                                         self_set_cover_na(self);
900                                         break;
901                         case STATE_FETCHING:
902                     self->_priv->state = STATE_EMPTY;
903                                         self_set_cover_fetching(self);
904                                         break;
905                         case STATE_IMAGE:
906                     // Set dirty state.
907                     self_set_dirty(self);
908                     if(self->_priv->song != NULL) {
909                         // Steal song.
910                         mpd_Song *song = self->_priv->song;
911                         self->_priv->song = NULL;
912                         // self update.
913                         self_update_cover_from_song(self,song);
914                         // free.
915                         mpd_freeSong(song);
916                     } else {
917                         self_set_cover_na(self);
918                     }
919             /* fix bitching */
920             case STATE_EMPTY:
921             case NUM_STATES:
922                         default:
923                                         break;
924                 }
925         }
927         public void set_dirty(self)
928     {
929         self->_priv->state = STATE_EMPTY;
930     }