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