xarchive  0.2.8-6
About: XArchive is a GTK+ front-end for command line archiving tools.
  Fossies Dox: xarchive-0.2.8-6.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

widgets_gtk.c
Go to the documentation of this file.
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 *
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 *
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 *
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());
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 *
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 *
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
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
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  {
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 *
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);
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
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)
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)
1588  &wrapper);
1589  error = wrapper_cmd(AR_ADD, wrapper.argv, NULL);
1590  if (error == 0)
1591  {
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)
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
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
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);
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
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 
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 }
open_selected_files
void open_selected_files(gboolean use_default_handler)
Definition: widgets_gtk.c:1525
UIMANAGER
GtkUIManager * UIMANAGER
Definition: widgets_gtk.h:32
make_myfc_ls
GtkListStore * make_myfc_ls(void)
Definition: myfc_gtk.c:121
wrapper_info
gchar * wrapper_info(void)
Definition: main.c:152
wrapper_data
Definition: widgets_gtk.h:24
AR_OPEN
Definition: common.h:12
start_myfc_onDragDataRecived
void start_myfc_onDragDataRecived(GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *seldata, guint info, guint time, gpointer userdata)
Definition: widgets_gtk.c:34
unselect_all_cb
void unselect_all_cb(GtkWidget *widget, gpointer data)
Definition: widgets_gtk.c:1659
read_help_cb
void read_help_cb(GtkWidget *widget, gpointer data)
Definition: widgets_gtk.c:1700
parsed_arguments::geom
char * geom
Definition: common.h:24
make_info_widget
GtkWidget * make_info_widget(gchar *msg)
Definition: widgets_gtk.c:521
sel_subdir_foreach_func
gboolean sel_subdir_foreach_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, SelectionData *seld)
Definition: widgets_gtk.c:609
my_search_equal_func
gboolean my_search_equal_func(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer search_data)
Definition: widgets_gtk.c:67
EMPTY
GtkWidget * EMPTY
Definition: widgets_gtk.h:34
get_default_handler
void get_default_handler(void)
Definition: widgets_gtk.c:1074
close_button_cb
void close_button_cb(GtkWidget *widget, gpointer data)
Definition: widgets_gtk.c:1413
select_all_cb
void select_all_cb(GtkWidget *widget, gpointer data)
Definition: widgets_gtk.c:1648
process_cancel_cb
static gboolean process_cancel_cb(GtkWidget *widget, gpointer data)
Definition: widgets_gtk.c:1736
askfor_extract_dir
gchar * askfor_extract_dir(void)
Definition: widgets_gtk.c:887
askfor_existing_archive
gchar * askfor_existing_archive(void)
Definition: widgets_gtk.c:721
COL_GROUP
Definition: common.h:16
COL_ICON
Definition: common.h:16
file_filter_func
gboolean file_filter_func(const GtkFileFilterInfo *filter_info, gpointer data)
Definition: widgets_gtk.c:707
COL_TIME
Definition: common.h:17
COL_LINK
Definition: common.h:17
parsed_arguments::files
char ** files
Definition: common.h:22
get_current_tree
GtkTreeView * get_current_tree(void)
Definition: widgets_gtk.c:192
make_notebook_widgets
void make_notebook_widgets(GtkWidget *container)
Definition: widgets_gtk.c:309
wrapper_info_cb
void wrapper_info_cb(GtkWidget *widget, gpointer data)
Definition: widgets_gtk.c:1670
askfor_new_archive
gchar * askfor_new_archive(gchar *name)
Definition: widgets_gtk.c:757
add_cb
void add_cb(GtkWidget *widget, gpointer data)
Definition: widgets_gtk.c:1560
AR_REMOVE
Definition: common.h:12
process_passed_arguments
void process_passed_arguments(ParsedArgs *pargs)
Definition: widgets_gtk.c:1903
dummy_cb
void dummy_cb(GtkWidget *widget, gpointer data)
Definition: widgets_gtk.c:1291
reload_current_tree
void reload_current_tree(GtkTreeView *treeview)
Definition: widgets_gtk.c:263
sel_data::dname
gchar * dname
Definition: widgets_gtk.h:20
get_current_archive
gchar * get_current_archive(void)
Definition: widgets_gtk.c:209
COL_USER
Definition: common.h:16
COL_DFILE
Definition: common.h:16
AR_ADD
Definition: common.h:12
extract_cb
void extract_cb(GtkWidget *widget, gpointer data)
Definition: widgets_gtk.c:1427
wrapper_cmd
gint wrapper_cmd(gint ar_func, gchar *argv[], gchar *dir)
Definition: main.c:287
askfor_openwith_command
gchar * askfor_openwith_command(gchar *fname)
Definition: widgets_gtk.c:1182
COL_FILE
Definition: common.h:16
PACKAGE_STRING
#define PACKAGE_STRING
Definition: config.h:112
get_wrapper
gchar * get_wrapper(gchar *archive)
Definition: main.c:188
select_extract_dir
void select_extract_dir(GtkWidget *widget, GtkWidget *entry)
Definition: widgets_gtk.c:863
NUM_COLS
Definition: common.h:17
MAIN_WINDOW
GtkWidget * MAIN_WINDOW
Definition: widgets_gtk.h:35
parsed_arguments
Definition: common.h:19
double_click_cb
void double_click_cb()
Definition: widgets_gtk.c:1519
open_cancel_cb
static gboolean open_cancel_cb(GtkWidget *widget, gpointer data)
Definition: widgets_gtk.c:1727
render_cols
void render_cols(GtkTreeView *view, gchar *title, gint mcol)
Definition: widgets_gtk.c:85
wait_with_progress_bar
void wait_with_progress_bar(GPid pid, gint *wrapper_status, gint ar_func)
Definition: widgets_gtk.c:449
AR_NEW
Definition: common.h:12
sel_data
Definition: widgets_gtk.h:17
COL_ATTR
Definition: common.h:16
my_strescape
gchar * my_strescape(gchar *string)
Definition: my_strescape.c:50
add_page
void add_page(gchar *archive)
Definition: widgets_gtk.c:322
remove_cb
void remove_cb(GtkWidget *widget, gpointer data)
Definition: widgets_gtk.c:1602
PACKAGE_BUGREPORT
#define PACKAGE_BUGREPORT
Definition: config.h:106
default_handler_foreach_func
void default_handler_foreach_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, WrapperData *wrapper)
Definition: widgets_gtk.c:1145
make_myfc
GtkDialog * make_myfc(gchar *archive, GtkListStore *myfc_ls)
Definition: myfc_gtk.c:207
getline
ssize_t getline(char **lineptr, size_t *n, FILE *stream)
Definition: main.c:34
make_ui_widgets
GtkUIManager * make_ui_widgets(GtkWidget *window, GtkWidget *box)
Definition: widgets_gtk.c:1767
AR_EXTRACT
Definition: common.h:12
open_cb
void open_cb(GtkWidget *widget, gpointer data)
Definition: widgets_gtk.c:1297
setup_opening_progress_bar
void setup_opening_progress_bar(GtkWidget *pbwin, GtkWidget *pbar, gboolean *stopit)
Definition: widgets_gtk.c:420
FIRST_FILE_INDEX
Definition: common.h:14
ask_create_or_add
gint ask_create_or_add(gchar *msg)
Definition: widgets_gtk.c:1880
unsel_subdir_foreach_func
gboolean unsel_subdir_foreach_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, SelectionData *seld)
Definition: widgets_gtk.c:627
parsed_arguments::archive
char * archive
Definition: common.h:23
get_openwith_cmdlist
GtkListStore * get_openwith_cmdlist(gchar *cmdlist_path)
Definition: widgets_gtk.c:959
add_to_cmdlist
void add_to_cmdlist(GtkListStore *cmdlist, gchar *command, gchar *cmdlist_path)
Definition: widgets_gtk.c:994
ARCHIVE_INDEX
Definition: common.h:14
message
gboolean message(GtkWidget *parentwin, gint type, gchar *text)
Definition: widgets_gtk.c:551
wrapper_data::index
gint index
Definition: widgets_gtk.h:27
sel_data::dirs
gboolean dirs
Definition: widgets_gtk.h:21
openwith_cb
void openwith_cb(GtkWidget *widget, gpointer data)
Definition: widgets_gtk.c:1513
sel_data::sel
GtkTreeSelection * sel
Definition: widgets_gtk.h:19
test_selection_func
gboolean test_selection_func(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer data)
Definition: widgets_gtk.c:645
wrapper_data::dir
gchar * dir
Definition: widgets_gtk.h:26
get_lastdir
void get_lastdir(void)
Definition: widgets_gtk.c:1040
treeview_button_press
gboolean treeview_button_press(GtkWidget *container, GdkEventButton *event, GtkUIManager *uimanager)
Definition: widgets_gtk.c:282
make_empty_page
void make_empty_page(GtkWidget *container)
Definition: widgets_gtk.c:540
multi_file_chooser
gboolean multi_file_chooser(gchar *archive, GtkListStore *filelist)
Definition: widgets_gtk.c:827
add_ui_widget
void add_ui_widget(GtkUIManager *uimanager, GtkWidget *widget, GtkContainer *container)
Definition: widgets_gtk.c:1751
make_widgets
int make_widgets(ParsedArgs *pargs)
Definition: widgets_gtk.c:2002
add_foreach_func
gboolean add_foreach_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, WrapperData *wrapper)
Definition: widgets_gtk.c:699
selected_foreach_func
void selected_foreach_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, WrapperData *wrapper)
Definition: widgets_gtk.c:590
NOTEBOOK
GtkNotebook * NOTEBOOK
Definition: widgets_gtk.h:33
open_one_file
void open_one_file(WrapperData *wrapper, gchar *command)
Definition: widgets_gtk.c:1128
new_cb
void new_cb(GtkWidget *widget, gpointer data)
Definition: widgets_gtk.c:1310
myfc_add_foreach_func
void myfc_add_foreach_func(gchar *fpath, GtkListStore *myfc_ls)
Definition: myfc_gtk.c:22
widgets_gtk.h
parsed_arguments::action
int action
Definition: common.h:21
COL_SIZE
Definition: common.h:16
openwith_foreach_func
void openwith_foreach_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, WrapperData *wrapper)
Definition: widgets_gtk.c:1250
make_liststore
GtkListStore * make_liststore(void)
Definition: widgets_gtk.c:128
set_default_handler
void set_default_handler(gchar *command)
Definition: widgets_gtk.c:1104
wrapper_data::argv
gchar ** argv
Definition: widgets_gtk.h:28
make_tree
GtkWidget * make_tree(GtkListStore *liststore)
Definition: widgets_gtk.c:143
add_row
void add_row(GtkListStore *liststore, gchar **ent)
Definition: widgets_gtk.c:228
canonicalize_file_name
char * canonicalize_file_name(char *path)
Definition: main.c:24
close_cb
void close_cb(GtkWidget *widget, gpointer data)
Definition: widgets_gtk.c:1386