kill window title numbering...
[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        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
44 RrFont *config_font_activewindow;
45 RrFont *config_font_inactivewindow;
46 RrFont *config_font_menuitem;
47 RrFont *config_font_menutitle;
48
49 gint    config_desktops_num;
50 GSList *config_desktops_names;
51 guint   config_screen_firstdesk;
52
53 gboolean config_resize_redraw;
54 gboolean config_resize_four_corners;
55 gint     config_resize_popup_show;
56 gint     config_resize_popup_pos;
57
58 ObStackingLayer config_dock_layer;
59 gboolean        config_dock_floating;
60 gboolean        config_dock_nostrut;
61 ObDirection     config_dock_pos;
62 gint            config_dock_x;
63 gint            config_dock_y;
64 ObOrientation   config_dock_orient;
65 gboolean        config_dock_hide;
66 guint           config_dock_hide_delay;
67 guint           config_dock_show_delay;
68 guint           config_dock_app_move_button;
69 guint           config_dock_app_move_modifiers;
70
71 guint config_keyboard_reset_keycode;
72 guint config_keyboard_reset_state;
73
74 gint config_mouse_threshold;
75 gint config_mouse_dclicktime;
76
77 gboolean config_menu_warppointer;
78 gboolean config_menu_xorstyle;
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     ObAction *action;
277     xmlNodePtr n, nact;
278     GList *it;
279
280     if ((n = parse_find_node("chainQuitKey", node))) {
281         key = parse_string(doc, n);
282         translate_key(key, &config_keyboard_reset_state,
283                       &config_keyboard_reset_keycode);
284         g_free(key);
285     }
286
287     n = parse_find_node("keybind", node);
288     while (n) {
289         if (parse_attr_string("key", n, &key)) {
290             keylist = g_list_append(keylist, key);
291
292             parse_key(i, doc, n->children, keylist);
293
294             it = g_list_last(keylist);
295             g_free(it->data);
296             keylist = g_list_delete_link(keylist, it);
297         }
298         n = parse_find_node("keybind", n->next);
299     }
300     if (keylist) {
301         nact = parse_find_node("action", node);
302         while (nact) {
303             if ((action = action_parse(i, doc, nact,
304                                        OB_USER_ACTION_KEYBOARD_KEY)))
305                 keyboard_bind(keylist, action);
306             nact = parse_find_node("action", nact->next);
307         }
308     }
309 }
310
311 static void parse_keyboard(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
312                            gpointer d)
313 {
314     keyboard_unbind_all();
315
316     parse_key(i, doc, node->children, NULL);
317 }
318
319 /*
320
321 <context name="Titlebar"> 
322   <mousebind button="Left" action="Press">
323     <action name="Raise"></action>
324   </mousebind>
325 </context>
326
327 */
328
329 static void parse_mouse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
330                         gpointer d)
331 {
332     xmlNodePtr n, nbut, nact;
333     gchar *buttonstr;
334     gchar *contextstr;
335     ObUserAction uact;
336     ObMouseAction mact;
337     ObAction *action;
338
339     mouse_unbind_all();
340
341     node = node->children;
342     
343     if ((n = parse_find_node("dragThreshold", node)))
344         config_mouse_threshold = parse_int(doc, n);
345     if ((n = parse_find_node("doubleClickTime", node)))
346         config_mouse_dclicktime = parse_int(doc, n);
347
348     n = parse_find_node("context", node);
349     while (n) {
350         if (!parse_attr_string("name", n, &contextstr))
351             goto next_n;
352         nbut = parse_find_node("mousebind", n->children);
353         while (nbut) {
354             if (!parse_attr_string("button", nbut, &buttonstr))
355                 goto next_nbut;
356             if (parse_attr_contains("press", nbut, "action")) {
357                 uact = OB_USER_ACTION_MOUSE_PRESS;
358                 mact = OB_MOUSE_ACTION_PRESS;
359             } else if (parse_attr_contains("release", nbut, "action")) {
360                 uact = OB_USER_ACTION_MOUSE_RELEASE;
361                 mact = OB_MOUSE_ACTION_RELEASE;
362             } else if (parse_attr_contains("click", nbut, "action")) {
363                 uact = OB_USER_ACTION_MOUSE_CLICK;
364                 mact = OB_MOUSE_ACTION_CLICK;
365             } else if (parse_attr_contains("doubleclick", nbut,"action")) {
366                 uact = OB_USER_ACTION_MOUSE_DOUBLE_CLICK;
367                 mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
368             } else if (parse_attr_contains("drag", nbut, "action")) {
369                 uact = OB_USER_ACTION_MOUSE_MOTION;
370                 mact = OB_MOUSE_ACTION_MOTION;
371             } else
372                 goto next_nbut;
373             nact = parse_find_node("action", nbut->children);
374             while (nact) {
375                 if ((action = action_parse(i, doc, nact, uact)))
376                     mouse_bind(buttonstr, contextstr, mact, action);
377                 nact = parse_find_node("action", nact->next);
378             }
379             g_free(buttonstr);
380         next_nbut:
381             nbut = parse_find_node("mousebind", nbut->next);
382         }
383         g_free(contextstr);
384     next_n:
385         n = parse_find_node("context", n->next);
386     }
387 }
388
389 static void parse_focus(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
390                         gpointer d)
391 {
392     xmlNodePtr n;
393
394     node = node->children;
395     
396     if ((n = parse_find_node("focusNew", node)))
397         config_focus_new = parse_bool(doc, n);
398     if ((n = parse_find_node("followMouse", node)))
399         config_focus_follow = parse_bool(doc, n);
400     if ((n = parse_find_node("focusDelay", node)))
401         config_focus_delay = parse_int(doc, n) * 1000;
402     if ((n = parse_find_node("raiseOnFocus", node)))
403         config_focus_raise = parse_bool(doc, n);
404     if ((n = parse_find_node("focusLast", node)))
405         config_focus_last = parse_bool(doc, n);
406 }
407
408 static void parse_placement(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
409                             gpointer d)
410 {
411     xmlNodePtr n;
412
413     node = node->children;
414     
415     if ((n = parse_find_node("policy", node)))
416         if (parse_contains("UnderMouse", doc, n))
417             config_place_policy = OB_PLACE_POLICY_MOUSE;
418 }
419
420 static void parse_theme(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("name", node))) {
428         gchar *c;
429
430         g_free(config_theme);
431         c = parse_string(doc, n);
432         config_theme = parse_expand_tilde(c);
433         g_free(c);
434     }
435     if ((n = parse_find_node("titleLayout", node))) {
436         g_free(config_title_layout);
437         config_title_layout = parse_string(doc, n);
438     }
439     if ((n = parse_find_node("keepBorder", node)))
440         config_theme_keepborder = parse_bool(doc, n);
441     if ((n = parse_find_node("hideDisabled", node)))
442         config_theme_hidedisabled = parse_bool(doc, n);
443
444     n = parse_find_node("font", node);
445     while (n) {
446         xmlNodePtr   fnode;
447         RrFont     **font;
448         gchar       *name = g_strdup(RrDefaultFontFamily);
449         gint         size = RrDefaultFontSize;
450         RrFontWeight weight = RrDefaultFontWeight;
451         RrFontSlant  slant = RrDefaultFontSlant;
452
453         if (parse_attr_contains("ActiveWindow", n, "place"))
454             font = &config_font_activewindow;
455         else if (parse_attr_contains("InactiveWindow", n, "place"))
456             font = &config_font_inactivewindow;
457         else if (parse_attr_contains("MenuTitle", n, "place"))
458             font = &config_font_menutitle;
459         else if (parse_attr_contains("MenuItem", n, "place"))
460             font = &config_font_menuitem;
461         else
462             goto next_font;
463
464         if ((fnode = parse_find_node("name", n->children))) {
465             g_free(name);
466             name = parse_string(doc, fnode);
467         }
468         if ((fnode = parse_find_node("size", n->children))) {
469             int s = parse_int(doc, fnode);
470             if (s > 0) size = s;
471         }
472         if ((fnode = parse_find_node("weight", n->children))) {
473             gchar *w = parse_string(doc, fnode);
474             if (!g_ascii_strcasecmp(w, "Bold"))
475                 weight = RR_FONTWEIGHT_BOLD;
476             g_free(w);
477         }
478         if ((fnode = parse_find_node("slant", n->children))) {
479             gchar *s = parse_string(doc, fnode);
480             if (!g_ascii_strcasecmp(s, "Italic"))
481                 slant = RR_FONTSLANT_ITALIC;
482             if (!g_ascii_strcasecmp(s, "Oblique"))
483                 slant = RR_FONTSLANT_OBLIQUE;
484             g_free(s);
485         }
486
487         *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
488         g_free(name);
489     next_font:
490         n = parse_find_node("font", n->next);
491     }
492 }
493
494 static void parse_desktops(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
495                            gpointer d)
496 {
497     xmlNodePtr n;
498
499     node = node->children;
500     
501     if ((n = parse_find_node("number", node))) {
502         gint d = parse_int(doc, n);
503         if (d > 0)
504             config_desktops_num = d;
505     }
506     if ((n = parse_find_node("firstdesk", node))) {
507         gint d = parse_int(doc, n);
508         if (d > 0)
509             config_screen_firstdesk = (unsigned) d;
510     }
511     if ((n = parse_find_node("names", node))) {
512         GSList *it;
513         xmlNodePtr nname;
514
515         for (it = config_desktops_names; it; it = it->next)
516             g_free(it->data);
517         g_slist_free(config_desktops_names);
518         config_desktops_names = NULL;
519
520         nname = parse_find_node("name", n->children);
521         while (nname) {
522             config_desktops_names = g_slist_append(config_desktops_names,
523                                                    parse_string(doc, nname));
524             nname = parse_find_node("name", nname->next);
525         }
526     }
527 }
528
529 static void parse_resize(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
530                          gpointer d)
531 {
532     xmlNodePtr n;
533
534     node = node->children;
535     
536     if ((n = parse_find_node("drawContents", node)))
537         config_resize_redraw = parse_bool(doc, n);
538     if ((n = parse_find_node("fourCorner", node)))
539         config_resize_four_corners = parse_bool(doc, n);
540     if ((n = parse_find_node("popupShow", node))) {
541         config_resize_popup_show = parse_int(doc, n);
542         if (parse_contains("Always", doc, n))
543             config_resize_popup_show = 2;
544         else if (parse_contains("Never", doc, n))
545             config_resize_popup_show = 0;
546         else if (parse_contains("Nonpixel", doc, n))
547             config_resize_popup_show = 1;
548     }
549     if ((n = parse_find_node("popupPosition", node))) {
550         config_resize_popup_pos = parse_int(doc, n);
551         if (parse_contains("Top", doc, n))
552             config_resize_popup_pos = 1;
553         else if (parse_contains("Center", doc, n))
554             config_resize_popup_pos = 0;
555     }
556 }
557
558 static void parse_dock(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
559                        gpointer d)
560 {
561     xmlNodePtr n;
562
563     node = node->children;
564
565     if ((n = parse_find_node("position", node))) {
566         if (parse_contains("TopLeft", doc, n))
567             config_dock_floating = FALSE,
568             config_dock_pos = OB_DIRECTION_NORTHWEST;
569         else if (parse_contains("Top", doc, n))
570             config_dock_floating = FALSE,
571             config_dock_pos = OB_DIRECTION_NORTH;
572         else if (parse_contains("TopRight", doc, n))
573             config_dock_floating = FALSE,
574             config_dock_pos = OB_DIRECTION_NORTHEAST;
575         else if (parse_contains("Right", doc, n))
576             config_dock_floating = FALSE,
577             config_dock_pos = OB_DIRECTION_EAST;
578         else if (parse_contains("BottomRight", doc, n))
579             config_dock_floating = FALSE,
580             config_dock_pos = OB_DIRECTION_SOUTHEAST;
581         else if (parse_contains("Bottom", doc, n))
582             config_dock_floating = FALSE,
583             config_dock_pos = OB_DIRECTION_SOUTH;
584         else if (parse_contains("BottomLeft", doc, n))
585             config_dock_floating = FALSE,
586             config_dock_pos = OB_DIRECTION_SOUTHWEST;
587         else if (parse_contains("Left", doc, n))
588             config_dock_floating = FALSE,
589             config_dock_pos = OB_DIRECTION_WEST;
590         else if (parse_contains("Floating", doc, n))
591             config_dock_floating = TRUE;
592     }
593     if (config_dock_floating) {
594         if ((n = parse_find_node("floatingX", node)))
595             config_dock_x = parse_int(doc, n);
596         if ((n = parse_find_node("floatingY", node)))
597             config_dock_y = parse_int(doc, n);
598     } else {
599         if ((n = parse_find_node("noStrut", node)))
600             config_dock_nostrut = parse_bool(doc, n);
601     }
602     if ((n = parse_find_node("stacking", node))) {
603         if (parse_contains("top", doc, n))
604             config_dock_layer = OB_STACKING_LAYER_ABOVE;
605         else if (parse_contains("normal", doc, n))
606             config_dock_layer = OB_STACKING_LAYER_NORMAL;
607         else if (parse_contains("bottom", doc, n))
608             config_dock_layer = OB_STACKING_LAYER_BELOW;
609     }
610     if ((n = parse_find_node("direction", node))) {
611         if (parse_contains("horizontal", doc, n))
612             config_dock_orient = OB_ORIENTATION_HORZ;
613         else if (parse_contains("vertical", doc, n))
614             config_dock_orient = OB_ORIENTATION_VERT;
615     }
616     if ((n = parse_find_node("autoHide", node)))
617         config_dock_hide = parse_bool(doc, n);
618     if ((n = parse_find_node("hideDelay", node)))
619         config_dock_hide_delay = parse_int(doc, n) * 1000;
620     if ((n = parse_find_node("showDelay", node)))
621         config_dock_show_delay = parse_int(doc, n) * 1000;
622     if ((n = parse_find_node("moveButton", node))) {
623         gchar *str = parse_string(doc, n);
624         guint b, s;
625         if (translate_button(str, &s, &b)) {
626             config_dock_app_move_button = b;
627             config_dock_app_move_modifiers = s;
628         } else {
629             g_warning("invalid button '%s'", str);
630         }
631         g_free(str);
632     }
633 }
634
635 static void parse_menu(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
636                        gpointer d)
637 {
638     xmlNodePtr n;
639     for (node = node->children; node; node = node->next) {
640         if (!xmlStrcasecmp(node->name, (const xmlChar*) "file")) {
641             gchar *c;
642
643             c = parse_string(doc, node);
644             config_menu_files = g_slist_append(config_menu_files,
645                                                parse_expand_tilde(c));
646             g_free(c);
647         }
648         if ((n = parse_find_node("warpPointer", node)))
649             config_menu_warppointer = parse_bool(doc, n);
650         if ((n = parse_find_node("xorStyle", node)))
651             config_menu_xorstyle = parse_bool(doc, n);
652         if ((n = parse_find_node("hideDelay", node)))
653             config_menu_hide_delay = parse_int(doc, n);
654         if ((n = parse_find_node("middle", node)))
655             config_menu_middle = parse_bool(doc, n);
656         if ((n = parse_find_node("submenuShowDelay", node)))
657             config_submenu_show_delay = parse_int(doc, n);
658         if ((n = parse_find_node("desktopMenuIcons", node)))
659             config_menu_client_list_icons = parse_bool(doc, n);
660     }
661 }
662    
663 static void parse_resistance(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node, 
664                              gpointer d)
665 {
666     xmlNodePtr n;
667
668     node = node->children;
669     if ((n = parse_find_node("strength", node)))
670         config_resist_win = parse_int(doc, n);
671     if ((n = parse_find_node("screen_edge_strength", node)))
672         config_resist_edge = parse_int(doc, n);
673     if ((n = parse_find_node("edges_hit_layers_below", node)))
674         config_resist_layers_below = parse_bool(doc, n);
675 }
676
677 typedef struct
678 {
679     const gchar *key;
680     const gchar *actname;
681 } ObDefKeyBind;
682
683 static void bind_default_keyboard()
684 {
685     ObDefKeyBind *it;
686     ObDefKeyBind binds[] = {
687         { "A-Tab", "NextWindow" },
688         { "S-A-Tab", "PreviousWindow" },
689         { "A-F4", "Close" },
690         { NULL, NULL }
691     };
692
693     for (it = binds; it->key; ++it) {
694         GList *l = g_list_append(NULL, g_strdup(it->key));
695         keyboard_bind(l, action_from_string(it->actname,
696                                             OB_USER_ACTION_KEYBOARD_KEY));
697     }
698 }
699
700 typedef struct
701 {
702     const gchar *button;
703     const gchar *context;
704     const ObMouseAction mact;
705     const gchar *actname;
706 } ObDefMouseBind;
707
708 static void bind_default_mouse()
709 {
710     ObDefMouseBind *it;
711     ObDefMouseBind binds[] = {
712         { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
713         { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
714         { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
715         { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
716         { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
717         { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
718         { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
719         { "Left", "Handle", OB_MOUSE_ACTION_PRESS, "Focus" },
720         { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
721         { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
722         { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
723         { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
724         { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
725         { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
726         { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
727         { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
728         { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
729         { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
730         { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
731         { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
732         { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
733         { "Left", "Handle", OB_MOUSE_ACTION_CLICK, "Raise" },
734         { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
735         { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
736         { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
737         { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
738         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
739         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
740         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
741         { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
742         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
743         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
744         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
745         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximizeFull" },
746         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
747         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
748         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
749         { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
750         { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
751         { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
752         { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
753         { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
754         { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
755         { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
756         { NULL, NULL, 0, NULL }
757     };
758
759     for (it = binds; it->button; ++it) {
760         ObUserAction uact;
761         switch (it->mact) {
762         case OB_MOUSE_ACTION_PRESS:
763             uact = OB_USER_ACTION_MOUSE_PRESS; break;
764         case OB_MOUSE_ACTION_RELEASE:
765             uact = OB_USER_ACTION_MOUSE_RELEASE; break;
766         case OB_MOUSE_ACTION_CLICK:
767             uact = OB_USER_ACTION_MOUSE_CLICK; break;
768         case OB_MOUSE_ACTION_DOUBLE_CLICK:
769             uact = OB_USER_ACTION_MOUSE_DOUBLE_CLICK; break;
770         case OB_MOUSE_ACTION_MOTION:
771             uact = OB_USER_ACTION_MOUSE_MOTION; break;
772         default:
773             g_assert_not_reached();
774         }
775         mouse_bind(it->button, it->context, it->mact,
776                    action_from_string(it->actname, uact));
777     }
778 }
779
780 void config_startup(ObParseInst *i)
781 {
782     config_focus_new = TRUE;
783     config_focus_follow = FALSE;
784     config_focus_delay = 0;
785     config_focus_raise = FALSE;
786     config_focus_last = FALSE;
787
788     parse_register(i, "focus", parse_focus, NULL);
789
790     config_place_policy = OB_PLACE_POLICY_SMART;
791
792     parse_register(i, "placement", parse_placement, NULL);
793
794     config_theme = NULL;
795
796     config_title_layout = g_strdup("NLIMC");
797     config_theme_keepborder = TRUE;
798     config_theme_hidedisabled = FALSE;
799
800     config_font_activewindow = NULL;
801     config_font_inactivewindow = NULL;
802     config_font_menuitem = NULL;
803     config_font_menutitle = NULL;
804
805     parse_register(i, "theme", parse_theme, NULL);
806
807     config_desktops_num = 4;
808     config_screen_firstdesk = 1;
809     config_desktops_names = NULL;
810
811     parse_register(i, "desktops", parse_desktops, NULL);
812
813     config_resize_redraw = TRUE;
814     config_resize_four_corners = FALSE;
815     config_resize_popup_show = 1; /* nonpixel increments */
816     config_resize_popup_pos = 0;  /* center of client */
817
818     parse_register(i, "resize", parse_resize, NULL);
819
820     config_dock_layer = OB_STACKING_LAYER_ABOVE;
821     config_dock_pos = OB_DIRECTION_NORTHEAST;
822     config_dock_floating = FALSE;
823     config_dock_nostrut = FALSE;
824     config_dock_x = 0;
825     config_dock_y = 0;
826     config_dock_orient = OB_ORIENTATION_VERT;
827     config_dock_hide = FALSE;
828     config_dock_hide_delay = 300;
829     config_dock_show_delay = 300;
830     config_dock_app_move_button = 2; /* middle */
831     config_dock_app_move_modifiers = 0;
832
833     parse_register(i, "dock", parse_dock, NULL);
834
835     translate_key("C-g", &config_keyboard_reset_state,
836                   &config_keyboard_reset_keycode);
837
838     bind_default_keyboard();
839
840     parse_register(i, "keyboard", parse_keyboard, NULL);
841
842     config_mouse_threshold = 3;
843     config_mouse_dclicktime = 200;
844
845     bind_default_mouse();
846
847     parse_register(i, "mouse", parse_mouse, NULL);
848
849     config_resist_win = 10;
850     config_resist_edge = 20;
851     config_resist_layers_below = FALSE;
852
853     parse_register(i, "resistance", parse_resistance, NULL);
854
855     config_menu_warppointer = TRUE;
856     config_menu_xorstyle = TRUE;
857     config_menu_hide_delay = 250;
858     config_menu_middle = FALSE;
859     config_submenu_show_delay = 0;
860     config_menu_client_list_icons = TRUE;
861     config_menu_files = NULL;
862
863     parse_register(i, "menu", parse_menu, NULL);
864
865     config_per_app_settings = NULL;
866
867     parse_register(i, "applications", parse_per_app_settings, NULL);
868 }
869
870 void config_shutdown()
871 {
872     GSList *it;
873
874     g_free(config_theme);
875
876     g_free(config_title_layout);
877
878     RrFontClose(config_font_activewindow);
879     RrFontClose(config_font_inactivewindow);
880     RrFontClose(config_font_menuitem);
881     RrFontClose(config_font_menutitle);
882
883     for (it = config_desktops_names; it; it = g_slist_next(it))
884         g_free(it->data);
885     g_slist_free(config_desktops_names);
886
887     for (it = config_menu_files; it; it = g_slist_next(it))
888         g_free(it->data);
889     g_slist_free(config_menu_files);
890
891     for (it = config_per_app_settings; it; it = g_slist_next(it)) {
892         ObAppSettings *itd = (ObAppSettings *)it->data;
893         g_free(itd->name);
894         g_free(itd->role);
895         g_free(itd->class);
896         g_free(it->data);
897     }
898     g_slist_free(config_per_app_settings);
899 }