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.
25 #define LOG_DOMAIN "MetaImage"
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}
53 typedef enum _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;
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;
94 * I want fully set/get control,so I don't use property stuff,
95 * is there a way around this?
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,
108 blurb = "Size of the image",
113 property BOOLEAN hide_on_na
115 blurb = "Hide the image when not available",
116 default_value = FALSE,
120 property BOOLEAN scale_up
121 (nick = "Scale image up",
122 blurb = "Scale cover art up",
123 default_value = FALSE,
127 property BOOLEAN squared
129 blurb = "Keep the widget squared",
130 default_value = TRUE,
132 public void set_no_cover_icon (self, const gchar *name)
134 if(self->no_cover_icon) {
135 q_free(self->no_cover_icon);
137 self->no_cover_icon = g_strdup(name);
139 public void set_loading_cover_icon (self, const gchar *name)
141 if(self->loading_cover_icon) {
142 q_free(self->loading_cover_icon);
144 self->loading_cover_icon = g_strdup(name);
146 public void set_squared (self, const gboolean item)
148 self->squared = item;
150 public void set_connection(self, MpdObj *conn)
152 self->connection = conn;
155 self->_priv->status_signal = g_signal_connect_swapped(G_OBJECT(gmpcconn),
157 G_CALLBACK(self_update_cover),
160 self->_priv->connect_signal = g_signal_connect_swapped(G_OBJECT(gmpcconn),
161 "connection_changed",
162 G_CALLBACK(self_connection_changed),
166 private GtkWidget *image = { (GtkWidget *)gmpc_meta_image_async_new()} ;
167 private GtkWidget *tooltip_image = { (GtkWidget *)gmpc_meta_image_async_new()} ;
171 GtkWidget *win = NULL;
172 gtk_container_add(GTK_CONTAINER(self), self->_priv->image);
174 gtk_widget_show_all(GTK_WIDGET(self));
176 g_signal_connect_swapped(G_OBJECT(self/*->_priv->image*/), "button-press-event",
177 G_CALLBACK(self_menu_populate_callback), self);
178 self->_priv->meta_id = g_signal_connect(G_OBJECT(gmw), "data-changed", G_CALLBACK(self_meta_callback), self);
179 gtk_widget_add_events(GTK_WIDGET(self->_priv->image), GDK_POINTER_MOTION_MASK);
180 gtk_widget_set_no_show_all(GTK_WIDGET(self),TRUE);
182 win = gtk_window_new(GTK_WINDOW_POPUP);
183 gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
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_show(self->_priv->tooltip_image);
188 gtk_widget_set_name(win, "gtk-tooltip");
189 gtk_widget_set_tooltip_window(GTK_WIDGET(self), GTK_WINDOW(win));
190 g_signal_connect(G_OBJECT(self), "query-tooltip", G_CALLBACK(self_tooltip_query), win);
193 gboolean tooltip_query(self, gint x, gint y,gboolean keyboard_mode, GtkTooltip *tip, GtkWidget *win)
195 if(self->_priv->state == STATE_IMAGE)
202 override (Gtk:Widget)
203 GtkSizeRequestMode get_request_mode(self)
206 return GTK_SIZE_REQUEST_CONSTANT_SIZE;
208 return gtk_widget_get_request_mode(self->_priv->image);
210 override (Gtk:Widget)
211 void get_preferred_height(self,int *min_height, int *nat_height)
214 if(min_height != NULL) *min_height = self->size;
215 if(nat_height != NULL) *nat_height = self->size;
217 gtk_widget_get_preferred_height(self->_priv->image, min_height, nat_height);
221 override (Gtk:Widget)
222 void get_preferred_width(self,int *min_width, int *nat_width)
225 if(min_width != NULL) *min_width = self->size;
226 if(nat_width != NULL) *nat_width = self->size;
228 gtk_widget_get_preferred_width(self->_priv->image, min_width, nat_width);
235 dispose(G:Object *obj)
237 Self *self = GMPC_METAIMAGE(obj);
238 if(self->_priv->meta_id)
240 g_signal_handler_disconnect(G_OBJECT(gmw),self->_priv->meta_id);
241 self->_priv->meta_id = 0;
243 if(self->_priv->metadata_force_reload)
245 g_signal_handler_disconnect(G_OBJECT(gmw),self->_priv->metadata_force_reload);
246 self->_priv->metadata_force_reload = 0;
248 if(self->_priv->image_url) {
249 q_free(self->_priv->image_url);
251 if(self->_priv->status_signal){
252 g_signal_handler_disconnect(G_OBJECT(gmpcconn), self->_priv->status_signal);
253 self->_priv->status_signal =0;
255 if(self->_priv->connect_signal){
256 g_signal_handler_disconnect(G_OBJECT(gmpcconn), self->_priv->connect_signal);
257 self->_priv->connect_signal=0;
263 drag_data_recieved (self,
264 GdkDragContext *context,
267 GtkSelectionData *data,
274 if(self->_priv->song)
276 if(info < num_drag_targets)
278 gchar **uri = gtk_selection_data_get_uris(data);
279 /* Only one uri is interresting */
282 gchar *path = g_filename_from_uri(uri[0], NULL, NULL);
285 if(path && gdk_pixbuf_get_file_info(path, NULL,NULL))
287 /* Create MetaData object */
288 MetaData* met = meta_data_new();
289 met->type = self->image_type;
290 met->plugin_name = g_strdup("User set");
291 met->content_type = META_DATA_CONTENT_URI;
292 meta_data_set_uri(met, path);
294 meta_data_set_entry(self->_priv->song, met);
295 /* free Metadata object */
304 gtk_drag_finish(context, found, FALSE, dnd_time);
306 /* hack to make the "delayed" image load when it gets visible"
310 expose_event(self, cairo_t *ct, gpointer data)
312 g_signal_handler_disconnect(G_OBJECT(self), self->_priv->expose_id);
313 self->_priv->expose_id = 0;
314 self_update_cover_from_song_delayed_real(self);
319 Gmpc:Meta:Image *new_size(int type, int size)
322 gmi->image_type = type;
323 gmi->size = size;//pixbuf_cache_get_closest_size(size);
326 gtk_event_box_set_visible_window(GTK_EVENT_BOX(gmi), FALSE);
327 gtk_drag_dest_set(GTK_WIDGET(gmi),
328 GTK_DEST_DEFAULT_ALL,
329 data_image_drag_target, num_drag_targets,
330 GDK_ACTION_COPY|GDK_ACTION_LINK|GDK_ACTION_DEFAULT|GDK_ACTION_MOVE);
332 g_signal_connect_swapped (G_OBJECT (gmi),"drag-data-received",
333 G_CALLBACK (self_drag_data_recieved),gmi);
335 gmi->_priv->metadata_force_reload = g_signal_connect_swapped(G_OBJECT(gmw), "force-reload", G_CALLBACK(self_reload_image), gmi);
340 GtkWidget * new (int type)
343 gmi->image_type = type;
345 gtk_event_box_set_visible_window(GTK_EVENT_BOX(gmi), FALSE);
346 gtk_drag_dest_set(GTK_WIDGET(gmi),
347 GTK_DEST_DEFAULT_ALL,
348 data_image_drag_target, num_drag_targets,
349 GDK_ACTION_COPY|GDK_ACTION_LINK|GDK_ACTION_DEFAULT|GDK_ACTION_MOVE);
350 g_signal_connect_swapped (G_OBJECT (gmi),"drag-data-received",
351 G_CALLBACK (self_drag_data_recieved),gmi);
352 gmi->_priv->metadata_force_reload = g_signal_connect_swapped(G_OBJECT(gmw), "force-reload", G_CALLBACK(self_reload_image), gmi);
353 return (GtkWidget *)gmi;
358 update_cover(self, MpdObj *mi, ChangedStatusType what, GmpcConnection *gc)
361 if(self->connection && what&(MPD_CST_STATE|MPD_CST_SONGID|MPD_CST_SONGPOS|MPD_CST_PLAYLIST) && self->is_visible)
363 int state = mpd_player_get_state(self->connection);
364 if(state == MPD_PLAYER_STOP || state == MPD_PLAYER_UNKNOWN)
366 self->_priv->refresh = TRUE;
367 self_set_cover_na(self);
370 mpd_Song *song = mpd_playlist_get_current_song(self->connection);
373 if( self->_priv->refresh == FALSE &&
375 self->_priv->song->artist &&
377 strcmp(song->artist, self->_priv->song->artist) == 0)
379 /* If we are artist iamge, don't update, same artist */
380 if(self->image_type == META_ARTIST_ART ) return;
381 /* If we are album, check if album matches too */
382 else if(self->image_type == META_ALBUM_ART &&
383 self->_priv->song->album && song->album &&
384 strcmp(self->_priv->song->album, song->album) == 0){
388 self_update_cover_from_song(self, song);
392 self_set_cover_na(self);
394 self->_priv->refresh = FALSE;
401 connection_changed(self,MpdObj *mi, int connect, GmpcConnection *gmpconn)
405 self_set_cover_na(self);
411 int state = mpd_player_get_state(self->connection);
412 if(state != MPD_PLAYER_STOP && state != MPD_PLAYER_UNKNOWN)
414 mpd_Song *song = mpd_playlist_get_current_song(self->connection);
416 self_update_cover_from_song(self, song);
427 update_cover_from_song(self, const mpd_Song *song)
433 if(self->_priv->song)
434 mpd_freeSong(self->_priv->song);
435 self->_priv->song = NULL;
439 self_set_cover_na(self);
442 self->_priv->song = mpd_songDup(song);
444 ret = meta_data_get_path(self->_priv->song, self->image_type, &met, NULL, NULL);
445 if(ret == META_DATA_FETCHING)
447 self_set_cover_fetching(self);
448 }else if (ret == META_DATA_AVAILABLE) {
449 if (met->content_type == META_DATA_CONTENT_RAW) {
450 self_set_cover_raw(self, met->content, met->size,met->md5sum);
452 self_set_cover_na(self);
454 } else if (ret == META_DATA_INVALID_QUERY) {
455 self_set_cover_invalid_query(self);
457 self_set_cover_na(self);
466 update_cover_from_song_delayed_real(self)
469 int ret = meta_data_get_path(self->_priv->song, self->image_type, &met, NULL, NULL);
470 if(ret == META_DATA_FETCHING)
472 self_set_cover_fetching(self);
473 }else if (ret == META_DATA_AVAILABLE) {
474 if (met->content_type == META_DATA_CONTENT_RAW) {
475 self_set_cover_raw(self, met->content, met->size,met->md5sum);
477 self_set_cover_na(self);
479 } else if (ret == META_DATA_INVALID_QUERY) {
480 self_set_cover_invalid_query(self);
482 self_set_cover_na(self);
492 update_cover_from_song_delayed(self, mpd_Song *song)
494 if(self->_priv->song)
495 mpd_freeSong(self->_priv->song);
497 self->_priv->song = mpd_songDup(song);
498 /* hack to make it load when it gets visible */
499 self->_priv->expose_id = g_signal_connect(G_OBJECT(self), "draw", G_CALLBACK(self_expose_event) , NULL);
504 meta_callback(GmpcMetaWatcher *gmv, mpd_Song *song, MetaDataType type, MetaDataResult ret, MetaData *met,gpointer data)
507 if(!song || !self || !self->_priv || !self->_priv->song)
513 if(self->image_type != type)
516 // Compare if callback is about 'our' song.
517 // TODO: optimize, by keeping checksum of current song around?
519 char *ck_a = mpd_song_checksum_type(self->_priv->song, self->image_type);
520 char *ck_b = mpd_song_checksum_type(song, self->image_type);
521 if(ck_a == NULL || ck_b == NULL || strcmp(ck_a, ck_b) != 0) {
531 * If mpd is stopped before the result is back, set the cover to na, and ignore the result
533 if(self->connection && mpd_player_get_state(self->connection) == MPD_PLAYER_STOP)
535 self_set_cover_na(self);
539 if(ret == META_DATA_AVAILABLE) {
540 if (met->content_type == META_DATA_CONTENT_RAW) {
541 self_set_cover_raw(self, met->content, met->size,met->md5sum);
543 self_set_cover_na(self);
544 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Method not implemented: %i", met->content_type);
546 } else if (ret == META_DATA_FETCHING) {
547 self_set_cover_fetching(self);
548 } else if (ret == META_DATA_INVALID_QUERY) {
549 self_set_cover_invalid_query(self);
551 self_set_cover_na(self);
559 set_cover_invalid_query(self)
562 GError *error = NULL;
563 GdkPixbuf *pb2 = NULL;
566 if(self->_priv->state == STATE_INVALID_QUERY) {
569 self->_priv->state = STATE_INVALID_QUERY;
570 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image));
572 if(self->_priv->image_url)
574 q_free(self->_priv->image_url);
575 self->_priv->image_url = NULL;
579 gtk_widget_hide(GTK_WIDGET(self));
583 if(cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART){
584 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "stylized-invalid-tags-cover", self->size, 0,&error);
587 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
593 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), self->no_cover_icon, self->size, 0,&error);
595 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
603 gmpc_meta_image_async_set_pixbuf(GMPC_META_IMAGE_ASYNC(self->_priv->image), pb2);
606 /* If failed to load an image, clear it */
607 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
615 GError *error = NULL;
616 GdkPixbuf *pb2 = NULL;
619 if(self->_priv->state == STATE_NA) {
622 self->_priv->state = STATE_NA;
623 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image));
625 if(self->_priv->image_url)
627 q_free(self->_priv->image_url);
628 self->_priv->image_url = NULL;
632 gtk_widget_hide(GTK_WIDGET(self));
636 if(cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART){
637 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "stylized-no-cover", self->size, 0,&error);
640 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
646 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), self->no_cover_icon, self->size, 0,&error);
648 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
656 gmpc_meta_image_async_set_pixbuf(GMPC_META_IMAGE_ASYNC(self->_priv->image), pb2);
659 /* If failed to load an image, clear it */
660 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
665 set_cover_fetching(self)
668 GError *error = NULL;
669 GdkPixbuf *pb2 = NULL;
671 if(self->_priv->state == STATE_FETCHING) {
674 self->_priv->state = STATE_FETCHING;
675 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image));
676 if(self->_priv->image_url)
678 q_free(self->_priv->image_url);
679 self->_priv->image_url = NULL;
683 gtk_widget_hide(GTK_WIDGET(self));
687 if(cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART){
688 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "stylized-fetching-cover", self->size, 0,&error);
690 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
697 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), self->loading_cover_icon, self->size, 0,&error);
699 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
708 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
712 gmpc_meta_image_async_set_pixbuf(GMPC_META_IMAGE_ASYNC(self->_priv->image), pb2);
715 /* If failed to load an image, clear it */
716 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
722 set_cover_raw(self, unsigned char *data, unsigned int size, unsigned char *md5sum)
724 self->_priv->state = STATE_IMAGE;
725 gmpc_meta_image_async_set_from_raw(GMPC_META_IMAGE_ASYNC(self->_priv->image),data, size, self->size,
726 ((cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART))?
727 GMPC_MODIFICATION_TYPE_CASING:GMPC_MODIFICATION_TYPE_BORDER,
731 if(gtk_widget_get_has_tooltip(GTK_WIDGET(self)))
733 gmpc_meta_image_async_set_from_raw(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image),
743 set_is_visible(self, gboolean is_visible)
745 self->is_visible = is_visible;
750 self_update_cover(self,self->connection, MPD_CST_STATE, NULL);
753 gtk_widget_hide(GTK_WIDGET(self));
761 if(self->_priv->song)
764 MetaData *met = NULL;
766 ret = meta_data_get_path(self->_priv->song, self->image_type|META_QUERY_NO_CACHE, &met, NULL, NULL);
767 if(ret == META_DATA_FETCHING)
769 self_set_cover_fetching(self);
770 }else if (ret == META_DATA_AVAILABLE) {
771 if (met->content_type == META_DATA_CONTENT_RAW) {
772 self_set_cover_raw(self, met->content, met->size,met->md5sum);
774 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Not implemented");
775 self_set_cover_na(self);
777 } else if (ret == META_DATA_INVALID_QUERY) {
778 self_set_cover_invalid_query(self);
780 self_set_cover_na(self);
789 signal last NONE (POINTER)
790 void menu_populate_client(self, GtkMenu *menu)
797 menu_populate_callback(self,GdkEventButton *event, gpointer data)
799 if(self->_priv->song && event->button == 3 && self->_priv->state != STATE_INVALID_QUERY)
801 GtkWidget *menu = gtk_menu_new();
802 GtkWidget *item = NULL;
804 self_menu_populate_client(self,GTK_MENU(menu));
806 item = gtk_image_menu_item_new_with_label(_("Refetch"));
807 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU));
808 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_query_refetch),self);
809 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
811 item = gtk_image_menu_item_new_with_label(_("Select file"));
812 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU));
813 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_select_file),self);
814 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
816 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR, NULL);
817 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_clear_entry),self);
818 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
820 item = gtk_image_menu_item_new_with_label(_("Metadata selector"));
821 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
822 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_select_metadata_editor),self);
823 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
825 gtk_widget_show_all(menu);
826 gtk_menu_popup(GTK_MENU(menu), NULL, NULL,NULL, NULL, event->button, event->time);
829 else if (self->_priv->state == STATE_INVALID_QUERY)
831 playlist3_show_error_message(_("Insufficient tags available to get image."), ERROR_WARNING);
841 meta_data_clear_entry(self->_priv->song, self->image_type);
845 select_metadata_editor(self)
847 gmpc_meta_data_edit_window_new(self->_priv->song,self->image_type);
855 mpd_Song *song = mpd_songDup(self->_priv->song);
856 GtkFileFilter *gff = gtk_file_filter_new();
857 GtkWidget *fcd = gtk_file_chooser_dialog_new(_("Select File"),NULL,
858 GTK_FILE_CHOOSER_ACTION_OPEN,
859 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
860 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
862 gtk_file_filter_set_name(gff, _("Images"));
863 gtk_file_filter_add_pixbuf_formats(gff);
864 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fcd), gff);
866 gff = gtk_file_filter_new();
867 gtk_file_filter_set_name(gff, _("All"));
868 gtk_file_filter_add_pattern(gff, "*");
869 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fcd), gff);
871 gtk_widget_show_all(fcd);
873 p = cfg_get_single_value_as_string(config, "MetaData", "image-file-chooser");
875 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fcd), p);
878 switch(gtk_dialog_run(GTK_DIALOG(fcd)))
880 case GTK_RESPONSE_ACCEPT:
882 gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fcd));
884 /* Create MetaData object */
885 MetaData* met = meta_data_new();
886 met->type = self->image_type;
887 met->plugin_name = g_strdup("User set");
888 met->content_type = META_DATA_CONTENT_URI;
889 meta_data_set_uri(met, filename);
891 meta_data_set_entry(self->_priv->song, met);
892 /* free Metadata object */
895 cfg_set_single_value_as_string(config, "MetaData", "image-file-chooser", filename);
902 gtk_widget_destroy(fcd);
910 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
911 switch(self->_priv->state)
914 self->_priv->state = STATE_EMPTY;
915 self_set_cover_na(self);
918 self->_priv->state = STATE_EMPTY;
919 self_set_cover_fetching(self);
923 self_set_dirty(self);
924 if(self->_priv->song != NULL) {
926 mpd_Song *song = self->_priv->song;
927 self->_priv->song = NULL;
929 self_update_cover_from_song(self,song);
933 self_set_cover_na(self);
944 public void set_dirty(self)
946 self->_priv->state = STATE_EMPTY;