# HG changeset patch # User Sadrul Habib Chowdhury # Date 1161464904 0 # Node ID 8a0cfee11af893b713476f65db1f6f8532500e71 # Parent 242f948ee7079fc8cfb2eaba815e377530001d9e [gaim-migrate @ 17558] Introduce actions. You can specify the bindings for the actions. Right now, only the tree and the entry widget have them. The manual includes the details. I believe Ethan had suggested something like this a while back. It made sense, so here it is. committer: Tailor Script diff -r 242f948ee707 -r 8a0cfee11af8 console/libgnt/gnt-skel.c --- a/console/libgnt/gnt-skel.c Sat Oct 21 20:40:12 2006 +0000 +++ b/console/libgnt/gnt-skel.c Sat Oct 21 21:08:24 2006 +0000 @@ -50,6 +50,13 @@ parent_class->size_request = gnt_skel_size_request; parent_class->key_pressed = gnt_skel_key_pressed; + parent_class->actions = g_hash_table_duplicate(parent_class->actions, g_str_hash, + g_str_equal, NULL, (GDestroyNotify)gnt_widget_action_free); + parent_class->bindings = g_hash_table_duplicate(parent_class->bindings, g_str_hash, + g_str_equal, NULL, (GDestroyNotify)gnt_widget_action_param_free); + + gnt_widget_actions_read(G_OBJECT_CLASS_TYPE(klass), klass); + GNTDEBUG; } diff -r 242f948ee707 -r 8a0cfee11af8 console/libgnt/gntentry.c --- a/console/libgnt/gntentry.c Sat Oct 21 20:40:12 2006 +0000 +++ b/console/libgnt/gntentry.c Sat Oct 21 21:08:24 2006 +0000 @@ -157,35 +157,40 @@ gnt_widget_queue_update(widget); } -static void -move_back(GntEntry *entry) +static gboolean +move_back(GntWidget *widget, GList *null) { + GntEntry *entry = GNT_ENTRY(widget); if (entry->cursor <= entry->start) - return; + return FALSE; entry->cursor = g_utf8_find_prev_char(entry->start, entry->cursor); if (entry->cursor < entry->scroll) entry->scroll = entry->cursor; entry_redraw(GNT_WIDGET(entry)); + return TRUE; } -static void -move_forward(GntEntry *entry) +static gboolean +move_forward(GntWidget *widget, GList *list) { + GntEntry *entry = GNT_ENTRY(widget); if (entry->cursor >= entry->end) - return; + return FALSE; entry->cursor = g_utf8_find_next_char(entry->cursor, NULL); while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= GNT_WIDGET(entry)->priv.width) entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); entry_redraw(GNT_WIDGET(entry)); + return TRUE; } -static void -backspace(GntEntry *entry) +static gboolean +backspace(GntWidget *widget, GList *null) { int len; + GntEntry *entry = GNT_ENTRY(widget); if (entry->cursor <= entry->start) - return; + return TRUE; len = entry->cursor - g_utf8_find_prev_char(entry->start, entry->cursor); entry->cursor -= len; @@ -198,15 +203,17 @@ entry_redraw(GNT_WIDGET(entry)); if (entry->ddown) show_suggest_dropdown(entry); + return TRUE; } -static void -delkey(GntEntry *entry) +static gboolean +delkey(GntWidget *widget, GList *null) { int len; + GntEntry *entry = GNT_ENTRY(widget); if (entry->cursor >= entry->end) - return; + return FALSE; len = g_utf8_find_next_char(entry->cursor, NULL) - entry->cursor; memmove(entry->cursor, entry->cursor + len, entry->end - entry->cursor - len + 1); @@ -215,23 +222,116 @@ if (entry->ddown) show_suggest_dropdown(entry); + return TRUE; } -static void -move_start(GntEntry *entry) +static gboolean +move_start(GntWidget *widget, GList *null) { + GntEntry *entry = GNT_ENTRY(widget); entry->scroll = entry->cursor = entry->start; entry_redraw(GNT_WIDGET(entry)); + return TRUE; } -static void -move_end(GntEntry *entry) +static gboolean +move_end(GntWidget *widget, GList *null) { + GntEntry *entry = GNT_ENTRY(widget); entry->cursor = entry->end; /* This should be better than this */ while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= GNT_WIDGET(entry)->priv.width) entry->scroll = g_utf8_find_next_char(entry->scroll, NULL); entry_redraw(GNT_WIDGET(entry)); + return TRUE; +} + +static gboolean +history_prev(GntWidget *widget, GList *null) +{ + GntEntry *entry = GNT_ENTRY(widget); + if (entry->histlength && entry->history->prev) + { + entry->history = entry->history->prev; + gnt_entry_set_text(entry, entry->history->data); + destroy_suggest(entry); + + return TRUE; + } + return FALSE; +} + +static gboolean +history_next(GntWidget *widget, GList *null) +{ + GntEntry *entry = GNT_ENTRY(widget); + if (entry->histlength && entry->history->next) + { + if (entry->history->prev == NULL) + { + /* Save the current contents */ + char *text = g_strdup(gnt_entry_get_text(entry)); + g_free(entry->history->data); + entry->history->data = text; + } + + entry->history = entry->history->next; + gnt_entry_set_text(entry, entry->history->data); + destroy_suggest(entry); + + return TRUE; + } + return FALSE; +} + +static gboolean +suggest_show(GntWidget *widget, GList *null) +{ + return show_suggest_dropdown(GNT_ENTRY(widget)); +} + +static gboolean +suggest_next(GntWidget *widget, GList *null) +{ + GntEntry *entry = GNT_ENTRY(widget); + if (entry->ddown) { + gnt_widget_perform_action_named(entry->ddown, "move-down", NULL); + return TRUE; + } + return FALSE; +} + +static gboolean +suggest_prev(GntWidget *widget, GList *null) +{ + GntEntry *entry = GNT_ENTRY(widget); + if (entry->ddown) { + gnt_widget_perform_action_named(entry->ddown, "move-up", NULL); + return TRUE; + } + return FALSE; +} + +static gboolean +del_to_home(GntWidget *widget, GList *null) +{ + GntEntry *entry = GNT_ENTRY(widget); + memmove(entry->start, entry->cursor, entry->end - entry->cursor); + entry->end -= (entry->cursor - entry->start); + entry->cursor = entry->scroll = entry->start; + memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); + entry_redraw(widget); + return TRUE; +} + +static gboolean +del_to_end(GntWidget *widget, GList *null) +{ + GntEntry *entry = GNT_ENTRY(widget); + entry->end = entry->cursor; + memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); + entry_redraw(widget); + return TRUE; } static gboolean @@ -241,73 +341,10 @@ if (text[0] == 27) { - if (strcmp(text + 1, GNT_KEY_DEL) == 0 && entry->cursor < entry->end) - { - delkey(entry); - return TRUE; - } - else if (strcmp(text + 1, GNT_KEY_LEFT) == 0) - { - move_back(entry); - return TRUE; - } - else if (strcmp(text + 1, GNT_KEY_RIGHT) == 0) - { - move_forward(entry); - return TRUE; - } - else if (strcmp(text + 1, GNT_KEY_HOME) == 0) - { - move_start(entry); - return TRUE; - } - else if (strcmp(text + 1, GNT_KEY_END) == 0) - { - move_end(entry); - return TRUE; - } - else if (strcmp(text + 1, GNT_KEY_CTRL_DOWN) == 0 && entry->histlength) - { - if (entry->history->prev) - { - entry->history = entry->history->prev; - gnt_entry_set_text(entry, entry->history->data); - destroy_suggest(entry); - - return TRUE; - } - } - else if (strcmp(text + 1, GNT_KEY_UP) == 0 || - strcmp(text + 1, GNT_KEY_DOWN) == 0) - { - if (entry->ddown) - { - gnt_widget_key_pressed(entry->ddown, text); - return TRUE; - } - } - else if (strcmp(text + 1, GNT_KEY_CTRL_UP) == 0 && entry->histlength) - { - if (entry->history->next) - { - if (entry->history->prev == NULL) - { - /* Save the current contents */ - char *text = g_strdup(gnt_entry_get_text(entry)); - g_free(entry->history->data); - entry->history->data = text; - } - - entry->history = entry->history->next; - gnt_entry_set_text(entry, entry->history->data); - destroy_suggest(entry); - - return TRUE; - } - } - else if (text[1] == 0) + if (text[1] == 0) { destroy_suggest(entry); + return TRUE; } return FALSE; @@ -400,60 +437,6 @@ entry_redraw(widget); return TRUE; } - else - { - if (strcmp(text, GNT_KEY_BACKSPACE) == 0 && entry->cursor > entry->start) - { - backspace(entry); - return TRUE; - } - else if (strcmp(text, GNT_KEY_CTRL_A) == 0) - { - move_start(entry); - return TRUE; - } - else if (strcmp(text, GNT_KEY_CTRL_B) == 0) - { - move_back(entry); - return TRUE; - } - else if (strcmp(text, GNT_KEY_CTRL_D) == 0) - { - delkey(entry); - return TRUE; - } - else if (strcmp(text, GNT_KEY_CTRL_E) == 0) - { - move_end(entry); - return TRUE; - } - else if (strcmp(text, GNT_KEY_CTRL_F) == 0) - { - move_forward(entry); - return TRUE; - } - else if (strcmp(text, GNT_KEY_CTRL_H) == 0) - { - backspace(entry); - return TRUE; - } - else if (strcmp(text, GNT_KEY_CTRL_K) == 0) - { - entry->end = entry->cursor; - memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); - entry_redraw(widget); - return TRUE; - } - else if (strcmp(text, GNT_KEY_CTRL_U) == 0) - { - memmove(entry->start, entry->cursor, entry->end - entry->cursor); - entry->end -= (entry->cursor - entry->start); - entry->cursor = entry->scroll = entry->start; - memset(entry->end, '\0', entry->buffer - (entry->end - entry->start)); - entry_redraw(widget); - return TRUE; - } - } } return FALSE; @@ -503,6 +486,49 @@ parent_class->key_pressed = gnt_entry_key_pressed; parent_class->lost_focus = gnt_entry_lost_focus; + parent_class->actions = g_hash_table_duplicate(parent_class->actions, g_str_hash, + g_str_equal, g_free, (GDestroyNotify)gnt_widget_action_free); + parent_class->bindings = g_hash_table_duplicate(parent_class->bindings, g_str_hash, + g_str_equal, g_free, (GDestroyNotify)gnt_widget_action_param_free); + + gnt_widget_class_register_action(parent_class, "cursor-home", move_start, + GNT_KEY_CTRL_A, NULL); + gnt_widget_register_binding(parent_class, "cursor-home", "\033" GNT_KEY_HOME, NULL); + gnt_widget_class_register_action(parent_class, "cursor-end", move_end, + GNT_KEY_CTRL_E, NULL); + gnt_widget_register_binding(parent_class, "cursor-end", "\033" GNT_KEY_END, NULL); + gnt_widget_class_register_action(parent_class, "delete-prev", backspace, + GNT_KEY_BACKSPACE, NULL); + gnt_widget_class_register_action(parent_class, "delete-next", delkey, + "\033" GNT_KEY_DEL, NULL); + gnt_widget_register_binding(parent_class, "delete-next", GNT_KEY_CTRL_D, NULL); + gnt_widget_class_register_action(parent_class, "delete-start", del_to_home, + GNT_KEY_CTRL_U, NULL); + gnt_widget_class_register_action(parent_class, "delete-end", del_to_end, + GNT_KEY_CTRL_K, NULL); +#if 0 + gnt_widget_class_register_action(parent_class, "delete-prev-word", del_prev_word, + NULL, 1, NULL); + gnt_widget_class_register_action(parent_class, "delete-next-word", del_next_word, + NULL, 1, NULL); +#endif + gnt_widget_class_register_action(parent_class, "cursor-prev", move_back, + "\033" GNT_KEY_LEFT, NULL); + gnt_widget_class_register_action(parent_class, "cursor-next", move_forward, + "\033" GNT_KEY_RIGHT, NULL); + gnt_widget_class_register_action(parent_class, "suggest-show", suggest_show, + "\t", NULL); + gnt_widget_class_register_action(parent_class, "suggest-next", suggest_next, + "\033" GNT_KEY_DOWN, NULL); + gnt_widget_class_register_action(parent_class, "suggest-prev", suggest_prev, + "\033" GNT_KEY_UP, NULL); + gnt_widget_class_register_action(parent_class, "history-prev", history_prev, + "\033" GNT_KEY_CTRL_UP, NULL); + gnt_widget_class_register_action(parent_class, "history-next", history_next, + "\033" GNT_KEY_CTRL_DOWN, NULL); + + gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), klass); + GNTDEBUG; } diff -r 242f948ee707 -r 8a0cfee11af8 console/libgnt/gntkeys.h --- a/console/libgnt/gntkeys.h Sat Oct 21 20:40:12 2006 +0000 +++ b/console/libgnt/gntkeys.h Sat Oct 21 21:08:24 2006 +0000 @@ -23,6 +23,7 @@ #define GNT_KEY_BACKSPACE "\177" #define GNT_KEY_DEL "[3~" +#define GNT_KEY_INS "[2~" #define GNT_KEY_CTRL_A "\001" #define GNT_KEY_CTRL_B "\002" @@ -47,6 +48,19 @@ #define GNT_KEY_CTRL_X "\030" #define GNT_KEY_CTRL_Y "\031" +#define GNT_KEY_F1 "[[A" +#define GNT_KEY_F2 "[[B" +#define GNT_KEY_F3 "[[C" +#define GNT_KEY_F4 "[[D" +#define GNT_KEY_F5 "[[E" +#define GNT_KEY_F6 "[17~" +#define GNT_KEY_F7 "[18~" +#define GNT_KEY_F8 "[19~" +#define GNT_KEY_F9 "[20~" +#define GNT_KEY_F10 "[21~" +#define GNT_KEY_F11 "[23~" +#define GNT_KEY_F12 "[24~" + /** * This will do stuff with the terminal settings and stuff. */ diff -r 242f948ee707 -r 8a0cfee11af8 console/libgnt/gntstyle.c --- a/console/libgnt/gntstyle.c Sat Oct 21 20:40:12 2006 +0000 +++ b/console/libgnt/gntstyle.c Sat Oct 21 21:08:24 2006 +0000 @@ -79,6 +79,141 @@ *t = '\0'; } +static char * +parse_key(const char *key) +{ + char *ret = NULL; + int ctrl = 0, alt = 0; + char k; + + /* XXX: Need to do something about ctrl/alt+home, end etc. */ + +#define SPECIAL_KEY(k, code) do { \ + if (strncasecmp(key, k, sizeof(k) - 1) == 0) \ + return g_strdup(code); \ + } while (0) + + SPECIAL_KEY("home", "\033" GNT_KEY_HOME); + SPECIAL_KEY("end", "\033" GNT_KEY_END); + SPECIAL_KEY("pageup", "\033" GNT_KEY_PGUP); + SPECIAL_KEY("pagedown", "\033" GNT_KEY_PGDOWN); + SPECIAL_KEY("insert", "\033" GNT_KEY_INS); + SPECIAL_KEY("delete", "\033" GNT_KEY_DEL); + + SPECIAL_KEY("left", "\033" GNT_KEY_LEFT); + SPECIAL_KEY("right", "\033" GNT_KEY_RIGHT); + SPECIAL_KEY("up", "\033" GNT_KEY_UP); + SPECIAL_KEY("down", "\033" GNT_KEY_DOWN); + + SPECIAL_KEY("tab", "\t"); + SPECIAL_KEY("menu", "\033" GNT_KEY_POPUP); + + SPECIAL_KEY("f1", "\033" GNT_KEY_F1); + SPECIAL_KEY("f2", "\033" GNT_KEY_F2); + SPECIAL_KEY("f3", "\033" GNT_KEY_F3); + SPECIAL_KEY("f4", "\033" GNT_KEY_F4); + SPECIAL_KEY("f5", "\033" GNT_KEY_F5); + SPECIAL_KEY("f6", "\033" GNT_KEY_F6); + SPECIAL_KEY("f7", "\033" GNT_KEY_F7); + SPECIAL_KEY("f8", "\033" GNT_KEY_F8); + SPECIAL_KEY("f9", "\033" GNT_KEY_F9); + SPECIAL_KEY("f10", "\033" GNT_KEY_F10); + SPECIAL_KEY("f11", "\033" GNT_KEY_F11); + SPECIAL_KEY("f12", "\033" GNT_KEY_F12); + +#undef SPECIAL_KEY + +#define MATCH(string, var) do { \ + if (strncasecmp(key, string, sizeof(string) - 1) == 0) { \ + key += sizeof(string) - 1; \ + var = 1; \ + } \ + }while (0) + + MATCH("c-", ctrl); + MATCH("ctl-", ctrl); + MATCH("ctr-", ctrl); + MATCH("ctrl-", ctrl); + + MATCH("alt-", alt); + MATCH("a-", alt); + MATCH("m-", alt); + MATCH("meta-", alt); + + if (strlen(key) != 1) /* We can only have stuff like "ctrl-alt-a" */ + return NULL; + + if (ctrl && (strchr("hijm", *key) != NULL || !isalpha(*key))) { + /* These keys cannot be used with ctrl */ + return NULL; + } + + if (ctrl) + k = *key | 0x20; + else + k = *key; + + ret = g_strdup_printf("%s%c", alt ? "\033" : "", ctrl ? k - 0x60 : k); + +#undef MATCH + + return ret; +} + +void gnt_style_read_actions(GType type, GntWidgetClass *klass) +{ +#if GLIB_CHECK_VERSION(2,6,0) + char *name; + GError *error = NULL; + + name = g_strdup_printf("%s::binding", g_type_name(type)); + + if (g_key_file_has_group(gkfile, name)) + { + unsigned int len = 0; + char **keys; + + keys = g_key_file_get_keys(gkfile, name, &len, &error); + if (error) + { + g_printerr("GntStyle: %s\n", error->message); + g_error_free(error); + g_free(name); + return; + } + + while (len--) + { + char *key, *action; + + key = g_strdup(keys[len]); + action = g_key_file_get_string(gkfile, name, keys[len], &error); + + if (error) + { + g_printerr("GntStyle: %s\n", error->message); + g_error_free(error); + error = NULL; + } + else + { + char *keycode = parse_key(key); + if (keycode == NULL) { + g_printerr("GntStyle: Invalid key-binding %s\n", key); + } else { + gnt_widget_register_binding(klass, action, keycode, NULL); + g_free(keycode); + } + } + g_free(key); + g_free(action); + } + g_strfreev(keys); + } + g_free(name); +#endif +} + void gnt_styles_get_keyremaps(GType type, GHashTable *hash) { #if GLIB_CHECK_VERSION(2,6,0) @@ -97,6 +232,7 @@ { g_printerr("GntStyle: %s\n", error->message); g_error_free(error); + g_free(name); return; } diff -r 242f948ee707 -r 8a0cfee11af8 console/libgnt/gnttree.c --- a/console/libgnt/gnttree.c Sat Oct 21 20:40:12 2006 +0000 +++ b/console/libgnt/gnttree.c Sat Oct 21 21:08:24 2006 +0000 @@ -480,32 +480,95 @@ return g_hash_table_lookup(tree->hash, key); } -static void -action_down(GntTree *tree) +static gboolean +action_down(GntWidget *widget, GList *null) { int dist; + GntTree *tree = GNT_TREE(widget); + GntTreeRow *old = tree->current; GntTreeRow *row = get_next(tree->current); if (row == NULL) - return; + return FALSE; tree->current = row; if ((dist = get_distance(tree->current, tree->bottom)) < 0) gnt_tree_scroll(tree, -dist); else redraw_tree(tree); + if (old != tree->current) + tree_selection_changed(tree, old, tree->current); + return TRUE; } -static void -action_up(GntTree *tree) +static gboolean +action_up(GntWidget *widget, GList *list) { int dist; + GntTree *tree = GNT_TREE(widget); + GntTreeRow *old = tree->current; GntTreeRow *row = get_prev(tree->current); if (!row) - return; + return FALSE; tree->current = row; if ((dist = get_distance(tree->current, tree->top)) > 0) gnt_tree_scroll(tree, -dist); else redraw_tree(tree); + if (old != tree->current) + tree_selection_changed(tree, old, tree->current); + + return TRUE; +} + +static gboolean +action_page_down(GntWidget *widget, GList *null) +{ + GntTree *tree = GNT_TREE(widget); + GntTreeRow *old = tree->current; + GntTreeRow *row = get_next(tree->bottom); + if (row) + { + int dist = get_distance(tree->top, tree->current); + tree->top = tree->bottom; + tree->current = get_next_n_opt(tree->top, dist, NULL); + redraw_tree(tree); + } + else if (tree->current != tree->bottom) + { + tree->current = tree->bottom; + redraw_tree(tree); + } + + if (old != tree->current) + tree_selection_changed(tree, old, tree->current); + return TRUE; +} + +static gboolean +action_page_up(GntWidget *widget, GList *null) +{ + GntTree *tree = GNT_TREE(widget); + GntTreeRow *row; + GntTreeRow *old = tree->current; + + if (tree->top != tree->root) + { + int dist = get_distance(tree->top, tree->current); + row = get_prev_n(tree->top, widget->priv.height - 1 - + tree->show_title * 2 - 2 * (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER) == 0)); + if (row == NULL) + row = tree->root; + tree->top = row; + tree->current = get_next_n_opt(tree->top, dist, NULL); + redraw_tree(tree); + } + else if (tree->current != tree->top) + { + tree->current = tree->top; + redraw_tree(tree); + } + if (old != tree->current) + tree_selection_changed(tree, old, tree->current); + return TRUE; } static gboolean @@ -516,75 +579,9 @@ GntTreeRow *row; int dist; - if (text[0] == 27) + if (text[0] == '\r') { - if (strcmp(text+1, GNT_KEY_DOWN) == 0) - { - action_down(tree); - } - else if (strcmp(text+1, GNT_KEY_UP) == 0) - { - action_up(tree); - } - else if (strcmp(text+1, GNT_KEY_PGDOWN) == 0) - { - row = get_next(tree->bottom); - if (row) - { - int dist = get_distance(tree->top, tree->current); - tree->top = tree->bottom; - tree->current = get_next_n_opt(tree->top, dist, NULL); - redraw_tree(tree); - } - else if (tree->current != tree->bottom) - { - tree->current = tree->bottom; - redraw_tree(tree); - } - } - else if (strcmp(text+1, GNT_KEY_PGUP) == 0) - { - if (tree->top != tree->root) - { - int dist = get_distance(tree->top, tree->current); - row = get_prev_n(tree->top, widget->priv.height - 1 - - tree->show_title * 2 - 2 * (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER) == 0)); - if (row == NULL) - row = tree->root; - tree->top = row; - tree->current = get_next_n_opt(tree->top, dist, NULL); - redraw_tree(tree); - } - else if (tree->current != tree->top) - { - tree->current = tree->top; - redraw_tree(tree); - } - } - } - else if (iscntrl(text[0])) - { - if (strcmp(text, GNT_KEY_CTRL_N) == 0 && (row = get_next(tree->current)) != NULL) - { - tree->current = row; - if ((dist = get_distance(tree->current, tree->bottom)) < 0) - gnt_tree_scroll(tree, -dist); - else - redraw_tree(tree); - } - else if (strcmp(text, GNT_KEY_CTRL_P) == 0 && (row = get_prev(tree->current)) != NULL) - { - tree->current = row; - - if ((dist = get_distance(tree->current, tree->top)) > 0) - gnt_tree_scroll(tree, -dist); - else - redraw_tree(tree); - } - else if (text[0] == '\r') - { - gnt_widget_activate(widget); - } + gnt_widget_activate(widget); } else if (text[0] == ' ' && text[1] == 0) { @@ -634,9 +631,9 @@ GntTree *tree = GNT_TREE(widget); GntTreeRow *old = tree->current; if (event == GNT_MOUSE_SCROLL_UP) { - action_up(GNT_TREE(widget)); + action_up(widget, NULL); } else if (event == GNT_MOUSE_SCROLL_DOWN) { - action_down(GNT_TREE(widget)); + action_down(widget, NULL); } else if (event == GNT_LEFT_MOUSE_DOWN) { GntTreeRow *row; GntTree *tree = GNT_TREE(widget); @@ -706,6 +703,24 @@ g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); + parent_class->actions = g_hash_table_duplicate(parent_class->actions, g_str_hash, + g_str_equal, g_free, (GDestroyNotify)gnt_widget_action_free); + parent_class->bindings = g_hash_table_duplicate(parent_class->bindings, g_str_hash, + g_str_equal, g_free, (GDestroyNotify)gnt_widget_action_param_free); + + gnt_widget_class_register_action(parent_class, "move-up", action_up, + "\033" GNT_KEY_UP, NULL); + gnt_widget_register_binding(parent_class, "move-up", "\033" GNT_KEY_CTRL_N, NULL); + gnt_widget_class_register_action(parent_class, "move-down", action_down, + "\033" GNT_KEY_DOWN, NULL); + gnt_widget_register_binding(parent_class, "move-down", "\033" GNT_KEY_CTRL_P, NULL); + gnt_widget_class_register_action(parent_class, "page-up", action_page_up, + "\033" GNT_KEY_PGUP, NULL); + gnt_widget_class_register_action(parent_class, "page-down", action_page_down, + "\033" GNT_KEY_PGDOWN, NULL); + + gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), klass); + GNTDEBUG; } @@ -1350,11 +1365,9 @@ for (i = 0; i < tree->ncol; i++) { gnt_tree_set_col_width(tree, i, widths[i]); twidth += widths[i] + (tree->show_separator ? 1 : 0) + 1; - fprintf(stderr, "column width for col %d: %d\n", i, widths[i]); } g_free(widths); - fprintf(stderr, "tree width: %d\n", twidth); gnt_widget_get_size(GNT_WIDGET(tree), NULL, &height); gnt_widget_set_size(GNT_WIDGET(tree), twidth, height); } diff -r 242f948ee707 -r 8a0cfee11af8 console/libgnt/gntutils.c --- a/console/libgnt/gntutils.c Sat Oct 21 20:40:12 2006 +0000 +++ b/console/libgnt/gntutils.c Sat Oct 21 21:08:24 2006 +0000 @@ -105,3 +105,17 @@ return g_string_free(str, FALSE); } +static void +duplicate_values(gpointer key, gpointer value, gpointer data) +{ + g_hash_table_insert(data, key, value); +} + +GHashTable *g_hash_table_duplicate(GHashTable *src, GHashFunc hash, + GEqualFunc equal, GDestroyNotify key_d, GDestroyNotify value_d) +{ + GHashTable *dest = g_hash_table_new_full(hash, equal, key_d, value_d); + g_hash_table_foreach(src, duplicate_values, dest); + return dest; +} + diff -r 242f948ee707 -r 8a0cfee11af8 console/libgnt/gntutils.h --- a/console/libgnt/gntutils.h Sat Oct 21 20:40:12 2006 +0000 +++ b/console/libgnt/gntutils.h Sat Oct 21 21:08:24 2006 +0000 @@ -17,3 +17,6 @@ * Returns a newly allocated string. */ char *gnt_util_onscreen_fit_string(const char *string, int maxw); + +GHashTable *g_hash_table_duplicate(GHashTable *src, GHashFunc hash, + GEqualFunc equal, GDestroyNotify key_d, GDestroyNotify value_d); diff -r 242f948ee707 -r 8a0cfee11af8 console/libgnt/gntwidget.c --- a/console/libgnt/gntwidget.c Sat Oct 21 20:40:12 2006 +0000 +++ b/console/libgnt/gntwidget.c Sat Oct 21 21:08:24 2006 +0000 @@ -234,6 +234,13 @@ gnt_closure_marshal_BOOLEAN__INT_INT_INT, G_TYPE_BOOLEAN, 3, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); + klass->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify)gnt_widget_action_free); + klass->bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify)gnt_widget_action_param_free); + + gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), klass); + GNTDEBUG; } @@ -384,12 +391,56 @@ } gboolean +gnt_widget_perform_action_named(GntWidget *widget, const char *name, ...) +{ + GType type = G_OBJECT_TYPE(widget); + GntWidgetClass *klass = GNT_WIDGET_CLASS(G_OBJECT_GET_CLASS(widget)); + GList *list = NULL; + va_list args; + GntWidgetAction *action; + void *p; + + va_start(args, name); + while ((p = va_arg(args, void *)) != NULL) + list = g_list_append(list, p); + va_end(args); + + action = g_hash_table_lookup(klass->actions, name); + if (action && action->u.action) { + if (list) + return action->u.action(widget, list); + else + return action->u.action_noparam(widget); + } + return FALSE; +} + +static gboolean +gnt_widget_perform_action(GntWidget *widget, const char *keys) +{ + GType type = G_OBJECT_TYPE(widget); + GntWidgetClass *klass = GNT_WIDGET_CLASS(G_OBJECT_GET_CLASS(widget)); + GntWidgetActionParam *param = g_hash_table_lookup(klass->bindings, keys); + + if (param && param->action) { + if (param->list) + return param->action->u.action(widget, param->list); + else + return param->action->u.action_noparam(widget); + } + return FALSE; +} + +gboolean gnt_widget_key_pressed(GntWidget *widget, const char *keys) { gboolean ret; if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_CAN_TAKE_FOCUS)) return FALSE; + if (gnt_widget_perform_action(widget, keys)) + return TRUE; + keys = gnt_widget_remap_keys(widget, keys); g_signal_emit(widget, signals[SIG_KEY_PRESSED], 0, keys, &ret); return ret; @@ -632,3 +683,71 @@ gnt_style_get_bool(GNT_STYLE_SHADOW, FALSE)); } +static void +register_binding(GntWidgetClass *klass, const char *name, const char *trigger, GList *list) +{ + GntWidgetActionParam *param; + + if (name == NULL || *name == '\0') { + g_hash_table_remove(klass->bindings, (char*)trigger); + return; + } + + param = g_new0(GntWidgetActionParam, 1); + param->action = g_hash_table_lookup(klass->actions, name); + param->list = list; + g_hash_table_replace(klass->bindings, g_strdup(trigger), param); +} + +void gnt_widget_register_binding(GntWidgetClass *klass, const char *name, + const char *trigger, ...) +{ + GList *list = NULL; + va_list args; + void *data; + + va_start(args, trigger); + while ((data = va_arg(args, void *))) { + list = g_list_append(list, data); + } + va_end(args); + + register_binding(klass, name, trigger, list); +} + +void gnt_widget_class_register_action(GntWidgetClass *klass, const char *name, + GntWidgetActionCallback callback, + const char *trigger, ...) +{ + void *data; + va_list args; + GntWidgetAction *action = g_new0(GntWidgetAction, 1); + GList *list; + + action->name = g_strdup(name); + action->u.action = callback; + + g_hash_table_replace(klass->actions, g_strdup(name), action); + + list = NULL; + va_start(args, trigger); + while ((data = va_arg(args, void *))) { + list = g_list_append(list, data); + } + va_end(args); + + register_binding(klass, name, trigger, list); +} + +void gnt_widget_action_free(GntWidgetAction *action) +{ + g_free(action->name); + g_free(action); +} + +void gnt_widget_action_param_free(GntWidgetActionParam *param) +{ + g_list_free(param->list); /* XXX: There may be a leak here for string parameters */ + g_free(param); +} + diff -r 242f948ee707 -r 8a0cfee11af8 console/libgnt/gntwidget.h --- a/console/libgnt/gntwidget.h Sat Oct 21 20:40:12 2006 +0000 +++ b/console/libgnt/gntwidget.h Sat Oct 21 21:08:24 2006 +0000 @@ -88,6 +88,8 @@ GObjectClass parent; GHashTable *remaps; /* Key remaps */ + GHashTable *actions; /* name -> Action */ + GHashTable *bindings; /* key -> ActionParam */ void (*map)(GntWidget *obj); void (*show)(GntWidget *obj); /* This will call draw() and take focus (if it can take focus) */ @@ -149,6 +151,40 @@ gboolean gnt_widget_has_shadow(GntWidget *widget); +/******************/ +/* Widget Actions */ +/******************/ +typedef gboolean (*GntWidgetActionCallback) (GntWidget *widget, GList *params); +typedef gboolean (*GntWidgetActionCallbackNoParam)(GntWidget *widget); + +typedef struct _GnWidgetAction GntWidgetAction; +typedef struct _GnWidgetActionParam GntWidgetActionParam; + +struct _GnWidgetAction +{ + char *name; /* The name of the action */ + union { + gboolean (*action)(GntWidget *widget, GList *params); + gboolean (*action_noparam)(GntWidget *widget); + } u; +}; + +struct _GnWidgetActionParam +{ + GntWidgetAction *action; + GList *list; +}; + + +GntWidgetAction *gnt_widget_action_parse(const char *name); + +void gnt_widget_action_free(GntWidgetAction *action); +void gnt_widget_action_param_free(GntWidgetActionParam *param); + + +void gnt_widget_class_register_action(GntWidgetClass *klass, const char *name, + GntWidgetActionCallback callback, const char *trigger, ...); + G_END_DECLS #endif /* GNT_WIDGET_H */ diff -r 242f948ee707 -r 8a0cfee11af8 console/libgnt/test/multiwin.c --- a/console/libgnt/test/multiwin.c Sat Oct 21 20:40:12 2006 +0000 +++ b/console/libgnt/test/multiwin.c Sat Oct 21 21:08:24 2006 +0000 @@ -62,6 +62,7 @@ gnt_tree_add_row_after(GNT_TREE(tree), "6", gnt_tree_create_row(GNT_TREE(tree), "6", " long text", "a2"), "4", NULL); + gnt_tree_add_row_after(GNT_TREE(tree), NULL, NULL, NULL, "4"); int i; for (i = 110; i < 430; i++) { diff -r 242f948ee707 -r 8a0cfee11af8 console/libgnt/test/tv.c --- a/console/libgnt/test/tv.c Sat Oct 21 20:40:12 2006 +0000 +++ b/console/libgnt/test/tv.c Sat Oct 21 21:08:24 2006 +0000 @@ -13,7 +13,7 @@ { gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(view), gnt_entry_get_text(GNT_ENTRY(w)), - GNT_TEXT_FLAG_HIGHLIGHT); + GNT_TEXT_FLAG_UNDERLINE | GNT_TEXT_FLAG_HIGHLIGHT); gnt_entry_add_to_history(GNT_ENTRY(w), gnt_entry_get_text(GNT_ENTRY(w))); gnt_text_view_next_line(GNT_TEXT_VIEW(view)); gnt_entry_clear(GNT_ENTRY(w)); diff -r 242f948ee707 -r 8a0cfee11af8 doc/gaim-text.1.in --- a/doc/gaim-text.1.in Sat Oct 21 20:40:12 2006 +0000 +++ b/doc/gaim-text.1.in Sat Oct 21 21:08:24 2006 +0000 @@ -192,6 +192,63 @@ \\ = \\r .br +.SH Widget Actions +You can specifiy key-bindings for specific widgets. The following entries in +\fI~/.gntrc\fR correspond to the default keybindings for the actions: + +.br +[GntEntry::binding] +.br +c-a = cursor-home +.br +home = cursor-home +.br +c-e = cursor-end +.br +end = cursor-end +.br +backspace = delete-prev +.br +del = delete-next +.br +c-d = delete-next +.br +c-u = delete-start +.br +c-k = delete-end +.br +left = cursor-prev +.br +right = cursor-next +.br +tab = suggest-show +.br +down = suggest-next +.br +up = suggest-prev +.br + +.br +[GntTree::binding] +.br +up = move-up +.br +down = move-down +.br +c-n = move-down +.br +c-p = move-up +.br +pageup = page-up +.br +pagedown = page-down +.br + +The \fBc-\fR corresponds to the \fBControl\fR key. You can also use \fBctrl-\fR +or \fBctr-\fR or \fBctl-\fR to indicate a combination. For alt-keys, you can use +one of \fBa-\fR, \fBalt-\fR, \fBm-\fR or \fBmeta-\fR. You can also use +\fBhome\fR, \fBend\fR, \fBleft\fR, \fBright\fR etc. keys. + .SH Mouse Support There is experimental mouse support. You can focus windows, activate buttons, select rows in a list, scroll using the wheel-scroll etc. Mouse support is