per app settings
[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) 2004        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 "parser/parse.h"
26 #include "openbox.h"
27
28 gboolean config_focus_new;
29 gboolean config_focus_follow;
30 guint    config_focus_delay;
31 gboolean config_focus_raise;
32 gboolean config_focus_last;
33
34 ObPlacePolicy config_place_policy;
35
36 gchar   *config_theme;
37 gboolean config_theme_keepborder;
38 gboolean config_theme_hidedisabled;
39
40 gchar *config_title_layout;
41
42 gint    config_desktops_num;
43 GSList *config_desktops_names;
44 gint    config_screen_firstdesk;
45
46 gboolean config_resize_redraw;
47 gboolean config_resize_four_corners;
48 gint     config_resize_popup_show;
49 gint     config_resize_popup_pos;
50
51 ObStackingLayer config_dock_layer;
52 gboolean        config_dock_floating;
53 gboolean        config_dock_nostrut;
54 ObDirection     config_dock_pos;
55 gint            config_dock_x;
56 gint            config_dock_y;
57 ObOrientation   config_dock_orient;
58 gboolean        config_dock_hide;
59 guint           config_dock_hide_delay;
60 guint           config_dock_show_delay;
61 guint           config_dock_app_move_button;
62 guint           config_dock_app_move_modifiers;
63
64 guint config_keyboard_reset_keycode;
65 guint config_keyboard_reset_state;
66
67 gint config_mouse_threshold;
68 gint config_mouse_dclicktime;
69
70 gboolean config_menu_warppointer;
71 gboolean config_menu_xorstyle;
72 guint    config_menu_hide_delay;
73 guint    config_submenu_show_delay;
74 gboolean config_menu_client_list_icons;
75
76 GSList *config_menu_files;
77
78 gint config_resist_win;
79 gint config_resist_edge;
80
81 gboolean config_resist_layers_below;
82
83 GSList *per_app_settings;
84
85 /*
86   <applications>
87     <application name="aterm">
88       <decor>false</decor>
89     </application>
90     <application name="Rhythmbox">
91       <layer>above</layer>
92       <position>
93         <x>700</x>
94         <y>0</y>
95       </position>
96       <head>1</head>
97     </application>
98   </applications>
99 */
100
101 /* Manages settings for individual applications.
102    Some notes: head is the screen number in a multi monitor
103    (Xinerama) setup (starting from 0) or mouse, meaning the
104    head the pointer is on. Default: mouse.
105    If decor is false and shade is true, the decor will be
106    set to true (otherwise we will have an invisible window).
107    Layer can be three values, above (Always on top), below
108    (Always on bottom) and everything else (normal behaviour).
109    Positions can be an integer value or center, which will
110    center the window in the specified axis. Position is relative
111    from head, so <position><x>center</x></position><head>1</head>
112    will center the window on the second head.
113 */
114 static void parse_per_app_settings(ObParseInst *i, xmlDocPtr doc,
115                                    xmlNodePtr node, gpointer d)
116 {
117     xmlNodePtr app = parse_find_node("application", node->children);
118     gchar *name;
119
120
121     while (app) {
122         if (parse_attr_string("name", app, &name)) {
123             xmlNodePtr n, c;
124             ObAppSetting *setting = g_new0(ObAppSetting, 1);
125             setting->name = name;
126
127             setting->decor = TRUE;
128             if ((n = parse_find_node("decor", app->children)))
129                 setting->decor = parse_bool(doc, n);
130
131             if ((n = parse_find_node("shade", app->children)))
132                 setting->shade = parse_bool(doc, n);
133
134             setting->position.x = setting->position.y = -1;
135             if ((n = parse_find_node("position", app->children))) {
136                 if ((c = parse_find_node("x", n->children))) {
137                     if (!strcmp(parse_string(doc, c), "center")) {
138                         setting->center_x = TRUE;
139                     }
140                     else
141                         setting->position.x = parse_int(doc, c);
142                 }
143
144                 if ((c = parse_find_node("y", n->children))) {
145                     if (!strcmp(parse_string(doc, c), "center")) {
146                         setting->center_y = TRUE;
147                     }
148                     else
149                         setting->position.y = parse_int(doc, c);
150                 }
151             }
152
153             if ((n = parse_find_node("focus", app->children)))
154                 setting->focus = parse_bool(doc, n);
155
156             if ((n = parse_find_node("desktop", app->children)))
157                 setting->desktop = parse_int(doc, n);
158             else
159                 setting->desktop = -1;
160
161             if ((n = parse_find_node("head", app->children))) {
162                 if (!strcmp(parse_string(doc, n), "mouse"))
163                     setting->head = -1;
164                 else
165                     setting->head = parse_int(doc, n);
166             }
167
168             if ((n = parse_find_node("layer", app->children))) {
169                 if (!strcmp(parse_string(doc, n), "above"))
170                     setting->layer = 1;
171                 else if (!strcmp(parse_string(doc, n), "below"))
172                     setting->layer = -1;
173                 else
174                     setting->layer = 0;
175             }
176
177             per_app_settings = g_slist_append(per_app_settings,
178                                               (gpointer) setting);
179         }
180         
181         app = parse_find_node("application", app->next);
182     }
183 }
184
185 /*
186
187 <keybind key="C-x">
188   <action name="ChangeDesktop">
189     <desktop>3</desktop>
190   </action>
191 </keybind>
192
193 */
194
195 static void parse_key(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
196                       GList *keylist)
197 {
198     gchar *key;
199     ObAction *action;
200     xmlNodePtr n, nact;
201     GList *it;
202
203     if ((n = parse_find_node("chainQuitKey", node))) {
204         key = parse_string(doc, n);
205         translate_key(key, &config_keyboard_reset_state,
206                       &config_keyboard_reset_keycode);
207         g_free(key);
208     }
209
210     n = parse_find_node("keybind", node);
211     while (n) {
212         if (parse_attr_string("key", n, &key)) {
213             keylist = g_list_append(keylist, key);
214
215             parse_key(i, doc, n->children, keylist);
216
217             it = g_list_last(keylist);
218             g_free(it->data);
219             keylist = g_list_delete_link(keylist, it);
220         }
221         n = parse_find_node("keybind", n->next);
222     }
223     if (keylist) {
224         nact = parse_find_node("action", node);
225         while (nact) {
226             if ((action = action_parse(i, doc, nact,
227                                        OB_USER_ACTION_KEYBOARD_KEY)))
228                 keyboard_bind(keylist, action);
229             nact = parse_find_node("action", nact->next);
230         }
231     }
232 }
233
234 static void parse_keyboard(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
235                            gpointer d)
236 {
237     keyboard_unbind_all();
238
239     parse_key(i, doc, node->children, NULL);
240 }
241
242 /*
243
244 <context name="Titlebar"> 
245   <mousebind button="Left" action="Press">
246     <action name="Raise"></action>
247   </mousebind>
248 </context>
249
250 */
251
252 static void parse_mouse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
253                         gpointer d)
254 {
255     xmlNodePtr n, nbut, nact;
256     gchar *buttonstr;
257     gchar *contextstr;
258     ObUserAction uact;
259     ObMouseAction mact;
260     ObAction *action;
261
262     mouse_unbind_all();
263
264     node = node->children;
265     
266     if ((n = parse_find_node("dragThreshold", node)))
267         config_mouse_threshold = parse_int(doc, n);
268     if ((n = parse_find_node("doubleClickTime", node)))
269         config_mouse_dclicktime = parse_int(doc, n);
270
271     n = parse_find_node("context", node);
272     while (n) {
273         if (!parse_attr_string("name", n, &contextstr))
274             goto next_n;
275         nbut = parse_find_node("mousebind", n->children);
276         while (nbut) {
277             if (!parse_attr_string("button", nbut, &buttonstr))
278                 goto next_nbut;
279             if (parse_attr_contains("press", nbut, "action")) {
280                 uact = OB_USER_ACTION_MOUSE_PRESS;
281                 mact = OB_MOUSE_ACTION_PRESS;
282             } else if (parse_attr_contains("release", nbut, "action")) {
283                 uact = OB_USER_ACTION_MOUSE_RELEASE;
284                 mact = OB_MOUSE_ACTION_RELEASE;
285             } else if (parse_attr_contains("click", nbut, "action")) {
286                 uact = OB_USER_ACTION_MOUSE_CLICK;
287                 mact = OB_MOUSE_ACTION_CLICK;
288             } else if (parse_attr_contains("doubleclick", nbut,"action")) {
289                 uact = OB_USER_ACTION_MOUSE_DOUBLE_CLICK;
290                 mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
291             } else if (parse_attr_contains("drag", nbut, "action")) {
292                 uact = OB_USER_ACTION_MOUSE_MOTION;
293                 mact = OB_MOUSE_ACTION_MOTION;
294             } else
295                 goto next_nbut;
296             nact = parse_find_node("action", nbut->children);
297             while (nact) {
298                 if ((action = action_parse(i, doc, nact, uact)))
299                     mouse_bind(buttonstr, contextstr, mact, action);
300                 nact = parse_find_node("action", nact->next);
301             }
302             g_free(buttonstr);
303         next_nbut:
304             nbut = parse_find_node("mousebind", nbut->next);
305         }
306         g_free(contextstr);
307     next_n:
308         n = parse_find_node("context", n->next);
309     }
310 }
311
312 static void parse_focus(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
313                         gpointer d)
314 {
315     xmlNodePtr n;
316
317     node = node->children;
318     
319     if ((n = parse_find_node("focusNew", node)))
320         config_focus_new = parse_bool(doc, n);
321     if ((n = parse_find_node("followMouse", node)))
322         config_focus_follow = parse_bool(doc, n);
323     if ((n = parse_find_node("focusDelay", node)))
324         config_focus_delay = parse_int(doc, n) * 1000;
325     if ((n = parse_find_node("raiseOnFocus", node)))
326         config_focus_raise = parse_bool(doc, n);
327     if ((n = parse_find_node("focusLast", node)))
328         config_focus_last = parse_bool(doc, n);
329 }
330
331 static void parse_placement(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
332                             gpointer d)
333 {
334     xmlNodePtr n;
335
336     node = node->children;
337     
338     if ((n = parse_find_node("policy", node)))
339         if (parse_contains("UnderMouse", doc, n))
340             config_place_policy = OB_PLACE_POLICY_MOUSE;
341 }
342
343 static void parse_theme(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
344                         gpointer d)
345 {
346     xmlNodePtr n;
347
348     node = node->children;
349
350     if ((n = parse_find_node("name", node))) {
351         gchar *c;
352
353         g_free(config_theme);
354         c = parse_string(doc, n);
355         config_theme = parse_expand_tilde(c);
356         g_free(c);
357     }
358     if ((n = parse_find_node("titleLayout", node))) {
359         g_free(config_title_layout);
360         config_title_layout = parse_string(doc, n);
361     }
362     if ((n = parse_find_node("keepBorder", node)))
363         config_theme_keepborder = parse_bool(doc, n);
364     if ((n = parse_find_node("hideDisabled", node)))
365         config_theme_hidedisabled = parse_bool(doc, n);
366 }
367
368 static void parse_desktops(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
369                            gpointer d)
370 {
371     xmlNodePtr n;
372
373     node = node->children;
374     
375     if ((n = parse_find_node("number", node))) {
376         gint d = parse_int(doc, n);
377         if (d > 0)
378             config_desktops_num = d;
379     }
380     if ((n = parse_find_node("firstdesk", node))) {
381         gint d = parse_int(doc, n);
382         if (d > 0)
383             config_screen_firstdesk = d;
384     }
385     if ((n = parse_find_node("names", node))) {
386         GSList *it;
387         xmlNodePtr nname;
388
389         for (it = config_desktops_names; it; it = it->next)
390             g_free(it->data);
391         g_slist_free(config_desktops_names);
392         config_desktops_names = NULL;
393
394         nname = parse_find_node("name", n->children);
395         while (nname) {
396             config_desktops_names = g_slist_append(config_desktops_names,
397                                                    parse_string(doc, nname));
398             nname = parse_find_node("name", nname->next);
399         }
400     }
401 }
402
403 static void parse_resize(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
404                          gpointer d)
405 {
406     xmlNodePtr n;
407
408     node = node->children;
409     
410     if ((n = parse_find_node("drawContents", node)))
411         config_resize_redraw = parse_bool(doc, n);
412     if ((n = parse_find_node("fourCorner", node)))
413         config_resize_four_corners = parse_bool(doc, n);
414     if ((n = parse_find_node("popupShow", node))) {
415         config_resize_popup_show = parse_int(doc, n);
416         if (parse_contains("Always", doc, n))
417             config_resize_popup_show = 2;
418         else if (parse_contains("Never", doc, n))
419             config_resize_popup_show = 0;
420         else if (parse_contains("Nonpixel", doc, n))
421             config_resize_popup_show = 1;
422     }
423     if ((n = parse_find_node("popupPosition", node))) {
424         config_resize_popup_pos = parse_int(doc, n);
425         if (parse_contains("Top", doc, n))
426             config_resize_popup_pos = 1;
427         else if (parse_contains("Center", doc, n))
428             config_resize_popup_pos = 0;
429     }
430 }
431
432 static void parse_dock(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("position", node))) {
440         if (parse_contains("TopLeft", doc, n))
441             config_dock_floating = FALSE,
442             config_dock_pos = OB_DIRECTION_NORTHWEST;
443         else if (parse_contains("Top", doc, n))
444             config_dock_floating = FALSE,
445             config_dock_pos = OB_DIRECTION_NORTH;
446         else if (parse_contains("TopRight", doc, n))
447             config_dock_floating = FALSE,
448             config_dock_pos = OB_DIRECTION_NORTHEAST;
449         else if (parse_contains("Right", doc, n))
450             config_dock_floating = FALSE,
451             config_dock_pos = OB_DIRECTION_EAST;
452         else if (parse_contains("BottomRight", doc, n))
453             config_dock_floating = FALSE,
454             config_dock_pos = OB_DIRECTION_SOUTHEAST;
455         else if (parse_contains("Bottom", doc, n))
456             config_dock_floating = FALSE,
457             config_dock_pos = OB_DIRECTION_SOUTH;
458         else if (parse_contains("BottomLeft", doc, n))
459             config_dock_floating = FALSE,
460             config_dock_pos = OB_DIRECTION_SOUTHWEST;
461         else if (parse_contains("Left", doc, n))
462             config_dock_floating = FALSE,
463             config_dock_pos = OB_DIRECTION_WEST;
464         else if (parse_contains("Floating", doc, n))
465             config_dock_floating = TRUE;
466     }
467     if (config_dock_floating) {
468         if ((n = parse_find_node("floatingX", node)))
469             config_dock_x = parse_int(doc, n);
470         if ((n = parse_find_node("floatingY", node)))
471             config_dock_y = parse_int(doc, n);
472     } else {
473         if ((n = parse_find_node("noStrut", node)))
474             config_dock_nostrut = parse_bool(doc, n);
475     }
476     if ((n = parse_find_node("stacking", node))) {
477         if (parse_contains("top", doc, n))
478             config_dock_layer = OB_STACKING_LAYER_ABOVE;
479         else if (parse_contains("normal", doc, n))
480             config_dock_layer = OB_STACKING_LAYER_NORMAL;
481         else if (parse_contains("bottom", doc, n))
482             config_dock_layer = OB_STACKING_LAYER_BELOW;
483     }
484     if ((n = parse_find_node("direction", node))) {
485         if (parse_contains("horizontal", doc, n))
486             config_dock_orient = OB_ORIENTATION_HORZ;
487         else if (parse_contains("vertical", doc, n))
488             config_dock_orient = OB_ORIENTATION_VERT;
489     }
490     if ((n = parse_find_node("autoHide", node)))
491         config_dock_hide = parse_bool(doc, n);
492     if ((n = parse_find_node("hideDelay", node)))
493         config_dock_hide_delay = parse_int(doc, n) * 1000;
494     if ((n = parse_find_node("showDelay", node)))
495         config_dock_show_delay = parse_int(doc, n) * 1000;
496     if ((n = parse_find_node("moveButton", node))) {
497         gchar *str = parse_string(doc, n);
498         guint b, s;
499         if (translate_button(str, &s, &b)) {
500             config_dock_app_move_button = b;
501             config_dock_app_move_modifiers = s;
502         } else {
503             g_warning("invalid button '%s'", str);
504         }
505         g_free(str);
506     }
507 }
508
509 static void parse_menu(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
510                        gpointer d)
511 {
512     xmlNodePtr n;
513     for (node = node->children; node; node = node->next) {
514         if (!xmlStrcasecmp(node->name, (const xmlChar*) "file")) {
515             gchar *c;
516
517             c = parse_string(doc, node);
518             config_menu_files = g_slist_append(config_menu_files,
519                                                parse_expand_tilde(c));
520             g_free(c);
521         }
522         if ((n = parse_find_node("warpPointer", node)))
523             config_menu_warppointer = parse_bool(doc, n);
524         if ((n = parse_find_node("xorStyle", node)))
525             config_menu_xorstyle = parse_bool(doc, n);
526         if ((n = parse_find_node("hideDelay", node)))
527             config_menu_hide_delay = parse_int(doc, n);
528         if ((n = parse_find_node("submenuShowDelay", node)))
529             config_submenu_show_delay = parse_int(doc, n);
530         if ((n = parse_find_node("desktopMenuIcons", node)))
531             config_menu_client_list_icons = parse_bool(doc, n);
532     }
533 }
534    
535 static void parse_resistance(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node, 
536                              gpointer d)
537 {
538     xmlNodePtr n;
539
540     node = node->children;
541     if ((n = parse_find_node("strength", node)))
542         config_resist_win = parse_int(doc, n);
543     if ((n = parse_find_node("screen_edge_strength", node)))
544         config_resist_edge = parse_int(doc, n);
545     if ((n = parse_find_node("edges_hit_layers_below", node)))
546         config_resist_layers_below = parse_bool(doc, n);
547 }
548
549 typedef struct
550 {
551     const gchar *key;
552     const gchar *actname;
553 } ObDefKeyBind;
554
555 static void bind_default_keyboard()
556 {
557     ObDefKeyBind *it;
558     ObDefKeyBind binds[] = {
559         { "A-Tab", "NextWindow" },
560         { "S-A-Tab", "PreviousWindow" },
561         { "A-F4", "Close" },
562         { NULL, NULL }
563     };
564
565     for (it = binds; it->key; ++it) {
566         GList *l = g_list_append(NULL, g_strdup(it->key));
567         keyboard_bind(l, action_from_string(it->actname,
568                                             OB_USER_ACTION_KEYBOARD_KEY));
569     }
570 }
571
572 typedef struct
573 {
574     const gchar *button;
575     const gchar *context;
576     const ObMouseAction mact;
577     const gchar *actname;
578 } ObDefMouseBind;
579
580 static void bind_default_mouse()
581 {
582     ObDefMouseBind *it;
583     ObDefMouseBind binds[] = {
584         { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
585         { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
586         { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
587         { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
588         { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
589         { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
590         { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
591         { "Left", "Handle", OB_MOUSE_ACTION_PRESS, "Focus" },
592         { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
593         { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
594         { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
595         { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
596         { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
597         { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
598         { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
599         { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
600         { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
601         { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
602         { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
603         { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
604         { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
605         { "Left", "Handle", OB_MOUSE_ACTION_CLICK, "Raise" },
606         { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
607         { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
608         { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
609         { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
610         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
611         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
612         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
613         { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
614         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
615         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
616         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
617         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximizeFull" },
618         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
619         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
620         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
621         { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
622         { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
623         { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
624         { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
625         { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
626         { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
627         { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
628         { NULL, NULL, 0, NULL }
629     };
630
631     for (it = binds; it->button; ++it) {
632         ObUserAction uact;
633         switch (it->mact) {
634         case OB_MOUSE_ACTION_PRESS:
635             uact = OB_USER_ACTION_MOUSE_PRESS; break;
636         case OB_MOUSE_ACTION_RELEASE:
637             uact = OB_USER_ACTION_MOUSE_RELEASE; break;
638         case OB_MOUSE_ACTION_CLICK:
639             uact = OB_USER_ACTION_MOUSE_CLICK; break;
640         case OB_MOUSE_ACTION_DOUBLE_CLICK:
641             uact = OB_USER_ACTION_MOUSE_DOUBLE_CLICK; break;
642         case OB_MOUSE_ACTION_MOTION:
643             uact = OB_USER_ACTION_MOUSE_MOTION; break;
644         case OB_NUM_MOUSE_ACTIONS:
645             g_assert_not_reached();
646         }
647         mouse_bind(it->button, it->context, it->mact,
648                    action_from_string(it->actname, uact));
649     }
650 }
651
652 void config_startup(ObParseInst *i)
653 {
654     config_focus_new = TRUE;
655     config_focus_follow = FALSE;
656     config_focus_delay = 0;
657     config_focus_raise = FALSE;
658     config_focus_last = FALSE;
659
660     parse_register(i, "focus", parse_focus, NULL);
661
662     config_place_policy = OB_PLACE_POLICY_SMART;
663
664     parse_register(i, "placement", parse_placement, NULL);
665
666     config_theme = NULL;
667
668     config_title_layout = g_strdup("NLIMC");
669     config_theme_keepborder = TRUE;
670     config_theme_hidedisabled = FALSE;
671
672     parse_register(i, "theme", parse_theme, NULL);
673
674     config_desktops_num = 4;
675     config_screen_firstdesk = 1;
676     config_desktops_names = NULL;
677
678     parse_register(i, "desktops", parse_desktops, NULL);
679
680     config_resize_redraw = TRUE;
681     config_resize_four_corners = FALSE;
682     config_resize_popup_show = 1; /* nonpixel increments */
683     config_resize_popup_pos = 0;  /* center of client */
684
685     parse_register(i, "resize", parse_resize, NULL);
686
687     config_dock_layer = OB_STACKING_LAYER_ABOVE;
688     config_dock_pos = OB_DIRECTION_NORTHEAST;
689     config_dock_floating = FALSE;
690     config_dock_nostrut = FALSE;
691     config_dock_x = 0;
692     config_dock_y = 0;
693     config_dock_orient = OB_ORIENTATION_VERT;
694     config_dock_hide = FALSE;
695     config_dock_hide_delay = 300;
696     config_dock_show_delay = 300;
697     config_dock_app_move_button = 2; /* middle */
698     config_dock_app_move_modifiers = 0;
699
700     parse_register(i, "dock", parse_dock, NULL);
701
702     translate_key("C-g", &config_keyboard_reset_state,
703                   &config_keyboard_reset_keycode);
704
705     bind_default_keyboard();
706
707     parse_register(i, "keyboard", parse_keyboard, NULL);
708
709     config_mouse_threshold = 3;
710     config_mouse_dclicktime = 200;
711
712     bind_default_mouse();
713
714     parse_register(i, "mouse", parse_mouse, NULL);
715
716     config_resist_win = 10;
717     config_resist_edge = 20;
718     config_resist_layers_below = FALSE;
719
720     parse_register(i, "resistance", parse_resistance, NULL);
721
722     config_menu_warppointer = TRUE;
723     config_menu_xorstyle = TRUE;
724     config_menu_hide_delay = 250;
725     config_submenu_show_delay = 0;
726     config_menu_client_list_icons = TRUE;
727     config_menu_files = NULL;
728
729     parse_register(i, "menu", parse_menu, NULL);
730
731     per_app_settings = NULL;
732
733     parse_register(i, "applications", parse_per_app_settings, NULL);
734 }
735
736 void config_shutdown()
737 {
738     GSList *it;
739
740     g_free(config_theme);
741
742     g_free(config_title_layout);
743
744     for (it = config_desktops_names; it; it = g_slist_next(it))
745         g_free(it->data);
746     g_slist_free(config_desktops_names);
747
748     for (it = config_menu_files; it; it = g_slist_next(it))
749         g_free(it->data);
750     g_slist_free(config_menu_files);
751 }