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