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;}