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