GList *keylist)
{
gchar *key;
- ObAction *action;
- xmlNodePtr n, nact;
- GList *it;
-
- if ((n = parse_find_node("chainQuitKey", node))) {
- key = parse_string(doc, n);
- translate_key(key, &config_keyboard_reset_state,
- &config_keyboard_reset_keycode);
- g_free(key);
- }
+ xmlNodePtr n;
+ gboolean is_chroot = FALSE;
- n = parse_find_node("keybind", node);
- while (n) {
- if (parse_attr_string("key", n, &key)) {
- keylist = g_list_append(keylist, key);
+ if (!parse_attr_string("key", node, &key))
+ return;
+ parse_attr_bool("chroot", node, &is_chroot);
- parse_key(i, doc, n->children, keylist);
+ keylist = g_list_append(keylist, key);
- it = g_list_last(keylist);
- g_free(it->data);
- keylist = g_list_delete_link(keylist, it);
+ /* a node either contains actions or key bindings */
+ if ((n = parse_find_node("keybind", node->children))) {
+ while (n) {
+ parse_key(i, doc, n, keylist);
+ n = parse_find_node("keybind", n->next);
}
- n = parse_find_node("keybind", n->next);
- }
- if (keylist) {
- nact = parse_find_node("action", node);
- while (nact) {
- if ((action = action_parse(i, doc, nact,
- OB_USER_ACTION_KEYBOARD_KEY)))
+ } else if ((n = parse_find_node("action", node->children))) {
+ while (n) {
+ ObAction *action;
+
+ action = action_parse(i, doc, n, OB_USER_ACTION_KEYBOARD_KEY);
+ if (action)
keyboard_bind(keylist, action);
- nact = parse_find_node("action", nact->next);
+ n = parse_find_node("action", n->next);
}
}
+
+ if (is_chroot)
+ keyboard_chroot(keylist);
+
+ g_free(key);
+ keylist = g_list_delete_link(keylist, g_list_last(keylist));
+
+ /* go to next sibling */
+ if (node->next) parse_key(i, doc, node->next, keylist);
}
static void parse_keyboard(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
gpointer d)
{
+ xmlNodePtr n;
+ gchar *key;
+
keyboard_unbind_all();
- parse_key(i, doc, node->children, NULL);
+ if ((n = parse_find_node("chainQuitKey", node->children))) {
+ key = parse_string(doc, n);
+ translate_key(key, &config_keyboard_reset_state,
+ &config_keyboard_reset_keycode);
+ g_free(key);
+ }
+
+ if ((n = parse_find_node("keybind", node->children)))
+ parse_key(i, doc, n, NULL);
}
/*
}
}
-void keyboard_reset_chains()
+void keyboard_reset_chains(gint break_chroots)
{
- if (curpos)
- set_curpos(NULL);
+ KeyBindingTree *p;
+
+ for (p = curpos; p; p = p->parent) {
+ if (p->chroot) {
+ if (break_chroots == 0) break; /* stop here */
+ if (break_chroots > 0)
+ --break_chroots;
+ }
+ }
+ set_curpos(p);
}
void keyboard_unbind_all()
keyboard_firstnode = NULL;
}
+void keyboard_chroot(GList *keylist)
+{
+ /* try do it in the existing tree. if we can't that means it is an empty
+ chroot binding. so add it to the tree then. */
+ if (!tree_chroot(keyboard_firstnode, keylist)) {
+ KeyBindingTree *tree;
+ if (!(tree = tree_build(keylist)))
+ return;
+ tree_chroot(tree, keylist);
+ tree_assimilate(tree);
+ }
+}
+
gboolean keyboard_bind(GList *keylist, ObAction *action)
{
KeyBindingTree *tree, *t;
if (!interactive_states) {
grab_keyboard(FALSE);
grab_pointer(FALSE, FALSE, OB_CURSOR_NONE);
- keyboard_reset_chains();
}
}
if (e->xkey.keycode == config_keyboard_reset_keycode &&
e->xkey.state == config_keyboard_reset_state)
{
- keyboard_reset_chains();
+ keyboard_reset_chains(-1);
return;
}
if (p->key == e->xkey.keycode &&
p->state == e->xkey.state)
{
- if (p->first_child != NULL) { /* part of a chain */
+ if (p->first_child != NULL) /* part of a chain */
set_curpos(p);
- } else {
-
- keyboard_reset_chains();
+ else if (p->chroot) /* an empty chroot */
+ set_curpos(p);
+ else {
+ keyboard_reset_chains(0);
action_run_key(p->actions, client, e->xkey.state,
e->xkey.x_root, e->xkey.y_root,
void keyboard_startup(gboolean reconfig);
void keyboard_shutdown(gboolean reconfig);
+void keyboard_chroot(GList *keylist);
gboolean keyboard_bind(GList *keylist, ObAction *action);
void keyboard_unbind_all();
void keyboard_event(struct _ObClient *client, const XEvent *e);
-void keyboard_reset_chains();
+/*! @param break_chroots how many chroots to break. -1 means to break them ALL!
+ */
+void keyboard_reset_chains(gint break_chroots);
gboolean keyboard_interactive_grab(guint state, struct _ObClient *client,
struct _ObAction *action);
ret->keylist = g_list_prepend(ret->keylist,
g_strdup(kit->data)); /* deep copy */
ret->first_child = p;
+ if (p != NULL) p->parent = ret;
if (!translate_key(it->data, &ret->state, &ret->key)) {
tree_destroy(ret);
return NULL;
a = a->first_child;
}
}
- if (!(last->state == b->state && last->key == b->key))
+ if (!(last->state == b->state && last->key == b->key)) {
last->next_sibling = b;
- else {
+ b->parent = last->parent;
+ } else {
last->first_child = b->first_child;
+ last->first_child->parent = last;
g_free(b);
}
}
}
return NULL; /* it just isn't in here */
}
+
+gboolean tree_chroot(KeyBindingTree *tree, GList *keylist)
+{
+ if (keylist == NULL) {
+ tree->chroot = TRUE;
+ return TRUE;
+ } else {
+ guint key, state;
+ if (translate_key(keylist->data, &state, &key)) {
+ while (tree != NULL && !(tree->state == state && tree->key == key))
+ tree = tree->next_sibling;
+ if (tree != NULL)
+ return tree_chroot(tree, keylist->next);
+ }
+ }
+ return FALSE;
+}
guint key;
GList *keylist;
GSList *actions; /* list of Action pointers */
+ gboolean chroot;
+ /* the level up in the tree */
+ struct KeyBindingTree *parent;
/* the next binding in the tree at the same level */
struct KeyBindingTree *next_sibling;
/* the first child of this binding (next binding in a chained sequence).*/
KeyBindingTree *tree_build(GList *keylist);
void tree_assimilate(KeyBindingTree *node);
KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict);
+gboolean tree_chroot(KeyBindingTree *tree, GList *keylist);
+
#endif