Index: openbox/keyboard.c =================================================================== --- openbox/keyboard.c (revision 5918) +++ openbox/keyboard.c (working copy) @@ -37,6 +37,9 @@ #include KeyBindingTree *keyboard_firstnode; +static KeyBindingTree *curpos; +static GSList *chroots; +static KeyBindingTree *chrootq; typedef struct { guint state; @@ -47,8 +50,6 @@ static GSList *interactive_states; -static KeyBindingTree *curpos; - static void grab_for_window(Window win, gboolean grab) { KeyBindingTree *p; @@ -76,6 +77,14 @@ grab_for_window(RootWindow(ob_display, ob_screen), grab); } +static void set_curpos(KeyBindingTree *newpos) +{ + grab_keys(FALSE); + curpos = newpos; + grab_keys(TRUE); +} + +static void keyboard_reset_chains(); static gboolean chain_timeout(gpointer data) { keyboard_reset_chains(); @@ -83,17 +92,32 @@ return FALSE; /* don't repeat */ } -void keyboard_reset_chains() +static void keyboard_reset_chains() { ob_main_loop_timeout_remove(ob_main_loop, chain_timeout); - if (curpos) { - grab_keys(FALSE); - curpos = NULL; - grab_keys(TRUE); - } + if (curpos) + set_curpos(NULL); } +void keyboard_chroot() +{ + if (chrootq == NULL || chroots != NULL && chroots->data == chrootq) return; + chroots = g_slist_prepend(chroots, keyboard_firstnode); + keyboard_firstnode = chrootq; + set_curpos(NULL); +} + +void keyboard_unchroot() +{ + if (chroots == NULL) return; + keyboard_firstnode = chroots->data; + chroots = g_slist_delete_link(chroots, chroots); + set_curpos(NULL); +} + void keyboard_unbind_all() { + while (chroots) + keyboard_unchroot(); tree_destroy(keyboard_firstnode); @@ -102,53 +126,83 @@ curpos = NULL; + chrootq = NULL; } -gboolean keyboard_bind(GList *keylist, ObAction *action) +static KeyBindingTree *make_nodes_and_find_leaf(KeyBindingTree *b) { - KeyBindingTree *tree, *t; - gboolean conflict; - gboolean mods = TRUE; + g_assert(b); + g_assert(b->next_sibling == NULL); + if (keyboard_firstnode == NULL) { + keyboard_firstnode = b; + } else { + KeyBindingTree *last; + KeyBindingTree *a = keyboard_firstnode; + do { + last = a; + if (a->state == b->state && a->key == b->key) { + KeyBindingTree *tmp = b; + b = b->first_child; + g_assert(b->next_sibling == NULL); + g_free(tmp); + a = a->first_child; + } else { + a = a->next_sibling; + } + } while (a && b); + g_assert(last); - g_assert(keylist != NULL); - g_assert(action != NULL); - - if (!(tree = tree_build(keylist))) - return FALSE; - - if ((t = tree_find(tree, &conflict)) != NULL) { - /* already bound to something, use the existing tree */ - tree_destroy(tree); - tree = NULL; - } else - t = tree; - - if (conflict) { - g_message(_("Conflict with key binding in config file")); - tree_destroy(tree); - return FALSE; + if (b == NULL) { + /* b is a prefix of something inside a */ + return last; + } else if (last->state == b->state && last->key == b->key) { + /* something inside of a is a prefix of b */ + KeyBindingTree *tmp = b; + g_assert(last->first_child == NULL); + last->first_child = b = b->first_child; + g_free(tmp); + } else { + /* neither of the above are true */ + last->next_sibling = b; + } } - /* find if every key in this chain has modifiers, and also find the - bottom node of the tree */ - while (t->first_child) { - if (!t->state) - mods = FALSE; - t = t->first_child; + while (b->first_child) { + b = b->first_child; + g_assert(b->next_sibling == NULL); } + return b; +} +static gboolean can_be_interactive(KeyBindingTree *tree) { /* when there are no modifiers in the binding, then the action cannot be interactive */ - if (!mods && action->data.any.interactive) { + for (; tree; tree = tree->first_child) + if (!tree->state) + return FALSE; + return TRUE; +} + +void keyboard_bind(GList *keylist, ObAction *action) +{ + KeyBindingTree *tree; + + g_assert(keylist != NULL); + g_assert(action != NULL); + + if (!(tree = tree_build(keylist))) + return; + + if (!can_be_interactive(tree) && action->data.any.interactive) { action->data.any.interactive = FALSE; action->data.inter.final = TRUE; } - /* set the action */ - t->actions = g_slist_append(t->actions, action); - /* assimilate this built tree into the main tree. assimilation - destroys/uses the tree */ - if (tree) tree_assimilate(tree); + /* consumes the allocation(s) made in tree_build */ + tree = make_nodes_and_find_leaf(tree); - return TRUE; + /* append the action */ + tree->actions = g_slist_append(tree->actions, action); + + return; } gboolean keyboard_interactive_grab(guint state, ObClient *client, @@ -174,8 +228,8 @@ return TRUE; } -void keyboard_interactive_end(ObInteractiveState *s, - guint state, gboolean cancel, Time time) +static void keyboard_interactive_end(ObInteractiveState *s, + guint state, gboolean cancel, Time time) { action_run_interactive(s->actions, s->client, state, time, cancel, TRUE); @@ -190,7 +244,7 @@ } } -void keyboard_interactive_end_client(ObClient *client, gpointer data) +static void keyboard_interactive_end_client(ObClient *client, gpointer data) { GSList *it, *next; @@ -206,15 +260,16 @@ gboolean keyboard_process_interactive_grab(const XEvent *e, ObClient **client) { - GSList *it, *next; gboolean handled = FALSE; gboolean done = FALSE; gboolean cancel = FALSE; + GSList *it = interactive_states; - for (it = interactive_states; it; it = next) { + while (it) { ObInteractiveState *s = it->data; - next = g_slist_next(it); + it = g_slist_next(it); + /* keyboard_interactive_end would invalidate it */ if ((e->type == KeyRelease && !(s->state & e->xkey.state))) @@ -257,23 +312,25 @@ if (p->key == e->xkey.keycode && p->state == e->xkey.state) { + if (p->actions) { + chrootq = p->first_child; + + action_run_key(p->actions, client, e->xkey.state, + e->xkey.x_root, e->xkey.y_root, + e->xkey.time); + } + if (p->first_child != NULL) { /* part of a chain */ ob_main_loop_timeout_remove(ob_main_loop, chain_timeout); /* 5 second timeout for chains */ ob_main_loop_timeout_add(ob_main_loop, 5 * G_USEC_PER_SEC, chain_timeout, NULL, g_direct_equal, NULL); - grab_keys(FALSE); - curpos = p; - grab_keys(TRUE); + set_curpos(p); } else { - keyboard_reset_chains(); + } - action_run_key(p->actions, client, e->xkey.state, - e->xkey.x_root, e->xkey.y_root, - e->xkey.time); - } break; } p = p->next_sibling; Index: openbox/keyboard.h =================================================================== --- openbox/keyboard.h (revision 5731) +++ openbox/keyboard.h (working copy) @@ -34,11 +34,10 @@ void keyboard_startup(gboolean reconfig); void keyboard_shutdown(gboolean reconfig); -gboolean keyboard_bind(GList *keylist, ObAction *action); +void keyboard_bind(GList *keylist, ObAction *action); void keyboard_unbind_all(); void keyboard_event(struct _ObClient *client, const XEvent *e); -void keyboard_reset_chains(); gboolean keyboard_interactive_grab(guint state, struct _ObClient *client, struct _ObAction *action); @@ -48,4 +47,7 @@ void keyboard_grab_for_client(struct _ObClient *c, gboolean grab); +void keyboard_chroot(); +void keyboard_unchroot(); + #endif Index: openbox/keytree.c =================================================================== --- openbox/keytree.c (revision 5731) +++ openbox/keytree.c (working copy) @@ -48,7 +48,7 @@ GList *it; KeyBindingTree *ret = NULL, *p; - if (g_list_length(keylist) <= 0) + if (keylist == NULL) return NULL; /* nothing in the list.. */ for (it = g_list_last(keylist); it; it = g_list_previous(it)) { @@ -70,62 +70,3 @@ } return ret; } - -void tree_assimilate(KeyBindingTree *node) -{ - KeyBindingTree *a, *b, *tmp, *last; - - if (keyboard_firstnode == NULL) { - /* there are no nodes at this level yet */ - keyboard_firstnode = node; - } else { - a = keyboard_firstnode; - last = a; - b = node; - while (a) { - last = a; - if (!(a->state == b->state && a->key == b->key)) { - a = a->next_sibling; - } else { - tmp = b; - b = b->first_child; - g_free(tmp); - a = a->first_child; - } - } - if (!(last->state == b->state && last->key == b->key)) - last->next_sibling = b; - else { - last->first_child = b->first_child; - g_free(b); - } - } -} - -KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict) -{ - KeyBindingTree *a, *b; - - *conflict = FALSE; - - a = keyboard_firstnode; - b = search; - while (a && b) { - if (!(a->state == b->state && a->key == b->key)) { - a = a->next_sibling; - } else { - if ((a->first_child == NULL) == (b->first_child == NULL)) { - if (a->first_child == NULL) { - /* found it! (return the actual node, not the search's) */ - return a; - } - } else { - *conflict = TRUE; - return NULL; /* the chain status' don't match (conflict!) */ - } - b = b->first_child; - a = a->first_child; - } - } - return NULL; /* it just isn't in here */ -} Index: openbox/action.c =================================================================== --- openbox/action.c (revision 5731) +++ openbox/action.c (working copy) @@ -877,6 +877,16 @@ setup_action_growtoedge_east }, { + "chroot", + action_chroot, + NULL + }, + { + "unchroot", + action_unchroot, + NULL + }, + { NULL, NULL, NULL @@ -1791,3 +1801,14 @@ { screen_show_desktop(FALSE); } + +void action_chroot(union ActionData *data) +{ + keyboard_chroot(); +} + +void action_unchroot(union ActionData *data) +{ + keyboard_unchroot(); +} +/* action_chroot and action_unchroot: in keyboard.c */ Index: openbox/keytree.h =================================================================== --- openbox/keytree.h (revision 5731) +++ openbox/keytree.h (working copy) @@ -37,7 +37,5 @@ void tree_destroy(KeyBindingTree *tree); KeyBindingTree *tree_build(GList *keylist); -void tree_assimilate(KeyBindingTree *node); -KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict); #endif Index: openbox/action.h =================================================================== --- openbox/action.h (revision 5731) +++ openbox/action.h (working copy) @@ -339,5 +339,9 @@ void action_show_desktop(union ActionData *data); /* Any */ void action_unshow_desktop(union ActionData *data); +/* Any */ +void action_chroot(union ActionData *data); +/* Any */ +void action_unchroot(union ActionData *data); #endif