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