hi, the attached patch will add a combobox to the gtk2 filechooser to easy switch between recent visit folder. (=folder you opened a file) maybe worth to add to gvim.
screenshot: http://www.jochen-baier.de/vim_recent.jpg regards jochen
Index: src/gui_gtk.c =================================================================== --- src/gui_gtk.c (revision 242) +++ src/gui_gtk.c (working copy) @@ -1195,7 +1195,415 @@ # define USE_FILE_CHOOSER #endif -#ifndef USE_FILE_CHOOSER +#if defined USE_FILE_CHOOSER +/*struct saving recent visit folder*/ +typedef struct _File_Chooser File_Chooser; +struct _File_Chooser +{ + GtkListStore *store; + GtkTreeModel *model; + GtkWidget *filechooserdialog; + GtkWidget *save_button; + GtkWidget *open_button; + GtkWidget *combo; +}; + +static void file_chooser_path_selected (GtkComboBox *combobox, + File_Chooser *file_chooser); + +/*return iter if path is in combo list*/ + static gboolean +file_chooser_get_iter_for_path (File_Chooser *file_chooser, + GtkTreeIter *iter, gchar *new_path) +{ + gchar *old_path=NULL; + gboolean valid=FALSE; + gboolean exist=FALSE; + + valid = gtk_tree_model_get_iter_first (file_chooser->model, iter); + while (valid) + { + old_path=NULL; + gtk_tree_model_get (file_chooser->model, iter, 0, + &old_path, -1); + + if (strcmp (new_path, old_path) == 0) + { + g_free (old_path); + exist=TRUE; + break; + } + g_free (old_path); + valid = gtk_tree_model_iter_next (file_chooser->model, iter); + } + + return exist; +} + + static void +file_chooser_append_path (File_Chooser *file_chooser, gchar *new_path) +{ + GtkTreeIter iter; + + if (!file_chooser_get_iter_for_path (file_chooser, &iter, new_path)) + { + gtk_list_store_append (file_chooser->store, &iter); + gtk_list_store_set (file_chooser->store, &iter, + 0, new_path, -1); + } + +} + +/*current folder inside file_chooser changed*/ + static void +file_chooser_folder_changed (GtkFileChooser *chooser, + File_Chooser *file_chooser) +{ + GtkTreeIter iter; + GtkTreeIter exist_iter; + gchar *combo_path=NULL; + gchar *chooser_path=NULL; + gboolean ret=FALSE; + + /*if combox_path == chooser_path do nothing*/ + chooser_path=gtk_file_chooser_get_current_folder ( + GTK_FILE_CHOOSER(file_chooser->filechooserdialog)); + + if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX( + file_chooser->combo), &iter)) + { + gtk_tree_model_get (file_chooser->model, &iter, 0, + &combo_path, -1); + + if (strcmp (combo_path, chooser_path) == 0) + { + ret=TRUE; + } + + g_free (combo_path); + } + + if (ret) + { + g_free (chooser_path); + return; + } + + /*if path is known, show it in the combo, if not clean the combo*/ + g_signal_handlers_disconnect_by_func(file_chooser->combo, + file_chooser_path_selected, file_chooser); + if (file_chooser_get_iter_for_path (file_chooser, + &exist_iter, chooser_path)) + { + + gtk_combo_box_set_active_iter ( + GTK_COMBO_BOX(file_chooser->combo), &exist_iter); + } + else + { + gtk_combo_box_set_active ( + GTK_COMBO_BOX(file_chooser->combo), -1); + gtk_entry_set_text (GTK_ENTRY + (GTK_BIN (file_chooser->combo)->child), ""); + } + + g_signal_connect ((gpointer) file_chooser->combo, "changed", + G_CALLBACK (file_chooser_path_selected), file_chooser); + g_free (chooser_path); +} + +/*user changed path in the combo box*/ + static void +file_chooser_path_selected (GtkComboBox *combobox, + File_Chooser *file_chooser) +{ + GtkTreeIter iter; + gboolean valid; + gchar *path=NULL; + + if (gtk_combo_box_get_active_iter (combobox, &iter)) + { + gtk_tree_model_get (file_chooser->model, &iter, 0, + &path, -1); + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER( + file_chooser->filechooserdialog), path); + g_free(path); + } + +} + + static void +file_chooser_destroyed (gpointer data) +{ + File_Chooser *file_chooser = (File_Chooser*) data; + gtk_list_store_clear (file_chooser->store); + g_object_unref (file_chooser->model); + g_free (file_chooser); +} + +/*mark active item italic*/ + static void +file_chooser_mark_active_item (GtkCellLayout *cell_layout, + GtkCellRenderer *cell, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gpointer data) +{ + GtkTreePath *path; + GtkTreeIter active_iter; + gboolean cursive=FALSE; + + File_Chooser *file_chooser = (File_Chooser*) data; + + path = gtk_tree_model_get_path (tree_model, iter); + + if (gtk_combo_box_get_active_iter ( + GTK_COMBO_BOX(file_chooser->combo), &active_iter)) + { + GtkTreePath* active_path= gtk_tree_model_get_path ( + tree_model, &active_iter); + + if (gtk_tree_path_compare (path,active_path)==0) + cursive=TRUE; + + gtk_tree_path_free (active_path); + } + + if (cursive) + g_object_set (cell, "style", PANGO_STYLE_ITALIC, NULL); + else + g_object_set (cell, "style", PANGO_STYLE_NORMAL, NULL); + + gtk_tree_path_free (path); +} + + static File_Chooser* +init_file_chooser (GtkWidget *parent) +{ + File_Chooser *file_chooser = g_new (File_Chooser, 1); + + GtkWidget *dialog_vbox1; + GtkWidget *dialog_action_area1; + GtkWidget *button1; + GtkWidget *frame2; + GtkWidget *vbox2; + GtkWidget *label2; + GtkWidget *hbox2; + GtkWidget *image2; + GtkCellRenderer *renderer; + GtkTreeIter iter; + + file_chooser->filechooserdialog = + gtk_file_chooser_dialog_new (NULL, NULL, 0, NULL); + gtk_window_set_type_hint ( + GTK_WINDOW (file_chooser->filechooserdialog), + GDK_WINDOW_TYPE_HINT_DIALOG); + gtk_window_set_position ( + GTK_WINDOW (file_chooser->filechooserdialog), + GTK_WIN_POS_CENTER_ON_PARENT); + gtk_window_set_modal ( + GTK_WINDOW (file_chooser->filechooserdialog), TRUE); + gtk_window_set_transient_for ( + GTK_WINDOW(file_chooser->filechooserdialog), + GTK_WINDOW(parent)); + gtk_window_set_destroy_with_parent( + GTK_WINDOW(file_chooser->filechooserdialog), TRUE); + + g_object_set_data_full ((GObject*) file_chooser->filechooserdialog, + "data", (gpointer) file_chooser, file_chooser_destroyed); + + dialog_vbox1 = GTK_DIALOG (file_chooser->filechooserdialog )->vbox; + gtk_widget_show (dialog_vbox1); + frame2 = gtk_frame_new (NULL); + gtk_widget_show (frame2); + gtk_box_pack_start (GTK_BOX (dialog_vbox1), frame2, FALSE, TRUE, 0); + gtk_frame_set_label_align (GTK_FRAME (frame2), 0, 0); + gtk_frame_set_shadow_type (GTK_FRAME (frame2), GTK_SHADOW_OUT); + vbox2 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame2), vbox2); + label2 = gtk_label_new (_("Recent visit folder:")); + gtk_widget_show (label2); + gtk_box_pack_start (GTK_BOX (vbox2), label2, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (label2), 0.01, 0.5); + gtk_misc_set_padding (GTK_MISC (label2), 0, 2); + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox2), 5); + + /*check for better looking icon first...*/ + if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), + "stock_folder")) + { + image2 = gtk_image_new_from_icon_name ("stock_folder", + GTK_ICON_SIZE_BUTTON); + } + else + { + image2 = gtk_image_new_from_stock (GTK_STOCK_DIRECTORY, + GTK_ICON_SIZE_BUTTON); + } + + gtk_widget_show (image2); + gtk_box_pack_start (GTK_BOX (hbox2), image2, FALSE, TRUE, 0); + + file_chooser->store = gtk_list_store_new (1, G_TYPE_STRING); + file_chooser->model = GTK_TREE_MODEL (file_chooser->store); + file_chooser->combo=gtk_combo_box_entry_new_with_model ( + file_chooser->model, 0); + + gtk_editable_set_editable (GTK_EDITABLE(GTK_ENTRY ( + GTK_BIN (file_chooser->combo)->child)), FALSE); + GTK_WIDGET_UNSET_FLAGS (GTK_ENTRY ( + GTK_BIN (file_chooser->combo)->child), GTK_CAN_FOCUS); + gtk_widget_show (file_chooser->combo); + gtk_widget_set_sensitive (file_chooser->combo, FALSE); + gtk_box_pack_start (GTK_BOX (hbox2), + file_chooser->combo, TRUE, TRUE, 0); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_clear (GTK_CELL_LAYOUT (file_chooser->combo)); + gtk_cell_layout_pack_start ( + GTK_CELL_LAYOUT (file_chooser->combo), renderer, TRUE); + + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT ( + file_chooser->combo), renderer, "text", 0, NULL); + + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT ( + file_chooser->combo), renderer, + file_chooser_mark_active_item, + (gpointer) file_chooser, NULL); + + dialog_action_area1 = + GTK_DIALOG (file_chooser->filechooserdialog)->action_area; + gtk_widget_show (dialog_action_area1); + gtk_button_box_set_layout ( + GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END); + button1 = gtk_button_new_from_stock (GTK_STOCK_CANCEL); + gtk_widget_show (button1); + gtk_dialog_add_action_widget ( + GTK_DIALOG (file_chooser->filechooserdialog), + button1, GTK_RESPONSE_CANCEL); + GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); + file_chooser->open_button = + gtk_button_new_from_stock (GTK_STOCK_OPEN); + gtk_dialog_add_action_widget ( + GTK_DIALOG (file_chooser->filechooserdialog), + file_chooser->open_button, GTK_RESPONSE_OK); + GTK_WIDGET_SET_FLAGS (file_chooser->open_button, GTK_CAN_DEFAULT); + file_chooser->save_button = + gtk_button_new_from_stock (GTK_STOCK_SAVE); + gtk_dialog_add_action_widget ( + GTK_DIALOG (file_chooser->filechooserdialog), + file_chooser->save_button, GTK_RESPONSE_OK); + GTK_WIDGET_SET_FLAGS (file_chooser->save_button, GTK_CAN_DEFAULT); + + return file_chooser; +} + +/* + * file chooser dialog with recent visit folder combo box + * saving=TRUE: save mode + * saving=FALSE: open mode + * do not destroy the dialog, just free the returned path + * */ + gchar * +file_chooser_dialog( + const gchar *title, + GtkWidget *parent, + const gchar *_current_folder, + gboolean saving) +{ + static File_Chooser *file_chooser=NULL; + gchar *filename=NULL; + gchar *folder=NULL; + GtkTreeIter iter; + gchar *current_folder=NULL; + + if (file_chooser == NULL) + { + file_chooser=init_file_chooser (parent); + } + + if (title != NULL) + { + gtk_window_set_title ( + GTK_WINDOW (file_chooser->filechooserdialog), title); + } + + if (saving) + { + gtk_file_chooser_set_action ( + GTK_FILE_CHOOSER (file_chooser->filechooserdialog), + GTK_FILE_CHOOSER_ACTION_SAVE ); + gtk_widget_hide (file_chooser->open_button); + gtk_widget_show (file_chooser->save_button); + gtk_widget_grab_default (file_chooser->save_button); + } + else + { + gtk_file_chooser_set_action ( + GTK_FILE_CHOOSER (file_chooser->filechooserdialog), + GTK_FILE_CHOOSER_ACTION_OPEN ); + gtk_widget_hide (file_chooser->save_button); + gtk_widget_grab_default (file_chooser->open_button); + gtk_widget_show (file_chooser->open_button); + } + + if (_current_folder != NULL) + { + current_folder=g_strdup (_current_folder); + current_folder[STRLEN(current_folder)-1]= '\0'; + + gtk_file_chooser_set_current_folder ( + GTK_FILE_CHOOSER(file_chooser->filechooserdialog), + current_folder); + + if (file_chooser_get_iter_for_path (file_chooser, &iter, + (gchar*) current_folder)) + { + gtk_combo_box_set_active_iter ( + GTK_COMBO_BOX(file_chooser->combo), &iter); + } + g_free (current_folder); + + } + + g_signal_connect ((gpointer) file_chooser->combo, "changed", + G_CALLBACK (file_chooser_path_selected), file_chooser); + g_signal_connect (GTK_FILE_CHOOSER(file_chooser->filechooserdialog), + "current-folder-changed", + G_CALLBACK (file_chooser_folder_changed), file_chooser); + + /*avoid too much resizing visible by the user*/ + gtk_widget_realize (file_chooser->filechooserdialog); + + if (gtk_dialog_run (GTK_DIALOG (file_chooser->filechooserdialog)) == + GTK_RESPONSE_OK) + { + filename = gtk_file_chooser_get_filename ( + GTK_FILE_CHOOSER (file_chooser->filechooserdialog)); + folder=gtk_file_chooser_get_current_folder ( + GTK_FILE_CHOOSER (file_chooser->filechooserdialog)); + + file_chooser_append_path (file_chooser, folder); + g_free(folder); + + if (!GTK_WIDGET_IS_SENSITIVE(file_chooser->combo)) + gtk_widget_set_sensitive (file_chooser->combo, TRUE); + } + + g_signal_handlers_disconnect_by_func(file_chooser->combo, + file_chooser_path_selected, file_chooser); + g_signal_handlers_disconnect_by_func(file_chooser->filechooserdialog, + file_chooser_folder_changed, file_chooser); + gtk_widget_hide (file_chooser->filechooserdialog); + + return filename; +} + +#else /*ARGSUSED*/ static void browse_ok_cb(GtkWidget *widget, gpointer cbdata) @@ -1287,29 +1695,15 @@ gui_mch_mousehide(FALSE); #ifdef USE_FILE_CHOOSER - /* We create the dialog each time, so that the button text can be "Open" - * or "Save" according to the action. */ - fc = gtk_file_chooser_dialog_new((const gchar *)title, - GTK_WINDOW(gui.mainwin), - saving ? GTK_FILE_CHOOSER_ACTION_SAVE - : GTK_FILE_CHOOSER_ACTION_OPEN, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - saving ? GTK_STOCK_SAVE : GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, - NULL); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fc), - (const gchar *)dirbuf); + gchar *filename= file_chooser_dialog ((const gchar *)title, + gui.mainwin, (const gchar *)dirbuf, saving); gui.browse_fname = NULL; - if (gtk_dialog_run(GTK_DIALOG(fc)) == GTK_RESPONSE_ACCEPT) + if (filename) { - char *filename; - - filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc)); gui.browse_fname = (char_u *)g_strdup(filename); g_free(filename); } - gtk_widget_destroy(GTK_WIDGET(fc)); - #else if (gui.filedlg == NULL)