// example-liststore.c // gcc -Wall `pkg-config --cflags --libs gtk+-2.0` -o liststore-demo example-liststore.c // This is the only header that you need for the basic gtk library #include #include // this function is now called when the User selects a file from the list void GetInfo(GtkTreeSelection*, GtkLabel**); // This is used by the "drag-and-drop" interface #define NDTYPE 1 // Number of "Drop Types" static GtkTargetEntry dtype[NDTYPE] = { // Drop Types { "text/uri-list", 0, 0 } }; // prototype for "drag-and-drop" function void DropFiles(GtkWidget*, GdkDragContext*, int, int, GtkSelectionData*, int, int, GtkListStore*); // prototype for "file selector" function void SelectFile(GtkWidget*, GtkListStore*); // prototype for "about dialog" function void AboutDialog(GtkWidget*); int main (int argc, char** argv) { GtkWidget* mwin; // Main Window GtkWidget* vbox; // gonna pack widgets in this GdkPixbuf* icon; // Hello, this is new! // wake the beast gtk_init (&argc, &argv); // load the Apply icon from the default theme, look this up icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default(), "gtk-apply", 48, GTK_ICON_LOOKUP_FORCE_SIZE, NULL); // the size "48" will be used in the About Dialog if(icon) { // this sets the icon in the title bar and About Dialog gtk_window_set_default_icon (icon); // we no longer need the pixbuf g_object_unref (icon); } // create the window mwin = gtk_window_new (GTK_WINDOW_TOPLEVEL); // obvious API functions gtk_window_set_title ((GtkWindow*)mwin, "Label-Demo"); gtk_container_set_border_width ((GtkContainer*)mwin, 2); // make sure the list has a reasonable width gtk_window_set_default_size ((GtkWindow*)mwin, 480, -1); // center on screen gtk_window_set_position ((GtkWindow*)mwin, GTK_WIN_POS_CENTER); GtkWidget *wvbox, *hbox, *bling; // we now add these first wvbox = gtk_vbox_new (FALSE, 2); gtk_container_add ((GtkContainer*)mwin, wvbox); hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start ((GtkBox*)wvbox, hbox, TRUE, TRUE, 0); bling = gtk_label_new ("" " Rabid Examples "); gtk_box_pack_start ((GtkBox*)hbox, bling, FALSE, FALSE, 0); gtk_label_set_use_markup ((GtkLabel*)bling, TRUE); gtk_label_set_angle ((GtkLabel*)bling, 90.0); // GtkLabel is derived from GtkMisc gtk_misc_set_padding ((GtkMisc*)bling, 4, 0); // create a scrollable list GtkWidget *scroll, *tree; GtkListStore* store; // the scrolling thing scroll = gtk_scrolled_window_new (NULL, NULL); gtk_box_pack_start ((GtkBox*)hbox, scroll, TRUE, TRUE, 0); gtk_scrolled_window_set_policy ((GtkScrolledWindow*)scroll, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type ((GtkScrolledWindow*)scroll, GTK_SHADOW_IN); // create the list model with 5 elements // filename size mtime IsDir fullpath store = gtk_list_store_new (5, G_TYPE_STRING, G_TYPE_INT64, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING); // the list widget tree = gtk_tree_view_new (); gtk_container_add ((GtkContainer*)scroll, tree); gtk_tree_view_set_model ((GtkTreeView*)tree, (GtkTreeModel*)store); // the TreeView now has the model, we do not need the reference g_object_unref (store); // get the tooltip from element 4 of the model gtk_tree_view_set_tooltip_column ((GtkTreeView*)tree, 4); // add a column to the list using element 0 of the model GtkCellRenderer* ren; GtkTreeViewColumn* tcol; ren = gtk_cell_renderer_text_new (); tcol = gtk_tree_view_column_new_with_attributes ("Filename", ren, "text", 0, NULL); gtk_tree_view_append_column ((GtkTreeView*)tree, tcol); // Allow alphabetic sort of the filenames gtk_tree_view_column_set_sort_column_id ((GtkTreeViewColumn*)tcol, 0); // create a layout box, look this up vbox = gtk_vbox_new (FALSE, 2); // the vbox is now packed into the hbox // the scroll expand to fill the window gtk_box_pack_start ((GtkBox*)hbox, vbox, FALSE, FALSE, 2); // make some label widgets GtkWidget* label[4]; label[0] = gtk_label_new (NULL); // pack it into the box, look this up too gtk_box_pack_start ((GtkBox*)vbox, label[0], FALSE, FALSE, 2); label[1] = gtk_label_new (NULL); gtk_box_pack_start ((GtkBox*)vbox, label[1], FALSE, FALSE, 2); label[2] = gtk_label_new (NULL); gtk_box_pack_start ((GtkBox*)vbox, label[2], FALSE, FALSE, 2); // make this one fancy gtk_label_set_selectable ((GtkLabel*)label[2], TRUE); // this label now has a maximum size label[3] = gtk_label_new (" "); gtk_box_pack_start ((GtkBox*)vbox, label[3], FALSE, FALSE, 2); gtk_label_set_selectable ((GtkLabel*)label[3], TRUE); // prevent this label from resizing the window gtk_label_set_ellipsize ((GtkLabel*)label[3], PANGO_ELLIPSIZE_MIDDLE); gtk_label_set_width_chars ((GtkLabel*)label[3], 24); GtkTreeSelection* tsel; // update the labels when the user selects a filename tsel = gtk_tree_view_get_selection ((GtkTreeView*)tree); g_signal_connect (tsel, "changed", G_CALLBACK(GetInfo), label); // add some buttons GtkWidget *bbox, *btn; // the buttonbox makes all the child widgets the same size bbox = gtk_hbutton_box_new (); // bbox is packed into wvbox gtk_box_pack_start ((GtkBox*)wvbox, bbox, FALSE, FALSE, 0); // make it pretty gtk_button_box_set_layout ((GtkButtonBox*)bbox, GTK_BUTTONBOX_CENTER); // buttonbox ignores the "gtk_box_pack" parameters // so we just use the container defaults btn = gtk_button_new_with_mnemonic ("_Select"); gtk_container_add ((GtkContainer*)bbox, btn); // call the function when the User clicks the button g_signal_connect (btn, "clicked", G_CALLBACK(SelectFile), store); // bbox has aaumed the reference to btn, so we can reuse the variable name btn = gtk_button_new_with_mnemonic ("_About"); gtk_container_add ((GtkContainer*)bbox, btn); g_signal_connect (btn, "clicked", G_CALLBACK(AboutDialog), NULL); btn = gtk_button_new_with_mnemonic ("_Quit"); gtk_container_add ((GtkContainer*)bbox, btn); g_signal_connect (btn, "clicked", G_CALLBACK(gtk_main_quit), NULL); // allow drag-and-drop on the list gtk_drag_dest_set (tree, GTK_DEST_DEFAULT_ALL, dtype, NDTYPE, GDK_ACTION_COPY); // add the filenames when it happens g_signal_connect (tree, "drag_data_received", G_CALLBACK(DropFiles), store); // exit main loop when the window is closed g_signal_connect (mwin, "delete-event", G_CALLBACK(gtk_main_quit), NULL); // show all the stuff added to the window gtk_widget_show_all (mwin); gtk_main (); // run the main loop return 0; // it's all good! } void GetInfo(GtkTreeSelection* tsel, GtkLabel** label) { char *sBase = NULL, *sSize = NULL, *sDate = NULL, *sPath = NULL; GtkTreeIter iter; if(gtk_tree_selection_get_selected (tsel, NULL, &iter)) { GtkTreeView* tree; GtkTreeModel* model; int64_t isize; int idir; time_t mtime; struct tm* lt; tree = gtk_tree_selection_get_tree_view (tsel); model = gtk_tree_view_get_model (tree); gtk_tree_model_get (model, &iter, 0, &sBase, 1, (int64_t*)&isize, 2, (time_t*)&mtime, 3, &idir, 4, &sPath, -1); // this is a useful function from GLib Miscellaneous Utility Functions if(!idir) sSize = g_format_size_full (isize, G_FORMAT_SIZE_LONG_FORMAT | G_FORMAT_SIZE_IEC_UNITS); else sSize = g_strdup ("Directory"); // show the date in a human-readable format lt = localtime(&mtime); // add some Pango markup to this one sDate = g_strdup_printf ("Modified: %02i/%02i/%i", lt->tm_mon+1, lt->tm_mday, lt->tm_year-100); } gtk_label_set_text (label[0], sBase); g_free (sBase); gtk_label_set_text (label[1], sSize); g_free (sSize); gtk_label_set_text (label[2], sDate); gtk_label_set_use_markup ((GtkLabel*)label[2], TRUE); g_free (sDate); // the extra label shows the file's path gtk_label_set_text (label[3], sPath); g_free (sPath); } void AddFile(char* sFile, GtkListStore* store) { // add or update file info int ix, ifiles, inew = TRUE; char *sPath, *sBase; struct stat sb; GtkTreeIter iter; // convenience variable GtkTreeModel* model = (GtkTreeModel*)store; stat(sFile, &sb); ifiles = gtk_tree_model_iter_n_children (model, NULL); for(ix = 0; ix < ifiles; ix++) { // is this file already in the list? gtk_tree_model_iter_nth_child (model, &iter, NULL, ix); gtk_tree_model_get (model, &iter, 4, &sPath, -1); inew = g_strcmp0 (sFile, sPath); g_free (sPath); if(!inew) break; // found it! } // not found, add to the list if(inew) gtk_list_store_append (store, &iter); sBase = g_path_get_basename (sFile); sPath = g_path_get_dirname (sFile); gtk_list_store_set (store, &iter, 0, sBase, 1, (int64_t)sb.st_size, 2, sb.st_mtime, 3, S_ISDIR(sb.st_mode), 4, sPath, -1); g_free (sPath); g_free (sBase); } void DropFiles(GtkWidget* w, GdkDragContext* context, int x, int y, GtkSelectionData* data, int info, int time, GtkListStore* store) { // User dropped files, do something! char **sDrop, *sFile; int ix = 0; // get the list of uris dropped on the window sDrop = gtk_selection_data_get_uris (data); while(sDrop[ix]) { // we need the filename of all the files sFile = g_filename_from_uri (sDrop[ix++], NULL, NULL); AddFile(sFile, store); g_free (sFile); } // we are done with this stuff g_strfreev (sDrop); gtk_drag_finish (context, TRUE, FALSE, time); } void SelectFile(GtkWidget* w, GtkListStore* store) { GtkWidget *fcd, *btn, *img; fcd = gtk_file_chooser_dialog_new ("Select File", NULL, GTK_FILE_CHOOSER_ACTION_OPEN, NULL, NULL); // allow multi-select gtk_file_chooser_set_select_multiple ((GtkFileChooser*)fcd, TRUE); // we prefer not to use STOCK buttons btn = gtk_dialog_add_button ((GtkDialog*)fcd, "_Okay", GTK_RESPONSE_OK); img = gtk_image_new_from_icon_name ("gtk-ok", GTK_ICON_SIZE_BUTTON); gtk_button_set_image ((GtkButton*)btn, img); btn = gtk_dialog_add_button ((GtkDialog*)fcd, "_Cancel", GTK_RESPONSE_CANCEL); img = gtk_image_new_from_icon_name ("gtk-cancel", GTK_ICON_SIZE_BUTTON); gtk_button_set_image ((GtkButton*)btn, img); if(gtk_dialog_run ((GtkDialog*)fcd) == GTK_RESPONSE_OK) { // we're only interested if the User clicks "Okay" GSList* flist = NULL; // look this up flist = gtk_file_chooser_get_filenames ((GtkFileChooser*)fcd); GSList* nxt = flist; while(nxt) { // iterate the list AddFile(nxt->data, store); nxt = nxt->next; } g_slist_free_full (flist, g_free); } gtk_widget_destroy (fcd); } void AboutDialog(GtkWidget* w) { // look this up char* sURL = "http://kotex.iwarp.com/code"; GtkWidget* about; about = gtk_about_dialog_new (); gtk_about_dialog_set_version ((GtkAboutDialog*)about, "Version 2.0"); gtk_about_dialog_set_website ((GtkAboutDialog*)about, sURL); gtk_about_dialog_set_website_label ((GtkAboutDialog*)about, "Rabid GTK Examples"); gtk_dialog_run ((GtkDialog*)about); gtk_widget_destroy (about); }