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)

Reply via email to