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