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)