From fdd413c854b446db3432e3fa207688df5739108e Mon Sep 17 00:00:00 2001 From: Simon Gomizelj Date: Sun, 3 Jun 2012 23:17:18 -0400 Subject: [PATCH] Move scrollback completion into the overlay. I also implemented the logic needed to "simulate" the input to the Vte. As a bonus, the search function also gets completion (this was unintentional but interesting enough that I let it be). Visible issues: - The down key doesn't pop up the completion, it gives focus back to the terminal. - The enter key does not select an item from the drop down list, it closes the entry and accepts the input as is. Maybe the completion popup delay should be configurable and the default value decreased? --- termite.c | 109 +++++++++++++++++++++++++++--------------------------- 1 file changed, 55 insertions(+), 54 deletions(-) diff --git a/termite.c b/termite.c index a1dd3c9..e31dde8 100644 --- a/termite.c +++ b/termite.c @@ -17,16 +17,21 @@ # define __attribute__(x) #endif +enum overlay_mode { + OVERLAY_HIDDEN, + OVERLAY_SEARCH, + OVERLAY_COMPLETION +}; + typedef struct search_panel_info { GtkWidget *vte; GtkWidget *entry; GtkBin *panel; + enum overlay_mode mode; bool reverse; } search_panel_info; -static gboolean always_selected(__attribute__((unused)) VteTerminal *vte, - __attribute__((unused)) glong column, - __attribute__((unused)) glong row) { +static gboolean always_selected() { return TRUE; } @@ -74,52 +79,6 @@ static GtkTreeModel *create_completion_model(VteTerminal *vte) { return GTK_TREE_MODEL(store); } -// TODO: turn this into an overlay -static GtkWidget *test_window = NULL; -static GtkWidget *do_entry_completion(VteTerminal *vte) { - GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(vte)); - - if (!test_window) { - test_window = gtk_dialog_new_with_buttons("GtkEntryCompletion", - GTK_WINDOW(window), - (GtkDialogFlags)0, - NULL, - NULL); - gtk_window_set_resizable(GTK_WINDOW(test_window), FALSE); - - g_signal_connect(test_window, "response", G_CALLBACK(gtk_widget_destroy), NULL); - g_signal_connect(test_window, "destroy", G_CALLBACK(gtk_widget_destroyed), &test_window); - - GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(test_window)); - - // Create our entry - GtkWidget *entry = gtk_entry_new(); - gtk_container_add(GTK_CONTAINER(content_area), entry); - - // Create the completion object - GtkEntryCompletion *completion = gtk_entry_completion_new(); - - // Assign the completion to the entry - gtk_entry_set_completion(GTK_ENTRY(entry), completion); - g_object_unref(completion); - - // Create a tree model and use it as the completion model - GtkTreeModel *completion_model = create_completion_model(vte); - gtk_entry_completion_set_model(completion, completion_model); - g_object_unref(completion_model); - - // Use model column 0 as the text column - gtk_entry_completion_set_text_column(completion, 0); - } - - if (!gtk_widget_get_visible(test_window)) - gtk_widget_show_all(test_window); - else - gtk_widget_destroy(test_window); - - return test_window; -} - static void search(VteTerminal *vte, const char *pattern, bool reverse) { GRegex *regex = vte_terminal_search_get_gregex(vte); if (regex) g_regex_unref(regex); @@ -134,17 +93,31 @@ static void search(VteTerminal *vte, const char *pattern, bool reverse) { vte_terminal_copy_primary(vte); } -static gboolean search_key_press_cb(GtkEntry *entry, GdkEventKey *event, search_panel_info *info) { +static gboolean entry_key_press_cb(GtkEntry *entry, GdkEventKey *event, search_panel_info *info) { gboolean ret = FALSE; if (event->keyval == GDK_KEY_Escape) { ret = TRUE; } else if (event->keyval == GDK_KEY_Return) { - search(VTE_TERMINAL(info->vte), gtk_entry_get_text(entry), info->reverse); - ret = TRUE; + const gchar *text = gtk_entry_get_text(entry); + + switch (info->mode) { + case OVERLAY_SEARCH: + search(VTE_TERMINAL(info->vte), text, info->reverse); + ret = TRUE; + break; + case OVERLAY_COMPLETION: + vte_terminal_feed(VTE_TERMINAL(info->vte), text, -1); + ret = TRUE; + break; + default: + ret = TRUE; + break; + } } if (ret) { + info->mode = OVERLAY_HIDDEN; gtk_widget_hide(GTK_WIDGET(info->panel)); gtk_widget_grab_focus(info->vte); } @@ -170,11 +143,13 @@ static gboolean key_press_cb(VteTerminal *vte, GdkEventKey *event, search_panel_ vte_terminal_copy_primary(vte); return TRUE; case KEY(KEY_SEARCH): + info->mode = OVERLAY_SEARCH; info->reverse = false; gtk_widget_show(GTK_WIDGET(info->panel)); gtk_widget_grab_focus(info->entry); return TRUE; case KEY(KEY_RSEARCH): + info->mode = OVERLAY_SEARCH; info->reverse = true; gtk_widget_show(GTK_WIDGET(info->panel)); gtk_widget_grab_focus(info->entry); @@ -186,6 +161,26 @@ static gboolean key_press_cb(VteTerminal *vte, GdkEventKey *event, search_panel_ search(vte, url_regex, true); return TRUE; } + } else if (modifiers == GDK_CONTROL_MASK && event->keyval == GDK_KEY_Tab) { + // Create the completion object + GtkEntryCompletion *completion = gtk_entry_completion_new(); + + // Assign the completion to the entry + gtk_entry_set_completion(GTK_ENTRY(info->entry), completion); + g_object_unref(completion); + + // Create a tree model and use it as the completion model + GtkTreeModel *completion_model = create_completion_model(vte); + gtk_entry_completion_set_model(completion, completion_model); + g_object_unref(completion_model); + + // Use model column 0 as the text column + gtk_entry_completion_set_text_column(completion, 0); + + info->mode = OVERLAY_COMPLETION; + gtk_widget_show(GTK_WIDGET(info->panel)); + gtk_widget_grab_focus(info->entry); + return TRUE; } if (modifiers == GDK_CONTROL_MASK && event->keyval == GDK_KEY_Tab) { do_entry_completion(vte); @@ -343,12 +338,18 @@ int main(int argc, char **argv) { gtk_container_add(GTK_CONTAINER(overlay), vte); gtk_container_add(GTK_CONTAINER(window), overlay); - search_panel_info info = {vte, entry, GTK_BIN(alignment), false}; + search_panel_info info = { + .vte = vte, + .entry = entry, + .panel = GTK_BIN(alignment), + .mode = OVERLAY_HIDDEN, + .reverse = false + }; g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(vte, "child-exited", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(vte, "key-press-event", G_CALLBACK(key_press_cb), &info); - g_signal_connect(entry, "key-press-event", G_CALLBACK(search_key_press_cb), &info); + g_signal_connect(entry, "key-press-event", G_CALLBACK(entry_key_press_cb), &info); g_signal_connect(overlay, "get-child-position", G_CALLBACK(position_overlay_cb), NULL); vte_terminal_set_scrollback_lines(VTE_TERMINAL(vte), scrollback_lines);