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