fixes for new keybindings stuff/chroot/parsing
[dana/openbox.git] / openbox / config.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    config.c for the Openbox window manager
4    Copyright (c) 2006        Mikael Magnusson
5    Copyright (c) 2003-2007   Dana Jansens
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "config.h"
21 #include "keyboard.h"
22 #include "mouse.h"
23 #include "prop.h"
24 #include "translate.h"
25 #include "client.h"
26 #include "screen.h"
27 #include "parser/parse.h"
28 #include "openbox.h"
29 #include "gettext.h"
30
31 gboolean config_focus_new;
32 gboolean config_focus_follow;
33 guint    config_focus_delay;
34 gboolean config_focus_raise;
35 gboolean config_focus_last;
36
37 ObPlacePolicy config_place_policy;
38
39 gchar   *config_theme;
40 gboolean config_theme_keepborder;
41 gboolean config_theme_hidedisabled;
42
43 gchar   *config_title_layout;
44
45 RrFont *config_font_activewindow;
46 RrFont *config_font_inactivewindow;
47 RrFont *config_font_menuitem;
48 RrFont *config_font_menutitle;
49
50 gint    config_desktops_num;
51 GSList *config_desktops_names;
52 guint   config_screen_firstdesk;
53
54 gboolean config_resize_redraw;
55 gboolean config_resize_four_corners;
56 gint     config_resize_popup_show;
57 gint     config_resize_popup_pos;
58
59 ObStackingLayer config_dock_layer;
60 gboolean        config_dock_floating;
61 gboolean        config_dock_nostrut;
62 ObDirection     config_dock_pos;
63 gint            config_dock_x;
64 gint            config_dock_y;
65 ObOrientation   config_dock_orient;
66 gboolean        config_dock_hide;
67 guint           config_dock_hide_delay;
68 guint           config_dock_show_delay;
69 guint           config_dock_app_move_button;
70 guint           config_dock_app_move_modifiers;
71
72 guint config_keyboard_reset_keycode;
73 guint config_keyboard_reset_state;
74
75 gint config_mouse_threshold;
76 gint config_mouse_dclicktime;
77
78 gboolean config_menu_warppointer;
79 guint    config_menu_hide_delay;
80 gboolean config_menu_middle;
81 guint    config_submenu_show_delay;
82 gboolean config_menu_client_list_icons;
83
84 GSList *config_menu_files;
85
86 gint     config_resist_win;
87 gint     config_resist_edge;
88 gboolean config_resist_layers_below;
89
90 GSList *config_per_app_settings;
91
92 /*
93   <applications>
94     <application name="aterm">
95       <decor>false</decor>
96     </application>
97     <application name="Rhythmbox">
98       <layer>above</layer>
99       <position>
100         <x>700</x>
101         <y>0</y>
102       </position>
103       <head>1</head>
104     </application>
105   </applications>
106 */
107
108 /* Manages settings for individual applications.
109    Some notes: head is the screen number in a multi monitor
110    (Xinerama) setup (starting from 0) or mouse, meaning the
111    head the pointer is on. Default: mouse.
112    Layer can be three values, above (Always on top), below
113    (Always on bottom) and everything else (normal behaviour).
114    Positions can be an integer value or center, which will
115    center the window in the specified axis. Position is relative
116    from head, so <position><x>center</x></position><head>1</head>
117    will center the window on the second head.
118 */
119 static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
120                                    xmlNodePtr node, gpointer d)
121 {
122     xmlNodePtr app = parse_find_node("application", node->children);
123     gchar *name, *class;
124     gboolean name_set, class_set;
125     gboolean x_pos_given;
126
127     while (app) {
128         name_set = class_set = x_pos_given = FALSE;
129
130         class_set = parse_attr_string("class", app, &class);
131         name_set = parse_attr_string("name", app, &name);
132         if (class_set || name_set) {
133             xmlNodePtr n, c;
134             ObAppSettings *settings = g_new0(ObAppSettings, 1);
135             
136             if (name_set)
137                 settings->name = name;
138             else
139                 settings->name = NULL;
140
141             if (class_set)
142                 settings->class = class;
143             else
144                 settings->class = NULL;
145
146             if (!parse_attr_string("role", app, &settings->role))
147                 settings->role = NULL;
148
149             settings->decor = -1;
150             if ((n = parse_find_node("decor", app->children)))
151                 settings->decor = parse_bool(doc, n);
152
153             settings->shade = -1;
154             if ((n = parse_find_node("shade", app->children)))
155                 settings->shade = parse_bool(doc, n);
156
157             settings->position.x = settings->position.y = 0;
158             settings->pos_given = FALSE;
159             if ((n = parse_find_node("position", app->children))) {
160                 if ((c = parse_find_node("x", n->children))) {
161                     gchar *s = parse_string(doc, c);
162                     if (!strcmp(s, "center")) {
163                         settings->center_x = TRUE;
164                         x_pos_given = TRUE;
165                     } else {
166                         settings->position.x = parse_int(doc, c);
167                         x_pos_given = TRUE;
168                     }
169                     g_free(s);
170                 }
171
172                 if (x_pos_given && (c = parse_find_node("y", n->children))) {
173                     gchar *s = parse_string(doc, c);
174                     if (!strcmp(s, "center")) {
175                         settings->center_y = TRUE;
176                         settings->pos_given = TRUE;
177                     } else {
178                         settings->position.y = parse_int(doc, c);
179                         settings->pos_given = TRUE;
180                     }
181                     g_free(s);
182                 }
183             }
184
185             settings->focus = -1;
186             if ((n = parse_find_node("focus", app->children)))
187                 settings->focus = parse_bool(doc, n);
188
189             if ((n = parse_find_node("desktop", app->children))) {
190                 gchar *s = parse_string(doc, n);
191                 if (!strcmp(s, "all"))
192                     settings->desktop = DESKTOP_ALL;
193                 else
194                     settings->desktop = parse_int(doc, n);
195                 g_free(s);
196             } else
197                 settings->desktop = DESKTOP_ALL - 1; /* lets hope the user
198                                                       * doesn't have 2^32
199                                                       * desktops */
200
201             if ((n = parse_find_node("head", app->children))) {
202                 gchar *s = parse_string(doc, n);
203                 if (!strcmp(s, "mouse"))
204                     settings->head = -1;
205                 else
206                     settings->head = parse_int(doc, n);
207                 g_free(s);
208             }
209
210             settings->layer = -2;
211             if ((n = parse_find_node("layer", app->children))) {
212                 gchar *s = parse_string(doc, n);
213                 if (!strcmp(s, "above"))
214                     settings->layer = 1;
215                 else if (!strcmp(s, "below"))
216                     settings->layer = -1;
217                 else
218                     settings->layer = 0;
219                 g_free(s);
220             }
221
222             settings->iconic = -1;
223             if ((n = parse_find_node("iconic", app->children)))
224                 settings->iconic = parse_bool(doc, n);
225
226             settings->skip_pager = -1;
227             if ((n = parse_find_node("skip_pager", app->children)))
228                 settings->skip_pager = parse_bool(doc, n);
229
230             settings->skip_taskbar = -1;
231             if ((n = parse_find_node("skip_taskbar", app->children)))
232                 settings->skip_taskbar = parse_bool(doc, n);
233
234             settings->fullscreen = -1;
235             if ((n = parse_find_node("fullscreen", app->children)))
236                 settings->fullscreen = parse_bool(doc, n);
237
238             settings->max_horz = -1;
239             settings->max_vert = -1;
240             if ((n = parse_find_node("maximized", app->children))) {
241                 gchar *s = parse_string(doc, n);
242                 if (!strcmp(s, "horizontal")) {
243                     settings->max_horz = TRUE;
244                     settings->max_vert = FALSE;
245                 } else if (!strcmp(s, "vertical")) {
246                     settings->max_horz = FALSE;
247                     settings->max_vert = TRUE;
248                 } else
249                     settings->max_horz = settings->max_vert =
250                         parse_bool(doc, n);
251                 g_free(s);
252             }
253
254             config_per_app_settings = g_slist_append(config_per_app_settings,
255                                               (gpointer) settings);
256         }
257         
258         app = parse_find_node("application", app->next);
259     }
260 }
261
262 /*
263
264 <keybind key="C-x">
265   <action name="ChangeDesktop">
266     <desktop>3</desktop>
267   </action>
268 </keybind>
269
270 */
271
272 static void parse_key(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
273                       GList *keylist)
274 {
275     gchar *key;
276     xmlNodePtr n;
277     gboolean is_chroot = FALSE;
278
279     if (!parse_attr_string("key", node, &key))
280         return;
281
282     parse_attr_bool("chroot", node, &is_chroot);
283
284     keylist = g_list_append(keylist, key);
285
286     /* a node either contains actions or key bindings */
287     if ((n = parse_find_node("keybind", node->children))) {
288         while (n) {
289             parse_key(i, doc, n, keylist);
290             n = parse_find_node("keybind", n->next);
291         }
292     } else if ((n = parse_find_node("action", node->children))) {
293         while (n) {
294             ObAction *action;
295             
296             action = action_parse(i, doc, n, OB_USER_ACTION_KEYBOARD_KEY);
297             if (action)
298                 keyboard_bind(keylist, action);
299             n = parse_find_node("action", n->next);
300         }
301     }
302
303     if (is_chroot)
304         keyboard_chroot(keylist);
305
306     g_free(key);
307     keylist = g_list_delete_link(keylist, g_list_last(keylist));
308 }
309
310 static void parse_keyboard(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
311                            gpointer d)
312 {
313     xmlNodePtr n;
314     gchar *key;
315
316     keyboard_unbind_all();
317
318     if ((n = parse_find_node("chainQuitKey", node->children))) {
319         key = parse_string(doc, n);
320         translate_key(key, &config_keyboard_reset_state,
321                       &config_keyboard_reset_keycode);
322         g_free(key);
323     }
324
325     if ((n = parse_find_node("keybind", node->children)))
326         while (n) {
327             parse_key(i, doc, n, NULL);
328             n = parse_find_node("keybind", n->next);
329         }
330 }
331
332 /*
333
334 <context name="Titlebar"> 
335   <mousebind button="Left" action="Press">
336     <action name="Raise"></action>
337   </mousebind>
338 </context>
339
340 */
341
342 static void parse_mouse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
343                         gpointer d)
344 {
345     xmlNodePtr n, nbut, nact;
346     gchar *buttonstr;
347     gchar *contextstr;
348     ObUserAction uact;
349     ObMouseAction mact;
350     ObAction *action;
351
352     mouse_unbind_all();
353
354     node = node->children;
355     
356     if ((n = parse_find_node("dragThreshold", node)))
357         config_mouse_threshold = parse_int(doc, n);
358     if ((n = parse_find_node("doubleClickTime", node)))
359         config_mouse_dclicktime = parse_int(doc, n);
360
361     n = parse_find_node("context", node);
362     while (n) {
363         if (!parse_attr_string("name", n, &contextstr))
364             goto next_n;
365         nbut = parse_find_node("mousebind", n->children);
366         while (nbut) {
367             if (!parse_attr_string("button", nbut, &buttonstr))
368                 goto next_nbut;
369             if (parse_attr_contains("press", nbut, "action")) {
370                 uact = OB_USER_ACTION_MOUSE_PRESS;
371                 mact = OB_MOUSE_ACTION_PRESS;
372             } else if (parse_attr_contains("release", nbut, "action")) {
373                 uact = OB_USER_ACTION_MOUSE_RELEASE;
374                 mact = OB_MOUSE_ACTION_RELEASE;
375             } else if (parse_attr_contains("click", nbut, "action")) {
376                 uact = OB_USER_ACTION_MOUSE_CLICK;
377                 mact = OB_MOUSE_ACTION_CLICK;
378             } else if (parse_attr_contains("doubleclick", nbut,"action")) {
379                 uact = OB_USER_ACTION_MOUSE_DOUBLE_CLICK;
380                 mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
381             } else if (parse_attr_contains("drag", nbut, "action")) {
382                 uact = OB_USER_ACTION_MOUSE_MOTION;
383                 mact = OB_MOUSE_ACTION_MOTION;
384             } else
385                 goto next_nbut;
386             nact = parse_find_node("action", nbut->children);
387             while (nact) {
388                 if ((action = action_parse(i, doc, nact, uact)))
389                     mouse_bind(buttonstr, contextstr, mact, action);
390                 nact = parse_find_node("action", nact->next);
391             }
392             g_free(buttonstr);
393         next_nbut:
394             nbut = parse_find_node("mousebind", nbut->next);
395         }
396         g_free(contextstr);
397     next_n:
398         n = parse_find_node("context", n->next);
399     }
400 }
401
402 static void parse_focus(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
403                         gpointer d)
404 {
405     xmlNodePtr n;
406
407     node = node->children;
408     
409     if ((n = parse_find_node("focusNew", node)))
410         config_focus_new = parse_bool(doc, n);
411     if ((n = parse_find_node("followMouse", node)))
412         config_focus_follow = parse_bool(doc, n);
413     if ((n = parse_find_node("focusDelay", node)))
414         config_focus_delay = parse_int(doc, n) * 1000;
415     if ((n = parse_find_node("raiseOnFocus", node)))
416         config_focus_raise = parse_bool(doc, n);
417     if ((n = parse_find_node("focusLast", node)))
418         config_focus_last = parse_bool(doc, n);
419 }
420
421 static void parse_placement(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
422                             gpointer d)
423 {
424     xmlNodePtr n;
425
426     node = node->children;
427     
428     if ((n = parse_find_node("policy", node)))
429         if (parse_contains("UnderMouse", doc, n))
430             config_place_policy = OB_PLACE_POLICY_MOUSE;
431 }
432
433 static void parse_theme(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
434                         gpointer d)
435 {
436     xmlNodePtr n;
437
438     node = node->children;
439
440     if ((n = parse_find_node("name", node))) {
441         gchar *c;
442
443         g_free(config_theme);
444         c = parse_string(doc, n);
445         config_theme = parse_expand_tilde(c);
446         g_free(c);
447     }
448     if ((n = parse_find_node("titleLayout", node))) {
449         g_free(config_title_layout);
450         config_title_layout = parse_string(doc, n);
451     }
452     if ((n = parse_find_node("keepBorder", node)))
453         config_theme_keepborder = parse_bool(doc, n);
454     if ((n = parse_find_node("hideDisabled", node)))
455         config_theme_hidedisabled = parse_bool(doc, n);
456
457     n = parse_find_node("font", node);
458     while (n) {
459         xmlNodePtr   fnode;
460         RrFont     **font;
461         gchar       *name = g_strdup(RrDefaultFontFamily);
462         gint         size = RrDefaultFontSize;
463         RrFontWeight weight = RrDefaultFontWeight;
464         RrFontSlant  slant = RrDefaultFontSlant;
465
466         if (parse_attr_contains("ActiveWindow", n, "place"))
467             font = &config_font_activewindow;
468         else if (parse_attr_contains("InactiveWindow", n, "place"))
469             font = &config_font_inactivewindow;
470         else if (parse_attr_contains("MenuTitle", n, "place"))
471             font = &config_font_menutitle;
472         else if (parse_attr_contains("MenuItem", n, "place"))
473             font = &config_font_menuitem;
474         else
475             goto next_font;
476
477         if ((fnode = parse_find_node("name", n->children))) {
478             g_free(name);
479             name = parse_string(doc, fnode);
480         }
481         if ((fnode = parse_find_node("size", n->children))) {
482             int s = parse_int(doc, fnode);
483             if (s > 0) size = s;
484         }
485         if ((fnode = parse_find_node("weight", n->children))) {
486             gchar *w = parse_string(doc, fnode);
487             if (!g_ascii_strcasecmp(w, "Bold"))
488                 weight = RR_FONTWEIGHT_BOLD;
489             g_free(w);
490         }
491         if ((fnode = parse_find_node("slant", n->children))) {
492             gchar *s = parse_string(doc, fnode);
493             if (!g_ascii_strcasecmp(s, "Italic"))
494                 slant = RR_FONTSLANT_ITALIC;
495             if (!g_ascii_strcasecmp(s, "Oblique"))
496                 slant = RR_FONTSLANT_OBLIQUE;
497             g_free(s);
498         }
499
500         *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
501         g_free(name);
502     next_font:
503         n = parse_find_node("font", n->next);
504     }
505 }
506
507 static void parse_desktops(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
508                            gpointer d)
509 {
510     xmlNodePtr n;
511
512     node = node->children;
513     
514     if ((n = parse_find_node("number", node))) {
515         gint d = parse_int(doc, n);
516         if (d > 0)
517             config_desktops_num = d;
518     }
519     if ((n = parse_find_node("firstdesk", node))) {
520         gint d = parse_int(doc, n);
521         if (d > 0)
522             config_screen_firstdesk = (unsigned) d;
523     }
524     if ((n = parse_find_node("names", node))) {
525         GSList *it;
526         xmlNodePtr nname;
527
528         for (it = config_desktops_names; it; it = it->next)
529             g_free(it->data);
530         g_slist_free(config_desktops_names);
531         config_desktops_names = NULL;
532
533         nname = parse_find_node("name", n->children);
534         while (nname) {
535             config_desktops_names = g_slist_append(config_desktops_names,
536                                                    parse_string(doc, nname));
537             nname = parse_find_node("name", nname->next);
538         }
539     }
540 }
541
542 static void parse_resize(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
543                          gpointer d)
544 {
545     xmlNodePtr n;
546
547     node = node->children;
548     
549     if ((n = parse_find_node("drawContents", node)))
550         config_resize_redraw = parse_bool(doc, n);
551     if ((n = parse_find_node("popupShow", node))) {
552         config_resize_popup_show = parse_int(doc, n);
553         if (parse_contains("Always", doc, n))
554             config_resize_popup_show = 2;
555         else if (parse_contains("Never", doc, n))
556             config_resize_popup_show = 0;
557         else if (parse_contains("Nonpixel", doc, n))
558             config_resize_popup_show = 1;
559     }
560     if ((n = parse_find_node("popupPosition", node))) {
561         config_resize_popup_pos = parse_int(doc, n);
562         if (parse_contains("Top", doc, n))
563             config_resize_popup_pos = 1;
564         else if (parse_contains("Center", doc, n))
565             config_resize_popup_pos = 0;
566     }
567 }
568
569 static void parse_dock(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
570                        gpointer d)
571 {
572     xmlNodePtr n;
573
574     node = node->children;
575
576     if ((n = parse_find_node("position", node))) {
577         if (parse_contains("TopLeft", doc, n))
578             config_dock_floating = FALSE,
579             config_dock_pos = OB_DIRECTION_NORTHWEST;
580         else if (parse_contains("Top", doc, n))
581             config_dock_floating = FALSE,
582             config_dock_pos = OB_DIRECTION_NORTH;
583         else if (parse_contains("TopRight", doc, n))
584             config_dock_floating = FALSE,
585             config_dock_pos = OB_DIRECTION_NORTHEAST;
586         else if (parse_contains("Right", doc, n))
587             config_dock_floating = FALSE,
588             config_dock_pos = OB_DIRECTION_EAST;
589         else if (parse_contains("BottomRight", doc, n))
590             config_dock_floating = FALSE,
591             config_dock_pos = OB_DIRECTION_SOUTHEAST;
592         else if (parse_contains("Bottom", doc, n))
593             config_dock_floating = FALSE,
594             config_dock_pos = OB_DIRECTION_SOUTH;
595         else if (parse_contains("BottomLeft", doc, n))
596             config_dock_floating = FALSE,
597             config_dock_pos = OB_DIRECTION_SOUTHWEST;
598         else if (parse_contains("Left", doc, n))
599             config_dock_floating = FALSE,
600             config_dock_pos = OB_DIRECTION_WEST;
601         else if (parse_contains("Floating", doc, n))
602             config_dock_floating = TRUE;
603     }
604     if (config_dock_floating) {
605         if ((n = parse_find_node("floatingX", node)))
606             config_dock_x = parse_int(doc, n);
607         if ((n = parse_find_node("floatingY", node)))
608             config_dock_y = parse_int(doc, n);
609     } else {
610         if ((n = parse_find_node("noStrut", node)))
611             config_dock_nostrut = parse_bool(doc, n);
612     }
613     if ((n = parse_find_node("stacking", node))) {
614         if (parse_contains("above", doc, n))
615             config_dock_layer = OB_STACKING_LAYER_ABOVE;
616         else if (parse_contains("normal", doc, n))
617             config_dock_layer = OB_STACKING_LAYER_NORMAL;
618         else if (parse_contains("below", doc, n))
619             config_dock_layer = OB_STACKING_LAYER_BELOW;
620     }
621     if ((n = parse_find_node("direction", node))) {
622         if (parse_contains("horizontal", doc, n))
623             config_dock_orient = OB_ORIENTATION_HORZ;
624         else if (parse_contains("vertical", doc, n))
625             config_dock_orient = OB_ORIENTATION_VERT;
626     }
627     if ((n = parse_find_node("autoHide", node)))
628         config_dock_hide = parse_bool(doc, n);
629     if ((n = parse_find_node("hideDelay", node)))
630         config_dock_hide_delay = parse_int(doc, n) * 1000;
631     if ((n = parse_find_node("showDelay", node)))
632         config_dock_show_delay = parse_int(doc, n) * 1000;
633     if ((n = parse_find_node("moveButton", node))) {
634         gchar *str = parse_string(doc, n);
635         guint b, s;
636         if (translate_button(str, &s, &b)) {
637             config_dock_app_move_button = b;
638             config_dock_app_move_modifiers = s;
639         } else {
640             g_message(_("Invalid button '%s' specified in config file"), str);
641         }
642         g_free(str);
643     }
644 }
645
646 static void parse_menu(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
647                        gpointer d)
648 {
649     xmlNodePtr n;
650     for (node = node->children; node; node = node->next) {
651         if (!xmlStrcasecmp(node->name, (const xmlChar*) "file")) {
652             gchar *c;
653
654             c = parse_string(doc, node);
655             config_menu_files = g_slist_append(config_menu_files,
656                                                parse_expand_tilde(c));
657             g_free(c);
658         }
659         if ((n = parse_find_node("warpPointer", node)))
660             config_menu_warppointer = parse_bool(doc, n);
661         if ((n = parse_find_node("hideDelay", node)))
662             config_menu_hide_delay = parse_int(doc, n);
663         if ((n = parse_find_node("middle", node)))
664             config_menu_middle = parse_bool(doc, n);
665         if ((n = parse_find_node("submenuShowDelay", node)))
666             config_submenu_show_delay = parse_int(doc, n);
667         if ((n = parse_find_node("desktopMenuIcons", node)))
668             config_menu_client_list_icons = parse_bool(doc, n);
669     }
670 }
671    
672 static void parse_resistance(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node, 
673                              gpointer d)
674 {
675     xmlNodePtr n;
676
677     node = node->children;
678     if ((n = parse_find_node("strength", node)))
679         config_resist_win = parse_int(doc, n);
680     if ((n = parse_find_node("screen_edge_strength", node)))
681         config_resist_edge = parse_int(doc, n);
682     if ((n = parse_find_node("edges_hit_layers_below", node)))
683         config_resist_layers_below = parse_bool(doc, n);
684 }
685
686 typedef struct
687 {
688     const gchar *key;
689     const gchar *actname;
690 } ObDefKeyBind;
691
692 static void bind_default_keyboard()
693 {
694     ObDefKeyBind *it;
695     ObDefKeyBind binds[] = {
696         { "A-Tab", "NextWindow" },
697         { "S-A-Tab", "PreviousWindow" },
698         { "A-F4", "Close" },
699         { NULL, NULL }
700     };
701
702     for (it = binds; it->key; ++it) {
703         GList *l = g_list_append(NULL, g_strdup(it->key));
704         keyboard_bind(l, action_from_string(it->actname,
705                                             OB_USER_ACTION_KEYBOARD_KEY));
706     }
707 }
708
709 typedef struct
710 {
711     const gchar *button;
712     const gchar *context;
713     const ObMouseAction mact;
714     const gchar *actname;
715 } ObDefMouseBind;
716
717 static void bind_default_mouse()
718 {
719     ObDefMouseBind *it;
720     ObDefMouseBind binds[] = {
721         { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
722         { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
723         { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
724         { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
725         { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
726         { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
727         { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
728         { "Left", "Handle", OB_MOUSE_ACTION_PRESS, "Focus" },
729         { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
730         { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
731         { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
732         { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
733         { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
734         { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
735         { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
736         { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
737         { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
738         { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
739         { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
740         { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
741         { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
742         { "Left", "Handle", OB_MOUSE_ACTION_CLICK, "Raise" },
743         { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
744         { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
745         { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
746         { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
747         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
748         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
749         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
750         { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
751         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
752         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
753         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
754         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximizeFull" },
755         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
756         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
757         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
758         { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
759         { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
760         { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
761         { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
762         { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
763         { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
764         { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
765         { NULL, NULL, 0, NULL }
766     };
767
768     for (it = binds; it->button; ++it) {
769         ObUserAction uact;
770         switch (it->mact) {
771         case OB_MOUSE_ACTION_PRESS:
772             uact = OB_USER_ACTION_MOUSE_PRESS; break;
773         case OB_MOUSE_ACTION_RELEASE:
774             uact = OB_USER_ACTION_MOUSE_RELEASE; break;
775         case OB_MOUSE_ACTION_CLICK:
776             uact = OB_USER_ACTION_MOUSE_CLICK; break;
777         case OB_MOUSE_ACTION_DOUBLE_CLICK:
778             uact = OB_USER_ACTION_MOUSE_DOUBLE_CLICK; break;
779         case OB_MOUSE_ACTION_MOTION:
780             uact = OB_USER_ACTION_MOUSE_MOTION; break;
781         default:
782             g_assert_not_reached();
783         }
784         mouse_bind(it->button, it->context, it->mact,
785                    action_from_string(it->actname, uact));
786     }
787 }
788
789 void config_startup(ObParseInst *i)
790 {
791     config_focus_new = TRUE;
792     config_focus_follow = FALSE;
793     config_focus_delay = 0;
794     config_focus_raise = FALSE;
795     config_focus_last = FALSE;
796
797     parse_register(i, "focus", parse_focus, NULL);
798
799     config_place_policy = OB_PLACE_POLICY_SMART;
800
801     parse_register(i, "placement", parse_placement, NULL);
802
803     config_theme = NULL;
804
805     config_title_layout = g_strdup("NLIMC");
806     config_theme_keepborder = TRUE;
807     config_theme_hidedisabled = FALSE;
808
809     config_font_activewindow = NULL;
810     config_font_inactivewindow = NULL;
811     config_font_menuitem = NULL;
812     config_font_menutitle = NULL;
813
814     parse_register(i, "theme", parse_theme, NULL);
815
816     config_desktops_num = 4;
817     config_screen_firstdesk = 1;
818     config_desktops_names = NULL;
819
820     parse_register(i, "desktops", parse_desktops, NULL);
821
822     config_resize_redraw = TRUE;
823     config_resize_four_corners = FALSE;
824     config_resize_popup_show = 1; /* nonpixel increments */
825     config_resize_popup_pos = 0;  /* center of client */
826
827     parse_register(i, "resize", parse_resize, NULL);
828
829     config_dock_layer = OB_STACKING_LAYER_ABOVE;
830     config_dock_pos = OB_DIRECTION_NORTHEAST;
831     config_dock_floating = FALSE;
832     config_dock_nostrut = FALSE;
833     config_dock_x = 0;
834     config_dock_y = 0;
835     config_dock_orient = OB_ORIENTATION_VERT;
836     config_dock_hide = FALSE;
837     config_dock_hide_delay = 300;
838     config_dock_show_delay = 300;
839     config_dock_app_move_button = 2; /* middle */
840     config_dock_app_move_modifiers = 0;
841
842     parse_register(i, "dock", parse_dock, NULL);
843
844     translate_key("C-g", &config_keyboard_reset_state,
845                   &config_keyboard_reset_keycode);
846
847     bind_default_keyboard();
848
849     parse_register(i, "keyboard", parse_keyboard, NULL);
850
851     config_mouse_threshold = 3;
852     config_mouse_dclicktime = 200;
853
854     bind_default_mouse();
855
856     parse_register(i, "mouse", parse_mouse, NULL);
857
858     config_resist_win = 10;
859     config_resist_edge = 20;
860     config_resist_layers_below = FALSE;
861
862     parse_register(i, "resistance", parse_resistance, NULL);
863
864     config_menu_warppointer = TRUE;
865     config_menu_hide_delay = 250;
866     config_menu_middle = FALSE;
867     config_submenu_show_delay = 0;
868     config_menu_client_list_icons = TRUE;
869     config_menu_files = NULL;
870
871     parse_register(i, "menu", parse_menu, NULL);
872
873     config_per_app_settings = NULL;
874
875     parse_register(i, "applications", parse_per_app_settings, NULL);
876 }
877
878 void config_shutdown()
879 {
880     GSList *it;
881
882     g_free(config_theme);
883
884     g_free(config_title_layout);
885
886     RrFontClose(config_font_activewindow);
887     RrFontClose(config_font_inactivewindow);
888     RrFontClose(config_font_menuitem);
889     RrFontClose(config_font_menutitle);
890
891     for (it = config_desktops_names; it; it = g_slist_next(it))
892         g_free(it->data);
893     g_slist_free(config_desktops_names);
894
895     for (it = config_menu_files; it; it = g_slist_next(it))
896         g_free(it->data);
897     g_slist_free(config_menu_files);
898
899     for (it = config_per_app_settings; it; it = g_slist_next(it)) {
900         ObAppSettings *itd = (ObAppSettings *)it->data;
901         g_free(itd->name);
902         g_free(itd->role);
903         g_free(itd->class);
904         g_free(it->data);
905     }
906     g_slist_free(config_per_app_settings);
907 }