/* * widgets_gtk.c - main gtk widgets for xarchive * Copyright (C) 2005 Lee Bigelow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include"widgets_gtk.h" #ifndef HAVE_CANONICALIZE_FILE_NAME /* from main.c */ char * canonicalize_file_name(char *path); #endif #ifndef HAVE_GETLINE ssize_t getline(char **lineptr, size_t *n, FILE *stream); #endif /***********************/ /* tree view functions */ /***********************/ void start_myfc_onDragDataRecived(GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *seldata, guint info, guint time, gpointer userdata) { GtkListStore *myfc_ls; GtkTreeIter iter; gchar **uri_list; gchar *hostname; gchar *filename; gint i; myfc_ls = make_myfc_ls(); uri_list = gtk_selection_data_get_uris(seldata); for(i=0; uri_list[i] != NULL; i++) { filename = g_filename_from_uri(uri_list[i], &hostname, NULL); if ( filename != NULL && g_file_test(filename, G_FILE_TEST_EXISTS) ) myfc_add_foreach_func(filename, myfc_ls); g_free(filename); } if (uri_list != NULL) g_strfreev(uri_list); if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(myfc_ls), &iter) == TRUE) add_cb(NULL, (gpointer) myfc_ls); else g_object_unref(myfc_ls); } gboolean my_search_equal_func(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer search_data) { gchar *haystack; gboolean res; gtk_tree_model_get(model, iter, COL_DFILE, &haystack, -1); res = (strcasestr(haystack, key) == NULL); g_free(haystack); return res; } void render_cols(GtkTreeView *view, gchar *title, gint mcol) { /* mcol is the liststore model coluumn. * tvcol is the treeview column. * Make a renderer to link the two, set the col header, * and make the column sortable. */ GtkTreeViewColumn *tvcol; GtkCellRenderer *renderer; tvcol = gtk_tree_view_column_new(); if (mcol == COL_DFILE) { renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_start(tvcol, renderer, FALSE); gtk_tree_view_column_add_attribute(tvcol, renderer, "stock-id", COL_ICON); } renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(tvcol, renderer, TRUE); gtk_tree_view_column_add_attribute(tvcol, renderer, "text", mcol); gtk_tree_view_column_set_title(tvcol, title); switch ( mcol ) { case COL_DFILE: gtk_tree_view_column_set_sizing(tvcol, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width(tvcol, 300); break; case COL_LINK: gtk_tree_view_column_set_sizing(tvcol, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width(tvcol, 60); break; } gtk_tree_view_column_set_resizable(tvcol, TRUE); gtk_tree_view_append_column(view, tvcol); gtk_tree_view_column_set_sort_column_id(tvcol, mcol); } GtkListStore * make_liststore(void) { GtkListStore *liststore; /* icon, file, dfile, size, attr, user, group, time, link */ liststore = gtk_list_store_new(NUM_COLS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_ULONG, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); return liststore; } GtkWidget * make_tree(GtkListStore *liststore) { /* Make an empty treeview attached to liststore. * Then attach a renderer to each column in the view.*/ GtkTreeView *treeview; GtkTreeSelection *sel; enum { TARGET_URI }; GtkTargetEntry targetentries[] = { { "text/uri-list", 0, TARGET_URI }, }; treeview = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(liststore))); gtk_tree_view_set_rules_hint(treeview, TRUE); sel = gtk_tree_view_get_selection(treeview); gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE); gtk_tree_selection_set_select_function(sel, (GtkTreeSelectionFunc)test_selection_func, NULL, NULL); render_cols(treeview, "File", COL_DFILE); render_cols(treeview, "SymLink", COL_LINK); render_cols(treeview, "Size", COL_SIZE); render_cols(treeview, "Permissions", COL_ATTR); render_cols(treeview, "User", COL_USER); render_cols(treeview, "Group", COL_GROUP); render_cols(treeview, "Time", COL_TIME); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore), COL_DFILE, GTK_SORT_ASCENDING); gtk_tree_view_set_search_column(treeview, COL_DFILE); gtk_tree_view_set_enable_search(treeview, TRUE); gtk_tree_view_set_search_equal_func(treeview, (GtkTreeViewSearchEqualFunc) my_search_equal_func, NULL, NULL); /* setup drag and drop attributes */ gtk_drag_dest_set(GTK_WIDGET(treeview), GTK_DEST_DEFAULT_ALL, targetentries, 1, GDK_ACTION_COPY|GDK_ACTION_MOVE); g_signal_connect(GTK_WIDGET(treeview), "drag_data_received", G_CALLBACK(start_myfc_onDragDataRecived), NULL); return GTK_WIDGET(treeview); } GtkTreeView * get_current_tree(void) { /* current notebook page contains a scrollwindow, * from which we get the current treeview. */ gint page; GtkWidget *scrollwin; GtkWidget *treeview; if ( (page = gtk_notebook_get_current_page(NOTEBOOK)) < 0) return NULL; scrollwin = gtk_notebook_get_nth_page(NOTEBOOK, page); treeview = gtk_bin_get_child(GTK_BIN(scrollwin)); return GTK_TREE_VIEW(treeview); } gchar * get_current_archive(void) { /* current notebook page contains scrollwindow, * the archive path from it's label */ GtkTreeView *treeview; GtkTreeModel *liststore; gchar *archive; if ( (treeview = get_current_tree()) != NULL) { liststore = gtk_tree_view_get_model(treeview); archive = (gchar *) g_object_get_data(G_OBJECT(liststore), "archive_path"); return archive; } return NULL; } void add_row(GtkListStore *liststore, gchar **ent) { /* add a row to the liststore model attached to the treeview on * the current notebook page. */ enum {name=0,size,attr,user,group,date,time,link,num_ent}; GtkTreeIter iter; gchar *icon = GTK_STOCK_FILE; gchar *dfname; gchar time_string[20]; sprintf(time_string, "%s %s", ent[date], ent[time]); dfname = g_filename_display_name(ent[name]); if (g_str_has_prefix(ent[attr],"d") == TRUE) { icon=GTK_STOCK_DIRECTORY; } gtk_list_store_append(liststore, &iter); gtk_list_store_set(liststore, &iter, COL_ICON, icon, COL_FILE, ent[name], COL_DFILE, dfname, COL_SIZE, strtoul(ent[size],NULL,10), COL_ATTR, ent[attr], COL_USER, ent[user], COL_GROUP, ent[group], COL_TIME, time_string, COL_LINK, ent[link], -1); g_free(dfname); } void reload_current_tree(GtkTreeView *treeview) { /* clear liststore, then reload * data from archive */ GtkTreeModel *liststore; gchar *argv[4]; /* wrapper, option, archive, NULL */ argv[ARCHIVE_INDEX] = g_strdup(get_current_archive()); argv[ARCHIVE_INDEX + 1] = NULL; liststore = gtk_tree_view_get_model(treeview); gtk_list_store_clear(GTK_LIST_STORE(liststore)); /* reload archive data */ if (wrapper_cmd(AR_OPEN, argv, NULL) < 0) { close_cb(NULL, NULL); } } gboolean treeview_button_press(GtkWidget *container, GdkEventButton *event, GtkUIManager *uimanager) { gtk_widget_grab_focus (container); if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { GtkWidget *menu = gtk_ui_manager_get_widget(uimanager, "/treeview_popup"); if (GTK_IS_MENU (menu)) { gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, container, 3, event->time); return TRUE; } } else if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) double_click_cb(); return FALSE; } /**********************/ /* notebook functions */ /**********************/ void make_notebook_widgets(GtkWidget *container) { NOTEBOOK = GTK_NOTEBOOK(gtk_notebook_new()); get_default_handler(); get_lastdir(); gtk_box_pack_end(GTK_BOX(container), GTK_WIDGET(NOTEBOOK),TRUE,TRUE,0); gtk_notebook_set_tab_pos(NOTEBOOK, GTK_POS_TOP); gtk_notebook_set_show_tabs(NOTEBOOK, TRUE); gtk_notebook_set_scrollable(NOTEBOOK, TRUE); gtk_notebook_popup_enable(NOTEBOOK); } void add_page(gchar *archive) { /* Add a page to the end of the notebook and make it active. * Page contains a scrolled window with a treeview in it. * Then get the data for the treeview model. */ GtkWidget *label, *image, *hbox, *button, *scrollw, *treeview; GtkListStore *liststore; GtkTooltips *button_tips = gtk_tooltips_new(); gchar *archive_path; gchar *archive_disp; gchar **argv; /* hide empty page and show notebook if neccessary */ if (gtk_notebook_get_current_page(NOTEBOOK) < 0) { gtk_widget_hide(EMPTY); gtk_widget_show(GTK_WIDGET(NOTEBOOK)); } archive_path = g_strdup(archive); archive_disp = g_filename_display_name(archive_path); /* make scrollw and it's label, then append to notebook and make * it the current active page */ scrollw = gtk_scrolled_window_new(NULL, NULL); gtk_widget_show(scrollw); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); hbox = gtk_hbox_new(FALSE, 2); label = gtk_label_new(archive_disp); g_free(archive_disp); gtk_label_set_max_width_chars(GTK_LABEL(label), 50); gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_START); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); button = gtk_button_new(); gtk_tooltips_set_tip(button_tips, button, "Close Archive", NULL); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(close_button_cb), (gpointer) scrollw); image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU); gtk_widget_set_size_request(image, 8, 8); gtk_container_add(GTK_CONTAINER(button), image); gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0); gtk_widget_show_all(hbox); gtk_notebook_append_page(NOTEBOOK, scrollw, hbox); gtk_notebook_set_current_page(NOTEBOOK, -1); /* make treeview with attached liststore model and add to scrollw */ liststore = make_liststore(); g_object_set_data(G_OBJECT(liststore), "archive_path", (gpointer) archive_path); treeview = make_tree(liststore); g_object_unref(liststore); gtk_container_add(GTK_CONTAINER(scrollw), treeview); gtk_widget_show(treeview); g_signal_connect(treeview, "button_press_event", G_CALLBACK(treeview_button_press), UIMANAGER); /* read in archive data, or close the page if it fails */ argv = g_new(gchar *, 4); /* wrapper, option, archive, NULL */ argv[ARCHIVE_INDEX] = g_strdup(archive_path); argv[FIRST_FILE_INDEX] = NULL; if (wrapper_cmd(AR_OPEN, argv, NULL) < 0) { close_cb(NULL, NULL); } else { gchar *lastdir, *lastdir_path; FILE *lastdir_file; lastdir = (gchar *) g_object_get_data(G_OBJECT(NOTEBOOK), "lastdir"); lastdir_path = (gchar *) g_object_get_data(G_OBJECT(NOTEBOOK), "lastdir_path"); g_free(lastdir); lastdir = g_path_get_dirname(archive_path); g_object_set_data(G_OBJECT(NOTEBOOK), "lastdir", (gpointer) g_path_get_dirname(archive_path)); lastdir_file = g_fopen(lastdir_path, "w"); fputs(lastdir, lastdir_file); fputs("\n", lastdir_file); fclose(lastdir_file); } g_strfreev(argv); } /************************************/ /* emtpy page and message functions */ /************************************/ void setup_opening_progress_bar(GtkWidget *pbwin, GtkWidget *pbar, gboolean *stopit) { GtkWidget *vbox, *label, *button; g_signal_connect(G_OBJECT(pbwin), "delete_event", G_CALLBACK(gtk_true), NULL); gtk_window_set_modal(GTK_WINDOW(pbwin), TRUE); gtk_window_set_transient_for(GTK_WINDOW(pbwin), GTK_WINDOW(MAIN_WINDOW)); gtk_window_set_title(GTK_WINDOW(pbwin), "Reading..."); vbox = gtk_vbox_new(FALSE, 2); gtk_container_add(GTK_CONTAINER(pbwin), vbox); label = gtk_label_new("Please wait, reading file..."); gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0); gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(pbar), 0.2); gtk_box_pack_start(GTK_BOX(vbox), pbar, TRUE, TRUE, 0); button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(open_cancel_cb), (gpointer) stopit); gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); gtk_widget_show_all(pbwin); } void wait_with_progress_bar(GPid pid, gint *wrapper_status, gint ar_func) { GtkWidget *pbwin, *pbar, *label, *button, *vbox; gchar *msg; gint process_status = 0; gboolean waiting = TRUE; pbwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(G_OBJECT(pbwin), "delete_event", G_CALLBACK(gtk_true), NULL); gtk_window_set_modal(GTK_WINDOW(pbwin), TRUE); gtk_window_set_transient_for(GTK_WINDOW(pbwin), GTK_WINDOW(MAIN_WINDOW)); gtk_window_set_title(GTK_WINDOW(pbwin), "Working..."); switch (ar_func) { case AR_ADD: msg = "Please wait, adding files..."; break; case AR_NEW: msg = "Please wait, creating new archive..."; break; case AR_REMOVE: msg = "Please wait, removing files..."; break; case AR_EXTRACT: msg = "Please wait, extracting files..."; break; default: msg = "Busy, Please wait..."; break; } vbox = gtk_vbox_new(FALSE, 2); gtk_container_add(GTK_CONTAINER(pbwin), vbox); label = gtk_label_new(msg); gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0); pbar = gtk_progress_bar_new(); gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(pbar), 0.2); gtk_box_pack_start(GTK_BOX(vbox), pbar, TRUE, TRUE, 0); button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(process_cancel_cb), GINT_TO_POINTER(pid)); gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); gtk_widget_show_all(pbwin); while (waiting) { process_status = waitpid((pid_t)pid, wrapper_status, WNOHANG); if (process_status < 0) { waiting = FALSE; } else { gtk_progress_bar_pulse(GTK_PROGRESS_BAR(pbar)); while (gtk_events_pending()) gtk_main_iteration(); g_usleep(200000); } } gtk_widget_destroy(pbwin); while (gtk_events_pending()) gtk_main_iteration(); } GtkWidget * make_info_widget(gchar *msg) { GtkWidget *scrollw, *label; scrollw = gtk_scrolled_window_new(0,0); gtk_container_set_border_width(GTK_CONTAINER(scrollw), 10); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_widget_show(scrollw); label = gtk_label_new(msg); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollw), label); gtk_widget_show(label); return scrollw; } void make_empty_page(GtkWidget *container) { gchar *wrapinf; wrapinf = wrapper_info(); EMPTY = make_info_widget(wrapinf); g_free(wrapinf); gtk_box_pack_end(GTK_BOX(container), EMPTY, TRUE, TRUE, 0); } gboolean message(GtkWidget *parentwin, gint type, gchar *text) { GtkWidget *md; md = gtk_message_dialog_new(GTK_WINDOW(parentwin), GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT, type, GTK_BUTTONS_NONE, text); if ( type == GTK_MESSAGE_WARNING || type == GTK_MESSAGE_QUESTION) { gtk_dialog_add_button(GTK_DIALOG(md), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); gtk_dialog_add_button(GTK_DIALOG(md), GTK_STOCK_OK, GTK_RESPONSE_OK); gtk_dialog_set_alternative_button_order(GTK_DIALOG(md), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); } else { gtk_dialog_add_button(GTK_DIALOG(md), GTK_STOCK_OK, GTK_RESPONSE_OK); } if( gtk_dialog_run(GTK_DIALOG(md)) == GTK_RESPONSE_OK ) { gtk_widget_destroy(md); return TRUE; } gtk_widget_destroy(md); return FALSE; } /******************************/ /* treeview foreach functions */ /******************************/ void selected_foreach_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, WrapperData *wrapper) { gchar *fname; gchar *esc_fname; gtk_tree_model_get(model, iter, COL_FILE, &fname, -1); esc_fname = g_strdup(fname); wrapper->argv[wrapper->index] = esc_fname; wrapper->index++; wrapper->argv[wrapper->index] = NULL; g_free(fname); } gboolean sel_subdir_foreach_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, SelectionData *seld) { gchar *fname; gtk_tree_model_get(model, iter, COL_FILE, &fname, -1); if ( g_str_has_prefix(fname, seld->dname) == TRUE ) { gtk_tree_selection_select_iter(seld->sel, iter); } g_free(fname); return FALSE; } gboolean unsel_subdir_foreach_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, SelectionData *seld) { gchar *fname; gtk_tree_model_get(model, iter, COL_FILE, &fname, -1); if ( g_str_has_prefix(fname, seld->dname) == TRUE ) { gtk_tree_selection_unselect_iter(seld->sel, iter); } g_free(fname); return FALSE; } gboolean test_selection_func(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer data) { GtkTreeIter iter; SelectionData seld; gchar *icon, *fname, *dname=NULL; static gboolean skipit = FALSE; if (skipit == TRUE) return TRUE; gtk_tree_model_get_iter(model, &iter, path); seld.sel = selection; gtk_tree_model_get(model, &iter, COL_ICON, &icon, COL_FILE, &fname, -1); if (g_str_has_prefix(icon, GTK_STOCK_DIRECTORY) == TRUE) { if (g_str_has_suffix(fname, "/") == FALSE) dname = g_strdup_printf("%s/", fname); else dname = g_strdup(fname); seld.dname = dname; seld.dirs = TRUE; skipit = TRUE; if (path_currently_selected == FALSE) gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc)sel_subdir_foreach_func, &seld); else gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc)unsel_subdir_foreach_func, &seld); } skipit = FALSE; g_free(icon); if (dname != NULL && strcmp(fname,dname) == 0) { g_free(fname); g_free(dname); return FALSE; } g_free(fname); if (dname != NULL) g_free(dname); return TRUE; } gboolean add_foreach_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, WrapperData *wrapper) { selected_foreach_func(model, path, iter, wrapper); return FALSE; } gboolean file_filter_func(const GtkFileFilterInfo *filter_info, gpointer data) { gchar *fname; fname = g_strdup(filter_info->filename); if ( get_wrapper(fname) != NULL ) return TRUE; g_free(fname); return FALSE; } /*******************/ /* chooser widgets */ /*******************/ gchar * askfor_existing_archive(void) { GtkWidget *fc; GtkFileFilter *filter; gchar *archive = NULL, *lastdir; fc = gtk_file_chooser_dialog_new("Open File", GTK_WINDOW(MAIN_WINDOW), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_alternative_button_order(GTK_DIALOG(fc), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); lastdir = (gchar *)g_object_get_data(G_OBJECT(NOTEBOOK), "lastdir"); printf("lastdir: %s\n", lastdir); gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fc), lastdir); filter = gtk_file_filter_new(); gtk_file_filter_set_name(filter, "Only Supported"); gtk_file_filter_add_custom(filter, GTK_FILE_FILTER_FILENAME, file_filter_func, NULL, g_free); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fc), filter); filter = gtk_file_filter_new(); gtk_file_filter_set_name(filter, "All"); gtk_file_filter_add_pattern(filter, "*"); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fc), filter); if (gtk_dialog_run(GTK_DIALOG(fc)) == GTK_RESPONSE_ACCEPT) archive = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc)); gtk_widget_destroy(fc); return archive; } gchar * askfor_new_archive(gchar *name) { gchar *archive = NULL; gboolean again = TRUE; GtkWidget *fc_new; gchar *msg; fc_new = gtk_file_chooser_dialog_new("Enter New Archive Name", GTK_WINDOW(MAIN_WINDOW), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_default_response(GTK_DIALOG(fc_new), GTK_RESPONSE_ACCEPT); gtk_dialog_set_alternative_button_order(GTK_DIALOG(fc_new), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); if (name == NULL) name = "somename.tar.gz"; gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fc_new), name); while (again == TRUE) { if (gtk_dialog_run(GTK_DIALOG(fc_new)) == GTK_RESPONSE_ACCEPT) { archive = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc_new)); /* if no wrapper for archive type exits try again */ if (get_wrapper(archive) == NULL) { message(fc_new, GTK_MESSAGE_ERROR, "Sorry, archive type not supported.\n\n" "Please use an archive name with an\n" "extenstion that you have a wrapper for.\n\n" "For example:\n" "If you have tar-wrap.sh:\n" "\tsomename.tar.gz\n" "If you have zip-wrap.sh:\n" "\tsomename.zip\n"); g_free(archive); archive = NULL; } /* if it already exists try again */ else if (g_file_test(archive, G_FILE_TEST_EXISTS) == TRUE) { msg = g_strdup_printf("Archive %s\n" "already exists.\n\n" "Please pick another name, or\n" "put archive in a different directory\n", archive); message(fc_new, GTK_MESSAGE_ERROR, msg); g_free(msg); g_free(archive); archive = NULL; } else again = FALSE; } else { again = FALSE; archive = NULL; } } gtk_widget_destroy(GTK_WIDGET(fc_new)); return archive; } gboolean multi_file_chooser(gchar *archive, GtkListStore *filelist) { GtkTreeIter iter; GtkDialog *myfc; gboolean accept = FALSE, again = TRUE; myfc = make_myfc(archive, filelist); while (again == TRUE) { if (gtk_dialog_run(myfc) == GTK_RESPONSE_ACCEPT) { /* if no first entry, redisplay the file selector */ if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filelist), &iter) == FALSE) message(GTK_WIDGET(myfc), GTK_MESSAGE_ERROR, "No files added to list.\n\n" "Please try again, or cancel."); else { again = FALSE; accept = TRUE; } } else { again = FALSE; accept = FALSE; } } gtk_widget_destroy(GTK_WIDGET(myfc)); return accept; } void select_extract_dir(GtkWidget *widget, GtkWidget *entry) { GtkWidget *fc; fc = gtk_file_chooser_dialog_new("Select Directory To Extract To", GTK_WINDOW(MAIN_WINDOW), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_alternative_button_order(GTK_DIALOG(fc), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fc), gtk_entry_get_text(GTK_ENTRY(entry))); if (gtk_dialog_run(GTK_DIALOG(fc)) == GTK_RESPONSE_ACCEPT) { gtk_entry_set_text(GTK_ENTRY(entry), gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc))); } gtk_widget_destroy(fc); } gchar * askfor_extract_dir(void) { gchar *dir = NULL, *mesg; GtkWidget *idialog, *hbox, *label, *entry, *choose_button; gboolean again = TRUE; idialog = gtk_dialog_new_with_buttons("Extraction Directory", GTK_WINDOW(MAIN_WINDOW), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OK,GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_default_response(GTK_DIALOG(idialog), GTK_RESPONSE_ACCEPT); gtk_dialog_set_alternative_button_order(GTK_DIALOG(idialog), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_REJECT, -1); label = gtk_label_new("Enter Directory To Extract To:"); hbox = gtk_hbox_new(FALSE, 1); entry = gtk_entry_new(); gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); gtk_entry_set_text(GTK_ENTRY(entry), g_path_get_dirname(get_current_archive())); gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE,1); choose_button = gtk_button_new_with_label("Choose"); g_signal_connect(G_OBJECT(choose_button), "clicked", G_CALLBACK(select_extract_dir), entry); gtk_box_pack_start(GTK_BOX(hbox), choose_button, TRUE, TRUE,1); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(idialog)->vbox), label, TRUE, TRUE,1); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(idialog)->vbox), hbox, TRUE, TRUE,1); gtk_widget_show_all(GTK_DIALOG(idialog)->vbox); while(again == TRUE) { if (gtk_dialog_run(GTK_DIALOG(idialog)) == GTK_RESPONSE_ACCEPT) { dir = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry))); if (g_file_test(dir,G_FILE_TEST_IS_DIR) == FALSE) { mesg = g_strdup_printf("Directory\n%s\nDoes not exist.\n\n" "Shall I create it?", dir); if (message(idialog, GTK_MESSAGE_QUESTION, mesg)) { if (g_mkdir(dir, S_IRWXU|S_IRWXG) != 0) message(idialog, GTK_MESSAGE_INFO, "Sorry, could not create directory.\n\n" "If you need to create a parent dir and\n" "a subdir, create the parent first." ); } g_free(mesg); } else again = FALSE; } else { dir = NULL; again = FALSE; } } gtk_widget_destroy(idialog); return dir; } /******************************************/ /* openwith and default handler functions */ /******************************************/ GtkListStore * get_openwith_cmdlist(gchar *cmdlist_path) { gchar *cmd; gchar *line = NULL; FILE *cmdlist_file; size_t linesize = 0; int length; GtkListStore *cmdlist; GtkTreeIter iter; if (g_file_test(cmdlist_path, G_FILE_TEST_EXISTS) == FALSE) { cmdlist_file = g_fopen(cmdlist_path, "w"); fputs("xarchive\n", cmdlist_file); fclose(cmdlist_file); } cmdlist = gtk_list_store_new(1, G_TYPE_STRING); cmdlist_file = g_fopen(cmdlist_path, "r"); while ( (length = getline(&line, &linesize, cmdlist_file)) > 0) { /* strip newline from line to get command */ cmd = g_strndup(line, length-1); gtk_list_store_append(cmdlist, &iter); gtk_list_store_set(cmdlist, &iter, 0, cmd, -1); g_free(cmd); } fclose(cmdlist_file); g_free(line); return cmdlist; } void add_to_cmdlist(GtkListStore *cmdlist, gchar *command, gchar *cmdlist_path) { GtkTreeIter iter; gchar *list_entry = NULL; gboolean found = FALSE; FILE *cmdlist_file; if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(cmdlist), &iter) == TRUE) { do { gtk_tree_model_get(GTK_TREE_MODEL(cmdlist), &iter, 0, &list_entry, -1); if (strcmp(list_entry,command) == 0) { found = TRUE; gtk_list_store_move_after(cmdlist, &iter, NULL); break; } g_free(list_entry); } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(cmdlist), &iter)); if (found == FALSE) { gtk_list_store_prepend(cmdlist, &iter); gtk_list_store_set(cmdlist, &iter, 0, command, -1); } /* save list */ gtk_tree_model_get_iter_first(GTK_TREE_MODEL(cmdlist), &iter); cmdlist_file = g_fopen(cmdlist_path, "w"); do { gtk_tree_model_get(GTK_TREE_MODEL(cmdlist), &iter, 0, &list_entry, -1); fputs(list_entry,cmdlist_file); fputs("\n",cmdlist_file); g_free(list_entry); } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(cmdlist), &iter)); fclose(cmdlist_file); } } void get_lastdir(void) { gchar *lastdir_path, *lastdir; gchar *line = NULL; FILE *lastdir_file; size_t linesize = 0; int length; lastdir_path = g_strdup_printf("%s/.xarchive/lastdir",getenv("HOME")); g_object_set_data(G_OBJECT(NOTEBOOK),"lastdir_path",(gpointer)lastdir_path); if (g_file_test(lastdir_path, G_FILE_TEST_EXISTS) == TRUE) { lastdir_file = g_fopen(lastdir_path, "r"); length = getline(&line, &linesize, lastdir_file); while (line[length-1] == '\n' || line[length-1] == ' ') { line[length-1] = '\0'; length--; } fclose(lastdir_file); g_object_set_data(G_OBJECT(NOTEBOOK),"lastdir",(gpointer)line); } else { lastdir = g_strdup_printf("%s",getenv("HOME")); lastdir_file = g_fopen(lastdir_path, "w"); fputs(lastdir, lastdir_file); fputs("\n", lastdir_file); fclose(lastdir_file); g_object_set_data(G_OBJECT(NOTEBOOK),"lastdir", (gpointer)lastdir); } } void get_default_handler(void) { gchar *defhand_path; gchar *line = NULL; FILE *defhand_file; size_t linesize = 0; int length; defhand_path = g_strdup_printf("%s/.xarchive/default_handler", getenv("HOME")); g_object_set_data(G_OBJECT(NOTEBOOK),"defhand_path",(gpointer)defhand_path); if (g_file_test(defhand_path, G_FILE_TEST_EXISTS) == FALSE) return; defhand_file = g_fopen(defhand_path, "r"); length = getline(&line, &linesize, defhand_file); /* strip trailing whitespace from line to get command */ /* isspace would be better if you want to #include ctype.h */ while (line[length-1] == '\n' || line[length-1] == ' ') { line[length-1] = '\0'; length--; } fclose(defhand_file); g_object_set_data(G_OBJECT(NOTEBOOK),"defhand_cmd",(gpointer)line); } void set_default_handler(gchar *command) { gchar *defhand_path; gchar *defhand_old_cmd; gchar *defhand_new_cmd; FILE *defhand_file; defhand_path = (gchar *)g_object_get_data(G_OBJECT(NOTEBOOK),"defhand_path"); defhand_old_cmd=(gchar *)g_object_get_data(G_OBJECT(NOTEBOOK),"defhand_cmd"); /* the passed command gets freed, so we'll store a copy */ defhand_new_cmd = g_strdup(command); printf("setting default handler to file %s\n", defhand_path); defhand_file = g_fopen(defhand_path, "w"); fputs(command, defhand_file); fputs("\n", defhand_file); fclose(defhand_file); g_free(defhand_old_cmd); g_object_set_data(G_OBJECT(NOTEBOOK),"defhand_cmd",(gpointer)defhand_new_cmd); return; } void open_one_file(WrapperData *wrapper, gchar *command) { gchar *fname; if (wrapper_cmd(AR_EXTRACT, wrapper->argv, wrapper->dir) == 0) { gchar *viewcmd; fname = my_strescape(wrapper->argv[FIRST_FILE_INDEX]); viewcmd = g_strconcat(command, " ", wrapper->dir, "/", fname, NULL); g_free(fname); printf("viewcmd: %s\n",viewcmd); system(viewcmd); g_free(viewcmd); } } void default_handler_foreach_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, WrapperData *wrapper) { gchar *fname; gchar *defhand_cmd; defhand_cmd = (gchar *)g_object_get_data(G_OBJECT(NOTEBOOK),"defhand_cmd"); /* if no cmd is set, pass off to open with dialog for setting */ if (defhand_cmd == NULL) { message(MAIN_WINDOW, GTK_MESSAGE_WARNING, "Double-clicking doesn't work until you\n" "set your default handler using the\n" "'set double-click default handler' flag\n" "in the 'open with..' dialog.\n\n"); openwith_foreach_func(model, path, iter, wrapper); return; } gtk_tree_model_get(model, iter, COL_FILE, &fname, -1); wrapper->argv = g_new(gchar *, 5); /*wrapper, option, archive, file, NULL*/ wrapper->argv[ARCHIVE_INDEX] = g_strdup(get_current_archive()); wrapper->argv[FIRST_FILE_INDEX] = g_strdup(fname); wrapper->argv[FIRST_FILE_INDEX + 1] = NULL; open_one_file(wrapper, defhand_cmd); g_strfreev(wrapper->argv); g_free(fname); } gchar * askfor_openwith_command(gchar *fname) { GtkWidget *dialog, *label, *combobox, *checkbox; GtkEntryCompletion *completion; static gchar *cmdlist_path = NULL; static GtkListStore *cmdlist = NULL; gchar *command = NULL, *msg; if (cmdlist_path == NULL) cmdlist_path = g_strdup_printf("%s/.xarchive/cmd_history",getenv("HOME")); if (cmdlist == NULL) cmdlist = get_openwith_cmdlist(cmdlist_path); dialog = gtk_dialog_new_with_buttons("Open With...", GTK_WINDOW(MAIN_WINDOW), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT); msg = g_strdup_printf("Open \"%s\" with...", fname); label = gtk_label_new(msg); g_free(msg); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE,TRUE,0); combobox = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(cmdlist), 0); gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0); gtk_widget_show(combobox); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),combobox,TRUE,TRUE,0); gtk_entry_set_activates_default(GTK_ENTRY(GTK_BIN(combobox)->child), TRUE); completion = gtk_entry_completion_new(); gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(cmdlist)); gtk_entry_completion_set_text_column(completion, 0); gtk_entry_completion_set_popup_completion(completion, TRUE); gtk_entry_set_completion(GTK_ENTRY(GTK_BIN(combobox)->child), completion); checkbox = gtk_check_button_new_with_label("set as default double-click handler"); gtk_widget_show(checkbox); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),checkbox,TRUE,TRUE,0); msg = g_strdup_printf("Current default handler: %s", (gchar *)g_object_get_data(G_OBJECT(NOTEBOOK), "defhand_cmd")); label = gtk_label_new(msg); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),label,TRUE,TRUE,0); g_free(msg); if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { command = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(combobox)->child))); add_to_cmdlist(cmdlist, command, cmdlist_path); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox)) == TRUE) set_default_handler(command); } gtk_widget_destroy(dialog); return command; } void openwith_foreach_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, WrapperData *wrapper) { gchar *fname, *command; /* see if cancel button pressed (xarchive set to null) */ if (wrapper->index == FALSE) return; /* esc file name */ gtk_tree_model_get(model, iter, COL_FILE, &fname, -1); /* display dialog asking to exatract and open fname with app */ command = askfor_openwith_command(fname); if (command != NULL && strcmp(command, GTK_STOCK_NO) == 0) wrapper->index = TRUE; else if (command != NULL) { wrapper->argv = g_new(gchar *, 5); /*wrapper, option, archive, file, NULL*/ wrapper->argv[ARCHIVE_INDEX] = g_strdup(get_current_archive()); wrapper->argv[FIRST_FILE_INDEX] = g_strdup(fname); wrapper->argv[FIRST_FILE_INDEX + 1] = NULL; open_one_file(wrapper, command); g_strfreev(wrapper->argv); } else { wrapper->index = FALSE; } g_free(command); g_free(fname); } /**********************/ /* callback functions */ /**********************/ void dummy_cb(GtkWidget *widget, gpointer data) { return; } void open_cb(GtkWidget *widget, gpointer data) { gchar *archive; archive = askfor_existing_archive(); if (archive == NULL) return; add_page(archive); g_free(archive); } void new_cb(GtkWidget *widget, gpointer data) { WrapperData wrapper; gchar *archive; GtkListStore *myfc_ls; /*file chooser liststore*/ GtkTreeIter iter; gchar *name; gint error, size; /* now get the files that are to be added to the new archive */ if (data == NULL) { archive = askfor_new_archive(NULL); if (archive == NULL) return; myfc_ls = make_myfc_ls(); } else { myfc_ls = (GtkListStore *) data; name = g_object_get_data(G_OBJECT(myfc_ls), "name"); archive = askfor_new_archive(name); g_free(name); if (archive == NULL) { g_object_unref(myfc_ls); return; } } if (multi_file_chooser(archive, myfc_ls) == TRUE) { /* set up cmd array */ /* adding 4 to list size for wrapper,option,archive, and null */ size = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(myfc_ls), NULL) + 4; wrapper.argv = g_new(gchar *, size); wrapper.index = FIRST_FILE_INDEX; wrapper.argv[ARCHIVE_INDEX] = g_strdup(archive); /* create new archive with first item by calling * foreach func by hand */ gtk_tree_model_get_iter_first(GTK_TREE_MODEL(myfc_ls), &iter); add_foreach_func(GTK_TREE_MODEL(myfc_ls), NULL, &iter, &wrapper); error = wrapper_cmd(AR_NEW, wrapper.argv, NULL); gtk_list_store_remove(myfc_ls, &iter); if (error != 0 ) { g_free(archive); g_strfreev(wrapper.argv); g_object_unref(myfc_ls); return; } /* then add the rest, if any, to new archive */ if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(myfc_ls), &iter) != FALSE) { gtk_tree_model_foreach(GTK_TREE_MODEL(myfc_ls), (GtkTreeModelForeachFunc) add_foreach_func, &wrapper); error = wrapper_cmd(AR_ADD, wrapper.argv, NULL); if (error != 0) { g_free(archive); g_strfreev(wrapper.argv); g_object_unref(myfc_ls); return; } } g_strfreev(wrapper.argv); /* now load up the archive in the notebook */ add_page(archive); } g_free(archive); g_object_unref(myfc_ls); } void close_cb(GtkWidget *widget, gpointer data) { gint page; gchar *archive; GtkWidget *scrollw; if ( data != NULL) { scrollw = GTK_WIDGET(data); page = gtk_notebook_page_num(NOTEBOOK, scrollw); gtk_notebook_set_current_page(NOTEBOOK, page); } archive = get_current_archive(); g_free(archive); page = gtk_notebook_get_current_page(NOTEBOOK); gtk_notebook_remove_page(NOTEBOOK, page); gtk_widget_queue_draw(GTK_WIDGET(NOTEBOOK)); page = gtk_notebook_get_current_page(NOTEBOOK); if (page < 0) { gtk_widget_hide(GTK_WIDGET(NOTEBOOK)); gtk_widget_show(EMPTY); } } void close_button_cb(GtkWidget *widget, gpointer data) { GtkWidget *current_scrollw; gint page; current_scrollw = gtk_notebook_get_nth_page(NOTEBOOK, gtk_notebook_get_current_page(NOTEBOOK)); close_cb(widget, data); page = gtk_notebook_page_num(NOTEBOOK, current_scrollw); if (page != -1) gtk_notebook_set_current_page(NOTEBOOK, page); } void extract_cb(GtkWidget *widget, gpointer data) { /* get selections from current treeview and a destdir. * create a gchar pointer array with selected files and send * to wrapper_cmd to process. */ static WrapperData wrapper; SelectionData seld; GtkTreeView *treeview; GtkTreeModel *liststore; gint sort_column; GtkSortType sort_order; gchar *msg; gint error; if ( (treeview = get_current_tree()) == NULL ) return; liststore = gtk_tree_view_get_model(treeview); /* if selection contains directories notify user */ seld.sel = gtk_tree_view_get_selection(treeview); /* if nothing selected ask to select all */ if (gtk_tree_selection_count_selected_rows(seld.sel) < 1) { if (message(MAIN_WINDOW, GTK_MESSAGE_WARNING, "No files selected,\n\n" "assuming you want to extract all") == TRUE) gtk_tree_selection_select_all(seld.sel); else return; } wrapper.dir = askfor_extract_dir(); if (wrapper.dir == NULL) return; /* if all is selected don't send any files, just extract the whole thing */ if ( gtk_tree_selection_count_selected_rows(seld.sel) == gtk_tree_model_iter_n_children(liststore, NULL) ) { /* need an array for 4 gchar pointers. wrapper option archive null. */ wrapper.argv = g_new(gchar *, 4); wrapper.argv[ARCHIVE_INDEX] = g_strdup(get_current_archive()); wrapper.argv[FIRST_FILE_INDEX] = NULL; } else { /* need an array for 4 gchar pointers plus the number of selected files. * Array will contain: wrapper option archive files... null */ wrapper.argv = g_new(gchar *, (4 + gtk_tree_selection_count_selected_rows(seld.sel))); wrapper.argv[ARCHIVE_INDEX] = g_strdup(get_current_archive()); wrapper.index = FIRST_FILE_INDEX; /* for extracting we need the DFILE column sorted descending so that * the directories are extracted before the children. Tar * hiccups if not. So change to that if it's not then * change back to what ever it was */ gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(liststore), &sort_column, &sort_order); if ( ! (sort_column == COL_DFILE && sort_order == GTK_SORT_DESCENDING) ) { gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore), COL_DFILE, GTK_SORT_DESCENDING); } gtk_tree_selection_selected_foreach(seld.sel, (GtkTreeSelectionForeachFunc) selected_foreach_func, &wrapper); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore), sort_column, sort_order); } error = wrapper_cmd(AR_EXTRACT, wrapper.argv, wrapper.dir); if (error == 0) { msg = g_strconcat("Done extracting files to:\n\n", wrapper.dir, NULL); message(MAIN_WINDOW, GTK_MESSAGE_INFO, msg); g_free(msg); } g_strfreev(wrapper.argv); g_free(wrapper.dir); } void openwith_cb(GtkWidget *widget, gpointer data) { open_selected_files(FALSE); } void double_click_cb() { open_selected_files(TRUE); } void open_selected_files(gboolean use_default_handler) { static WrapperData wrapper; SelectionData seld; GtkTreeView *treeview; GtkTreeSelectionForeachFunc foreach_func = (GtkTreeSelectionForeachFunc) ((use_default_handler) ? default_handler_foreach_func : openwith_foreach_func); gchar *tdir, *rm_command; const gchar *tpath = NULL; if ( (treeview = get_current_tree()) == NULL ) return; seld.sel = gtk_tree_view_get_selection(treeview); /* if nothing selected do nothing */ if ( gtk_tree_selection_count_selected_rows(seld.sel) < 1 ) return; tpath = g_get_tmp_dir(); tdir = g_strconcat(tpath,"/xarchiveXXXXXX", NULL); wrapper.dir = mkdtemp(tdir); wrapper.index = TRUE; /* use index to check for a cancel */ gtk_tree_selection_selected_foreach(seld.sel, foreach_func, &wrapper); /* remove temp dir tdir */ rm_command = g_strconcat("rm -fr ", tdir, NULL); printf("rm_command: %s\n", rm_command); system(rm_command); g_free(rm_command); g_free(tdir); } void add_cb(GtkWidget *widget, gpointer data) { WrapperData wrapper; GtkListStore *myfc_ls; /*file chooser liststore*/ gchar *archive_disp, *archive; gint error; if ( (archive = get_current_archive()) == NULL ) return; if (data != NULL) myfc_ls = (GtkListStore *) data; else myfc_ls = make_myfc_ls(); archive_disp = g_filename_display_name(archive); if (multi_file_chooser(archive_disp, myfc_ls) == TRUE) { /* need a gchar pointer array for 4 pointers plus the number * of files on the list (wrapper, option, archive, files.., null) */ wrapper.argv = g_new(gchar *, 4 + gtk_tree_model_iter_n_children(GTK_TREE_MODEL(myfc_ls),NULL)); wrapper.index = FIRST_FILE_INDEX; wrapper.argv[ARCHIVE_INDEX] = g_strdup(archive); gtk_tree_model_foreach( GTK_TREE_MODEL(myfc_ls), (GtkTreeModelForeachFunc) add_foreach_func, &wrapper); error = wrapper_cmd(AR_ADD, wrapper.argv, NULL); if (error == 0) { reload_current_tree(get_current_tree()); } g_strfreev(wrapper.argv); } g_free(archive_disp); g_object_unref(myfc_ls); } void remove_cb(GtkWidget *widget, gpointer data) { WrapperData wrapper; SelectionData seld; GtkTreeView *treeview; GtkTreeModel *liststore; gint sort_column; GtkSortType sort_order; if ( (treeview = get_current_tree()) == NULL) return; liststore = gtk_tree_view_get_model(treeview); seld.sel = gtk_tree_view_get_selection(treeview); if ( gtk_tree_selection_count_selected_rows(seld.sel) < 1 ) return; wrapper.argv = g_new(gchar *, (4 + gtk_tree_selection_count_selected_rows(seld.sel))); wrapper.index = FIRST_FILE_INDEX; wrapper.argv[ARCHIVE_INDEX] = g_strdup(get_current_archive()); /* for removing we need the DFILE column sorted descending so that a * directories children are removed before the directory itself. Tar * hiccups if not. So change to that if it's not, do the remove, then * change back to what ever it was */ gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(liststore), &sort_column, &sort_order); if ( ! (sort_column == COL_DFILE && sort_order == GTK_SORT_DESCENDING) ) { gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore), COL_DFILE, GTK_SORT_DESCENDING); } gtk_tree_selection_selected_foreach(seld.sel, (GtkTreeSelectionForeachFunc) selected_foreach_func, &wrapper); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(liststore), sort_column, sort_order); wrapper_cmd(AR_REMOVE, wrapper.argv, NULL); reload_current_tree(treeview); g_strfreev(wrapper.argv); } void select_all_cb(GtkWidget *widget, gpointer data) { GtkTreeView *treeview; GtkTreeSelection *sel; if ( (treeview = get_current_tree()) == NULL ) return; sel = gtk_tree_view_get_selection(treeview); gtk_tree_selection_select_all(sel); } void unselect_all_cb(GtkWidget *widget, gpointer data) { GtkTreeView *treeview; GtkTreeSelection *sel; if ( (treeview = get_current_tree()) == NULL ) return; sel = gtk_tree_view_get_selection(treeview); gtk_tree_selection_unselect_all(sel); } void wrapper_info_cb(GtkWidget *widget, gpointer data) { GtkWidget *dialog, *infobox; gchar *wrapinf, *msg; dialog = gtk_dialog_new_with_buttons("Wrapper Info", NULL, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); g_signal_connect_swapped(dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog); gtk_widget_set_size_request(dialog, 500, 300); wrapinf = wrapper_info(); msg = g_strdup_printf("%s\n%s\n\n%s", PACKAGE_STRING, PACKAGE_BUGREPORT, wrapinf); g_free(wrapinf); infobox = make_info_widget(msg); g_free(msg); gtk_box_pack_start(GTK_BOX( GTK_DIALOG(dialog)->vbox ), infobox, TRUE,TRUE,0); gtk_widget_show_all(dialog); } void read_help_cb(GtkWidget *widget, gpointer data) { GtkWidget *dialog, *infobox; gchar *helptxt; dialog = gtk_dialog_new_with_buttons("View Help", NULL, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); g_signal_connect_swapped(dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog); gtk_widget_set_size_request(dialog, 500, 300); g_file_get_contents(HELP_FILE_PATH, &helptxt, NULL, NULL); infobox = make_info_widget(helptxt); g_free(helptxt); gtk_box_pack_start(GTK_BOX( GTK_DIALOG(dialog)->vbox ), infobox, TRUE,TRUE,0); gtk_widget_show_all(dialog); } static gboolean open_cancel_cb(GtkWidget *widget, gpointer data) { gboolean *stopit = (gboolean *) data; *stopit = TRUE; return FALSE; } static gboolean process_cancel_cb(GtkWidget *widget, gpointer data) { pid_t pid = (pid_t) GPOINTER_TO_INT(data); gint err; printf("Trying to send kill signal to process %d\n", pid); err = kill( pid, SIGTERM); printf("Returned from kill: %d\n", err); return FALSE; } /***********************/ /* UIMananger functions*/ /***********************/ void add_ui_widget(GtkUIManager *uimanager, GtkWidget *widget, GtkContainer *container) { GtkToolbar *toolbar; gtk_box_pack_start (GTK_BOX(container), widget, FALSE, FALSE, 0); gtk_widget_show(widget); if (GTK_IS_TOOLBAR(widget)) { toolbar = GTK_TOOLBAR(widget); gtk_toolbar_set_show_arrow(toolbar, TRUE); } } GtkUIManager * make_ui_widgets(GtkWidget *window, GtkWidget *box) { GtkUIManager *uimanager; GtkActionGroup *action_group; GError *error = NULL; GtkActionEntry entries[] = { { "FileMenuAction", NULL, "_File" }, { "ActionsMenuAction", NULL, "_Archive" }, { "HelpMenuAction", NULL, "_Help" }, { "PopupMenuAction", NULL, "_Popup" }, { "new", GTK_STOCK_NEW, "_New", "N", "(CTRL-N) Create new archive", G_CALLBACK(new_cb)}, { "open", GTK_STOCK_OPEN, "_Open", "O", "(CTRL-O) Open exisiting archive", G_CALLBACK(open_cb)}, { "close", GTK_STOCK_CLOSE, "_Close", "W", "(CTRL-W) Close current archive window", G_CALLBACK(close_cb)}, { "quit", GTK_STOCK_QUIT, "_Quit", "Q", "(CTRL-Q) Quit application, closing all open archives", G_CALLBACK(gtk_main_quit)}, { "extract", GTK_STOCK_HARDDISK, "_Extract", "E", "(CTRL-E) Extract selected files from current archive", G_CALLBACK(extract_cb)}, { "add", GTK_STOCK_ADD, "_Add", "A", "(CTRL-A) Add files to current archive", G_CALLBACK(add_cb)}, { "remove", GTK_STOCK_REMOVE, "_Remove", "R", "(CTRL-R) Remove selected files from current archive", G_CALLBACK(remove_cb)}, { "openwith", GTK_STOCK_EXECUTE, "O_pen With...", "P", "(CTRL-P) Temporarily extract the selected files from current archive then open them with the specified application", G_CALLBACK(openwith_cb)}, { "SelectionMenuAction", NULL, "_Selection" }, { "select all", GTK_STOCK_APPLY, "_Select All", "S", "(CTRL-S) selected all files in current archive", G_CALLBACK(select_all_cb)}, { "unselect all", GTK_STOCK_CLEAR, "_Unselect All", "U", "(CTRL-U) unselect all files in current archive", G_CALLBACK(unselect_all_cb)}, { "wrapper info", GTK_STOCK_ABOUT, "Wrapper _Info", "I", "(CTRL-I) Show information on found wrappers", G_CALLBACK(wrapper_info_cb)}, { "read help", GTK_STOCK_HELP, "Read _Help", "H", "(CTRL-H) Read help file", G_CALLBACK(read_help_cb)}, }; guint n_entries = G_N_ELEMENTS(entries); gchar *ui_info = " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" ; action_group = gtk_action_group_new("XArchiveActions"); gtk_action_group_add_actions(action_group, entries, n_entries, NULL); uimanager = gtk_ui_manager_new(); gtk_ui_manager_insert_action_group(uimanager, action_group, 0); g_signal_connect(uimanager, "add_widget", G_CALLBACK(add_ui_widget), box); gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(uimanager)); if (!gtk_ui_manager_add_ui_from_string(uimanager, ui_info, -1, &error)) { g_message("building menus failed: %s", error->message); g_error_free(error); } return uimanager; } /******************************/ /* passed aurgument functions */ /******************************/ gint ask_create_or_add(gchar *msg) { gint response; GtkWidget *md; md = gtk_message_dialog_new(GTK_WINDOW(MAIN_WINDOW), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_CANCEL, msg); gtk_dialog_add_buttons(GTK_DIALOG(md), "New", AR_NEW, "Existing", AR_ADD, NULL); gtk_dialog_set_alternative_button_order(GTK_DIALOG(md), AR_NEW, AR_ADD, GTK_RESPONSE_CANCEL, -1); response = gtk_dialog_run(GTK_DIALOG(md)); gtk_widget_destroy(md); return response; } void process_passed_arguments(ParsedArgs *pargs) { gchar *archive = NULL, *msg, *filepath; gint i, response=AR_ADD; GtkListStore *filelist; switch (pargs->action) { case AR_OPEN: if (pargs->files == NULL) break; for (i=0; pargs->files[i] != NULL; i++) { archive = canonicalize_file_name(pargs->files[i]); if(archive != NULL) add_page(archive); else { msg = g_strconcat("Could not open archive:\n\n", pargs->files[i], NULL); message(MAIN_WINDOW, GTK_MESSAGE_ERROR, msg); g_free(msg); } } break; case AR_ADD: msg = g_strdup_printf("Would you like to:\n" "Create a new archive, or\n" "Add to an existing archive?"); if (strcmp(pargs->archive,"ask") != 0 && (archive = canonicalize_file_name(pargs->archive)) == NULL) msg = g_strdup_printf("Archive not found\n%s\n\n%s", pargs->archive, msg); else { g_free(pargs->archive); pargs->archive = NULL; } if (archive == NULL && (response = ask_create_or_add(msg)) == AR_ADD) archive = askfor_existing_archive(); filelist = make_myfc_ls(); if (pargs->files != NULL) for (i=0; pargs->files[i] != NULL; i++) { filepath = canonicalize_file_name(pargs->files[i]); if (filepath == NULL) continue; else myfc_add_foreach_func(filepath, filelist); g_free(filepath); } if (response == AR_ADD && archive != NULL) { add_page(archive); add_cb(NULL, (gpointer) filelist); } else if (response == AR_NEW) { g_object_set_data(G_OBJECT(filelist),"name", (gpointer)pargs->archive); new_cb(NULL, (gpointer) filelist); } else gtk_widget_show(EMPTY); g_free(archive); break; case AR_NEW: if (strcmp(pargs->archive, "ask") == 0) { g_free(pargs->archive); pargs->archive = NULL; } filelist = make_myfc_ls(); if (pargs->files != NULL) for (i=0; pargs->files[i] != NULL; i++) { filepath = canonicalize_file_name(pargs->files[i]); if (filepath == NULL) continue; else myfc_add_foreach_func(filepath, filelist); g_free(filepath); } g_object_set_data(G_OBJECT(filelist),"name", (gpointer)pargs->archive); new_cb(NULL, (gpointer) filelist); break; default: gtk_widget_show(EMPTY); break; } } /***********************/ /* Main setup function */ /***********************/ int make_widgets(ParsedArgs *pargs) { GdkGeometry size_hints; GtkWidget *mainbox; static GdkPixbuf *xarchive_pixbuf; MAIN_WINDOW = gtk_window_new(GTK_WINDOW_TOPLEVEL); xarchive_pixbuf = gdk_pixbuf_new_from_xpm_data(xarchive_xpm); gtk_window_set_default_icon(xarchive_pixbuf); g_signal_connect(G_OBJECT(MAIN_WINDOW), "delete_event", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(G_OBJECT(MAIN_WINDOW), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_container_set_border_width(GTK_CONTAINER(MAIN_WINDOW), 0); gtk_window_set_title (GTK_WINDOW(MAIN_WINDOW), PACKAGE_STRING); size_hints.min_width=300; size_hints.min_height=250; size_hints.base_width=0; size_hints.base_height=0; gtk_window_set_geometry_hints(GTK_WINDOW(MAIN_WINDOW), MAIN_WINDOW, &size_hints, GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE); gtk_window_set_default_size(GTK_WINDOW(MAIN_WINDOW), 640, 400); if (pargs->geom != NULL) gtk_window_parse_geometry(GTK_WINDOW(MAIN_WINDOW), pargs->geom); mainbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(MAIN_WINDOW), mainbox); UIMANAGER = make_ui_widgets(MAIN_WINDOW, mainbox); make_empty_page(mainbox); make_notebook_widgets(mainbox); process_passed_arguments(pargs); gtk_widget_show(mainbox); gtk_widget_show(MAIN_WINDOW); gtk_main(); return 0; }