
#include "gamix.h"

typedef struct e_q_cell e_q_cell_t;
struct e_q_cell {
	snd_mixer_eid_t eid;
	e_q_cell_t *next;
};
typedef struct g_q_cell g_q_cell_t;
struct g_q_cell {
	snd_mixer_gid_t gid;
	g_q_cell_t *next;
};

static char *cmd_name[]={"rebuild","element value","element change",
						 "element route","element add","element remove",
						 "group value","group change","group add",
						 "group remove"
};
static struct {
	e_q_cell_t *q;
	int q_n;
} e_q;
static struct {
	g_q_cell_t *q;
	int q_n;
} g_q;

static void cb_rb(void *);
static void element_callback(void *,int,snd_mixer_eid_t *);
static void cb_gp(void *,int,snd_mixer_gid_t *);
static void search_obj_elem(s_obj_t **,s_element_t **,snd_mixer_eid_t *);
static void s_e_chk(s_element_t *);
static void rmw_elem(s_element_t *);
static int que_e( snd_mixer_eid_t * );
static int que_g( snd_mixer_gid_t * );
static int chk_group( s_mixer_t * );
static void element_free(s_element_t *);
static gboolean chk_eid(s_obj_t *,snd_mixer_eid_t * );
static void ctl_rb_cb(void *);
static void ctl_xsw_cb(void *,int,int,int,int,snd_switch_list_item_t *);
extern GtkWidget *main_vbox;
extern GtkWidget *mixer_container;

static snd_mixer_callbacks_t cb_mix={
	NULL,
	cb_rb,
	element_callback,
	cb_gp
};
static snd_ctl_callbacks_t cb_ctl={
	NULL,
	ctl_rb_cb,
	ctl_xsw_cb
};

static void cb_rb(void *pd ) {
#ifdef DISP_DEBUG
	printf("cb rb hoe\n");
#endif
}

static void element_callback(void *pd,int cmd,snd_mixer_eid_t *eid) {
	//int i,j;
	gint ccc;
	//s_group_t *group;
	s_element_t *e;
	//s_eelements_t *ee;
	s_mixer_t *mixer=(s_mixer_t *)pd;
	s_obj_t *obj=mixer->obj;

	if( !is_etype(eid->type) ) return;

	search_obj_elem(&obj,&e,eid);
	switch( cmd ) {
	case SND_MIXER_READ_ELEMENT_VALUE:
		if( obj == NULL || e == NULL ) break;
		snd_mixer_element_read(mixer->handle,&e->e);
		if( obj->enabled ) {
			ccc=obj->chain;
			obj->chain=FALSE;
			s_e_chk(e);
			obj->chain=ccc;
		}
		return;
		break;
	case SND_MIXER_READ_ELEMENT_REMOVE:
		if( obj == NULL || e == NULL ) break;
		if( obj->enabled ) rmw_elem(e);
		return;
		break;
	case SND_MIXER_READ_ELEMENT_ADD:
		if( obj && e ) {
			snd_mixer_element_read(mixer->handle,&e->e);
			return;
		} else {
			if( que_e(eid) == 0 ) return;
		}
		break;
	case SND_MIXER_READ_ELEMENT_CHANGE:
	case SND_MIXER_READ_ELEMENT_ROUTE:
	default:
		printf("eb el cmd %s eid '%s',%d,%d\n",cmd_name[cmd],eid->name,eid->index,eid->type);
		return;
	}

#ifdef DISP_DEBUG
	printf("cb_el cmd %s %s %d %d\n",cmd_name[cmd],eid->name,eid->index,
		   eid->type);
#endif
}

static void search_obj_elem( s_obj_t **objs,s_element_t **e_r,
							 snd_mixer_eid_t *eid) {
	s_element_t *e;
	s_eelements_t *ee;
	s_group_t *group;
	s_obj_t *obj;
	int j;

	for( obj=*objs ; obj != NULL ; obj=obj->next ) {
		if( obj->e ) {
			ee=obj->e;
			if( strcmp(ee->e.e.eid.name,eid->name)==0 &&
				ee->e.e.eid.index==eid->index ) {
				*objs=obj;
				*e_r=&ee->e;
				return;
			}
		}
		if( obj->g ) {
			group=obj->g;
			for( j=0 ; j<group->g.elements ; j++ ) {
				e=&group->e[j];
				if( strcmp(e->e.eid.name,eid->name) == 0 &&
					e->e.eid.index == eid->index && e->e.eid.type != 0 ) {
					*objs=obj;
					*e_r=e;
					return;
				}
			}
		}
	}
	*objs=NULL;
	*e_r=NULL;
}

static int que_e(snd_mixer_eid_t *eid ) {
	e_q_cell_t *p;

	if( e_q.q == NULL ) {
		e_q.q=(e_q_cell_t *)malloc(sizeof(e_q_cell_t));
		if( e_q.q == NULL ) {
			pr_err(nomem_msg);
			return -1;
		}
		p=e_q.q;
		p->eid=*eid;
		p->next=NULL;
		e_q.q_n=1;
		return 0;
	}
	p=e_q.q;
	while( p->next != NULL ) {
		if( strcmp(p->eid.name,eid->name) == 0 && p->eid.index == eid->index )
			return 0;
		p=p->next;
	}
	if( strcmp(p->eid.name,eid->name) == 0 && p->eid.index == eid->index )
		return 0;
	p->next=(e_q_cell_t *)malloc(sizeof(e_q_cell_t));
	if( p->next==NULL ) {
		pr_err(nomem_msg);
		return -1;
	}
	p=p->next;
	p->eid=*eid;
	p->next=NULL;
	e_q.q_n++;
	return 0;
}

static void cb_gp(void *pd,int cmd,snd_mixer_gid_t *gid) {
	s_mixer_t *mixer=(s_mixer_t *)pd;
	s_obj_t *obj=mixer->obj,*o1;
	s_group_t *g;
	//int i;

	for( ; obj != NULL ; obj=obj->next ) {
		if( obj->g ) {
			g=obj->g;
			if( strcmp(g->g.gid.name,gid->name) == 0 &&
				g->g.gid.index == gid->index ) {
				break;
			}
		}
	}

	switch(cmd) {
	case SND_MIXER_READ_GROUP_REMOVE:
		if( obj ) {
			if( obj->enabled ) {
				gtk_widget_destroy(obj->v_frame);
			}
			obj->dyn_e=2;
			obj->enabled=FALSE;
			return;
		}
		break;
	case SND_MIXER_READ_GROUP_CHANGE:
		if( que_g(gid)== 0 ) return;
		break;
	case SND_MIXER_READ_GROUP_ADD:
		if( obj ) {
			obj->dyn_e=3;
			return;
		}
		o1=NULL;
		obj_ins_new_g(&mixer->obj,&o1,gid);
		mixer->o_nums++;
		o1->enable=conf.i_dyn;
		o1->dyn_e=3;
		break;
	default:
	}
#ifdef DISP_DEBUG
	printf("cb_gp cmd %s gid '%s',%d\n",cmd_name[cmd],gid->name,gid->index);
#endif
}

static int que_g(snd_mixer_gid_t *gid ) {
	g_q_cell_t *p;

	if( g_q.q == NULL ) {
		g_q.q=(g_q_cell_t *)malloc(sizeof(g_q_cell_t));
		if( g_q.q == NULL ) {
			pr_err(nomem_msg);
			return -1;
		}
		p=g_q.q;
		p->gid=*gid;
		p->next=NULL;
		g_q.q_n=1;
		return 0;
	}
	p=g_q.q;
	while( p->next != NULL ) {
		if( strcmp(p->gid.name,gid->name) == 0 && p->gid.index == gid->index )
			return 0;
		p=p->next;
	}
	
	if( strcmp(p->gid.name,gid->name) == 0 && p->gid.index == gid->index )
		return 0;
	p->next=(g_q_cell_t *)malloc(sizeof(g_q_cell_t));
	if( p->next==NULL ) {
		pr_err(nomem_msg);
		return -1;
	}
	p=p->next;
	p->gid=*gid;
	p->next=NULL;
	g_q.q_n++;
	return 0;
}

gint time_callback(gpointer data) {
	//GtkRequisition rq;
	int i,j,k,err;
	e_q_cell_t *eq;
	g_q_cell_t *gq;

	k=0;
	for( i=0 ; i<card_num ; i++ ) {
		cb_ctl.private_data=(void *)&cards[i];
		snd_ctl_read(cards[i].chandle,&cb_ctl);
		for( j=0 ; j<cards[i].info.mixerdevs ; j++ ) {
			cb_mix.private_data=(void *)&cards[i].mixer[j];
			e_q.q=NULL;
			e_q.q_n=0;
			g_q.q=NULL;
			g_q.q_n=0;
			err=snd_mixer_read(cards[i].mixer[j].handle,&cb_mix);
			//if( err ) printf("count %d\n",err);
#if DISP_DEBUG
			for( eq=e_q.q ; eq != NULL ; eq=eq->next )
				printf("que eid '%s',%d,%d\n",eq->eid.name,eq->eid.index,eq->eid.type);
			for( gq=g_q.q ; gq != NULL ; gq=gq->next )
				printf("que gid '%s',%d\n",gq->gid.name,gq->gid.index);
#endif
			if( g_q.q_n ) k+=chk_group( &cards[i].mixer[j] );
		}
	}
	if( k ) {
		gtk_container_remove(GTK_CONTAINER(main_vbox),mixer_container);
		disp_mixer();
	}

	return 1;
}

static int chk_group( s_mixer_t *mixer ) {
	s_obj_t *obj;
	s_group_t *group;
	//s_element_t *e;
	g_q_cell_t *gq,*gq2;
	snd_mixer_group_t m_g;
	int i,j,k,l,err,rt=0;

	gq=g_q.q;
	while( gq ) {
		for( obj=mixer->obj ; obj != NULL ; obj=obj->next ) {
			if( obj->g ) {
				if( strcmp( obj->g->g.gid.name , gq->gid.name ) == 0 &&
					obj->g->g.gid.index == gq->gid.index ) break;
			}
		}
		if( obj ) {
			group=obj->g;
			memset(&m_g,0,sizeof(snd_mixer_group_t));
			m_g.gid=gq->gid;
			if( (err=snd_mixer_group_read(mixer->handle,&m_g))<0 ) {
				sprintf(err_msg,_("Mixer group '%s',%d err 1: %s\n"),
						m_g.gid.name,m_g.gid.index,snd_strerror(err));
				pr_err(err_msg);
				goto __next;
			}
			m_g.pelements = (snd_mixer_eid_t *)malloc(m_g.elements_over*
													sizeof(snd_mixer_eid_t));
			if( m_g.pelements == NULL ) {
				pr_err(nomem_msg);
				goto __next;
			}
			m_g.elements_size=m_g.elements_over;
			m_g.elements=m_g.elements_over=0;
			if( (err=snd_mixer_group_read(mixer->handle,&m_g))<0 ) {
				sprintf(err_msg,_("Mixer group '%s',%d err 2: %s\n"),
						m_g.gid.name,m_g.gid.index,snd_strerror(err));
				pr_err(err_msg);
				free(m_g.pelements);
				goto __next;
			}
			j=0;
			if( group->g.elements == 0 ) {
				j=1;
			} else if( group->g.elements != m_g.elements ) {
				j=1;
			} else {
				k=0;
				for( i=0 ; i<m_g.elements ; i++ ) {
					for( l=k ; l<m_g.elements ; l++ ) {
						if( strcmp(m_g.pelements[i].name,
								   group->g.pelements[l].name)==0 &&
							m_g.pelements[i].index ==
							group->g.pelements[l].index ) {
							if( l==k ) k++;
							break;
						}
					}
					if( l==m_g.elements ) {
						j=1;
						break;
					}
				}
			}
			if( j ) {
				for( i=0 ; i<group->g.elements ; i++ ) {
					element_free(&group->e[i]);
				}
				if( group->g.pelements ) free(group->g.pelements);
				if( group->e ) free(group->e);
				group->g=m_g;
				group->e=(s_element_t *)g_malloc0(group->g.elements*
												  sizeof(s_element_t));
				if( group->e == NULL ) {
					pr_err(nomem_msg);
					goto __next;
				}
				for( i=0 ; i<group->g.elements ; i++ ) {
					if( chk_eid(mixer->obj,&m_g.pelements[i]) ) {
						/*
						printf("%d: build '%s',%d,%d\n",i,
							   m_g.pelements[i].name,m_g.pelements[i].index,
							   m_g.pelements[i].type);
						*/
						s_element_build(mixer->handle,&group->e[i],NULL,
										group->g.pelements[i],mixer->c_dev,
										mixer->m_dev);
					} else {
						group->g.pelements[i].type=0;
						group->e[i].e.eid=group->g.pelements[i];
						group->e[i].info.eid=group->g.pelements[i];
					}
				}
			} else {
				free(m_g.pelements);
			}
			if( obj->enable ) rt=1;
		} else {
			pr_err(_("not added gid before change.\n"));
		}
	__next:
		gq2 = gq->next;
		free(gq);
		gq=gq2;
	}
	return rt;
}

static void element_free(s_element_t *e) {
	if( e->w ) g_free(e->w);
	if( e->adj ) g_free(e->adj);
	if( e->mux ) free(e->mux);
	snd_mixer_element_free(&e->e);
	snd_mixer_element_info_free(&e->info);
}

static gboolean chk_eid(s_obj_t *obj,snd_mixer_eid_t *eid ) {
	e_q_cell_t *eq,*ep;
	s_element_t *e;
	int i;

	if( !is_etype(eid->type) ) return FALSE;
	for( eq=e_q.q; eq != NULL ; eq=eq->next ) {
		if( strcmp(eq->eid.name,eid->name) == 0 &&
			eq->eid.index == eid->index && eq->eid.type == eq->eid.type ) {
			if( eq == e_q.q ) {
				e_q.q=e_q.q->next;
			} else {
				for(ep=e_q.q;ep->next !=eq ; ep=ep->next );
				ep->next=eq->next;
			}
			free(eq);
			return TRUE;
		}
	}
	for( ; obj != NULL ; obj=obj->next ) {
		if(obj->g) {
			for( i=0 ; i < obj->g->g.elements ; i++ ) {
				e=&obj->g->e[i];
				if( strcmp( e->e.eid.name,eid->name ) == 0 &&
					e->e.eid.index == eid->index &&
					e->e.eid.type == eid->type ) return FALSE;
			}
		}
		if(obj->e) {
			e=&obj->e->e;
			if( strcmp( e->e.eid.name,eid->name ) == 0 &&
				e->e.eid.index == eid->index &&
				e->e.eid.type == eid->type ) return FALSE;
			
		}
	}
	return TRUE;
}

void s_e_chk( s_element_t *e ) {
	int i,j;
	switch( e->e.eid.type ) {
	case SND_MIXER_ETYPE_VOLUME1:
		for( i=0 ; i<e->Evol1(e.); i++ ) {
			if( (e->info.data.volume1.prange[i].max-
				 e->info.data.volume1.prange[i].min) == 1 ) {
				gtk_toggle_button_set_active(
											 GTK_TOGGLE_BUTTON(e->w[i]),
											 e->Epvol1(e.)[i]);
			} else {
				e->adj[i]->value=(gfloat)
					-e->Epvol1(e.)[i];
				gtk_signal_emit_by_name(GTK_OBJECT(e->adj[i]),"value_changed");
			}
		}
		break;
	case SND_MIXER_ETYPE_SWITCH1:
		for( i=0 ; i<e->e.data.switch1.sw; i++) {
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(e->w[i]),
									 snd_mixer_get_bit(e->e.data.switch1.psw,i)
										 );
		}
		break;
	case SND_MIXER_ETYPE_SWITCH2:
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(e->w[0]),
									 e->e.data.switch2.sw);
	case SND_MIXER_ETYPE_SWITCH3:
		for( i=0 ; i<e->e.data.switch3.rsw ; i++) {
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(e->w[i]),
								snd_mixer_get_bit(e->e.data.switch3.prsw,i));
		}
		break;
	case SND_MIXER_ETYPE_ACCU3:
		for( i=0 ; i<e->Eaccu3(e.) ; i++ ) {
			e->adj[i]->value=(gfloat)
				-e->Epvol1(e.)[i];
			gtk_signal_emit_by_name(GTK_OBJECT(e->adj[i]),"value_changed");
		}
		break;
	case SND_MIXER_ETYPE_MUX1:
		for( i=0 ; i<e->Emux1(e.) ; i++ ) {
			for( j=0; j<e->mux_n ; j++ ) {
				if( strcmp(e->mux[j].name,e->Epmux1(e.)[i].name)==0 &&
					e->mux[j].index == e->Epmux1(e.)[i].index &&
					e->mux[j].type == e->Epmux1(e.)[i].type ) break;
			}
			if( j < e->mux_n )
				gtk_option_menu_set_history(GTK_OPTION_MENU(e->w[i]),j);
		}
		break;
	case SND_MIXER_ETYPE_MUX2:
		for( i=0; i<e->mux_n ; i++ ) {
			if( strcmp(e->mux[i].name,e->Emux2(e.).name)==0 &&
				e->mux[i].index == e->Emux2(e.).index &&
				e->mux[i].type == e->Emux2(e.).type )
				break;
		}
		if( i < e->mux_n )
			gtk_option_menu_set_history(GTK_OPTION_MENU(e->w[0]),i);
		break;
	case SND_MIXER_ETYPE_3D_EFFECT1:
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_SW ) {
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(e->w[0]),
										 e->e.data.teffect1.sw);
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_MONO_SW ) {
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(e->w[1]),
										 e->e.data.teffect1.sw);
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_WIDE ) {
			e->adj[0]->value=(gfloat)e->e.data.teffect1.wide;
			gtk_signal_emit_by_name(GTK_OBJECT(e->adj[0]),"value_changed");
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_VOLUME ) {
			e->adj[1]->value=(gfloat)e->e.data.teffect1.volume;
			gtk_signal_emit_by_name(GTK_OBJECT(e->adj[1]),"value_changed");
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_CENTER ) {
			e->adj[2]->value=(gfloat)e->e.data.teffect1.center;
			gtk_signal_emit_by_name(GTK_OBJECT(e->adj[2]),
									"value_changed");
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_SPACE ) {
			e->adj[3]->value=(gfloat)e->e.data.teffect1.space;
			gtk_signal_emit_by_name(GTK_OBJECT(e->adj[3]),"value_changed");
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_DEPTH ) {
			e->adj[4]->value=(gfloat)e->e.data.teffect1.depth;
			gtk_signal_emit_by_name(GTK_OBJECT(e->adj[4]),"value_changed");
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_DELAY ) {
			e->adj[5]->value=(gfloat)e->e.data.teffect1.delay;
			gtk_signal_emit_by_name(GTK_OBJECT(e->adj[5]),"value_changed");
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_FEEDBACK ) {
			e->adj[6]->value=(gfloat)e->e.data.teffect1.feedback;
			gtk_signal_emit_by_name(GTK_OBJECT(e->adj[6]),"value_changed");
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_DEPTH_REAR ) {
			e->adj[7]->value=(gfloat)e->e.data.teffect1.depth_rear;
			gtk_signal_emit_by_name(GTK_OBJECT(e->adj[7]),"value_changed");
		}
		break;
	case SND_MIXER_ETYPE_TONE_CONTROL1:
		if( e->info.data.tc1.tc & SND_MIXER_TC1_SW ) {
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(e->w[0]),
										 e->e.data.tc1.sw);
		}
		if( e->info.data.tc1.tc & SND_MIXER_TC1_BASS ) {
			e->adj[0]->value=-(gfloat)e->e.data.tc1.bass;
			gtk_signal_emit_by_name(GTK_OBJECT(e->adj[0]),"value_changed");
		}
		if( e->info.data.tc1.tc & SND_MIXER_TC1_TREBLE ) {
			e->adj[1]->value=-(gfloat)e->e.data.tc1.treble;
			gtk_signal_emit_by_name(GTK_OBJECT(e->adj[1]),"value_changed");
		}
		break;
	case SND_MIXER_ETYPE_PAN_CONTROL1:
		printf("catch pan ");
		for( i=0 ; i<e->e.data.pc1.pan ; i++ ) {
			printf(" %d",e->e.data.pc1.ppan[i]);
			e->adj[i]->value=(gfloat)e->e.data.pc1.ppan[i];
			gtk_signal_emit_by_name(GTK_OBJECT(e->adj[i]),"value_changed");
		}
		printf("\n");
		break;
	}
}

static void rmw_elem(s_element_t *e) {
	int i,j;
	switch( e->e.eid.type ) {
	case SND_MIXER_ETYPE_VOLUME1:
		for( i=0 ; i<e->Evol1(e.); i++ ) {
			if( (e->info.data.volume1.prange[i].max-
				 e->info.data.volume1.prange[i].min) == 1 ) {
				gtk_widget_destroy( e->w[i] );
			} else {
				//gtk_widget_destroy(e->adj[i]);
				gtk_widget_destroy(e->w[i]);
			}
		}
		break;
	case SND_MIXER_ETYPE_SWITCH1:
		for( i=0 ; i<e->e.data.switch1.sw; i++) {
			gtk_widget_destroy(e->w[i]);
		}
		break;
	case SND_MIXER_ETYPE_SWITCH2:
		gtk_widget_destroy(e->w[0]);
		break;
	case SND_MIXER_ETYPE_SWITCH3:
		for( i=0 ; i<e->e.data.switch3.rsw; i++) {
			gtk_widget_destroy(e->w[i]);
		}
		break;
	case SND_MIXER_ETYPE_ACCU3:
		for( i=0 ; i<e->Eaccu3(e.) ; i++ ) {
			gtk_widget_destroy(e->w[i]);
		}
		break;
	case SND_MIXER_ETYPE_MUX1:
		for( i=0 ; i<e->Emux1(e.) ; i++ ) {
			gtk_widget_destroy(e->w[i]);
		}
		break;
	case SND_MIXER_ETYPE_MUX2:
		gtk_widget_destroy(e->w[0]);
		break;
	case SND_MIXER_ETYPE_3D_EFFECT1:
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_SW ) {
			gtk_widget_destroy(e->w[0]);
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_MONO_SW ) {
			gtk_widget_destroy(e->w[1]);
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_WIDE ) {
			gtk_widget_destroy(e->w[2]);
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_VOLUME ) {
			gtk_widget_destroy(e->w[3]);
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_CENTER ) {
			gtk_widget_destroy(e->w[4]);
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_SPACE ) {
			gtk_widget_destroy(e->w[5]);
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_DEPTH ) {
			gtk_widget_destroy(e->w[6]);
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_DELAY ) {
			gtk_widget_destroy(e->w[7]);
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_FEEDBACK ) {
			gtk_widget_destroy(e->w[8]);
		}
		if( e->info.data.teffect1.effect & SND_MIXER_EFF1_DEPTH_REAR ) {
			gtk_widget_destroy(e->w[9]);
		}
		break;
	case SND_MIXER_ETYPE_TONE_CONTROL1:
		if( e->info.data.tc1.tc & SND_MIXER_TC1_SW ) {
			gtk_widget_destroy(e->w[0]);
		}
		if( e->info.data.tc1.tc & SND_MIXER_TC1_BASS ) {
			gtk_widget_destroy(e->w[1]);
		}
		if( e->info.data.tc1.tc & SND_MIXER_TC1_TREBLE ) {
			gtk_widget_destroy(e->w[2]);
		}
		break;
	case SND_MIXER_ETYPE_PAN_CONTROL1:
		j=0;
		for( i=0 ; i<e->e.data.pc1.pan ; i++ ) {
			gtk_widget_destroy(e->w[j++]);
			gtk_widget_destroy(e->w[j++]);
			gtk_widget_destroy(e->w[j++]);
			gtk_widget_destroy(e->w[j++]);
		}
		break;
	}
}

static void ctl_rb_cb(void *date) {
#if DISP_DEBUG
	printf("ctl rebuild callback\n");
#endif
}
static void ctl_xsw_cb(void *data,int cmd,int iface,int dev,int ch,
					   snd_switch_list_item_t *item) {
	s_card_t *card=(s_card_t *)data;
	s_obj_t *obj;
	s_sw_t *sw;
	int err;

	/*
#if DISP_DEBUG
	printf("ctl dev %d xsw sw '%s' cmd %d\n",dev,item->name,cmd);
#endif
	*/
	if( iface != SND_CTL_IFACE_MIXER ) return;
	if( dev > card->info.mixerdevs ) return;
	
	for( obj=card->mixer[dev].obj; obj != NULL ; obj=obj->next ) {
		if( obj->sw )
			if( strcmp(obj->sw->sw.name,item->name) == 0 ) break;
	}
	if( obj ) {
		sw=obj->sw;
#if SND_LIB_VERSION < SND_PROTOCOL_VERSION(0,5,5)
		err=snd_ctl_mixer_switch_read(card->chandle,dev,&sw->sw);
#else
		err=snd_ctl_switch_read(card->chandle,&sw->sw);
#endif
		if( obj->enabled ) {
			/*
#if DISP_DEBUG
			printf("sw %s %d\n",item->name,sw->sw.value.enable);
#endif
			*/
			switch(sw->sw.type) {
			case SND_SW_TYPE_BOOLEAN:
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sw->w[0]),
											 sw->sw.value.enable);
			}
		}
	}
}
