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