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