[geany/geany] f86ab3: Merge branch 'techee/mru-patches'

Colomban Wendling git-noreply at xxxxx
Thu Jul 26 00:02:36 UTC 2012


Branch:      refs/heads/document-messages
Author:      Colomban Wendling <ban at herbesfolles.org>
Committer:   Colomban Wendling <ban at herbesfolles.org>
Date:        Mon, 26 Dec 2011 19:08:53
Commit:      f86ab3e41990a4fe184511423c2d009ccba2fee9
             https://github.com/geany/geany/commit/f86ab3e41990a4fe184511423c2d009ccba2fee9

Log Message:
-----------
Merge branch 'techee/mru-patches'


Modified Paths:
--------------
    data/geany.glade
    src/document.h
    src/keybindings.c
    src/keyfile.c
    src/main.c
    src/notebook.c
    src/notebook.h

Modified: data/geany.glade
12 files changed, 12 insertions(+), 0 deletions(-)
===================================================================
@@ -2117,6 +2117,18 @@
                                     <property name="position">3</property>
                                   </packing>
                                 </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="check_tab_close_switch_to_mru">
+                                    <property name="label" translatable="yes">Switch to last used document after closing a tab</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">4</property>
+                                  </packing>
+                                </child>
                               </object>
                             </child>
                           </object>


Modified: src/document.h
1 files changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -62,6 +62,7 @@
 	gboolean		gio_unsafe_save_backup;
 	gboolean		use_gio_unsafe_file_saving; /* whether to use GIO as the unsafe backend */
 	gchar			*extract_filetype_regex;	/* regex to extract filetype on opening */
+	gboolean		tab_close_switch_to_mru;
 }
 GeanyFilePrefs;
 


Modified: src/keybindings.c
206 files changed, 2 insertions(+), 204 deletions(-)
===================================================================
@@ -52,6 +52,7 @@
 #include "vte.h"
 #include "toolbar.h"
 #include "sidebar.h"
+#include "notebook.h"
 #include "geanywraplabel.h"
 #include "main.h"
 #include "search.h"
@@ -71,18 +72,9 @@
 static GtkAccelGroup *kb_accel_group = NULL;
 static const gboolean swap_alt_tab_order = FALSE;
 
-static const gsize MAX_MRU_DOCS = 20;
-static GQueue *mru_docs = NULL;
-static guint mru_pos = 0;
-
-static gboolean switch_in_progress = FALSE;
-static GtkWidget *switch_dialog = NULL;
-static GtkWidget *switch_dialog_label = NULL;
-
 
 /* central keypress event handler, almost all keypress events go to this function */
 static gboolean on_key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
-static gboolean on_key_release_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
 
 static gboolean check_current_word(GeanyDocument *doc, gboolean sci_word);
 static gboolean read_current_word(GeanyDocument *doc, gboolean sci_word);
@@ -597,55 +589,8 @@ static void init_default_kb(void)
 }
 
 
-/* before the tab changes, add the current document to the MRU list */
-static void on_notebook_switch_page(void)
-{
-	GeanyDocument *old = document_get_current();
-
-	/* when closing current doc, old is NULL.
-	 * Don't add to the mru list when switch dialog is visible. */
-	if (old && !switch_in_progress)
-	{
-		g_queue_remove(mru_docs, old);
-		g_queue_push_head(mru_docs, old);
-
-		if (g_queue_get_length(mru_docs) > MAX_MRU_DOCS)
-			g_queue_pop_tail(mru_docs);
-	}
-}
-
-
-/* really this should be just after a document was closed, not idle */
-static gboolean on_idle_close(gpointer data)
-{
-	GeanyDocument *current;
-
-	current = document_get_current();
-	if (current && g_queue_peek_head(mru_docs) == current)
-		g_queue_pop_head(mru_docs);
-
-	return FALSE;
-}
-
-
-static void on_document_close(GObject *obj, GeanyDocument *doc)
-{
-	if (! main_status.quitting)
-	{
-		g_queue_remove(mru_docs, doc);
-		g_idle_add(on_idle_close, NULL);
-	}
-}
-
-
 void keybindings_init(void)
 {
-	mru_docs = g_queue_new();
-	g_signal_connect(main_widgets.notebook, "switch-page",
-		G_CALLBACK(on_notebook_switch_page), NULL);
-	g_signal_connect(geany_object, "document-close",
-		G_CALLBACK(on_document_close), NULL);
-
 	memset(binding_ids, 0, sizeof binding_ids);
 	keybinding_groups = g_ptr_array_sized_new(GEANY_KEY_GROUP_COUNT);
 	kb_accel_group = gtk_accel_group_new();
@@ -654,8 +599,6 @@ void keybindings_init(void)
 	gtk_window_add_accel_group(GTK_WINDOW(main_widgets.window), kb_accel_group);
 
 	g_signal_connect(main_widgets.window, "key-press-event", G_CALLBACK(on_key_press_event), NULL);
-	/* in case the switch dialog misses an event while drawing the dialog */
-	g_signal_connect(main_widgets.window, "key-release-event", G_CALLBACK(on_key_release_event), NULL);
 }
 
 
@@ -820,7 +763,6 @@ void keybindings_free(void)
 		keybindings_free_group(group);
 
 	g_ptr_array_free(keybinding_groups, TRUE);
-	g_queue_free(mru_docs);
 }
 
 
@@ -1265,29 +1207,6 @@ static gboolean on_key_press_event(GtkWidget *widget, GdkEventKey *ev, gpointer
 }
 
 
-static gboolean is_modifier_key(guint keyval)
-{
-	switch (keyval)
-	{
-		case GDK_Shift_L:
-		case GDK_Shift_R:
-		case GDK_Control_L:
-		case GDK_Control_R:
-		case GDK_Meta_L:
-		case GDK_Meta_R:
-		case GDK_Alt_L:
-		case GDK_Alt_R:
-		case GDK_Super_L:
-		case GDK_Super_R:
-		case GDK_Hyper_L:
-		case GDK_Hyper_R:
-			return TRUE;
-		default:
-			return FALSE;
-	}
-}
-
-
 /* group_id must be a core group, e.g. GEANY_KEY_GROUP_EDITOR
  * key_id e.g. GEANY_KEYS_EDITOR_CALLTIP */
 GeanyKeyBinding *keybindings_lookup_item(guint group_id, guint key_id)
@@ -1745,130 +1664,9 @@ static void cb_func_switch_tabright(G_GNUC_UNUSED guint key_id)
 }
 
 
-static gboolean on_key_release_event(GtkWidget *widget, GdkEventKey *ev, gpointer user_data)
-{
-	/* user may have rebound keybinding to a different modifier than Ctrl, so check all */
-	if (switch_in_progress && is_modifier_key(ev->keyval))
-	{
-		switch_in_progress = FALSE;
-
-		if (switch_dialog)
-		{
-			gtk_widget_destroy(switch_dialog);
-			switch_dialog = NULL;
-		}
-
-		mru_pos = 0;
-	}
-	return FALSE;
-}
-
-
-static GtkWidget *ui_minimal_dialog_new(GtkWindow *parent, const gchar *title)
-{
-	GtkWidget *dialog;
-
-	dialog = gtk_window_new(GTK_WINDOW_POPUP);
-
-	if (parent)
-	{
-		gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
-		gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
-	}
-	gtk_window_set_title(GTK_WINDOW(dialog), title);
-	gtk_window_set_type_hint(GTK_WINDOW(dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
-	gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
-
-	gtk_widget_set_name(dialog, "GeanyDialog");
-	return dialog;
-}
-
-
-static GtkWidget *create_switch_dialog(void)
-{
-	GtkWidget *dialog, *widget, *vbox;
-
-	dialog = ui_minimal_dialog_new(GTK_WINDOW(main_widgets.window), _("Switch to Document"));
-	gtk_window_set_decorated(GTK_WINDOW(dialog), FALSE);
-	gtk_window_set_default_size(GTK_WINDOW(dialog), 150, -1);
-
-	vbox = gtk_vbox_new(FALSE, 6);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
-	gtk_container_add(GTK_CONTAINER(dialog), vbox);
-
-	widget = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_BUTTON);
-	gtk_container_add(GTK_CONTAINER(vbox), widget);
-
-	widget = geany_wrap_label_new(NULL);
-	gtk_label_set_justify(GTK_LABEL(widget), GTK_JUSTIFY_CENTER);
-	gtk_container_add(GTK_CONTAINER(vbox), widget);
-	switch_dialog_label = widget;
-
-	g_signal_connect(dialog, "key-release-event", G_CALLBACK(on_key_release_event), NULL);
-	return dialog;
-}
-
-
-static void update_filename_label(void)
-{
-	if (!switch_dialog)
-	{
-		switch_dialog = create_switch_dialog();
-		gtk_widget_show_all(switch_dialog);
-	}
-
-	gtk_label_set_text(GTK_LABEL(switch_dialog_label), DOC_FILENAME(document_get_current()));
-}
-
-
-static gboolean on_switch_timeout(G_GNUC_UNUSED gpointer data)
-{
-	if (!switch_in_progress || switch_dialog)
-	{
-		return FALSE;
-	}
-
-	update_filename_label();
-	return FALSE;
-}
-
-
 static void cb_func_switch_tablastused(G_GNUC_UNUSED guint key_id)
 {
-	GeanyDocument *last_doc = g_queue_peek_nth(mru_docs, mru_pos);
-
-	if (! DOC_VALID(last_doc))
-	{
-		utils_beep();
-		mru_pos = 0;
-		last_doc = g_queue_peek_nth(mru_docs, mru_pos);
-	}
-	if (! DOC_VALID(last_doc))
-		return;
-
-	document_show_tab(last_doc);
-
-	/* if there's a modifier key, we can switch back in MRU order each time unless
-	 * the key is released */
-	if (!switch_in_progress)
-	{
-		switch_in_progress = TRUE;
-
-		/* because switch_in_progress was not set when we called
-		 * gtk_notebook_set_current_page() above, this function inserted last_doc
-		 * into the queue => on mru_pos = 0 there is last_doc, on mru_pos = 1
-		 * there is the currently displayed doc, so we want to continue from 2
-		 * next time this function is called */
-		mru_pos = 2;
-
-		/* delay showing dialog to give user time to let go of any modifier keys */
-		g_timeout_add(600, on_switch_timeout, NULL);
-	}
-	else
-	{
-		update_filename_label();
-		mru_pos += 1;
-	}
+	notebook_switch_tablastused();
 }
 
 


Modified: src/keyfile.c
2 files changed, 2 insertions(+), 0 deletions(-)
===================================================================
@@ -139,6 +139,8 @@ static void init_pref_groups(void)
 
 	stash_group_add_toggle_button(group, &interface_prefs.notebook_double_click_hides_widgets,
 		"notebook_double_click_hides_widgets", FALSE, "check_double_click_hides_widgets");
+	stash_group_add_toggle_button(group, &file_prefs.tab_close_switch_to_mru,
+		"tab_close_switch_to_mru", FALSE, "check_tab_close_switch_to_mru");
 	stash_group_add_integer(group, &interface_prefs.tab_pos_sidebar, "tab_pos_sidebar", GTK_POS_TOP);
 	stash_group_add_radio_buttons(group, &interface_prefs.sidebar_pos,
 		"sidebar_pos", GTK_POS_LEFT,


Modified: src/main.c
1 files changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -1183,6 +1183,7 @@ void main_quit()
 
 	navqueue_free();
 	keybindings_free();
+	notebook_free();
 	highlighting_free_styles();
 	templates_free_templates();
 	msgwin_finalize();


Modified: src/notebook.c
260 files changed, 256 insertions(+), 4 deletions(-)
===================================================================
@@ -24,6 +24,9 @@
  */
 
 #include "geany.h"
+
+#include <gdk/gdkkeysyms.h>
+
 #include "notebook.h"
 #include "document.h"
 #include "editor.h"
@@ -34,6 +37,7 @@
 #include "callbacks.h"
 #include "utils.h"
 #include "keybindings.h"
+#include "main.h"
 
 #define GEANY_DND_NOTEBOOK_TAB_TYPE	"geany_dnd_notebook_tab"
 
@@ -49,6 +53,14 @@
 	{ "text/uri-list",	0, 0 }
 };
 
+static const gsize MAX_MRU_DOCS = 20;
+static GQueue *mru_docs = NULL;
+static guint mru_pos = 0;
+
+static gboolean switch_in_progress = FALSE;
+static GtkWidget *switch_dialog = NULL;
+static GtkWidget *switch_dialog_label = NULL;
+
 
 static void
 notebook_page_reordered_cb(GtkNotebook *notebook, GtkWidget *child, guint page_num,
@@ -65,6 +77,218 @@
 static void setup_tab_dnd(void);
 
 
+static void update_mru_docs_head(GeanyDocument *doc)
+{
+	if (doc)
+	{
+		g_queue_remove(mru_docs, doc);
+		g_queue_push_head(mru_docs, doc);
+
+		if (g_queue_get_length(mru_docs) > MAX_MRU_DOCS)
+			g_queue_pop_tail(mru_docs);
+	}
+}
+
+
+/* before the tab changes, add the current document to the MRU list */
+static void on_notebook_switch_page(GtkNotebook *notebook,
+	GtkNotebookPage *page, guint page_num, gpointer user_data)
+{
+	GeanyDocument *new;
+
+	new = document_get_from_page(page_num);
+
+	/* insert the very first document (when adding the second document
+	 * and switching to it) */
+	if (g_queue_get_length(mru_docs) == 0 && gtk_notebook_get_n_pages(notebook) == 2)
+		update_mru_docs_head(document_get_current());
+
+	if (!switch_in_progress)
+		update_mru_docs_head(new);
+}
+
+
+static void on_document_close(GObject *obj, GeanyDocument *doc)
+{
+	if (! main_status.quitting)
+	{
+		g_queue_remove(mru_docs, doc);
+		/* this prevents the pop up window from showing when there's a single
+		 * document */
+		if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.notebook)) == 2)
+			g_queue_clear(mru_docs);
+	}
+}
+
+
+static GtkWidget *ui_minimal_dialog_new(GtkWindow *parent, const gchar *title)
+{
+	GtkWidget *dialog;
+
+	dialog = gtk_window_new(GTK_WINDOW_POPUP);
+
+	if (parent)
+	{
+		gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
+		gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
+	}
+	gtk_window_set_title(GTK_WINDOW(dialog), title);
+	gtk_window_set_type_hint(GTK_WINDOW(dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
+	gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
+
+	gtk_widget_set_name(dialog, "GeanyDialog");
+	return dialog;
+}
+
+
+static gboolean is_modifier_key(guint keyval)
+{
+	switch (keyval)
+	{
+		case GDK_Shift_L:
+		case GDK_Shift_R:
+		case GDK_Control_L:
+		case GDK_Control_R:
+		case GDK_Meta_L:
+		case GDK_Meta_R:
+		case GDK_Alt_L:
+		case GDK_Alt_R:
+		case GDK_Super_L:
+		case GDK_Super_R:
+		case GDK_Hyper_L:
+		case GDK_Hyper_R:
+			return TRUE;
+		default:
+			return FALSE;
+	}
+}
+
+
+static gboolean on_key_release_event(GtkWidget *widget, GdkEventKey *ev, gpointer user_data)
+{
+	/* user may have rebound keybinding to a different modifier than Ctrl, so check all */
+	if (switch_in_progress && is_modifier_key(ev->keyval))
+	{
+		switch_in_progress = FALSE;
+
+		if (switch_dialog)
+		{
+			gtk_widget_destroy(switch_dialog);
+			switch_dialog = NULL;
+		}
+
+		update_mru_docs_head(document_get_current());
+		mru_pos = 0;
+	}
+	return FALSE;
+}
+
+
+static GtkWidget *create_switch_dialog(void)
+{
+	GtkWidget *dialog, *widget, *vbox;
+
+	dialog = ui_minimal_dialog_new(GTK_WINDOW(main_widgets.window), _("Switch to Document"));
+	gtk_window_set_decorated(GTK_WINDOW(dialog), FALSE);
+	gtk_window_set_default_size(GTK_WINDOW(dialog), 200, -1);
+
+	vbox = gtk_vbox_new(FALSE, 6);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
+	gtk_container_add(GTK_CONTAINER(dialog), vbox);
+
+	widget = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_BUTTON);
+	gtk_container_add(GTK_CONTAINER(vbox), widget);
+
+	widget = gtk_label_new(NULL);
+	gtk_label_set_justify(GTK_LABEL(widget), GTK_JUSTIFY_CENTER);
+	gtk_container_add(GTK_CONTAINER(vbox), widget);
+	switch_dialog_label = widget;
+
+	g_signal_connect(dialog, "key-release-event", G_CALLBACK(on_key_release_event), NULL);
+	return dialog;
+}
+
+
+static void update_filename_label(void)
+{
+	guint i;
+	gchar *msg = NULL;
+	guint queue_length;
+	GeanyDocument *doc;
+
+	if (!switch_dialog)
+	{
+		switch_dialog = create_switch_dialog();
+		gtk_widget_show_all(switch_dialog);
+	}
+
+	queue_length = g_queue_get_length(mru_docs);
+	for (i = mru_pos; (i <= mru_pos + 3) && (doc = g_queue_peek_nth(mru_docs, i % queue_length)); i++)
+	{
+		gchar *basename;
+
+		basename = g_path_get_basename(DOC_FILENAME(doc));
+		if (i == mru_pos)
+			msg = g_markup_printf_escaped ("<b>%s</b>", basename);
+		else if (i % queue_length == mru_pos)    /* && i != mru_pos */
+		{
+			/* We have wrapped around and got to the starting document again */
+			g_free(basename);
+			break;
+		}
+		else
+		{
+			setptr(basename, g_markup_printf_escaped ("\n%s", basename));
+			setptr(msg, g_strconcat(msg, basename, NULL));
+		}
+		g_free(basename);
+	}
+	gtk_label_set_markup(GTK_LABEL(switch_dialog_label), msg);
+	g_free(msg);
+}
+
+
+static gboolean on_switch_timeout(G_GNUC_UNUSED gpointer data)
+{
+	if (!switch_in_progress || switch_dialog)
+	{
+		return FALSE;
+	}
+
+	update_filename_label();
+	return FALSE;
+}
+
+
+void notebook_switch_tablastused(void)
+{
+	GeanyDocument *last_doc;
+	gboolean switch_start = !switch_in_progress;
+
+	mru_pos += 1;
+	last_doc = g_queue_peek_nth(mru_docs, mru_pos);
+
+	if (! DOC_VALID(last_doc))
+	{
+		utils_beep();
+		mru_pos = 0;
+		last_doc = g_queue_peek_nth(mru_docs, mru_pos);
+	}
+	if (! DOC_VALID(last_doc))
+		return;
+
+	switch_in_progress = TRUE;
+	document_show_tab(last_doc);
+
+	/* if there's a modifier key, we can switch back in MRU order each time unless
+	 * the key is released */
+	if (switch_start)
+		g_timeout_add(600, on_switch_timeout, NULL);
+	else
+		update_filename_label();
+}
+
+
 static gboolean focus_sci(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
 {
 	GeanyDocument *doc = document_get_current();
@@ -313,10 +537,25 @@ void notebook_init()
 	g_signal_connect(main_widgets.notebook, "drag-data-received",
 		G_CALLBACK(on_window_drag_data_received), NULL);
 
+	mru_docs = g_queue_new();
+	g_signal_connect(main_widgets.notebook, "switch-page",
+		G_CALLBACK(on_notebook_switch_page), NULL);
+	g_signal_connect(geany_object, "document-close",
+		G_CALLBACK(on_document_close), NULL);
+
+	/* in case the switch dialog misses an event while drawing the dialog */
+	g_signal_connect(main_widgets.window, "key-release-event", G_CALLBACK(on_key_release_event), NULL);
+
 	setup_tab_dnd();
 }
 
 
+void notebook_free(void)
+{
+	g_queue_free(mru_docs);
+}
+
+
 static void setup_tab_dnd()
 {
 	GtkWidget *notebook = main_widgets.notebook;
@@ -493,12 +732,25 @@ gint notebook_new_tab(GeanyDocument *this)
 /* Always use this instead of gtk_notebook_remove_page(). */
 void notebook_remove_page(gint page_num)
 {
-	gint curpage = gtk_notebook_get_current_page(GTK_NOTEBOOK(main_widgets.notebook));
+	gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(main_widgets.notebook));
 
-	/* Focus the next page, not the previous */
-	if (curpage == page_num && file_prefs.tab_order_ltr)
+	if (page_num == page)
 	{
-		gtk_notebook_set_current_page(GTK_NOTEBOOK(main_widgets.notebook), curpage + 1);
+		if (file_prefs.tab_order_ltr)
+			page += 1;
+		else if (page > 0) /* never go negative, it would select the last page */
+			page -= 1;
+
+		if (file_prefs.tab_close_switch_to_mru)
+		{
+			GeanyDocument *last_doc;
+
+			last_doc = g_queue_peek_nth(mru_docs, 0);
+			if (DOC_VALID(last_doc))
+				page = document_get_notebook_page(last_doc);
+		}
+
+		gtk_notebook_set_current_page(GTK_NOTEBOOK(main_widgets.notebook), page);
 	}
 
 	/* now remove the page (so we don't temporarily switch to the previous page) */


Modified: src/notebook.h
6 files changed, 6 insertions(+), 0 deletions(-)
===================================================================
@@ -24,10 +24,16 @@
 
 void notebook_init(void);
 
+void notebook_free(void);
+
 /* Returns page number of notebook page, or -1 on error */
 gint notebook_new_tab(GeanyDocument *doc);
 
 /* Always use this instead of gtk_notebook_remove_page(). */
 void notebook_remove_page(gint page_num);
 
+/* Switch notebook to the last used tab. Can be called repeatedly to get to the
+ * previous tabs. */
+void notebook_switch_tablastused(void);
+
 #endif


@@ Diff output truncated at 100000 characters. @@


--------------
This E-Mail was brought to you by github_commit_mail.py (Source: TBD).



More information about the Commits mailing list