Prevent overflow while calculating frame size hints
[notion/jeffpc.git] / ioncore / conf-bindings.c
blob83a171709919a23ceb81e0f3175cff14ab5d13a9
1 /*
2 * ion/ioncore/conf-bindings.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <string.h>
11 #define XK_MISCELLANY
12 #include <X11/keysymdef.h>
14 #ifdef CF_SUN_F1X_REMAP
15 #include <X11/Sunkeysym.h>
16 #endif
18 #include <libtu/map.h>
20 #include "common.h"
21 #include "binding.h"
22 #include <libextl/readconfig.h>
23 #include "global.h"
24 #include <libextl/extl.h>
25 #include "conf-bindings.h"
26 #include "bindmaps.h"
27 #include "ioncore.h"
30 /*{{{ parse_keybut */
33 #define MOD5_NDX 7
35 static StringIntMap state_map[]={
36 {"Shift", ShiftMask},
37 {"Lock", LockMask},
38 {"Control", ControlMask},
39 {"Mod1", Mod1Mask},
40 {"Mod2", Mod2Mask},
41 {"Mod3", Mod3Mask},
42 {"Mod4", Mod4Mask},
43 {"Mod5", Mod5Mask},
44 {"AnyModifier", AnyModifier},
45 {"NoModifier", 0},
46 {NULL, 0},
49 static StringIntMap button_map[]={
50 {"Button1", Button1},
51 {"Button2", Button2},
52 {"Button3", Button3},
53 {"Button4", Button4},
54 {"Button5", Button5},
55 {"Button6", 6},
56 {"Button7", 7},
57 {"AnyButton", AnyButton},
58 {NULL, 0},
62 bool ioncore_parse_keybut(const char *str, uint *mod_ret, uint *ksb_ret,
63 bool button, bool init_any)
65 char *str2, *p, *p2;
66 int keysym=NoSymbol, i;
67 bool ret=FALSE;
69 *ksb_ret=NoSymbol;
70 *mod_ret=(init_any && !button ? AnyModifier : 0);
72 str2=scopy(str);
74 if(str2==NULL)
75 return FALSE;
77 p=str2;
79 while(*p!='\0'){
80 p2=strchr(p, '+');
82 if(p2!=NULL)
83 *p2='\0';
85 if(!button){
86 keysym=XStringToKeysym(p);
87 #ifdef CF_SUN_F1X_REMAP
88 if(keysym==XK_F11)
89 keysym=SunXK_F36;
90 else if(keysym==XK_F12)
91 keysym=SunXK_F37;
92 #endif
95 if(!button && keysym!=NoSymbol){
96 int tmp;
97 if(*ksb_ret!=NoSymbol){
98 warn_obj(str, TR("Insane key combination."));
99 break;
101 if(XKeysymToKeycode(ioncore_g.dpy, keysym)==0){
102 ioncore_warn_nolog("%s: %s", str,
103 TR("Could not convert keysym to keycode."));
104 break;
106 *ksb_ret=keysym;
107 }else{
108 i=stringintmap_ndx(state_map, p);
110 if(i<0){
111 i=stringintmap_ndx(button_map, p);
113 if(i<0){
114 warn(TR("Unknown button \"%s\"."), p);
115 break;
118 if(!button || *ksb_ret!=NoSymbol){
119 warn_obj(str, TR("Insane button combination."));
120 break;
122 *ksb_ret=button_map[i].value;
123 }else{
124 if(*mod_ret==AnyModifier){
125 if(!init_any){
126 warn_obj(str, TR("Insane modifier combination."));
127 break;
128 }else{
129 *mod_ret=state_map[i].value;
131 }else{
132 if(*mod_ret!=0 && state_map[i].value==AnyModifier){
133 warn_obj(str, TR("Insane modifier combination."));
134 break;
135 }else{
136 *mod_ret|=state_map[i].value;
142 if(p2==NULL){
143 ret=TRUE;
144 break;
147 p=p2+1;
150 free(str2);
152 return ret;
155 #undef BUTTON1_NDX
158 /*}}}*/
161 /*{{{ bindmap_defbindings */
164 static bool do_action(WBindmap *bindmap, const char *str,
165 ExtlFn func, uint act, uint mod, uint ksb,
166 int area, bool wr)
168 WBinding binding;
170 if(wr && mod==0){
171 warn(TR("Can not wait on modifiers when no modifiers set in \"%s\"."),
172 str);
173 wr=FALSE;
176 binding.wait=wr;
177 binding.act=act;
178 binding.state=mod;
179 binding.ksb=ksb;
180 binding.kcb=(act==BINDING_KEYPRESS ? XKeysymToKeycode(ioncore_g.dpy, ksb) : ksb);
181 binding.area=area;
182 binding.submap=NULL;
184 if(func!=extl_fn_none()){
185 binding.func=extl_ref_fn(func);
186 if(bindmap_add_binding(bindmap, &binding))
187 return TRUE;
188 extl_unref_fn(binding.func);
189 warn(TR("Unable to add binding %s."), str);
190 }else{
191 binding.func=func;
192 if(bindmap_remove_binding(bindmap, &binding))
193 return TRUE;
194 /*warn(TR("Unable to remove binding %s."), str);*/
197 return FALSE;
201 static bool do_submap(WBindmap *bindmap, const char *str,
202 ExtlTab subtab, uint action, uint mod, uint ksb)
204 WBinding binding, *bnd;
205 uint kcb=0;
207 if(action!=BINDING_KEYPRESS)
208 return FALSE;
210 kcb=XKeysymToKeycode(ioncore_g.dpy, ksb);
212 bnd=bindmap_lookup_binding(bindmap, action, mod, kcb);
214 if(bnd!=NULL && bnd->submap!=NULL && bnd->state==mod)
215 return bindmap_defbindings(bnd->submap, subtab, TRUE);
217 binding.wait=FALSE;
218 binding.act=BINDING_KEYPRESS;
219 binding.state=mod;
220 binding.ksb=ksb;
221 binding.kcb=kcb;
222 binding.area=0;
223 binding.func=extl_fn_none();
224 binding.submap=create_bindmap();
226 if(binding.submap==NULL)
227 return FALSE;
229 if(bindmap_add_binding(bindmap, &binding))
230 return bindmap_defbindings(binding.submap, subtab, TRUE);
232 binding_deinit(&binding);
234 warn(TR("Unable to add submap for binding %s."), str);
236 return FALSE;
240 static StringIntMap action_map[]={
241 {"kpress", BINDING_KEYPRESS},
242 {"mpress", BINDING_BUTTONPRESS},
243 {"mclick", BINDING_BUTTONCLICK},
244 {"mdblclick", BINDING_BUTTONDBLCLICK},
245 {"mdrag", BINDING_BUTTONMOTION},
246 {"submap_enter", BINDING_SUBMAP_ENTER},
247 {"submap_wait", BINDING_SUBMAP_RELEASEMOD},
248 /*{"submap_leave", BINDING_SUBMAP_LEAVE},*/
249 {NULL, 0}
253 static bool do_entry(WBindmap *bindmap, ExtlTab tab,
254 const StringIntMap *areamap, bool init_any)
256 bool ret=FALSE;
257 char *action_str=NULL, *ksb_str=NULL, *area_str=NULL;
258 int action=0;
259 uint ksb=0, mod=0;
260 WBinding *bnd=NULL;
261 ExtlTab subtab;
262 ExtlFn func;
263 bool wr=FALSE;
264 int area=0;
266 if(!extl_table_gets_s(tab, "action", &action_str)){
267 warn(TR("Binding type not set."));
268 goto fail;
271 if(strcmp(action_str, "kpress_wait")==0){
272 action=BINDING_KEYPRESS;
273 wr=TRUE;
274 }else{
275 action=stringintmap_value(action_map, action_str, -1);
276 if(action<0){
277 warn(TR("Unknown binding type \"%s\"."), action_str);
278 goto fail;
282 if(!BINDING_IS_PSEUDO(action)){
283 if(!extl_table_gets_s(tab, "kcb", &ksb_str))
284 goto fail;
286 if(!ioncore_parse_keybut(ksb_str, &mod, &ksb,
287 (action!=BINDING_KEYPRESS && action!=-1),
288 init_any)){
289 goto fail;
293 if(extl_table_gets_t(tab, "submap", &subtab)){
294 ret=do_submap(bindmap, ksb_str, subtab, action, mod, ksb);
295 extl_unref_table(subtab);
296 }else{
297 if(areamap!=NULL){
298 if(extl_table_gets_s(tab, "area", &area_str)){
299 area=stringintmap_value(areamap, area_str, -1);
300 if(area<0){
301 warn(TR("Unknown area \"%s\" for binding %s."),
302 area_str, ksb_str);
303 area=0;
308 if(!extl_table_gets_f(tab, "func", &func)){
309 /*warn("Function for binding %s not set/nil/undefined.", ksb_str);
310 goto fail;*/
311 func=extl_fn_none();
313 ret=do_action(bindmap, ksb_str, func, action, mod, ksb, area, wr);
314 if(!ret)
315 extl_unref_fn(func);
318 fail:
319 if(action_str!=NULL)
320 free(action_str);
321 if(ksb_str!=NULL)
322 free(ksb_str);
323 if(area_str!=NULL)
324 free(area_str);
325 return ret;
329 bool bindmap_defbindings(WBindmap *bindmap, ExtlTab tab, bool submap)
331 int i, n, nok=0;
332 ExtlTab ent;
334 n=extl_table_get_n(tab);
336 for(i=1; i<=n; i++){
337 if(extl_table_geti_t(tab, i, &ent)){
338 nok+=do_entry(bindmap, ent, bindmap->areamap, submap);
339 extl_unref_table(ent);
340 continue;
342 warn(TR("Unable to get bindmap entry %d."), i);
344 return (nok!=0);
348 /*}}}*/
351 /*{{{ bindmap_getbindings */
354 static char *get_mods(uint state)
356 char *ret=NULL;
357 int i;
359 if(state==AnyModifier){
360 ret=scopy("AnyModifier+");
361 }else{
362 ret=scopy("");
363 for(i=0; i<=MOD5_NDX; i++){
364 if(ret==NULL)
365 break;
366 if((int)(state&state_map[i].value)==state_map[i].value){
367 char *ret2=ret;
368 ret=scat3(ret, state_map[i].string, "+");
369 free(ret2);
374 return ret;
378 static char *get_key(char *mods, uint ksb)
380 const char *s=XKeysymToString(ksb);
381 char *ret=NULL;
383 if(s==NULL){
384 warn(TR("Unable to convert keysym to string."));
385 return NULL;
388 return scat(mods, s);
392 static char *get_button(char *mods, uint ksb)
394 const char *s=stringintmap_key(button_map, ksb, NULL);
395 char *ret=NULL;
397 if(s==NULL){
398 warn(TR("Unable to convert button to string."));
399 return NULL;
402 return scat(mods, s);
406 static bool get_kpress(WBindmap *bindmap, WBinding *b, ExtlTab t)
408 char *mods;
409 char *key;
411 if(b->wait)
412 extl_table_sets_s(t, "action", "kpress_wait");
413 else
414 extl_table_sets_s(t, "action", "kpress");
416 mods=get_mods(b->state);
418 if(mods==NULL)
419 return FALSE;
421 key=get_key(mods, b->ksb);
423 free(mods);
425 if(key==NULL)
426 return FALSE;
428 extl_table_sets_s(t, "kcb", key);
430 free(key);
432 if(b->submap!=NULL){
433 ExtlTab stab=bindmap_getbindings(b->submap);
434 extl_table_sets_t(t, "submap", stab);
435 }else{
436 extl_table_sets_f(t, "func", b->func);
439 return TRUE;
443 static bool get_mact(WBindmap *bindmap, WBinding *b, ExtlTab t)
445 char *mods;
446 char *button;
448 extl_table_sets_s(t, "action", stringintmap_key(action_map, b->act, NULL));
450 mods=get_mods(b->state);
452 if(mods==NULL)
453 return FALSE;
455 button=get_button(mods, b->ksb);
457 free(mods);
459 if(button==NULL)
460 return FALSE;
462 extl_table_sets_s(t, "kcb", button);
464 free(button);
466 if(b->area!=0 && bindmap->areamap!=NULL)
467 extl_table_sets_s(t, "area",
468 stringintmap_key(bindmap->areamap, b->area, NULL));
470 extl_table_sets_f(t, "func", b->func);
472 return TRUE;
476 static ExtlTab getbinding(WBindmap *bindmap, WBinding *b)
478 ExtlTab t=extl_create_table();
480 if(b->act==BINDING_KEYPRESS){
481 if(get_kpress(bindmap, b, t))
482 return t;
483 }else{
484 if(get_mact(bindmap, b, t))
485 return t;
488 return extl_unref_table(t);
492 ExtlTab bindmap_getbindings(WBindmap *bindmap)
494 Rb_node node;
495 WBinding *b;
496 ExtlTab tab;
497 ExtlTab btab;
498 int n=0;
500 tab=extl_create_table();
502 FOR_ALL_BINDINGS(b, node, bindmap->bindings){
503 btab=getbinding(bindmap, b);
504 extl_table_seti_t(tab, n+1, btab);
505 extl_unref_table(btab);
506 n++;
509 return tab;
513 /*}}}*/