mouse and key bindings plugins work. segfault somewhere still on shutdown
[mikachu/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_new(KeyBindingTree, 1);
35         ret->next_sibling = NULL;
36         if (p == NULL) {
37             GList *it;
38
39             /* this is the first built node, the bottom node of the tree */
40             ret->keylist = g_list_copy(keylist); /* shallow copy */
41             for (it = ret->keylist; it != NULL; it = it->next) /* deep copy */
42                 it->data = g_strdup(it->data);
43         }
44         ret->first_child = p;
45         if (!translate_key(it->data, &ret->state, &ret->key)) {
46             tree_destroy(ret);
47             return NULL;
48         }
49     }
50     return ret;
51 }
52
53 void tree_assimilate(KeyBindingTree *node)
54 {
55     KeyBindingTree *a, *b, *tmp, *last;
56
57     if (firstnode == NULL) {
58         /* there are no nodes at this level yet */
59         firstnode = node;
60     } else {
61         a = firstnode;
62         last = a;
63         b = node;
64         while (a) {
65             last = a;
66             if (!(a->state == b->state && a->key == b->key)) {
67                 a = a->next_sibling;
68             } else {
69                 tmp = b;
70                 b = b->first_child;
71                 g_free(tmp);
72                 a = a->first_child;
73             }
74         }
75         if (!(last->state == b->state && last->key == b->key))
76             last->next_sibling = b;
77         else {
78             last->first_child = b->first_child;
79             g_free(b);
80         }
81     }
82 }
83
84 KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict)
85 {
86     KeyBindingTree *a, *b;
87
88     *conflict = FALSE;
89
90     a = firstnode;
91     b = search;
92     while (a && b) {
93         if (!(a->state == b->state && a->key == b->key)) {
94             a = a->next_sibling;
95         } else {
96             if ((a->first_child == NULL) == (b->first_child == NULL)) {
97                 if (a->first_child == NULL) {
98                     /* found it! (return the actual node, not the search's) */
99                     return a;
100                 }
101             } else {
102                 *conflict = TRUE;
103                 return NULL; /* the chain status' don't match (conflict!) */
104             }
105             b = b->first_child;
106             a = a->first_child;
107         }
108     }
109     return NULL; /* it just isn't in here */
110 }