From f8c8c748f054f8ade3d174d665e5709add1cb72e Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 5 Jul 2012 02:40:48 -0400 Subject: [PATCH] initial implementation of keyboard selection --- README.rst | 6 ++++++ termite.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index e203b0b..3f666b6 100644 --- a/README.rst +++ b/README.rst @@ -22,6 +22,7 @@ KEYBINDINGS * ``ctrl-shift-n``: jump to next search match * ``ctrl-shift-p``: jump to previous search match * ``ctrl-tab``: start scrollback completion +* ``ctrl-shift-space``: start selection mode During scrollback search, the current selection is changed to the search match and copied to the PRIMARY clipboard buffer. @@ -29,6 +30,11 @@ and copied to the PRIMARY clipboard buffer. With the scrollback search/completion widget open, up/down cycle through completions, escape closes the widget and enter accepts the input. +TEXT SELECTION MODE +------------------- + +* ``escape``: deactivate selection mode + TODO ==== diff --git a/termite.c b/termite.c index 4603d23..d57bbb0 100644 --- a/termite.c +++ b/termite.c @@ -1,11 +1,13 @@ #define _POSIX_C_SOURCE 200809L #include +#include #include #include #include #include +#include #ifndef __GNUC__ # define __attribute__(x) @@ -20,11 +22,19 @@ typedef enum overlay_mode { OVERLAY_COMPLETION } overlay_mode; +typedef struct select_info { + AtkText *text; + bool mode; + int begin; + int end; +} select_info; + typedef struct search_panel_info { GtkWidget *vte; GtkWidget *entry; GtkWidget *panel; enum overlay_mode mode; + select_info select; } search_panel_info; static char *browser_cmd[3] = {NULL}; @@ -60,11 +70,54 @@ void window_title_cb(VteTerminal *vte, GtkWindow *window) { gtk_window_set_title(window, t ? t : "termite"); } +static void update_selection(VteTerminal *vte, select_info *select) { + int n_selections = atk_text_get_n_selections(select->text); + + if (n_selections) { + if (n_selections == 1) { + atk_text_remove_selection(select->text, 0); + } else { + g_printerr("more than one selection!"); + exit(EXIT_FAILURE); + } + } + + atk_text_add_selection(select->text, + MIN(select->begin, select->end), + MAX(select->begin, select->end)); + + vte_terminal_copy_primary(vte); +} + +static void start_selection(select_info *select) { + select->mode = true; + select->begin = select->end = atk_text_get_caret_offset(select->text); +} + gboolean key_press_cb(VteTerminal *vte, GdkEventKey *event, search_panel_info *info) { const guint modifiers = event->state & gtk_accelerator_get_default_mod_mask(); gboolean dynamic_title = FALSE, urgent_on_bell = FALSE, clickable_url = FALSE; + if (info->select.mode) { + switch (event->keyval) { + case GDK_KEY_h: + info->select.end--; + update_selection(vte, &info->select); + break; + case GDK_KEY_l: + info->select.end++; + update_selection(vte, &info->select); + break; + case GDK_KEY_Escape: + info->select.mode = false; + break; + } + return TRUE; + } if (modifiers == (GDK_CONTROL_MASK|GDK_SHIFT_MASK)) { switch (gdk_keyval_to_lower(event->keyval)) { + case GDK_KEY_space: + start_selection(&info->select); + return TRUE; case GDK_KEY_c: vte_terminal_copy_clipboard(vte); return TRUE; @@ -559,7 +612,8 @@ 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, alignment, OVERLAY_HIDDEN}; + select_info select = {ATK_TEXT(vte_terminal_accessible_new(VTE_TERMINAL(vte))), false, 0, 0}; + search_panel_info info = {vte, entry, alignment, OVERLAY_HIDDEN, select}; g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(vte, "child-exited", G_CALLBACK(gtk_main_quit), NULL);