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