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