]> icculus.org git repositories - dana/openbox.git/blob - openbox/keytree.c
better handling of starting a new interactive grab while one is in progress
[dana/openbox.git] / openbox / keytree.c
1 #include "keyboard.h"
2 #include "translate.h"
3 #include <glib.h>
4
5 void tree_destroy(KeyBindingTree *tree)
6 {
7     KeyBindingTree *c;
8
9     while (tree) {
10         tree_destroy(tree->next_sibling);
11         c = tree->first_child;
12         if (c == NULL) {
13             GList *it;
14             GSList *sit;
15             for (it = tree->keylist; it != NULL; it = it->next)
16                 g_free(it->data);
17             g_list_free(tree->keylist);
18             for (sit = tree->actions; sit != NULL; sit = sit->next)
19                 action_free(sit->data);
20             g_slist_free(tree->actions);
21         }
22         g_free(tree);
23         tree = c;
24     }
25 }
26
27 KeyBindingTree *tree_build(GList *keylist)
28 {
29     GList *it;
30     KeyBindingTree *ret = NULL, *p;
31
32     if (g_list_length(keylist) <= 0)
33         return NULL; /* nothing in the list.. */
34
35     for (it = g_list_last(keylist); it != NULL; it = it->prev) {
36         p = ret;
37         ret = g_new0(KeyBindingTree, 1);
38         if (p == NULL) {
39             GList *it;
40
41             /* this is the first built node, the bottom node of the tree */
42             ret->keylist = g_list_copy(keylist); /* shallow copy */
43             for (it = ret->keylist; it != NULL; it = it->next) /* deep copy */
44                 it->data = g_strdup(it->data);
45         }
46         ret->first_child = p;
47         if (!translate_key(it->data, &ret->state, &ret->key)) {
48             tree_destroy(ret);
49             return NULL;
50         }
51     }
52     return ret;
53 }
54
55 void tree_assimilate(KeyBindingTree *node)
56 {
57     KeyBindingTree *a, *b, *tmp, *last;
58
59     if (keyboard_firstnode == NULL) {
60         /* there are no nodes at this level yet */
61         keyboard_firstnode = node;
62     } else {
63         a = keyboard_firstnode;
64         last = a;
65         b = node;
66         while (a) {
67             last = a;
68             if (!(a->state == b->state && a->key == b->key)) {
69                 a = a->next_sibling;
70             } else {
71                 tmp = b;
72                 b = b->first_child;
73                 g_free(tmp);
74                 a = a->first_child;
75             }
76         }
77         if (!(last->state == b->state && last->key == b->key))
78             last->next_sibling = b;
79         else {
80             last->first_child = b->first_child;
81             g_free(b);
82         }
83     }
84 }
85
86 KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict)
87 {
88     KeyBindingTree *a, *b;
89
90     *conflict = FALSE;
91
92     a = keyboard_firstnode;
93     b = search;
94     while (a && b) {
95         if (!(a->state == b->state && a->key == b->key)) {
96             a = a->next_sibling;
97         } else {
98             if ((a->first_child == NULL) == (b->first_child == NULL)) {
99                 if (a->first_child == NULL) {
100                     /* found it! (return the actual node, not the search's) */
101                     return a;
102                 }
103             } else {
104                 *conflict = TRUE;
105                 return NULL; /* the chain status' don't match (conflict!) */
106             }
107             b = b->first_child;
108             a = a->first_child;
109         }
110     }
111     return NULL; /* it just isn't in here */
112 }