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);
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);
184 // gtk_widget_modify_bg(win, GTK_STATE_NORMAL, &(GTK_WIDGET(self)->style->black));
185 gtk_container_set_border_width(GTK_CONTAINER(win), 6);
186 gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(self->_priv->tooltip_image));
188 gtk_widget_set_tooltip_window(GTK_WIDGET(self), GTK_WINDOW(win));
189 g_signal_connect(G_OBJECT(self), "query-tooltip", G_CALLBACK(self_tooltip_query), win);
192 gboolean tooltip_query(self, gint x, gint y,gboolean keyboard_mode, GtkTooltip *tip, GtkWidget *win)
194 if(self->_priv->state == STATE_IMAGE)
196 gtk_widget_show(self->_priv->tooltip_image);
204 dispose(G:Object *obj)
206 Self *self = GMPC_METAIMAGE(obj);
207 if(self->_priv->meta_id)
209 g_signal_handler_disconnect(G_OBJECT(gmw),self->_priv->meta_id);
210 self->_priv->meta_id = 0;
212 if(self->_priv->metadata_force_reload)
214 g_signal_handler_disconnect(G_OBJECT(gmw),self->_priv->metadata_force_reload);
215 self->_priv->metadata_force_reload = 0;
217 if(self->_priv->image_url) {
218 q_free(self->_priv->image_url);
220 if(self->_priv->status_signal){
221 g_signal_handler_disconnect(G_OBJECT(gmpcconn), self->_priv->status_signal);
222 self->_priv->status_signal =0;
224 if(self->_priv->connect_signal){
225 g_signal_handler_disconnect(G_OBJECT(gmpcconn), self->_priv->connect_signal);
226 self->_priv->connect_signal=0;
232 drag_data_recieved (self,
233 GdkDragContext *context,
236 GtkSelectionData *data,
243 if(self->_priv->song)
245 if(info < num_drag_targets)
247 gchar **uri = gtk_selection_data_get_uris(data);
248 /* Only one uri is interresting */
251 gchar *path = g_filename_from_uri(uri[0], NULL, NULL);
254 if(path && gdk_pixbuf_get_file_info(path, NULL,NULL))
256 /* Create MetaData object */
257 MetaData* met = meta_data_new();
258 met->type = self->image_type;
259 met->plugin_name = g_strdup("User set");
260 met->content_type = META_DATA_CONTENT_URI;
261 meta_data_set_uri(met, path);
263 meta_data_set_entry(self->_priv->song, met);
264 /* free Metadata object */
273 gtk_drag_finish(context, found, FALSE, dnd_time);
275 /* hack to make the "delayed" image load when it gets visible"
279 expose_event(self, cairo_t *ct, gpointer data)
281 g_signal_handler_disconnect(G_OBJECT(self), self->_priv->expose_id);
282 self->_priv->expose_id = 0;
283 self_update_cover_from_song_delayed_real(self);
288 Gmpc:Meta:Image *new_size(int type, int size)
291 gmi->image_type = type;
292 gmi->size = size;//pixbuf_cache_get_closest_size(size);
295 gtk_event_box_set_visible_window(GTK_EVENT_BOX(gmi), FALSE);
296 gtk_drag_dest_set(GTK_WIDGET(gmi),
297 GTK_DEST_DEFAULT_ALL,
298 data_image_drag_target, num_drag_targets,
299 GDK_ACTION_COPY|GDK_ACTION_LINK|GDK_ACTION_DEFAULT|GDK_ACTION_MOVE);
301 g_signal_connect_swapped (G_OBJECT (gmi),"drag-data-received",
302 G_CALLBACK (self_drag_data_recieved),gmi);
304 gmi->_priv->metadata_force_reload = g_signal_connect_swapped(G_OBJECT(gmw), "force-reload", G_CALLBACK(self_reload_image), gmi);
309 GtkWidget * new (int type)
312 gmi->image_type = type;
314 gtk_event_box_set_visible_window(GTK_EVENT_BOX(gmi), FALSE);
315 gtk_drag_dest_set(GTK_WIDGET(gmi),
316 GTK_DEST_DEFAULT_ALL,
317 data_image_drag_target, num_drag_targets,
318 GDK_ACTION_COPY|GDK_ACTION_LINK|GDK_ACTION_DEFAULT|GDK_ACTION_MOVE);
319 g_signal_connect_swapped (G_OBJECT (gmi),"drag-data-received",
320 G_CALLBACK (self_drag_data_recieved),gmi);
321 gmi->_priv->metadata_force_reload = g_signal_connect_swapped(G_OBJECT(gmw), "force-reload", G_CALLBACK(self_reload_image), gmi);
322 return (GtkWidget *)gmi;
327 update_cover(self, MpdObj *mi, ChangedStatusType what, GmpcConnection *gc)
330 if(self->connection && what&(MPD_CST_STATE|MPD_CST_SONGID|MPD_CST_SONGPOS|MPD_CST_PLAYLIST) && self->is_visible)
332 int state = mpd_player_get_state(self->connection);
333 if(state == MPD_PLAYER_STOP || state == MPD_PLAYER_UNKNOWN)
335 self->_priv->refresh = TRUE;
336 self_set_cover_na(self);
339 mpd_Song *song = mpd_playlist_get_current_song(self->connection);
342 if( self->_priv->refresh == FALSE &&
344 self->_priv->song->artist &&
346 strcmp(song->artist, self->_priv->song->artist) == 0)
348 /* If we are artist iamge, don't update, same artist */
349 if(self->image_type == META_ARTIST_ART ) return;
350 /* If we are album, check if album matches too */
351 else if(self->image_type == META_ALBUM_ART &&
352 self->_priv->song->album && song->album &&
353 strcmp(self->_priv->song->album, song->album) == 0){
357 self_update_cover_from_song(self, song);
361 self_set_cover_na(self);
363 self->_priv->refresh = FALSE;
370 connection_changed(self,MpdObj *mi, int connect, GmpcConnection *gmpconn)
374 self_set_cover_na(self);
380 int state = mpd_player_get_state(self->connection);
381 if(state != MPD_PLAYER_STOP && state != MPD_PLAYER_UNKNOWN)
383 mpd_Song *song = mpd_playlist_get_current_song(self->connection);
385 self_update_cover_from_song(self, song);
396 update_cover_from_song(self, const mpd_Song *song)
402 if(self->_priv->song)
403 mpd_freeSong(self->_priv->song);
404 self->_priv->song = NULL;
408 self_set_cover_na(self);
411 self->_priv->song = mpd_songDup(song);
413 ret = meta_data_get_path(self->_priv->song, self->image_type, &met, NULL, NULL);
414 if(ret == META_DATA_FETCHING)
416 self_set_cover_fetching(self);
417 }else if (ret == META_DATA_AVAILABLE) {
418 if (met->content_type == META_DATA_CONTENT_RAW) {
419 self_set_cover_raw(self, met->content, met->size,met->md5sum);
421 self_set_cover_na(self);
423 } else if (ret == META_DATA_INVALID_QUERY) {
424 self_set_cover_invalid_query(self);
426 self_set_cover_na(self);
435 update_cover_from_song_delayed_real(self)
438 int ret = meta_data_get_path(self->_priv->song, self->image_type, &met, NULL, NULL);
439 if(ret == META_DATA_FETCHING)
441 self_set_cover_fetching(self);
442 }else if (ret == META_DATA_AVAILABLE) {
443 if (met->content_type == META_DATA_CONTENT_RAW) {
444 self_set_cover_raw(self, met->content, met->size,met->md5sum);
446 self_set_cover_na(self);
448 } else if (ret == META_DATA_INVALID_QUERY) {
449 self_set_cover_invalid_query(self);
451 self_set_cover_na(self);
461 update_cover_from_song_delayed(self, mpd_Song *song)
463 if(self->_priv->song)
464 mpd_freeSong(self->_priv->song);
466 gtk_widget_set_size_request(GTK_WIDGET(self), self->size, self->size);
467 self->_priv->song = mpd_songDup(song);
468 /* hack to make it load when it gets visible */
469 self->_priv->expose_id = g_signal_connect(G_OBJECT(self), "draw", G_CALLBACK(self_expose_event) , NULL);
474 meta_callback(GmpcMetaWatcher *gmv, mpd_Song *song, MetaDataType type, MetaDataResult ret, MetaData *met,gpointer data)
477 if(!song || !self || !self->_priv || !self->_priv->song)
483 if(self->image_type != type)
486 // Compare if callback is about 'our' song.
487 // TODO: optimize, by keeping checksum of current song around?
489 char *ck_a = mpd_song_checksum_type(self->_priv->song, self->image_type);
490 char *ck_b = mpd_song_checksum_type(song, self->image_type);
491 if(ck_a == NULL || ck_b == NULL || strcmp(ck_a, ck_b) != 0) {
501 * If mpd is stopped before the result is back, set the cover to na, and ignore the result
503 if(self->connection && mpd_player_get_state(self->connection) == MPD_PLAYER_STOP)
505 self_set_cover_na(self);
509 if(ret == META_DATA_AVAILABLE) {
510 if (met->content_type == META_DATA_CONTENT_RAW) {
511 self_set_cover_raw(self, met->content, met->size,met->md5sum);
513 self_set_cover_na(self);
514 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Method not implemented: %i", met->content_type);
516 } else if (ret == META_DATA_FETCHING) {
517 self_set_cover_fetching(self);
518 } else if (ret == META_DATA_INVALID_QUERY) {
519 self_set_cover_invalid_query(self);
521 self_set_cover_na(self);
529 set_cover_invalid_query(self)
532 GError *error = NULL;
533 GdkPixbuf *pb2 = NULL;
536 if(self->_priv->state == STATE_INVALID_QUERY) {
539 self->_priv->state = STATE_INVALID_QUERY;
540 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image));
542 if(self->_priv->image_url)
544 q_free(self->_priv->image_url);
545 self->_priv->image_url = NULL;
549 gtk_widget_hide(GTK_WIDGET(self));
553 if(cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART){
554 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "stylized-invalid-tags-cover", self->size, 0,&error);
557 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
563 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), self->no_cover_icon, self->size, 0,&error);
565 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
574 gtk_widget_set_size_request(GTK_WIDGET(self), self->size, self->size);
576 // gtk_widget_set_size_request(GTK_WIDGET(self), gdk_pixbuf_get_width(pb2), gdk_pixbuf_get_height(pb2));
578 gmpc_meta_image_async_set_pixbuf(GMPC_META_IMAGE_ASYNC(self->_priv->image), pb2);
581 /* If failed to load an image, clear it */
582 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
590 GError *error = NULL;
591 GdkPixbuf *pb2 = NULL;
594 if(self->_priv->state == STATE_NA) {
597 self->_priv->state = STATE_NA;
598 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image));
600 if(self->_priv->image_url)
602 q_free(self->_priv->image_url);
603 self->_priv->image_url = NULL;
607 gtk_widget_hide(GTK_WIDGET(self));
611 if(cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART){
612 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "stylized-no-cover", self->size, 0,&error);
615 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
621 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), self->no_cover_icon, self->size, 0,&error);
623 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
632 gtk_widget_set_size_request(GTK_WIDGET(self), self->size, self->size);
634 // gtk_widget_set_size_request(GTK_WIDGET(self), gdk_pixbuf_get_width(pb2), gdk_pixbuf_get_height(pb2));
636 gmpc_meta_image_async_set_pixbuf(GMPC_META_IMAGE_ASYNC(self->_priv->image), pb2);
639 /* If failed to load an image, clear it */
640 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
645 set_cover_fetching(self)
648 GError *error = NULL;
649 GdkPixbuf *pb2 = NULL;
651 if(self->_priv->state == STATE_FETCHING) {
654 self->_priv->state = STATE_FETCHING;
655 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image));
656 if(self->_priv->image_url)
658 q_free(self->_priv->image_url);
659 self->_priv->image_url = NULL;
663 gtk_widget_hide(GTK_WIDGET(self));
667 if(cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART){
668 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "stylized-fetching-cover", self->size, 0,&error);
670 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
677 pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), self->loading_cover_icon, self->size, 0,&error);
679 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Following error loading stylized-no-cover: %s", error->message);
688 gtk_widget_set_size_request(GTK_WIDGET(self), self->size, self->size);
690 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
694 gmpc_meta_image_async_set_pixbuf(GMPC_META_IMAGE_ASYNC(self->_priv->image), pb2);
697 /* If failed to load an image, clear it */
698 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
704 set_cover_raw(self, unsigned char *data, unsigned int size, unsigned char *md5sum)
706 self->_priv->state = STATE_IMAGE;
707 gmpc_meta_image_async_set_from_raw(GMPC_META_IMAGE_ASYNC(self->_priv->image),data, size, self->size,
708 ((cfg_get_single_value_as_int_with_default(config, "metaimage", "addcase",TRUE) && self->image_type == META_ALBUM_ART))?
709 GMPC_MODIFICATION_TYPE_CASING:GMPC_MODIFICATION_TYPE_BORDER,
713 gtk_widget_set_size_request(GTK_WIDGET(self), self->size, self->size);
716 if(gtk_widget_get_has_tooltip(GTK_WIDGET(self)))
718 gmpc_meta_image_async_set_from_raw(GMPC_META_IMAGE_ASYNC(self->_priv->tooltip_image),
728 set_is_visible(self, gboolean is_visible)
730 self->is_visible = is_visible;
735 self_update_cover(self,self->connection, MPD_CST_STATE, NULL);
738 gtk_widget_hide(GTK_WIDGET(self));
746 if(self->_priv->song)
749 MetaData *met = NULL;
751 ret = meta_data_get_path(self->_priv->song, self->image_type|META_QUERY_NO_CACHE, &met, NULL, NULL);
752 if(ret == META_DATA_FETCHING)
754 self_set_cover_fetching(self);
755 }else if (ret == META_DATA_AVAILABLE) {
756 if (met->content_type == META_DATA_CONTENT_RAW) {
757 self_set_cover_raw(self, met->content, met->size,met->md5sum);
759 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Not implemented");
760 self_set_cover_na(self);
762 } else if (ret == META_DATA_INVALID_QUERY) {
763 self_set_cover_invalid_query(self);
765 self_set_cover_na(self);
774 signal last NONE (POINTER)
775 void menu_populate_client(self, GtkMenu *menu)
782 menu_populate_callback(self,GdkEventButton *event, gpointer data)
784 if(self->_priv->song && event->button == 3 && self->_priv->state != STATE_INVALID_QUERY)
786 GtkWidget *menu = gtk_menu_new();
787 GtkWidget *item = NULL;
789 self_menu_populate_client(self,GTK_MENU(menu));
791 item = gtk_image_menu_item_new_with_label(_("Refetch"));
792 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU));
793 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_query_refetch),self);
794 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
796 item = gtk_image_menu_item_new_with_label(_("Select file"));
797 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU));
798 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_select_file),self);
799 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
801 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR, NULL);
802 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_clear_entry),self);
803 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
805 item = gtk_image_menu_item_new_with_label(_("Metadata selector"));
806 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
807 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_select_metadata_editor),self);
808 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
810 gtk_widget_show_all(menu);
811 gtk_menu_popup(GTK_MENU(menu), NULL, NULL,NULL, NULL, event->button, event->time);
814 else if (self->_priv->state == STATE_INVALID_QUERY)
816 playlist3_show_error_message(_("Insufficient tags available to get image."), ERROR_WARNING);
826 meta_data_clear_entry(self->_priv->song, self->image_type);
830 select_metadata_editor(self)
832 gmpc_meta_data_edit_window_new(self->_priv->song,self->image_type);
840 mpd_Song *song = mpd_songDup(self->_priv->song);
841 GtkFileFilter *gff = gtk_file_filter_new();
842 GtkWidget *fcd = gtk_file_chooser_dialog_new(_("Select File"),NULL,
843 GTK_FILE_CHOOSER_ACTION_OPEN,
844 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
845 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
847 gtk_file_filter_set_name(gff, _("Images"));
848 gtk_file_filter_add_pixbuf_formats(gff);
849 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fcd), gff);
851 gff = gtk_file_filter_new();
852 gtk_file_filter_set_name(gff, _("All"));
853 gtk_file_filter_add_pattern(gff, "*");
854 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fcd), gff);
856 gtk_widget_show_all(fcd);
858 p = cfg_get_single_value_as_string(config, "MetaData", "image-file-chooser");
860 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fcd), p);
863 switch(gtk_dialog_run(GTK_DIALOG(fcd)))
865 case GTK_RESPONSE_ACCEPT:
867 gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fcd));
869 /* Create MetaData object */
870 MetaData* met = meta_data_new();
871 met->type = self->image_type;
872 met->plugin_name = g_strdup("User set");
873 met->content_type = META_DATA_CONTENT_URI;
874 meta_data_set_uri(met, filename);
876 meta_data_set_entry(self->_priv->song, met);
877 /* free Metadata object */
880 cfg_set_single_value_as_string(config, "MetaData", "image-file-chooser", filename);
887 gtk_widget_destroy(fcd);
895 gmpc_meta_image_async_clear_now(GMPC_META_IMAGE_ASYNC(self->_priv->image));
896 switch(self->_priv->state)
899 self->_priv->state = STATE_EMPTY;
900 self_set_cover_na(self);
903 self->_priv->state = STATE_EMPTY;
904 self_set_cover_fetching(self);
908 self_set_dirty(self);
909 if(self->_priv->song != NULL) {
911 mpd_Song *song = self->_priv->song;
912 self->_priv->song = NULL;
914 self_update_cover_from_song(self,song);
918 self_set_cover_na(self);
928 public void set_dirty(self)
930 self->_priv->state = STATE_EMPTY;