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