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