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