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