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