changeset 2862:1439cc16d954

Automated merge with ssh://hg.atheme.org//hg/audacious-plugins
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 04 Aug 2008 06:44:55 +0300
parents 2e081c64a529 (diff) bc0f157aeb86 (current diff)
children dd8b44fbfd6f
files
diffstat 19 files changed, 337 insertions(+), 362 deletions(-) [+]
line wrap: on
line diff
--- a/buildsys.mk.in	Wed Jul 30 17:28:41 2008 +0300
+++ b/buildsys.mk.in	Mon Aug 04 06:44:55 2008 +0300
@@ -1,5 +1,5 @@
 #
-#  Copyright (c) 2007, Jonathan Schleifer <js-buildsys@webkeks.org>
+#  Copyright (c) 2007 - 2008, Jonathan Schleifer <js-buildsys@webkeks.org>
 #
 #  https://webkeks.org/hg/buildsys/
 #
@@ -46,7 +46,7 @@
 LIB_LDFLAGS = @LIB_LDFLAGS@
 LIB_PREFIX = @LIB_PREFIX@
 LIB_SUFFIX = @LIB_SUFFIX@
-PLUGIN_DEFNAME = `echo -n ${subst ${PLUGIN_SUFFIX},,${PLUGIN}} | tr [:lower:] [:upper:] | tr -C [:alnum:] _`
+PLUGIN_DEFNAME = `echo ${subst ${PLUGIN_SUFFIX},,${PLUGIN}} | tr [:lower:] [:upper:]`
 PLUGIN_CPPFLAGS = @PLUGIN_CPPFLAGS@ -D${PLUGIN_DEFNAME}_CFGID=\"${subst ${PLUGIN_SUFFIX},,${PLUGIN}}\"
 PLUGIN_CFLAGS = @PLUGIN_CFLAGS@
 PLUGIN_LDFLAGS = @PLUGIN_LDFLAGS@
@@ -75,11 +75,11 @@
 OBJS3 = ${OBJS2:.cxx=.o}
 OBJS4 = ${OBJS3:.d=.o}
 OBJS5 = ${OBJS4:.erl=.beam}
-OBJS += ${OBJS5:.m=.o}
-DEPS += ${OBJS:.o=.dep}
+OBJS6 = ${OBJS5:.m=.o}
+OBJS += ${OBJS6:.xpm=.o}
 
 .SILENT:
-.SUFFIXES: .beam .c .cc .cxx .d .dep .erl .m
+.SUFFIXES: .beam .c .cc .cxx .d .dep .erl .m .xpm
 .PHONY: all subdirs pre-depend depend install install-extra uninstall uninstall-extra clean distclean
 
 all:
@@ -96,17 +96,25 @@
 
 depend: pre-depend ${SRCS}
 	regen=0; \
+	deps=""; \
 	test -f .deps || regen=1; \
-	for i in ${SRCS}; do test $$i -nt .deps && regen=1; done; \
-	if test x"$$regen" = x"1" -a x"${DEPS}" != "x"; then \
+	for i in ${SRCS}; do \
+		case $$i in \
+			*.o) \
+				test $$i -nt .deps && regen=1; \
+				deps="$${deps%.o}.dep $$i"; \
+				;; \
+		esac; \
+	done; \
+	if test x"$$regen" = x"1" -a x"$$deps" != "x"; then \
 		${DEPEND_STATUS}; \
 		rm -f .deps; \
-		if ${MAKE} ${MFLAGS} ${DEPS}; then \
-			cat ${DEPS} >.deps; \
-			rm -f ${DEPS}; \
+		if ${MAKE} ${MFLAGS} $$deps; then \
+			cat $$deps >.deps; \
+			rm -f $$deps; \
 			${DEPEND_OK}; \
 		else \
-			rm -f .deps ${DEPS}; \
+			rm -f .deps $$deps; \
 			${DEPEND_FAILED}; \
 		fi; \
 	fi
@@ -115,6 +123,7 @@
 	${CPP} ${CPPFLAGS} -M $< >$@
 
 .d.dep:
+.xpm.dep:
 
 pre-depend:
 
@@ -198,6 +207,14 @@
 		${COMPILE_FAILED}; \
 	fi
 
+.xpm.o:
+	${COMPILE_STATUS}
+	if ${CC} ${CFLAGS} ${CPPFLAGS} -x c -c -o $@ $<; then \
+		${COMPILE_OK}; \
+	else \
+		${COMPILE_FAILED}; \
+	fi
+
 install: ${LIB} ${STATIC_LIB} ${PLUGIN} ${PROG} install-extra
 	for i in ${SUBDIRS}; do \
 		${DIR_ENTER}; \
--- a/src/alsa/configure.c	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/alsa/configure.c	Mon Aug 04 06:44:55 2008 +0300
@@ -40,24 +40,19 @@
 	alsa_cfg.mixer_card = current_mixer_card;
 	alsa_cfg.mixer_device = GET_CHARS(GTK_COMBO(mixer_devices_combo)->entry);
 
+	alsa_save_config();
 	gtk_widget_destroy(configure_win);
+}
 
-	/* Save configuration */
+void alsa_save_config(void)
+{
 	mcs_handle_t *cfgfile = aud_cfg_db_open();
+
 	aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "buffer_time", alsa_cfg.buffer_time);
 	aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "period_time", alsa_cfg.period_time);
 	aud_cfg_db_set_string(cfgfile,ALSA_CFGID,"pcm_device", alsa_cfg.pcm_device);
 	aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "mixer_card", alsa_cfg.mixer_card);
 	aud_cfg_db_set_string(cfgfile,ALSA_CFGID,"mixer_device", alsa_cfg.mixer_device);
-	aud_cfg_db_close(cfgfile);
-	
-	/* Save volumes */
-	alsa_save_config();
-}
-
-void alsa_save_config(void)
-{
-	mcs_handle_t *cfgfile = aud_cfg_db_open();
 	aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "volume_left", alsa_cfg.vol.left);
 	aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "volume_right", alsa_cfg.vol.right);
 	aud_cfg_db_close(cfgfile);
--- a/src/bluetooth/bluetooth.c	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/bluetooth/bluetooth.c	Mon Aug 04 06:44:55 2008 +0300
@@ -16,6 +16,9 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses>.
  */
 
+#include <glib/gstdio.h>
+#include <errno.h>
+#include <string.h>
 #include "bluetooth.h"
 #include "marshal.h"
 #include "gui.h"
@@ -27,6 +30,7 @@
 gint config = 0;
 gint devices_no = 0;
 GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+static gchar *current_address=NULL;
 static GThread *connect_th;
 void bluetooth_init ( void );
 void bluetooth_cleanup ( void );
@@ -39,7 +43,7 @@
 static void discovery_completed(DBusGProxy *object, gpointer user_data);
 void discover_devices(void);
 void disconnect_dbus_signals(void);
-
+static void show_restart_dialog(void);
 
 GeneralPlugin bluetooth_gp =
 {
@@ -63,7 +67,8 @@
 void bluetooth_cleanup ( void )
 {
     printf("bluetooth: exit\n");
-    if (config ==1 ){
+    if (config ==1 )
+    {
         close_window();
         config =0;
     }
@@ -105,7 +110,8 @@
 
 }
 
-void clean_devices_list(){
+void clean_devices_list()
+{
     g_list_free(audio_devices);
     dbus_g_connection_flush (bus);
     dbus_g_connection_unref(bus);
@@ -136,18 +142,94 @@
 
     dbus_g_object_register_marshaller(marshal_VOID__STRING_UINT_INT, G_TYPE_NONE, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INT, G_TYPE_INVALID);
     run_agents();
-    dbus_g_proxy_call(obj,"CreateBonding",NULL,G_TYPE_STRING,((DeviceData*)(selected_dev->data))->address,G_TYPE_INVALID,G_TYPE_INVALID); 
-     
+    dbus_g_proxy_call(obj,"CreateBonding",NULL,G_TYPE_STRING,current_address,G_TYPE_INVALID,G_TYPE_INVALID); 
+
 }
 void connect_call(void)
 {
- connect_th = g_thread_create((GThreadFunc)connect_call_th,NULL,TRUE,NULL) ; 
- close_call();
- close_window();
- show_scan(1);
+    current_address = g_strdup(((DeviceData*)(selected_dev->data))->address);
+    connect_th = g_thread_create((GThreadFunc)connect_call_th,NULL,TRUE,NULL) ; 
+    close_call();
+    close_window();
+    show_scan(1);
 }
 
 
+void play_call()
+{
+
+    FILE *file;
+    FILE *temp_file;
+    gint prev=0;
+    char line[128];
+    gchar *home;
+    gchar *device_line;
+    gchar *file_name="";
+    gchar *temp_file_name;
+    int ret = EOF+1;
+    home = g_get_home_dir();
+    file_name = g_strconcat(home,"/.asoundrc",NULL);
+    temp_file_name = g_strconcat(home,"/temp_bt",NULL);
+    file = fopen(file_name,"r");
+    temp_file = fopen(temp_file_name,"w");
+    /* hardcoded address TO REMOVE after testing */
+    //   current_address = "00:0D:3C:B1:1C:7A";
+    device_line = g_strdup_printf("device %s\n",current_address);
+    if ( file != NULL )
+    {
+        while ( fgets ( line, sizeof line, file ) != NULL )
+        {
+            if(!(strcmp(line,"pcm.audacious_bt{\n"))){
+                fputs(line,temp_file);
+                fgets ( line, sizeof line, file ); /* type bluetooth */
+                fputs(line,temp_file);
+                fgets ( line, sizeof line, file ); /* device MAC */
+                fputs(device_line,temp_file);
+                prev = 1;
+            } else 
+                fputs(line,temp_file);
+        }
+
+        fclose (file);
+    }
+    if(!prev){
+        fputs("pcm.audacious_bt{\n",temp_file);
+        fputs("type bluetooth\n",temp_file);
+        fputs(device_line,temp_file);
+        fputs("}\n",temp_file);
+        prev = 0;
+    }
+
+    fclose(temp_file);
+    int err = rename(temp_file_name,file_name);
+    printf("rename error : %d",err);
+    perror("zz");
+    g_free(device_line);
+    g_free(file_name);
+    g_free(temp_file_name);
+    mcs_handle_t *cfgfile = aud_cfg_db_open();
+    aud_cfg_db_set_string(cfgfile,"ALSA","pcm_device", "audacious_bt");
+    aud_cfg_db_close(cfgfile);
+
+    printf("play callback\n");
+    close_window();
+    show_restart_dialog();
+
+
+}
+static void show_restart_dialog()
+{
+static GtkWidget *window = NULL;
+ GtkWidget *dialog;
+  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+				   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+				   GTK_MESSAGE_INFO,
+				   GTK_BUTTONS_OK,
+				   "Please restart the player to apply the bluetooth audio settings!");
+   gtk_dialog_run (GTK_DIALOG (dialog));
+   gtk_widget_destroy (dialog);
+}
+
 static void remote_device_found(DBusGProxy *object, char *address, const unsigned int class, const int rssi, gpointer user_data)
 {
     int found_in_list=FALSE; 
--- a/src/bluetooth/bluetooth.h	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/bluetooth/bluetooth.h	Mon Aug 04 06:44:55 2008 +0300
@@ -40,6 +40,7 @@
 
 void refresh_call(void);
 void connect_call(void);
+void play_call(void);
 GList * audio_devices;
 gint discover_finish ;
 DBusGConnection * bus;
--- a/src/bluetooth/scan_gui.c	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/bluetooth/scan_gui.c	Mon Aug 04 06:44:55 2008 +0300
@@ -31,56 +31,58 @@
 static GtkWidget *close_button;
 static gint usage=0;
 
-gpointer progress() {
+gpointer progress()
+{
 
     for(;;){
         if(window){
             gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progress_bar));
         }
         sleep(1);
-       if(usage == 0){
-       if(discover_finish == 2 ) {            
-            if(window){
-                gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_bar),1);
+        if(usage == 0){
+            if(discover_finish == 2 ) {            
+                if(window){
+                    gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_bar),1);
+                }
+                return 0;
             }
-            return 0;
+        }else 
+        {
+            if(bonding_finish == 1 ) {            
+                if(window){
+                    gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_bar),1);
+                    show_pairing_ok();
+                }
+                return 0;
+            }
         }
-       }else 
-           {
-                if(bonding_finish == 1 ) {            
-                    if(window){
-                        gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_bar),1);
-                        show_pairing_ok();
-                    }
-                return 0;
-                }
-           }
     }
     return 0;
 }
 
 void show_pairing_ok()
 {
- if(window ){
+    if(window ){
         gtk_label_set_text(GTK_LABEL(scan_label),_("Bonding finish!"));
     }
 }
 
-void show_no_devices(){
+void show_no_devices()
+{
     if(window ){
         gtk_label_set_text(GTK_LABEL(scan_label),_("No devices found!"));
     }
 }
-void destroy_scan_window(){
+void destroy_scan_window()
+{
     gtk_widget_hide(window);
 }
-void close_window(void){
+void close_window(void)
+{
     printf("scan_gui close callback \n");
     gtk_widget_destroy (window);
     window = NULL;
 }
-
-
 void show_scan(gint use)
 {
     GThread *th1;
@@ -113,9 +115,9 @@
         if(usage == 0){
             scan_label = gtk_label_new_with_mnemonic(_("Scanning..."));
         }else
-            {
-                scan_label = gtk_label_new_with_mnemonic(_("Pairing..."));
-            }
+        {
+            scan_label = gtk_label_new_with_mnemonic(_("Pairing..."));
+        }
 
         gtk_container_add(GTK_CONTAINER(scanbox),scan_label);
 
@@ -129,8 +131,15 @@
         /* I have to modify the rescan button with a play one 
          * and treat the case when the bounding is not ok
          */
-        rescan_buttton = gtk_button_new_with_mnemonic(_("Rescan"));
-        g_signal_connect(rescan_buttton,"clicked",G_CALLBACK (refresh_call),NULL);
+        if(usage == 0){
+            rescan_buttton = gtk_button_new_with_mnemonic(_("Rescan"));
+            g_signal_connect(rescan_buttton,"clicked",G_CALLBACK (refresh_call),NULL);
+        }else{
+            rescan_buttton = gtk_button_new_with_mnemonic(_("Play"));
+            g_signal_connect(rescan_buttton,"clicked",G_CALLBACK (play_call),NULL);
+        }
+
+
 
         close_button = gtk_button_new_with_mnemonic(_("Close"));
         gtk_container_add(GTK_CONTAINER(buttonsbox),rescan_buttton);
--- a/src/bluetooth/scan_gui.h	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/bluetooth/scan_gui.h	Mon Aug 04 06:44:55 2008 +0300
@@ -18,6 +18,12 @@
 
 #include <gtk/gtk.h>
 #include <glib.h>
+#include <alsa/asoundlib.h>
+#include <alsa/pcm_plugin.h>
+#include <audacious/plugin.h>
+#include <audacious/i18n.h>
+
+
 void show_scan(gint use);
 void show_no_devices();
 void destroy_scan_window();
--- a/src/skins/plugin.c	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/skins/plugin.c	Mon Aug 04 06:44:55 2008 +0300
@@ -107,6 +107,7 @@
 gboolean skins_cleanup(void) {
     if (plugin_is_active == TRUE) {
         skins_cfg_save();
+        cleanup_skins();
         skins_free_paths();
         ui_main_evlistener_dissociate();
         ui_playlist_evlistener_dissociate();
@@ -115,8 +116,6 @@
         gtk_widget_destroy(equalizerwin);
         gtk_widget_destroy(playlistwin);
         ui_manager_destroy();
-        skin_destroy(aud_active_skin);
-        aud_active_skin = NULL;
         mainwin = NULL;
         equalizerwin = NULL;
         playlistwin = NULL;
--- a/src/skins/ui_skin.c	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/skins/ui_skin.c	Mon Aug 04 06:44:55 2008 +0300
@@ -1749,42 +1749,25 @@
                 gtk_widget_hide(widget);
                 return;
             }
-            gint x, y;
-            x = -1;
-            y = -1;
 
-            if (gtk_widget_get_parent(widget) == SKINNED_WINDOW(mainwin)->normal) {
-                GList *iter;
-                for (iter = GTK_FIXED (SKINNED_WINDOW(mainwin)->normal)->children; iter; iter = g_list_next (iter)) {
-                     GtkFixedChild *child_data = (GtkFixedChild *) iter->data;
-                     if (child_data->widget == widget) {
-                         x = child_data->x;
-                         y = child_data->y;
-                         break;
-                     }
-                }
+            /* Some skins include SKIN_VOLUME and/or SKIN_BALANCE without knobs */
+            if (pixmap_id == SKIN_VOLUME || pixmap_id == SKIN_BALANCE) {
+                if (ysrc+height > 421 && xsrc+width <= pixmap->width)
+                    return;
+            }
 
-                if (x != -1 && y != -1) {
-                    /* Some skins include SKIN_VOLUME and/or SKIN_BALANCE
-                       without knobs */
-                    if (pixmap_id == SKIN_VOLUME || pixmap_id == SKIN_BALANCE) {
-                        if (ysrc+height > 421 && xsrc+width <= pixmap->width)
-                            return;
-                    }
-                    /* let's copy what's under widget */
-                    gdk_pixbuf_copy_area(skin_get_pixmap(aud_active_skin, SKIN_MAIN)->pixbuf,
-                                         x, y, width, height, pix, xdest, ydest);
+            /* XMMS skins seems to have SKIN_MONOSTEREO with size 58x20 instead of 58x24 */
+            if (pixmap_id == SKIN_MONOSTEREO)
+                height = pixmap->height/2;
 
-                    /* XMMS skins seems to have SKIN_MONOSTEREO with size 58x20 instead of 58x24 */
-                    if (pixmap_id == SKIN_MONOSTEREO)
-                        height = pixmap->height/2;
-                }
-            } else if (gtk_widget_get_parent(widget) == SKINNED_WINDOW(equalizerwin)->normal) {
-                   if (!(pixmap_id == SKIN_EQMAIN && ysrc == 314)) /* equalizer preamp on equalizer graph */
-                         gtk_widget_hide(widget);
-            } else if (gtk_widget_get_parent(widget) == SKINNED_WINDOW(playlistwin)->normal) {
-                   /* I haven't seen any skin with substandard playlist */
-                   gtk_widget_hide(widget);
+            if (gtk_widget_get_parent(widget) == SKINNED_WINDOW(equalizerwin)->normal) {
+                if (!(pixmap_id == SKIN_EQMAIN && ysrc == 314)) /* equalizer preamp on equalizer graph */
+                    gtk_widget_hide(widget);
+            }
+
+            if (gtk_widget_get_parent(widget) == SKINNED_WINDOW(playlistwin)->normal) {
+                /* I haven't seen any skin with substandard playlist */
+                gtk_widget_hide(widget);
             }
         } else
             return;
@@ -2039,16 +2022,19 @@
     aud_active_skin_load(node->path);
 }
 
-
-void ui_skinned_widget_draw(GtkWidget *widget, GdkPixbuf *obj, gint width, gint height, gboolean scale) {
+void ui_skinned_widget_draw_with_coordinates(GtkWidget *widget, GdkPixbuf *obj, gint width, gint height, gint destx, gint desty, gboolean scale) {
     g_return_if_fail(widget != NULL);
     g_return_if_fail(obj != NULL);
 
     if (scale) {
         GdkPixbuf *image = gdk_pixbuf_scale_simple(obj, width * config.scale_factor, height* config.scale_factor, GDK_INTERP_NEAREST);
-        gdk_draw_pixbuf(widget->window, NULL, image, 0, 0, 0, 0, width * config.scale_factor , height * config.scale_factor, GDK_RGB_DITHER_NONE, 0, 0);
+        gdk_draw_pixbuf(widget->window, NULL, image, 0, 0, destx, desty, width * config.scale_factor , height * config.scale_factor, GDK_RGB_DITHER_NONE, 0, 0);
         g_object_unref(image);
     } else {
-        gdk_draw_pixbuf(widget->window, NULL, obj, 0, 0, 0, 0, width, height, GDK_RGB_DITHER_NONE, 0, 0);
+        gdk_draw_pixbuf(widget->window, NULL, obj, 0, 0, destx, desty, width, height, GDK_RGB_DITHER_NONE, 0, 0);
     }
 }
+
+void ui_skinned_widget_draw(GtkWidget *widget, GdkPixbuf *obj, gint width, gint height, gboolean scale) {
+    ui_skinned_widget_draw_with_coordinates(widget, obj, width, height, 0, 0, scale);
+}
--- a/src/skins/ui_skin.h	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/skins/ui_skin.h	Mon Aug 04 06:44:55 2008 +0300
@@ -239,7 +239,7 @@
 
 void skin_set_random_skin(void);
 
-
+void ui_skinned_widget_draw_with_coordinates(GtkWidget *widget, GdkPixbuf *obj, gint width, gint height, gint destx, gint desty, gboolean scale);
 void ui_skinned_widget_draw(GtkWidget *widget, GdkPixbuf *obj, gint width, gint height, gboolean scale);
 
 #endif
--- a/src/skins/ui_skinned_button.c	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/skins/ui_skinned_button.c	Mon Aug 04 06:44:55 2008 +0300
@@ -157,6 +157,8 @@
     priv->move_x = 0;
     priv->move_y = 0;
     button->event_window = NULL;
+
+    GTK_WIDGET_SET_FLAGS (button, GTK_NO_WINDOW);
 }
 
 static void ui_skinned_button_destroy (GtkObject *object) {
@@ -174,38 +176,28 @@
 static void ui_skinned_button_realize (GtkWidget *widget) {
     g_return_if_fail (widget != NULL);
     g_return_if_fail (UI_SKINNED_IS_BUTTON(widget));
+
+    if (GTK_WIDGET_CLASS (parent_class)->realize)
+        (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
+
     UiSkinnedButton *button = UI_SKINNED_BUTTON (widget);
     GdkWindowAttr attributes;
     gint attributes_mask;
 
-    GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
-
     attributes.x = widget->allocation.x;
     attributes.y = widget->allocation.y;
     attributes.width = widget->allocation.width;
     attributes.height = widget->allocation.height;
+    attributes.wclass = GDK_INPUT_ONLY;
     attributes.window_type = GDK_WINDOW_CHILD;
     attributes.event_mask = gtk_widget_get_events(widget);
     attributes.event_mask |= GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK;
 
-    if (button->type == TYPE_SMALL || button->type == TYPE_NOT_SET) {
-        widget->window = gtk_widget_get_parent_window (widget);
-        g_object_ref (widget->window);
-        attributes.wclass = GDK_INPUT_ONLY;
-        attributes_mask = GDK_WA_X | GDK_WA_Y;
-        button->event_window = gdk_window_new (widget->window, &attributes, attributes_mask);
-        GTK_WIDGET_SET_FLAGS (widget, GTK_NO_WINDOW);
-        gdk_window_set_user_data(button->event_window, widget);
-    } else {
-        attributes.visual = gtk_widget_get_visual(widget);
-        attributes.colormap = gtk_widget_get_colormap(widget);
-        attributes.wclass = GDK_INPUT_OUTPUT;
-        attributes.event_mask |= GDK_EXPOSURE_MASK;
-        attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
-        widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask);
-        GTK_WIDGET_UNSET_FLAGS (widget, GTK_NO_WINDOW);
-        gdk_window_set_user_data(widget->window, widget);
-    }
+    attributes.wclass = GDK_INPUT_ONLY;
+    attributes_mask = GDK_WA_X | GDK_WA_Y;
+    button->event_window = gdk_window_new (widget->window, &attributes, attributes_mask);
+
+    gdk_window_set_user_data(button->event_window, widget);
 
     widget->style = gtk_style_attach(widget->style, widget->window);
 }
@@ -289,12 +281,9 @@
     if (button->type == TYPE_SMALL || button->type == TYPE_NOT_SET)
         return FALSE;
 
-    /* paranoia */
-    if (button->event_window != NULL)
-        return FALSE;
-
     GdkPixbuf *obj;
     obj = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, priv->w, priv->h);
+    gdk_pixbuf_fill(obj, 0x00000000); /* fill with alpha */
 
     switch (button->type) {
         case TYPE_PUSH:
@@ -322,7 +311,10 @@
             break;
     }
 
-    ui_skinned_widget_draw(widget, obj, priv->w, priv->h, priv->scaled);
+    ui_skinned_widget_draw_with_coordinates(widget, obj, priv->w, priv->h,
+                                            widget->allocation.x,
+                                            widget->allocation.y,
+                                            priv->scaled);
     g_object_unref(obj);
 
     return FALSE;
--- a/src/skins/ui_skinned_textbox.c	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/skins/ui_skinned_textbox.c	Mon Aug 04 06:44:55 2008 +0300
@@ -69,6 +69,9 @@
 static void ui_skinned_textbox_init               (UiSkinnedTextbox *textbox);
 static void ui_skinned_textbox_destroy            (GtkObject *object);
 static void ui_skinned_textbox_realize            (GtkWidget *widget);
+static void ui_skinned_textbox_unrealize          (GtkWidget *widget);
+static void ui_skinned_textbox_map                (GtkWidget *widget);
+static void ui_skinned_textbox_unmap              (GtkWidget *widget);
 static void ui_skinned_textbox_size_request       (GtkWidget *widget, GtkRequisition *requisition);
 static void ui_skinned_textbox_size_allocate      (GtkWidget *widget, GtkAllocation *allocation);
 static gboolean ui_skinned_textbox_expose         (GtkWidget *widget, GdkEventExpose *event);
@@ -118,6 +121,9 @@
     object_class->destroy = ui_skinned_textbox_destroy;
 
     widget_class->realize = ui_skinned_textbox_realize;
+    widget_class->unrealize = ui_skinned_textbox_unrealize;
+    widget_class->map = ui_skinned_textbox_map;
+    widget_class->unmap = ui_skinned_textbox_unmap;
     widget_class->expose_event = ui_skinned_textbox_expose;
     widget_class->size_request = ui_skinned_textbox_size_request;
     widget_class->size_allocate = ui_skinned_textbox_size_allocate;
@@ -157,6 +163,9 @@
     UiSkinnedTextboxPrivate *priv = UI_SKINNED_TEXTBOX_GET_PRIVATE(textbox);
     priv->move_x = 0;
     priv->move_y = 0;
+
+    textbox->event_window = NULL;
+    GTK_WIDGET_SET_FLAGS (textbox, GTK_NO_WINDOW);
 }
 
 GtkWidget* ui_skinned_textbox_new(GtkWidget *fixed, gint x, gint y, gint w, gboolean allow_scroll, SkinPixmapId si) {
@@ -210,28 +219,64 @@
     g_return_if_fail (widget != NULL);
     g_return_if_fail (UI_SKINNED_IS_TEXTBOX(widget));
 
-    GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
+    if (GTK_WIDGET_CLASS (parent_class)->realize)
+        (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
+
     textbox = UI_SKINNED_TEXTBOX(widget);
 
     attributes.x = widget->allocation.x;
     attributes.y = widget->allocation.y;
     attributes.width = widget->allocation.width;
     attributes.height = widget->allocation.height;
-    attributes.wclass = GDK_INPUT_OUTPUT;
+    attributes.wclass = GDK_INPUT_ONLY;
     attributes.window_type = GDK_WINDOW_CHILD;
     attributes.event_mask = gtk_widget_get_events(widget);
-    attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
+    attributes.event_mask |= GDK_BUTTON_PRESS_MASK |
                              GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
                              GDK_POINTER_MOTION_HINT_MASK;
-    attributes.visual = gtk_widget_get_visual(widget);
-    attributes.colormap = gtk_widget_get_colormap(widget);
 
-    attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
-    widget->window = gdk_window_new(widget->parent->window, &attributes, attributes_mask);
+    attributes_mask = GDK_WA_X | GDK_WA_Y;
+    textbox->event_window = gdk_window_new (widget->window, &attributes, attributes_mask);
 
     widget->style = gtk_style_attach(widget->style, widget->window);
 
-    gdk_window_set_user_data(widget->window, widget);
+    gdk_window_set_user_data(textbox->event_window, widget);
+}
+
+static void ui_skinned_textbox_unrealize(GtkWidget *widget) {
+    UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX(widget);
+
+    if ( textbox->event_window != NULL )
+    {
+      gdk_window_set_user_data( textbox->event_window , NULL );
+      gdk_window_destroy( textbox->event_window );
+      textbox->event_window = NULL;
+    }
+
+    if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+        (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+}
+
+static void ui_skinned_textbox_map (GtkWidget *widget)
+{
+    UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget);
+
+    if (textbox->event_window != NULL)
+      gdk_window_show (textbox->event_window);
+
+    if (GTK_WIDGET_CLASS (parent_class)->map)
+      (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
+}
+
+static void ui_skinned_textbox_unmap (GtkWidget *widget)
+{
+    UiSkinnedTextbox *textbox = UI_SKINNED_TEXTBOX (widget);
+
+    if (textbox->event_window != NULL)
+      gdk_window_hide (textbox->event_window);
+
+    if (GTK_WIDGET_CLASS (parent_class)->unmap)
+      (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
 }
 
 static void ui_skinned_textbox_size_request(GtkWidget *widget, GtkRequisition *requisition) {
@@ -250,7 +295,8 @@
     widget->allocation.x *= (priv->scaled ? config.scale_factor : 1);
     widget->allocation.y *= (priv->scaled ? config.scale_factor : 1);
     if (GTK_WIDGET_REALIZED (widget))
-        gdk_window_move_resize(widget->window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height);
+        if (textbox->event_window)
+            gdk_window_move_resize(textbox->event_window, widget->allocation.x, widget->allocation.y, allocation->width, allocation->height);
 
     if (textbox->x + priv->move_x - widget->allocation.x/(priv->scaled ? config.scale_factor : 1) <3);
         priv->move_x = 0;
@@ -317,7 +363,10 @@
             }
         }
 
-        ui_skinned_widget_draw(widget, obj, textbox->width, textbox->height, priv->scaled);
+        ui_skinned_widget_draw_with_coordinates(widget, obj, textbox->width, textbox->height,
+                                                widget->allocation.x,
+                                                widget->allocation.y,
+                                                priv->scaled);
 
         g_object_unref(obj);
     }
--- a/src/skins/ui_skinned_textbox.h	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/skins/ui_skinned_textbox.h	Mon Aug 04 06:44:55 2008 +0300
@@ -44,6 +44,7 @@
 struct _UiSkinnedTextbox {
     GtkWidget        widget;
 
+    GdkWindow        *event_window;
     gint             x, y, width, height;
     gchar            *text;
 };
--- a/src/streambrowser/gui/streambrowser_win.c	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/streambrowser/gui/streambrowser_win.c	Mon Aug 04 06:44:55 2008 +0300
@@ -19,7 +19,7 @@
 } streamdir_gui_t;
 
 
-void					(* update_function) (streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo, gboolean add_to_playlist);
+void					(* update_function) (streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo);
 
 static GtkWidget*		gtk_label_new_with_icon(gchar *icon_filename, gchar *label_text);
 static GtkWidget*		gtk_streamdir_tree_view_new();
@@ -33,7 +33,7 @@
 static gboolean			on_tree_view_button_pressed(GtkWidget *widget, GdkEventButton *event, gpointer data);
 
 static streamdir_gui_t*	find_streamdir_gui_by_name(gchar *name);
-//static streamdir_gui_t*	find_streamdir_gui_by_tree_view(GtkTreeView *tree_view); todo: remove this
+static streamdir_gui_t*	find_streamdir_gui_by_tree_view(GtkTreeView *tree_view);
 static streamdir_gui_t*	find_streamdir_gui_by_table(GtkTable *table);
 static streamdir_gui_t*	find_streamdir_gui_by_streamdir(streamdir_t *streamdir);
 static gboolean			tree_view_search_equal_func(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer data);
@@ -46,9 +46,6 @@
 static GtkCellRenderer*	cell_renderer_pixbuf;
 static GtkCellRenderer*	cell_renderer_text;
 
-static gboolean			tree_view_button_pressed = FALSE;
-
-
 
 void streambrowser_win_init()
 {
@@ -189,37 +186,13 @@
 		streaminfo = streaminfo_get_by_index(category, i);
 
 		gtk_tree_store_append(store, &new_iter, &iter);
-		gtk_tree_store_set(store, &new_iter, 0, "gtk-media-play", 1, streaminfo->name, 2, streaminfo->current_track, -1);
+		gtk_tree_store_set(store, &new_iter, 0, "gtk-directory", 1, streaminfo->name, 2, streaminfo->current_track, -1);
 	}
 	
 	gtk_tree_path_free(path);
 }
 
-void streambrowser_win_set_streaminfo(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo)
-{
-	streamdir_gui_t *streamdir_gui = find_streamdir_gui_by_name(streamdir->name);
-	if (streamdir_gui == NULL) {
-		failure("gui: streambrowser_win_set_category() called with non-existent streamdir\n");
-		return;
-	}
-	
-	GtkTreeView *tree_view = GTK_TREE_VIEW(streamdir_gui->tree_view);
-	GtkTreeStore *store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)));
-	GtkTreePath *path;
-	GtkTreeIter iter, new_iter;
-	
-	/* find the corresponding streaminfo tree iter */
-	path = gtk_tree_path_new_from_indices(category_get_index(streamdir, category), streaminfo_get_index(category, streaminfo), -1);
-	if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
-		return;
-	
-	/* update the streaminfo*/
-	gtk_tree_store_set(store, &new_iter, 0, "gtk-media-play", 1, streaminfo->name, 2, streaminfo->current_track, -1);
-	
-	gtk_tree_path_free(path);
-}
-
-void streambrowser_win_set_update_function(void (*function) (streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo, gboolean add_to_playlist))
+void streambrowser_win_set_update_function(void (*function) (streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo))
 {
 	update_function = function;
 }
@@ -267,7 +240,7 @@
 		gtk_tree_store_set(store, &iter, 0, "gtk-refresh", 1, temp, 2, streaminfo->current_track, -1);
 	}
 	else {
-		gtk_tree_store_set(store, &iter, 0, "gtk-media-play", 1, streaminfo->name, 2, streaminfo->current_track, -1);
+		gtk_tree_store_set(store, &iter, 0, "gtk-directory", 1, streaminfo->name, 2, streaminfo->current_track, -1);
 	}
 }
 
@@ -357,72 +330,53 @@
 	return TRUE;
 }
 
-
 static gboolean on_tree_view_cursor_changed(GtkTreeView *tree_view, gpointer data)
 {
-	/* only do the refresh if this cursor change occured due to a mouse click */
-	if (!tree_view_button_pressed)
-		return FALSE;
-
-	tree_view_button_pressed = FALSE;
-
 	GtkTreePath *path;
-	GtkTreeViewColumn *focus_column;
+	GtkTreeIter iter;
+	GtkTreeModel *model;
 
-	/* get the currently selected tree view */
-	GtkWidget *table = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
-	streamdir_gui_t *streamdir_gui = find_streamdir_gui_by_table(GTK_TABLE(table));
-	if (streamdir_gui == NULL)
-		return FALSE;
-
-	/* get the currently selected path in the tree */
-	gtk_tree_view_get_cursor(tree_view, &path, &focus_column);
-
-	if (path == NULL || gtk_tree_path_get_depth(path) == 0)
-		return FALSE;
-
+	/* obtain the current category */
+	gtk_tree_view_get_cursor(tree_view, &path, NULL);
+	
+	if (path == NULL)
+		return TRUE;
+	
 	gint *indices = gtk_tree_path_get_indices(path);
-	int category_index = indices[0];
-	streamdir_t *streamdir = streamdir_gui->streamdir;
-	category_t *category = category_get_by_index(streamdir_gui->streamdir, category_index);
-
-	/* if the selected item is a category */
-	if (gtk_tree_path_get_depth(path) == 1) {
-		if (!gtk_tree_view_row_expanded(tree_view, path)) {
-			gtk_entry_set_text(GTK_ENTRY(search_entry), "");
-			update_function(streamdir, category, NULL, FALSE);
-		}
-
+	if (gtk_tree_path_get_depth(path) != 1) {
 		gtk_tree_path_free(path);
-	}
-	/* if the selected item is a streaminfo */
-	else {
-		int streaminfo_index = indices[1];
-
-		gtk_tree_path_free(path);
-
-		/* get the currently selected stream (info) */
-		streaminfo_t *streaminfo = streaminfo_get_by_index(category, streaminfo_index);
-		
-		gtk_entry_set_text(GTK_ENTRY(search_entry), "");
-		update_function(streamdir, category, streaminfo, FALSE);
+		return TRUE;
 	}
 	
-	return FALSE;
+	model = gtk_tree_view_get_model(tree_view);
+	gtk_tree_model_get_iter(model, &iter, path);
+	
+	/* don't fetch a category that has been already fetched */
+	if (gtk_tree_model_iter_has_child(model, &iter)) {
+		gtk_tree_path_free(path);
+		return TRUE;
+	}
+	
+	int category_index = indices[0];
+	
+	gtk_tree_path_free(path);
+	
+	streamdir_gui_t *streamdir_gui = find_streamdir_gui_by_tree_view(tree_view);
+	if (streamdir_gui == NULL)
+		return TRUE;
+	
+	/* issue an update on the current category */	
+	update_function(streamdir_gui->streamdir, category_get_by_index(streamdir_gui->streamdir, category_index), NULL);
+	
+	return TRUE;
 }
 
 static gboolean on_tree_view_button_pressed(GtkWidget *widget, GdkEventButton *event, gpointer data)
 {
 	/* double click adds the currently selected stream to the playlist */
 	if (event->type == GDK_2BUTTON_PRESS) {
-		tree_view_button_pressed = FALSE;
 		on_add_button_clicked(NULL, NULL);
 	}
-	/* single click triggers a refresh of the selected item */
-	else {
-		// todo: separate single from double click somehow
-		tree_view_button_pressed = TRUE;
-	}	
 	
 	return FALSE;
 }
@@ -432,7 +386,6 @@
 	GtkTreePath *path;
 	GtkTreeViewColumn *focus_column;
 
-	/* get the currently selected tree view */
 	GtkWidget *table = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
 	streamdir_gui_t *streamdir_gui = find_streamdir_gui_by_table(GTK_TABLE(table));
 	if (streamdir_gui == NULL)
@@ -440,7 +393,6 @@
 
 	GtkTreeView *tree_view = GTK_TREE_VIEW(streamdir_gui->tree_view);
 	
-	/* get the currently selected path in the tree */
 	gtk_tree_view_get_cursor(tree_view, &path, &focus_column);
 	
 	if (path == NULL)
@@ -462,13 +414,12 @@
 	
 	gtk_tree_path_free(path);
 	
-	/* get the currently selected stream (info) */
 	streamdir_t *streamdir = streamdir_gui->streamdir;
 	category_t *category = category_get_by_index(streamdir_gui->streamdir, category_index);
 	streaminfo_t *streaminfo = streaminfo_get_by_index(category, streaminfo_index);
 	
 	gtk_entry_set_text(GTK_ENTRY(search_entry), "");
-	update_function(streamdir, category, streaminfo, TRUE);
+	update_function(streamdir, category, streaminfo);
 
 	return TRUE;
 }
@@ -519,7 +470,6 @@
 	return NULL;
 }
 
-/* todo: remove this
 static streamdir_gui_t *find_streamdir_gui_by_tree_view(GtkTreeView *tree_view)
 {
 	GList *iterator;
@@ -534,7 +484,6 @@
 	
 	return NULL;
 }
-*/
 
 static streamdir_gui_t *find_streamdir_gui_by_table(GtkTable *table)
 {
--- a/src/streambrowser/gui/streambrowser_win.h	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/streambrowser/gui/streambrowser_win.h	Mon Aug 04 06:44:55 2008 +0300
@@ -12,9 +12,7 @@
 
 void			streambrowser_win_set_streamdir(streamdir_t *streamdir, gchar *icon_filename);
 void			streambrowser_win_set_category(streamdir_t *streamdir, category_t *category);
-void			streambrowser_win_set_streaminfo(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo);
-
-void			streambrowser_win_set_update_function(void (* update_function) (streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo, gboolean add_to_playlist));
+void			streambrowser_win_set_update_function(void (* update_function) (streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo));
 void			streambrowser_win_set_category_state(streamdir_t *streamdir, category_t *category, gboolean fetching);
 void			streambrowser_win_set_streaminfo_state(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo, gboolean fetching);
 
--- a/src/streambrowser/shoutcast.c	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/streambrowser/shoutcast.c	Mon Aug 04 06:44:55 2008 +0300
@@ -27,78 +27,6 @@
 #include "shoutcast.h"
 
 
-gboolean shoutcast_streaminfo_fetch(category_t *category, streaminfo_t *streaminfo)
-{
-	gchar url[DEF_STRING_LEN];
-	g_snprintf(url, DEF_STRING_LEN, SHOUTCAST_CATEGORY_URL, category->name);
-
-	/* generate a valid, temporary filename */
-	char *temp_filename = tempnam(NULL, "aud_sb");
-	if (temp_filename == NULL) {
-		failure("shoutcast: failed to create a temporary file\n");
-		return FALSE;
-	}
-
-	char temp_pathname[DEF_STRING_LEN];
-	sprintf(temp_pathname, "file://%s", temp_filename);
-
-	debug("shoutcast: fetching category file '%s'\n", url);
-	if (!fetch_remote_to_local_file(url, temp_pathname))  {
-		failure("shoutcast: category file '%s' could not be downloaded to '%s'\n", url, temp_pathname);
-		free(temp_filename);
-		return FALSE;
-	}
-	debug("shoutcast: category file '%s' successfuly downloaded to '%s'\n", url, temp_pathname);
-
-	xmlDoc *doc = xmlReadFile(temp_pathname, NULL, 0);
-	if (doc == NULL) {
-		failure("shoutcast: failed to read '%s' category file\n", category->name);
-		free(temp_filename);
-		return FALSE;
-	}
-	
-	xmlNode *root_node = xmlDocGetRootElement(doc);
-	xmlNode *node;
-	
-	root_node = root_node->children;
-
-	for (node = root_node; node != NULL; node = node->next) {
-		if (node->type == XML_ELEMENT_NODE && !strcmp((char *) node->name, "station")) {
-			gchar *streaminfo_name = (gchar*) xmlGetProp(node, (xmlChar *) "name");
-			gchar *streaminfo_id = (gchar*) xmlGetProp(node, (xmlChar *) "id");
-			gchar streaminfo_playlist_url[DEF_STRING_LEN];
-			gchar *streaminfo_current_track = (gchar*) xmlGetProp(node, (xmlChar *) "ct");
-			
-			g_snprintf(streaminfo_playlist_url, DEF_STRING_LEN, SHOUTCAST_STREAMINFO_URL, streaminfo_id);
-			
-			if (strncmp(streaminfo_playlist_url, streaminfo->playlist_url, DEF_STRING_LEN) == 0) {
-				debug("shoutcast: updating stream info for '%s/%d' from '%s'\n", streaminfo_name, streaminfo_id, url);
-
-				strcpy(streaminfo->name, streaminfo_name);
-				strcpy(streaminfo->playlist_url, streaminfo_playlist_url);
-				strcpy(streaminfo->current_track, streaminfo_current_track);
-			
-				xmlFree(streaminfo_name);
-				xmlFree(streaminfo_id);
-				xmlFree(streaminfo_current_track);
-
-				debug("shoutcast: stream info added\n");
-			
-				break;
-			}
-		}
-	}
-	
-	xmlFreeDoc(doc);
-	
-	if (remove(temp_filename) != 0) {
-		failure("shoutcast: cannot remove the temporary file: %s\n", strerror(errno));
-	}
-	free(temp_filename);
-
-	return TRUE;
-}
-
 gboolean shoutcast_category_fetch(category_t *category)
 {
 	gchar url[DEF_STRING_LEN];
@@ -147,7 +75,7 @@
 			
 			g_snprintf(streaminfo_playlist_url, DEF_STRING_LEN, SHOUTCAST_STREAMINFO_URL, streaminfo_id);
 
-			debug("shoutcast: adding stream info for '%s/%d' from '%s'\n", streaminfo_name, streaminfo_id, url);
+			debug("shoutcast: fetching stream info for '%s/%d' from '%s'\n", streaminfo_name, streaminfo_id, url);
 
 			streaminfo_t *streaminfo = streaminfo_new(streaminfo_name, streaminfo_playlist_url, "", streaminfo_current_track);
 			streaminfo_add(category, streaminfo);
--- a/src/streambrowser/shoutcast.h	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/streambrowser/shoutcast.h	Mon Aug 04 06:44:55 2008 +0300
@@ -30,7 +30,6 @@
 #define SHOUTCAST_STREAMINFO_URL	"http://www.shoutcast.com/sbin/shoutcast-playlist.pls?rn=%s&file=filename.pls"
 
 
-gboolean							shoutcast_streaminfo_fetch(category_t *category, streaminfo_t *streaminfo);
 gboolean							shoutcast_category_fetch(category_t *category);
 streamdir_t*						shoutcast_streamdir_fetch();
 
--- a/src/streambrowser/streambrowser.c	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/streambrowser/streambrowser.c	Mon Aug 04 06:44:55 2008 +0300
@@ -34,7 +34,6 @@
     streamdir_t *streamdir;
     category_t *category;
     streaminfo_t *streaminfo;
-    gboolean add_to_playlist;
 } update_thread_data_t;
 
 
@@ -48,7 +47,7 @@
 static void config_load();
 static void config_save();
 
-static void streamdir_update(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo, gboolean add_to_playlist);
+static void streamdir_update(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo);
 static gpointer update_thread_core(gpointer user_data);
 static void streaminfo_add_to_playlist(streaminfo_t *streaminfo);
 static void on_plugin_services_menu_item_click();
@@ -272,13 +271,12 @@
     debug("configuration saved\n");
 }
 
-static void streamdir_update(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo, gboolean add_to_playlist)
+static void streamdir_update(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo)
 {
-    debug("requested streamdir update (streamdir = '%s', category = '%s', streaminfo = '%s', add_to_playlist = %d)\n", 
+    debug("requested streamdir update (streamdir = '%s', category = '%s', streaminfo = '%s')\n", 
           streamdir == NULL ? "" : streamdir->name, 
           category == NULL ? "" : category->name,
-          streaminfo == NULL ? "" : streaminfo->name,
-          add_to_playlist);
+          streaminfo == NULL ? "" : streaminfo->name);
 
     if (g_queue_get_length(update_thread_data_queue) >= MAX_UPDATE_THREADS) {
         debug("another %d streamdir updates are pending, this request will be dropped\n", g_queue_get_length(update_thread_data_queue));
@@ -297,8 +295,7 @@
                 update_thread_data = g_queue_peek_nth(update_thread_data_queue, i);
                 if (update_thread_data->streamdir == streamdir &&
                     update_thread_data->category == category &&
-                    update_thread_data->streaminfo == streaminfo &&
-                    update_thread_data->add_to_playlist == add_to_playlist) {
+                    update_thread_data->streaminfo == streaminfo) {
                     exists = TRUE;
                     break;
                 }
@@ -313,7 +310,6 @@
                 update_thread_data->streamdir = streamdir;
                 update_thread_data->category = category;
                 update_thread_data->streaminfo = streaminfo;
-                update_thread_data->add_to_playlist = add_to_playlist;
  
                 g_queue_push_tail(update_thread_data_queue, update_thread_data);
             }
@@ -330,7 +326,6 @@
             data->streamdir = streamdir;
             data->category = category;
             data->streaminfo = streaminfo;
-            data->add_to_playlist = add_to_playlist;
  
             g_queue_push_tail(update_thread_data_queue, data);
 
@@ -355,50 +350,46 @@
 
 	/* repetitively process the queue elements, until queue is empty */
 	while (data != NULL && g_queue_get_length(update_thread_data_queue) > 0) {
-	    /* update a streaminfo */
+	    /* update a streaminfo - that is - add this streaminfo to playlist */
 		if (data->streaminfo != NULL) {
 	    	gdk_threads_enter();
 			streambrowser_win_set_streaminfo_state(data->streamdir, data->category, data->streaminfo, TRUE);
 	    	gdk_threads_leave();
 
-			if (data->add_to_playlist)
-			    streaminfo_add_to_playlist(data->streaminfo);
-			else {
-				/* shoutcast */
-				if (strncmp(data->streamdir->name, SHOUTCAST_NAME, strlen(SHOUTCAST_NAME)) == 0) {
-				    shoutcast_streaminfo_fetch(data->category, data->streaminfo);
-				}
-				/* xiph */
-				else if (strncmp(data->streamdir->name, XIPH_NAME, strlen(XIPH_NAME)) == 0) {
-					xiph_streaminfo_fetch(data->category, data->streaminfo);
-				}
-			}
+		    streaminfo_add_to_playlist(data->streaminfo);
 
 	        gdk_threads_enter();
-	        if (!data->add_to_playlist)
-		        streambrowser_win_set_streaminfo(data->streamdir, data->category, data->streaminfo);
 			streambrowser_win_set_streaminfo_state(data->streamdir, data->category, data->streaminfo, FALSE);
 	        gdk_threads_leave();
 		}
 		/* update a category */
 		else if (data->category != NULL) {
-	    	gdk_threads_enter();
-			streambrowser_win_set_category_state(data->streamdir, data->category, TRUE);
-	    	gdk_threads_leave();
-	    	
 		    /* shoutcast */
 		    if (strncmp(data->streamdir->name, SHOUTCAST_NAME, strlen(SHOUTCAST_NAME)) == 0) {
+		    	gdk_threads_enter();
+				streambrowser_win_set_category_state(data->streamdir, data->category, TRUE);
+		    	gdk_threads_leave();
+		    	
 		        shoutcast_category_fetch(data->category);
+
+		        gdk_threads_enter();
+		        streambrowser_win_set_category(data->streamdir, data->category);
+				streambrowser_win_set_category_state(data->streamdir, data->category, FALSE);
+		        gdk_threads_leave();
 		    }
 		    /* xiph */
 		    else if (strncmp(data->streamdir->name, XIPH_NAME, strlen(XIPH_NAME)) == 0) {
+		    	gdk_threads_enter();
+				streambrowser_win_set_category_state(data->streamdir, data->category, TRUE);
+		    	gdk_threads_leave();
+		    	
 		        xiph_category_fetch(data->category);
-		    }
 
-	        gdk_threads_enter();
-	        streambrowser_win_set_category(data->streamdir, data->category);
-			streambrowser_win_set_category_state(data->streamdir, data->category, FALSE);
-	        gdk_threads_leave();
+		        gdk_threads_enter();
+		        streambrowser_win_set_category(data->streamdir, data->category);
+				streambrowser_win_set_category_state(data->streamdir, data->category, FALSE);
+		        gdk_threads_leave();
+		    }
 		}
 		/* update a streamdir */
 		else if (data->streamdir != NULL) {
@@ -475,7 +466,7 @@
 	}
 
 	if (strlen(streaminfo->url) > 0) {
-		aud_playlist_add(aud_playlist_get_active(), streaminfo->url);
+	   	aud_playlist_add(aud_playlist_get_active(), streaminfo->url);
 		debug("stream '%s' added\n", streaminfo->url);
 	}
 }
@@ -485,6 +476,6 @@
     debug("on_plugin_services_menu_item_click()\n");
 
     streambrowser_win_show();
-    streamdir_update(NULL, NULL, NULL, FALSE);
+    streamdir_update(NULL, NULL, NULL);
 }
 
--- a/src/streambrowser/xiph.c	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/streambrowser/xiph.c	Mon Aug 04 06:44:55 2008 +0300
@@ -28,12 +28,10 @@
 
 
 typedef struct {
-
 	gchar name[DEF_STRING_LEN];
 	gchar url[DEF_STRING_LEN];
 	gchar current_song[DEF_STRING_LEN];
 	gchar genre[DEF_STRING_LEN];
-
 } xiph_entry_t;
 
 
@@ -41,10 +39,8 @@
 static int xiph_entry_count = 0;
 
 typedef struct {
-
 	gchar *name;
 	gchar *match_string;
-	
 } xiph_category_t;
 
 /* inspired from streamtuner's xiph plugin */
@@ -66,34 +62,14 @@
 };
 
 
+// todo: call refresh_streamdir() more often to refresh the current track
 static void refresh_streamdir();
 	/* returns true if any of the words in string1 is present in string2 */
 static gboolean genre_match(gchar *string1, gchar *string2);
 
-gboolean xiph_streaminfo_fetch(category_t *category, streaminfo_t *streaminfo)
-{
-	int entryno;
-	
-	refresh_streamdir();
-	
-	/* find the corresponding xiph entry */
-	for (entryno = 0; entryno < xiph_entry_count; entryno++) {
-		if (strcmp(xiph_entries[entryno].name, streaminfo->name) == 0) {
-			strcpy(streaminfo->name, xiph_entries[entryno].name);
-			strcpy(streaminfo->url, xiph_entries[entryno].url);
-			strcpy(streaminfo->current_track, xiph_entries[entryno].current_song);
-
-			break;
-		}
-	}
-	
-	return TRUE;
-}
 
 gboolean xiph_category_fetch(category_t *category)
 {
-	refresh_streamdir();
-
 	int entryno, categoryno;
 	int xiph_category_count = sizeof(xiph_categories) / sizeof(xiph_category_t);
 	xiph_category_t *xiph_category = NULL;
@@ -163,10 +139,8 @@
 static void refresh_streamdir()
 {
 	/* free any previously fetched streamdir data */
-	if (xiph_entries != NULL) {
+	if (xiph_entries != NULL)
 		free(xiph_entries);
-		xiph_entries = NULL;
-	}
 	xiph_entry_count = 0;
 
 	debug("xiph: fetching streaming directory file '%s'\n", XIPH_STREAMDIR_URL);
--- a/src/streambrowser/xiph.h	Wed Jul 30 17:28:41 2008 +0300
+++ b/src/streambrowser/xiph.h	Mon Aug 04 06:44:55 2008 +0300
@@ -29,7 +29,6 @@
 #define XIPH_TEMP_FILENAME		"file:///tmp/xiph_yp.xml"
 
 
-gboolean							xiph_streaminfo_fetch(category_t *category, streaminfo_t *streaminfo);
 gboolean							xiph_category_fetch(category_t *category);
 streamdir_t*						xiph_streamdir_fetch();