]> icculus.org git repositories - mikachu/openbox.git/blob - openbox/config.c
lighten the default shadow, it's alittle harsh right now
[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        Ben 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
30 gboolean config_focus_new;
31 gboolean config_focus_follow;
32 guint    config_focus_delay;
33 gboolean config_focus_raise;
34 gboolean config_focus_last;
35
36 ObPlacePolicy config_place_policy;
37
38 gchar   *config_theme;
39 gboolean config_theme_keepborder;
40 gboolean config_theme_hidedisabled;
41
42 gchar   *config_title_layout;
43 gboolean config_title_number;
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 gboolean config_menu_xorstyle;
80 guint    config_menu_hide_delay;
81 gboolean config_menu_middle;
82 guint    config_submenu_show_delay;
83 gboolean config_menu_client_list_icons;
84
85 GSList *config_menu_files;
86
87 gint     config_resist_win;
88 gint     config_resist_edge;
89 gboolean config_resist_layers_below;
90
91 GSList *config_per_app_settings;
92
93 /*
94   <applications>
95     <application name="aterm">
96       <decor>false</decor>
97     </application>
98     <application name="Rhythmbox">
99       <layer>above</layer>
100       <position>
101         <x>700</x>
102         <y>0</y>
103       </position>
104       <head>1</head>
105     </application>
106   </applications>
107 */
108
109 /* Manages settings for individual applications.
110    Some notes: head is the screen number in a multi monitor
111    (Xinerama) setup (starting from 0) or mouse, meaning the
112    head the pointer is on. Default: mouse.
113    Layer can be three values, above (Always on top), below
114    (Always on bottom) and everything else (normal behaviour).
115    Positions can be an integer value or center, which will
116    center the window in the specified axis. Position is relative
117    from head, so <position><x>center</x></position><head>1</head>
118    will center the window on the second head.
119 */
120 static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
121                                    xmlNodePtr node, gpointer d)
122 {
123     xmlNodePtr app = parse_find_node("application", node->children);
124     gchar *name, *class;
125     gboolean name_set, class_set;
126     gboolean x_pos_given;
127
128     while (app) {
129         name_set = class_set = x_pos_given = FALSE;
130
131         class_set = parse_attr_string("class", app, &class);
132         name_set = parse_attr_string("name", app, &name);
133         if (class_set || name_set) {
134             xmlNodePtr n, c;
135             ObAppSettings *settings = g_new0(ObAppSettings, 1);
136             
137             if (name_set)
138                 settings->name = name;
139             else
140                 settings->name = NULL;
141
142             if (class_set)
143                 settings->class = class;
144             else
145                 settings->class = NULL;
146
147             if (!parse_attr_string("role", app, &settings->role))
148                 settings->role = NULL;
149
150             settings->decor = -1;
151             if ((n = parse_find_node("decor", app->children)))
152                 settings->decor = parse_bool(doc, n);
153
154             settings->shade = -1;
155             if ((n = parse_find_node("shade", app->children)))
156                 settings->shade = parse_bool(doc, n);
157
158             settings->position.x = settings->position.y = 0;
159             settings->pos_given = FALSE;
160             if ((n = parse_find_node("position", app->children))) {
161                 if ((c = parse_find_node("x", n->children))) {
162                     gchar *s = parse_string(doc, c);
163                     if (!strcmp(s, "center")) {
164                         settings->center_x = TRUE;
165                         x_pos_given = TRUE;
166                     } else {
167                         settings->position.x = parse_int(doc, c);
168                         x_pos_given = TRUE;
169                     }
170                     g_free(s);
171                 }
172
173                 if (x_pos_given && (c = parse_find_node("y", n->children))) {
174                     gchar *s = parse_string(doc, c);
175                     if (!strcmp(s, "center")) {
176                         settings->center_y = TRUE;
177                         settings->pos_given = TRUE;
178                     } else {
179                         settings->position.y = parse_int(doc, c);
180                         settings->pos_given = TRUE;
181                     }
182                     g_free(s);
183                 }
184             }
185
186             settings->focus = -1;
187             if ((n = parse_find_node("focus", app->children)))
188                 settings->focus = parse_bool(doc, n);
189
190             if ((n = parse_find_node("desktop", app->children))) {
191                 gchar *s = parse_string(doc, n);
192                 if (!strcmp(s, "all"))
193                     settings->desktop = DESKTOP_ALL;
194                 else
195                     settings->desktop = parse_int(doc, n);
196                 g_free(s);
197             } else
198                 settings->desktop = DESKTOP_ALL - 1; /* lets hope the user
199                                                       * doesn't have 2^32
200                                                       * desktops */
201
202             if ((n = parse_find_node("head", app->children))) {
203                 gchar *s = parse_string(doc, n);
204                 if (!strcmp(s, "mouse"))
205                     settings->head = -1;
206                 else
207                     settings->head = parse_int(doc, n);
208                 g_free(s);
209             }
210
211             settings->layer = -2;
212             if ((n = parse_find_node("layer", app->children))) {
213                 gchar *s = parse_string(doc, n);
214                 if (!strcmp(s, "above"))
215                     settings->layer = 1;
216                 else if (!strcmp(s, "below"))
217                     settings->layer = -1;
218                 else
219                     settings->layer = 0;
220                 g_free(s);
221             }
222
223             settings->iconic = -1;
224             if ((n = parse_find_node("iconic", app->children)))
225                 settings->iconic = parse_bool(doc, n);
226
227             settings->skip_pager = -1;
228             if ((n = parse_find_node("skip_pager", app->children)))
229                 settings->skip_pager = parse_bool(doc, n);
230
231             settings->skip_taskbar = -1;
232             if ((n = parse_find_node("skip_taskbar", app->children)))
233                 settings->skip_taskbar = parse_bool(doc, n);
234
235             settings->fullscreen = -1;
236             if ((n = parse_find_node("fullscreen", app->children)))
237                 settings->fullscreen = parse_bool(doc, n);
238
239             settings->max_horz = -1;
240             settings->max_vert = -1;
241             if ((n = parse_find_node("maximized", app->children))) {
242                 gchar *s = parse_string(doc, n);
243                 if (!strcmp(s, "horizontal")) {
244                     settings->max_horz = TRUE;
245                     settings->max_vert = FALSE;
246                 } else if (!strcmp(s, "vertical")) {
247                     settings->max_horz = FALSE;
248                     settings->max_vert = TRUE;
249                 } else
250                     settings->max_horz = settings->max_vert =
251                         parse_bool(doc, n);
252                 g_free(s);
253             }
254
255             config_per_app_settings = g_slist_append(config_per_app_settings,
256                                               (gpointer) settings);
257         }
258         
259         app = parse_find_node("application", app->next);
260     }
261 }
262
263 /*
264
265 <keybind key="C-x">
266   <action name="ChangeDesktop">
267     <desktop>3</desktop>
268   </action>
269 </keybind>
270
271 */
272
273 static void parse_key(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
274                       GList *keylist)
275 {
276     gchar *key;
277     ObAction *action;
278     xmlNodePtr n, nact;
279     GList *it;
280
281     if ((n = parse_find_node("chainQuitKey", node))) {
282         key = parse_string(doc, n);
283         translate_key(key, &config_keyboard_reset_state,
284                       &config_keyboard_reset_keycode);
285         g_free(key);
286     }
287
288     n = parse_find_node("keybind", node);
289     while (n) {
290         if (parse_attr_string("key", n, &key)) {
291             keylist = g_list_append(keylist, key);
292
293             parse_key(i, doc, n->children, keylist);
294
295             it = g_list_last(keylist);
296             g_free(it->data);
297             keylist = g_list_delete_link(keylist, it);
298         }
299         n = parse_find_node("keybind", n->next);
300     }
301     if (keylist) {
302         nact = parse_find_node("action", node);
303         while (nact) {
304             if ((action = action_parse(i, doc, nact,
305                                        OB_USER_ACTION_KEYBOARD_KEY)))
306                 keyboard_bind(keylist, action);
307             nact = parse_find_node("action", nact->next);
308         }
309     }
310 }
311
312 static void parse_keyboard(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
313                            gpointer d)
314 {
315     keyboard_unbind_all();
316
317     parse_key(i, doc, node->children, NULL);
318 }
319
320 /*
321
322 <context name="Titlebar"> 
323   <mousebind button="Left" action="Press">
324     <action name="Raise"></action>
325   </mousebind>
326 </context>
327
328 */
329
330 static void parse_mouse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
331                         gpointer d)
332 {
333     xmlNodePtr n, nbut, nact;
334     gchar *buttonstr;
335     gchar *contextstr;
336     ObUserAction uact;
337     ObMouseAction mact;
338     ObAction *action;
339
340     mouse_unbind_all();
341
342     node = node->children;
343     
344     if ((n = parse_find_node("dragThreshold", node)))
345         config_mouse_threshold = parse_int(doc, n);
346     if ((n = parse_find_node("doubleClickTime", node)))
347         config_mouse_dclicktime = parse_int(doc, n);
348
349     n = parse_find_node("context", node);
350     while (n) {
351         if (!parse_attr_string("name", n, &contextstr))
352             goto next_n;
353         nbut = parse_find_node("mousebind", n->children);
354         while (nbut) {
355             if (!parse_attr_string("button", nbut, &buttonstr))
356                 goto next_nbut;
357             if (parse_attr_contains("press", nbut, "action")) {
358                 uact = OB_USER_ACTION_MOUSE_PRESS;
359                 mact = OB_MOUSE_ACTION_PRESS;
360             } else if (parse_attr_contains("release", nbut, "action")) {
361                 uact = OB_USER_ACTION_MOUSE_RELEASE;
362                 mact = OB_MOUSE_ACTION_RELEASE;
363             } else if (parse_attr_contains("click", nbut, "action")) {
364                 uact = OB_USER_ACTION_MOUSE_CLICK;
365                 mact = OB_MOUSE_ACTION_CLICK;
366             } else if (parse_attr_contains("doubleclick", nbut,"action")) {
367                 uact = OB_USER_ACTION_MOUSE_DOUBLE_CLICK;
368                 mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
369             } else if (parse_attr_contains("drag", nbut, "action")) {
370                 uact = OB_USER_ACTION_MOUSE_MOTION;
371                 mact = OB_MOUSE_ACTION_MOTION;
372             } else
373                 goto next_nbut;
374             nact = parse_find_node("action", nbut->children);
375             while (nact) {
376                 if ((action = action_parse(i, doc, nact, uact)))
377                     mouse_bind(buttonstr, contextstr, mact, action);
378                 nact = parse_find_node("action", nact->next);
379             }
380             g_free(buttonstr);
381         next_nbut:
382             nbut = parse_find_node("mousebind", nbut->next);
383         }
384         g_free(contextstr);
385     next_n:
386         n = parse_find_node("context", n->next);
387     }
388 }
389
390 static void parse_focus(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
391                         gpointer d)
392 {
393     xmlNodePtr n;
394
395     node = node->children;
396     
397     if ((n = parse_find_node("focusNew", node)))
398         config_focus_new = parse_bool(doc, n);
399     if ((n = parse_find_node("followMouse", node)))
400         config_focus_follow = parse_bool(doc, n);
401     if ((n = parse_find_node("focusDelay", node)))
402         config_focus_delay = parse_int(doc, n) * 1000;
403     if ((n = parse_find_node("raiseOnFocus", node)))
404         config_focus_raise = parse_bool(doc, n);
405     if ((n = parse_find_node("focusLast", node)))
406         config_focus_last = parse_bool(doc, n);
407 }
408
409 static void parse_placement(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
410                             gpointer d)
411 {
412     xmlNodePtr n;
413
414     node = node->children;
415     
416     if ((n = parse_find_node("policy", node)))
417         if (parse_contains("UnderMouse", doc, n))
418             config_place_policy = OB_PLACE_POLICY_MOUSE;
419 }
420
421 static void parse_theme(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("name", node))) {
429         gchar *c;
430
431         g_free(config_theme);
432         c = parse_string(doc, n);
433         config_theme = parse_expand_tilde(c);
434         g_free(c);
435     }
436     if ((n = parse_find_node("titleLayout", node))) {
437         g_free(config_title_layout);
438         config_title_layout = parse_string(doc, n);
439     }
440     if ((n = parse_find_node("titleNumber", node)))
441         config_title_number = parse_bool(doc, n);
442     if ((n = parse_find_node("keepBorder", node)))
443         config_theme_keepborder = parse_bool(doc, n);
444     if ((n = parse_find_node("hideDisabled", node)))
445         config_theme_hidedisabled = parse_bool(doc, n);
446
447     n = parse_find_node("font", node);
448     while (n) {
449         xmlNodePtr   fnode;
450         RrFont     **font;
451         gchar       *name = g_strdup(RrDefaultFontFamily);
452         gint         size = RrDefaultFontSize;
453         RrFontWeight weight = RrDefaultFontWeight;
454         RrFontSlant  slant = RrDefaultFontSlant;
455         gboolean     shadow = RrDefaultFontShadow;
456         gint         offset = RrDefaultFontShadowOffset;
457         gchar        tint = RrDefaultFontShadowTint;
458
459         if (parse_attr_contains("ActiveWindow", n, "place"))
460             font = &config_font_activewindow;
461         else if (parse_attr_contains("InactiveWindow", n, "place"))
462             font = &config_font_inactivewindow;
463         else if (parse_attr_contains("MenuTitle", n, "place"))
464             font = &config_font_menutitle;
465         else if (parse_attr_contains("MenuItem", n, "place"))
466             font = &config_font_menuitem;
467         else
468             goto next_font;
469
470         if ((fnode = parse_find_node("name", n->children))) {
471             g_free(name);
472             name = parse_string(doc, fnode);
473         }
474         if ((fnode = parse_find_node("size", n->children))) {
475             int s = parse_int(doc, fnode);
476             if (s > 0) size = s;
477         }
478         if ((fnode = parse_find_node("weight", n->children))) {
479             gchar *w = parse_string(doc, fnode);
480             if (!g_ascii_strcasecmp(w, "Bold"))
481                 weight = RR_FONTWEIGHT_BOLD;
482             g_free(w);
483         }
484         if ((fnode = parse_find_node("slant", n->children))) {
485             gchar *s = parse_string(doc, fnode);
486             if (!g_ascii_strcasecmp(s, "Italic"))
487                 slant = RR_FONTSLANT_ITALIC;
488             if (!g_ascii_strcasecmp(s, "Oblique"))
489                 slant = RR_FONTSLANT_OBLIQUE;
490             g_free(s);
491         }
492         if ((fnode = parse_find_node("shadow", n->children)))
493             shadow = parse_bool(doc, fnode);
494         if ((fnode = parse_find_node("shadowoffset", n->children)))
495             offset = parse_int(doc, fnode);
496         if ((fnode = parse_find_node("shadowtint", n->children))) {
497             tint = parse_int(doc, fnode);
498             if (tint > 100) tint = 100;
499             else if (tint < -100) tint = -100;
500         }
501
502         *font = RrFontOpen(ob_rr_inst, name, size, weight, slant,
503                            shadow, offset, tint);
504         g_free(name);
505     next_font:
506         n = parse_find_node("font", n->next);
507     }
508 }
509
510 static void parse_desktops(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
511                            gpointer d)
512 {
513     xmlNodePtr n;
514
515     node = node->children;
516     
517     if ((n = parse_find_node("number", node))) {
518         gint d = parse_int(doc, n);
519         if (d > 0)
520             config_desktops_num = d;
521     }
522     if ((n = parse_find_node("firstdesk", node))) {
523         gint d = parse_int(doc, n);
524         if (d > 0)
525             config_screen_firstdesk = (unsigned) d;
526     }
527     if ((n = parse_find_node("names", node))) {
528         GSList *it;
529         xmlNodePtr nname;
530
531         for (it = config_desktops_names; it; it = it->next)
532             g_free(it->data);
533         g_slist_free(config_desktops_names);
534         config_desktops_names = NULL;
535
536         nname = parse_find_node("name", n->children);
537         while (nname) {
538             config_desktops_names = g_slist_append(config_desktops_names,
539                                                    parse_string(doc, nname));
540             nname = parse_find_node("name", nname->next);
541         }
542     }
543 }
544
545 static void parse_resize(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
546                          gpointer d)
547 {
548     xmlNodePtr n;
549
550     node = node->children;
551     
552     if ((n = parse_find_node("drawContents", node)))
553         config_resize_redraw = parse_bool(doc, n);
554     if ((n = parse_find_node("fourCorner", node)))
555         config_resize_four_corners = parse_bool(doc, n);
556     if ((n = parse_find_node("popupShow", node))) {
557         config_resize_popup_show = parse_int(doc, n);
558         if (parse_contains("Always", doc, n))
559             config_resize_popup_show = 2;
560         else if (parse_contains("Never", doc, n))
561             config_resize_popup_show = 0;
562         else if (parse_contains("Nonpixel", doc, n))
563             config_resize_popup_show = 1;
564     }
565     if ((n = parse_find_node("popupPosition", node))) {
566         config_resize_popup_pos = parse_int(doc, n);
567         if (parse_contains("Top", doc, n))
568             config_resize_popup_pos = 1;
569         else if (parse_contains("Center", doc, n))
570             config_resize_popup_pos = 0;
571     }
572 }
573
574 static void parse_dock(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
575                        gpointer d)
576 {
577     xmlNodePtr n;
578
579     node = node->children;
580
581     if ((n = parse_find_node("position", node))) {
582         if (parse_contains("TopLeft", doc, n))
583             config_dock_floating = FALSE,
584             config_dock_pos = OB_DIRECTION_NORTHWEST;
585         else if (parse_contains("Top", doc, n))
586             config_dock_floating = FALSE,
587             config_dock_pos = OB_DIRECTION_NORTH;
588         else if (parse_contains("TopRight", doc, n))
589             config_dock_floating = FALSE,
590             config_dock_pos = OB_DIRECTION_NORTHEAST;
591         else if (parse_contains("Right", doc, n))
592             config_dock_floating = FALSE,
593             config_dock_pos = OB_DIRECTION_EAST;
594         else if (parse_contains("BottomRight", doc, n))
595             config_dock_floating = FALSE,
596             config_dock_pos = OB_DIRECTION_SOUTHEAST;
597         else if (parse_contains("Bottom", doc, n))
598             config_dock_floating = FALSE,
599             config_dock_pos = OB_DIRECTION_SOUTH;
600         else if (parse_contains("BottomLeft", doc, n))
601             config_dock_floating = FALSE,
602             config_dock_pos = OB_DIRECTION_SOUTHWEST;
603         else if (parse_contains("Left", doc, n))
604             config_dock_floating = FALSE,
605             config_dock_pos = OB_DIRECTION_WEST;
606         else if (parse_contains("Floating", doc, n))
607             config_dock_floating = TRUE;
608     }
609     if (config_dock_floating) {
610         if ((n = parse_find_node("floatingX", node)))
611             config_dock_x = parse_int(doc, n);
612         if ((n = parse_find_node("floatingY", node)))
613             config_dock_y = parse_int(doc, n);
614     } else {
615         if ((n = parse_find_node("noStrut", node)))
616             config_dock_nostrut = parse_bool(doc, n);
617     }
618     if ((n = parse_find_node("stacking", node))) {
619         if (parse_contains("top", doc, n))
620             config_dock_layer = OB_STACKING_LAYER_ABOVE;
621         else if (parse_contains("normal", doc, n))
622             config_dock_layer = OB_STACKING_LAYER_NORMAL;
623         else if (parse_contains("bottom", doc, n))
624             config_dock_layer = OB_STACKING_LAYER_BELOW;
625     }
626     if ((n = parse_find_node("direction", node))) {
627         if (parse_contains("horizontal", doc, n))
628             config_dock_orient = OB_ORIENTATION_HORZ;
629         else if (parse_contains("vertical", doc, n))
630             config_dock_orient = OB_ORIENTATION_VERT;
631     }
632     if ((n = parse_find_node("autoHide", node)))
633         config_dock_hide = parse_bool(doc, n);
634     if ((n = parse_find_node("hideDelay", node)))
635         config_dock_hide_delay = parse_int(doc, n) * 1000;
636     if ((n = parse_find_node("showDelay", node)))
637         config_dock_show_delay = parse_int(doc, n) * 1000;
638     if ((n = parse_find_node("moveButton", node))) {
639         gchar *str = parse_string(doc, n);
640         guint b, s;
641         if (translate_button(str, &s, &b)) {
642             config_dock_app_move_button = b;
643             config_dock_app_move_modifiers = s;
644         } else {
645             g_warning("invalid button '%s'", str);
646         }
647         g_free(str);
648     }
649 }
650
651 static void parse_menu(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
652                        gpointer d)
653 {
654     xmlNodePtr n;
655     for (node = node->children; node; node = node->next) {
656         if (!xmlStrcasecmp(node->name, (const xmlChar*) "file")) {
657             gchar *c;
658
659             c = parse_string(doc, node);
660             config_menu_files = g_slist_append(config_menu_files,
661                                                parse_expand_tilde(c));
662             g_free(c);
663         }
664         if ((n = parse_find_node("warpPointer", node)))
665             config_menu_warppointer = parse_bool(doc, n);
666         if ((n = parse_find_node("xorStyle", node)))
667             config_menu_xorstyle = 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_title_layout = g_strdup("NLIMC");
813     config_title_number = TRUE;
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_xorstyle = TRUE;
874     config_menu_hide_delay = 250;
875     config_menu_middle = FALSE;
876     config_submenu_show_delay = 0;
877     config_menu_client_list_icons = TRUE;
878     config_menu_files = NULL;
879
880     parse_register(i, "menu", parse_menu, NULL);
881
882     config_per_app_settings = NULL;
883
884     parse_register(i, "applications", parse_per_app_settings, NULL);
885 }
886
887 void config_shutdown()
888 {
889     GSList *it;
890
891     g_free(config_theme);
892
893     g_free(config_title_layout);
894
895     RrFontClose(config_font_activewindow);
896     RrFontClose(config_font_inactivewindow);
897     RrFontClose(config_font_menuitem);
898     RrFontClose(config_font_menutitle);
899
900     for (it = config_desktops_names; it; it = g_slist_next(it))
901         g_free(it->data);
902     g_slist_free(config_desktops_names);
903
904     for (it = config_menu_files; it; it = g_slist_next(it))
905         g_free(it->data);
906     g_slist_free(config_menu_files);
907
908     for (it = config_per_app_settings; it; it = g_slist_next(it)) {
909         ObAppSettings *itd = (ObAppSettings *)it->data;
910         g_free(itd->name);
911         g_free(itd->role);
912         g_free(itd->class);
913         g_free(it->data);
914     }
915     g_slist_free(config_per_app_settings);
916 }