change the perapp settings "head" option to "monitor" i think its easier to understand.
[dana/openbox.git] / openbox / config.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    config.c for the Openbox window manager
4    Copyright (c) 2006        Mikael Magnusson
5    Copyright (c) 2003-2007   Dana Jansens
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "config.h"
21 #include "keyboard.h"
22 #include "mouse.h"
23 #include "prop.h"
24 #include "translate.h"
25 #include "client.h"
26 #include "screen.h"
27 #include "parser/parse.h"
28 #include "openbox.h"
29 #include "gettext.h"
30
31 gboolean config_focus_new;
32 gboolean config_focus_follow;
33 guint    config_focus_delay;
34 gboolean config_focus_raise;
35 gboolean config_focus_last;
36
37 ObPlacePolicy config_place_policy;
38
39 gchar   *config_theme;
40 gboolean config_theme_keepborder;
41 gboolean config_theme_hidedisabled;
42
43 gchar   *config_title_layout;
44
45 gboolean config_animate_iconify;
46
47 RrFont *config_font_activewindow;
48 RrFont *config_font_inactivewindow;
49 RrFont *config_font_menuitem;
50 RrFont *config_font_menutitle;
51 RrFont *config_font_osd;
52
53 gint    config_desktops_num;
54 GSList *config_desktops_names;
55 guint   config_screen_firstdesk;
56
57 gboolean config_resize_redraw;
58 gboolean config_resize_four_corners;
59 gint     config_resize_popup_show;
60 gint     config_resize_popup_pos;
61
62 ObStackingLayer config_dock_layer;
63 gboolean        config_dock_floating;
64 gboolean        config_dock_nostrut;
65 ObDirection     config_dock_pos;
66 gint            config_dock_x;
67 gint            config_dock_y;
68 ObOrientation   config_dock_orient;
69 gboolean        config_dock_hide;
70 guint           config_dock_hide_delay;
71 guint           config_dock_show_delay;
72 guint           config_dock_app_move_button;
73 guint           config_dock_app_move_modifiers;
74
75 guint config_keyboard_reset_keycode;
76 guint config_keyboard_reset_state;
77
78 gint config_mouse_threshold;
79 gint config_mouse_dclicktime;
80
81 gboolean config_menu_warppointer;
82 guint    config_menu_hide_delay;
83 gboolean config_menu_middle;
84 guint    config_submenu_show_delay;
85 gboolean config_menu_client_list_icons;
86
87 GSList *config_menu_files;
88
89 gint     config_resist_win;
90 gint     config_resist_edge;
91 gboolean config_resist_layers_below;
92
93 GSList *config_per_app_settings;
94
95 /*
96   <applications>
97     <application name="aterm">
98       <decor>false</decor>
99     </application>
100     <application name="Rhythmbox">
101       <layer>above</layer>
102       <position>
103         <x>700</x>
104         <y>0</y>
105         <monitor>1</monitor>
106       </position>
107       .. there is a lot more settings available
108     </application>
109   </applications>
110 */
111
112 /* Manages settings for individual applications.
113    Some notes: monitor is the screen number in a multi monitor
114    (Xinerama) setup (starting from 0) or mouse, meaning the
115    monitor the pointer is on. Default: mouse.
116    Layer can be three values, above (Always on top), below
117    (Always on bottom) and everything else (normal behaviour).
118    Positions can be an integer value or center, which will
119    center the window in the specified axis. Position is within
120    the monitor, so <position><x>center</x></position><monitor>2</monitor>
121    will center the window on the second monitor.
122 */
123 static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
124                                    xmlNodePtr node, gpointer d)
125 {
126     xmlNodePtr app = parse_find_node("application", node->children);
127     gchar *name, *class;
128     gboolean name_set, class_set;
129     gboolean x_pos_given;
130
131     while (app) {
132         name_set = class_set = x_pos_given = FALSE;
133
134         class_set = parse_attr_string("class", app, &class);
135         name_set = parse_attr_string("name", app, &name);
136         if (class_set || name_set) {
137             xmlNodePtr n, c;
138             ObAppSettings *settings = g_new0(ObAppSettings, 1);
139             
140             if (name_set)
141                 settings->name = name;
142             else
143                 settings->name = NULL;
144
145             if (class_set)
146                 settings->class = class;
147             else
148                 settings->class = NULL;
149
150             if (!parse_attr_string("role", app, &settings->role))
151                 settings->role = NULL;
152
153             settings->decor = -1;
154             if ((n = parse_find_node("decor", app->children)))
155                 if (!parse_contains("default", doc, n))
156                     settings->decor = parse_bool(doc, n);
157
158             settings->shade = -1;
159             if ((n = parse_find_node("shade", app->children)))
160                 if (!parse_contains("default", doc, n))
161                     settings->shade = parse_bool(doc, n);
162
163             settings->position.x = settings->position.y = 0;
164             settings->pos_given = FALSE;
165             if ((n = parse_find_node("position", app->children))) {
166                 if ((c = parse_find_node("x", n->children)))
167                     if (!parse_contains("default", doc, c)) {
168                         gchar *s = parse_string(doc, c);
169                         if (!strcmp(s, "center")) {
170                             settings->center_x = TRUE;
171                             x_pos_given = TRUE;
172                         } else {
173                             settings->position.x = parse_int(doc, c);
174                             x_pos_given = TRUE;
175                         }
176                         g_free(s);
177                     }
178
179                 if (x_pos_given && (c = parse_find_node("y", n->children)))
180                     if (!parse_contains("default", doc, c)) {
181                         gchar *s = parse_string(doc, c);
182                         if (!strcmp(s, "center")) {
183                             settings->center_y = TRUE;
184                             settings->pos_given = TRUE;
185                         } else {
186                             settings->position.y = parse_int(doc, c);
187                             settings->pos_given = TRUE;
188                         }
189                         g_free(s);
190                     }
191
192                 if (settings->pos_given &&
193                     (c = parse_find_node("monitor", n->children)))
194                     if (!parse_contains("default", doc, c)) {
195                         gchar *s = parse_string(doc, c);
196                         if (!strcmp(s, "mouse"))
197                             settings->monitor = 0;
198                         else
199                             settings->monitor = parse_int(doc, c) + 1;
200                         g_free(s);
201                     }
202             }
203
204             settings->focus = -1;
205             if ((n = parse_find_node("focus", app->children)))
206                 if (!parse_contains("default", doc, n))
207                     settings->focus = parse_bool(doc, n);
208
209             if ((n = parse_find_node("desktop", app->children))) {
210                 if (!parse_contains("default", doc, n)) {
211                     gchar *s = parse_string(doc, n);
212                     if (!strcmp(s, "all"))
213                         settings->desktop = DESKTOP_ALL;
214                     else {
215                         gint i = parse_int(doc, n);
216                         if (i > 0)
217                             settings->desktop = i;
218                     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         g_free(config_title_layout);
469         config_title_layout = parse_string(doc, n);
470     }
471     if ((n = parse_find_node("keepBorder", node)))
472         config_theme_keepborder = parse_bool(doc, n);
473     if ((n = parse_find_node("hideDisabled", node)))
474         config_theme_hidedisabled = parse_bool(doc, n);
475     if ((n = parse_find_node("animateIconify", node)))
476         config_animate_iconify = parse_bool(doc, n);
477
478     n = parse_find_node("font", node);
479     while (n) {
480         xmlNodePtr   fnode;
481         RrFont     **font;
482         gchar       *name = g_strdup(RrDefaultFontFamily);
483         gint         size = RrDefaultFontSize;
484         RrFontWeight weight = RrDefaultFontWeight;
485         RrFontSlant  slant = RrDefaultFontSlant;
486
487         if (parse_attr_contains("ActiveWindow", n, "place"))
488             font = &config_font_activewindow;
489         else if (parse_attr_contains("InactiveWindow", n, "place"))
490             font = &config_font_inactivewindow;
491         else if (parse_attr_contains("MenuHeader", n, "place"))
492             font = &config_font_menutitle;
493         else if (parse_attr_contains("MenuItem", n, "place"))
494             font = &config_font_menuitem;
495         else if (parse_attr_contains("OnScreenDisplay", n, "place"))
496             font = &config_font_osd;
497         else
498             goto next_font;
499
500         if ((fnode = parse_find_node("name", n->children))) {
501             g_free(name);
502             name = parse_string(doc, fnode);
503         }
504         if ((fnode = parse_find_node("size", n->children))) {
505             int s = parse_int(doc, fnode);
506             if (s > 0) size = s;
507         }
508         if ((fnode = parse_find_node("weight", n->children))) {
509             gchar *w = parse_string(doc, fnode);
510             if (!g_ascii_strcasecmp(w, "Bold"))
511                 weight = RR_FONTWEIGHT_BOLD;
512             g_free(w);
513         }
514         if ((fnode = parse_find_node("slant", n->children))) {
515             gchar *s = parse_string(doc, fnode);
516             if (!g_ascii_strcasecmp(s, "Italic"))
517                 slant = RR_FONTSLANT_ITALIC;
518             if (!g_ascii_strcasecmp(s, "Oblique"))
519                 slant = RR_FONTSLANT_OBLIQUE;
520             g_free(s);
521         }
522
523         *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
524         g_free(name);
525     next_font:
526         n = parse_find_node("font", n->next);
527     }
528 }
529
530 static void parse_desktops(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
531                            gpointer d)
532 {
533     xmlNodePtr n;
534
535     node = node->children;
536     
537     if ((n = parse_find_node("number", node))) {
538         gint d = parse_int(doc, n);
539         if (d > 0)
540             config_desktops_num = d;
541     }
542     if ((n = parse_find_node("firstdesk", node))) {
543         gint d = parse_int(doc, n);
544         if (d > 0)
545             config_screen_firstdesk = (unsigned) d;
546     }
547     if ((n = parse_find_node("names", node))) {
548         GSList *it;
549         xmlNodePtr nname;
550
551         for (it = config_desktops_names; it; it = it->next)
552             g_free(it->data);
553         g_slist_free(config_desktops_names);
554         config_desktops_names = NULL;
555
556         nname = parse_find_node("name", n->children);
557         while (nname) {
558             config_desktops_names = g_slist_append(config_desktops_names,
559                                                    parse_string(doc, nname));
560             nname = parse_find_node("name", nname->next);
561         }
562     }
563 }
564
565 static void parse_resize(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
566                          gpointer d)
567 {
568     xmlNodePtr n;
569
570     node = node->children;
571     
572     if ((n = parse_find_node("drawContents", node)))
573         config_resize_redraw = parse_bool(doc, n);
574     if ((n = parse_find_node("popupShow", node))) {
575         config_resize_popup_show = parse_int(doc, n);
576         if (parse_contains("Always", doc, n))
577             config_resize_popup_show = 2;
578         else if (parse_contains("Never", doc, n))
579             config_resize_popup_show = 0;
580         else if (parse_contains("Nonpixel", doc, n))
581             config_resize_popup_show = 1;
582     }
583     if ((n = parse_find_node("popupPosition", node))) {
584         config_resize_popup_pos = parse_int(doc, n);
585         if (parse_contains("Top", doc, n))
586             config_resize_popup_pos = 1;
587         else if (parse_contains("Center", doc, n))
588             config_resize_popup_pos = 0;
589     }
590 }
591
592 static void parse_dock(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
593                        gpointer d)
594 {
595     xmlNodePtr n;
596
597     node = node->children;
598
599     if ((n = parse_find_node("position", node))) {
600         if (parse_contains("TopLeft", doc, n))
601             config_dock_floating = FALSE,
602             config_dock_pos = OB_DIRECTION_NORTHWEST;
603         else if (parse_contains("Top", doc, n))
604             config_dock_floating = FALSE,
605             config_dock_pos = OB_DIRECTION_NORTH;
606         else if (parse_contains("TopRight", doc, n))
607             config_dock_floating = FALSE,
608             config_dock_pos = OB_DIRECTION_NORTHEAST;
609         else if (parse_contains("Right", doc, n))
610             config_dock_floating = FALSE,
611             config_dock_pos = OB_DIRECTION_EAST;
612         else if (parse_contains("BottomRight", doc, n))
613             config_dock_floating = FALSE,
614             config_dock_pos = OB_DIRECTION_SOUTHEAST;
615         else if (parse_contains("Bottom", doc, n))
616             config_dock_floating = FALSE,
617             config_dock_pos = OB_DIRECTION_SOUTH;
618         else if (parse_contains("BottomLeft", doc, n))
619             config_dock_floating = FALSE,
620             config_dock_pos = OB_DIRECTION_SOUTHWEST;
621         else if (parse_contains("Left", doc, n))
622             config_dock_floating = FALSE,
623             config_dock_pos = OB_DIRECTION_WEST;
624         else if (parse_contains("Floating", doc, n))
625             config_dock_floating = TRUE;
626     }
627     if (config_dock_floating) {
628         if ((n = parse_find_node("floatingX", node)))
629             config_dock_x = parse_int(doc, n);
630         if ((n = parse_find_node("floatingY", node)))
631             config_dock_y = parse_int(doc, n);
632     } else {
633         if ((n = parse_find_node("noStrut", node)))
634             config_dock_nostrut = parse_bool(doc, n);
635     }
636     if ((n = parse_find_node("stacking", node))) {
637         if (parse_contains("above", doc, n))
638             config_dock_layer = OB_STACKING_LAYER_ABOVE;
639         else if (parse_contains("normal", doc, n))
640             config_dock_layer = OB_STACKING_LAYER_NORMAL;
641         else if (parse_contains("below", doc, n))
642             config_dock_layer = OB_STACKING_LAYER_BELOW;
643     }
644     if ((n = parse_find_node("direction", node))) {
645         if (parse_contains("horizontal", doc, n))
646             config_dock_orient = OB_ORIENTATION_HORZ;
647         else if (parse_contains("vertical", doc, n))
648             config_dock_orient = OB_ORIENTATION_VERT;
649     }
650     if ((n = parse_find_node("autoHide", node)))
651         config_dock_hide = parse_bool(doc, n);
652     if ((n = parse_find_node("hideDelay", node)))
653         config_dock_hide_delay = parse_int(doc, n) * 1000;
654     if ((n = parse_find_node("showDelay", node)))
655         config_dock_show_delay = parse_int(doc, n) * 1000;
656     if ((n = parse_find_node("moveButton", node))) {
657         gchar *str = parse_string(doc, n);
658         guint b, s;
659         if (translate_button(str, &s, &b)) {
660             config_dock_app_move_button = b;
661             config_dock_app_move_modifiers = s;
662         } else {
663             g_message(_("Invalid button '%s' specified in config file"), str);
664         }
665         g_free(str);
666     }
667 }
668
669 static void parse_menu(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
670                        gpointer d)
671 {
672     xmlNodePtr n;
673     for (node = node->children; node; node = node->next) {
674         if (!xmlStrcasecmp(node->name, (const xmlChar*) "file")) {
675             gchar *c;
676
677             c = parse_string(doc, node);
678             config_menu_files = g_slist_append(config_menu_files,
679                                                parse_expand_tilde(c));
680             g_free(c);
681         }
682         if ((n = parse_find_node("hideDelay", node)))
683             config_menu_hide_delay = parse_int(doc, n);
684         if ((n = parse_find_node("middle", node)))
685             config_menu_middle = parse_bool(doc, n);
686         if ((n = parse_find_node("submenuShowDelay", node)))
687             config_submenu_show_delay = parse_int(doc, n);
688         if ((n = parse_find_node("applicationIcons", node)))
689             config_menu_client_list_icons = parse_bool(doc, n);
690     }
691 }
692    
693 static void parse_resistance(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node, 
694                              gpointer d)
695 {
696     xmlNodePtr n;
697
698     node = node->children;
699     if ((n = parse_find_node("strength", node)))
700         config_resist_win = parse_int(doc, n);
701     if ((n = parse_find_node("screen_edge_strength", node)))
702         config_resist_edge = parse_int(doc, n);
703     if ((n = parse_find_node("edges_hit_layers_below", node)))
704         config_resist_layers_below = parse_bool(doc, n);
705 }
706
707 typedef struct
708 {
709     const gchar *key;
710     const gchar *actname;
711 } ObDefKeyBind;
712
713 static void bind_default_keyboard()
714 {
715     ObDefKeyBind *it;
716     ObDefKeyBind binds[] = {
717         { "A-Tab", "NextWindow" },
718         { "S-A-Tab", "PreviousWindow" },
719         { "A-F4", "Close" },
720         { NULL, NULL }
721     };
722
723     for (it = binds; it->key; ++it) {
724         GList *l = g_list_append(NULL, g_strdup(it->key));
725         keyboard_bind(l, action_from_string(it->actname,
726                                             OB_USER_ACTION_KEYBOARD_KEY));
727     }
728 }
729
730 typedef struct
731 {
732     const gchar *button;
733     const gchar *context;
734     const ObMouseAction mact;
735     const gchar *actname;
736 } ObDefMouseBind;
737
738 static void bind_default_mouse()
739 {
740     ObDefMouseBind *it;
741     ObDefMouseBind binds[] = {
742         { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
743         { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
744         { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
745         { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
746         { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
747         { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
748         { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
749         { "Left", "Handle", OB_MOUSE_ACTION_PRESS, "Focus" },
750         { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
751         { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
752         { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
753         { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
754         { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
755         { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
756         { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
757         { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
758         { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
759         { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
760         { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
761         { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
762         { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
763         { "Left", "Handle", OB_MOUSE_ACTION_CLICK, "Raise" },
764         { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
765         { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
766         { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
767         { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
768         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
769         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
770         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
771         { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
772         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
773         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
774         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
775         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximizeFull" },
776         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
777         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
778         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
779         { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
780         { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
781         { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
782         { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
783         { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
784         { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
785         { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
786         { NULL, NULL, 0, NULL }
787     };
788
789     for (it = binds; it->button; ++it) {
790         ObUserAction uact;
791         switch (it->mact) {
792         case OB_MOUSE_ACTION_PRESS:
793             uact = OB_USER_ACTION_MOUSE_PRESS; break;
794         case OB_MOUSE_ACTION_RELEASE:
795             uact = OB_USER_ACTION_MOUSE_RELEASE; break;
796         case OB_MOUSE_ACTION_CLICK:
797             uact = OB_USER_ACTION_MOUSE_CLICK; break;
798         case OB_MOUSE_ACTION_DOUBLE_CLICK:
799             uact = OB_USER_ACTION_MOUSE_DOUBLE_CLICK; break;
800         case OB_MOUSE_ACTION_MOTION:
801             uact = OB_USER_ACTION_MOUSE_MOTION; break;
802         default:
803             g_assert_not_reached();
804         }
805         mouse_bind(it->button, it->context, it->mact,
806                    action_from_string(it->actname, uact));
807     }
808 }
809
810 void config_startup(ObParseInst *i)
811 {
812     config_focus_new = TRUE;
813     config_focus_follow = FALSE;
814     config_focus_delay = 0;
815     config_focus_raise = FALSE;
816     config_focus_last = FALSE;
817
818     parse_register(i, "focus", parse_focus, NULL);
819
820     config_place_policy = OB_PLACE_POLICY_SMART;
821
822     parse_register(i, "placement", parse_placement, NULL);
823
824     config_theme = NULL;
825
826     config_animate_iconify = TRUE;
827     config_title_layout = g_strdup("NLIMC");
828     config_theme_keepborder = TRUE;
829     config_theme_hidedisabled = FALSE;
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     config_resist_layers_below = FALSE;
883
884     parse_register(i, "resistance", parse_resistance, NULL);
885
886     config_menu_warppointer = TRUE;
887     config_menu_hide_delay = 250;
888     config_menu_middle = FALSE;
889     config_submenu_show_delay = 0;
890     config_menu_client_list_icons = TRUE;
891     config_menu_files = NULL;
892
893     parse_register(i, "menu", parse_menu, NULL);
894
895     config_per_app_settings = NULL;
896
897     parse_register(i, "applications", parse_per_app_settings, NULL);
898 }
899
900 void config_shutdown()
901 {
902     GSList *it;
903
904     g_free(config_theme);
905
906     g_free(config_title_layout);
907
908     RrFontClose(config_font_activewindow);
909     RrFontClose(config_font_inactivewindow);
910     RrFontClose(config_font_menuitem);
911     RrFontClose(config_font_menutitle);
912
913     for (it = config_desktops_names; it; it = g_slist_next(it))
914         g_free(it->data);
915     g_slist_free(config_desktops_names);
916
917     for (it = config_menu_files; it; it = g_slist_next(it))
918         g_free(it->data);
919     g_slist_free(config_menu_files);
920
921     for (it = config_per_app_settings; it; it = g_slist_next(it)) {
922         ObAppSettings *itd = (ObAppSettings *)it->data;
923         g_free(itd->name);
924         g_free(itd->role);
925         g_free(itd->class);
926         g_free(it->data);
927     }
928     g_slist_free(config_per_app_settings);
929 }