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