1) translate all of openbox's output
[dana/openbox-history.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("fourCorner", node)))
539         config_resize_four_corners = parse_bool(doc, n);
540     if ((n = parse_find_node("popupShow", node))) {
541         config_resize_popup_show = parse_int(doc, n);
542         if (parse_contains("Always", doc, n))
543             config_resize_popup_show = 2;
544         else if (parse_contains("Never", doc, n))
545             config_resize_popup_show = 0;
546         else if (parse_contains("Nonpixel", doc, n))
547             config_resize_popup_show = 1;
548     }
549     if ((n = parse_find_node("popupPosition", node))) {
550         config_resize_popup_pos = parse_int(doc, n);
551         if (parse_contains("Top", doc, n))
552             config_resize_popup_pos = 1;
553         else if (parse_contains("Center", doc, n))
554             config_resize_popup_pos = 0;
555     }
556 }
557
558 static void parse_dock(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
559                        gpointer d)
560 {
561     xmlNodePtr n;
562
563     node = node->children;
564
565     if ((n = parse_find_node("position", node))) {
566         if (parse_contains("TopLeft", doc, n))
567             config_dock_floating = FALSE,
568             config_dock_pos = OB_DIRECTION_NORTHWEST;
569         else if (parse_contains("Top", doc, n))
570             config_dock_floating = FALSE,
571             config_dock_pos = OB_DIRECTION_NORTH;
572         else if (parse_contains("TopRight", doc, n))
573             config_dock_floating = FALSE,
574             config_dock_pos = OB_DIRECTION_NORTHEAST;
575         else if (parse_contains("Right", doc, n))
576             config_dock_floating = FALSE,
577             config_dock_pos = OB_DIRECTION_EAST;
578         else if (parse_contains("BottomRight", doc, n))
579             config_dock_floating = FALSE,
580             config_dock_pos = OB_DIRECTION_SOUTHEAST;
581         else if (parse_contains("Bottom", doc, n))
582             config_dock_floating = FALSE,
583             config_dock_pos = OB_DIRECTION_SOUTH;
584         else if (parse_contains("BottomLeft", doc, n))
585             config_dock_floating = FALSE,
586             config_dock_pos = OB_DIRECTION_SOUTHWEST;
587         else if (parse_contains("Left", doc, n))
588             config_dock_floating = FALSE,
589             config_dock_pos = OB_DIRECTION_WEST;
590         else if (parse_contains("Floating", doc, n))
591             config_dock_floating = TRUE;
592     }
593     if (config_dock_floating) {
594         if ((n = parse_find_node("floatingX", node)))
595             config_dock_x = parse_int(doc, n);
596         if ((n = parse_find_node("floatingY", node)))
597             config_dock_y = parse_int(doc, n);
598     } else {
599         if ((n = parse_find_node("noStrut", node)))
600             config_dock_nostrut = parse_bool(doc, n);
601     }
602     if ((n = parse_find_node("stacking", node))) {
603         if (parse_contains("top", doc, n))
604             config_dock_layer = OB_STACKING_LAYER_ABOVE;
605         else if (parse_contains("normal", doc, n))
606             config_dock_layer = OB_STACKING_LAYER_NORMAL;
607         else if (parse_contains("bottom", doc, n))
608             config_dock_layer = OB_STACKING_LAYER_BELOW;
609     }
610     if ((n = parse_find_node("direction", node))) {
611         if (parse_contains("horizontal", doc, n))
612             config_dock_orient = OB_ORIENTATION_HORZ;
613         else if (parse_contains("vertical", doc, n))
614             config_dock_orient = OB_ORIENTATION_VERT;
615     }
616     if ((n = parse_find_node("autoHide", node)))
617         config_dock_hide = parse_bool(doc, n);
618     if ((n = parse_find_node("hideDelay", node)))
619         config_dock_hide_delay = parse_int(doc, n) * 1000;
620     if ((n = parse_find_node("showDelay", node)))
621         config_dock_show_delay = parse_int(doc, n) * 1000;
622     if ((n = parse_find_node("moveButton", node))) {
623         gchar *str = parse_string(doc, n);
624         guint b, s;
625         if (translate_button(str, &s, &b)) {
626             config_dock_app_move_button = b;
627             config_dock_app_move_modifiers = s;
628         } else {
629             g_message(_("Invalid button '%s' specified in config file"), str);
630         }
631         g_free(str);
632     }
633 }
634
635 static void parse_menu(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
636                        gpointer d)
637 {
638     xmlNodePtr n;
639     for (node = node->children; node; node = node->next) {
640         if (!xmlStrcasecmp(node->name, (const xmlChar*) "file")) {
641             gchar *c;
642
643             c = parse_string(doc, node);
644             config_menu_files = g_slist_append(config_menu_files,
645                                                parse_expand_tilde(c));
646             g_free(c);
647         }
648         if ((n = parse_find_node("warpPointer", node)))
649             config_menu_warppointer = parse_bool(doc, n);
650         if ((n = parse_find_node("hideDelay", node)))
651             config_menu_hide_delay = parse_int(doc, n);
652         if ((n = parse_find_node("middle", node)))
653             config_menu_middle = parse_bool(doc, n);
654         if ((n = parse_find_node("submenuShowDelay", node)))
655             config_submenu_show_delay = parse_int(doc, n);
656         if ((n = parse_find_node("desktopMenuIcons", node)))
657             config_menu_client_list_icons = parse_bool(doc, n);
658     }
659 }
660    
661 static void parse_resistance(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node, 
662                              gpointer d)
663 {
664     xmlNodePtr n;
665
666     node = node->children;
667     if ((n = parse_find_node("strength", node)))
668         config_resist_win = parse_int(doc, n);
669     if ((n = parse_find_node("screen_edge_strength", node)))
670         config_resist_edge = parse_int(doc, n);
671     if ((n = parse_find_node("edges_hit_layers_below", node)))
672         config_resist_layers_below = parse_bool(doc, n);
673 }
674
675 typedef struct
676 {
677     const gchar *key;
678     const gchar *actname;
679 } ObDefKeyBind;
680
681 static void bind_default_keyboard()
682 {
683     ObDefKeyBind *it;
684     ObDefKeyBind binds[] = {
685         { "A-Tab", "NextWindow" },
686         { "S-A-Tab", "PreviousWindow" },
687         { "A-F4", "Close" },
688         { NULL, NULL }
689     };
690
691     for (it = binds; it->key; ++it) {
692         GList *l = g_list_append(NULL, g_strdup(it->key));
693         keyboard_bind(l, action_from_string(it->actname,
694                                             OB_USER_ACTION_KEYBOARD_KEY));
695     }
696 }
697
698 typedef struct
699 {
700     const gchar *button;
701     const gchar *context;
702     const ObMouseAction mact;
703     const gchar *actname;
704 } ObDefMouseBind;
705
706 static void bind_default_mouse()
707 {
708     ObDefMouseBind *it;
709     ObDefMouseBind binds[] = {
710         { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
711         { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
712         { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
713         { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
714         { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
715         { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
716         { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
717         { "Left", "Handle", OB_MOUSE_ACTION_PRESS, "Focus" },
718         { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
719         { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
720         { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
721         { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
722         { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
723         { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
724         { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
725         { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
726         { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
727         { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
728         { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
729         { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
730         { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
731         { "Left", "Handle", OB_MOUSE_ACTION_CLICK, "Raise" },
732         { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
733         { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
734         { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
735         { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
736         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
737         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
738         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
739         { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
740         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
741         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
742         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
743         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximizeFull" },
744         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
745         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
746         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
747         { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
748         { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
749         { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
750         { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
751         { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
752         { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
753         { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
754         { NULL, NULL, 0, NULL }
755     };
756
757     for (it = binds; it->button; ++it) {
758         ObUserAction uact;
759         switch (it->mact) {
760         case OB_MOUSE_ACTION_PRESS:
761             uact = OB_USER_ACTION_MOUSE_PRESS; break;
762         case OB_MOUSE_ACTION_RELEASE:
763             uact = OB_USER_ACTION_MOUSE_RELEASE; break;
764         case OB_MOUSE_ACTION_CLICK:
765             uact = OB_USER_ACTION_MOUSE_CLICK; break;
766         case OB_MOUSE_ACTION_DOUBLE_CLICK:
767             uact = OB_USER_ACTION_MOUSE_DOUBLE_CLICK; break;
768         case OB_MOUSE_ACTION_MOTION:
769             uact = OB_USER_ACTION_MOUSE_MOTION; break;
770         default:
771             g_assert_not_reached();
772         }
773         mouse_bind(it->button, it->context, it->mact,
774                    action_from_string(it->actname, uact));
775     }
776 }
777
778 void config_startup(ObParseInst *i)
779 {
780     config_focus_new = TRUE;
781     config_focus_follow = FALSE;
782     config_focus_delay = 0;
783     config_focus_raise = FALSE;
784     config_focus_last = FALSE;
785
786     parse_register(i, "focus", parse_focus, NULL);
787
788     config_place_policy = OB_PLACE_POLICY_SMART;
789
790     parse_register(i, "placement", parse_placement, NULL);
791
792     config_theme = NULL;
793
794     config_title_layout = g_strdup("NLIMC");
795     config_theme_keepborder = TRUE;
796     config_theme_hidedisabled = FALSE;
797
798     config_font_activewindow = NULL;
799     config_font_inactivewindow = NULL;
800     config_font_menuitem = NULL;
801     config_font_menutitle = NULL;
802
803     parse_register(i, "theme", parse_theme, NULL);
804
805     config_desktops_num = 4;
806     config_screen_firstdesk = 1;
807     config_desktops_names = NULL;
808
809     parse_register(i, "desktops", parse_desktops, NULL);
810
811     config_resize_redraw = TRUE;
812     config_resize_four_corners = FALSE;
813     config_resize_popup_show = 1; /* nonpixel increments */
814     config_resize_popup_pos = 0;  /* center of client */
815
816     parse_register(i, "resize", parse_resize, NULL);
817
818     config_dock_layer = OB_STACKING_LAYER_ABOVE;
819     config_dock_pos = OB_DIRECTION_NORTHEAST;
820     config_dock_floating = FALSE;
821     config_dock_nostrut = FALSE;
822     config_dock_x = 0;
823     config_dock_y = 0;
824     config_dock_orient = OB_ORIENTATION_VERT;
825     config_dock_hide = FALSE;
826     config_dock_hide_delay = 300;
827     config_dock_show_delay = 300;
828     config_dock_app_move_button = 2; /* middle */
829     config_dock_app_move_modifiers = 0;
830
831     parse_register(i, "dock", parse_dock, NULL);
832
833     translate_key("C-g", &config_keyboard_reset_state,
834                   &config_keyboard_reset_keycode);
835
836     bind_default_keyboard();
837
838     parse_register(i, "keyboard", parse_keyboard, NULL);
839
840     config_mouse_threshold = 3;
841     config_mouse_dclicktime = 200;
842
843     bind_default_mouse();
844
845     parse_register(i, "mouse", parse_mouse, NULL);
846
847     config_resist_win = 10;
848     config_resist_edge = 20;
849     config_resist_layers_below = FALSE;
850
851     parse_register(i, "resistance", parse_resistance, NULL);
852
853     config_menu_warppointer = TRUE;
854     config_menu_hide_delay = 250;
855     config_menu_middle = FALSE;
856     config_submenu_show_delay = 0;
857     config_menu_client_list_icons = TRUE;
858     config_menu_files = NULL;
859
860     parse_register(i, "menu", parse_menu, NULL);
861
862     config_per_app_settings = NULL;
863
864     parse_register(i, "applications", parse_per_app_settings, NULL);
865 }
866
867 void config_shutdown()
868 {
869     GSList *it;
870
871     g_free(config_theme);
872
873     g_free(config_title_layout);
874
875     RrFontClose(config_font_activewindow);
876     RrFontClose(config_font_inactivewindow);
877     RrFontClose(config_font_menuitem);
878     RrFontClose(config_font_menutitle);
879
880     for (it = config_desktops_names; it; it = g_slist_next(it))
881         g_free(it->data);
882     g_slist_free(config_desktops_names);
883
884     for (it = config_menu_files; it; it = g_slist_next(it))
885         g_free(it->data);
886     g_slist_free(config_menu_files);
887
888     for (it = config_per_app_settings; it; it = g_slist_next(it)) {
889         ObAppSettings *itd = (ObAppSettings *)it->data;
890         g_free(itd->name);
891         g_free(itd->role);
892         g_free(itd->class);
893         g_free(it->data);
894     }
895     g_slist_free(config_per_app_settings);
896 }