Do the loading inside the fetcher thread.
[gmpc.git] / src / gmpc-metaimage.gob
blob1ac83d2f09e3c9bc570c014e2fbaf3535e8dd49e
1 /* Gnome Music Player Client (GMPC)
2  * Copyright (C) 2004-2011 Qball Cow <qball@gmpclient.org>
3  * Project homepage: http://gmpclient.org/
4  
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         NUM_STATES
59 }GmpcMetaImageState;
67 class Gmpc:MetaImage from Gtk:Event:Box{
68         private GmpcMetaImageState state = {STATE_EMPTY};
69         private int refresh = FALSE;
70         private gulong status_signal = {0};
71         private gulong connect_signal = {0};
72         private gulong meta_id = {0};
74         private gulong metadata_force_reload = {0};
76         private gchar *image_url = {NULL};
78         private mpd_Song *song = {NULL} destroywith mpd_freeSong;
80         /** Public */
82         public int size = {64};
83         public MetaDataType image_type = {META_ALBUM_ART};
84         public MpdObj *connection= {NULL};
85         public gboolean hide_on_na = {FALSE};
86         public gboolean squared = {TRUE};
87         public gchar *no_cover_icon = {g_strdup("gmpc-no-cover")} destroywith g_free;
88         public gchar *loading_cover_icon = {g_strdup("gmpc-loading-cover")} destroywith g_free;
90         private gulong expose_id = {0};
91         public gboolean scale_up = FALSE;
92         /**
93          * I want fully set/get control,so I don't use property stuff,
94          * is there a way around this?
95          */
96         public gboolean is_visible = {TRUE};
98         property INT image_type 
99                 (nick = "Image type",
100                 blurb = "Type of the image, like artist art",
101                 default_value = META_ALBUM_ART,
102                 export,
103                 link);
104                  
105         property INT size
106                 (nick = "Size",
107                 blurb = "Size of the image",
108                 default_value = 64,
109                 export,
110                 link);
112         property BOOLEAN hide_on_na
113                 (nick = "HideOnNA",
114                 blurb = "Hide the image when not available",
115                 default_value = FALSE,
116                 export,
117                 link);
119     property BOOLEAN scale_up
120         (nick = "Scale image up",
121         blurb = "Scale cover art up",
122         default_value = FALSE,
123         export,
124         link);
126         property BOOLEAN squared
127                 (nick = "Squared",
128                         blurb = "Keep the widget squared",
129                         default_value = TRUE,
130                         link);
131     public void set_no_cover_icon (self, const gchar *name)
132     {
133         if(self->no_cover_icon) {
134             q_free(self->no_cover_icon);
135         }
136         self->no_cover_icon = g_strdup(name);
137     }
138     public void set_loading_cover_icon (self, const gchar *name)
139     {
140         if(self->loading_cover_icon) {
141             q_free(self->loading_cover_icon);
142         }
143         self->loading_cover_icon = g_strdup(name);
144     }
145     public void set_squared (self, const gboolean item)
146     {
147         self->squared = item;
148     }
149     public void set_connection(self, MpdObj *conn)
150     {
151         self->connection = conn;
152         if(conn)
153         {
154             self->_priv->status_signal = g_signal_connect_swapped(G_OBJECT(gmpcconn), 
155                     "status_changed",
156                     G_CALLBACK(self_update_cover),
157                     G_OBJECT(self));
159             self->_priv->connect_signal = g_signal_connect_swapped(G_OBJECT(gmpcconn), 
160                     "connection_changed",
161                     G_CALLBACK(self_connection_changed),
162                     G_OBJECT(self));                                            
163         }
164     }
165     private GtkWidget *image = { (GtkWidget *)gmpc_meta_image_async_new()} ;
166     private GtkWidget *tooltip_image = { (GtkWidget *)gmpc_meta_image_async_new()} ;
168     init (self)
169     {
170             GtkWidget *win = NULL;
171             gtk_container_add(GTK_CONTAINER(self), self->_priv->image);         
172             gtk_container_set_resize_mode(GTK_CONTAINER(self), GTK_RESIZE_IMMEDIATE);
173             gtk_widget_show_all(GTK_WIDGET(self));
175             g_signal_connect_swapped(G_OBJECT(self/*->_priv->image*/), "button-press-event", G_CALLBACK(self_menu_populate_callback), self);
176             self->_priv->meta_id = g_signal_connect(G_OBJECT(gmw), "data-changed", G_CALLBACK(self_meta_callback), self);
177             gtk_widget_add_events(GTK_WIDGET(self->_priv->image), GDK_POINTER_MOTION_MASK);
178             gtk_widget_set_no_show_all(GTK_WIDGET(self),TRUE);
180             win = gtk_window_new(GTK_WINDOW_POPUP); 
181             gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
182             gtk_widget_modify_bg(win, GTK_STATE_NORMAL, &(GTK_WIDGET(self)->style->black));
183             gtk_container_set_border_width(GTK_CONTAINER(win), 6);
184             gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(self->_priv->tooltip_image));
186             gtk_widget_set_tooltip_window(GTK_WIDGET(self), GTK_WINDOW(win));
187             g_signal_connect(G_OBJECT(self), "query-tooltip", G_CALLBACK(self_tooltip_query), win);
188     }
189     private 
190     gboolean tooltip_query(self, gint x, gint y,gboolean keyboard_mode, GtkTooltip *tip, GtkWidget *win)
191     {
192         if(self->_priv->state == STATE_IMAGE)
193         {
194                         gtk_widget_show(self->_priv->tooltip_image);
195                         return TRUE;
196                 }
197         return FALSE;
198     }
200         override (G:Object)
201                 void 
202                 dispose(G:Object *obj)
203                 {
204                         Self *self = GMPC_METAIMAGE(obj); 
205             if(self->_priv->meta_id)
206                         {
207                                 g_signal_handler_disconnect(G_OBJECT(gmw),self->_priv->meta_id);
208                                 self->_priv->meta_id =  0;
209                         }
210             if(self->_priv->metadata_force_reload)
211             {
212                 g_signal_handler_disconnect(G_OBJECT(gmw),self->_priv->metadata_force_reload);
213                 self->_priv->metadata_force_reload =  0;
214             }
215                         if(self->_priv->image_url) {
216                                 q_free(self->_priv->image_url);
217                         }
218                         if(self->_priv->status_signal){
219                                 g_signal_handler_disconnect(G_OBJECT(gmpcconn), self->_priv->status_signal);
220                                 self->_priv->status_signal =0;
221                         }
222                         if(self->_priv->connect_signal){
223                                 g_signal_handler_disconnect(G_OBJECT(gmpcconn), self->_priv->connect_signal);
224                                 self->_priv->connect_signal=0;
225                         }
226                         PARENT_HANDLER(obj);
227                 }
228     private 
229         void 
230         drag_data_recieved (self,
231                 GdkDragContext     *context,
232                 gint                x,
233                 gint                y,
234                 GtkSelectionData   *data,
235                 guint               info,
236                 guint               dnd_time,
237                 GtkWidget          *widget
238                 )
239         {
240             int found = FALSE;
241             if(self->_priv->song)
242             {
243                 if(info < num_drag_targets)
244                 {
245                     gchar **uri =  gtk_selection_data_get_uris(data);   
246                     /* Only one uri is interresting */
247                     if(uri && uri[0])
248                     {
249                         gchar *path = g_filename_from_uri(uri[0], NULL, NULL);
251                         /* try to open it */
252                         if(path && gdk_pixbuf_get_file_info(path, NULL,NULL))
253                                                 {
254                                                         /* Create MetaData object */
255                                                         MetaData* met = meta_data_new();
256                                                         met->type = self->image_type;
257                                                         met->plugin_name = g_strdup("User set");
258                                                         met->content_type = META_DATA_CONTENT_URI;
259                                                         meta_data_set_uri(met, path);
261                                                         meta_data_set_entry(self->_priv->song, met);
262                                                         /* free Metadata object */
263                                                         meta_data_free(met);
264                                                 }
265                         g_free(path);
266                     }
267                     g_strfreev(uri);
268                 }
269             }
271             gtk_drag_finish(context, found, FALSE, dnd_time);
272         }
273         /* hack to make the "delayed" image load when it gets visible"
274          */
275         private 
276         gboolean 
277         expose_event(self, GdkEventExpose *event, gpointer data)
278         {
279             g_signal_handler_disconnect(G_OBJECT(self), self->_priv->expose_id);
280             self->_priv->expose_id = 0;
281             self_update_cover_from_song_delayed_real(self);
282             return FALSE;
283         }
285         public
286         Gmpc:Meta:Image *new_size(int type, int size)
287         {
288             Self *gmi =  GET_NEW;
289             gmi->image_type = type;
290             gmi->size = size;
293             gtk_event_box_set_visible_window(GTK_EVENT_BOX(gmi), FALSE);
294             gtk_drag_dest_set(GTK_WIDGET(gmi),
295                     GTK_DEST_DEFAULT_ALL,
296                     data_image_drag_target, num_drag_targets,
297                     GDK_ACTION_COPY|GDK_ACTION_LINK|GDK_ACTION_DEFAULT|GDK_ACTION_MOVE);
299             g_signal_connect_swapped (G_OBJECT (gmi),"drag-data-received",
300                     GTK_SIGNAL_FUNC (self_drag_data_recieved),gmi);
302             gmi->_priv->metadata_force_reload = g_signal_connect_swapped(G_OBJECT(gmw), "force-reload", G_CALLBACK(self_reload_image), gmi);
304             return gmi;
305         }
306         public 
307                 GtkWidget * new (int type)
308                 {
309                         Self *gmi =  GET_NEW;
310                         gmi->image_type = type;
312             gtk_event_box_set_visible_window(GTK_EVENT_BOX(gmi), FALSE);
313             gtk_drag_dest_set(GTK_WIDGET(gmi),
314                     GTK_DEST_DEFAULT_ALL,
315                 data_image_drag_target, num_drag_targets,
316                 GDK_ACTION_COPY|GDK_ACTION_LINK|GDK_ACTION_DEFAULT|GDK_ACTION_MOVE);
317         g_signal_connect_swapped (G_OBJECT (gmi),"drag-data-received",
318                 GTK_SIGNAL_FUNC (self_drag_data_recieved),gmi);
319             gmi->_priv->metadata_force_reload = g_signal_connect_swapped(G_OBJECT(gmw), "force-reload", G_CALLBACK(self_reload_image), gmi);
320             return (GtkWidget *)gmi;
321                 }
323         public  
324                 void
325                 update_cover(self, MpdObj *mi, ChangedStatusType what, GmpcConnection *gc)
326                 {
328                         if(self->connection && what&(MPD_CST_STATE|MPD_CST_SONGID|MPD_CST_SONGPOS|MPD_CST_PLAYLIST) && self->is_visible)
329                         {
330                                 int state = mpd_player_get_state(self->connection);
331                                 if(state == MPD_PLAYER_STOP || state == MPD_PLAYER_UNKNOWN)
332                                 {
333                     self->_priv->refresh = TRUE;
334                                         self_set_cover_na(self);
335                                 }
336                                 else {
337                                         mpd_Song *song = mpd_playlist_get_current_song(self->connection);
338                                         if(song)
339                                         {
340                         if( self->_priv->refresh == FALSE && 
341                             self->_priv->song && 
342                             self->_priv->song->artist && 
343                             song->artist && 
344                             strcmp(song->artist, self->_priv->song->artist) == 0)
345                         {
346                             /* If we are artist iamge, don't update, same artist */
347                             if(self->image_type == META_ARTIST_ART ) return;
348                             /* If we are album, check if album matches too */
349                             else if(self->image_type == META_ALBUM_ART && 
350                                 self->_priv->song->album && song->album &&
351                                 strcmp(self->_priv->song->album, song->album) == 0){
352                                 return;
353                             }
354                         }
355                                                 self_update_cover_from_song(self, song);
356                                         }
357                                         else
358                                         {
359                                                 self_set_cover_na(self);
360                                         }
361                     self->_priv->refresh = FALSE;
362                                 }
364                         }
365                 }
366         private
367                 void
368                 connection_changed(self,MpdObj *mi, int connect, GmpcConnection *gmpconn)
369                 {
370                         if(!connect)
371                         {
372                                 self_set_cover_na(self);
373                         }
374             else
375             {
376                 if(self->connection)
377                 {
378                     int state = mpd_player_get_state(self->connection);
379                     if(state != MPD_PLAYER_STOP && state != MPD_PLAYER_UNKNOWN)
380                     {
381                         mpd_Song *song = mpd_playlist_get_current_song(self->connection);
382                         if(song){
383                             self_update_cover_from_song(self, song);
384                         }
385                     }
386                 }
388             }
390                 }
392         public 
393                 void
394                 update_cover_from_song(self, const mpd_Song *song)
395                 {
396                         MetaDataResult ret;
397             MetaData *met= NULL;
400                         if(self->_priv->song)
401                                 mpd_freeSong(self->_priv->song);
402             self->_priv->song = NULL;
404                         if(!song)
405                         {
406                                 self_set_cover_na(self);
407                                 return;
408                         }
409             self->_priv->song = mpd_songDup(song);
411                         ret = gmpc_meta_watcher_get_meta_path(gmw,self->_priv->song, self->image_type, &met);
412                         if(ret == META_DATA_FETCHING)
413                         {
414                                 self_set_cover_fetching(self);
415                         }else if (ret == META_DATA_AVAILABLE) {
416                     if(met->content_type == META_DATA_CONTENT_URI) {
417                         const gchar *path = meta_data_get_uri(met);
418                         self_set_cover_from_path(self,path); 
419                                         }else if (met->content_type == META_DATA_CONTENT_RAW) {
420                                                 self_set_cover_raw(self, met->content, met->size);
421                     }else{
422                         self_set_cover_na(self);
423                     }
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 = gmpc_meta_watcher_get_meta_path(gmw,self->_priv->song, self->image_type, &met);
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_URI) {
443                     const gchar *path = meta_data_get_uri(met);
444                     self_set_cover_from_path(self,path); 
445                                 }else if (met->content_type == META_DATA_CONTENT_RAW) {
446                                         self_set_cover_raw(self, met->content, met->size);
447                 } else {
448                     self_set_cover_na(self);
449                 }
450             }
451             else{
452                 self_set_cover_na(self);
453             }
454             if(met)
455             {
456                 meta_data_free(met);
457             }
459             return FALSE;
460         }
461         public 
462                 void
463                 update_cover_from_song_delayed(self, mpd_Song *song)
464         {
465             if(self->_priv->song)
466                 mpd_freeSong(self->_priv->song);
468             gtk_widget_set_size_request(GTK_WIDGET(self), self->size, self->size);
469             self->_priv->song = mpd_songDup(song);
470             /* hack to make it load when it gets visible */
471             self->_priv->expose_id = g_signal_connect(G_OBJECT(self), "expose-event", G_CALLBACK(self_expose_event) , NULL);
472         }
473                 
474         private
475         void
476         meta_callback(GmpcMetaWatcher *gmv, mpd_Song *song, MetaDataType type, MetaDataResult ret, MetaData *met,gpointer data)
477     {
478         Self *self = data;
479         if(!song || !self || !self->_priv || !self->_priv->song)
480             return;
482         /**
483          * Check for fields
484          */
485         if(self->image_type != type)
486             return;
488                 printf("aa: %i  %p - %p\n", self->image_type, self->_priv->song, song);
489         if(!gmpc_meta_watcher_match_data(self->image_type, self->_priv->song, song))
490         {
491             return;
492         }
493                 printf("bb\n");
495         /**
496          * If mpd is stopped before the result is back, set the cover to na, and ignore the result
497          */
498         if(self->connection && mpd_player_get_state(self->connection) == MPD_PLAYER_STOP)
499         {
500             self_set_cover_na(self);
501         }
502         else
503         {
504             if(ret == META_DATA_AVAILABLE) {
505                 if(met->content_type == META_DATA_CONTENT_URI) {
506                     const char *path = meta_data_get_uri(met);
507                     self_set_cover_from_path(self,path); 
508                                 }else if (met->content_type == META_DATA_CONTENT_RAW) {
509                                         self_set_cover_raw(self, met->content, met->size);
510                 }else{
511                     self_set_cover_na(self);
512                     g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Method not implemented: %i", met->content_type);
513                 }
514             } else if (ret == META_DATA_FETCHING) {
515                 self_set_cover_fetching(self);
516             } else {
517                 self_set_cover_na(self);
518             }
519         }
520     }
523         public 
524                 void
525                 set_cover_na(self)
526         {
527             int border = FALSE;
528             GError *error = NULL;
529             GdkPixbuf *pb2 = NULL; 
532             if(self->_priv->state == STATE_NA) {
533                 return;
534             }
535             self->_priv->state = STATE_NA;
536                         gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image));
538             if(self->_priv->image_url)
539             {
540                 q_free(self->_priv->image_url);
541                 self->_priv->image_url = NULL;
542             }
543             if(self->hide_on_na)
544             {           
545                 gtk_widget_hide(GTK_WIDGET(self));
546                 return;
547             }
549             if(cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART){
550                 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "stylized-no-cover", self->size, 0,&error);
551                 border = TRUE;
552                 if(error) {
553                     g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
554                     g_error_free(error);
555                     error = NULL;
556                 }
557             }
558             if(!pb2){
559                 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), self->no_cover_icon, self->size, 0,&error);
560                 if(error) {
561                     g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
562                     g_error_free(error);
563                     error = NULL;
564                 }
565                 border = FALSE;
566             }
568             if(pb2) {
569                 if(self->squared) {
570                     gtk_widget_set_size_request(GTK_WIDGET(self), self->size, self->size);
571                 } else {
572                 //    gtk_widget_set_size_request(GTK_WIDGET(self), gdk_pixbuf_get_width(pb2), gdk_pixbuf_get_height(pb2));
573                 }
574                 gmpc_meta_image_async_set_pixbuf(GMPC_META_IMAGE_ASYNC(self->_priv->image), pb2);
575                 g_object_unref(pb2);
576             } else {
577                 /* If failed to load an image, clear it */
578                 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
579             }
580         }
581         public 
582                 void
583                 set_cover_fetching(self)
584         {
585             int border = FALSE;
586             GError *error = NULL;
587             GdkPixbuf *pb2 = NULL;
589             if(self->_priv->state == STATE_FETCHING) {
590                 return;
591             }
592             self->_priv->state = STATE_FETCHING;
593                         gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image));
594                         if(self->_priv->image_url)
595             {
596                 q_free(self->_priv->image_url);
597                 self->_priv->image_url = NULL;
598             }
599             if(self->hide_on_na)
600             {           
601                 gtk_widget_hide(GTK_WIDGET(self));
602             }
605             if(cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART){
606                 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "stylized-fetching-cover", self->size, 0,&error);
607                 if(error) {
608                     g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
609                     g_error_free(error);
610                     error = NULL;
611                 }
612                 border=TRUE;
613             }
614             if(!pb2){
615                 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), self->loading_cover_icon, self->size, 0,&error);
616                 if(error) {
617                     g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
618                     g_error_free(error);
619                     error = NULL;
620                 }
621                 border = FALSE;
623             }
625             if(self->squared) {
626                 gtk_widget_set_size_request(GTK_WIDGET(self), self->size, self->size);
627             } else {
628 //                gtk_widget_set_size_request(GTK_WIDGET(self), gdk_pixbuf_get_width(pb2), gdk_pixbuf_get_height(pb2));
629                 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
630             }
632             if(pb2) {
633                 gmpc_meta_image_async_set_pixbuf(GMPC_META_IMAGE_ASYNC(self->_priv->image), pb2);
634                 g_object_unref(pb2);
635             } else {
636                 /* If failed to load an image, clear it */
637                 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
638             }
639         }
641     public      
642         void
643         set_cover_raw(self, unsigned char *data, unsigned int size) 
644                 {
645                         self->_priv->state = STATE_IMAGE;
646                         gmpc_meta_image_async_set_from_raw(GMPC_META_IMAGE_ASYNC(self->_priv->image),data, size, self->size,
647                                         ((cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART))?
648                                         GMPC_MODIFICATION_TYPE_CASING:GMPC_MODIFICATION_TYPE_BORDER
650                                         );
651                         if(self->squared) {
652                                 gtk_widget_set_size_request(GTK_WIDGET(self), self->size, self->size);
653                         }
654                         // Update tooltip.
656                         gmpc_meta_image_async_set_from_raw(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image),
657                                         data, size, 350,
658                                         0       
659                                         );
660                 }
661         public  
662         void
663         set_cover_from_path(self, const gchar *path)
664         {
665             self->_priv->state = STATE_IMAGE;
666             
667             if(self->_priv->image_url)
668             {
669                 if(strcmp(path, self->_priv->image_url) == 0) {
670                     return;
671                 }
672                 q_free(self->_priv->image_url);
673                 self->_priv->image_url = NULL;
674             }
675             self->_priv->image_url = g_strdup(path); 
676             gmpc_meta_image_async_set_from_file(GMPC_META_IMAGE_ASYNC(self->_priv->image), self->_priv->image_url, self->size,
677                     ((cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART))?
678                     GMPC_MODIFICATION_TYPE_CASING:GMPC_MODIFICATION_TYPE_BORDER
679                     
680                     );
681             if(self->squared) {
682                 gtk_widget_set_size_request(GTK_WIDGET(self), self->size, self->size);
683             }
684            
685                         // Update tooltip.
686                         gmpc_meta_image_async_set_from_file(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image),
687                                         self->_priv->image_url, 350,
688                                         0       
689                                         );
690             return;
691                 }
693         public 
694                 void
695                 set_is_visible(self, gboolean is_visible)
696                 {
697                         self->is_visible = is_visible;
698                         if(self->is_visible)
699                         {
700                                 if(self->connection)
701                                 {
702                                         self_update_cover(self,self->connection, MPD_CST_STATE, NULL);
703                                 }
704                         } else {
705                                 gtk_widget_hide(GTK_WIDGET(self));
706                         }
707                 }
709         public 
710         void
711         query_refetch(self)
712         {
713                 if(self->_priv->song)
714                 {
715                         MetaDataResult ret;
716                         MetaData *met = NULL;
718                         ret = gmpc_meta_watcher_get_meta_path(gmw,self->_priv->song, self->image_type|META_QUERY_NO_CACHE, &met);
719                         if(ret == META_DATA_FETCHING)
720                         {
721                                 self_set_cover_fetching(self);
722                         }else if (ret == META_DATA_AVAILABLE) {
723                                 if(met->content_type == META_DATA_CONTENT_URI) {
724                                         const gchar *path = meta_data_get_uri(met);
725                                         self_set_cover_from_path(self,path); 
726                                 }else if (met->content_type == META_DATA_CONTENT_RAW) {
727                                         self_set_cover_raw(self, met->content, met->size);
728                                 }else{
729                                         g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Not implemented");
730                                         self_set_cover_na(self);
731                                 }
732                         } else {
733                                 self_set_cover_na(self);
734                         }
735                         if(met)
736                         {
737                                 meta_data_free(met);
738                         }
739                 }
740         }
742     signal last NONE (POINTER)
743     void menu_populate_client(self, GtkMenu *menu)
744     {
746     }
748         private 
749         gboolean        
750         menu_populate_callback(self,GdkEventButton *event,  gpointer data)
751         {
752                 if(self->_priv->song && event->button == 3)
753                 {
754                         GtkWidget *menu = gtk_menu_new();
755                         GtkWidget *item = NULL; 
757             self_menu_populate_client(self,GTK_MENU(menu));
759                         item = gtk_image_menu_item_new_with_label(_("Refetch"));
760                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU));
761                         g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_query_refetch),self);
762                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
764                         item = gtk_image_menu_item_new_with_label(_("Select file"));
765                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU));
766                         g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_select_file),self);
767                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
769                         item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR, NULL);
770                         g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_clear_entry),self);
771                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
773                         item = gtk_image_menu_item_new_with_label(_("Metadata selector"));
774                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
775                         g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_select_metadata_editor),self);
776                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
778                         gtk_widget_show_all(menu);
779                         gtk_menu_popup(GTK_MENU(menu), NULL, NULL,NULL, NULL, event->button, event->time);
780                         return TRUE;
781                 }
782                 return FALSE;
783         }
785         private
786         void
787         clear_entry(self)
788         {
789                 meta_data_clear_entry(self->_priv->song, self->image_type);
790         }
792     private void
793     select_metadata_editor(self)
794     {
795                 gmpc_meta_data_edit_window_new(self->_priv->song,self->image_type);
796     }
798         public
799         void
800         select_file(self)
801         {
802         gchar *p;
803                 mpd_Song *song = mpd_songDup(self->_priv->song);
804                 MetaDataType type = self->image_type;
805                 GtkFileFilter *gff = gtk_file_filter_new();
806                 GtkWidget *fcd = gtk_file_chooser_dialog_new(_("Select File"),NULL,
807                                          GTK_FILE_CHOOSER_ACTION_OPEN,
808                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
809                                       GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
810                                       NULL);
811                 gtk_file_filter_set_name(gff, _("Images"));
812                 gtk_file_filter_add_pixbuf_formats(gff);
813                 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fcd), gff);   
815                 gff = gtk_file_filter_new();
816                 gtk_file_filter_set_name(gff, _("All"));
817                 gtk_file_filter_add_pattern(gff, "*");
818                 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fcd), gff);   
820                 gtk_widget_show_all(fcd);
821              
822         p = cfg_get_single_value_as_string(config, "MetaData", "image-file-chooser"); 
823         if(p) {
824             gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fcd), p);
825             g_free(p);
826         }
827         switch(gtk_dialog_run(GTK_DIALOG(fcd)))
828                 {
829                         case GTK_RESPONSE_ACCEPT:
830                                 {       
831                                         gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fcd));
832                                         {
833                                                 /* Create MetaData object */
834                                                 MetaData* met = meta_data_new();
835                                                 met->type = self->image_type;
836                                                 met->plugin_name = g_strdup("User set");
837                                                 met->content_type = META_DATA_CONTENT_URI;
838                                                 meta_data_set_uri(met, filename);
840                                                 meta_data_set_entry(self->_priv->song, met);
841                                                 /* free Metadata object */
842                                                 meta_data_free(met);
844                                                 cfg_set_single_value_as_string(config, "MetaData", "image-file-chooser", filename); 
845                                         }
847                                 }
848                         default:
849                                 break;
850                 } 
851                 gtk_widget_destroy(fcd);
852                 mpd_freeSong(song);
853         }
855         public
856         void
857         reload_image(self)
858         {
859                 //gmpc_meta_image_async_clear(GMPC_META_IMAGE_ASYNC(self->_priv->image)); 
860         gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
861         switch(self->_priv->state)
862                 {
863                         case STATE_NA:
864                     self->_priv->state = STATE_EMPTY;
865                                         self_set_cover_na(self);
866                                         break;
867                         case STATE_FETCHING:
868                     self->_priv->state = STATE_EMPTY;
869                                         self_set_cover_fetching(self);
870                                         break;
871                         case STATE_IMAGE:
872                     if(self->_priv->image_url)
873                     {
874                         gchar *temp = self->_priv->image_url;
875                         self->_priv->image_url = NULL;
877                         self_set_cover_from_path(self, temp);
878                         g_free(temp);
879                     }
880             /* fix bitching */
881             case STATE_EMPTY:
882             case NUM_STATES:
883                         default:
884                                         break;
885                 }
886         }