parses the 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     }
83     begin = end + 1;
84   }
85   
86   printf("got modifier: %s\n", modstring.c_str());
87     
88   KeySym sym = XStringToKeysym(const_cast<char *>(key.c_str()));
89   if (sym == NoSymbol) return false;
90   b.modifiers = mods;
91   b.key = XKeysymToKeycode(otk::OBDisplay::display, sym);
92   return b.key != 0;
93 }
94
95 BindingTree *OBBindings::buildtree(const StringVect &keylist, int id)
96 {
97   if (keylist.empty()) return 0; // nothing in the list.. return 0
98
99   BindingTree *ret = new BindingTree(id), *p = 0;
100
101   StringVect::const_iterator it, end = keylist.end();
102   for (it = keylist.begin(); it != end; ++it) {
103     if (p)
104       p = p->first_child = new BindingTree(id);
105     else
106       p = ret; // the first node
107     
108     if (!translate(*it, p->binding))
109       break;
110     p->text = *it;
111   }
112   if (it != end) {
113     // build failed.. clean up and return 0
114     p = ret;
115     while (p->first_child) {
116       BindingTree *c = p->first_child;
117       delete p;
118       p = c;      
119     }
120     delete p;
121     return 0;
122   } else {
123     // set the proper chain status on the last node
124     p->chain = false;
125   }
126
127   printf("BUILDING:\n");
128   print_branch(ret, "");
129   
130   // successfully built a tree
131   return ret;
132 }
133
134 static void destroytree(BindingTree *tree)
135 {
136   while (tree) {
137     BindingTree *c = tree->first_child;
138     delete tree;
139     tree = c;
140   }
141 }
142
143 OBBindings::OBBindings()
144 {
145 }
146
147
148 OBBindings::~OBBindings()
149 {
150   remove_all();
151 }
152
153
154 void OBBindings::assimilate(BindingTree *node)
155 {
156   BindingTree *a, *b, *tmp, *last;
157
158   if (!_tree.first_child) {
159     // there are no nodes at this level yet
160     _tree.first_child = node;
161     return;
162   } else {
163     a = _tree.first_child;
164     last = a;
165     b = node;
166     while (a->first_child) {
167       last = a;
168       if (a->binding != b->binding) {
169         a = a->next_sibling;
170       } else {
171         tmp = b;
172         b = b->first_child;
173         delete tmp;
174         a = a->first_child;
175       }
176     }
177     last->first_child = b->first_child;
178     delete b;
179   }
180 }
181
182
183 int OBBindings::find(BindingTree *search) {
184   BindingTree *a, *b;
185   a = _tree.first_child;
186   b = search;
187   while (a && b) {
188     if (a->binding != b->binding) {
189       a = a->next_sibling;
190     } else {
191       if (a->chain == b->chain) {
192         if (!a->chain)
193           return a->id; // found it! (return the actual id, not the search's)
194       } else
195           return -2; // the chain status' don't match (conflict!)
196       b = b->first_child;
197       a = a->first_child;
198     }
199   }
200   return -1; // it just isn't in here
201 }
202
203 /*
204 static int find(BindingTree *parent, BindingTree *node) {
205   BindingTree *p, *lastsib, *nextparent, *nextnode = node->first_child;
206
207   if (!parent->first_child)
208     return -1;
209
210   p = parent->first_child;
211   while (p) {
212     if (node->binding == p->binding) {
213       if (node->chain == p->chain) {
214         if (!node->chain) {
215           return p->id; // found it! (return the actual id, not the search's)
216         } else {
217           break; // go on to the next child in the chain
218         }
219       } else {
220         return -2; // the chain status' don't match (conflict!)
221       }
222     }
223     p = p->next_sibling;
224   }
225   if (!p) return -1; // doesn't exist
226
227   if (node->chain) {
228     assert(node->first_child);
229     return find(p, node->first_child);
230   } else
231     return -1; // it just isnt in here
232 }
233 */
234
235 bool OBBindings::add(const StringVect &keylist, int id)
236 {
237   BindingTree *tree;
238
239   if (!(tree = buildtree(keylist, id)))
240     return false; // invalid binding requested
241
242   if (find(tree) < -1) {
243     // conflicts with another binding
244     destroytree(tree);
245     return false;
246   }
247
248   // assimilate this built tree into the main tree
249   assimilate(tree); // assimilation destroys/uses the tree
250   return true;
251 }
252
253
254 int OBBindings::find(const StringVect &keylist)
255 {
256   BindingTree *tree;
257   bool ret;
258
259   if (!(tree = buildtree(keylist, 0)))
260     return false; // invalid binding requested
261
262   ret = find(tree) >= 0;
263
264   destroytree(tree);
265
266   return ret;
267 }
268
269
270 int OBBindings::remove(const StringVect &keylist)
271 {
272   (void)keylist;
273   assert(false); // XXX: function not implemented yet
274 }
275
276
277 static void remove_branch(BindingTree *first)
278 {
279   BindingTree *p = first;
280
281   while (p) {
282     if (p->first_child)
283       remove_branch(p->first_child);
284     BindingTree *s = p->next_sibling;
285     delete p;
286     p = s;
287   }
288 }
289
290
291 void OBBindings::remove_all()
292 {
293   if (_tree.first_child)
294     remove_branch(_tree.first_child);
295 }
296
297 }