[geany/geany] 943bfa: Re-implement goto tag popup with a poped-up GtkMenu

Colomban Wendling git-noreply at xxxxx
Thu Feb 25 23:05:22 UTC 2016


Branch:      refs/heads/master
Author:      Colomban Wendling <ban at herbesfolles.org>
Committer:   Jiří Techet <techet at gmail.com>
Date:        Thu, 25 Feb 2016 23:05:22 UTC
Commit:      943bfa52c5f98e3adc0f8581845e492203c1218c
             https://github.com/geany/geany/commit/943bfa52c5f98e3adc0f8581845e492203c1218c

Log Message:
-----------
Re-implement goto tag popup with a poped-up GtkMenu


Modified Paths:
--------------
    src/symbols.c

Modified: src/symbols.c
171 lines changed, 54 insertions(+), 117 deletions(-)
===================================================================
@@ -54,7 +54,6 @@
 #include "tm_tag.h"
 #include "ui_utils.h"
 #include "utils.h"
-#include "keybindings.h"
 
 #include "SciLexer.h"
 
@@ -63,7 +62,6 @@
 #include <ctype.h>
 #include <string.h>
 #include <stdlib.h>
-#include <gdk/gdkkeysyms.h>
 
 
 static gchar **html_entities = NULL;
@@ -86,13 +84,6 @@ enum	/* Geany tag files */
 	GTF_MAX
 };
 
-enum {
-	PIXBUF_COLUMN,
-	TEXT_COLUMN,
-	TAG_COLUMN,
-	N_COLUMNS
-};
-
 static TagFileInfo tag_file_info[GTF_MAX] =
 {
 	{FALSE, "c99.tags"},
@@ -147,9 +138,6 @@ static struct
 }
 symbol_menu;
 
-static GtkWidget *tag_goto_popup = NULL;
-static GtkWidget *tag_goto_tree_view = NULL;
-
 static void html_tags_loaded(void);
 static void load_user_tags(filetype_id ft_id);
 
@@ -1840,22 +1828,10 @@ static void load_user_tags(filetype_id ft_id)
 }
 
 
-static void on_focus_out(GtkWidget *list, GdkEventFocus *unused, gpointer *user_data)
-{
-	gtk_widget_hide(tag_goto_popup);
-}
-
-
-static void on_row_activated(GtkTreeView *tree_view, GtkTreePath *path,
-	GtkTreeViewColumn *column, gpointer user_data)
+static void on_goto_popup_item_activate(GtkMenuItem *item, TMTag *tag)
 {
-	GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
 	GeanyDocument *new_doc, *old_doc;
-	GtkTreeIter iter;
-	TMTag *tag;
 
-	gtk_tree_model_get_iter(model, &iter, path);
-	gtk_tree_model_get(model, &iter, TAG_COLUMN, &tag, -1);
 	g_return_if_fail(tag);
 
 	old_doc = document_get_current();
@@ -1863,23 +1839,6 @@ static void on_row_activated(GtkTreeView *tree_view, GtkTreePath *path,
 
 	if (new_doc)
 		navqueue_goto_line(old_doc, new_doc, tag->line);
-
-	gtk_widget_hide(tag_goto_popup);
-	tm_tag_unref(tag);
-}
-
-
-static gboolean on_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
-{
-	guint state = event->state & gtk_accelerator_get_default_mod_mask();
-
-	if (event->keyval == GDK_Escape && state == 0)
-	{
-		gtk_widget_hide(tag_goto_popup);
-		keybindings_send_command(GEANY_KEY_GROUP_FOCUS, GEANY_KEYS_FOCUS_EDITOR);
-		return TRUE;
-	}
-	return FALSE;
 }
 
 
@@ -1918,106 +1877,84 @@ static guint get_tag_class(const TMTag *tag)
 }
 
 
-static void create_goto_popup(void)
+/* positions a popup below the caret from the ScintillaObject in @p data */
+static void goto_popup_position_func(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
 {
-	GtkWidget *frame, *scroller;
-	GtkListStore *store;
-	GtkTreeSelection *selection;
-	GtkTreeViewColumn *column;
-	GtkCellRenderer *renderer;
-
-	tag_goto_popup = g_object_new(GTK_TYPE_WINDOW, "type", GTK_WINDOW_TOPLEVEL, NULL);
-	gtk_widget_set_can_focus(tag_goto_popup, TRUE);
-	gtk_window_set_type_hint(GTK_WINDOW(tag_goto_popup), GDK_WINDOW_TYPE_HINT_DIALOG);
-	gtk_window_set_decorated(GTK_WINDOW(tag_goto_popup), FALSE);
-	gtk_window_set_transient_for(GTK_WINDOW(tag_goto_popup), GTK_WINDOW(main_widgets.window));
-	gtk_window_set_destroy_with_parent(GTK_WINDOW(tag_goto_popup), TRUE);
-	gtk_window_set_position(GTK_WINDOW(tag_goto_popup), GTK_WIN_POS_CENTER_ON_PARENT);
-	gtk_widget_set_size_request(tag_goto_popup, 250, 150);
-
-	frame = gtk_frame_new(NULL);
-	gtk_container_add(GTK_CONTAINER(tag_goto_popup), frame);
-	gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
-	gtk_container_set_border_width(GTK_CONTAINER(frame), 0);
-
-	scroller = gtk_scrolled_window_new(NULL, NULL);
-	gtk_container_set_border_width(GTK_CONTAINER(scroller), 0);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller),
-		GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-	gtk_container_add(GTK_CONTAINER(frame), scroller);
-
-	/* TreeView and its model */
-	store = gtk_list_store_new(N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, TM_TYPE_TAG);
-	tag_goto_tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
-	gtk_widget_set_can_focus(tag_goto_tree_view, TRUE);
-	gtk_container_add(GTK_CONTAINER(scroller), tag_goto_tree_view);
-	g_signal_connect(tag_goto_tree_view, "focus-out-event", G_CALLBACK(on_focus_out), tag_goto_popup);
-	g_signal_connect(tag_goto_tree_view, "row-activated", G_CALLBACK(on_row_activated), NULL);
-	g_signal_connect(tag_goto_tree_view, "key-press-event", G_CALLBACK(on_key_pressed), NULL);
+	ScintillaObject *sci = data;
+	GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(sci));
+	gint pos = sci_get_current_position(sci);
+	gint line = sci_get_line_from_position(sci, pos);
+	gint line_height = scintilla_send_message(sci, SCI_TEXTHEIGHT, line, 0);
+	gint pos_x = scintilla_send_message(sci, SCI_POINTXFROMPOSITION, 0, pos);
+	gint pos_y = scintilla_send_message(sci, SCI_POINTYFROMPOSITION, 0, pos);
 
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tag_goto_tree_view));
-	gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
-	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tag_goto_tree_view), FALSE);
-	gtk_tree_view_set_reorderable(GTK_TREE_VIEW(tag_goto_tree_view), FALSE);
+	gdk_window_get_origin(window, x, y);
 
-	/* Columns */
-	column = gtk_tree_view_column_new();
-	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
-
-	renderer = gtk_cell_renderer_pixbuf_new();
-	gtk_tree_view_column_pack_start(column, renderer, FALSE);
-	gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", PIXBUF_COLUMN);
-
-	renderer = gtk_cell_renderer_text_new();
-	gtk_tree_view_column_pack_start(column, renderer, TRUE);
-	gtk_tree_view_column_add_attribute(column, renderer, "markup", TEXT_COLUMN);
-
-	gtk_tree_view_append_column(GTK_TREE_VIEW(tag_goto_tree_view), column);
-
-	gtk_widget_show_all(frame);
+	*x += pos_x;
+	*y += pos_y + line_height;
+	*push_in = TRUE;
 }
 
 
-static void show_goto_popup(GPtrArray *tags, gboolean have_best)
+static void show_goto_popup(GeanyDocument *doc, GPtrArray *tags, gboolean have_best)
 {
-	gboolean first = TRUE;
-	GtkTreePath *path;
-	GtkTreeModel *model;
-	GtkTreeIter iter;
+	GtkWidget *first = NULL;
+	GtkWidget *menu;
+	GdkEvent *event;
 	TMTag *tmtag;
 	guint i;
 
-	if (!tag_goto_popup)
-		create_goto_popup();
-
-	model = gtk_tree_view_get_model(GTK_TREE_VIEW(tag_goto_tree_view));
-	gtk_list_store_clear(GTK_LIST_STORE(model));
+	menu = gtk_menu_new();
 
 	foreach_ptr_array(tmtag, i, tags)
 	{
+		GtkWidget *item;
+		GtkWidget *label;
+		GtkWidget *image;
 		gchar *fname = g_path_get_basename(tmtag->file->file_name);
 		gchar *text;
 
-		if (first && have_best)
+		if (! first && have_best)
 			text = g_markup_printf_escaped("<b>%s: %lu</b>", fname, tmtag->line);
 		else
 			text = g_markup_printf_escaped("%s: %lu", fname, tmtag->line);
 
-		gtk_list_store_insert_with_values(GTK_LIST_STORE(model), &iter, -1,
-				PIXBUF_COLUMN, symbols_icons[get_tag_class(tmtag)].pixbuf,
-				TEXT_COLUMN, text,
-				TAG_COLUMN, tmtag, -1);
+		image = gtk_image_new_from_pixbuf(symbols_icons[get_tag_class(tmtag)].pixbuf);
+		label = g_object_new(GTK_TYPE_LABEL, "label", text, "use-markup", TRUE, "xalign", 0.0, NULL);
+		item = g_object_new(GTK_TYPE_IMAGE_MENU_ITEM, "image", image, "child", label, NULL);
+		g_signal_connect_data(item, "activate", G_CALLBACK(on_goto_popup_item_activate),
+		                      tm_tag_ref(tmtag), (GClosureNotify) tm_tag_unref, 0);
+		gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+		if (! first)
+			first = item;
 
 		g_free(text);
 		g_free(fname);
-		first = FALSE;
 	}
 
-	path = gtk_tree_path_new_first();
-	gtk_tree_view_set_cursor (GTK_TREE_VIEW(tag_goto_tree_view), path, NULL, FALSE);
-	gtk_tree_path_free(path);
+	gtk_widget_show_all(menu);
 
-	gtk_window_present(GTK_WINDOW(tag_goto_popup));
+	/* FIXME: this should get the real event directly instead of looking it up */
+	event = gtk_get_current_event();
+	if (event && event->type == GDK_BUTTON_PRESS)
+	{
+		GdkEventButton *event_button = (GdkEventButton *) event;
+		/* FIXME: should this also use the position func?  as the cursor must be on the location
+		 *        under the cursor at this point anyway, it might give prettier alignment.
+		 *        But might as well be farther from the pointer or otherwise misaligned with the
+		 *        pointer, so maybe not. */
+		gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event_button->button, event_button->time);
+	}
+	else
+	{
+		if (first) /* always select the first item for better keyboard navigation */
+			g_signal_connect(menu, "realize", G_CALLBACK(gtk_menu_shell_select_item), first);
+		gtk_menu_popup(GTK_MENU(menu), NULL, NULL, goto_popup_position_func, doc->editor->sci,
+		               0, gtk_get_current_event_time ());
+	}
+	if (event)
+		gdk_event_free(event);
 }
 
 
@@ -2141,7 +2078,7 @@ static gboolean goto_tag(const gchar *name, gboolean definition)
 			if (tag != best_tag)
 				g_ptr_array_add(tags, tag);
 		}
-		show_goto_popup(tags, best_tag != NULL);
+		show_goto_popup(old_doc, tags, best_tag != NULL);
 
 		g_ptr_array_free(tags, TRUE);
 		found = TRUE;



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Commits mailing list