"Fossies" - the Fresh Open Source Software Archive

Member "xarchive-0.2.8-6/src/widgets_gtk.c" (27 Feb 2006, 63979 Bytes) of package /linux/privat/old/xarchive-0.2.8-6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "widgets_gtk.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  *  widgets_gtk.c - main gtk widgets for xarchive 
    3  *  Copyright (C) 2005 Lee Bigelow <ligelowbee@yahoo.com> 
    4  *
    5  *  This program is free software; you can redistribute it and/or modify
    6  *  it under the terms of the GNU General Public License as published by
    7  *  the Free Software Foundation; either version 2 of the License, or
    8  *  (at your option) any later version.
    9  *
   10  *  This program is distributed in the hope that it will be useful,
   11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13  *  GNU General Public License for more details.
   14  *
   15  *  You should have received a copy of the GNU General Public License
   16  *  along with this program; if not, write to the Free Software
   17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   18  */
   19 #include"widgets_gtk.h"
   20 
   21 #ifndef HAVE_CANONICALIZE_FILE_NAME
   22 /* from main.c */
   23 char *
   24 canonicalize_file_name(char *path);
   25 #endif
   26 #ifndef HAVE_GETLINE
   27 ssize_t
   28 getline(char **lineptr, size_t *n, FILE *stream);
   29 #endif
   30 /***********************/
   31 /* tree view functions */
   32 /***********************/
   33 void
   34 start_myfc_onDragDataRecived(GtkWidget *widget,
   35                  GdkDragContext *context,
   36                  int x, int y,
   37                  GtkSelectionData *seldata,
   38                  guint info, guint time,
   39                  gpointer userdata)
   40 {
   41   GtkListStore *myfc_ls;
   42   GtkTreeIter iter;
   43   gchar **uri_list;
   44   gchar *hostname;
   45   gchar *filename;
   46   gint i;
   47   
   48   myfc_ls = make_myfc_ls();
   49   uri_list = gtk_selection_data_get_uris(seldata);
   50   for(i=0; uri_list[i] != NULL; i++)
   51   {
   52     filename = g_filename_from_uri(uri_list[i], &hostname, NULL);
   53     if ( filename != NULL && g_file_test(filename, G_FILE_TEST_EXISTS) )
   54      myfc_add_foreach_func(filename, myfc_ls);
   55     g_free(filename);
   56   }
   57   
   58   if (uri_list != NULL) g_strfreev(uri_list);
   59   if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(myfc_ls), &iter) == TRUE)
   60     add_cb(NULL, (gpointer) myfc_ls);
   61   else
   62     g_object_unref(myfc_ls);
   63   
   64 }
   65 
   66 gboolean
   67 my_search_equal_func(GtkTreeModel *model,
   68          gint column,
   69          const gchar *key,
   70          GtkTreeIter *iter,
   71          gpointer search_data)
   72 {
   73   gchar *haystack;
   74   gboolean res;
   75   
   76   gtk_tree_model_get(model, iter, COL_DFILE, &haystack, -1);
   77 
   78   res = (strcasestr(haystack, key) == NULL);
   79   g_free(haystack);
   80   
   81   return res;
   82 }
   83 
   84 void 
   85 render_cols(GtkTreeView *view, gchar *title, gint mcol)
   86 {
   87   /* mcol is the liststore model coluumn. 
   88    * tvcol is the treeview column. 
   89    * Make a renderer to link the two, set the col header,
   90    * and make the column sortable.
   91    */
   92 
   93   GtkTreeViewColumn   *tvcol; 
   94   GtkCellRenderer     *renderer;
   95 
   96   tvcol = gtk_tree_view_column_new();
   97   if (mcol == COL_DFILE)
   98   {
   99     renderer = gtk_cell_renderer_pixbuf_new();
  100     gtk_tree_view_column_pack_start(tvcol, renderer, FALSE);
  101     gtk_tree_view_column_add_attribute(tvcol, renderer, 
  102                                        "stock-id", COL_ICON);
  103   }
  104   renderer = gtk_cell_renderer_text_new();
  105   gtk_tree_view_column_pack_start(tvcol, renderer, TRUE);
  106   gtk_tree_view_column_add_attribute(tvcol, renderer, "text", mcol);
  107   gtk_tree_view_column_set_title(tvcol, title);
  108 
  109   switch ( mcol ) 
  110   {
  111     case COL_DFILE:
  112       gtk_tree_view_column_set_sizing(tvcol, GTK_TREE_VIEW_COLUMN_FIXED);
  113       gtk_tree_view_column_set_fixed_width(tvcol, 300);
  114       break;
  115     case COL_LINK:
  116       gtk_tree_view_column_set_sizing(tvcol, GTK_TREE_VIEW_COLUMN_FIXED);
  117       gtk_tree_view_column_set_fixed_width(tvcol, 60);
  118       break;
  119   }
  120 
  121   gtk_tree_view_column_set_resizable(tvcol, TRUE);
  122   gtk_tree_view_append_column(view, tvcol);
  123 
  124   gtk_tree_view_column_set_sort_column_id(tvcol, mcol); 
  125 }
  126 
  127 GtkListStore *
  128 make_liststore(void)
  129 {
  130   GtkListStore *liststore;
  131 
  132   /* icon, file, dfile, size, attr, user, group, time, link */ 
  133   liststore = gtk_list_store_new(NUM_COLS, G_TYPE_STRING, G_TYPE_STRING, 
  134                                  G_TYPE_STRING, G_TYPE_ULONG, 
  135                                  G_TYPE_STRING, G_TYPE_STRING,
  136                                  G_TYPE_STRING, G_TYPE_STRING,
  137                                  G_TYPE_STRING);
  138 
  139   return liststore;
  140 }
  141 
  142 GtkWidget *
  143 make_tree(GtkListStore *liststore)
  144 {
  145   /* Make an empty treeview attached to liststore.
  146    * Then attach a renderer to each column in the view.*/
  147   GtkTreeView *treeview;
  148   GtkTreeSelection *sel; 
  149   enum { TARGET_URI };
  150   GtkTargetEntry targetentries[] =
  151     {
  152       { "text/uri-list", 0, TARGET_URI },
  153     };
  154 
  155   treeview = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(liststore)));
  156 
  157   gtk_tree_view_set_rules_hint(treeview, TRUE);
  158 
  159   sel = gtk_tree_view_get_selection(treeview);
  160   gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
  161   gtk_tree_selection_set_select_function(sel,
  162                                          (GtkTreeSelectionFunc)test_selection_func,
  163                                          NULL, NULL);
  164   render_cols(treeview, "File", COL_DFILE);
  165   render_cols(treeview, "SymLink", COL_LINK);
  166   render_cols(treeview, "Size", COL_SIZE);
  167   render_cols(treeview, "Permissions", COL_ATTR);
  168   render_cols(treeview, "User", COL_USER);
  169   render_cols(treeview, "Group", COL_GROUP);
  170   render_cols(treeview, "Time", COL_TIME);
  171 
  172   gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore), 
  173                                        COL_DFILE, GTK_SORT_ASCENDING);
  174   gtk_tree_view_set_search_column(treeview, COL_DFILE);
  175   gtk_tree_view_set_enable_search(treeview, TRUE);
  176   gtk_tree_view_set_search_equal_func(treeview,
  177                       (GtkTreeViewSearchEqualFunc) my_search_equal_func,
  178                       NULL, NULL);
  179   /* setup drag and drop attributes */
  180   gtk_drag_dest_set(GTK_WIDGET(treeview),
  181             GTK_DEST_DEFAULT_ALL,
  182             targetentries, 1,
  183             GDK_ACTION_COPY|GDK_ACTION_MOVE);
  184   g_signal_connect(GTK_WIDGET(treeview),
  185            "drag_data_received",
  186            G_CALLBACK(start_myfc_onDragDataRecived),
  187            NULL);
  188   return GTK_WIDGET(treeview);
  189 }
  190 
  191 GtkTreeView *
  192 get_current_tree(void)
  193 {
  194   /* current notebook page contains a scrollwindow,
  195    * from which we get the current treeview.
  196    */
  197   gint page;
  198   GtkWidget *scrollwin;
  199   GtkWidget *treeview;
  200     
  201   if ( (page = gtk_notebook_get_current_page(NOTEBOOK)) < 0) return NULL;
  202   scrollwin = gtk_notebook_get_nth_page(NOTEBOOK, page); 
  203   treeview = gtk_bin_get_child(GTK_BIN(scrollwin)); 
  204     
  205   return GTK_TREE_VIEW(treeview);
  206 }
  207 
  208 gchar *
  209 get_current_archive(void)
  210 {
  211   /* current notebook page contains scrollwindow,
  212    * the archive path from it's label */
  213   GtkTreeView *treeview;
  214   GtkTreeModel *liststore;
  215   gchar *archive;
  216     
  217   if ( (treeview = get_current_tree()) != NULL)
  218   { 
  219     liststore = gtk_tree_view_get_model(treeview);
  220     archive = (gchar *) g_object_get_data(G_OBJECT(liststore), 
  221                                           "archive_path");
  222     return archive;
  223   }
  224   return NULL;
  225 }
  226     
  227 void 
  228 add_row(GtkListStore *liststore, gchar **ent)
  229 {
  230   /* add a row to the liststore model attached to the treeview on 
  231    * the current notebook page.
  232    */
  233   enum {name=0,size,attr,user,group,date,time,link,num_ent};
  234   GtkTreeIter iter;
  235   gchar *icon = GTK_STOCK_FILE;
  236   gchar *dfname;
  237   gchar time_string[20];
  238   
  239   sprintf(time_string, "%s %s", ent[date], ent[time]);
  240   
  241   dfname = g_filename_display_name(ent[name]);
  242   if (g_str_has_prefix(ent[attr],"d") == TRUE)
  243   {
  244     icon=GTK_STOCK_DIRECTORY;
  245   } 
  246     
  247   gtk_list_store_append(liststore, &iter);
  248   gtk_list_store_set(liststore, &iter,
  249                      COL_ICON, icon,
  250                      COL_FILE, ent[name],
  251                      COL_DFILE, dfname,
  252                      COL_SIZE, strtoul(ent[size],NULL,10),
  253                      COL_ATTR, ent[attr],
  254                      COL_USER, ent[user],
  255                      COL_GROUP, ent[group],
  256                      COL_TIME, time_string,
  257                      COL_LINK, ent[link],
  258                      -1); 
  259   g_free(dfname);
  260 }
  261 
  262 void 
  263 reload_current_tree(GtkTreeView *treeview)
  264 {
  265   /* clear liststore, then reload
  266    * data from archive */
  267   GtkTreeModel *liststore;
  268   gchar *argv[4]; /* wrapper, option, archive, NULL */
  269 
  270   argv[ARCHIVE_INDEX] = g_strdup(get_current_archive());
  271   argv[ARCHIVE_INDEX + 1] = NULL;
  272   liststore = gtk_tree_view_get_model(treeview); 
  273   gtk_list_store_clear(GTK_LIST_STORE(liststore));
  274   /* reload archive data */
  275   if (wrapper_cmd(AR_OPEN, argv, NULL) < 0) 
  276   {
  277     close_cb(NULL, NULL);
  278   }
  279 }
  280 
  281 gboolean
  282 treeview_button_press(GtkWidget  *container,
  283                       GdkEventButton *event,
  284                       GtkUIManager *uimanager)
  285 {
  286   gtk_widget_grab_focus (container);
  287       
  288   if (event->button == 3 && event->type == GDK_BUTTON_PRESS) 
  289   {
  290     GtkWidget *menu = gtk_ui_manager_get_widget(uimanager, 
  291                                                 "/treeview_popup");
  292     if (GTK_IS_MENU (menu)) 
  293     {
  294       gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, 
  295                       container, 3, event->time);
  296       return TRUE;
  297     }
  298   }
  299   else if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
  300     double_click_cb();
  301 
  302   return FALSE;
  303 }
  304 
  305 /**********************/
  306 /* notebook functions */
  307 /**********************/
  308 void 
  309 make_notebook_widgets(GtkWidget *container)
  310 {
  311   NOTEBOOK = GTK_NOTEBOOK(gtk_notebook_new());
  312   get_default_handler();
  313   get_lastdir();
  314   gtk_box_pack_end(GTK_BOX(container), GTK_WIDGET(NOTEBOOK),TRUE,TRUE,0);
  315   gtk_notebook_set_tab_pos(NOTEBOOK, GTK_POS_TOP);
  316   gtk_notebook_set_show_tabs(NOTEBOOK, TRUE);
  317   gtk_notebook_set_scrollable(NOTEBOOK, TRUE);
  318   gtk_notebook_popup_enable(NOTEBOOK); 
  319 }
  320 
  321 void 
  322 add_page(gchar *archive)
  323 {
  324   /* Add a page to the end of the notebook and make it active.
  325    * Page contains a scrolled window with a treeview in it.
  326    * Then get the data for the treeview model.
  327    */ 
  328 
  329   GtkWidget *label, *image, *hbox, *button, *scrollw, *treeview;
  330   GtkListStore *liststore;
  331   GtkTooltips *button_tips = gtk_tooltips_new();
  332   gchar *archive_path;
  333   gchar *archive_disp;
  334   gchar **argv;
  335 
  336   /* hide empty page and show notebook if neccessary */
  337   if (gtk_notebook_get_current_page(NOTEBOOK) < 0)
  338   {
  339     gtk_widget_hide(EMPTY);
  340     gtk_widget_show(GTK_WIDGET(NOTEBOOK));
  341   }
  342   
  343   archive_path = g_strdup(archive);
  344   archive_disp = g_filename_display_name(archive_path);
  345   /* make scrollw and it's label, then append to notebook and make
  346    * it the current active page */
  347   scrollw = gtk_scrolled_window_new(NULL, NULL);
  348   gtk_widget_show(scrollw);
  349   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollw),
  350                                  GTK_POLICY_AUTOMATIC,
  351                                  GTK_POLICY_AUTOMATIC);
  352 
  353   hbox = gtk_hbox_new(FALSE, 2);
  354 
  355   label = gtk_label_new(archive_disp);
  356   g_free(archive_disp);
  357   gtk_label_set_max_width_chars(GTK_LABEL(label), 50);
  358   gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_START);
  359   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
  360 
  361   button = gtk_button_new();
  362   gtk_tooltips_set_tip(button_tips, button,
  363                        "Close Archive", NULL);
  364   g_signal_connect(G_OBJECT(button), "clicked", 
  365                    G_CALLBACK(close_button_cb), (gpointer) scrollw);
  366   image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
  367   gtk_widget_set_size_request(image, 8, 8);
  368   gtk_container_add(GTK_CONTAINER(button), image);
  369   gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
  370   gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
  371   gtk_widget_show_all(hbox);
  372 
  373   gtk_notebook_append_page(NOTEBOOK, scrollw, hbox); 
  374   gtk_notebook_set_current_page(NOTEBOOK, -1);
  375 
  376   /* make treeview with attached liststore model and add to scrollw */
  377   liststore = make_liststore();
  378   g_object_set_data(G_OBJECT(liststore), "archive_path", 
  379                     (gpointer) archive_path);
  380   treeview = make_tree(liststore);
  381   g_object_unref(liststore);
  382   gtk_container_add(GTK_CONTAINER(scrollw), treeview);
  383   gtk_widget_show(treeview);
  384   g_signal_connect(treeview, "button_press_event", 
  385                    G_CALLBACK(treeview_button_press),
  386                    UIMANAGER);
  387 
  388   /* read in archive data, or close the page if it fails */
  389   argv = g_new(gchar *, 4); /* wrapper, option, archive, NULL */
  390   argv[ARCHIVE_INDEX] = g_strdup(archive_path);
  391   argv[FIRST_FILE_INDEX] = NULL;
  392   
  393   if (wrapper_cmd(AR_OPEN, argv, NULL) < 0) 
  394   {
  395     close_cb(NULL, NULL);
  396   }
  397   else
  398   {
  399     gchar *lastdir, *lastdir_path;
  400     FILE *lastdir_file;
  401 
  402     lastdir = (gchar *) g_object_get_data(G_OBJECT(NOTEBOOK), "lastdir");
  403     lastdir_path = (gchar *) g_object_get_data(G_OBJECT(NOTEBOOK), 
  404                                                "lastdir_path");
  405     g_free(lastdir);
  406     lastdir = g_path_get_dirname(archive_path);
  407     g_object_set_data(G_OBJECT(NOTEBOOK), "lastdir", (gpointer) g_path_get_dirname(archive_path));
  408     lastdir_file = g_fopen(lastdir_path, "w");
  409     fputs(lastdir, lastdir_file);
  410     fputs("\n", lastdir_file);
  411     fclose(lastdir_file);
  412   }
  413   g_strfreev(argv);
  414 } 
  415    
  416 /************************************/
  417 /* emtpy page and message functions */
  418 /************************************/
  419 void
  420 setup_opening_progress_bar(GtkWidget *pbwin, GtkWidget *pbar, gboolean *stopit)
  421 {
  422   GtkWidget *vbox, *label, *button;
  423 
  424   g_signal_connect(G_OBJECT(pbwin), "delete_event", 
  425                    G_CALLBACK(gtk_true), NULL);
  426   gtk_window_set_modal(GTK_WINDOW(pbwin), TRUE);
  427   gtk_window_set_transient_for(GTK_WINDOW(pbwin), GTK_WINDOW(MAIN_WINDOW));
  428   gtk_window_set_title(GTK_WINDOW(pbwin), "Reading...");
  429     
  430   vbox = gtk_vbox_new(FALSE, 2);
  431   gtk_container_add(GTK_CONTAINER(pbwin), vbox);
  432   
  433   label = gtk_label_new("Please wait, reading file...");
  434   gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
  435   
  436   gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(pbar), 0.2);
  437   gtk_box_pack_start(GTK_BOX(vbox), pbar, TRUE, TRUE, 0);
  438   
  439   button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
  440   g_signal_connect(G_OBJECT(button), "clicked", 
  441                    G_CALLBACK(open_cancel_cb),
  442                    (gpointer) stopit);
  443   gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
  444 
  445   gtk_widget_show_all(pbwin);
  446 }  
  447 
  448 void
  449 wait_with_progress_bar(GPid pid, gint *wrapper_status, gint ar_func)
  450 {
  451   GtkWidget *pbwin, *pbar, *label, *button, *vbox;
  452   gchar *msg;
  453   gint process_status = 0;
  454   gboolean waiting = TRUE;
  455   
  456   pbwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  457   g_signal_connect(G_OBJECT(pbwin), "delete_event",
  458                  G_CALLBACK(gtk_true),
  459                  NULL);
  460   gtk_window_set_modal(GTK_WINDOW(pbwin), TRUE);
  461   gtk_window_set_transient_for(GTK_WINDOW(pbwin), GTK_WINDOW(MAIN_WINDOW));
  462   gtk_window_set_title(GTK_WINDOW(pbwin), "Working...");
  463   
  464   switch (ar_func)
  465   {
  466     case AR_ADD:
  467       msg = "Please wait, adding files...";
  468       break;
  469     case AR_NEW:
  470       msg = "Please wait, creating new archive...";
  471       break;
  472     case AR_REMOVE:
  473       msg = "Please wait, removing files...";
  474       break;
  475     case AR_EXTRACT:
  476       msg = "Please wait, extracting files...";
  477       break;
  478     default:
  479       msg = "Busy, Please wait...";
  480       break;
  481   }
  482   vbox = gtk_vbox_new(FALSE, 2);
  483   gtk_container_add(GTK_CONTAINER(pbwin), vbox);
  484   
  485   label = gtk_label_new(msg);
  486   gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
  487   
  488   pbar = gtk_progress_bar_new();
  489   gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(pbar), 0.2);
  490   gtk_box_pack_start(GTK_BOX(vbox), pbar, TRUE, TRUE, 0);
  491   
  492   button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
  493   g_signal_connect(G_OBJECT(button), "clicked", 
  494                    G_CALLBACK(process_cancel_cb),
  495                    GINT_TO_POINTER(pid));
  496   gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
  497   
  498   gtk_widget_show_all(pbwin);
  499   
  500   while (waiting)
  501   { 
  502     process_status = waitpid((pid_t)pid, wrapper_status, WNOHANG);
  503     if (process_status < 0)
  504     {
  505       waiting = FALSE;
  506     }
  507     else 
  508     {
  509       gtk_progress_bar_pulse(GTK_PROGRESS_BAR(pbar));
  510       while (gtk_events_pending())
  511         gtk_main_iteration();
  512       g_usleep(200000);
  513     }
  514   }
  515   gtk_widget_destroy(pbwin);
  516   while (gtk_events_pending())
  517     gtk_main_iteration();
  518 }
  519 
  520 GtkWidget *
  521 make_info_widget(gchar *msg)
  522 {
  523   GtkWidget *scrollw, *label;
  524     
  525   scrollw = gtk_scrolled_window_new(0,0);
  526   gtk_container_set_border_width(GTK_CONTAINER(scrollw), 10);
  527   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollw),
  528                                  GTK_POLICY_AUTOMATIC,
  529                                  GTK_POLICY_AUTOMATIC);
  530   gtk_widget_show(scrollw);
  531     
  532   label = gtk_label_new(msg);
  533   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollw), label);
  534   gtk_widget_show(label);
  535 
  536   return scrollw;
  537 }
  538 
  539 void 
  540 make_empty_page(GtkWidget *container)
  541 {
  542   gchar *wrapinf;
  543 
  544   wrapinf = wrapper_info();
  545   EMPTY = make_info_widget(wrapinf);
  546   g_free(wrapinf);
  547   gtk_box_pack_end(GTK_BOX(container), EMPTY, TRUE, TRUE, 0);
  548 }
  549 
  550 gboolean 
  551 message(GtkWidget *parentwin, gint type, gchar *text)
  552 {
  553   GtkWidget *md;
  554 
  555   md = gtk_message_dialog_new(GTK_WINDOW(parentwin), 
  556                               GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
  557                               type,
  558                               GTK_BUTTONS_NONE,
  559                               text);
  560   if ( type == GTK_MESSAGE_WARNING || type == GTK_MESSAGE_QUESTION) 
  561   {
  562     gtk_dialog_add_button(GTK_DIALOG(md),
  563                           GTK_STOCK_CANCEL, 
  564                           GTK_RESPONSE_CANCEL);
  565     gtk_dialog_add_button(GTK_DIALOG(md),
  566                           GTK_STOCK_OK, 
  567                           GTK_RESPONSE_OK);
  568     gtk_dialog_set_alternative_button_order(GTK_DIALOG(md), GTK_RESPONSE_OK,
  569                                             GTK_RESPONSE_CANCEL, -1);
  570   }
  571   else
  572   {
  573     gtk_dialog_add_button(GTK_DIALOG(md),
  574                           GTK_STOCK_OK, 
  575                           GTK_RESPONSE_OK);
  576   }
  577   if( gtk_dialog_run(GTK_DIALOG(md)) == GTK_RESPONSE_OK ) 
  578   {
  579     gtk_widget_destroy(md);
  580     return TRUE;
  581   }
  582   gtk_widget_destroy(md);
  583   return FALSE;
  584 }
  585 
  586 /******************************/
  587 /* treeview foreach functions */
  588 /******************************/
  589 void 
  590 selected_foreach_func(GtkTreeModel *model,
  591                       GtkTreePath *path,
  592                       GtkTreeIter *iter,
  593                       WrapperData *wrapper)
  594 {
  595   gchar *fname;
  596   gchar *esc_fname;
  597 
  598   gtk_tree_model_get(model, iter, COL_FILE, &fname, -1);
  599   esc_fname = g_strdup(fname);
  600 
  601   wrapper->argv[wrapper->index] = esc_fname;
  602   wrapper->index++;
  603   wrapper->argv[wrapper->index] = NULL;
  604 
  605   g_free(fname);
  606 }
  607 
  608 gboolean 
  609 sel_subdir_foreach_func(GtkTreeModel *model,
  610                         GtkTreePath *path,
  611                         GtkTreeIter *iter,
  612                         SelectionData *seld)
  613 {
  614   gchar *fname;
  615 
  616   gtk_tree_model_get(model, iter, COL_FILE, &fname, -1); 
  617   if ( g_str_has_prefix(fname, seld->dname) == TRUE ) 
  618   {
  619     gtk_tree_selection_select_iter(seld->sel, iter);
  620   }
  621 
  622   g_free(fname);
  623   return FALSE;
  624 }
  625 
  626 gboolean 
  627 unsel_subdir_foreach_func(GtkTreeModel *model,
  628                         GtkTreePath *path,
  629                         GtkTreeIter *iter,
  630                         SelectionData *seld)
  631 {
  632   gchar *fname;
  633 
  634   gtk_tree_model_get(model, iter, COL_FILE, &fname, -1); 
  635   if ( g_str_has_prefix(fname, seld->dname) == TRUE ) 
  636   {
  637     gtk_tree_selection_unselect_iter(seld->sel, iter);
  638   }
  639 
  640   g_free(fname);
  641   return FALSE;
  642 }
  643 
  644 gboolean
  645 test_selection_func(GtkTreeSelection *selection,
  646                     GtkTreeModel *model,
  647                     GtkTreePath *path,
  648                     gboolean path_currently_selected,
  649                     gpointer data)
  650 {
  651   GtkTreeIter iter;
  652   SelectionData seld;
  653   gchar *icon, *fname, *dname=NULL;
  654   static gboolean skipit = FALSE;
  655 
  656   if (skipit == TRUE) 
  657     return TRUE;
  658 
  659   gtk_tree_model_get_iter(model, &iter, path);
  660   seld.sel = selection;
  661   
  662   gtk_tree_model_get(model, &iter, COL_ICON, &icon, COL_FILE, &fname, -1);
  663   if (g_str_has_prefix(icon, GTK_STOCK_DIRECTORY) == TRUE)
  664   {
  665     if (g_str_has_suffix(fname, "/") == FALSE)
  666       dname = g_strdup_printf("%s/", fname);
  667     else
  668       dname = g_strdup(fname);
  669     seld.dname = dname;
  670     seld.dirs = TRUE;
  671     skipit = TRUE;
  672     if (path_currently_selected == FALSE)
  673       gtk_tree_model_foreach(model,
  674                              (GtkTreeModelForeachFunc)sel_subdir_foreach_func,
  675                              &seld);
  676     else
  677       gtk_tree_model_foreach(model,
  678                              (GtkTreeModelForeachFunc)unsel_subdir_foreach_func,
  679                              &seld);
  680   }
  681   
  682   skipit = FALSE;
  683   g_free(icon);
  684 
  685   if (dname != NULL && strcmp(fname,dname) == 0)
  686   {
  687     g_free(fname);
  688     g_free(dname);
  689     return FALSE;
  690   }
  691   
  692   g_free(fname);
  693   if (dname != NULL) g_free(dname);
  694   
  695   return TRUE;
  696 }
  697 
  698 gboolean 
  699 add_foreach_func(GtkTreeModel *model, GtkTreePath *path, 
  700                  GtkTreeIter *iter, WrapperData *wrapper)
  701 {
  702   selected_foreach_func(model, path, iter, wrapper);
  703   return FALSE;
  704 }
  705 
  706 gboolean 
  707 file_filter_func(const GtkFileFilterInfo *filter_info, gpointer data)
  708 {
  709   gchar *fname;
  710     
  711   fname = g_strdup(filter_info->filename);
  712   if ( get_wrapper(fname) != NULL ) return TRUE;
  713   g_free(fname);
  714   return FALSE;
  715 }
  716 
  717 /*******************/
  718 /* chooser widgets */
  719 /*******************/
  720 gchar *
  721 askfor_existing_archive(void)
  722 {
  723   GtkWidget *fc;
  724   GtkFileFilter *filter;
  725   gchar *archive = NULL, *lastdir;
  726 
  727   fc = gtk_file_chooser_dialog_new("Open File",
  728                                    GTK_WINDOW(MAIN_WINDOW),
  729                                    GTK_FILE_CHOOSER_ACTION_OPEN,
  730                                    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
  731                                    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
  732                                    NULL);
  733   gtk_dialog_set_alternative_button_order(GTK_DIALOG(fc), GTK_RESPONSE_ACCEPT,
  734                                           GTK_RESPONSE_CANCEL, -1);
  735   lastdir = (gchar *)g_object_get_data(G_OBJECT(NOTEBOOK), "lastdir");
  736   printf("lastdir: %s\n", lastdir);
  737   gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fc), lastdir);
  738   filter = gtk_file_filter_new();
  739   gtk_file_filter_set_name(filter, "Only Supported");
  740   gtk_file_filter_add_custom(filter, GTK_FILE_FILTER_FILENAME, 
  741                              file_filter_func, NULL, g_free);
  742   gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fc), filter);
  743   filter = gtk_file_filter_new();
  744   gtk_file_filter_set_name(filter, "All");
  745   gtk_file_filter_add_pattern(filter, "*");
  746   gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fc), filter);
  747 
  748   if (gtk_dialog_run(GTK_DIALOG(fc)) == GTK_RESPONSE_ACCEPT) 
  749     archive = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc));
  750 
  751   gtk_widget_destroy(fc);
  752   
  753   return archive;
  754 }
  755 
  756 gchar *
  757 askfor_new_archive(gchar *name)
  758 {
  759   gchar *archive = NULL;
  760   gboolean again = TRUE;
  761   GtkWidget *fc_new;
  762   gchar *msg;
  763   
  764   fc_new = gtk_file_chooser_dialog_new("Enter New Archive Name", 
  765                                        GTK_WINDOW(MAIN_WINDOW),
  766                                        GTK_FILE_CHOOSER_ACTION_SAVE,
  767                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
  768                                        GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
  769                                        NULL);
  770   gtk_dialog_set_default_response(GTK_DIALOG(fc_new), GTK_RESPONSE_ACCEPT);
  771   gtk_dialog_set_alternative_button_order(GTK_DIALOG(fc_new),
  772                                           GTK_RESPONSE_ACCEPT,
  773                                           GTK_RESPONSE_CANCEL, -1);
  774   if (name == NULL) 
  775     name = "somename.tar.gz";
  776   gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fc_new), 
  777                                     name);
  778   while (again == TRUE)
  779   {
  780     if (gtk_dialog_run(GTK_DIALOG(fc_new)) == GTK_RESPONSE_ACCEPT) 
  781     {
  782       archive = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc_new));
  783       /* if no wrapper for archive type exits try again */
  784       if (get_wrapper(archive) == NULL)
  785       {
  786         message(fc_new,
  787         GTK_MESSAGE_ERROR, 
  788                 "Sorry, archive type not supported.\n\n"
  789                 "Please use an archive name with an\n"
  790                 "extenstion that you have a wrapper for.\n\n"
  791                 "For example:\n"
  792                 "If you have tar-wrap.sh:\n"
  793                 "\tsomename.tar.gz\n"
  794                 "If you have zip-wrap.sh:\n"
  795                 "\tsomename.zip\n");
  796         g_free(archive);
  797         archive = NULL;
  798       }
  799       /* if it already exists try again */
  800       else if (g_file_test(archive, G_FILE_TEST_EXISTS) == TRUE)
  801       {
  802         msg = g_strdup_printf("Archive %s\n"
  803                               "already exists.\n\n"
  804                               "Please pick another name, or\n"
  805                               "put archive in a different directory\n",
  806                               archive);
  807         message(fc_new,
  808         GTK_MESSAGE_ERROR, msg);
  809         g_free(msg);
  810         g_free(archive);
  811         archive = NULL;
  812       }
  813       else again = FALSE;
  814     }
  815     else
  816     {
  817       again = FALSE;
  818       archive = NULL;
  819     }
  820   }
  821   
  822   gtk_widget_destroy(GTK_WIDGET(fc_new));
  823   return archive;
  824 }
  825 
  826 gboolean
  827 multi_file_chooser(gchar *archive, GtkListStore *filelist)
  828 {
  829   GtkTreeIter iter;
  830   GtkDialog *myfc;
  831   gboolean accept = FALSE, again = TRUE;
  832 
  833   myfc = make_myfc(archive, filelist);
  834   while (again == TRUE)
  835   {
  836     if (gtk_dialog_run(myfc) == GTK_RESPONSE_ACCEPT) 
  837     {
  838       /* if no first entry, redisplay the file selector */
  839       if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filelist), 
  840                                         &iter) == FALSE) 
  841         message(GTK_WIDGET(myfc),
  842         GTK_MESSAGE_ERROR, 
  843                 "No files added to list.\n\n"
  844                 "Please try again, or cancel.");
  845       else 
  846       {
  847         again = FALSE;
  848         accept = TRUE;
  849       }
  850     }
  851     else 
  852     {
  853       again = FALSE;
  854       accept = FALSE;
  855     }
  856   }
  857 
  858   gtk_widget_destroy(GTK_WIDGET(myfc));
  859   return accept;
  860 }
  861 
  862 void
  863 select_extract_dir(GtkWidget *widget, GtkWidget *entry)
  864 {
  865   GtkWidget *fc;
  866 
  867   fc = gtk_file_chooser_dialog_new("Select Directory To Extract To", 
  868                                    GTK_WINDOW(MAIN_WINDOW),
  869                                    GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
  870                                    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
  871                                    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
  872                                    NULL);
  873   gtk_dialog_set_alternative_button_order(GTK_DIALOG(fc), GTK_RESPONSE_ACCEPT, 
  874                                           GTK_RESPONSE_CANCEL, -1);
  875   gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fc), 
  876                                   gtk_entry_get_text(GTK_ENTRY(entry)));
  877   if (gtk_dialog_run(GTK_DIALOG(fc)) == GTK_RESPONSE_ACCEPT) 
  878   {
  879     gtk_entry_set_text(GTK_ENTRY(entry), 
  880                        gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc)));
  881   }
  882 
  883   gtk_widget_destroy(fc);
  884 }
  885 
  886 gchar *
  887 askfor_extract_dir(void)
  888 {
  889   gchar *dir = NULL, *mesg;
  890   GtkWidget *idialog, *hbox, *label, *entry, *choose_button;
  891   gboolean again = TRUE;
  892 
  893   idialog = gtk_dialog_new_with_buttons("Extraction Directory",
  894                                         GTK_WINDOW(MAIN_WINDOW),
  895                                         GTK_DIALOG_MODAL | 
  896                                         GTK_DIALOG_DESTROY_WITH_PARENT,
  897                                         GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
  898                                         GTK_STOCK_OK,GTK_RESPONSE_ACCEPT,
  899                                         NULL);
  900   gtk_dialog_set_default_response(GTK_DIALOG(idialog), GTK_RESPONSE_ACCEPT);
  901   gtk_dialog_set_alternative_button_order(GTK_DIALOG(idialog), GTK_RESPONSE_ACCEPT, 
  902                                           GTK_RESPONSE_REJECT, -1);
  903   label = gtk_label_new("Enter Directory To Extract To:");
  904   hbox = gtk_hbox_new(FALSE, 1);
  905   entry = gtk_entry_new();
  906   gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
  907   gtk_entry_set_text(GTK_ENTRY(entry), 
  908                      g_path_get_dirname(get_current_archive()));
  909   gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE,1);
  910   choose_button = gtk_button_new_with_label("Choose");
  911   g_signal_connect(G_OBJECT(choose_button), "clicked", 
  912                    G_CALLBACK(select_extract_dir), entry);
  913   gtk_box_pack_start(GTK_BOX(hbox), choose_button, TRUE, TRUE,1);
  914   
  915   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(idialog)->vbox), label, TRUE, TRUE,1);
  916   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(idialog)->vbox), hbox, TRUE, TRUE,1);
  917   gtk_widget_show_all(GTK_DIALOG(idialog)->vbox);
  918   
  919   while(again == TRUE)
  920   {
  921     if (gtk_dialog_run(GTK_DIALOG(idialog)) == GTK_RESPONSE_ACCEPT) 
  922     {
  923       dir = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
  924       if (g_file_test(dir,G_FILE_TEST_IS_DIR) == FALSE)
  925       {  
  926     mesg = g_strdup_printf("Directory\n%s\nDoes not exist.\n\n"
  927                                "Shall I create it?", dir);
  928     if (message(idialog,
  929             GTK_MESSAGE_QUESTION, mesg))
  930     {
  931       if (g_mkdir(dir, S_IRWXU|S_IRWXG) != 0)
  932         message(idialog,
  933             GTK_MESSAGE_INFO, 
  934             "Sorry, could not create directory.\n\n"
  935             "If you need to create a parent dir and\n"
  936             "a subdir, create the parent first."
  937             );
  938     }
  939     g_free(mesg);
  940       }
  941       else    
  942         again = FALSE;
  943     }
  944     else
  945     {
  946       dir = NULL;
  947       again = FALSE;
  948     }
  949   }
  950   gtk_widget_destroy(idialog);
  951   return dir;
  952 }
  953 
  954 /******************************************/
  955 /* openwith and default handler functions */
  956 /******************************************/
  957 
  958 GtkListStore *
  959 get_openwith_cmdlist(gchar *cmdlist_path)
  960 {
  961   gchar *cmd;
  962   gchar *line = NULL;
  963   FILE *cmdlist_file;
  964   size_t linesize = 0;
  965   int length;
  966   GtkListStore *cmdlist;
  967   GtkTreeIter iter;
  968 
  969   if (g_file_test(cmdlist_path, G_FILE_TEST_EXISTS) == FALSE)
  970   {
  971     cmdlist_file = g_fopen(cmdlist_path, "w");
  972     fputs("xarchive\n", cmdlist_file);
  973     fclose(cmdlist_file);
  974   }
  975   cmdlist = gtk_list_store_new(1, G_TYPE_STRING); 
  976 
  977   cmdlist_file = g_fopen(cmdlist_path, "r");
  978   while ( (length = getline(&line, &linesize, cmdlist_file)) > 0)
  979   {
  980     /* strip newline from line to get command */
  981     cmd = g_strndup(line, length-1);
  982     gtk_list_store_append(cmdlist, &iter);
  983     gtk_list_store_set(cmdlist, &iter, 0, cmd, -1);
  984     g_free(cmd);
  985   }
  986   fclose(cmdlist_file);
  987 
  988   g_free(line);
  989 
  990   return cmdlist;
  991 }
  992 
  993 void
  994 add_to_cmdlist(GtkListStore *cmdlist, gchar *command, gchar *cmdlist_path)
  995 {
  996   GtkTreeIter iter;
  997   gchar *list_entry = NULL;
  998   gboolean found = FALSE;
  999   FILE *cmdlist_file;
 1000 
 1001   if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(cmdlist), &iter) == TRUE)
 1002   {
 1003     do
 1004     {
 1005       gtk_tree_model_get(GTK_TREE_MODEL(cmdlist), &iter, 
 1006                          0, &list_entry, -1);
 1007       if (strcmp(list_entry,command) == 0) 
 1008       {
 1009         found = TRUE;
 1010         gtk_list_store_move_after(cmdlist, &iter, NULL);
 1011         break;
 1012       }
 1013       g_free(list_entry);
 1014     } 
 1015     while (gtk_tree_model_iter_next(GTK_TREE_MODEL(cmdlist), &iter));        
 1016         
 1017     if (found == FALSE)
 1018     {
 1019       gtk_list_store_prepend(cmdlist, &iter);
 1020       gtk_list_store_set(cmdlist, &iter, 0, command, -1);
 1021     }
 1022 
 1023     /* save list */
 1024     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(cmdlist), &iter);
 1025     cmdlist_file = g_fopen(cmdlist_path, "w");
 1026     do
 1027     {
 1028       gtk_tree_model_get(GTK_TREE_MODEL(cmdlist), &iter,
 1029                          0, &list_entry, -1);
 1030       fputs(list_entry,cmdlist_file);
 1031       fputs("\n",cmdlist_file);
 1032       g_free(list_entry);
 1033     }
 1034     while (gtk_tree_model_iter_next(GTK_TREE_MODEL(cmdlist), &iter));
 1035     fclose(cmdlist_file);
 1036   }
 1037 }
 1038 
 1039 void
 1040 get_lastdir(void)
 1041 {
 1042   gchar *lastdir_path, *lastdir;
 1043   gchar *line = NULL;
 1044   FILE *lastdir_file;
 1045   size_t linesize = 0;
 1046   int length;
 1047 
 1048   lastdir_path = g_strdup_printf("%s/.xarchive/lastdir",getenv("HOME"));
 1049   g_object_set_data(G_OBJECT(NOTEBOOK),"lastdir_path",(gpointer)lastdir_path);
 1050   if (g_file_test(lastdir_path, G_FILE_TEST_EXISTS) == TRUE)
 1051   {
 1052     lastdir_file = g_fopen(lastdir_path, "r");
 1053     length = getline(&line, &linesize, lastdir_file);
 1054     while (line[length-1] == '\n' || line[length-1] == ' ')
 1055     {
 1056       line[length-1] = '\0';
 1057       length--;
 1058     }
 1059     fclose(lastdir_file);
 1060     g_object_set_data(G_OBJECT(NOTEBOOK),"lastdir",(gpointer)line);
 1061   }
 1062   else
 1063   {
 1064     lastdir = g_strdup_printf("%s",getenv("HOME"));
 1065     lastdir_file = g_fopen(lastdir_path, "w");
 1066     fputs(lastdir, lastdir_file);
 1067     fputs("\n", lastdir_file);
 1068     fclose(lastdir_file);
 1069     g_object_set_data(G_OBJECT(NOTEBOOK),"lastdir", (gpointer)lastdir);
 1070   }
 1071 }
 1072 
 1073 void
 1074 get_default_handler(void)
 1075 {
 1076   gchar *defhand_path;
 1077   gchar *line = NULL;
 1078   FILE *defhand_file;
 1079   size_t linesize = 0;
 1080   int length;
 1081 
 1082   defhand_path = g_strdup_printf("%s/.xarchive/default_handler",
 1083                                  getenv("HOME"));
 1084   g_object_set_data(G_OBJECT(NOTEBOOK),"defhand_path",(gpointer)defhand_path);
 1085   if (g_file_test(defhand_path, G_FILE_TEST_EXISTS) == FALSE)
 1086     return;
 1087 
 1088   defhand_file = g_fopen(defhand_path, "r");
 1089   length = getline(&line, &linesize, defhand_file);
 1090   /* strip trailing whitespace from line to get command */
 1091   /* isspace would be better if you want to #include ctype.h */
 1092   while (line[length-1] == '\n' || line[length-1] == ' ')
 1093   {
 1094     line[length-1] = '\0';
 1095     length--;
 1096   }
 1097 
 1098   fclose(defhand_file);
 1099 
 1100   g_object_set_data(G_OBJECT(NOTEBOOK),"defhand_cmd",(gpointer)line);
 1101 }
 1102 
 1103 void
 1104 set_default_handler(gchar *command)
 1105 {
 1106   gchar *defhand_path;
 1107   gchar *defhand_old_cmd;
 1108   gchar *defhand_new_cmd;
 1109   FILE *defhand_file;
 1110   
 1111   defhand_path = (gchar *)g_object_get_data(G_OBJECT(NOTEBOOK),"defhand_path");
 1112   defhand_old_cmd=(gchar *)g_object_get_data(G_OBJECT(NOTEBOOK),"defhand_cmd");
 1113   /* the passed command gets freed, so we'll store a copy */
 1114   defhand_new_cmd = g_strdup(command);
 1115 
 1116   printf("setting default handler to file %s\n", defhand_path);
 1117   defhand_file = g_fopen(defhand_path, "w");
 1118   fputs(command, defhand_file);
 1119   fputs("\n", defhand_file);
 1120   fclose(defhand_file);
 1121   
 1122   g_free(defhand_old_cmd);
 1123   g_object_set_data(G_OBJECT(NOTEBOOK),"defhand_cmd",(gpointer)defhand_new_cmd);
 1124   return;
 1125 }
 1126 
 1127 void 
 1128 open_one_file(WrapperData *wrapper, gchar *command)
 1129 {
 1130   gchar *fname;
 1131 
 1132   if (wrapper_cmd(AR_EXTRACT, wrapper->argv, wrapper->dir) == 0)
 1133   {
 1134     fname = my_strescape(wrapper->argv[FIRST_FILE_INDEX]);
 1135     gchar *viewcmd = g_strconcat(command, " ", wrapper->dir,
 1136                                  "/", fname, NULL);
 1137     g_free(fname);
 1138     printf("viewcmd: %s\n",viewcmd);
 1139     system(viewcmd);
 1140     g_free(viewcmd);
 1141   }
 1142 }
 1143 
 1144 void 
 1145 default_handler_foreach_func(GtkTreeModel *model,
 1146                              GtkTreePath  *path,
 1147                              GtkTreeIter  *iter,
 1148                              WrapperData  *wrapper)
 1149 {
 1150   gchar *fname;
 1151   gchar *defhand_cmd;
 1152   
 1153   defhand_cmd = (gchar *)g_object_get_data(G_OBJECT(NOTEBOOK),"defhand_cmd");
 1154  
 1155   /* if no cmd is set, pass off to open with dialog for setting */
 1156   if (defhand_cmd == NULL)
 1157   {
 1158     message(MAIN_WINDOW,
 1159         GTK_MESSAGE_WARNING,
 1160             "Double-clicking doesn't work until you\n"
 1161             "set your default handler using the\n"
 1162             "'set double-click default handler' flag\n"
 1163             "in the 'open with..' dialog.\n\n");
 1164     openwith_foreach_func(model, path, iter, wrapper);
 1165     return;
 1166   }
 1167 
 1168   gtk_tree_model_get(model, iter, COL_FILE, &fname, -1);
 1169 
 1170   wrapper->argv = g_new(gchar *, 5); /*wrapper, option, archive, file, NULL*/
 1171   wrapper->argv[ARCHIVE_INDEX] = g_strdup(get_current_archive());
 1172   wrapper->argv[FIRST_FILE_INDEX] = g_strdup(fname);
 1173   wrapper->argv[FIRST_FILE_INDEX + 1] = NULL;
 1174 
 1175   open_one_file(wrapper, defhand_cmd);
 1176   
 1177   g_strfreev(wrapper->argv);
 1178   g_free(fname);
 1179 }
 1180 
 1181 gchar *
 1182 askfor_openwith_command(gchar *fname)
 1183 {
 1184   GtkWidget *dialog, *label, *combobox, *checkbox;
 1185   GtkEntryCompletion *completion;
 1186   static gchar *cmdlist_path = NULL;
 1187   static GtkListStore *cmdlist = NULL;
 1188   gchar *command = NULL, *msg;
 1189   
 1190   if (cmdlist_path == NULL)
 1191     cmdlist_path = g_strdup_printf("%s/.xarchive/cmd_history",getenv("HOME"));
 1192   if (cmdlist == NULL)
 1193     cmdlist = get_openwith_cmdlist(cmdlist_path);
 1194   
 1195   dialog = gtk_dialog_new_with_buttons("Open With...",
 1196                                        GTK_WINDOW(MAIN_WINDOW),
 1197                                        GTK_DIALOG_DESTROY_WITH_PARENT,
 1198                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 1199                                        GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
 1200                                        NULL);
 1201   gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog), 
 1202                                           GTK_RESPONSE_ACCEPT,
 1203                                           GTK_RESPONSE_CANCEL, -1);
 1204   gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
 1205   msg = g_strdup_printf("Open \"%s\" with...", fname); 
 1206   label = gtk_label_new(msg);
 1207   g_free(msg);
 1208   gtk_widget_show(label);
 1209   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE,TRUE,0);
 1210 
 1211   combobox = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(cmdlist), 0);
 1212   gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0);
 1213   gtk_widget_show(combobox);
 1214   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),combobox,TRUE,TRUE,0);
 1215   
 1216   gtk_entry_set_activates_default(GTK_ENTRY(GTK_BIN(combobox)->child), 
 1217                                   TRUE);
 1218   completion = gtk_entry_completion_new();
 1219   gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(cmdlist));
 1220   gtk_entry_completion_set_text_column(completion, 0);
 1221   gtk_entry_completion_set_popup_completion(completion, TRUE);
 1222   gtk_entry_set_completion(GTK_ENTRY(GTK_BIN(combobox)->child), 
 1223                            completion);
 1224   
 1225   checkbox = gtk_check_button_new_with_label("set as default double-click handler");
 1226   gtk_widget_show(checkbox);
 1227   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),checkbox,TRUE,TRUE,0);
 1228 
 1229   msg = g_strdup_printf("Current default handler: %s", 
 1230                         (gchar *)g_object_get_data(G_OBJECT(NOTEBOOK), 
 1231                                                    "defhand_cmd"));
 1232   label = gtk_label_new(msg);
 1233   gtk_widget_show(label);
 1234   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),label,TRUE,TRUE,0);
 1235   g_free(msg);
 1236 
 1237   if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
 1238   {         
 1239     command = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(combobox)->child)));
 1240     add_to_cmdlist(cmdlist, command, cmdlist_path);
 1241     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox)) == TRUE) 
 1242       set_default_handler(command);
 1243   }
 1244   
 1245   gtk_widget_destroy(dialog);
 1246   return command;
 1247 }
 1248 
 1249 void 
 1250 openwith_foreach_func(GtkTreeModel *model,
 1251                       GtkTreePath  *path,
 1252                       GtkTreeIter  *iter,
 1253                       WrapperData  *wrapper)
 1254 {
 1255   gchar *fname, *command;
 1256       
 1257   /* see if cancel button pressed (xarchive set to null) */
 1258   if (wrapper->index == FALSE) return;
 1259 
 1260   /* esc file name */
 1261   gtk_tree_model_get(model, iter, COL_FILE, &fname, -1);
 1262    
 1263   /* display dialog asking to exatract and open fname with app */
 1264   command = askfor_openwith_command(fname);
 1265   if (command != NULL && strcmp(command, GTK_STOCK_NO) == 0)
 1266     wrapper->index = TRUE;
 1267   else if (command != NULL)
 1268   {
 1269     wrapper->argv = g_new(gchar *, 5); /*wrapper, option, archive, file, NULL*/
 1270     wrapper->argv[ARCHIVE_INDEX] = g_strdup(get_current_archive());
 1271     wrapper->argv[FIRST_FILE_INDEX] = g_strdup(fname);
 1272     wrapper->argv[FIRST_FILE_INDEX + 1] = NULL;
 1273 
 1274     open_one_file(wrapper, command);
 1275 
 1276     g_strfreev(wrapper->argv);
 1277   }
 1278   else
 1279   {
 1280     wrapper->index = FALSE;
 1281   }
 1282 
 1283   g_free(command);
 1284   g_free(fname);
 1285 }
 1286 
 1287 /**********************/
 1288 /* callback functions */
 1289 /**********************/
 1290 void
 1291 dummy_cb(GtkWidget *widget, gpointer data)
 1292 {
 1293   return;
 1294 }
 1295 
 1296 void 
 1297 open_cb(GtkWidget *widget, gpointer data)
 1298 {
 1299   gchar *archive;
 1300 
 1301   archive = askfor_existing_archive();
 1302   if (archive == NULL) return;
 1303   
 1304   add_page(archive);
 1305   g_free(archive);
 1306   
 1307 }
 1308 
 1309 void 
 1310 new_cb(GtkWidget *widget, gpointer data)
 1311 {
 1312   WrapperData wrapper;
 1313   gchar *archive;
 1314   GtkListStore *myfc_ls; /*file chooser liststore*/
 1315   GtkTreeIter iter;
 1316   gchar *name;
 1317   gint error, size;
 1318 
 1319   /* now get the files that are to be added to the new archive */
 1320   if (data == NULL)
 1321   {
 1322     archive = askfor_new_archive(NULL);
 1323     if (archive == NULL) return;
 1324     myfc_ls = make_myfc_ls();
 1325   }
 1326   else
 1327   {
 1328     myfc_ls = (GtkListStore *) data;
 1329     name = g_object_get_data(G_OBJECT(myfc_ls), "name");
 1330     archive = askfor_new_archive(name);
 1331     g_free(name);
 1332     if (archive == NULL)
 1333     {
 1334       g_object_unref(myfc_ls);
 1335       return;
 1336     }
 1337   }
 1338 
 1339   if (multi_file_chooser(archive, myfc_ls) == TRUE) 
 1340   {
 1341     /* set up cmd array */
 1342     /* adding 4 to list size for wrapper,option,archive, and null */
 1343     size = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(myfc_ls), NULL) + 4;
 1344     wrapper.argv = g_new(gchar *, size);
 1345     wrapper.index = FIRST_FILE_INDEX;
 1346     wrapper.argv[ARCHIVE_INDEX] = g_strdup(archive);                    
 1347     /* create new archive with first item by calling
 1348      * foreach func by hand */
 1349     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(myfc_ls), &iter); 
 1350     add_foreach_func(GTK_TREE_MODEL(myfc_ls), NULL, &iter, &wrapper); 
 1351     error = wrapper_cmd(AR_NEW, wrapper.argv, NULL);
 1352     gtk_list_store_remove(myfc_ls, &iter);
 1353     if (error != 0 )
 1354     {
 1355       g_free(archive);
 1356       g_strfreev(wrapper.argv);
 1357       g_object_unref(myfc_ls);
 1358       return;
 1359     }
 1360     
 1361     /* then add the rest, if any, to new archive */
 1362     if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(myfc_ls), &iter) != FALSE)
 1363     {
 1364       gtk_tree_model_foreach(GTK_TREE_MODEL(myfc_ls), 
 1365                              (GtkTreeModelForeachFunc) add_foreach_func,
 1366                              &wrapper);
 1367       error = wrapper_cmd(AR_ADD, wrapper.argv, NULL);
 1368       if (error != 0) {
 1369         g_free(archive);
 1370         g_strfreev(wrapper.argv);
 1371         g_object_unref(myfc_ls);
 1372         return;
 1373       }
 1374     }
 1375     
 1376     g_strfreev(wrapper.argv);
 1377     /* now load up the archive in the notebook */
 1378     add_page(archive);
 1379   }
 1380   
 1381   g_free(archive);
 1382   g_object_unref(myfc_ls);
 1383 }
 1384 
 1385 void 
 1386 close_cb(GtkWidget *widget, gpointer data)
 1387 {
 1388   gint page;
 1389   gchar *archive;
 1390   GtkWidget *scrollw;
 1391 
 1392   if ( data != NULL)
 1393   {
 1394     scrollw = GTK_WIDGET(data);
 1395     page = gtk_notebook_page_num(NOTEBOOK, scrollw);
 1396     gtk_notebook_set_current_page(NOTEBOOK, page);
 1397   }
 1398   archive = get_current_archive();
 1399   g_free(archive);
 1400   page = gtk_notebook_get_current_page(NOTEBOOK);
 1401   gtk_notebook_remove_page(NOTEBOOK, page);
 1402   gtk_widget_queue_draw(GTK_WIDGET(NOTEBOOK));
 1403 
 1404   page = gtk_notebook_get_current_page(NOTEBOOK);
 1405   if (page < 0) 
 1406   {
 1407     gtk_widget_hide(GTK_WIDGET(NOTEBOOK));
 1408     gtk_widget_show(EMPTY);
 1409   }
 1410 }
 1411 
 1412 void
 1413 close_button_cb(GtkWidget *widget, gpointer data)
 1414 {
 1415   GtkWidget *current_scrollw;
 1416   gint page;
 1417 
 1418   current_scrollw = gtk_notebook_get_nth_page(NOTEBOOK, 
 1419                             gtk_notebook_get_current_page(NOTEBOOK));
 1420   close_cb(widget, data);
 1421   page = gtk_notebook_page_num(NOTEBOOK, current_scrollw);
 1422   if (page != -1)
 1423     gtk_notebook_set_current_page(NOTEBOOK, page);
 1424 }
 1425 
 1426 void 
 1427 extract_cb(GtkWidget *widget, gpointer data)
 1428 {
 1429   /* get selections from current treeview and a destdir.
 1430    * create a gchar pointer array with selected files and send
 1431    * to wrapper_cmd to process. */
 1432   static WrapperData wrapper;
 1433   SelectionData seld;
 1434   GtkTreeView *treeview;
 1435   GtkTreeModel *liststore;
 1436   gint sort_column;
 1437   GtkSortType sort_order;
 1438   gchar *msg;
 1439   gint error;
 1440 
 1441   if ( (treeview = get_current_tree()) == NULL ) return; 
 1442   liststore = gtk_tree_view_get_model(treeview);
 1443   /* if selection contains directories notify user */
 1444   seld.sel = gtk_tree_view_get_selection(treeview);
 1445 
 1446   /* if nothing selected ask to select all */
 1447   if (gtk_tree_selection_count_selected_rows(seld.sel) < 1) 
 1448   {
 1449     if (message(MAIN_WINDOW,
 1450         GTK_MESSAGE_WARNING, 
 1451                 "No files selected,\n\n"
 1452                 "assuming you want to extract all") == TRUE) 
 1453       gtk_tree_selection_select_all(seld.sel);
 1454     else return;
 1455   }
 1456 
 1457   wrapper.dir = askfor_extract_dir();
 1458   if (wrapper.dir == NULL) return;
 1459   
 1460   /* if all is selected don't send any files, just extract the whole thing */
 1461   if ( gtk_tree_selection_count_selected_rows(seld.sel) == 
 1462        gtk_tree_model_iter_n_children(liststore, NULL) )
 1463   {
 1464     /* need an array for 4 gchar pointers. wrapper option archive null. */ 
 1465     wrapper.argv = g_new(gchar *, 4);
 1466     wrapper.argv[ARCHIVE_INDEX] = g_strdup(get_current_archive());
 1467     wrapper.argv[FIRST_FILE_INDEX] = NULL;
 1468   }
 1469   else
 1470   {
 1471     /* need an array for 4 gchar pointers plus the number of selected files.
 1472      * Array will contain: wrapper option archive files... null 
 1473      */
 1474     wrapper.argv = g_new(gchar *, 
 1475                          (4 + 
 1476                           gtk_tree_selection_count_selected_rows(seld.sel)));
 1477     wrapper.argv[ARCHIVE_INDEX] = g_strdup(get_current_archive());
 1478     wrapper.index = FIRST_FILE_INDEX;
 1479   
 1480     /* for extracting we need the DFILE column sorted descending so that
 1481      * the directories are extracted before the children.  Tar
 1482      * hiccups if not. So change to that if it's not then
 1483      * change back to what ever it was */
 1484     gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(liststore),
 1485                                          &sort_column, &sort_order);
 1486     if ( ! (sort_column == COL_DFILE && sort_order == GTK_SORT_DESCENDING) ) 
 1487     {
 1488       gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore), 
 1489                                            COL_DFILE, GTK_SORT_DESCENDING);
 1490     }
 1491 
 1492     gtk_tree_selection_selected_foreach(seld.sel, 
 1493                                         (GtkTreeSelectionForeachFunc)
 1494                                         selected_foreach_func, &wrapper);
 1495 
 1496     gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore),
 1497                                          sort_column, sort_order);
 1498   }
 1499   error = wrapper_cmd(AR_EXTRACT, wrapper.argv, wrapper.dir); 
 1500   if (error == 0)
 1501   {
 1502     msg = g_strconcat("Done extracting files to:\n\n",
 1503                       wrapper.dir, NULL);
 1504     message(MAIN_WINDOW,
 1505         GTK_MESSAGE_INFO, msg);
 1506     g_free(msg);
 1507   }
 1508   g_strfreev(wrapper.argv);
 1509   g_free(wrapper.dir);
 1510 } 
 1511 
 1512 void
 1513 openwith_cb(GtkWidget *widget, gpointer data)
 1514 {
 1515   open_selected_files(FALSE);
 1516 }
 1517 
 1518 void
 1519 double_click_cb()
 1520 {
 1521   open_selected_files(TRUE);
 1522 }
 1523 
 1524 void
 1525 open_selected_files(gboolean use_default_handler)
 1526 {
 1527   static WrapperData wrapper;
 1528   SelectionData seld;
 1529   GtkTreeView *treeview;
 1530   GtkTreeSelectionForeachFunc foreach_func = (GtkTreeSelectionForeachFunc)
 1531     ((use_default_handler)
 1532      ? default_handler_foreach_func
 1533      : openwith_foreach_func);
 1534   gchar *tdir, *rm_command;
 1535   const gchar *tpath = NULL;
 1536         
 1537 
 1538   if ( (treeview = get_current_tree()) == NULL ) return;
 1539     
 1540   seld.sel = gtk_tree_view_get_selection(treeview);
 1541 
 1542   /* if nothing selected do nothing */
 1543   if ( gtk_tree_selection_count_selected_rows(seld.sel) < 1 ) return; 
 1544 
 1545   tpath = g_get_tmp_dir();
 1546   tdir = g_strconcat(tpath,"/xarchiveXXXXXX", NULL); 
 1547   wrapper.dir = mkdtemp(tdir);
 1548   wrapper.index = TRUE; /* use index to check for a cancel */
 1549   gtk_tree_selection_selected_foreach(seld.sel, foreach_func, &wrapper);
 1550   
 1551   /* remove temp dir tdir */
 1552   rm_command = g_strconcat("rm -fr ", tdir, NULL);
 1553   printf("rm_command: %s\n", rm_command);
 1554   system(rm_command);
 1555   g_free(rm_command);
 1556   g_free(tdir);
 1557 }
 1558 
 1559 void 
 1560 add_cb(GtkWidget *widget, gpointer data)
 1561 {
 1562   WrapperData wrapper;
 1563   GtkListStore *myfc_ls; /*file chooser liststore*/
 1564   gchar *archive_disp, *archive;
 1565   gint error;
 1566 
 1567   if ( (archive = get_current_archive()) == NULL ) return; 
 1568   
 1569   if (data != NULL)
 1570     myfc_ls = (GtkListStore *) data;
 1571   else
 1572     myfc_ls = make_myfc_ls();
 1573   
 1574   archive_disp = g_filename_display_name(archive);
 1575   if (multi_file_chooser(archive_disp, myfc_ls) == TRUE) 
 1576   {
 1577     /* need a gchar pointer array for 4 pointers plus the number
 1578      * of files on the list (wrapper, option, archive, files.., null)
 1579      */
 1580     wrapper.argv = g_new(gchar *,
 1581                          4 + 
 1582                          gtk_tree_model_iter_n_children(GTK_TREE_MODEL(myfc_ls),NULL));
 1583     wrapper.index = FIRST_FILE_INDEX;
 1584     wrapper.argv[ARCHIVE_INDEX] = g_strdup(archive);
 1585     gtk_tree_model_foreach( GTK_TREE_MODEL(myfc_ls),
 1586                             (GtkTreeModelForeachFunc) 
 1587                             add_foreach_func,
 1588                             &wrapper);
 1589     error = wrapper_cmd(AR_ADD, wrapper.argv, NULL);
 1590     if (error == 0)
 1591     {
 1592       reload_current_tree(get_current_tree());
 1593     }
 1594     g_strfreev(wrapper.argv);
 1595   }
 1596   
 1597   g_free(archive_disp);
 1598   g_object_unref(myfc_ls);
 1599 } 
 1600 
 1601 void 
 1602 remove_cb(GtkWidget *widget, gpointer data)
 1603 {
 1604   WrapperData wrapper;
 1605   SelectionData seld;
 1606   GtkTreeView *treeview;
 1607   GtkTreeModel *liststore;
 1608   gint sort_column;
 1609   GtkSortType sort_order;
 1610 
 1611   if ( (treeview = get_current_tree()) == NULL) return;
 1612   liststore = gtk_tree_view_get_model(treeview);
 1613   seld.sel = gtk_tree_view_get_selection(treeview);
 1614   if ( gtk_tree_selection_count_selected_rows(seld.sel) < 1 ) return;
 1615 
 1616   wrapper.argv = g_new(gchar *,
 1617                        (4 +
 1618                         gtk_tree_selection_count_selected_rows(seld.sel)));
 1619   wrapper.index = FIRST_FILE_INDEX;
 1620   wrapper.argv[ARCHIVE_INDEX] = g_strdup(get_current_archive());
 1621 
 1622   /* for removing we need the DFILE column sorted descending so that a
 1623    * directories children are removed before the directory itself.  Tar
 1624    * hiccups if not. So change to that if it's not, do the remove, then
 1625    * change back to what ever it was */
 1626   gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(liststore),
 1627                                        &sort_column, &sort_order);
 1628   if ( ! (sort_column == COL_DFILE && sort_order == GTK_SORT_DESCENDING) ) 
 1629   {
 1630     gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore), 
 1631                                          COL_DFILE, GTK_SORT_DESCENDING);
 1632   }
 1633 
 1634   gtk_tree_selection_selected_foreach(seld.sel, 
 1635                                       (GtkTreeSelectionForeachFunc)
 1636                                       selected_foreach_func, 
 1637                                       &wrapper);
 1638 
 1639   gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore),
 1640                                        sort_column, sort_order);
 1641 
 1642   wrapper_cmd(AR_REMOVE, wrapper.argv, NULL);
 1643   reload_current_tree(treeview);
 1644   g_strfreev(wrapper.argv);
 1645 }
 1646 
 1647 void 
 1648 select_all_cb(GtkWidget *widget, gpointer data)
 1649 {
 1650   GtkTreeView *treeview;
 1651   GtkTreeSelection *sel;
 1652 
 1653   if ( (treeview = get_current_tree()) == NULL ) return;
 1654   sel = gtk_tree_view_get_selection(treeview);
 1655   gtk_tree_selection_select_all(sel);
 1656 }
 1657 
 1658 void 
 1659 unselect_all_cb(GtkWidget *widget, gpointer data)
 1660 {
 1661   GtkTreeView *treeview;
 1662   GtkTreeSelection *sel;
 1663 
 1664   if ( (treeview = get_current_tree()) == NULL ) return;
 1665   sel = gtk_tree_view_get_selection(treeview);
 1666   gtk_tree_selection_unselect_all(sel);
 1667 }
 1668 
 1669 void 
 1670 wrapper_info_cb(GtkWidget *widget, gpointer data)
 1671 {
 1672   GtkWidget *dialog, *infobox;
 1673   gchar *wrapinf, *msg;
 1674 
 1675   dialog = gtk_dialog_new_with_buttons("Wrapper Info", 
 1676                                        NULL,
 1677                                        GTK_DIALOG_DESTROY_WITH_PARENT |
 1678                                        GTK_DIALOG_NO_SEPARATOR,
 1679                                        GTK_STOCK_OK,
 1680                                        GTK_RESPONSE_ACCEPT,
 1681                                        NULL);
 1682   g_signal_connect_swapped(dialog, "response", 
 1683                            G_CALLBACK(gtk_widget_destroy), 
 1684                            dialog);
 1685   gtk_widget_set_size_request(dialog, 500, 300);
 1686 
 1687   wrapinf = wrapper_info();
 1688   msg = g_strdup_printf("%s\n%s\n\n%s",
 1689                         PACKAGE_STRING, PACKAGE_BUGREPORT, wrapinf);
 1690   g_free(wrapinf);
 1691   infobox = make_info_widget(msg);
 1692   g_free(msg);
 1693   
 1694   gtk_box_pack_start(GTK_BOX( GTK_DIALOG(dialog)->vbox ), infobox, TRUE,TRUE,0);
 1695 
 1696   gtk_widget_show_all(dialog);
 1697 }
 1698 
 1699 void
 1700 read_help_cb(GtkWidget *widget, gpointer data)
 1701 {
 1702   GtkWidget *dialog, *infobox;
 1703   gchar *helptxt;
 1704   
 1705   dialog = gtk_dialog_new_with_buttons("View Help", 
 1706                                        NULL,
 1707                                        GTK_DIALOG_DESTROY_WITH_PARENT |
 1708                                        GTK_DIALOG_NO_SEPARATOR,
 1709                                        GTK_STOCK_OK,
 1710                                        GTK_RESPONSE_ACCEPT,
 1711                                        NULL);
 1712   g_signal_connect_swapped(dialog, "response", 
 1713                            G_CALLBACK(gtk_widget_destroy), 
 1714                            dialog);
 1715   gtk_widget_set_size_request(dialog, 500, 300);
 1716 
 1717   g_file_get_contents(HELP_FILE_PATH, &helptxt, NULL, NULL);
 1718   infobox = make_info_widget(helptxt);
 1719   g_free(helptxt);
 1720   gtk_box_pack_start(GTK_BOX( GTK_DIALOG(dialog)->vbox ), 
 1721                      infobox, TRUE,TRUE,0);
 1722 
 1723   gtk_widget_show_all(dialog);
 1724 }
 1725 
 1726 static gboolean
 1727 open_cancel_cb(GtkWidget *widget, gpointer data)
 1728 {
 1729   gboolean *stopit = (gboolean *) data;
 1730 
 1731   *stopit = TRUE;
 1732   return FALSE;
 1733 }
 1734 
 1735 static gboolean
 1736 process_cancel_cb(GtkWidget *widget, gpointer data)
 1737 {
 1738   pid_t pid = (pid_t) GPOINTER_TO_INT(data);
 1739   gint err;
 1740   
 1741   printf("Trying to send kill signal to process %d\n", pid);
 1742   err = kill( pid, SIGTERM);
 1743   printf("Returned from kill: %d\n", err);
 1744   return FALSE;
 1745 }
 1746 
 1747 /***********************/
 1748 /* UIMananger functions*/
 1749 /***********************/
 1750 void 
 1751 add_ui_widget(GtkUIManager *uimanager, 
 1752               GtkWidget *widget,
 1753               GtkContainer *container)
 1754 {
 1755   GtkToolbar *toolbar;
 1756 
 1757   gtk_box_pack_start (GTK_BOX(container), widget, FALSE, FALSE, 0);
 1758   gtk_widget_show(widget);
 1759   if (GTK_IS_TOOLBAR(widget)) 
 1760   {
 1761     toolbar = GTK_TOOLBAR(widget);
 1762     gtk_toolbar_set_show_arrow(toolbar, TRUE);
 1763   }
 1764 }
 1765 
 1766 GtkUIManager * 
 1767 make_ui_widgets(GtkWidget *window, GtkWidget *box)
 1768 {
 1769   GtkUIManager *uimanager;
 1770   GtkActionGroup *action_group;
 1771   GError *error = NULL;
 1772   GtkActionEntry entries[] = {
 1773     { "FileMenuAction", NULL, "_File" },
 1774     { "ActionsMenuAction", NULL, "_Archive" },
 1775     { "HelpMenuAction", NULL, "_Help" },
 1776     { "PopupMenuAction", NULL, "_Popup" },
 1777     { "new", GTK_STOCK_NEW, "_New", "<control>N",
 1778       "(CTRL-N) Create new archive", G_CALLBACK(new_cb)},
 1779     { "open", GTK_STOCK_OPEN, "_Open", "<control>O",
 1780       "(CTRL-O) Open exisiting archive", G_CALLBACK(open_cb)},
 1781     { "close", GTK_STOCK_CLOSE, "_Close", "<control>W",
 1782       "(CTRL-W) Close current archive window", G_CALLBACK(close_cb)},
 1783     { "quit", GTK_STOCK_QUIT, "_Quit", "<control>Q",
 1784       "(CTRL-Q) Quit application, closing all open archives", 
 1785       G_CALLBACK(gtk_main_quit)},
 1786     { "extract", GTK_STOCK_HARDDISK, "_Extract", "<control>E",
 1787       "(CTRL-E) Extract selected files from current archive", 
 1788       G_CALLBACK(extract_cb)},
 1789     { "add", GTK_STOCK_ADD, "_Add", "<control>A",
 1790       "(CTRL-A) Add files to current archive", G_CALLBACK(add_cb)},
 1791     { "remove", GTK_STOCK_REMOVE, "_Remove", "<control>R",
 1792       "(CTRL-R) Remove selected files from current archive", G_CALLBACK(remove_cb)},
 1793     { "openwith", GTK_STOCK_EXECUTE, "O_pen With...", "<control>P",
 1794       "(CTRL-P) Temporarily extract the selected files from current archive then open them with the specified application", G_CALLBACK(openwith_cb)},
 1795     { "SelectionMenuAction", NULL, "_Selection" },
 1796     { "select all", GTK_STOCK_APPLY, "_Select All", "<control>S",
 1797       "(CTRL-S) selected all files in current archive", G_CALLBACK(select_all_cb)},
 1798     { "unselect all", GTK_STOCK_CLEAR, "_Unselect All", "<control>U",
 1799       "(CTRL-U) unselect all files in current archive", G_CALLBACK(unselect_all_cb)},
 1800     { "wrapper info", GTK_STOCK_ABOUT, "Wrapper _Info", "<control>I",
 1801       "(CTRL-I) Show information on found wrappers", G_CALLBACK(wrapper_info_cb)},
 1802     { "read help", GTK_STOCK_HELP, "Read _Help", "<control>H",
 1803       "(CTRL-H) Read help file", G_CALLBACK(read_help_cb)},
 1804   };
 1805   guint n_entries = G_N_ELEMENTS(entries);
 1806   gchar *ui_info =
 1807     "  <menubar>\n"
 1808     "    <menu name=\"_File\" action=\"FileMenuAction\">\n"
 1809     "      <menuitem name=\"open\" action=\"open\" />\n"
 1810     "      <menuitem name=\"new\" action=\"new\" />\n"
 1811     "      <menuitem name=\"close\" action=\"close\" />\n"
 1812     "      <separator name=\"sep1\" />\n"
 1813     "      <menuitem name=\"quit\" action=\"quit\" />\n"
 1814     "    </menu>\n"
 1815     "    <menu name=\"_Selection\" action=\"SelectionMenuAction\">\n"
 1816     "      <menuitem name=\"select all\" action=\"select all\" />\n"
 1817     "      <menuitem name=\"unselect all\" action=\"unselect all\" />\n"
 1818     "    </menu>\n"
 1819     "    <menu name=\"_Actions\" action=\"ActionsMenuAction\" >\n"
 1820     "      <menuitem name=\"extract\" action=\"extract\" />\n"
 1821     "      <menuitem name=\"openwith\" action=\"openwith\" />\n"
 1822     "      <menuitem name=\"remove\" action=\"remove\" />\n"
 1823     "      <menuitem name=\"add\" action=\"add\" />\n"
 1824     "    </menu>\n"
 1825     "    <menu name=\"_Help\" action=\"HelpMenuAction\" >\n"
 1826     "      <menuitem name=\"read help\" action=\"read help\" />\n"
 1827     "      <menuitem name=\"wrapper info\" action=\"wrapper info\" />\n"
 1828     "    </menu>\n"
 1829     "  </menubar>\n"
 1830     "  <toolbar name=\"toolbar\">\n"
 1831     "    <toolitem name=\"open\" action=\"open\" />\n"
 1832     "    <toolitem name=\"new\" action=\"new\" />\n"
 1833     "    <toolitem name=\"close\" action=\"close\" />\n"
 1834     "    <separator name=\"sep1\" /> \n"
 1835     "    <toolitem name=\"select all\" action=\"select all\" />\n"
 1836     "    <toolitem name=\"unselect all\" action=\"unselect all\" />\n"
 1837     "    <separator name=\"sep2\" /> \n"
 1838     "    <toolitem name=\"extract\" action=\"extract\" />\n"
 1839     "    <toolitem name=\"openwith\" action=\"openwith\" />\n"
 1840     "    <toolitem name=\"remove\" action=\"remove\" />\n"
 1841     "    <toolitem name=\"add\" action=\"add\" />\n"
 1842     "    <separator name=\"sep3\" /> \n"
 1843     "    <toolitem name=\"quit\" action=\"quit\" />\n"
 1844     "  </toolbar>\n"
 1845     "  <popup name=\"treeview_popup\" action=\"PopupMenuAction\">\n"
 1846     "    <menuitem name=\"select all\" action=\"select all\" />\n"
 1847     "    <menuitem name=\"unselect all\" action=\"unselect all\" />\n"
 1848     "    <separator name=\"sep4\" /> \n"
 1849     "    <menuitem name=\"extract\" action=\"extract\" />\n"
 1850     "    <menuitem name=\"openwith\" action=\"openwith\" />\n"
 1851     "    <menuitem name=\"remove\" action=\"remove\" />\n"
 1852     "    <menuitem name=\"add\" action=\"add\" />\n"
 1853     "    <separator name=\"sep5\" /> \n"
 1854     "    <menuitem name=\"close\" action=\"close\" />\n"
 1855     "  </popup>\n"
 1856     ;
 1857     
 1858   action_group = gtk_action_group_new("XArchiveActions");
 1859   gtk_action_group_add_actions(action_group, entries, n_entries, NULL);
 1860     
 1861   uimanager = gtk_ui_manager_new();
 1862   gtk_ui_manager_insert_action_group(uimanager, action_group, 0);
 1863   g_signal_connect(uimanager, "add_widget", G_CALLBACK(add_ui_widget), box);
 1864   gtk_window_add_accel_group(GTK_WINDOW(window), 
 1865                              gtk_ui_manager_get_accel_group(uimanager));
 1866   if (!gtk_ui_manager_add_ui_from_string(uimanager, ui_info, -1, &error)) 
 1867   {
 1868     g_message("building menus failed: %s", error->message);
 1869     g_error_free(error);
 1870   }
 1871   return uimanager;
 1872 }
 1873 
 1874 
 1875 /******************************/
 1876 /* passed aurgument functions */
 1877 /******************************/
 1878 
 1879 gint
 1880 ask_create_or_add(gchar *msg)
 1881 {
 1882   gint response;
 1883   GtkWidget *md;
 1884 
 1885   md = gtk_message_dialog_new(GTK_WINDOW(MAIN_WINDOW), 
 1886                               GTK_DIALOG_DESTROY_WITH_PARENT,
 1887                               GTK_MESSAGE_QUESTION,
 1888                               GTK_BUTTONS_CANCEL,
 1889                               msg);
 1890   gtk_dialog_add_buttons(GTK_DIALOG(md),
 1891                          "New", AR_NEW,
 1892                          "Existing", AR_ADD,
 1893                          NULL);
 1894   gtk_dialog_set_alternative_button_order(GTK_DIALOG(md), AR_NEW, AR_ADD,
 1895                                           GTK_RESPONSE_CANCEL, -1);
 1896   response = gtk_dialog_run(GTK_DIALOG(md));
 1897   gtk_widget_destroy(md);
 1898   
 1899   return response;
 1900 }
 1901 
 1902 void
 1903 process_passed_arguments(ParsedArgs *pargs)
 1904 {
 1905   gchar *archive = NULL, *msg, *filepath;
 1906   gint i, response=AR_ADD;
 1907   GtkListStore *filelist;
 1908 
 1909   switch (pargs->action)
 1910   {
 1911     case AR_OPEN:
 1912       if (pargs->files == NULL) break;
 1913       for (i=0; pargs->files[i] != NULL; i++)
 1914       {
 1915         archive = canonicalize_file_name(pargs->files[i]);
 1916         if(archive != NULL) add_page(archive);
 1917         else
 1918         {
 1919           msg = g_strconcat("Could not open archive:\n\n",
 1920                             pargs->files[i], NULL);
 1921           message(MAIN_WINDOW,
 1922           GTK_MESSAGE_ERROR, msg);
 1923           g_free(msg);
 1924         }
 1925       }
 1926       break;
 1927     
 1928     case AR_ADD:
 1929       msg = g_strdup_printf("Would you like to:\n"
 1930                             "Create a new archive, or\n"
 1931                             "Add to an existing archive?");
 1932       if (strcmp(pargs->archive,"ask") != 0 &&
 1933           (archive = canonicalize_file_name(pargs->archive)) == NULL)
 1934         msg = g_strdup_printf("Archive not found\n%s\n\n%s",
 1935                               pargs->archive, msg);
 1936       else
 1937       {
 1938         g_free(pargs->archive);
 1939         pargs->archive = NULL;
 1940       }
 1941       
 1942       if (archive == NULL &&
 1943           (response = ask_create_or_add(msg)) == AR_ADD)
 1944         archive = askfor_existing_archive();
 1945       
 1946       filelist = make_myfc_ls();
 1947       if (pargs->files != NULL)
 1948         for (i=0; pargs->files[i] != NULL; i++)
 1949         {
 1950           filepath = canonicalize_file_name(pargs->files[i]);
 1951           if (filepath == NULL) continue;
 1952           else myfc_add_foreach_func(filepath, filelist);
 1953           g_free(filepath);
 1954         }
 1955 
 1956       if (response == AR_ADD && archive != NULL)
 1957       {
 1958         add_page(archive);
 1959         add_cb(NULL, (gpointer) filelist);
 1960       }
 1961       else if (response == AR_NEW)
 1962       {
 1963         g_object_set_data(G_OBJECT(filelist),"name", (gpointer)pargs->archive);
 1964         new_cb(NULL, (gpointer) filelist);
 1965       }
 1966       else 
 1967         gtk_widget_show(EMPTY);
 1968 
 1969       g_free(archive);
 1970       break;
 1971 
 1972     case AR_NEW:
 1973       if (strcmp(pargs->archive, "ask") == 0)
 1974       {
 1975         g_free(pargs->archive);
 1976         pargs->archive = NULL;
 1977       }
 1978       filelist = make_myfc_ls();
 1979       if (pargs->files != NULL)
 1980         for (i=0; pargs->files[i] != NULL; i++)
 1981         {
 1982           filepath = canonicalize_file_name(pargs->files[i]);
 1983           if (filepath == NULL) continue;
 1984           else myfc_add_foreach_func(filepath, filelist);
 1985           g_free(filepath);
 1986         }
 1987       g_object_set_data(G_OBJECT(filelist),"name", (gpointer)pargs->archive);
 1988       new_cb(NULL, (gpointer) filelist);
 1989       break;
 1990       
 1991     default:
 1992       gtk_widget_show(EMPTY);
 1993       break;
 1994   }
 1995 }
 1996 
 1997 /***********************/
 1998 /* Main setup function */
 1999 /***********************/
 2000 
 2001 int 
 2002 make_widgets(ParsedArgs *pargs)
 2003 {
 2004   GdkGeometry size_hints;
 2005   GtkWidget *mainbox;
 2006   static GdkPixbuf *xarchive_pixbuf;
 2007 
 2008   MAIN_WINDOW = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 2009   xarchive_pixbuf = gdk_pixbuf_new_from_xpm_data(xarchive_xpm);
 2010   gtk_window_set_default_icon(xarchive_pixbuf);
 2011   g_signal_connect(G_OBJECT(MAIN_WINDOW), "delete_event",
 2012                    G_CALLBACK(gtk_main_quit), NULL);
 2013   g_signal_connect(G_OBJECT(MAIN_WINDOW), "destroy",
 2014                    G_CALLBACK(gtk_main_quit), NULL);
 2015 
 2016   gtk_container_set_border_width(GTK_CONTAINER(MAIN_WINDOW), 0);
 2017   gtk_window_set_title (GTK_WINDOW(MAIN_WINDOW), PACKAGE_STRING);
 2018   size_hints.min_width=300;
 2019   size_hints.min_height=250;
 2020   size_hints.base_width=0;
 2021   size_hints.base_height=0;
 2022   gtk_window_set_geometry_hints(GTK_WINDOW(MAIN_WINDOW), MAIN_WINDOW, 
 2023                                 &size_hints,
 2024                                  GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE); 
 2025   gtk_window_set_default_size(GTK_WINDOW(MAIN_WINDOW), 640, 400);
 2026   if (pargs->geom != NULL)
 2027     gtk_window_parse_geometry(GTK_WINDOW(MAIN_WINDOW), pargs->geom);
 2028   
 2029   mainbox = gtk_vbox_new(FALSE, 0);
 2030   gtk_container_add(GTK_CONTAINER(MAIN_WINDOW), mainbox);
 2031 
 2032   UIMANAGER = make_ui_widgets(MAIN_WINDOW, mainbox);
 2033 
 2034   make_empty_page(mainbox);
 2035   make_notebook_widgets(mainbox);
 2036 
 2037   process_passed_arguments(pargs);
 2038 
 2039   gtk_widget_show(mainbox);
 2040   gtk_widget_show(MAIN_WINDOW);
 2041   gtk_main(); 
 2042   return 0;
 2043 }