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