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