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