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