dont try use invalid modifiers
[mikachu/openbox.git] / src / bindings.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #ifdef HAVE_CONFIG_H
4 # include "../config.h"
5 #endif
6
7 #include "bindings.hh"
8 #include "otk/display.hh"
9
10 extern "C" {
11 #include <X11/Xlib.h>
12 }
13
14 namespace ob {
15
16 #include <stdio.h>
17 static void print_branch(BindingTree *first, std::string str)
18 {
19   BindingTree *p = first;
20   
21   while (p) {
22     if (p->first_child)
23       print_branch(p->first_child, str + " " + p->text);
24     if (!p->chain)
25       printf("%d%s\n", p->id, (str + " " + p->text).c_str());
26     BindingTree *s = p->next_sibling;
27     delete p;
28     p = s;
29   }
30 }
31
32
33 void OBBindings::display()
34 {
35   if (_tree.first_child)
36     print_branch(_tree.first_child, "");
37 }
38
39
40
41 bool OBBindings::translate(const std::string &str, Binding &b)
42 {
43   unsigned int mods = 0;
44   std::string modstring;
45   
46   // parse out the base key name
47   std::string::size_type keybegin = str.find_last_of('-');
48   keybegin = (keybegin == std::string::npos) ? 0 : keybegin + 1;
49   std::string key(str, keybegin);
50
51   // XXX: get some modifiers up in the hizzie
52   // parse out the requested modifier keys
53   std::string::size_type begin = 0, end;
54   while (begin != keybegin) {
55     end = str.find_first_of('-', begin);
56
57     std::string mod(str, begin, end-begin);
58     modstring += mod;
59
60     if (mod == "C") {           // control
61       mods |= ControlMask;
62     } else if (mod == "S") {    // shift
63       mods |= ShiftMask;
64     } else if (mod == "A" ||    // alt/mod1
65                mod == "M" ||
66                mod == "M1" ||
67                mod == "Mod1") {
68       mods |= Mod1Mask;
69     } else if (mod == "M2" ||   // mod2
70                mod == "Mod2") {
71       mods |= Mod2Mask;
72     } else if (mod == "M3" ||   // mod3
73                mod == "Mod3") {
74       mods |= Mod3Mask;
75     } else if (mod == "W" ||    // windows/mod4
76                mod == "M4" ||
77                mod == "Mod4") {
78       mods |= Mod4Mask;
79     } else if (mod == "M5" ||   // mod5
80                mod == "Mod5") {
81       mods |= Mod5Mask;
82     } else {                    // invalid
83       return false;
84     }
85     begin = end + 1;
86   }
87   
88   printf("got modifier: %s\n", modstring.c_str());
89     
90   KeySym sym = XStringToKeysym(const_cast<char *>(key.c_str()));
91   if (sym == NoSymbol) return false;
92   b.modifiers = mods;
93   b.key = XKeysymToKeycode(otk::OBDisplay::display, sym);
94   return b.key != 0;
95 }
96
97 BindingTree *OBBindings::buildtree(const StringVect &keylist, int id)
98 {
99   if (keylist.empty()) return 0; // nothing in the list.. return 0
100
101   BindingTree *ret = new BindingTree(id), *p = 0;
102
103   StringVect::const_iterator it, end = keylist.end();
104   for (it = keylist.begin(); it != end; ++it) {
105     if (p)
106       p = p->first_child = new BindingTree(id);
107     else
108       p = ret; // the first node
109     
110     if (!translate(*it, p->binding))
111       break;
112     p->text = *it;
113   }
114   if (it != end) {
115     // build failed.. clean up and return 0
116     p = ret;
117     while (p->first_child) {
118       BindingTree *c = p->first_child;
119       delete p;
120       p = c;      
121     }
122     delete p;
123     return 0;
124   } else {
125     // set the proper chain status on the last node
126     p->chain = false;
127   }
128
129   printf("BUILDING:\n");
130   print_branch(ret, "");
131   
132   // successfully built a tree
133   return ret;
134 }
135
136 static void destroytree(BindingTree *tree)
137 {
138   while (tree) {
139     BindingTree *c = tree->first_child;
140     delete tree;
141     tree = c;
142   }
143 }
144
145 OBBindings::OBBindings()
146 {
147 }
148
149
150 OBBindings::~OBBindings()
151 {
152   remove_all();
153 }
154
155
156 void OBBindings::assimilate(BindingTree *node)
157 {
158   BindingTree *a, *b, *tmp, *last;
159
160   if (!_tree.first_child) {
161     // there are no nodes at this level yet
162     _tree.first_child = node;
163     return;
164   } else {
165     a = _tree.first_child;
166     last = a;
167     b = node;
168     while (a->first_child) {
169       last = a;
170       if (a->binding != b->binding) {
171         a = a->next_sibling;
172       } else {
173         tmp = b;
174         b = b->first_child;
175         delete tmp;
176         a = a->first_child;
177       }
178     }
179     last->first_child = b->first_child;
180     delete b;
181   }
182 }
183
184
185 int OBBindings::find(BindingTree *search) {
186   BindingTree *a, *b;
187   a = _tree.first_child;
188   b = search;
189   while (a && b) {
190     if (a->binding != b->binding) {
191       a = a->next_sibling;
192     } else {
193       if (a->chain == b->chain) {
194         if (!a->chain)
195           return a->id; // found it! (return the actual id, not the search's)
196       } else
197           return -2; // the chain status' don't match (conflict!)
198       b = b->first_child;
199       a = a->first_child;
200     }
201   }
202   return -1; // it just isn't in here
203 }
204
205 /*
206 static int find(BindingTree *parent, BindingTree *node) {
207   BindingTree *p, *lastsib, *nextparent, *nextnode = node->first_child;
208
209   if (!parent->first_child)
210     return -1;
211
212   p = parent->first_child;
213   while (p) {
214     if (node->binding == p->binding) {
215       if (node->chain == p->chain) {
216         if (!node->chain) {
217           return p->id; // found it! (return the actual id, not the search's)
218         } else {
219           break; // go on to the next child in the chain
220         }
221       } else {
222         return -2; // the chain status' don't match (conflict!)
223       }
224     }
225     p = p->next_sibling;
226   }
227   if (!p) return -1; // doesn't exist
228
229   if (node->chain) {
230     assert(node->first_child);
231     return find(p, node->first_child);
232   } else
233     return -1; // it just isnt in here
234 }
235 */
236
237 bool OBBindings::add(const StringVect &keylist, int id)
238 {
239   BindingTree *tree;
240
241   if (!(tree = buildtree(keylist, id)))
242     return false; // invalid binding requested
243
244   if (find(tree) < -1) {
245     // conflicts with another binding
246     destroytree(tree);
247     return false;
248   }
249
250   // assimilate this built tree into the main tree
251   assimilate(tree); // assimilation destroys/uses the tree
252   return true;
253 }
254
255
256 int OBBindings::find(const StringVect &keylist)
257 {
258   BindingTree *tree;
259   bool ret;
260
261   if (!(tree = buildtree(keylist, 0)))
262     return false; // invalid binding requested
263
264   ret = find(tree) >= 0;
265
266   destroytree(tree);
267
268   return ret;
269 }
270
271
272 int OBBindings::remove(const StringVect &keylist)
273 {
274   (void)keylist;
275   assert(false); // XXX: function not implemented yet
276 }
277
278
279 static void remove_branch(BindingTree *first)
280 {
281   BindingTree *p = first;
282
283   while (p) {
284     if (p->first_child)
285       remove_branch(p->first_child);
286     BindingTree *s = p->next_sibling;
287     delete p;
288     p = s;
289   }
290 }
291
292
293 void OBBindings::remove_all()
294 {
295   if (_tree.first_child)
296     remove_branch(_tree.first_child);
297 }
298
299 }