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