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