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
start_myfc_onDragDataRecived(GtkWidget * widget,GdkDragContext * context,int x,int y,GtkSelectionData * seldata,guint info,guint time,gpointer userdata)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
my_search_equal_func(GtkTreeModel * model,gint column,const gchar * key,GtkTreeIter * iter,gpointer search_data)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
render_cols(GtkTreeView * view,gchar * title,gint mcol)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 *
make_liststore(void)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 *
make_tree(GtkListStore * liststore)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 *
get_current_tree(void)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 *
get_current_archive(void)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
add_row(GtkListStore * liststore,gchar ** ent)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
reload_current_tree(GtkTreeView * treeview)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
treeview_button_press(GtkWidget * container,GdkEventButton * event,GtkUIManager * uimanager)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
make_notebook_widgets(GtkWidget * container)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
add_page(gchar * archive)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
setup_opening_progress_bar(GtkWidget * pbwin,GtkWidget * pbar,gboolean * stopit)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
wait_with_progress_bar(GPid pid,gint * wrapper_status,gint ar_func)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 *
make_info_widget(gchar * msg)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
make_empty_page(GtkWidget * container)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
message(GtkWidget * parentwin,gint type,gchar * text)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
selected_foreach_func(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,WrapperData * wrapper)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
sel_subdir_foreach_func(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,SelectionData * seld)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
unsel_subdir_foreach_func(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,SelectionData * seld)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
test_selection_func(GtkTreeSelection * selection,GtkTreeModel * model,GtkTreePath * path,gboolean path_currently_selected,gpointer data)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
add_foreach_func(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,WrapperData * wrapper)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
file_filter_func(const GtkFileFilterInfo * filter_info,gpointer data)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 *
askfor_existing_archive(void)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 *
askfor_new_archive(gchar * name)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
multi_file_chooser(gchar * archive,GtkListStore * filelist)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
select_extract_dir(GtkWidget * widget,GtkWidget * entry)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 *
askfor_extract_dir(void)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 *
get_openwith_cmdlist(gchar * cmdlist_path)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
add_to_cmdlist(GtkListStore * cmdlist,gchar * command,gchar * cmdlist_path)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
get_lastdir(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
get_default_handler(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
set_default_handler(gchar * command)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
open_one_file(WrapperData * wrapper,gchar * command)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     gchar *viewcmd;
1135     fname = my_strescape(wrapper->argv[FIRST_FILE_INDEX]);
1136     viewcmd = g_strconcat(command, " ", wrapper->dir,
1137                                  "/", fname, NULL);
1138     g_free(fname);
1139     printf("viewcmd: %s\n",viewcmd);
1140     system(viewcmd);
1141     g_free(viewcmd);
1142   }
1143 }
1144 
1145 void
default_handler_foreach_func(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,WrapperData * wrapper)1146 default_handler_foreach_func(GtkTreeModel *model,
1147                              GtkTreePath  *path,
1148                              GtkTreeIter  *iter,
1149                              WrapperData  *wrapper)
1150 {
1151   gchar *fname;
1152   gchar *defhand_cmd;
1153 
1154   defhand_cmd = (gchar *)g_object_get_data(G_OBJECT(NOTEBOOK),"defhand_cmd");
1155 
1156   /* if no cmd is set, pass off to open with dialog for setting */
1157   if (defhand_cmd == NULL)
1158   {
1159     message(MAIN_WINDOW,
1160 	    GTK_MESSAGE_WARNING,
1161             "Double-clicking doesn't work until you\n"
1162             "set your default handler using the\n"
1163             "'set double-click default handler' flag\n"
1164             "in the 'open with..' dialog.\n\n");
1165     openwith_foreach_func(model, path, iter, wrapper);
1166     return;
1167   }
1168 
1169   gtk_tree_model_get(model, iter, COL_FILE, &fname, -1);
1170 
1171   wrapper->argv = g_new(gchar *, 5); /*wrapper, option, archive, file, NULL*/
1172   wrapper->argv[ARCHIVE_INDEX] = g_strdup(get_current_archive());
1173   wrapper->argv[FIRST_FILE_INDEX] = g_strdup(fname);
1174   wrapper->argv[FIRST_FILE_INDEX + 1] = NULL;
1175 
1176   open_one_file(wrapper, defhand_cmd);
1177 
1178   g_strfreev(wrapper->argv);
1179   g_free(fname);
1180 }
1181 
1182 gchar *
askfor_openwith_command(gchar * fname)1183 askfor_openwith_command(gchar *fname)
1184 {
1185   GtkWidget *dialog, *label, *combobox, *checkbox;
1186   GtkEntryCompletion *completion;
1187   static gchar *cmdlist_path = NULL;
1188   static GtkListStore *cmdlist = NULL;
1189   gchar *command = NULL, *msg;
1190 
1191   if (cmdlist_path == NULL)
1192     cmdlist_path = g_strdup_printf("%s/.xarchive/cmd_history",getenv("HOME"));
1193   if (cmdlist == NULL)
1194     cmdlist = get_openwith_cmdlist(cmdlist_path);
1195 
1196   dialog = gtk_dialog_new_with_buttons("Open With...",
1197                                        GTK_WINDOW(MAIN_WINDOW),
1198                                        GTK_DIALOG_DESTROY_WITH_PARENT,
1199                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1200                                        GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1201                                        NULL);
1202   gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog),
1203                                           GTK_RESPONSE_ACCEPT,
1204                                           GTK_RESPONSE_CANCEL, -1);
1205   gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1206   msg = g_strdup_printf("Open \"%s\" with...", fname);
1207   label = gtk_label_new(msg);
1208   g_free(msg);
1209   gtk_widget_show(label);
1210   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE,TRUE,0);
1211 
1212   combobox = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(cmdlist), 0);
1213   gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0);
1214   gtk_widget_show(combobox);
1215   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),combobox,TRUE,TRUE,0);
1216 
1217   gtk_entry_set_activates_default(GTK_ENTRY(GTK_BIN(combobox)->child),
1218                                   TRUE);
1219   completion = gtk_entry_completion_new();
1220   gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(cmdlist));
1221   gtk_entry_completion_set_text_column(completion, 0);
1222   gtk_entry_completion_set_popup_completion(completion, TRUE);
1223   gtk_entry_set_completion(GTK_ENTRY(GTK_BIN(combobox)->child),
1224                            completion);
1225 
1226   checkbox = gtk_check_button_new_with_label("set as default double-click handler");
1227   gtk_widget_show(checkbox);
1228   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),checkbox,TRUE,TRUE,0);
1229 
1230   msg = g_strdup_printf("Current default handler: %s",
1231                         (gchar *)g_object_get_data(G_OBJECT(NOTEBOOK),
1232                                                    "defhand_cmd"));
1233   label = gtk_label_new(msg);
1234   gtk_widget_show(label);
1235   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),label,TRUE,TRUE,0);
1236   g_free(msg);
1237 
1238   if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1239   {
1240     command = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(combobox)->child)));
1241     add_to_cmdlist(cmdlist, command, cmdlist_path);
1242     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox)) == TRUE)
1243       set_default_handler(command);
1244   }
1245 
1246   gtk_widget_destroy(dialog);
1247   return command;
1248 }
1249 
1250 void
openwith_foreach_func(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,WrapperData * wrapper)1251 openwith_foreach_func(GtkTreeModel *model,
1252                       GtkTreePath  *path,
1253                       GtkTreeIter  *iter,
1254                       WrapperData  *wrapper)
1255 {
1256   gchar *fname, *command;
1257 
1258   /* see if cancel button pressed (xarchive set to null) */
1259   if (wrapper->index == FALSE) return;
1260 
1261   /* esc file name */
1262   gtk_tree_model_get(model, iter, COL_FILE, &fname, -1);
1263 
1264   /* display dialog asking to exatract and open fname with app */
1265   command = askfor_openwith_command(fname);
1266   if (command != NULL && strcmp(command, GTK_STOCK_NO) == 0)
1267     wrapper->index = TRUE;
1268   else if (command != NULL)
1269   {
1270     wrapper->argv = g_new(gchar *, 5); /*wrapper, option, archive, file, NULL*/
1271     wrapper->argv[ARCHIVE_INDEX] = g_strdup(get_current_archive());
1272     wrapper->argv[FIRST_FILE_INDEX] = g_strdup(fname);
1273     wrapper->argv[FIRST_FILE_INDEX + 1] = NULL;
1274 
1275     open_one_file(wrapper, command);
1276 
1277     g_strfreev(wrapper->argv);
1278   }
1279   else
1280   {
1281     wrapper->index = FALSE;
1282   }
1283 
1284   g_free(command);
1285   g_free(fname);
1286 }
1287 
1288 /**********************/
1289 /* callback functions */
1290 /**********************/
1291 void
dummy_cb(GtkWidget * widget,gpointer data)1292 dummy_cb(GtkWidget *widget, gpointer data)
1293 {
1294   return;
1295 }
1296 
1297 void
open_cb(GtkWidget * widget,gpointer data)1298 open_cb(GtkWidget *widget, gpointer data)
1299 {
1300   gchar *archive;
1301 
1302   archive = askfor_existing_archive();
1303   if (archive == NULL) return;
1304 
1305   add_page(archive);
1306   g_free(archive);
1307 
1308 }
1309 
1310 void
new_cb(GtkWidget * widget,gpointer data)1311 new_cb(GtkWidget *widget, gpointer data)
1312 {
1313   WrapperData wrapper;
1314   gchar *archive;
1315   GtkListStore *myfc_ls; /*file chooser liststore*/
1316   GtkTreeIter iter;
1317   gchar *name;
1318   gint error, size;
1319 
1320   /* now get the files that are to be added to the new archive */
1321   if (data == NULL)
1322   {
1323     archive = askfor_new_archive(NULL);
1324     if (archive == NULL) return;
1325     myfc_ls = make_myfc_ls();
1326   }
1327   else
1328   {
1329     myfc_ls = (GtkListStore *) data;
1330     name = g_object_get_data(G_OBJECT(myfc_ls), "name");
1331     archive = askfor_new_archive(name);
1332     g_free(name);
1333     if (archive == NULL)
1334     {
1335       g_object_unref(myfc_ls);
1336       return;
1337     }
1338   }
1339 
1340   if (multi_file_chooser(archive, myfc_ls) == TRUE)
1341   {
1342     /* set up cmd array */
1343     /* adding 4 to list size for wrapper,option,archive, and null */
1344     size = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(myfc_ls), NULL) + 4;
1345     wrapper.argv = g_new(gchar *, size);
1346     wrapper.index = FIRST_FILE_INDEX;
1347     wrapper.argv[ARCHIVE_INDEX] = g_strdup(archive);
1348     /* create new archive with first item by calling
1349      * foreach func by hand */
1350     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(myfc_ls), &iter);
1351     add_foreach_func(GTK_TREE_MODEL(myfc_ls), NULL, &iter, &wrapper);
1352     error = wrapper_cmd(AR_NEW, wrapper.argv, NULL);
1353     gtk_list_store_remove(myfc_ls, &iter);
1354     if (error != 0 )
1355     {
1356       g_free(archive);
1357       g_strfreev(wrapper.argv);
1358       g_object_unref(myfc_ls);
1359       return;
1360     }
1361 
1362     /* then add the rest, if any, to new archive */
1363     if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(myfc_ls), &iter) != FALSE)
1364     {
1365       gtk_tree_model_foreach(GTK_TREE_MODEL(myfc_ls),
1366                              (GtkTreeModelForeachFunc) add_foreach_func,
1367                              &wrapper);
1368       error = wrapper_cmd(AR_ADD, wrapper.argv, NULL);
1369       if (error != 0) {
1370         g_free(archive);
1371         g_strfreev(wrapper.argv);
1372         g_object_unref(myfc_ls);
1373         return;
1374       }
1375     }
1376 
1377     g_strfreev(wrapper.argv);
1378     /* now load up the archive in the notebook */
1379     add_page(archive);
1380   }
1381 
1382   g_free(archive);
1383   g_object_unref(myfc_ls);
1384 }
1385 
1386 void
close_cb(GtkWidget * widget,gpointer data)1387 close_cb(GtkWidget *widget, gpointer data)
1388 {
1389   gint page;
1390   gchar *archive;
1391   GtkWidget *scrollw;
1392 
1393   if ( data != NULL)
1394   {
1395     scrollw = GTK_WIDGET(data);
1396     page = gtk_notebook_page_num(NOTEBOOK, scrollw);
1397     gtk_notebook_set_current_page(NOTEBOOK, page);
1398   }
1399   archive = get_current_archive();
1400   g_free(archive);
1401   page = gtk_notebook_get_current_page(NOTEBOOK);
1402   gtk_notebook_remove_page(NOTEBOOK, page);
1403   gtk_widget_queue_draw(GTK_WIDGET(NOTEBOOK));
1404 
1405   page = gtk_notebook_get_current_page(NOTEBOOK);
1406   if (page < 0)
1407   {
1408     gtk_widget_hide(GTK_WIDGET(NOTEBOOK));
1409     gtk_widget_show(EMPTY);
1410   }
1411 }
1412 
1413 void
close_button_cb(GtkWidget * widget,gpointer data)1414 close_button_cb(GtkWidget *widget, gpointer data)
1415 {
1416   GtkWidget *current_scrollw;
1417   gint page;
1418 
1419   current_scrollw = gtk_notebook_get_nth_page(NOTEBOOK,
1420                             gtk_notebook_get_current_page(NOTEBOOK));
1421   close_cb(widget, data);
1422   page = gtk_notebook_page_num(NOTEBOOK, current_scrollw);
1423   if (page != -1)
1424     gtk_notebook_set_current_page(NOTEBOOK, page);
1425 }
1426 
1427 void
extract_cb(GtkWidget * widget,gpointer data)1428 extract_cb(GtkWidget *widget, gpointer data)
1429 {
1430   /* get selections from current treeview and a destdir.
1431    * create a gchar pointer array with selected files and send
1432    * to wrapper_cmd to process. */
1433   static WrapperData wrapper;
1434   SelectionData seld;
1435   GtkTreeView *treeview;
1436   GtkTreeModel *liststore;
1437   gint sort_column;
1438   GtkSortType sort_order;
1439   gchar *msg;
1440   gint error;
1441 
1442   if ( (treeview = get_current_tree()) == NULL ) return;
1443   liststore = gtk_tree_view_get_model(treeview);
1444   /* if selection contains directories notify user */
1445   seld.sel = gtk_tree_view_get_selection(treeview);
1446 
1447   /* if nothing selected ask to select all */
1448   if (gtk_tree_selection_count_selected_rows(seld.sel) < 1)
1449   {
1450     if (message(MAIN_WINDOW,
1451 		GTK_MESSAGE_WARNING,
1452                 "No files selected,\n\n"
1453                 "assuming you want to extract all") == TRUE)
1454       gtk_tree_selection_select_all(seld.sel);
1455     else return;
1456   }
1457 
1458   wrapper.dir = askfor_extract_dir();
1459   if (wrapper.dir == NULL) return;
1460 
1461   /* if all is selected don't send any files, just extract the whole thing */
1462   if ( gtk_tree_selection_count_selected_rows(seld.sel) ==
1463        gtk_tree_model_iter_n_children(liststore, NULL) )
1464   {
1465     /* need an array for 4 gchar pointers. wrapper option archive null. */
1466     wrapper.argv = g_new(gchar *, 4);
1467     wrapper.argv[ARCHIVE_INDEX] = g_strdup(get_current_archive());
1468     wrapper.argv[FIRST_FILE_INDEX] = NULL;
1469   }
1470   else
1471   {
1472     /* need an array for 4 gchar pointers plus the number of selected files.
1473      * Array will contain: wrapper option archive files... null
1474      */
1475     wrapper.argv = g_new(gchar *,
1476                          (4 +
1477                           gtk_tree_selection_count_selected_rows(seld.sel)));
1478     wrapper.argv[ARCHIVE_INDEX] = g_strdup(get_current_archive());
1479     wrapper.index = FIRST_FILE_INDEX;
1480 
1481     /* for extracting we need the DFILE column sorted descending so that
1482      * the directories are extracted before the children.  Tar
1483      * hiccups if not. So change to that if it's not then
1484      * change back to what ever it was */
1485     gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(liststore),
1486                                          &sort_column, &sort_order);
1487     if ( ! (sort_column == COL_DFILE && sort_order == GTK_SORT_DESCENDING) )
1488     {
1489       gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore),
1490                                            COL_DFILE, GTK_SORT_DESCENDING);
1491     }
1492 
1493     gtk_tree_selection_selected_foreach(seld.sel,
1494                                         (GtkTreeSelectionForeachFunc)
1495                                         selected_foreach_func, &wrapper);
1496 
1497     gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore),
1498                                          sort_column, sort_order);
1499   }
1500   error = wrapper_cmd(AR_EXTRACT, wrapper.argv, wrapper.dir);
1501   if (error == 0)
1502   {
1503     msg = g_strconcat("Done extracting files to:\n\n",
1504                       wrapper.dir, NULL);
1505     message(MAIN_WINDOW,
1506 	    GTK_MESSAGE_INFO, msg);
1507     g_free(msg);
1508   }
1509   g_strfreev(wrapper.argv);
1510   g_free(wrapper.dir);
1511 }
1512 
1513 void
openwith_cb(GtkWidget * widget,gpointer data)1514 openwith_cb(GtkWidget *widget, gpointer data)
1515 {
1516   open_selected_files(FALSE);
1517 }
1518 
1519 void
double_click_cb()1520 double_click_cb()
1521 {
1522   open_selected_files(TRUE);
1523 }
1524 
1525 void
open_selected_files(gboolean use_default_handler)1526 open_selected_files(gboolean use_default_handler)
1527 {
1528   static WrapperData wrapper;
1529   SelectionData seld;
1530   GtkTreeView *treeview;
1531   GtkTreeSelectionForeachFunc foreach_func = (GtkTreeSelectionForeachFunc)
1532     ((use_default_handler)
1533      ? default_handler_foreach_func
1534      : openwith_foreach_func);
1535   gchar *tdir, *rm_command;
1536   const gchar *tpath = NULL;
1537 
1538 
1539   if ( (treeview = get_current_tree()) == NULL ) return;
1540 
1541   seld.sel = gtk_tree_view_get_selection(treeview);
1542 
1543   /* if nothing selected do nothing */
1544   if ( gtk_tree_selection_count_selected_rows(seld.sel) < 1 ) return;
1545 
1546   tpath = g_get_tmp_dir();
1547   tdir = g_strconcat(tpath,"/xarchiveXXXXXX", NULL);
1548   wrapper.dir = mkdtemp(tdir);
1549   wrapper.index = TRUE; /* use index to check for a cancel */
1550   gtk_tree_selection_selected_foreach(seld.sel, foreach_func, &wrapper);
1551 
1552   /* remove temp dir tdir */
1553   rm_command = g_strconcat("rm -fr ", tdir, NULL);
1554   printf("rm_command: %s\n", rm_command);
1555   system(rm_command);
1556   g_free(rm_command);
1557   g_free(tdir);
1558 }
1559 
1560 void
add_cb(GtkWidget * widget,gpointer data)1561 add_cb(GtkWidget *widget, gpointer data)
1562 {
1563   WrapperData wrapper;
1564   GtkListStore *myfc_ls; /*file chooser liststore*/
1565   gchar *archive_disp, *archive;
1566   gint error;
1567 
1568   if ( (archive = get_current_archive()) == NULL ) return;
1569 
1570   if (data != NULL)
1571     myfc_ls = (GtkListStore *) data;
1572   else
1573     myfc_ls = make_myfc_ls();
1574 
1575   archive_disp = g_filename_display_name(archive);
1576   if (multi_file_chooser(archive_disp, myfc_ls) == TRUE)
1577   {
1578     /* need a gchar pointer array for 4 pointers plus the number
1579      * of files on the list (wrapper, option, archive, files.., null)
1580      */
1581     wrapper.argv = g_new(gchar *,
1582                          4 +
1583                          gtk_tree_model_iter_n_children(GTK_TREE_MODEL(myfc_ls),NULL));
1584     wrapper.index = FIRST_FILE_INDEX;
1585     wrapper.argv[ARCHIVE_INDEX] = g_strdup(archive);
1586     gtk_tree_model_foreach( GTK_TREE_MODEL(myfc_ls),
1587                             (GtkTreeModelForeachFunc)
1588                             add_foreach_func,
1589                             &wrapper);
1590     error = wrapper_cmd(AR_ADD, wrapper.argv, NULL);
1591     if (error == 0)
1592     {
1593       reload_current_tree(get_current_tree());
1594     }
1595     g_strfreev(wrapper.argv);
1596   }
1597 
1598   g_free(archive_disp);
1599   g_object_unref(myfc_ls);
1600 }
1601 
1602 void
remove_cb(GtkWidget * widget,gpointer data)1603 remove_cb(GtkWidget *widget, gpointer data)
1604 {
1605   WrapperData wrapper;
1606   SelectionData seld;
1607   GtkTreeView *treeview;
1608   GtkTreeModel *liststore;
1609   gint sort_column;
1610   GtkSortType sort_order;
1611 
1612   if ( (treeview = get_current_tree()) == NULL) return;
1613   liststore = gtk_tree_view_get_model(treeview);
1614   seld.sel = gtk_tree_view_get_selection(treeview);
1615   if ( gtk_tree_selection_count_selected_rows(seld.sel) < 1 ) return;
1616 
1617   wrapper.argv = g_new(gchar *,
1618                        (4 +
1619                         gtk_tree_selection_count_selected_rows(seld.sel)));
1620   wrapper.index = FIRST_FILE_INDEX;
1621   wrapper.argv[ARCHIVE_INDEX] = g_strdup(get_current_archive());
1622 
1623   /* for removing we need the DFILE column sorted descending so that a
1624    * directories children are removed before the directory itself.  Tar
1625    * hiccups if not. So change to that if it's not, do the remove, then
1626    * change back to what ever it was */
1627   gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(liststore),
1628                                        &sort_column, &sort_order);
1629   if ( ! (sort_column == COL_DFILE && sort_order == GTK_SORT_DESCENDING) )
1630   {
1631     gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore),
1632                                          COL_DFILE, GTK_SORT_DESCENDING);
1633   }
1634 
1635   gtk_tree_selection_selected_foreach(seld.sel,
1636                                       (GtkTreeSelectionForeachFunc)
1637                                       selected_foreach_func,
1638                                       &wrapper);
1639 
1640   gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore),
1641                                        sort_column, sort_order);
1642 
1643   wrapper_cmd(AR_REMOVE, wrapper.argv, NULL);
1644   reload_current_tree(treeview);
1645   g_strfreev(wrapper.argv);
1646 }
1647 
1648 void
select_all_cb(GtkWidget * widget,gpointer data)1649 select_all_cb(GtkWidget *widget, gpointer data)
1650 {
1651   GtkTreeView *treeview;
1652   GtkTreeSelection *sel;
1653 
1654   if ( (treeview = get_current_tree()) == NULL ) return;
1655   sel = gtk_tree_view_get_selection(treeview);
1656   gtk_tree_selection_select_all(sel);
1657 }
1658 
1659 void
unselect_all_cb(GtkWidget * widget,gpointer data)1660 unselect_all_cb(GtkWidget *widget, gpointer data)
1661 {
1662   GtkTreeView *treeview;
1663   GtkTreeSelection *sel;
1664 
1665   if ( (treeview = get_current_tree()) == NULL ) return;
1666   sel = gtk_tree_view_get_selection(treeview);
1667   gtk_tree_selection_unselect_all(sel);
1668 }
1669 
1670 void
wrapper_info_cb(GtkWidget * widget,gpointer data)1671 wrapper_info_cb(GtkWidget *widget, gpointer data)
1672 {
1673   GtkWidget *dialog, *infobox;
1674   gchar *wrapinf, *msg;
1675 
1676   dialog = gtk_dialog_new_with_buttons("Wrapper Info",
1677                                        NULL,
1678                                        GTK_DIALOG_DESTROY_WITH_PARENT |
1679                                        GTK_DIALOG_NO_SEPARATOR,
1680                                        GTK_STOCK_OK,
1681                                        GTK_RESPONSE_ACCEPT,
1682                                        NULL);
1683   g_signal_connect_swapped(dialog, "response",
1684                            G_CALLBACK(gtk_widget_destroy),
1685                            dialog);
1686   gtk_widget_set_size_request(dialog, 500, 300);
1687 
1688   wrapinf = wrapper_info();
1689   msg = g_strdup_printf("%s\n%s\n\n%s",
1690                         PACKAGE_STRING, PACKAGE_BUGREPORT, wrapinf);
1691   g_free(wrapinf);
1692   infobox = make_info_widget(msg);
1693   g_free(msg);
1694 
1695   gtk_box_pack_start(GTK_BOX( GTK_DIALOG(dialog)->vbox ), infobox, TRUE,TRUE,0);
1696 
1697   gtk_widget_show_all(dialog);
1698 }
1699 
1700 void
read_help_cb(GtkWidget * widget,gpointer data)1701 read_help_cb(GtkWidget *widget, gpointer data)
1702 {
1703   GtkWidget *dialog, *infobox;
1704   gchar *helptxt;
1705 
1706   dialog = gtk_dialog_new_with_buttons("View Help",
1707                                        NULL,
1708                                        GTK_DIALOG_DESTROY_WITH_PARENT |
1709                                        GTK_DIALOG_NO_SEPARATOR,
1710                                        GTK_STOCK_OK,
1711                                        GTK_RESPONSE_ACCEPT,
1712                                        NULL);
1713   g_signal_connect_swapped(dialog, "response",
1714                            G_CALLBACK(gtk_widget_destroy),
1715                            dialog);
1716   gtk_widget_set_size_request(dialog, 500, 300);
1717 
1718   g_file_get_contents(HELP_FILE_PATH, &helptxt, NULL, NULL);
1719   infobox = make_info_widget(helptxt);
1720   g_free(helptxt);
1721   gtk_box_pack_start(GTK_BOX( GTK_DIALOG(dialog)->vbox ),
1722                      infobox, TRUE,TRUE,0);
1723 
1724   gtk_widget_show_all(dialog);
1725 }
1726 
1727 static gboolean
open_cancel_cb(GtkWidget * widget,gpointer data)1728 open_cancel_cb(GtkWidget *widget, gpointer data)
1729 {
1730   gboolean *stopit = (gboolean *) data;
1731 
1732   *stopit = TRUE;
1733   return FALSE;
1734 }
1735 
1736 static gboolean
process_cancel_cb(GtkWidget * widget,gpointer data)1737 process_cancel_cb(GtkWidget *widget, gpointer data)
1738 {
1739   pid_t pid = (pid_t) GPOINTER_TO_INT(data);
1740   gint err;
1741 
1742   printf("Trying to send kill signal to process %d\n", pid);
1743   err = kill( pid, SIGTERM);
1744   printf("Returned from kill: %d\n", err);
1745   return FALSE;
1746 }
1747 
1748 /***********************/
1749 /* UIMananger functions*/
1750 /***********************/
1751 void
add_ui_widget(GtkUIManager * uimanager,GtkWidget * widget,GtkContainer * container)1752 add_ui_widget(GtkUIManager *uimanager,
1753               GtkWidget *widget,
1754               GtkContainer *container)
1755 {
1756   GtkToolbar *toolbar;
1757 
1758   gtk_box_pack_start (GTK_BOX(container), widget, FALSE, FALSE, 0);
1759   gtk_widget_show(widget);
1760   if (GTK_IS_TOOLBAR(widget))
1761   {
1762     toolbar = GTK_TOOLBAR(widget);
1763     gtk_toolbar_set_show_arrow(toolbar, TRUE);
1764   }
1765 }
1766 
1767 GtkUIManager *
make_ui_widgets(GtkWidget * window,GtkWidget * box)1768 make_ui_widgets(GtkWidget *window, GtkWidget *box)
1769 {
1770   GtkUIManager *uimanager;
1771   GtkActionGroup *action_group;
1772   GError *error = NULL;
1773   GtkActionEntry entries[] = {
1774     { "FileMenuAction", NULL, "_File" },
1775     { "ActionsMenuAction", NULL, "_Archive" },
1776     { "HelpMenuAction", NULL, "_Help" },
1777     { "PopupMenuAction", NULL, "_Popup" },
1778     { "new", GTK_STOCK_NEW, "_New", "<control>N",
1779       "(CTRL-N) Create new archive", G_CALLBACK(new_cb)},
1780     { "open", GTK_STOCK_OPEN, "_Open", "<control>O",
1781       "(CTRL-O) Open exisiting archive", G_CALLBACK(open_cb)},
1782     { "close", GTK_STOCK_CLOSE, "_Close", "<control>W",
1783       "(CTRL-W) Close current archive window", G_CALLBACK(close_cb)},
1784     { "quit", GTK_STOCK_QUIT, "_Quit", "<control>Q",
1785       "(CTRL-Q) Quit application, closing all open archives",
1786       G_CALLBACK(gtk_main_quit)},
1787     { "extract", GTK_STOCK_HARDDISK, "_Extract", "<control>E",
1788       "(CTRL-E) Extract selected files from current archive",
1789       G_CALLBACK(extract_cb)},
1790     { "add", GTK_STOCK_ADD, "_Add", "<control>A",
1791       "(CTRL-A) Add files to current archive", G_CALLBACK(add_cb)},
1792     { "remove", GTK_STOCK_REMOVE, "_Remove", "<control>R",
1793       "(CTRL-R) Remove selected files from current archive", G_CALLBACK(remove_cb)},
1794     { "openwith", GTK_STOCK_EXECUTE, "O_pen With...", "<control>P",
1795       "(CTRL-P) Temporarily extract the selected files from current archive then open them with the specified application", G_CALLBACK(openwith_cb)},
1796     { "SelectionMenuAction", NULL, "_Selection" },
1797     { "select all", GTK_STOCK_APPLY, "_Select All", "<control>S",
1798       "(CTRL-S) selected all files in current archive", G_CALLBACK(select_all_cb)},
1799     { "unselect all", GTK_STOCK_CLEAR, "_Unselect All", "<control>U",
1800       "(CTRL-U) unselect all files in current archive", G_CALLBACK(unselect_all_cb)},
1801     { "wrapper info", GTK_STOCK_ABOUT, "Wrapper _Info", "<control>I",
1802       "(CTRL-I) Show information on found wrappers", G_CALLBACK(wrapper_info_cb)},
1803     { "read help", GTK_STOCK_HELP, "Read _Help", "<control>H",
1804       "(CTRL-H) Read help file", G_CALLBACK(read_help_cb)},
1805   };
1806   guint n_entries = G_N_ELEMENTS(entries);
1807   gchar *ui_info =
1808     "  <menubar>\n"
1809     "    <menu name=\"_File\" action=\"FileMenuAction\">\n"
1810     "      <menuitem name=\"open\" action=\"open\" />\n"
1811     "      <menuitem name=\"new\" action=\"new\" />\n"
1812     "      <menuitem name=\"close\" action=\"close\" />\n"
1813     "      <separator name=\"sep1\" />\n"
1814     "      <menuitem name=\"quit\" action=\"quit\" />\n"
1815     "    </menu>\n"
1816     "    <menu name=\"_Selection\" action=\"SelectionMenuAction\">\n"
1817     "      <menuitem name=\"select all\" action=\"select all\" />\n"
1818     "      <menuitem name=\"unselect all\" action=\"unselect all\" />\n"
1819     "    </menu>\n"
1820     "    <menu name=\"_Actions\" action=\"ActionsMenuAction\" >\n"
1821     "      <menuitem name=\"extract\" action=\"extract\" />\n"
1822     "      <menuitem name=\"openwith\" action=\"openwith\" />\n"
1823     "      <menuitem name=\"remove\" action=\"remove\" />\n"
1824     "      <menuitem name=\"add\" action=\"add\" />\n"
1825     "    </menu>\n"
1826     "    <menu name=\"_Help\" action=\"HelpMenuAction\" >\n"
1827     "      <menuitem name=\"read help\" action=\"read help\" />\n"
1828     "      <menuitem name=\"wrapper info\" action=\"wrapper info\" />\n"
1829     "    </menu>\n"
1830     "  </menubar>\n"
1831     "  <toolbar name=\"toolbar\">\n"
1832     "    <toolitem name=\"open\" action=\"open\" />\n"
1833     "    <toolitem name=\"new\" action=\"new\" />\n"
1834     "    <toolitem name=\"close\" action=\"close\" />\n"
1835     "    <separator name=\"sep1\" /> \n"
1836     "    <toolitem name=\"select all\" action=\"select all\" />\n"
1837     "    <toolitem name=\"unselect all\" action=\"unselect all\" />\n"
1838     "    <separator name=\"sep2\" /> \n"
1839     "    <toolitem name=\"extract\" action=\"extract\" />\n"
1840     "    <toolitem name=\"openwith\" action=\"openwith\" />\n"
1841     "    <toolitem name=\"remove\" action=\"remove\" />\n"
1842     "    <toolitem name=\"add\" action=\"add\" />\n"
1843     "    <separator name=\"sep3\" /> \n"
1844     "    <toolitem name=\"quit\" action=\"quit\" />\n"
1845     "  </toolbar>\n"
1846     "  <popup name=\"treeview_popup\" action=\"PopupMenuAction\">\n"
1847     "    <menuitem name=\"select all\" action=\"select all\" />\n"
1848     "    <menuitem name=\"unselect all\" action=\"unselect all\" />\n"
1849     "    <separator name=\"sep4\" /> \n"
1850     "    <menuitem name=\"extract\" action=\"extract\" />\n"
1851     "    <menuitem name=\"openwith\" action=\"openwith\" />\n"
1852     "    <menuitem name=\"remove\" action=\"remove\" />\n"
1853     "    <menuitem name=\"add\" action=\"add\" />\n"
1854     "    <separator name=\"sep5\" /> \n"
1855     "    <menuitem name=\"close\" action=\"close\" />\n"
1856     "  </popup>\n"
1857     ;
1858 
1859   action_group = gtk_action_group_new("XArchiveActions");
1860   gtk_action_group_add_actions(action_group, entries, n_entries, NULL);
1861 
1862   uimanager = gtk_ui_manager_new();
1863   gtk_ui_manager_insert_action_group(uimanager, action_group, 0);
1864   g_signal_connect(uimanager, "add_widget", G_CALLBACK(add_ui_widget), box);
1865   gtk_window_add_accel_group(GTK_WINDOW(window),
1866                              gtk_ui_manager_get_accel_group(uimanager));
1867   if (!gtk_ui_manager_add_ui_from_string(uimanager, ui_info, -1, &error))
1868   {
1869     g_message("building menus failed: %s", error->message);
1870     g_error_free(error);
1871   }
1872   return uimanager;
1873 }
1874 
1875 
1876 /******************************/
1877 /* passed aurgument functions */
1878 /******************************/
1879 
1880 gint
ask_create_or_add(gchar * msg)1881 ask_create_or_add(gchar *msg)
1882 {
1883   gint response;
1884   GtkWidget *md;
1885 
1886   md = gtk_message_dialog_new(GTK_WINDOW(MAIN_WINDOW),
1887                               GTK_DIALOG_DESTROY_WITH_PARENT,
1888                               GTK_MESSAGE_QUESTION,
1889                               GTK_BUTTONS_CANCEL,
1890                               msg);
1891   gtk_dialog_add_buttons(GTK_DIALOG(md),
1892                          "New", AR_NEW,
1893                          "Existing", AR_ADD,
1894                          NULL);
1895   gtk_dialog_set_alternative_button_order(GTK_DIALOG(md), AR_NEW, AR_ADD,
1896                                           GTK_RESPONSE_CANCEL, -1);
1897   response = gtk_dialog_run(GTK_DIALOG(md));
1898   gtk_widget_destroy(md);
1899 
1900   return response;
1901 }
1902 
1903 void
process_passed_arguments(ParsedArgs * pargs)1904 process_passed_arguments(ParsedArgs *pargs)
1905 {
1906   gchar *archive = NULL, *msg, *filepath;
1907   gint i, response=AR_ADD;
1908   GtkListStore *filelist;
1909 
1910   switch (pargs->action)
1911   {
1912     case AR_OPEN:
1913       if (pargs->files == NULL) break;
1914       for (i=0; pargs->files[i] != NULL; i++)
1915       {
1916         archive = canonicalize_file_name(pargs->files[i]);
1917         if(archive != NULL) add_page(archive);
1918         else
1919         {
1920           msg = g_strconcat("Could not open archive:\n\n",
1921                             pargs->files[i], NULL);
1922           message(MAIN_WINDOW,
1923 		  GTK_MESSAGE_ERROR, msg);
1924           g_free(msg);
1925         }
1926       }
1927       break;
1928 
1929     case AR_ADD:
1930       msg = g_strdup_printf("Would you like to:\n"
1931                             "Create a new archive, or\n"
1932                             "Add to an existing archive?");
1933       if (strcmp(pargs->archive,"ask") != 0 &&
1934           (archive = canonicalize_file_name(pargs->archive)) == NULL)
1935         msg = g_strdup_printf("Archive not found\n%s\n\n%s",
1936                               pargs->archive, msg);
1937       else
1938       {
1939         g_free(pargs->archive);
1940         pargs->archive = NULL;
1941       }
1942 
1943       if (archive == NULL &&
1944           (response = ask_create_or_add(msg)) == AR_ADD)
1945         archive = askfor_existing_archive();
1946 
1947       filelist = make_myfc_ls();
1948       if (pargs->files != NULL)
1949         for (i=0; pargs->files[i] != NULL; i++)
1950         {
1951           filepath = canonicalize_file_name(pargs->files[i]);
1952           if (filepath == NULL) continue;
1953           else myfc_add_foreach_func(filepath, filelist);
1954           g_free(filepath);
1955         }
1956 
1957       if (response == AR_ADD && archive != NULL)
1958       {
1959         add_page(archive);
1960         add_cb(NULL, (gpointer) filelist);
1961       }
1962       else if (response == AR_NEW)
1963       {
1964         g_object_set_data(G_OBJECT(filelist),"name", (gpointer)pargs->archive);
1965         new_cb(NULL, (gpointer) filelist);
1966       }
1967       else
1968         gtk_widget_show(EMPTY);
1969 
1970       g_free(archive);
1971       break;
1972 
1973     case AR_NEW:
1974       if (strcmp(pargs->archive, "ask") == 0)
1975       {
1976         g_free(pargs->archive);
1977         pargs->archive = NULL;
1978       }
1979       filelist = make_myfc_ls();
1980       if (pargs->files != NULL)
1981         for (i=0; pargs->files[i] != NULL; i++)
1982         {
1983           filepath = canonicalize_file_name(pargs->files[i]);
1984           if (filepath == NULL) continue;
1985           else myfc_add_foreach_func(filepath, filelist);
1986           g_free(filepath);
1987         }
1988       g_object_set_data(G_OBJECT(filelist),"name", (gpointer)pargs->archive);
1989       new_cb(NULL, (gpointer) filelist);
1990       break;
1991 
1992     default:
1993       gtk_widget_show(EMPTY);
1994       break;
1995   }
1996 }
1997 
1998 /***********************/
1999 /* Main setup function */
2000 /***********************/
2001 
2002 int
make_widgets(ParsedArgs * pargs)2003 make_widgets(ParsedArgs *pargs)
2004 {
2005   GdkGeometry size_hints;
2006   GtkWidget *mainbox;
2007   static GdkPixbuf *xarchive_pixbuf;
2008 
2009   MAIN_WINDOW = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2010   xarchive_pixbuf = gdk_pixbuf_new_from_xpm_data(xarchive_xpm);
2011   gtk_window_set_default_icon(xarchive_pixbuf);
2012   g_signal_connect(G_OBJECT(MAIN_WINDOW), "delete_event",
2013                    G_CALLBACK(gtk_main_quit), NULL);
2014   g_signal_connect(G_OBJECT(MAIN_WINDOW), "destroy",
2015                    G_CALLBACK(gtk_main_quit), NULL);
2016 
2017   gtk_container_set_border_width(GTK_CONTAINER(MAIN_WINDOW), 0);
2018   gtk_window_set_title (GTK_WINDOW(MAIN_WINDOW), PACKAGE_STRING);
2019   size_hints.min_width=300;
2020   size_hints.min_height=250;
2021   size_hints.base_width=0;
2022   size_hints.base_height=0;
2023   gtk_window_set_geometry_hints(GTK_WINDOW(MAIN_WINDOW), MAIN_WINDOW,
2024                                 &size_hints,
2025                                  GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE);
2026   gtk_window_set_default_size(GTK_WINDOW(MAIN_WINDOW), 640, 400);
2027   if (pargs->geom != NULL)
2028     gtk_window_parse_geometry(GTK_WINDOW(MAIN_WINDOW), pargs->geom);
2029 
2030   mainbox = gtk_vbox_new(FALSE, 0);
2031   gtk_container_add(GTK_CONTAINER(MAIN_WINDOW), mainbox);
2032 
2033   UIMANAGER = make_ui_widgets(MAIN_WINDOW, mainbox);
2034 
2035   make_empty_page(mainbox);
2036   make_notebook_widgets(mainbox);
2037 
2038   process_passed_arguments(pargs);
2039 
2040   gtk_widget_show(mainbox);
2041   gtk_widget_show(MAIN_WINDOW);
2042   gtk_main();
2043   return 0;
2044 }
2045