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