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