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