All pastes #1752532 Raw Edit

C

public c v1 · immutable
#1752532 ·published 2010-01-15 16:31 UTC
rendered paste body
#define _GNU_SOURCE#include <string.h>#include <stdio.h>#include <gtk/gtk.h>#include "notebook.h"#include "playlist.h"#include "coverart_wizard.h"#include "misc.h"/* http://tadeboro.blogspot.com/2009/05/wrapping-adn-resizing-gtklabel.html */const GtkTargetEntry targetentries[] ={	{"Collection Tree Node",0, COLLECTION},	{"Album Button",0,ALBUM_BUTTON}};static void on_size_allocate_tadeboro_hack(GtkWidget *label, GtkAllocation *alloc,gpointer data){	gtk_widget_set_size_request( label, alloc->width - 2, -1 );}void on_song_clicked(GtkWidget *godknowshwat, gpointer data){	printf("on_song_clicked:%p\n",data);}void on_album_button_toggled(GtkToggleButton *toggle, gpointer data){	GtkWidget *widget = data;	g_object_set(widget,"no-show-all",FALSE,NULL);	if(gtk_toggle_button_get_active (toggle)){		gtk_widget_show_all(widget);	}else {		gtk_widget_hide(widget);	}}gboolean on_album_button_event(GtkWidget *button,GdkEventButton *event,gpointer data){	// Mouse right click	if(event->button == 3){		printf("right clicked\n");		gtk_menu_popup (GTK_MENU(data), NULL, NULL, NULL, NULL,			event->button, event->time);	}else {		return FALSE;	}	return TRUE;}GtkWidget *create_content_page(GUI_SESSION *g){	GtkWidget *content;		GtkWidget *vbox;	GtkWidget *hbox;	/* Scroll Window */	content = gtk_scrolled_window_new(NULL,NULL);	/* Disable horizontal scroll */	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(content),		GTK_POLICY_NEVER,GTK_POLICY_AUTOMATIC);	g->content_view = GTK_VIEWPORT(gtk_viewport_new (NULL,NULL));	gtk_viewport_set_shadow_type(g->content_view,GTK_SHADOW_NONE);	/* homogenious = false */	vbox = gtk_vbox_new(FALSE,1);	hbox = gtk_hbox_new(FALSE,10);	gtk_box_pack_start(GTK_BOX(hbox),vbox,TRUE,TRUE,10);	gtk_container_add(GTK_CONTAINER(g->content_view),hbox);	/* Add the Amatory logo */	GtkWidget *logo;	logo = gtk_image_new_from_file("/home/vikky/amatory.svg");		gtk_box_pack_start(GTK_BOX(vbox),logo,FALSE,TRUE,10);	char buffer[256];	LIBRARY_get_stat(buffer);	buffer[255]=0;	GtkWidget *stats_label = gtk_label_new(buffer);	gtk_label_set_justify(GTK_LABEL(stats_label),GTK_JUSTIFY_RIGHT);	gtk_box_pack_start(GTK_BOX(vbox),stats_label,FALSE,TRUE,0);	LIBRARY_album_metadata **latest_albums=NULL;	GtkWidget *label;	GtkWidget *album;	int size;	int i;	size = LIBRARY_get_latest_albums(&latest_albums);		if(size>0){		strcpy(buffer,"<big><b>Latest Albums</b></big>");		label = gtk_label_new( (const gchar *)buffer);		gtk_label_set_use_markup(GTK_LABEL(label),TRUE);		gtk_label_set_line_wrap(GTK_LABEL(label),TRUE);//		gtk_misc_set_alignment(GTK_MISC(label),0,1);		gtk_box_pack_start(GTK_BOX(vbox),label,FALSE,FALSE,10);		g_signal_connect( G_OBJECT( label ), "size-allocate",		G_CALLBACK( on_size_allocate_tadeboro_hack ), NULL );		for(i=0;i<size;i++){			album=NULL;			album = create_album_button(g,latest_albums[i]);			if(album!=NULL){				gtk_box_pack_start(GTK_BOX(vbox),album,	FALSE,FALSE,1);			}		}	}	LIBRARY_free_album_metadata_array(latest_albums,size);	gtk_container_add(GTK_CONTAINER(content),GTK_WIDGET(g->content_view));	// FIXME: fix the ambiguity in the naming scheme, current vs content page	g->cpage = hbox;	g->dpage = hbox;	return content;}void songlist_on_drag_data_get (GtkWidget *widget, GdkDragContext *drag_context,			GtkSelectionData *sdata, guint info, guint time, 				gpointer  user_data){	GtkTreeView *view = user_data;	GtkTreeIter iter;	GtkTreeModel *store;	GtkTreeSelection *selector;	PLAYLIST_ROW *msg;	gboolean rv;	printf("songlist_on_drag_data_get\n");	/* Get the selector widget from the treeview in question */	selector = gtk_tree_view_get_selection(view);	/* Get the tree model (list_store) and initialise the iterator */	rv = gtk_tree_selection_get_selected(selector,&store,&iter);	/* This shouldn't really happen, but just in case */	if(rv==FALSE){		printf(" No row selected\n");		return;	}	msg = malloc(sizeof(PLAYLIST_ROW));	long long id;		gtk_tree_model_get (store, &iter, 		SL_TAG_ID_COL, &id,-1);	msg->id  = id;	msg->type = TAG;	gtk_selection_data_set(sdata,		gdk_atom_intern ("Integer Array Pointer", FALSE),		8, // byte pack		(void *)&msg,		sizeof (&msg));	printf("Sent %p\n",msg);}void album_button_on_drag_data_get (GtkWidget *widget, GdkDragContext *drag_context,			GtkSelectionData *sdata, guint info, guint time, 				gpointer  user_data){	GtkTreeModel *model = user_data;	PLAYLIST_ROW *msg;	GtkTreeIter iter;	int type;	long long id,artist_id;	gtk_tree_model_get_iter_first (model,&iter);	gtk_tree_model_get (model, &iter,		SL_TYPE_COL,&type,		SL_ALBUM_ID_COL,&id,		SL_ARTIST_ID_COL,&artist_id,		-1);	msg = malloc(sizeof(PLAYLIST_ROW));	msg->id  = id;	msg->artist_id = artist_id;	msg->type = type;	gtk_selection_data_set(sdata,		gdk_atom_intern ("Integer Array Pointer", FALSE),		8, // byte pack		(void *)&msg,		sizeof (&msg));	printf("Sent %p\n",msg);}GtkWidget *create_album_button(GUI_SESSION *g, LIBRARY_album_metadata *a){	char *buffer=NULL;	size_t buffer_size;	GtkWidget *img;	/* Create empty Button */	GtkWidget *button = gtk_toggle_button_new();	g_object_set(button,"relief",GTK_RELIEF_NONE,		NULL);	gtk_widget_set_can_focus(button,FALSE);	gtk_drag_source_set(button,GDK_BUTTON1_MASK, (const GtkTargetEntry*)&targetentries,2,			GDK_ACTION_LINK);	/* Add a horizontal box to the button */	GtkWidget *button_hbox = gtk_hbox_new(FALSE,0);	gtk_container_add(GTK_CONTAINER(button),button_hbox);	/* Try get an album cover, otherwise get an artist photo */	if(	!LIBRARY_get_image_blob(0,a->id,(unsigned char **)&buffer,&buffer_size) ||		!LIBRARY_get_image_blob(a->artist_id,0,(unsigned char **)&buffer,&buffer_size)	){		img = vgtk_image_new_from_memory((unsigned char *)buffer,buffer_size,0,50);		free(buffer);	}else{	/* Get a default image if neither album or artist art could be found */		if(buffer)free(buffer);		img = gtk_image_new_from_file(BLANK_COVER_SMALL);	}		/* Add the image to the button's horizontal box */	gtk_box_pack_start(GTK_BOX(button_hbox),img,TRUE,TRUE,0);	/* Create an alignment for the labels */	/* Center X, Center Y, Expand X, No-expand Y */	GtkWidget *label_align_container = gtk_alignment_new(0.5,0.5,1.0,0.0);	/* Create a horizontal box for the two labels */	GtkWidget *label_hbox = gtk_hbox_new(FALSE,0);	/* Add the label box to its aligned container */	gtk_container_add(GTK_CONTAINER(label_align_container),label_hbox);	/* Add the label's aligned container to the button's hbox */	gtk_box_pack_start(GTK_BOX(button_hbox),label_align_container,TRUE,TRUE,5);	/* Create the textual descriptions */	buffer = g_markup_printf_escaped("<small><b>%s</b></small>\n<small><b><span fgcolor=\"gray\">%4u</span></b></small> <small>%u:%02u</small>",a->name,a->tracks[0]->year,(a->length/60),(a->length%60) );	GtkWidget *name_label = gtk_label_new(buffer);	g_free(buffer);	gtk_label_set_use_markup(GTK_LABEL(name_label),TRUE);	gtk_label_set_line_wrap(GTK_LABEL(name_label),TRUE);	/* Dynamic GtkLabel Line Wrap workaround */	g_signal_connect( G_OBJECT( name_label ), "size-allocate",                      G_CALLBACK( on_size_allocate_tadeboro_hack ), NULL );	gtk_misc_set_alignment(GTK_MISC(name_label),0,0.0); 	buffer = g_strdup_printf("<small>%u Tracks</small>",a->track_count);	GtkWidget *track_label = gtk_label_new(buffer);	gtk_label_set_use_markup(GTK_LABEL(track_label),TRUE);	gtk_misc_set_alignment(GTK_MISC(track_label),1,0.0); // Right,	g_free(buffer);	/* Create a size grouping so the track and name label stay aligned */	GtkSizeGroup *sizegroup  = gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL);	gtk_size_group_add_widget(sizegroup,name_label);	gtk_size_group_add_widget(sizegroup,track_label);	g_object_unref(sizegroup);		/* Move the name 5pix away from the image */	gtk_box_pack_start(GTK_BOX(label_hbox),name_label,TRUE,TRUE,5);	gtk_box_pack_start(GTK_BOX(label_hbox),track_label,TRUE,TRUE,5);	/* Create a song list for the album *////	GtkWidget *songlist = gtk_vbox_new(FALSE,0);	GtkListStore *songs = gtk_list_store_new(SL_N_COLS,		G_TYPE_INT,		G_TYPE_STRING,		G_TYPE_INT,		G_TYPE_UINT64,		G_TYPE_UINT64,		G_TYPE_UINT64		);	GtkTreeIter iter;	int i;	for(i=0;i<a->track_count;i++){		gtk_list_store_append(songs,&iter);		gtk_list_store_set(songs,&iter,			SL_TRK_COL,a->tracks[i]->track,			SL_TIT_COL,a->tracks[i]->name,			SL_TYPE_COL,((a->va) ? VA_ALBUM : ALBUM),			SL_TAG_ID_COL,a->tracks[i]->id,			SL_ALBUM_ID_COL,a->id,			SL_ARTIST_ID_COL,((a->va) ? a->tracks[i]->artist_id : a->artist_id),			-1);	}		GtkWidget *songlist = gtk_tree_view_new_with_model(GTK_TREE_MODEL(songs));	g_object_unref(songs);	GtkCellRenderer *renderer;        GtkTreeViewColumn *column;        renderer = gtk_cell_renderer_text_new();	g_object_set (renderer,"size-points",9.0,NULL);	column = gtk_tree_view_column_new_with_attributes("Track",renderer,                "text",0,NULL);	gtk_tree_view_append_column(GTK_TREE_VIEW(songlist), column);	renderer = gtk_cell_renderer_text_new();	g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END,                "size-points",9.0,NULL);	column = gtk_tree_view_column_new_with_attributes("Title",renderer,                "text",1,NULL);	gtk_tree_view_append_column (GTK_TREE_VIEW(songlist), column);	gtk_tree_view_set_headers_visible  (GTK_TREE_VIEW(songlist),FALSE);	gtk_tree_view_set_rules_hint (GTK_TREE_VIEW(songlist),TRUE);	/* Make the background of the little songlist really nice */	gtk_widget_modify_base (songlist,GTK_STATE_NORMAL,		g->window->style->bg);	g_signal_connect( G_OBJECT( songlist ), "size-allocate",                      G_CALLBACK( on_size_allocate_tadeboro_hack ), NULL );	gtk_drag_source_set(songlist,GDK_BUTTON1_MASK,(const GtkTargetEntry *) &targetentries,2,			GDK_ACTION_LINK);	g_signal_connect(songlist,"drag-data-get",                G_CALLBACK(songlist_on_drag_data_get),songlist);	g_signal_connect(button,"drag-data-get",                G_CALLBACK(album_button_on_drag_data_get),songs);	/* Now add the image button and the song list to a vbox */	GtkWidget *album_box = gtk_vbox_new(FALSE,0);//	GtkWidget *button_frame = gtk_frame_new(NULL);//	gtk_container_add(button_frame,button_hbox);	gtk_box_pack_start(GTK_BOX(album_box),button,TRUE,TRUE,0);	g_signal_connect(button,"toggled",G_CALLBACK(on_album_button_toggled),		songlist);	g_signal_connect(button,"button-press-event",		G_CALLBACK(on_album_button_event),g->album_button_menu);	/* Stop the album_box from exposing us */	g_object_set(songlist,"no-show-all",TRUE,NULL); 		gtk_box_pack_start(GTK_BOX(album_box),songlist,FALSE,FALSE,0);	return album_box;}GtkWidget *create_current_content(GUI_SESSION *g){	GtkWidget *vbox = NULL;	GtkWidget *img = NULL;	GtkWidget *img_button = NULL;	unsigned char *buffer=NULL;	size_t buffer_size;	char *cptr = NULL;	if(!g->amatory->audio_session->playing )return g->dpage;	/* homogenious = false */	vbox = gtk_vbox_new(FALSE,0);	if(	!LIBRARY_get_image_blob(0,g->playing->album_id,	&buffer,&buffer_size)		||		!LIBRARY_get_image_blob(g->playing->artist_id,0,&buffer,&buffer_size)	){		img_button = gtk_button_new();		img = vgtk_image_new_from_memory(buffer,buffer_size,200,0);		free(buffer);		gtk_button_set_image(GTK_BUTTON(img_button),img);		g_object_set(img_button,"relief",GTK_RELIEF_HALF,			"focus-on-click",FALSE,NULL);		gtk_widget_set_can_focus(img_button,FALSE);		gtk_box_pack_start(GTK_BOX(vbox),img_button,FALSE,FALSE,2);	}else {		img_button = gtk_button_new();		img = gtk_image_new_from_file(BLANK_COVER);		gtk_button_set_image(GTK_BUTTON(img_button),img);		g_object_set(img_button,"relief",GTK_RELIEF_HALF,			"focus-on-click",FALSE,NULL);		gtk_widget_set_can_focus(img_button,FALSE);		gtk_box_pack_start(GTK_BOX(vbox),img_button,FALSE,FALSE,10);	}		/* Push the button 10pix  off the edge *///	gtk_box_pack_start(GTK_BOX(hbox),GTK_WIDGET(img_button),FALSE,FALSE,0);	/* Expand = False, Fill = TRUE, spacing = 10 *///	gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,10);	cptr = g_markup_escape_text(g->playing->artist_name,-1);	char lbuf[256];			GtkWidget *label;	GtkWidget *album;	int i;	int size;	LIBRARY_artist_metadata *artist=NULL;	size = LIBRARY_get_artist(&artist,g->playing->artist_id);	if(size>0){		snprintf(lbuf,255,"<big><b>Albums by %s</b></big>",cptr);		label = gtk_label_new(lbuf);		gtk_label_set_use_markup(GTK_LABEL(label),TRUE);		gtk_label_set_line_wrap(GTK_LABEL(label),TRUE);		gtk_misc_set_alignment(GTK_MISC(label),0,1);		gtk_box_pack_start(GTK_BOX(vbox),label,FALSE,FALSE,10);		g_signal_connect( G_OBJECT( label ), "size-allocate",		G_CALLBACK( on_size_allocate_tadeboro_hack ), NULL );		for(i=0;i<size;i++){			album = create_album_button(g,artist->album[i]);			if(album!=NULL){				gtk_box_pack_start(GTK_BOX(vbox),album,	FALSE,FALSE,1);			}		}	}	LIBRARY_free_artist_metadata(artist);	LIBRARY_album_metadata **va_albums=NULL;	size = LIBRARY_get_va_albums(&va_albums,g->playing->artist_id);	if(size>0){		snprintf(lbuf,255,"<big><b>Compilations with %s</b></big>",cptr);		label = gtk_label_new(lbuf);		gtk_label_set_use_markup(GTK_LABEL(label),TRUE);		gtk_label_set_line_wrap(GTK_LABEL(label),TRUE);		gtk_misc_set_alignment(GTK_MISC(label),0,1);		gtk_box_pack_start(GTK_BOX(vbox),label,FALSE,FALSE,10);		g_signal_connect( G_OBJECT( label ), "size-allocate",		G_CALLBACK( on_size_allocate_tadeboro_hack ), NULL );		for(i=0;i<size;i++){			album = create_album_button(g,va_albums[i]);			if(album!=NULL){				gtk_box_pack_start(GTK_BOX(vbox),album,FALSE,FALSE,1);			}		}	}	LIBRARY_free_album_metadata_array(va_albums,size);	free(cptr);	GtkWidget *content = gtk_hbox_new(FALSE,10);	gtk_box_pack_start(GTK_BOX(content),GTK_WIDGET(vbox),TRUE,TRUE,10);		return content;}void update_content_page(GUI_SESSION *g){	printf("update_content_page\n");	if(!g->amatory->audio_session->playing){		// Switch on the default page 		if(g->cpage != g->dpage){			gtk_widget_destroy(GTK_WIDGET(g->cpage));			gtk_container_add(GTK_CONTAINER(g->content_view),				GTK_WIDGET(g->dpage));			g->cpage = g->dpage;			g_object_unref(g->dpage); // remove my ref			gtk_widget_show_all(GTK_WIDGET(g->content_view));		}else{			printf("update_content_page: already at default page\n");		}	}else{		GtkWidget *page;		page = create_current_content(g);		if(g->cpage != g->dpage){			gtk_widget_destroy(GTK_WIDGET(g->cpage));		}else {			g_object_ref(g->dpage); // stop gtk from deleting 			gtk_container_remove(GTK_CONTAINER(g->content_view),				GTK_WIDGET(g->dpage));		}		gtk_container_add(GTK_CONTAINER(g->content_view),page);			gtk_widget_show_all(GTK_WIDGET(g->content_view));		g->cpage = page;	}}void _collection_filter(GtkTreeModel *model, GtkTreeIter *iter){	GtkTreeIter iter_c;	gtk_tree_store_set(GTK_TREE_STORE(model),iter,CO_FLT_COL,TRUE,-1);	if(gtk_tree_model_iter_children(model,&iter_c,iter)){		_collection_filter(model,&iter_c);	}	while(gtk_tree_model_iter_next(model,iter)){		gtk_tree_store_set(GTK_TREE_STORE(model),iter,CO_FLT_COL,TRUE,			-1);		if(gtk_tree_model_iter_children(model,&iter_c,iter)){			_collection_filter(model,&iter_c);		}	}	return;}void *vstrcasestr(const char *s1, const char *s2){	int i;	int s1_len;	int s2_len;	char s1_new[256],s2_new[256];		if(s1== NULL || s2 == NULL)return NULL;	s1_len = strlen(s1);	s2_len = strlen(s2);	if(s1_len<s2_len)return NULL;	strcpy(s1_new,s1);	strcpy(s2_new,s2);	for(i=0;i<s1_new[i];i++){//		if(s1_new[i]>= 'A' && s1_new[i]<= 'Z'){		if(s1_new[i]<= 'Z'){			s1_new[i] += 32;		}	}	for(i=0;i<s2_new[i];i++){		if(s2_new[i]<= 'Z'){			s2_new[i] += 32;		}	}		return (memmem(s1_new,s1_len,s2_new,s2_len));}gboolean filter_collection_foreach(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data){	int type;	GUI_SESSION *g = data;	GtkTreeIter iter_p,iter_pp;	gboolean visible;	int vis;	long long id;	char *name=NULL;	LIBRARY_track_metadata *t=NULL;	visible = FALSE;	gtk_tree_model_get (model, iter,		CO_TYPE_COL,&type,		CO_ID_COL,&id,		CO_NAME_COL,&name,		-1);		switch(type){	case ARTIST:		if(vstrcasestr(name,g->entry_text)){			visible = TRUE;			vis = 1;		}else {			visible = FALSE;			vis  = 0;		}		gtk_tree_store_set(GTK_TREE_STORE(model),iter,CO_VIS_COL,vis,-1);		break;	case ALBUM:		// Check the parent first 		gtk_tree_model_iter_parent((model),&iter_p,iter);		gtk_tree_model_get (model, &iter_p,			CO_VIS_COL,&vis,			-1);		if(vis){			visible = TRUE;			vis = 0;		}else if(vstrcasestr(name,g->entry_text)){			vis = 1;			visible = TRUE;			// Make sure parent is true as well 				gtk_tree_store_set(GTK_TREE_STORE(model),&iter_p,CO_FLT_COL,visible,-1);		}else {			vis = 0;			visible = FALSE;		}		gtk_tree_store_set(GTK_TREE_STORE(model),iter,CO_VIS_COL,vis,-1);		break;	case TAG:		gtk_tree_model_iter_parent(model,&iter_p,iter);		gtk_tree_model_get (model, &iter_p,CO_VIS_COL,&vis,-1);		if(vis){			visible = TRUE;			break;		}		gtk_tree_model_iter_parent(model,&iter_pp,&iter_p);		gtk_tree_model_get (model, &iter_pp,CO_VIS_COL,&vis,-1);		if(vis){			visible = TRUE;			gtk_tree_store_set(GTK_TREE_STORE(model),&iter_p,CO_FLT_COL,visible,-1);		} else if(vstrcasestr(name,g->entry_text)){			visible = TRUE;			// Make sure parents are true as well 				gtk_tree_store_set(GTK_TREE_STORE(model),&iter_p,CO_FLT_COL,visible,-1);			gtk_tree_store_set(GTK_TREE_STORE(model),&iter_pp,CO_FLT_COL,visible,-1);		}else {			visible = FALSE;		}		break;	case VA_ALBUM:		gtk_tree_model_iter_parent(model,&iter_p,iter);		if(vstrcasestr(name,g->entry_text)){			vis = 1;			visible = TRUE;			// Make sure parent is true as well 				gtk_tree_model_iter_parent((model),&iter_p,iter);			gtk_tree_store_set(GTK_TREE_STORE(model),&iter_p,CO_FLT_COL,visible,-1);		}else {			vis =0;			visible = FALSE;		}		gtk_tree_store_set(GTK_TREE_STORE(model),iter,CO_VIS_COL,vis,-1);		break;	case VA_TAG:		gtk_tree_model_iter_parent(model,&iter_p,iter);		gtk_tree_model_iter_parent(model,&iter_pp,&iter_p);		gtk_tree_model_get (model, &iter_p,CO_VIS_COL,&vis,-1);		if(vis){			visible = TRUE;			LIBRARY_free_track_metadata(t);			break;		}		if(vstrcasestr(name,g->entry_text)){			visible = TRUE;			// Make sure parents are true as well 				gtk_tree_model_iter_parent(model,&iter_pp,&iter_p);			gtk_tree_store_set(GTK_TREE_STORE(model),&iter_p,CO_FLT_COL,visible,-1);			gtk_tree_store_set(GTK_TREE_STORE(model),&iter_pp,CO_FLT_COL,visible,-1);		}else {			visible = FALSE;		}		break;	case ALL_VA:		break;	default:		printf("Unhandled Type = %i\n",type);	}	gtk_tree_store_set(GTK_TREE_STORE(model),iter,CO_FLT_COL,visible,-1);	g_free(name);	return FALSE; // to conintue iterating}void filter_collection(gpointer data){	GUI_SESSION *g = data;	GtkTreeIter iter;	GtkTreeModel *model =  gtk_tree_model_filter_get_model(g->collection_filter);		/* If the search expression matches an:		1. artist, show all albums + tracks		2. album, show all tracks for that album only	  Otherwise look at individual track names 	*/	if(strlen(g->entry_text)==0){		gtk_tree_model_get_iter_first (model,&iter);		_collection_filter(model,&iter);		return;	}	struct timespec t1,t2;	clock_gettime(CLOCK_REALTIME,&t1);	gtk_tree_model_foreach(model,filter_collection_foreach,data);	clock_gettime(CLOCK_REALTIME,&t2);		printf("%01li.%03li\n",(t2.tv_sec - t1.tv_sec),(t2.tv_nsec-t1.tv_nsec)/1000000);	//gtk_tree_model_get (model, iter,CO_TYPE_COL, &type, CO_PTR_COL,&ptr,-1);}GtkTreeModelFilter *populate_collection_model (){	GtkTreeStore *model;	GtkTreeModelFilter *filter;	GtkTreeIter iter,child_iter,grand_iter;	/* Create tree store. Hidden ID column on the end */	model = gtk_tree_store_new (CO_N_COLS,		G_TYPE_STRING, //name		G_TYPE_INT, // type		G_TYPE_UINT64, // id		G_TYPE_BOOLEAN,		G_TYPE_INT // my own visibility marker		); // pointer	filter = GTK_TREE_MODEL_FILTER(gtk_tree_model_filter_new(GTK_TREE_MODEL(model),NULL));	int i,j,k;	gtk_tree_store_append(model,&iter,NULL);	LIBRARY_album_metadata **va_lib;	long long size;	size = LIBRARY_get_all_va_albums(&va_lib);	/* Do the Various Artists first */	gtk_tree_store_set(model,&iter,CO_NAME_COL,"Various Artists",		CO_TYPE_COL,ALL_VA,		CO_FLT_COL,TRUE,		-1);	for(i=0;i<size;i++){		gtk_tree_store_append(model,&child_iter,&iter);		gtk_tree_store_set(model,&child_iter,				CO_NAME_COL,va_lib[i]->name,				CO_TYPE_COL,VA_ALBUM,				CO_ID_COL,va_lib[i]->id,				CO_FLT_COL,TRUE,				CO_VIS_COL,1,				-1);		for(j=0;j<va_lib[i]->track_count;j++){			gtk_tree_store_append(model,&grand_iter,&child_iter);			gtk_tree_store_set(model,&grand_iter,				CO_NAME_COL,va_lib[i]->tracks[j]->name,				CO_TYPE_COL,VA_TAG,				CO_ID_COL,va_lib[i]->tracks[j]->id,				CO_FLT_COL,TRUE,				CO_VIS_COL,1,				-1);		}	}	LIBRARY_free_album_metadata_array(va_lib,size);	LIBRARY_artist_metadata **alib;	size = LIBRARY_get_all_artists(&alib);	for(i=0;i<size;i++){	gtk_tree_store_append(model,&iter,NULL);		gtk_tree_store_set(model,&iter,			CO_NAME_COL,alib[i]->name,			CO_TYPE_COL,ARTIST,			CO_ID_COL,alib[i]->id,			CO_FLT_COL,TRUE,			CO_VIS_COL,1,			-1);		for(j=0;j<alib[i]->album_count;j++){			gtk_tree_store_append(model,&child_iter,&iter);			gtk_tree_store_set(model,&child_iter,				CO_NAME_COL,alib[i]->album[j]->name,				CO_TYPE_COL,ALBUM,				CO_ID_COL,alib[i]->album[j]->id,				CO_FLT_COL,TRUE,				CO_VIS_COL,1,				-1);			for(k=0;k<alib[i]->album[j]->track_count;k++){				gtk_tree_store_append(model,&grand_iter,&child_iter);				gtk_tree_store_set(model,&grand_iter,					CO_NAME_COL,alib[i]->album[j]->tracks[k]->name,					CO_TYPE_COL,TAG,					CO_ID_COL,alib[i]->album[j]->tracks[k]->id,					CO_FLT_COL,TRUE,					CO_VIS_COL,1,					-1);			}		}	}	LIBRARY_free_artist_metadata_array(alib,size);	gtk_tree_model_filter_set_visible_column(  filter ,                                              CO_FLT_COL );	return filter;}void add_collection_columns (GtkTreeView *treeview){	GtkCellRenderer *renderer;	GtkTreeViewColumn *column;	/* column for holiday names */	renderer = gtk_cell_renderer_text_new ();//	g_object_set (renderer, "xalign", 0.0, NULL);		/* Shrink... text effect */	g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END,			"size-points",9.0, NULL);	/* Gives us speed up  - apparently */	gtk_tree_view_set_fixed_height_mode (treeview,TRUE);	column = gtk_tree_view_column_new_with_attributes("Artist / Album",		renderer,"text",0,NULL);	g_object_set(treeview,"fixed-height-mode",TRUE, NULL);	g_object_set(column,"sizing",GTK_TREE_VIEW_COLUMN_FIXED,NULL);	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview),TRUE);	gtk_tree_view_append_column(treeview,column);	}/*void collection_on_drag_data_received(GtkWidget *widget, gpointer data){	printf("CALLBACK: on_drag_data_received\n");}*/void collection_on_drag_data_get (GtkWidget *widget, GdkDragContext *drag_context,			GtkSelectionData *sdata, guint info, guint time, 				gpointer  data){	GtkTreeIter iter;	GtkTreeModel *store;	GtkTreeSelection *selector;	GtkTreeIter iter_p;	gboolean rv;	printf("CALLBACK: Collection: on_drag_data_get\n");	/* Get the selector widget from the treeview in question */	selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));	/* Get the tree model (list_store) and initialise the iterator */	rv = gtk_tree_selection_get_selected(selector,&store,&iter);	/* This shouldn't really happen, but just in case */	if(rv==FALSE){		printf(" No row selected\n");		return;	}	int type;	PLAYLIST_ROW *msg;	msg = malloc(sizeof(PLAYLIST_ROW));	long long id;		gtk_tree_model_get (store, &iter, 		CO_TYPE_COL, &type, CO_ID_COL,&id,-1);	msg->id  = id;	msg->type = type;	if(type == ALBUM){		gtk_tree_model_iter_parent(store,&iter_p,&iter);		gtk_tree_model_get (store, &iter_p, CO_ID_COL,&(msg->artist_id),-1);	}	gtk_selection_data_set(sdata,		gdk_atom_intern ("Integer Array Pointer", FALSE),		8, // byte pack		(void *)&msg,		sizeof (&msg));				printf("Sent %p\n",msg);}void collection_on_row_activated(GtkTreeView *tree_view,GtkTreePath *path, 			GtkTreeViewColumn *column,gpointer user_data){	GtkTreeSelection *selector;	GtkTreeIter iter;	GtkTreeModel *list_store;	gboolean rv;	printf("collection_on_row_activated\n");		/* Find out which row was selected *///	gtk_tree_selection_select_path(selector,path);	selector = gtk_tree_view_get_selection(tree_view);	rv = gtk_tree_selection_get_selected(selector,&list_store,&iter);	if(rv==FALSE){		printf(" No row selected\n");		return;	}	long long id;	int type;	gtk_tree_model_get (list_store, &iter,CO_TYPE_COL, &type, 		CO_ID_COL,&id,-1);	PLAYLIST_ROW *msg;	msg = malloc(sizeof(PLAYLIST_ROW));	msg->id = id;	msg->type = type;	GtkSelectionData sdata;	/*	gtk_selection_data_set(&sdata,		gdk_atom_intern ("Integer Array Pointer", FALSE),		8, // byte pack		(void *)&msg,		sizeof (&msg));	*/				sdata.data = (void *)&msg;	printf("Sent %p\n",msg);	/* Naughty */	on_drag_data_received (NULL,NULL,0,0,&sdata,0,0,user_data);}unsigned int hash[2];unsigned short s=0;gboolean entry_watcher(gpointer data){	GUI_SESSION *g = data;	const gchar *string;	string =  gtk_entry_get_text(g->entry);	printf("text = %s\n",string);	hash[s] = SuperFastHash(string,strlen(string));	s^=1;	if(hash[0] == hash[1]){		printf("Done!!\n");		g->entry_handler_id = 0;		g->entry_text = string;			g->entry_text_len = strlen(string);		filter_collection(g);		gtk_tree_model_filter_refilter(g->collection_filter);		return FALSE; // stop this timeout	}	return TRUE; // keep the timeout going}void on_entry_changed(GtkEditable *editable,gpointer data){	GUI_SESSION *g = data;	printf("on_entry_changed:\n");	if(g->entry_handler_id==0){		g->entry_handler_id = gdk_threads_add_timeout_full(			G_PRIORITY_DEFAULT,500,entry_watcher,data,NULL);	}}gboolean add_on_entry(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data){	int type;	int vis,vis_p,vis_pp;	gboolean visible;	long long id;		PLAYLIST_ROW *msg;	GtkSelectionData sdata;	GtkTreeIter iter_p,iter_pp;	gtk_tree_model_get (model, iter,		CO_TYPE_COL,&type,		CO_ID_COL,&id,		CO_VIS_COL,&vis,		CO_FLT_COL,&visible,		-1);		if(  (type == TAG) || (type == VA_TAG) ) { 		/* Check if parents have been sent already */		gtk_tree_model_iter_parent((model),&iter_p,iter);		gtk_tree_model_get(model,&iter_p,CO_VIS_COL,&vis_p,-1);		if(vis_p) return FALSE;		gtk_tree_model_iter_parent((model),&iter_pp,&iter_p);		gtk_tree_model_get(model,&iter_pp,CO_VIS_COL,&vis_pp,-1);		if(vis_pp) return FALSE;		if(visible !=TRUE) return FALSE;		msg = malloc(sizeof(PLAYLIST_ROW));		msg->id = id;		msg->type = type;				sdata.data = (void *) &msg;				on_drag_data_received (NULL,NULL,0,0,&sdata,0,0,user_data);	}else if (vis){		msg = malloc(sizeof(PLAYLIST_ROW));		msg->id = id;		msg->type = type;				sdata.data = (void *)&msg;				on_drag_data_received (NULL,NULL,0,0,&sdata,0,0,user_data);	}	return FALSE; // keep _foreach going }void on_entry_activate(GtkEditable *editable,gpointer data){	GUI_SESSION *g = data;	GtkTreeIter iter;	GtkTreeModel *model =  gtk_tree_model_filter_get_model(g->collection_filter);		printf("on_entry_activate:\n");	struct timespec t1,t2;	/*TODO:  check if blank etc.. */	clock_gettime(CLOCK_REALTIME,&t1);	gtk_tree_model_foreach(model,add_on_entry,data);	clock_gettime(CLOCK_REALTIME,&t2);		printf("%01li.%03li\n",(t2.tv_sec - t1.tv_sec),(t2.tv_nsec-t1.tv_nsec)/1000000);	gtk_tree_model_get_iter_first (model,&iter);	_collection_filter(model,&iter);	/* Clear the entry */	 gtk_editable_delete_text(editable,0,-1);}void on_switch_page(GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, gpointer data){	GtkWidget *child = NULL;	char *cptr = NULL;	printf("on_switch_page\n");	child = gtk_notebook_get_nth_page(notebook,page_num);	if(child == NULL){		printf("on_switch_page: child == NULL\n");		return;	}	cptr = gtk_notebook_get_tab_label_text (notebook,child);	if(cptr == NULL){		printf("on_switch_page: cptr == NULL\n");		return;	}	if (strstr(cptr,"Art")){		gtk_widget_hide(data);	}else {		gtk_widget_show(data);	}}GtkWidget *create_notebook(GUI_SESSION *g){	GtkWidget *main_notebook;	GtkWidget *content_page;	GtkWidget *label;	/* Add a notebook to the left side of the pane */	main_notebook = gtk_notebook_new();	/* Put the notebook tabs on the left */	g_object_set (G_OBJECT (main_notebook), "tab-pos",GTK_POS_LEFT,NULL);	g_object_set (G_OBJECT (main_notebook), "homogeneous",TRUE, NULL);	g_object_set (G_OBJECT (main_notebook),"show-border", FALSE,NULL);	/******** Add pages to the notebook *********/ 	content_page = create_content_page(g);	gtk_label_set_angle( GTK_LABEL(label = gtk_label_new("Content")),90);	gtk_notebook_append_page_menu(GTK_NOTEBOOK(main_notebook), 		content_page, label, NULL);	/********* Collection Page **********/	/* Homogeneous = FALSE, Space = 0 */	GtkWidget *collection_page = gtk_vbox_new (FALSE, 0);	/* Parent, Child, Expand, Filli, Padding */	GtkWidget *collection_entry = gtk_entry_new();	gtk_box_pack_start (GTK_BOX(collection_page), collection_entry,			FALSE,TRUE,0);	g_signal_connect(collection_entry,"changed",G_CALLBACK(on_entry_changed),g);	g_signal_connect(collection_entry,"activate",G_CALLBACK(on_entry_activate),g);	g->entry = GTK_ENTRY(collection_entry);	GtkTreeModelFilter *model = populate_collection_model(g);	g->collection_filter = model;	GtkWidget *treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));//	g_object_unref(model);	add_collection_columns (GTK_TREE_VIEW (treeview));	GtkWidget *scroll = gtk_scrolled_window_new(NULL,NULL);	/* Disable Horizontal Scroll cos we have ellipzable text */	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),		GTK_POLICY_NEVER,GTK_POLICY_AUTOMATIC);	gtk_container_add(GTK_CONTAINER(scroll),treeview);	gtk_drag_source_set(treeview,GDK_BUTTON1_MASK,(const GtkTargetEntry*)&targetentries,2,			GDK_ACTION_LINK);	g_signal_connect(treeview,"drag-data-get",                G_CALLBACK(collection_on_drag_data_get),NULL);	g_signal_connect(treeview,"row-activated",		G_CALLBACK(collection_on_row_activated),g);	/*	g_signal_connect(treeview,"drag-data-received",                G_CALLBACK(tree_on_drag_data_received),NULL);*/	gtk_box_pack_start(GTK_BOX(collection_page),scroll,			TRUE,TRUE,0);	gtk_label_set_angle(GTK_LABEL(label = gtk_label_new("Collection")),90);	gtk_notebook_append_page_menu(GTK_NOTEBOOK(main_notebook), 		collection_page, label, NULL);	/********* Playlist Page **********/	gtk_label_set_angle(GTK_LABEL(label = gtk_label_new("Playlist")),90);	gtk_notebook_append_page_menu(GTK_NOTEBOOK(main_notebook), 		gtk_label_new("Playlist Child"),label, NULL);	/********* File Page **********/	GtkWidget *temp = gtk_label_new("Files Child");	gtk_label_set_angle(GTK_LABEL(label = gtk_label_new("Files")),90);	gtk_notebook_append_page_menu(GTK_NOTEBOOK(main_notebook), 		temp,label, NULL);	gtk_container_child_set(GTK_CONTAINER(main_notebook),temp,		"tab-expand",TRUE,NULL);	/********* Art Wizard Page  **********/	GtkWidget *artwiz = create_coverart_wizard(g);	gtk_label_set_angle(GTK_LABEL(label = gtk_label_new("Artwork")),90);	gtk_notebook_append_page_menu(GTK_NOTEBOOK(main_notebook), 		artwiz,label, NULL);	return main_notebook;}