Update autogen.sh
[gmpc-lastfmradio.git] / src / plugin.c
blobb2814b519d488f9a15ec4e7d6e85a4db280793ea
1 /* gmpc-lastfmradio (GMPC plugin)
2 * Copyright (C) 2008-2009 Qball Cow <qball@sarine.nl>
3 * Project homepage: http://gmpcwiki.sarine.nl/
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 #include <string.h>
21 #include <gmpc/plugin.h>
22 #include <gmpc/config1.h>
23 #include <gmpc/gmpc-metaimage.h>
24 #include <config.h>
25 #include <gmpc/playlist3-messages.h>
26 #include "lfr_plugin.h"
27 #include "last-fm.h"
30 /* The plugin structure */
31 gmpcPlugin plugin;
33 /* This keeps a reference to the browser in the left row */
34 static GtkTreeRowReference *lfr_ref = NULL;
35 /* The widget that holds the browser view */
36 static GtkWidget *lfr_vbox = NULL;
38 /* Last.FM object */
39 static LastFM *lfm = NULL;
40 /**
41 * Destroy, init and saving
43 static void lfr_init(void)
46 gchar *path = gmpc_plugin_get_data_path(&plugin);
47 gchar *url = g_build_path(G_DIR_SEPARATOR_S,path, "lfr", NULL);
48 debug_printf(DEBUG_WARNING,"Found url: %s\n", url);
49 gtk_icon_theme_append_search_path(gtk_icon_theme_get_default (),url);
50 g_free(url);
51 g_free(path);
53 /* Add plugin path */
54 // gtk_icon_theme_append_search_path(gtk_icon_theme_get_default (),DATA_DIR);
56 g_assert(lfm == NULL);
57 lfm = last_fm_new();
59 static void lfr_destroy(void)
61 /* remove the extra reference */
62 if(lfr_vbox) {g_object_unref(lfr_vbox);lfr_vbox = NULL;}
63 if(lfm) {g_object_unref(lfm);lfm = NULL;}
66 static void lfr_save_myself(void)
68 /* Save the position in the left tree */
69 if (lfr_ref)
71 GtkTreePath *path = gtk_tree_row_reference_get_path(lfr_ref);
72 if(path)
74 gint *indices = gtk_tree_path_get_indices(path);
75 debug_printf(DEBUG_INFO,"Saving myself '%s' to position: %i\n",plugin.name, indices[0]);
76 cfg_set_single_value_as_int(config, CONFIG_NAME,"position",indices[0]);
77 gtk_tree_path_free(path);
82 /**
83 * The actual browser
85 static GtkWidget *connection_warning_box = NULL;
86 static GtkWidget *rest_box = NULL;
87 static GtkWidget *user_label = NULL;
88 static GtkWidget *my_station_combo = NULL;
89 static GtkWidget *progressbar = NULL;
90 static GtkWidget *song_info_box = NULL;
92 static void lfr_browser_conn_changed(LastFM *l, gboolean connected,gpointer data)
94 if(connected) {
95 gchar *str = g_markup_printf_escaped("<span size='xx-large'>%s's Last.FM Dashboard</span>",
96 last_fm_get_username(lfm));
98 gtk_label_set_markup(GTK_LABEL(user_label),str);
99 g_free(str);
100 gtk_widget_show_all(rest_box);
101 gtk_widget_hide(connection_warning_box);
102 }else{
103 gtk_widget_hide(rest_box);
104 gtk_widget_show_all(connection_warning_box);
107 void play_path(const gchar *path);
108 static void lfr_browser_play_stream(LastFM *l, const gchar *stream, gpointer data)
110 play_path(stream);
112 static void lfr_browser_error_callback(LastFM *l,gboolean fatal, const gchar *errormsg, gpointer data)
114 playlist3_show_error_message(errormsg, (fatal)?ERROR_CRITICAL:ERROR_WARNING);
116 guint pb_timeout = 0;
117 static gboolean lfr_browser_pulse(GtkProgressBar *pb)
119 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(pb));
120 return TRUE;
122 static void lfr_browser_processing(LastFM *l, gboolean processing, gpointer data)
124 if(processing)
126 gtk_widget_set_sensitive(rest_box, FALSE);
127 gtk_widget_show(progressbar);
128 if(pb_timeout == 0) {
129 pb_timeout = g_timeout_add(100, (GSourceFunc)lfr_browser_pulse, progressbar);
131 }else{
132 gtk_widget_set_sensitive(rest_box, TRUE);
133 gtk_widget_hide(progressbar);
134 if(pb_timeout)
135 g_source_remove(pb_timeout);
136 pb_timeout = 0;
139 extern GmpcConnection *gmpcconn;
141 static void lfr_browser_song_info(LastFM *l, mpd_Song *song, gpointer data)
143 GtkWidget *label = NULL;
144 GtkWidget *hbox = gtk_table_new(3, 3,FALSE);
145 GtkWidget *temp = gtk_bin_get_child(GTK_BIN(song_info_box));
147 if(cfg_get_single_value_as_int_with_default(config, CONFIG_NAME, "dirty-hack", FALSE) == 0)
149 if(temp)
150 gtk_widget_destroy(temp);
151 if(song)
153 gtk_table_set_row_spacings(GTK_TABLE(hbox), 6);
154 gtk_table_set_col_spacings(GTK_TABLE(hbox), 6);
155 gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
156 /* artist */
157 label = gtk_label_new("");
158 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
159 gtk_label_set_markup(GTK_LABEL(label),"<b>Track</b>");
160 gtk_table_attach(GTK_TABLE(hbox), label,1,2,0,1,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
161 label = gtk_label_new(song->title);
162 gtk_misc_set_alignment(GTK_MISC(label), 0.0,0.5);
163 gtk_table_attach(GTK_TABLE(hbox), label,2,3,0,1,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
165 label = gtk_label_new("");
166 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
167 gtk_label_set_markup(GTK_LABEL(label),"<b>Artist</b>");
168 gtk_table_attach(GTK_TABLE(hbox), label,1,2,1,2,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
169 label = gtk_label_new(song->artist);
170 gtk_misc_set_alignment(GTK_MISC(label), 0.0,0.5);
171 gtk_table_attach(GTK_TABLE(hbox), label,2,3,1,2,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
173 label = gtk_label_new("");
174 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
175 gtk_label_set_markup(GTK_LABEL(label),"<b>Album</b>");
176 gtk_table_attach(GTK_TABLE(hbox), label,1,2,2,3,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
177 label = gtk_label_new(song->album);
178 gtk_misc_set_alignment(GTK_MISC(label), 0.0,0.5);
179 gtk_table_attach(GTK_TABLE(hbox), label,2,3,2,3,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
181 label = gmpc_metaimage_new_size(META_ALBUM_ART,96);
182 gmpc_metaimage_update_cover_from_song(GMPC_METAIMAGE(label), song);
183 gtk_table_attach(GTK_TABLE(hbox), label,0,1,0,3,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
185 gtk_widget_show_all(hbox);
186 gtk_container_add(GTK_CONTAINER(song_info_box), hbox);
189 else if(song && song->artist)
191 mpd_Song *song2 = mpd_playlist_get_current_song(connection);
192 int changed = 0;
193 if(song2->artist){
194 if(song->artist) changed += (strcmp(song2->artist, song->artist) != 0);
195 else changed+=1;
196 g_free(song2->artist);
197 song2->artist = g_strdup(song->artist);
198 }else if(song->artist) {
199 changed+=1;
200 song2->artist = g_strdup(song->artist);
202 if(song2->album){
203 if(song->album) changed += (strcmp(song2->album, song->album) != 0);
204 else changed+=1;
205 g_free(song2->album);
206 song2->album = g_strdup(song->album);
207 }else if (song->album)
209 changed+=1;
210 song2->album = g_strdup(song->album);
212 if(song2->title){
213 if(song->title) changed += (strcmp(song2->title, song->title) != 0);
214 else changed+=1;
215 g_free(song2->title);
216 song2->title = g_strdup(song->title);
217 }else if (song->title)
219 changed+=1;
220 song2->title = g_strdup(song->title);
222 if(changed)
224 gmpc_connection_status_changed(gmpcconn,connection, MPD_CST_SONGID|MPD_CST_SONGPOS);
225 if(temp)
226 gtk_widget_destroy(temp);
227 if(song)
229 gtk_table_set_row_spacings(GTK_TABLE(hbox), 6);
230 gtk_table_set_col_spacings(GTK_TABLE(hbox), 6);
231 gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
232 /* artist */
233 label = gtk_label_new("");
234 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
235 gtk_label_set_markup(GTK_LABEL(label),"<b>Track</b>");
236 gtk_table_attach(GTK_TABLE(hbox), label,1,2,0,1,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
237 label = gtk_label_new(song->title);
238 gtk_misc_set_alignment(GTK_MISC(label), 0.0,0.5);
239 gtk_table_attach(GTK_TABLE(hbox), label,2,3,0,1,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
241 label = gtk_label_new("");
242 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
243 gtk_label_set_markup(GTK_LABEL(label),"<b>Artist</b>");
244 gtk_table_attach(GTK_TABLE(hbox), label,1,2,1,2,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
245 label = gtk_label_new(song->artist);
246 gtk_misc_set_alignment(GTK_MISC(label), 0.0,0.5);
247 gtk_table_attach(GTK_TABLE(hbox), label,2,3,1,2,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
249 label = gtk_label_new("");
250 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
251 gtk_label_set_markup(GTK_LABEL(label),"<b>Album</b>");
252 gtk_table_attach(GTK_TABLE(hbox), label,1,2,2,3,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
253 label = gtk_label_new(song->album);
254 gtk_misc_set_alignment(GTK_MISC(label), 0.0,0.5);
255 gtk_table_attach(GTK_TABLE(hbox), label,2,3,2,3,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
257 label = gmpc_metaimage_new_size(META_ALBUM_ART,96);
258 gmpc_metaimage_update_cover_from_song(GMPC_METAIMAGE(label), song);
259 gtk_table_attach(GTK_TABLE(hbox), label,0,1,0,3,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
261 gtk_widget_show_all(hbox);
262 gtk_container_add(GTK_CONTAINER(song_info_box), hbox);
266 else
268 if(temp)
269 gtk_widget_destroy(temp);
274 gulong lfm_update_timeout = 0;
275 static int lfm_update(LastFM *l)
277 last_fm_get_current_song(lfm);
278 return TRUE;
280 static void lfr_browser_song_info_query(GtkWidget *button, gpointer data)
282 mpd_Song *song = mpd_playlist_get_current_song(connection);
283 if(song && song->file)
285 const gchar *stream_url = last_fm_get_stream_url(lfm);
286 if(stream_url && strcmp(stream_url, song->file) == 0)
288 last_fm_get_current_song(lfm);
289 if(lfm_update_timeout == 0) {
290 if(cfg_get_single_value_as_int_with_default(config, CONFIG_NAME, "dirty-hack", FALSE))
291 lfm_update_timeout = g_timeout_add_seconds(15, G_CALLBACK(lfm_update), lfm);
293 return;
297 lfr_browser_song_info(lfm, NULL, NULL);
298 if(lfm_update_timeout)
300 g_source_remove(lfm_update_timeout);
301 lfm_update_timeout = 0;
304 static void lfr_mpd_status_changed(MpdObj *mi, ChangedStatusType what, void *data)
306 if(what&MPD_CST_SONGPOS || what&MPD_CST_SONGPOS)
308 if(song_info_box)
309 lfr_browser_song_info_query(NULL, NULL);
312 static void lfr_button_clicked(GtkWidget *button, GtkWidget *entry)
314 const gchar *combotext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(my_station_combo));
315 const gchar *text = gtk_entry_get_text(GTK_ENTRY(entry));
316 if(strlen(text) > 0 && combotext)
318 if(strcmp(combotext, "Artist") == 0) {
319 last_fm_play_artist_radio(lfm, text);
320 } else if(strcmp(combotext, "Similar Artist") == 0) {
321 last_fm_play_similar_artist_radio(lfm, text);
322 } else if(strcmp(combotext, "Tag") == 0) {
323 last_fm_play_tag_radio(lfm, text);
324 } else if(strcmp(combotext, "User") == 0) {
325 last_fm_play_user_radio(lfm, text);
326 } else if(strcmp(combotext, "Group") == 0) {
327 last_fm_play_group_radio(lfm, text);
328 } else if(strcmp(combotext, "Neighbourhood") == 0) {
329 last_fm_play_neighbours_radio(lfm, text);
334 static void lfr_button_play_recommendations(GtkWidget *button, gpointer data) {
335 last_fm_play_recommendations(lfm);
337 static void lfr_button_play_my_radio_station(GtkWidget *button, gpointer data) {
338 last_fm_play_user_radio(lfm,NULL);
340 static void lfr_button_play_my_neighbourhood(GtkWidget *button, gpointer data) {
341 last_fm_play_neighbours_radio(lfm, NULL);
343 static void lfr_button_play_my_loved(GtkWidget *button, gpointer data) {
344 last_fm_play_loved_radio (lfm);
347 void preferences_show_pref_window(int plugin_id);
348 static void lfr_open_preferences(GtkWidget *but, gpointer data)
350 preferences_show_pref_window(plugin.id);
353 * Styles
355 static void lfr_background_style_changed(GtkWidget *vbox, GtkStyle *style, GtkWidget *vp)
357 gtk_widget_modify_bg(vp,GTK_STATE_NORMAL, &(GTK_WIDGET(vbox)->style->base[GTK_STATE_NORMAL]));
359 static gboolean lfr_heading_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
362 int width = widget->allocation.width;
363 int height = widget->allocation.height;
365 gtk_paint_flat_box(widget->style,
366 widget->window,
367 GTK_STATE_SELECTED,
368 GTK_SHADOW_NONE,
369 NULL,
370 widget,
371 "cell_odd",
372 0,0,
373 width,height);
375 gtk_paint_focus(widget->style, widget->window,
376 GTK_STATE_NORMAL,
377 NULL,
378 widget,
379 "button",
380 0,0,width,height);
381 return FALSE;
385 static void lfr_browser_init()
387 GtkWidget *hbox;
388 GtkWidget *temp, *temp2;
389 GtkWidget *event = NULL;
390 /* If the widget allready exists, don't try to create it. */
391 if(lfr_vbox != NULL) return;
395 * VBOX <holds everything>
396 * +
397 * - Header
398 * + Frame
399 * + Event box (for bg colour)
400 * - <content>
401 * +
402 * - Warning box
404 lfr_vbox = gtk_vbox_new(FALSE, 0);
405 /* Header */
406 event = gtk_event_box_new();
407 gtk_widget_set_app_paintable(event, TRUE);
408 g_signal_connect(G_OBJECT(event), "expose-event", G_CALLBACK(lfr_heading_expose_event), NULL);
410 hbox = gtk_hbox_new(FALSE, 6);
411 gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
413 temp = gtk_image_new_from_icon_name("lastfm", GTK_ICON_SIZE_DND);
414 gtk_box_pack_start(GTK_BOX(hbox), temp, FALSE, TRUE, 0);
416 temp = gtk_label_new("");
417 gtk_label_set_markup(GTK_LABEL(temp), "<span size='xx-large' weight='bold'>Last.FM Radio</span>");
418 gtk_misc_set_alignment(GTK_MISC(temp), 0.0, 0.5);
419 gtk_box_pack_start(GTK_BOX(hbox), temp, FALSE, TRUE, 0);
420 gtk_container_add(GTK_CONTAINER(event), hbox);
421 gtk_box_pack_start(GTK_BOX(lfr_vbox), event, FALSE, TRUE, 0);
422 gtk_widget_show_all(event);
425 /* Event box for colouring back */
426 temp = gtk_scrolled_window_new(NULL, NULL);
427 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(temp), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
428 event = gtk_event_box_new();
429 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(temp), GTK_SHADOW_IN);
430 gtk_widget_modify_bg(event,GTK_STATE_NORMAL, &(GTK_WIDGET(lfr_vbox)->style->base[GTK_STATE_NORMAL]));
431 g_signal_connect(G_OBJECT(lfr_vbox), "style-set", G_CALLBACK(lfr_background_style_changed), event);
434 rest_box = gtk_vbox_new(FALSE, 6);
435 gtk_container_set_border_width(GTK_CONTAINER(rest_box), 8);
436 gtk_container_add(GTK_CONTAINER(event), rest_box);
437 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(temp), event);
438 gtk_box_pack_start(GTK_BOX(lfr_vbox), temp, TRUE, TRUE, 0);
440 gtk_widget_show(event);
441 gtk_widget_show(temp);
445 /**
446 * Content
448 user_label = gtk_label_new("");
449 gtk_misc_set_alignment(GTK_MISC(user_label), 0.0,0.5);
450 gtk_box_pack_start(GTK_BOX(rest_box), user_label, FALSE,TRUE,12);
453 temp = gtk_label_new("");
454 gtk_label_set_markup(GTK_LABEL(temp),"<span size='x-large'>My Stations</span>");
455 gtk_misc_set_alignment(GTK_MISC(temp), 0.0,0.5);
456 gtk_box_pack_start(GTK_BOX(rest_box), temp, FALSE,TRUE,0);
459 /* My recommendations */
460 hbox = gtk_hbox_new(FALSE, 0);
461 temp = gtk_image_new_from_icon_name("recommended_radio", GTK_ICON_SIZE_MENU);
462 gtk_box_pack_start(GTK_BOX(hbox), temp, FALSE,TRUE,0);
463 temp = gtk_label_new("My Recommendations");
464 temp2 = gtk_button_new();
465 gtk_container_add(GTK_CONTAINER(temp2), temp);
466 gtk_button_set_relief(GTK_BUTTON(temp2), GTK_RELIEF_NONE);
467 gtk_box_pack_start(GTK_BOX(hbox), temp2, FALSE,TRUE,0);
468 gtk_box_pack_start(GTK_BOX(rest_box), hbox, FALSE,TRUE,0);
469 g_signal_connect(G_OBJECT(temp2), "clicked", G_CALLBACK(lfr_button_play_recommendations), NULL);
471 /* My Radio Station*/
472 hbox = gtk_hbox_new(FALSE, 0);
473 temp = gtk_image_new_from_icon_name("personal_radio", GTK_ICON_SIZE_MENU);
474 gtk_box_pack_start(GTK_BOX(hbox), temp, FALSE,TRUE,0);
475 temp = gtk_label_new("My Radio Station");
476 temp2 = gtk_button_new();
477 gtk_container_add(GTK_CONTAINER(temp2), temp);
478 gtk_button_set_relief(GTK_BUTTON(temp2), GTK_RELIEF_NONE);
479 gtk_box_pack_start(GTK_BOX(hbox), temp2, FALSE,TRUE,0);
480 gtk_box_pack_start(GTK_BOX(rest_box), hbox, FALSE,TRUE,0);
481 g_signal_connect(G_OBJECT(temp2), "clicked", G_CALLBACK(lfr_button_play_my_radio_station), NULL);
484 /* My Radio Station*/
485 hbox = gtk_hbox_new(FALSE, 0);
486 temp = gtk_image_new_from_icon_name("my_neighbours", GTK_ICON_SIZE_MENU);
487 gtk_box_pack_start(GTK_BOX(hbox), temp, FALSE,TRUE,0);
488 temp = gtk_label_new("My Neighbourhood");
489 temp2 = gtk_button_new();
490 gtk_container_add(GTK_CONTAINER(temp2), temp);
491 gtk_button_set_relief(GTK_BUTTON(temp2), GTK_RELIEF_NONE);
492 gtk_box_pack_start(GTK_BOX(hbox), temp2, FALSE,TRUE,0);
493 gtk_box_pack_start(GTK_BOX(rest_box), hbox, FALSE,TRUE,0);
494 g_signal_connect(G_OBJECT(temp2), "clicked", G_CALLBACK(lfr_button_play_my_neighbourhood), NULL);
496 /* My Radio Station*/
497 hbox = gtk_hbox_new(FALSE, 0);
498 temp = gtk_image_new_from_icon_name("loved_radio", GTK_ICON_SIZE_MENU);
499 gtk_box_pack_start(GTK_BOX(hbox), temp, FALSE,TRUE,0);
500 temp = gtk_label_new("My Loved Songs");
501 temp2 = gtk_button_new();
502 gtk_container_add(GTK_CONTAINER(temp2), temp);
503 gtk_button_set_relief(GTK_BUTTON(temp2), GTK_RELIEF_NONE);
504 gtk_box_pack_start(GTK_BOX(hbox), temp2, FALSE,TRUE,0);
505 gtk_box_pack_start(GTK_BOX(rest_box), hbox, FALSE,TRUE,0);
506 g_signal_connect(G_OBJECT(temp2), "clicked", G_CALLBACK(lfr_button_play_my_loved), NULL);
509 /* */
510 temp = gtk_label_new("");
511 gtk_label_set_markup(GTK_LABEL(temp),"<span size='x-large'>Create Radio Station</span>");
512 gtk_misc_set_alignment(GTK_MISC(temp), 0.0,0.5);
513 gtk_box_pack_start(GTK_BOX(rest_box), temp, FALSE,TRUE,0);
517 progressbar = gtk_progress_bar_new();
518 gtk_box_pack_start(GTK_BOX(lfr_vbox), progressbar, FALSE,TRUE,0);
520 /* Quick and dirty box */
521 hbox = gtk_hbox_new(FALSE, 6);
523 my_station_combo = temp = gtk_combo_box_new_text();
524 gtk_combo_box_append_text(GTK_COMBO_BOX(temp), "Artist");
525 gtk_combo_box_append_text(GTK_COMBO_BOX(temp), "Similar Artist");
526 gtk_combo_box_append_text(GTK_COMBO_BOX(temp), "Tag");
527 gtk_combo_box_append_text(GTK_COMBO_BOX(temp), "User");
528 gtk_combo_box_append_text(GTK_COMBO_BOX(temp), "Group");
529 gtk_combo_box_append_text(GTK_COMBO_BOX(temp), "Neighbourhood");
530 gtk_combo_box_set_active(GTK_COMBO_BOX(temp), 1);
531 gtk_box_pack_start(GTK_BOX(hbox), temp, FALSE,TRUE,0);
533 temp = gtk_entry_new();
534 gtk_box_pack_start(GTK_BOX(hbox), temp, TRUE,TRUE,0);
535 g_signal_connect(G_OBJECT(temp), "activate", G_CALLBACK(lfr_button_clicked), temp);
536 temp2 = gtk_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);
537 gtk_box_pack_start(GTK_BOX(hbox), temp2, FALSE,TRUE,0);
538 g_signal_connect(G_OBJECT(temp2), "clicked", G_CALLBACK(lfr_button_clicked), temp);
540 gtk_box_pack_start(GTK_BOX(rest_box), hbox, FALSE,TRUE,0);
543 song_info_box = gtk_frame_new(NULL);
544 gtk_box_pack_start(GTK_BOX(rest_box), song_info_box, FALSE,TRUE,0);
546 hbox = gtk_hbox_new(FALSE, 0);
547 temp = gtk_image_new_from_icon_name(GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU);
548 gtk_box_pack_start(GTK_BOX(hbox), temp, FALSE,TRUE,0);
549 temp2 = gtk_button_new_with_label("Query current song info");
550 gtk_button_set_relief(GTK_BUTTON(temp2), GTK_RELIEF_NONE);
551 gtk_box_pack_start(GTK_BOX(hbox), temp2, FALSE,TRUE,0);
552 gtk_box_pack_start(GTK_BOX(rest_box), hbox, FALSE,TRUE,0);
553 g_signal_connect(temp2, "clicked", G_CALLBACK(lfr_browser_song_info_query), NULL);
555 /** Show this box when we are not connected */
556 hbox = gtk_hbox_new(FALSE, 6);
557 connection_warning_box = gtk_frame_new(NULL);
558 gtk_container_add(GTK_CONTAINER(connection_warning_box), hbox);
559 gtk_container_set_border_width(GTK_CONTAINER(hbox), 8);
560 /* Pack it */
561 gtk_box_pack_end(GTK_BOX(lfr_vbox), connection_warning_box, FALSE, TRUE, 0);
562 temp = gtk_image_new_from_stock(GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG);
563 gtk_box_pack_start(GTK_BOX(hbox), temp, FALSE, TRUE, 0);
564 temp = gtk_label_new("You must enter a valid last.FM username and pasword");
565 gtk_misc_set_alignment(GTK_MISC(temp), 0.0,0.5);
566 gtk_box_pack_start(GTK_BOX(hbox), temp, TRUE, TRUE, 0);
567 temp = gtk_button_new_with_label("Open preferences");
568 gtk_box_pack_start(GTK_BOX(hbox), temp, FALSE, TRUE, 0);
569 g_signal_connect(G_OBJECT(temp), "clicked", G_CALLBACK(lfr_open_preferences), NULL);
571 if(last_fm_is_connected(lfm)) {
572 gtk_widget_show_all(rest_box);
573 }else{
574 gtk_widget_show_all(connection_warning_box);
577 gtk_widget_show(lfr_vbox);
578 /* Add extra references so the widget is not destroyed when removed*/
579 g_object_ref(lfr_vbox);
582 g_signal_connect(G_OBJECT(lfm), "connection_changed", G_CALLBACK(lfr_browser_conn_changed), NULL);
583 g_signal_connect(G_OBJECT(lfm), "play_stream", G_CALLBACK(lfr_browser_play_stream), NULL);
584 g_signal_connect(G_OBJECT(lfm), "processing", G_CALLBACK(lfr_browser_processing), NULL);
586 g_signal_connect(G_OBJECT(lfm), "song_info_available", G_CALLBACK(lfr_browser_song_info), NULL);
587 g_signal_connect(G_OBJECT(lfm), "error_callback", G_CALLBACK(lfr_browser_error_callback), NULL);
589 last_fm_connect(lfm);
593 * Browser integration functions
595 /* When the player needs to be added to the right pane */
596 static void lfr_browser_selected(GtkWidget *container)
598 if(lfr_vbox == NULL)
600 lfr_browser_init();
602 gtk_container_add(GTK_CONTAINER(container), lfr_vbox);
603 gtk_widget_show(lfr_vbox);
605 /* When the player needs to be removed from the right pane */
606 static void lfr_browser_unselected(GtkWidget *container)
608 gtk_container_remove(GTK_CONTAINER(container), gtk_bin_get_child(GTK_BIN(container)));
610 /* Add the plugin to the left pane */
611 static void lfr_browser_add(GtkWidget *cat_tree)
613 GtkTreePath *path = NULL;
614 GtkTreeIter iter;
615 GtkListStore *pl3_tree = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(cat_tree));
616 gint pos = cfg_get_single_value_as_int_with_default(config, CONFIG_NAME,"position",20);
618 if(!cfg_get_single_value_as_int_with_default(config, CONFIG_NAME, "enable", TRUE)) return;
620 debug_printf(DEBUG_INFO,"Adding at position: %i", pos);
621 playlist3_insert_browser(&iter, pos);
622 gtk_list_store_set(GTK_LIST_STORE(pl3_tree), &iter,
623 PL3_CAT_TYPE, plugin.id,
624 PL3_CAT_TITLE, "Last.FM Radio",
625 PL3_CAT_INT_ID, "",
626 PL3_CAT_ICON_ID, "lastfm",
627 -1);
629 * Clean up old row reference if it exists
631 if (lfr_ref)
633 gtk_tree_row_reference_free(lfr_ref);
634 lfr_ref = NULL;
637 * create row reference
639 path = gtk_tree_model_get_path(GTK_TREE_MODEL(playlist3_get_category_tree_store()), &iter);
640 if (path)
642 lfr_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(playlist3_get_category_tree_store()), path);
643 gtk_tree_path_free(path);
647 * Enable Set & Get
649 static int lfr_get_enabled()
651 return cfg_get_single_value_as_int_with_default(config, CONFIG_NAME, "enable", TRUE);
653 void pl3_update_go_menu(void);
654 static void lfr_set_enabled(int enabled)
656 cfg_set_single_value_as_int(config, CONFIG_NAME, "enable", enabled);
657 if (enabled)
659 /* Add the browser to the left pane, if there is none to begin with */
660 if(lfr_ref == NULL)
662 lfr_browser_add(GTK_WIDGET(playlist3_get_category_tree_view()));
665 else if (lfr_ref)
667 /* Remove it from the left pane */
668 GtkTreePath *path = gtk_tree_row_reference_get_path(lfr_ref);
669 if (path){
670 GtkTreeIter iter;
671 /* for a save of myself */
672 lfr_save_myself();
673 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(playlist3_get_category_tree_store()), &iter, path)){
674 gtk_list_store_remove(playlist3_get_category_tree_store(), &iter);
676 gtk_tree_path_free(path);
677 gtk_tree_row_reference_free(lfr_ref);
678 lfr_ref = NULL;
681 /* Make sure the go menu is in sync */
682 pl3_update_go_menu();
685 * Preferences
687 gulong id = 0;
688 GtkWidget *username_entry;
689 GtkWidget *password_entry;
690 static void lfr_pref_set_info(GtkWidget *button, gpointer data)
692 const gchar *username = gtk_entry_get_text(GTK_ENTRY(username_entry));
693 const gchar *password = gtk_entry_get_text(GTK_ENTRY(password_entry));
694 if(strlen(username) > 0 && strlen(password) > 0)
696 last_fm_set_login(lfm, username, password);
697 last_fm_connect(lfm);
700 static void lfr_pref_conn_changed(LastFM *l, gboolean connected, GtkWidget *label)
702 gtk_label_set_text(GTK_LABEL(label),connected?"connected":"disconnected");
704 static void lfr_pref_construct(GtkWidget *container)
706 GtkWidget *table = gtk_table_new(3,2,FALSE);
707 GtkWidget *label;
709 gtk_table_set_row_spacings(GTK_TABLE(table),6);
710 gtk_table_set_col_spacings(GTK_TABLE(table),6);
712 label = gtk_label_new("Username");
713 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
714 gtk_table_attach(GTK_TABLE(table), label, 0,1,0,1,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
715 username_entry = gtk_entry_new();
716 if(last_fm_get_username(lfm) != NULL) gtk_entry_set_text(GTK_ENTRY(username_entry),last_fm_get_username(lfm));
717 gtk_table_attach(GTK_TABLE(table), username_entry, 1,2,0,1,GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_SHRINK, 0,0);
720 label = gtk_label_new("Password");
721 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
722 gtk_table_attach(GTK_TABLE(table), label, 0,1,1,2,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
723 password_entry = gtk_entry_new();
724 gtk_entry_set_visibility(GTK_ENTRY(password_entry), FALSE);
725 gtk_table_attach(GTK_TABLE(table), password_entry, 1,2,1,2,GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_SHRINK, 0,0);
728 label = gtk_button_new_with_label("Set information");
729 gtk_table_attach(GTK_TABLE(table), label, 1,2,2,3,GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_SHRINK, 0,0);
730 g_signal_connect(G_OBJECT(label), "clicked", G_CALLBACK(lfr_pref_set_info), NULL);
732 label = gtk_label_new(last_fm_is_connected(lfm)?"connected":"disconnected");
733 gtk_table_attach(GTK_TABLE(table), label, 0,1,2,3,GTK_FILL, GTK_FILL|GTK_SHRINK, 0,0);
735 gtk_container_add(GTK_CONTAINER(container), GTK_WIDGET(GTK_TABLE(table)));
736 gtk_widget_show_all(table);
738 id = g_signal_connect(lfm, "connection_changed",G_CALLBACK(lfr_pref_conn_changed), label);
740 static void lfr_pref_destroy(GtkWidget *container)
742 g_signal_handler_disconnect(lfm, id);
743 id = 0;
744 gtk_container_remove(GTK_CONTAINER(container), gtk_bin_get_child(GTK_BIN(container)));
747 gmpcPrefPlugin lfr_pref = {
748 .construct = lfr_pref_construct,
749 .destroy = lfr_pref_destroy
752 * Structure used by gmpc for integrating the browser
754 gmpcPlBrowserPlugin lfr_gbp = {
755 .add = lfr_browser_add,
756 .selected = lfr_browser_selected,
757 .unselected = lfr_browser_unselected,
761 * This allows gmpc to check the api this plugin is compiled against
763 int plugin_api_version = PLUGIN_API_VERSION;
765 * The plugin structure
767 gmpcPlugin plugin = {
768 .name = "Last.FM Radio",
769 .version = {PLUGIN_MAJOR_VERSION,PLUGIN_MINOR_VERSION,PLUGIN_MICRO_VERSION},
770 .plugin_type = GMPC_PLUGIN_PL_BROWSER,
771 /* Creation and destruction */
772 .init = lfr_init,
773 .destroy = lfr_destroy,
774 .save_yourself = lfr_save_myself,
775 .mpd_status_changed = lfr_mpd_status_changed,
776 /* Browser extention */
777 .browser = &lfr_gbp,
778 /* Preferences pane */
779 .pref = &lfr_pref,
781 /* Get/set enabled */
782 .get_enabled = lfr_get_enabled,
783 .set_enabled = lfr_set_enabled