]> icculus.org git repositories - dana/openbox.git/blob - openbox/config.c
wip: loading theme stuff
[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 "config_value.h"
22 #include "keyboard.h"
23 #include "mouse.h"
24 #include "action.h"
25 #include "action_list.h"
26 #include "action_parser.h"
27 #include "translate.h"
28 #include "client.h"
29 #include "screen.h"
30 #include "openbox.h"
31 #include "gettext.h"
32 #include "obt/paths.h"
33
34 gboolean config_focus_new;
35 gboolean config_focus_follow;
36 guint    config_focus_delay;
37 gboolean config_focus_raise;
38 gboolean config_focus_last;
39 gboolean config_focus_under_mouse;
40 gboolean config_unfocus_leave;
41
42 ObPlacePolicy  config_place_policy;
43 gboolean       config_place_center;
44 ObPlaceMonitor config_place_monitor;
45
46 guint          config_primary_monitor_index;
47 ObPlaceMonitor config_primary_monitor;
48
49 StrutPartial config_margins;
50
51 gchar   *config_theme;
52 gboolean config_theme_keepborder;
53 guint    config_theme_window_list_icon_size;
54
55 gchar   *config_title_layout;
56
57 gboolean config_animate_iconify;
58
59 RrFont *config_font_activewindow;
60 RrFont *config_font_inactivewindow;
61 RrFont *config_font_menuitem;
62 RrFont *config_font_menutitle;
63 RrFont *config_font_activeosd;
64 RrFont *config_font_inactiveosd;
65
66 guint   config_desktops_num;
67 GSList *config_desktops_names;
68 guint   config_screen_firstdesk;
69 guint   config_desktop_popup_time;
70
71 gboolean         config_resize_redraw;
72 gint             config_resize_popup_show;
73 ObResizePopupPos config_resize_popup_pos;
74 GravityPoint     config_resize_popup_fixed;
75
76 ObStackingLayer config_dock_layer;
77 gboolean        config_dock_floating;
78 gboolean        config_dock_nostrut;
79 ObDirection     config_dock_pos;
80 gint            config_dock_x;
81 gint            config_dock_y;
82 ObOrientation   config_dock_orient;
83 gboolean        config_dock_hide;
84 guint           config_dock_hide_delay;
85 guint           config_dock_show_delay;
86 guint           config_dock_app_move_button;
87 guint           config_dock_app_move_modifiers;
88
89 guint config_keyboard_reset_keycode;
90 guint config_keyboard_reset_state;
91
92 gint     config_mouse_threshold;
93 gint     config_mouse_dclicktime;
94 gint     config_mouse_screenedgetime;
95 gboolean config_mouse_screenedgewarp;
96
97 guint    config_menu_hide_delay;
98 gboolean config_menu_middle;
99 guint    config_submenu_show_delay;
100 guint    config_submenu_hide_delay;
101 gboolean config_menu_manage_desktops;
102 gboolean config_menu_show_icons;
103
104 GSList *config_menu_files;
105
106 gint     config_resist_win;
107 gint     config_resist_edge;
108
109 GSList *config_per_app_settings;
110
111 ObAppSettings* config_create_app_settings(void)
112 {
113     ObAppSettings *settings = g_slice_new0(ObAppSettings);
114     settings->type = -1;
115     settings->decor = -1;
116     settings->shade = -1;
117     settings->monitor = -1;
118     settings->focus = -1;
119     settings->desktop = 0;
120     settings->layer = -2;
121     settings->iconic = -1;
122     settings->skip_pager = -1;
123     settings->skip_taskbar = -1;
124     settings->fullscreen = -1;
125     settings->max_horz = -1;
126     settings->max_vert = -1;
127     return settings;
128 }
129
130 #define copy_if(setting, default) \
131   if (src->setting != default) dst->setting = src->setting
132 void config_app_settings_copy_non_defaults(const ObAppSettings *src,
133                                            ObAppSettings *dst)
134 {
135     g_assert(src != NULL);
136     g_assert(dst != NULL);
137
138     copy_if(type, (ObClientType)-1);
139     copy_if(decor, -1);
140     copy_if(shade, -1);
141     copy_if(monitor, -1);
142     copy_if(focus, -1);
143     copy_if(desktop, 0);
144     copy_if(layer, -2);
145     copy_if(iconic, -1);
146     copy_if(skip_pager, -1);
147     copy_if(skip_taskbar, -1);
148     copy_if(fullscreen, -1);
149     copy_if(max_horz, -1);
150     copy_if(max_vert, -1);
151
152     if (src->pos_given) {
153         dst->pos_given = TRUE;
154         dst->pos_force = src->pos_force;
155         dst->position = src->position;
156         /* monitor is copied above */
157     }
158 }
159
160 /*
161   <applications>
162     <application name="aterm">
163       <decor>false</decor>
164     </application>
165     <application name="Rhythmbox">
166       <layer>above</layer>
167       <position>
168         <x>700</x>
169         <y>0</y>
170         <monitor>1</monitor>
171       </position>
172       .. there is a lot more settings available
173     </application>
174   </applications>
175 */
176
177 /* Manages settings for individual applications.
178    Some notes: monitor is the screen number in a multi monitor
179    (Xinerama) setup (starting from 0) or mouse, meaning the
180    monitor the pointer is on. Default: mouse.
181    Layer can be three values, above (Always on top), below
182    (Always on bottom) and everything else (normal behaviour).
183    Positions can be an integer value or center, which will
184    center the window in the specified axis. Position is within
185    the monitor, so <position><x>center</x></position><monitor>2</monitor>
186    will center the window on the second monitor.
187 */
188 static void parse_per_app_settings(xmlNodePtr node, gpointer d)
189 {
190     xmlNodePtr app = obt_xml_find_sibling(node->children, "application");
191     gchar *name = NULL, *class = NULL, *role = NULL, *title = NULL,
192         *type_str = NULL;
193     gboolean name_set, class_set, type_set, role_set, title_set;
194     ObClientType type;
195     gboolean x_pos_given;
196
197     while (app) {
198         x_pos_given = FALSE;
199
200         class_set = obt_xml_attr_string(app, "class", &class);
201         name_set = obt_xml_attr_string(app, "name", &name);
202         type_set = obt_xml_attr_string(app, "type", &type_str);
203         role_set = obt_xml_attr_string(app, "role", &role);
204         title_set = obt_xml_attr_string(app, "title", &title);
205
206         /* validate the type tho */
207         if (type_set) {
208             if (!g_ascii_strcasecmp(type_str, "normal"))
209                 type = OB_CLIENT_TYPE_NORMAL;
210             else if (!g_ascii_strcasecmp(type_str, "dialog"))
211                 type = OB_CLIENT_TYPE_DIALOG;
212             else if (!g_ascii_strcasecmp(type_str, "splash"))
213                 type = OB_CLIENT_TYPE_SPLASH;
214             else if (!g_ascii_strcasecmp(type_str, "utility"))
215                 type = OB_CLIENT_TYPE_UTILITY;
216             else if (!g_ascii_strcasecmp(type_str, "menu"))
217                 type = OB_CLIENT_TYPE_MENU;
218             else if (!g_ascii_strcasecmp(type_str, "toolbar"))
219                 type = OB_CLIENT_TYPE_TOOLBAR;
220             else if (!g_ascii_strcasecmp(type_str, "dock"))
221                 type = OB_CLIENT_TYPE_DOCK;
222             else if (!g_ascii_strcasecmp(type_str, "desktop"))
223                 type = OB_CLIENT_TYPE_DESKTOP;
224             else
225                 type_set = FALSE; /* not valid! */
226         }
227
228         if (class_set || name_set || role_set || title_set || type_set) {
229             xmlNodePtr n, c;
230             ObAppSettings *settings = config_create_app_settings();
231
232             if (name_set)
233                 settings->name = g_pattern_spec_new(name);
234
235             if (class_set)
236                 settings->class = g_pattern_spec_new(class);
237
238             if (role_set)
239                 settings->role = g_pattern_spec_new(role);
240
241             if (title_set)
242                 settings->title = g_pattern_spec_new(title);
243
244             if (type_set)
245                 settings->type = type;
246
247             if ((n = obt_xml_find_sibling(app->children, "decor")))
248                 if (!obt_xml_node_contains(n, "default"))
249                     settings->decor = obt_xml_node_bool(n);
250
251             if ((n = obt_xml_find_sibling(app->children, "shade")))
252                 if (!obt_xml_node_contains(n, "default"))
253                     settings->shade = obt_xml_node_bool(n);
254
255             if ((n = obt_xml_find_sibling(app->children, "position"))) {
256                 if ((c = obt_xml_find_sibling(n->children, "x")))
257                     if (!obt_xml_node_contains(c, "default")) {
258                         ObConfigValue *v = config_value_new_string(
259                             obt_xml_node_string(node));
260                         config_value_gravity_coord(v, &settings->position.x);
261                         config_value_unref(v);
262                         x_pos_given = TRUE;
263                     }
264
265                 if (x_pos_given && (c = obt_xml_find_sibling(n->children, "y")))
266                     if (!obt_xml_node_contains(c, "default")) {
267                         ObConfigValue *v = config_value_new_string(
268                             obt_xml_node_string(node));
269                         config_value_gravity_coord(v, &settings->position.y);
270                         config_value_unref(v);
271                         settings->pos_given = TRUE;
272                     }
273
274                 if (settings->pos_given &&
275                     (c = obt_xml_find_sibling(n->children, "monitor")))
276                     if (!obt_xml_node_contains(c, "default")) {
277                         gchar *s = obt_xml_node_string(c);
278                         if (!g_ascii_strcasecmp(s, "mouse"))
279                             settings->monitor = 0;
280                         else
281                             settings->monitor = obt_xml_node_int(c);
282                         g_free(s);
283                     }
284
285                 obt_xml_attr_bool(n, "force", &settings->pos_force);
286             }
287
288             if ((n = obt_xml_find_sibling(app->children, "focus")))
289                 if (!obt_xml_node_contains(n, "default"))
290                     settings->focus = obt_xml_node_bool(n);
291
292             if ((n = obt_xml_find_sibling(app->children, "desktop"))) {
293                 if (!obt_xml_node_contains(n, "default")) {
294                     gchar *s = obt_xml_node_string(n);
295                     if (!g_ascii_strcasecmp(s, "all"))
296                         settings->desktop = DESKTOP_ALL;
297                     else {
298                         gint i = obt_xml_node_int(n);
299                         if (i > 0)
300                             settings->desktop = i;
301                     }
302                     g_free(s);
303                 }
304             }
305
306             if ((n = obt_xml_find_sibling(app->children, "layer")))
307                 if (!obt_xml_node_contains(n, "default")) {
308                     gchar *s = obt_xml_node_string(n);
309                     if (!g_ascii_strcasecmp(s, "above"))
310                         settings->layer = 1;
311                     else if (!g_ascii_strcasecmp(s, "below"))
312                         settings->layer = -1;
313                     else
314                         settings->layer = 0;
315                     g_free(s);
316                 }
317
318             if ((n = obt_xml_find_sibling(app->children, "iconic")))
319                 if (!obt_xml_node_contains(n, "default"))
320                     settings->iconic = obt_xml_node_bool(n);
321
322             if ((n = obt_xml_find_sibling(app->children, "skip_pager")))
323                 if (!obt_xml_node_contains(n, "default"))
324                     settings->skip_pager = obt_xml_node_bool(n);
325
326             if ((n = obt_xml_find_sibling(app->children, "skip_taskbar")))
327                 if (!obt_xml_node_contains(n, "default"))
328                     settings->skip_taskbar = obt_xml_node_bool(n);
329
330             if ((n = obt_xml_find_sibling(app->children, "fullscreen")))
331                 if (!obt_xml_node_contains(n, "default"))
332                     settings->fullscreen = obt_xml_node_bool(n);
333
334             if ((n = obt_xml_find_sibling(app->children, "maximized")))
335                 if (!obt_xml_node_contains(n, "default")) {
336                     gchar *s = obt_xml_node_string(n);
337                     if (!g_ascii_strcasecmp(s, "horizontal")) {
338                         settings->max_horz = TRUE;
339                         settings->max_vert = FALSE;
340                     } else if (!g_ascii_strcasecmp(s, "vertical")) {
341                         settings->max_horz = FALSE;
342                         settings->max_vert = TRUE;
343                     } else
344                         settings->max_horz = settings->max_vert =
345                             obt_xml_node_bool(n);
346                     g_free(s);
347                 }
348
349             config_per_app_settings = g_slist_append(config_per_app_settings,
350                                                      (gpointer) settings);
351             g_free(name);
352             g_free(class);
353             g_free(role);
354             g_free(title);
355             g_free(type_str);
356             name = class = role = title = type_str = NULL;
357         }
358
359         app = obt_xml_find_sibling(app->next, "application");
360     }
361 }
362
363 /*
364
365 <keybind key="C-x">
366   <action name="ChangeDesktop">
367     <desktop>3</desktop>
368   </action>
369 </keybind>
370
371 */
372
373 static void parse_keybind(xmlNodePtr node, GList *keylist)
374 {
375     gchar *keystring, **keys, **key;
376     xmlNodePtr n;
377     gboolean is_chroot = FALSE;
378
379     if (!obt_xml_attr_string(node, "key", &keystring))
380         return;
381
382     obt_xml_attr_bool(node, "chroot", &is_chroot);
383
384     keys = g_strsplit(keystring, " ", 0);
385     for (key = keys; *key; ++key) {
386         keylist = g_list_append(keylist, *key);
387
388         if ((n = obt_xml_find_sibling(node->children, "keybind"))) {
389             while (n) {
390                 parse_keybind(n, keylist);
391                 n = obt_xml_find_sibling(n->next, "keybind");
392             }
393         }
394         else if ((n = obt_xml_find_sibling(node->children, "action"))) {
395             while (n) {
396                 ObActionParser *p;
397                 ObActionList *actions;
398                 xmlChar *c;
399
400                 c = xmlNodeGetContent(node);
401                 p = action_parser_new();
402                 actions = action_parser_read_string(p, (gchar*)c);
403                 xmlFree(c);
404                 action_parser_unref(p);
405
406                 if (actions)
407                     keyboard_bind(keylist, actions);
408
409                 action_list_unref(actions);
410                 n = obt_xml_find_sibling(n->next, "action");
411             }
412         }
413
414
415         if (is_chroot)
416             keyboard_chroot(keylist);
417         keylist = g_list_delete_link(keylist, g_list_last(keylist));
418     }
419
420     g_strfreev(keys);
421     g_free(keystring);
422 }
423
424 static void parse_keyboard(xmlNodePtr node, gpointer d)
425 {
426     xmlNodePtr n;
427     gchar *key;
428
429     if ((n = obt_xml_find_sibling(node->children, "chainQuitKey"))) {
430         key = obt_xml_node_string(n);
431         translate_key(key, &config_keyboard_reset_state,
432                       &config_keyboard_reset_keycode);
433         g_free(key);
434     }
435 }
436
437 /*
438
439 <context name="Titlebar">
440   <mousebind button="Left" action="Press">
441     <action name="Raise"></action>
442   </mousebind>
443 </context>
444
445 */
446
447 static void parse_mouse(xmlNodePtr node, gpointer d)
448 {
449     xmlNodePtr n;
450
451     mouse_unbind_all();
452
453     node = node->children;
454
455     if ((n = obt_xml_find_sibling(node, "dragThreshold")))
456         config_mouse_threshold = obt_xml_node_int(n);
457     if ((n = obt_xml_find_sibling(node, "doubleClickTime")))
458         config_mouse_dclicktime = obt_xml_node_int(n);
459     if ((n = obt_xml_find_sibling(node, "screenEdgeWarpTime"))) {
460         config_mouse_screenedgetime = obt_xml_node_int(n);
461         /* minimum value of 25 for this property, when it is 1 and you hit the
462            edge it basically never stops */
463         if (config_mouse_screenedgetime && config_mouse_screenedgetime < 25)
464             config_mouse_screenedgetime = 25;
465     }
466     if ((n = obt_xml_find_sibling(node, "screenEdgeWarpMouse")))
467         config_mouse_screenedgewarp = obt_xml_node_bool(n);
468 }
469
470 static void parse_context(xmlNodePtr n, gpointer d)
471 {
472     xmlNodePtr nbut, nact;
473     gchar *buttonstr;
474     gchar *cxstr;
475     ObMouseAction mact;
476     gchar *modcxstr;
477     ObFrameContext cx;
478
479     if (!obt_xml_attr_string(n, "name", &cxstr))
480         return;
481
482     modcxstr = g_strdup(cxstr); /* make a copy to mutilate */
483     while (frame_next_context_from_string(modcxstr, &cx)) {
484         if (!cx) {
485             gchar *s = strchr(modcxstr, ' ');
486             if (s) {
487                 *s = '\0';
488                 g_message(_("Invalid context \"%s\" in mouse binding"),
489                           modcxstr);
490                 *s = ' ';
491             }
492             continue;
493         }
494
495         nbut = obt_xml_find_sibling(n->children, "mousebind");
496         while (nbut) {
497             if (!obt_xml_attr_string(nbut, "button", &buttonstr))
498                 goto next_nbut;
499             if (obt_xml_attr_contains(nbut, "action", "press"))
500                 mact = OB_MOUSE_ACTION_PRESS;
501             else if (obt_xml_attr_contains(nbut, "action", "release"))
502                 mact = OB_MOUSE_ACTION_RELEASE;
503             else if (obt_xml_attr_contains(nbut, "action", "click"))
504                 mact = OB_MOUSE_ACTION_CLICK;
505             else if (obt_xml_attr_contains(nbut, "action","doubleclick"))
506                 mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
507             else if (obt_xml_attr_contains(nbut, "action", "drag"))
508                 mact = OB_MOUSE_ACTION_MOTION;
509             else
510                 goto next_nbut;
511
512             nact = obt_xml_find_sibling(nbut->children, "action");
513             while (nact) {
514                 ObActionList *actions;
515                 ObActionParser *p;
516                 xmlChar *c;
517
518                 c = xmlNodeGetContent(nact);
519                 p = action_parser_new();
520                 if ((actions = action_parser_read_string(p, (gchar*)c)))
521                     mouse_bind(buttonstr, cx, mact, actions);
522                 nact = obt_xml_find_sibling(nact->next, "action");
523                 action_list_unref(actions);
524                 xmlFree(c);
525                 action_parser_unref(p);
526             }
527             g_free(buttonstr);
528         next_nbut:
529             nbut = obt_xml_find_sibling(nbut->next, "mousebind");
530         }
531     }
532     g_free(modcxstr);
533     g_free(cxstr);
534 }
535
536
537 static void parse_desktops(xmlNodePtr node, gpointer d)
538 {
539     xmlNodePtr n;
540
541     node = node->children;
542
543     if ((n = obt_xml_find_sibling(node, "number"))) {
544         gint d = obt_xml_node_int(n);
545         if (d > 0)
546             config_desktops_num = (unsigned) d;
547     }
548     if ((n = obt_xml_find_sibling(node, "firstdesk"))) {
549         gint d = obt_xml_node_int(n);
550         if (d > 0)
551             config_screen_firstdesk = (unsigned) d;
552     }
553     if ((n = obt_xml_find_sibling(node, "names"))) {
554         GSList *it;
555         xmlNodePtr nname;
556
557         for (it = config_desktops_names; it; it = it->next)
558             g_free(it->data);
559         g_slist_free(config_desktops_names);
560         config_desktops_names = NULL;
561
562         nname = obt_xml_find_sibling(n->children, "name");
563         while (nname) {
564             config_desktops_names =
565                 g_slist_append(config_desktops_names,
566                                obt_xml_node_string(nname));
567             nname = obt_xml_find_sibling(nname->next, "name");
568         }
569     }
570     if ((n = obt_xml_find_sibling(node, "popupTime")))
571         config_desktop_popup_time = obt_xml_node_int(n);
572 }
573
574 static void parse_resize(xmlNodePtr node, gpointer d)
575 {
576     xmlNodePtr n;
577
578     node = node->children;
579
580     if ((n = obt_xml_find_sibling(node, "drawContents")))
581         config_resize_redraw = obt_xml_node_bool(n);
582     if ((n = obt_xml_find_sibling(node, "popupShow"))) {
583         config_resize_popup_show = obt_xml_node_int(n);
584         if (obt_xml_node_contains(n, "Always"))
585             config_resize_popup_show = 2;
586         else if (obt_xml_node_contains(n, "Never"))
587             config_resize_popup_show = 0;
588         else if (obt_xml_node_contains(n, "Nonpixel"))
589             config_resize_popup_show = 1;
590     }
591     if ((n = obt_xml_find_sibling(node, "popupPosition"))) {
592         if (obt_xml_node_contains(n, "Top"))
593             config_resize_popup_pos = OB_RESIZE_POS_TOP;
594         else if (obt_xml_node_contains(n, "Center"))
595             config_resize_popup_pos = OB_RESIZE_POS_CENTER;
596         else if (obt_xml_node_contains(n, "Fixed")) {
597             config_resize_popup_pos = OB_RESIZE_POS_FIXED;
598
599             if ((n = obt_xml_find_sibling(node, "popupFixedPosition"))) {
600                 xmlNodePtr n2;
601
602                 if ((n2 = obt_xml_find_sibling(n->children, "x"))) {
603                     ObConfigValue *v = config_value_new_string(
604                         obt_xml_node_string(n2));
605                     config_value_gravity_coord(v,
606                                                &config_resize_popup_fixed.x);
607                     config_value_unref(v);
608                 }
609                 if ((n2 = obt_xml_find_sibling(n->children, "y"))) {
610                     ObConfigValue *v = config_value_new_string(
611                         obt_xml_node_string(n2));
612                     config_value_gravity_coord(v,
613                                                &config_resize_popup_fixed.y);
614                     config_value_unref(v);
615                 }
616
617                 config_resize_popup_fixed.x.pos =
618                     MAX(config_resize_popup_fixed.x.pos, 0);
619                 config_resize_popup_fixed.y.pos =
620                     MAX(config_resize_popup_fixed.y.pos, 0);
621             }
622         }
623     }
624 }
625
626 static void parse_dock(xmlNodePtr node, gpointer d)
627 {
628     xmlNodePtr n;
629
630     node = node->children;
631
632     if ((n = obt_xml_find_sibling(node, "position"))) {
633         if (obt_xml_node_contains(n, "TopLeft"))
634             config_dock_floating = FALSE,
635             config_dock_pos = OB_DIRECTION_NORTHWEST;
636         else if (obt_xml_node_contains(n, "Top"))
637             config_dock_floating = FALSE,
638             config_dock_pos = OB_DIRECTION_NORTH;
639         else if (obt_xml_node_contains(n, "TopRight"))
640             config_dock_floating = FALSE,
641             config_dock_pos = OB_DIRECTION_NORTHEAST;
642         else if (obt_xml_node_contains(n, "Right"))
643             config_dock_floating = FALSE,
644             config_dock_pos = OB_DIRECTION_EAST;
645         else if (obt_xml_node_contains(n, "BottomRight"))
646             config_dock_floating = FALSE,
647             config_dock_pos = OB_DIRECTION_SOUTHEAST;
648         else if (obt_xml_node_contains(n, "Bottom"))
649             config_dock_floating = FALSE,
650             config_dock_pos = OB_DIRECTION_SOUTH;
651         else if (obt_xml_node_contains(n, "BottomLeft"))
652             config_dock_floating = FALSE,
653             config_dock_pos = OB_DIRECTION_SOUTHWEST;
654         else if (obt_xml_node_contains(n, "Left"))
655             config_dock_floating = FALSE,
656             config_dock_pos = OB_DIRECTION_WEST;
657         else if (obt_xml_node_contains(n, "Floating"))
658             config_dock_floating = TRUE;
659     }
660     if (config_dock_floating) {
661         if ((n = obt_xml_find_sibling(node, "floatingX")))
662             config_dock_x = obt_xml_node_int(n);
663         if ((n = obt_xml_find_sibling(node, "floatingY")))
664             config_dock_y = obt_xml_node_int(n);
665     } else {
666         if ((n = obt_xml_find_sibling(node, "noStrut")))
667             config_dock_nostrut = obt_xml_node_bool(n);
668     }
669     if ((n = obt_xml_find_sibling(node, "stacking"))) {
670         if (obt_xml_node_contains(n, "normal"))
671             config_dock_layer = OB_STACKING_LAYER_NORMAL;
672         else if (obt_xml_node_contains(n, "below"))
673             config_dock_layer = OB_STACKING_LAYER_BELOW;
674         else if (obt_xml_node_contains(n, "above"))
675             config_dock_layer = OB_STACKING_LAYER_ABOVE;
676     }
677     if ((n = obt_xml_find_sibling(node, "direction"))) {
678         if (obt_xml_node_contains(n, "horizontal"))
679             config_dock_orient = OB_ORIENTATION_HORZ;
680         else if (obt_xml_node_contains(n, "vertical"))
681             config_dock_orient = OB_ORIENTATION_VERT;
682     }
683     if ((n = obt_xml_find_sibling(node, "autoHide")))
684         config_dock_hide = obt_xml_node_bool(n);
685     if ((n = obt_xml_find_sibling(node, "hideDelay")))
686         config_dock_hide_delay = obt_xml_node_int(n);
687     if ((n = obt_xml_find_sibling(node, "showDelay")))
688         config_dock_show_delay = obt_xml_node_int(n);
689     if ((n = obt_xml_find_sibling(node, "moveButton"))) {
690         gchar *str = obt_xml_node_string(n);
691         guint b, s;
692         if (translate_button(str, &s, &b)) {
693             config_dock_app_move_button = b;
694             config_dock_app_move_modifiers = s;
695         } else {
696             g_message(_("Invalid button \"%s\" specified in config file"), str);
697         }
698         g_free(str);
699     }
700 }
701
702 static void parse_menu(xmlNodePtr node, gpointer d)
703 {
704     xmlNodePtr n;
705     node = node->children;
706
707     if ((n = obt_xml_find_sibling(node, "hideDelay")))
708         config_menu_hide_delay = obt_xml_node_int(n);
709     if ((n = obt_xml_find_sibling(node, "middle")))
710         config_menu_middle = obt_xml_node_bool(n);
711     if ((n = obt_xml_find_sibling(node, "submenuShowDelay")))
712         config_submenu_show_delay = obt_xml_node_int(n);
713     if ((n = obt_xml_find_sibling(node, "submenuHideDelay")))
714         config_submenu_hide_delay = obt_xml_node_int(n);
715     if ((n = obt_xml_find_sibling(node, "manageDesktops")))
716         config_menu_manage_desktops = obt_xml_node_bool(n);
717     if ((n = obt_xml_find_sibling(node, "showIcons"))) {
718         config_menu_show_icons = obt_xml_node_bool(n);
719 #ifndef USE_IMLIB2
720         if (config_menu_show_icons)
721             g_message(_("Openbox was compiled without Imlib2 image loading support. Icons in menus will not be loaded."));
722 #endif
723     }
724
725     while ((node = obt_xml_find_sibling(node, "file"))) {
726             gchar *c = obt_xml_node_string(node);
727             config_menu_files = g_slist_append(config_menu_files,
728                                                obt_paths_expand_tilde(c));
729             g_free(c);
730             node = node->next;
731     }
732 }
733
734 static void parse_resistance(xmlNodePtr node, gpointer d)
735 {
736     xmlNodePtr n;
737
738     node = node->children;
739     if ((n = obt_xml_find_sibling(node, "strength")))
740         config_resist_win = obt_xml_node_int(n);
741     if ((n = obt_xml_find_sibling(node, "screen_edge_strength")))
742         config_resist_edge = obt_xml_node_int(n);
743 }
744
745 typedef struct
746 {
747     const gchar *key;
748     const gchar *actiontext;
749 } ObDefKeyBind;
750
751 static void bind_default_keyboard(void)
752 {
753     ObDefKeyBind *it;
754     ObDefKeyBind binds[] = {
755         { "A-Tab", "NextWindow" },
756         { "S-A-Tab", "PreviousWindow" },
757         { "A-F4", "Close" },
758         { NULL, NULL }
759     };
760     ObActionParser *p;
761
762     p = action_parser_new();
763     for (it = binds; it->key; ++it) {
764         GList *l = g_list_append(NULL, g_strdup(it->key));
765         ObActionList *actions = action_parser_read_string(p, it->actiontext);
766         keyboard_bind(l, actions);
767         action_list_unref(actions);
768     }
769     action_parser_unref(p);
770 }
771
772 typedef struct
773 {
774     const gchar *button;
775     const gchar *context;
776     const ObMouseAction mact;
777     const gchar *actname;
778 } ObDefMouseBind;
779
780 static void bind_default_mouse(void)
781 {
782     ObDefMouseBind *it;
783     ObDefMouseBind binds[] = {
784         { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
785         { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
786         { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
787         { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
788         { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
789         { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
790         { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
791         { "Left", "Bottom", OB_MOUSE_ACTION_PRESS, "Focus" },
792         { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
793         { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
794         { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
795         { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
796         { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
797         { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
798         { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
799         { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
800         { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
801         { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
802         { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
803         { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
804         { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
805         { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
806         { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
807         { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
808         { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
809         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
810         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
811         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
812         { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
813         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
814         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
815         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
816         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Maximize" },
817         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
818         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Omnipresent" },
819         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Shade" },
820         { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
821         { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
822         { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
823         { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
824         { "Left", "Top", OB_MOUSE_ACTION_MOTION, "Resize" },
825         { "Left", "Bottom", OB_MOUSE_ACTION_MOTION, "Resize" },
826         { "Left", "Left", OB_MOUSE_ACTION_MOTION, "Resize" },
827         { "Left", "Right", OB_MOUSE_ACTION_MOTION, "Resize" },
828         { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
829         { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
830         { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
831         { NULL, NULL, 0, NULL }
832     };
833     ObActionParser *p;
834     ObActionList *actions;
835
836     p = action_parser_new();
837     for (it = binds; it->button; ++it) {
838         actions = action_parser_read_string(p, it->actname);
839         mouse_bind(it->button, frame_context_from_string(it->context),
840                    it->mact, actions);
841         action_list_unref(actions);
842     }
843     action_parser_unref(p);
844 }
845
846 static ObtXmlInst *config_inst = NULL;
847
848 void config_startup()
849 {
850 }
851
852 void config_shutdown(void)
853 {
854     GSList *it;
855
856     g_free(config_theme);
857
858     g_free(config_title_layout);
859
860     RrFontClose(config_font_activewindow);
861     RrFontClose(config_font_inactivewindow);
862     RrFontClose(config_font_menuitem);
863     RrFontClose(config_font_menutitle);
864     RrFontClose(config_font_activeosd);
865     RrFontClose(config_font_inactiveosd);
866
867     for (it = config_desktops_names; it; it = g_slist_next(it))
868         g_free(it->data);
869     g_slist_free(config_desktops_names);
870
871     for (it = config_menu_files; it; it = g_slist_next(it))
872         g_free(it->data);
873     g_slist_free(config_menu_files);
874
875     for (it = config_per_app_settings; it; it = g_slist_next(it)) {
876         ObAppSettings *itd = (ObAppSettings *)it->data;
877         if (itd->name)  g_pattern_spec_free(itd->name);
878         if (itd->role)  g_pattern_spec_free(itd->role);
879         if (itd->title) g_pattern_spec_free(itd->title);
880         if (itd->class) g_pattern_spec_free(itd->class);
881         g_slice_free(ObAppSettings, it->data);
882     }
883     g_slist_free(config_per_app_settings);
884 }
885
886 void config_load_config(void)
887 {
888     xmlNodePtr n, root, e;
889     gboolean ok;
890     gchar *c;
891
892     config_inst = obt_xml_instance_new();
893     ok = obt_xml_load_cache_file(config_inst, "openbox", "config", "config");
894     root = obt_xml_root(config_inst);
895
896     /* focus */
897     n = obt_xml_path_get_node(root, "focus", "");
898     config_focus_new = obt_xml_path_bool(n, "focusNew", "yes");
899     config_focus_follow = obt_xml_path_bool(n, "followMouse", "no");
900     config_focus_delay = obt_xml_path_int(n, "focusDelay", "0");
901     config_focus_raise = obt_xml_path_bool(n, "raiseOnFocus", "no");
902     config_focus_last = obt_xml_path_bool(n, "focusLast", "yes");
903     config_focus_under_mouse = obt_xml_path_bool(n, "underMouse", "no");
904     config_unfocus_leave = obt_xml_path_bool(n, "unfocusOnLeave", "no");
905
906     /* placement */
907     n = obt_xml_path_get_node(root, "placement", "");
908     e = obt_xml_path_get_node(n, "policy", "smart");
909     if (obt_xml_node_contains(e, "smart"))
910         config_place_policy = OB_PLACE_POLICY_SMART;
911     else if (obt_xml_node_contains(e, "undermouse"))
912         config_place_policy = OB_PLACE_POLICY_MOUSE;
913     else
914         config_place_policy = OB_PLACE_POLICY_SMART;
915     config_place_center = obt_xml_path_bool(n, "center", "true");
916     e = obt_xml_path_get_node(n, "monitor", "primary");
917     if (obt_xml_node_contains(e, "primary"))
918         config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
919     else if (obt_xml_node_contains(e, "active"))
920         config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
921     else if (obt_xml_node_contains(e, "mouse"))
922         config_place_monitor = OB_PLACE_MONITOR_MOUSE;
923     else if (obt_xml_node_contains(e, "any"))
924         config_place_monitor = OB_PLACE_MONITOR_ANY;
925     else
926         config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
927     e = obt_xml_path_get_node(n, "primaryMonitor", "1");
928     if (obt_xml_node_contains(e, "active")) {
929         config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
930         config_primary_monitor_index = 1;
931     }
932     else if (obt_xml_node_contains(e, "mouse")) {
933         config_primary_monitor = OB_PLACE_MONITOR_MOUSE;
934         config_primary_monitor_index = 1;
935     }
936     else {
937         config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
938         config_primary_monitor_index = obt_xml_node_int(e);
939     }
940
941     /* margins */
942     n = obt_xml_path_get_node(root, "margins", "");
943     STRUT_PARTIAL_SET(config_margins, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
944     config_margins.top = MAX(0, obt_xml_path_int(n, "top", "0"));
945     config_margins.left = MAX(0, obt_xml_path_int(n, "left", "0"));
946     config_margins.right = MAX(0, obt_xml_path_int(n, "right", "0"));
947     config_margins.bottom = MAX(0, obt_xml_path_int(n, "bottom", "0"));
948
949     /* theme */
950     n = obt_xml_path_get_node(root, "theme", "");
951     g_free(config_theme);
952     c = obt_xml_path_string(n, "name", NULL);
953     config_theme = obt_paths_expand_tilde(c);
954     g_free(c);
955
956     g_free(config_title_layout);
957     config_title_layout = obt_xml_path_string(n, "titleLayout", "NLIMC");
958     /* replace duplicates with spaces */
959     for (c = config_title_layout; *c != '\0'; ++c)
960         for (d = c+1; *d != '\0'; ++d)
961             if (*c == *d) *d = ' ';
962
963     config_animate_iconify = obt_xml_path_bool(n, "animateIconify", "true");
964     config_theme_keepborder = obt_xml_path_bool(n, "keepBorder", "true");
965     config_theme_window_list_icon_size =
966         MAX(16, MIN(96, obt_xml_path_int(n, "windowListIconSize", 36)));
967
968     RrFontClose(config_font_activewindow);
969     config_font_activewindow = read_font(n, "font:place=ActiveWindow");
970     RrFontClose(config_font_inactivewindow);
971     config_font_inactivewindow = read_font(n, "font:place=InactiveWindow");
972     RrFontClose(config_font_menuitem);
973     config_font_menuitem = read_font(n, "font:place=MenuItem");
974     RrFontClose(config_font_menutitle);
975     config_font_menutitle = read_font(n, "font:place=MenuHeader");
976     RrFontClose(config_font_activeosd);
977     config_font_activeosd = read_font(n, "font:place=ActiveOnScreenDisplay");
978     RrFontClose(config_font_inactiveosd);
979     config_font_inactiveosd = read_font(n, "font:place=InactiveOnScreenDisplay");
980
981     obt_xml_register(config_inst, "theme", parse_theme, NULL);
982 static void parse_theme(xmlNodePtr node, gpointer d)
983 {
984
985     n = obt_xml_find_sibling(node, "font");
986     while (n) {
987         xmlNodePtr   fnode;
988         RrFont     **font;
989         gchar       *name = g_strdup(RrDefaultFontFamily);
990         gint         size = RrDefaultFontSize;
991         RrFontWeight weight = RrDefaultFontWeight;
992         RrFontSlant  slant = RrDefaultFontSlant;
993
994         if (obt_xml_attr_contains(n, "place", "ActiveWindow"))
995             font = &config_font_activewindow;
996         else if (obt_xml_attr_contains(n, "place", "InactiveWindow"))
997             font = &config_font_inactivewindow;
998         else if (obt_xml_attr_contains(n, "place", "MenuHeader"))
999             font = &config_font_menutitle;
1000         else if (obt_xml_attr_contains(n, "place", "MenuItem"))
1001             font = &config_font_menuitem;
1002         else if (obt_xml_attr_contains(n, "place", "ActiveOnScreenDisplay"))
1003             font = &config_font_activeosd;
1004         else if (obt_xml_attr_contains(n, "place", "OnScreenDisplay"))
1005             font = &config_font_activeosd;
1006         else if (obt_xml_attr_contains(n, "place","InactiveOnScreenDisplay"))
1007             font = &config_font_inactiveosd;
1008         else
1009             goto next_font;
1010
1011         if ((fnode = obt_xml_find_sibling(n->children, "name"))) {
1012             g_free(name);
1013             name = obt_xml_node_string(fnode);
1014         }
1015         if ((fnode = obt_xml_find_sibling(n->children, "size"))) {
1016             int s = obt_xml_node_int(fnode);
1017             if (s > 0) size = s;
1018         }
1019         if ((fnode = obt_xml_find_sibling(n->children, "weight"))) {
1020             gchar *w = obt_xml_node_string(fnode);
1021             if (!g_ascii_strcasecmp(w, "Bold"))
1022                 weight = RR_FONTWEIGHT_BOLD;
1023             g_free(w);
1024         }
1025         if ((fnode = obt_xml_find_sibling(n->children, "slant"))) {
1026             gchar *s = obt_xml_node_string(fnode);
1027             if (!g_ascii_strcasecmp(s, "Italic"))
1028                 slant = RR_FONTSLANT_ITALIC;
1029             if (!g_ascii_strcasecmp(s, "Oblique"))
1030                 slant = RR_FONTSLANT_OBLIQUE;
1031             g_free(s);
1032         }
1033
1034         *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
1035         g_free(name);
1036     next_font:
1037         n = obt_xml_find_sibling(n->next, "font");
1038     }
1039 }
1040
1041     config_desktops_num = 4;
1042     config_screen_firstdesk = 1;
1043     config_desktops_names = NULL;
1044     config_desktop_popup_time = 875;
1045
1046     obt_xml_register(config_inst, "desktops", parse_desktops, NULL);
1047
1048     config_resize_redraw = TRUE;
1049     config_resize_popup_show = 1; /* nonpixel increments */
1050     config_resize_popup_pos = OB_RESIZE_POS_CENTER;
1051     GRAVITY_COORD_SET(config_resize_popup_fixed.x, 0, FALSE, FALSE);
1052     GRAVITY_COORD_SET(config_resize_popup_fixed.y, 0, FALSE, FALSE);
1053
1054     obt_xml_register(config_inst, "resize", parse_resize, NULL);
1055
1056     config_dock_layer = OB_STACKING_LAYER_ABOVE;
1057     config_dock_pos = OB_DIRECTION_NORTHEAST;
1058     config_dock_floating = FALSE;
1059     config_dock_nostrut = FALSE;
1060     config_dock_x = 0;
1061     config_dock_y = 0;
1062     config_dock_orient = OB_ORIENTATION_VERT;
1063     config_dock_hide = FALSE;
1064     config_dock_hide_delay = 300;
1065     config_dock_show_delay = 300;
1066     config_dock_app_move_button = 2; /* middle */
1067     config_dock_app_move_modifiers = 0;
1068
1069     obt_xml_register(config_inst, "dock", parse_dock, NULL);
1070
1071     translate_key("C-g", &config_keyboard_reset_state,
1072                   &config_keyboard_reset_keycode);
1073
1074     obt_xml_register(config_inst, "keyboard", parse_keyboard, NULL);
1075
1076     config_mouse_threshold = 8;
1077     config_mouse_dclicktime = 200;
1078     config_mouse_screenedgetime = 400;
1079     config_mouse_screenedgewarp = FALSE;
1080
1081     obt_xml_register(config_inst, "mouse", parse_mouse, NULL);
1082
1083     config_resist_win = 10;
1084     config_resist_edge = 20;
1085
1086     obt_xml_register(config_inst, "resistance", parse_resistance, NULL);
1087
1088     config_menu_hide_delay = 250;
1089     config_menu_middle = FALSE;
1090     config_submenu_show_delay = 100;
1091     config_submenu_hide_delay = 400;
1092     config_menu_manage_desktops = TRUE;
1093     config_menu_files = NULL;
1094     config_menu_show_icons = TRUE;
1095
1096     obt_xml_register(config_inst, "menu", parse_menu, NULL);
1097
1098
1099     if (ok) {
1100         obt_xml_tree_from_root(config_inst);
1101         obt_xml_close(config_inst);
1102     }
1103 }
1104
1105 void config_save_config(void)
1106 {
1107     xmlNodePtr n, root;
1108     const gchar *e;
1109
1110     root = obt_xml_root(config_inst);
1111
1112     n = obt_xml_path_get_node(root, "focus", "");
1113     obt_xml_path_set_bool(n, "focusNew", config_focus_new);
1114     obt_xml_path_set_bool(n, "followMouse", config_focus_follow);
1115     obt_xml_path_set_int(n, "focusDelay", config_focus_delay);
1116     obt_xml_path_set_bool(n, "raiseOnFocus", config_focus_raise);
1117     obt_xml_path_set_bool(n, "focusLast", config_focus_last);
1118     obt_xml_path_set_bool(n, "underMouse", config_focus_under_mouse);
1119     obt_xml_path_set_bool(n, "unfocusOnLeave", config_unfocus_leave);
1120
1121     n = obt_xml_path_get_node(root, "placement", "");
1122     switch (config_place_policy) {
1123     case OB_PLACE_POLICY_SMART: e = "smart"; break;
1124     case OB_PLACE_POLICY_MOUSE: e = "mouse"; break;
1125     }
1126     obt_xml_path_set_string(n, "policy", e);
1127     obt_xml_path_set_bool(n, "center", config_place_center);
1128     switch (config_place_monitor) {
1129     case OB_PLACE_MONITOR_PRIMARY: e = "primary"; break;
1130     case OB_PLACE_MONITOR_ACTIVE: e = "active"; break;
1131     case OB_PLACE_MONITOR_MOUSE: e = "mouse"; break;
1132     case OB_PLACE_MONITOR_ANY: e = "any"; break;
1133     }
1134     obt_xml_path_set_string(n, "monitor", e);
1135     if (config_primary_monitor_index)
1136         obt_xml_path_set_int(
1137             n, "primaryMonitor", config_primary_monitor_index);
1138     else {
1139         switch (config_primary_monitor) {
1140         case OB_PLACE_MONITOR_ACTIVE: e = "active"; break;
1141         case OB_PLACE_MONITOR_MOUSE: e = "mouse"; break;
1142         case OB_PLACE_MONITOR_PRIMARY: 
1143         case OB_PLACE_MONITOR_ANY: g_assert_not_reached();
1144         }
1145         obt_xml_path_set_string(n, "primaryMonitor", e);
1146     }
1147
1148     n = obt_xml_path_get_node(root, "margins", "");
1149     obt_xml_path_set_int(n, "top", config_margins.top);
1150     obt_xml_path_set_int(n, "left", config_margins.left);
1151     obt_xml_path_set_int(n, "right", config_margins.right);
1152     obt_xml_path_set_int(n, "bottom", config_margins.bottom);
1153
1154     if (!obt_xml_save_cache_file(config_inst, "openbox", "config", TRUE))
1155         g_warning("Unable to save configuration in XDG cache directory.");
1156     obt_xml_instance_unref(config_inst);
1157     config_inst = NULL;
1158 }
1159
1160 gboolean config_load_keys(void)
1161 {
1162     ObtXmlInst *i = obt_xml_instance_new();
1163     gboolean ok;
1164
1165     ok = obt_xml_load_config_file(i, "openbox", "keys", "keys");
1166     if (!ok)
1167         bind_default_keyboard();
1168     else {
1169         xmlNodePtr n, r;
1170
1171         r = obt_xml_root(i);
1172         if ((n = obt_xml_find_sibling(r->children, "keybind")))
1173             while (n) {
1174                 parse_keybind(n, NULL);
1175                 n = obt_xml_find_sibling(n->next, "keybind");
1176             }
1177     }
1178     obt_xml_instance_unref(i);
1179     return ok;
1180 }
1181
1182 gboolean config_load_mouse(void)
1183 {
1184     ObtXmlInst *i = obt_xml_instance_new();
1185     gboolean ok;
1186
1187     obt_xml_register(i, "context", parse_context, NULL);
1188
1189     ok = obt_xml_load_config_file(i, "openbox", "mouse", "mouse");
1190     if (!ok)
1191         bind_default_mouse();
1192     else {
1193         obt_xml_tree_from_root(i);
1194         obt_xml_close(i);
1195     }
1196     obt_xml_instance_unref(i);
1197     return ok;
1198 }
1199
1200 gboolean config_load_windows(void)
1201 {
1202     ObtXmlInst *i = obt_xml_instance_new();
1203     gboolean ok;
1204
1205     config_per_app_settings = NULL;
1206     obt_xml_register(i, "applications", parse_per_app_settings, NULL);
1207
1208     ok = obt_xml_load_config_file(
1209         i, "openbox", "applications", "applications");
1210     if (ok) {
1211         obt_xml_tree_from_root(i);
1212         obt_xml_close(i);
1213     }
1214     obt_xml_instance_unref(i);
1215     return ok;
1216 }