#include #include #include "tracker.h" typedef struct { gchar *uri; gchar **keys; gchar **tags; gchar **metadata; gint mtime; } TrackerResult; typedef struct { GtkWidget *window; GtkWidget *entry; GtkListStore *results; TrackerClient *tracker; } TrackerSearch; /** * searching functions */ static void search_result_callback(gchar **result, GError *error, TrackerSearch *app) { GtkTreeIter iter; gpointer element; gboolean valid; int i = 0; if(error || !result) return; /* clear and free the list */ valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(app->results), &iter); while(valid) { gtk_tree_model_get(GTK_TREE_MODEL(app->results), &iter, 0, &element, -1); g_free(((TrackerResult*)element)->uri); // g_strfreev(((TrackerResult*)element)->tags); g_slice_free(TrackerResult, element); valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(app->results), &iter); } gtk_list_store_clear(app->results); /* add the results we've gotten to the list */ for(i = 0; result[i] != NULL; i++) { TrackerResult *res = g_slice_new0(TrackerResult); res->uri = result[i]; // res->tags = tracker_keywords_get(app->tracker, SERVICE_FILES, res->uri, NULL); gtk_list_store_append(app->results, &iter); gtk_list_store_set(app->results, &iter, 0, res, -1); } } static void start_search(const gchar *text, TrackerSearch *app) { /* no text was given, don't bug trackerd */ if(*text == '\0') return; tracker_search_text_async(app->tracker, -1, SERVICE_FILES, text, 0, 20, TRUE, (TrackerArrayReply)search_result_callback, (gpointer)app); } /** * GUI callbacks */ static gboolean entry_focus_out_event(GtkEntry *entry, GdkEventFocus *event, TrackerSearch *app) { start_search(gtk_entry_get_text(entry), app); return FALSE; } static gboolean entry_key_press_event(GtkEntry *entry, GdkEventKey *event, TrackerSearch *app) { if(event->keyval == GDK_Return && event->type == GDK_KEY_PRESS) { start_search(gtk_entry_get_text(entry), app); } return FALSE; } static void entry_notify_text(GtkEntry *entry, GParamSpec pspec, TrackerSearch *app) { start_search(gtk_entry_get_text(entry), app); } static void search_clicked(GtkButton *button, TrackerSearch *app) { start_search(gtk_entry_get_text(GTK_ENTRY(app->entry)), app); } static void clear_clicked(GtkButton *button, TrackerSearch *app) { gtk_entry_set_text(GTK_ENTRY(app->entry), ""); // should we also clear the list of results? } /** * eventually, to allow some cool manipulation of the text before putting it in a cell */ static void pretty_print(GtkTreeViewColumn *col, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, TrackerSearch *app) { TrackerResult *result; GString *string; int i = 0; gtk_tree_model_get(model, iter, 0, &result, -1); string = g_string_new(result->uri); if(result->tags && result->tags[0]) { g_string_append_printf(string, "\n"); for(i = 0; i < 3 && result->tags[i]; i++) g_string_append_printf(string, "%s ", result->tags[i]); } g_object_set(cell, "text", string->str, NULL); g_string_free(string, TRUE); } /** * main GUI code */ static void make_window(TrackerSearch *app) { GtkWidget *treeview, *vbox, *hbox, *label, *clear, *search, *statusbar; GtkTreeViewColumn *col; GtkCellRenderer *cell; app->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); app->entry = gtk_entry_new(); gtk_window_set_default_size(GTK_WINDOW(app->window), 300, 400); hbox = gtk_hbox_new(FALSE, 6); label = gtk_label_new("Search:"); search = gtk_button_new_from_stock(GTK_STOCK_FIND); clear = gtk_button_new_from_stock(GTK_STOCK_CLEAR); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), app->entry, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), search, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), clear, FALSE, FALSE, 0); vbox = gtk_vbox_new(FALSE, 6); treeview = gtk_tree_view_new(); statusbar = gtk_statusbar_new(); col = gtk_tree_view_column_new(); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), col); /* for rendering thumbnails */ cell = gtk_cell_renderer_pixbuf_new(); g_object_set(cell, "cell-background", "azure2", "cell-background-set", TRUE, NULL); gtk_tree_view_column_pack_start(col, cell, TRUE); /* for displaying result info */ cell = gtk_cell_renderer_text_new(); g_object_set(cell, "cell-background", "white", "cell-background-set", TRUE, NULL); gtk_tree_view_column_pack_start(col, cell, TRUE); gtk_tree_view_column_set_cell_data_func(col, cell, (GtkTreeCellDataFunc)pretty_print, app, NULL); gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(app->results)); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), treeview, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0); /* should we search when the entry loses focus? */ // g_signal_connect(G_OBJECT(app->entry), "focus-out-event", G_CALLBACK(entry_focus_out_event), app); /* should we do a "live-update" search where every keypress triggers a search? */ // g_signal_connect(G_OBJECT(app->entry), "notify::text", G_CALLBACK(entry_notify_text), app); g_signal_connect(G_OBJECT(app->entry), "key-press-event", G_CALLBACK(entry_key_press_event), app); g_signal_connect(G_OBJECT(search), "clicked", G_CALLBACK(search_clicked), app); g_signal_connect(G_OBJECT(clear), "clicked", G_CALLBACK(clear_clicked), app); g_signal_connect_swapped(G_OBJECT(app->window), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_container_add(GTK_CONTAINER(app->window), vbox); gtk_widget_show_all(app->window); } int main(int argc, char *argv[]) { TrackerSearch app; gtk_init(&argc, &argv); app.tracker = tracker_connect(FALSE); /* list store to hold the results, which are all pointers to 'TrackerResult's */ app.results = gtk_list_store_new(1, G_TYPE_POINTER); make_window(&app); gtk_main(); tracker_disconnect(app.tracker); return 0; }