]> icculus.org git repositories - mikachu/openbox.git/blob - openbox/config.c
Don't update hints when the title is the same.
[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         if (obt_xml_node_contains(n, "Random"))
662             config_place_policy = OB_PLACE_POLICY_RANDOM;
663     }
664     if ((n = obt_xml_find_node(node, "center"))) {
665         config_place_center = obt_xml_node_bool(n);
666     }
667     if ((n = obt_xml_find_node(node, "monitor"))) {
668         if (obt_xml_node_contains(n, "active"))
669             config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
670         else if (obt_xml_node_contains(n, "mouse"))
671             config_place_monitor = OB_PLACE_MONITOR_MOUSE;
672         else if (obt_xml_node_contains(n, "any"))
673             config_place_monitor = OB_PLACE_MONITOR_ANY;
674     }
675     if ((n = obt_xml_find_node(node, "primaryMonitor"))) {
676         config_primary_monitor_index = obt_xml_node_int(n);
677         if (!config_primary_monitor_index) {
678             if (obt_xml_node_contains(n, "mouse"))
679                 config_primary_monitor = OB_PLACE_MONITOR_MOUSE;
680         }
681     }
682 }
683
684 static void parse_margins(xmlNodePtr node, gpointer d)
685 {
686     xmlNodePtr n;
687
688     node = node->children;
689
690     if ((n = obt_xml_find_node(node, "top")))
691         config_margins.top = MAX(0, obt_xml_node_int(n));
692     if ((n = obt_xml_find_node(node, "left")))
693         config_margins.left = MAX(0, obt_xml_node_int(n));
694     if ((n = obt_xml_find_node(node, "right")))
695         config_margins.right = MAX(0, obt_xml_node_int(n));
696     if ((n = obt_xml_find_node(node, "bottom")))
697         config_margins.bottom = MAX(0, obt_xml_node_int(n));
698 }
699
700 static void parse_theme(xmlNodePtr node, gpointer d)
701 {
702     xmlNodePtr n;
703
704     node = node->children;
705
706     if ((n = obt_xml_find_node(node, "name"))) {
707         gchar *c;
708
709         g_free(config_theme);
710         c = obt_xml_node_string(n);
711         config_theme = obt_paths_expand_tilde(c);
712         g_free(c);
713     }
714     if ((n = obt_xml_find_node(node, "titleLayout"))) {
715         gchar *c, *d;
716
717         g_free(config_title_layout);
718         config_title_layout = obt_xml_node_string(n);
719
720         /* replace duplicates with spaces */
721         for (c = config_title_layout; *c != '\0'; ++c)
722             for (d = c+1; *d != '\0'; ++d)
723                 if (*c == *d) *d = ' ';
724     }
725     if ((n = obt_xml_find_node(node, "keepBorder")))
726         config_theme_keepborder = obt_xml_node_bool(n);
727     if ((n = obt_xml_find_node(node, "animateIconify")))
728         config_animate_iconify = obt_xml_node_bool(n);
729     if ((n = obt_xml_find_node(node, "windowListIconSize"))) {
730         config_theme_window_list_icon_size = obt_xml_node_int(n);
731         if (config_theme_window_list_icon_size < 16)
732             config_theme_window_list_icon_size = 16;
733         else if (config_theme_window_list_icon_size > 96)
734             config_theme_window_list_icon_size = 96;
735     }
736
737     for (n = obt_xml_find_node(node, "font");
738          n;
739          n = obt_xml_find_node(n->next, "font"))
740     {
741         xmlNodePtr   fnode;
742         RrFont     **font;
743         gchar       *name = g_strdup(RrDefaultFontFamily);
744         gint         size = RrDefaultFontSize;
745         RrFontWeight weight = RrDefaultFontWeight;
746         RrFontSlant  slant = RrDefaultFontSlant;
747
748         if (obt_xml_attr_contains(n, "place", "ActiveWindow"))
749             font = &config_font_activewindow;
750         else if (obt_xml_attr_contains(n, "place", "InactiveWindow"))
751             font = &config_font_inactivewindow;
752         else if (obt_xml_attr_contains(n, "place", "MenuHeader"))
753             font = &config_font_menutitle;
754         else if (obt_xml_attr_contains(n, "place", "MenuItem"))
755             font = &config_font_menuitem;
756         else if (obt_xml_attr_contains(n, "place", "ActiveOnScreenDisplay"))
757             font = &config_font_activeosd;
758         else if (obt_xml_attr_contains(n, "place", "OnScreenDisplay"))
759             font = &config_font_activeosd;
760         else if (obt_xml_attr_contains(n, "place","InactiveOnScreenDisplay"))
761             font = &config_font_inactiveosd;
762         else
763             continue;
764
765         if ((fnode = obt_xml_find_node(n->children, "name"))) {
766             g_free(name);
767             name = obt_xml_node_string(fnode);
768         }
769         if ((fnode = obt_xml_find_node(n->children, "size"))) {
770             int s = obt_xml_node_int(fnode);
771             if (s > 0) size = s;
772         }
773         if ((fnode = obt_xml_find_node(n->children, "weight"))) {
774             gchar *w = obt_xml_node_string(fnode);
775             if (!g_ascii_strcasecmp(w, "Bold"))
776                 weight = RR_FONTWEIGHT_BOLD;
777             g_free(w);
778         }
779         if ((fnode = obt_xml_find_node(n->children, "slant"))) {
780             gchar *s = obt_xml_node_string(fnode);
781             if (!g_ascii_strcasecmp(s, "Italic"))
782                 slant = RR_FONTSLANT_ITALIC;
783             if (!g_ascii_strcasecmp(s, "Oblique"))
784                 slant = RR_FONTSLANT_OBLIQUE;
785             g_free(s);
786         }
787
788         *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
789         g_free(name);
790
791         if ((fnode = obt_xml_find_node(n->children, "description"))) {
792             gchar *s = obt_xml_node_string(fnode);
793             RrFontDescriptionFromString(*font, s);
794             g_free(s);
795         }
796     }
797 }
798
799 static void parse_desktops(xmlNodePtr node, gpointer d)
800 {
801     xmlNodePtr n;
802
803     node = node->children;
804
805     if ((n = obt_xml_find_node(node, "number"))) {
806         gint d = obt_xml_node_int(n);
807         if (d > 0)
808             config_desktops_num = (unsigned) d;
809     }
810     if ((n = obt_xml_find_node(node, "firstdesk"))) {
811         gint d = obt_xml_node_int(n);
812         if (d > 0)
813             config_screen_firstdesk = (unsigned) d;
814     }
815     if ((n = obt_xml_find_node(node, "names"))) {
816         GSList *it;
817         xmlNodePtr nname;
818
819         for (it = config_desktops_names; it; it = it->next)
820             g_free(it->data);
821         g_slist_free(config_desktops_names);
822         config_desktops_names = NULL;
823
824         for (nname = obt_xml_find_node(n->children, "name");
825              nname;
826              nname = obt_xml_find_node(nname->next, "name"))
827         {
828             config_desktops_names =
829                 g_slist_append(config_desktops_names,
830                                obt_xml_node_string(nname));
831         }
832     }
833     if ((n = obt_xml_find_node(node, "popupTime")))
834         config_desktop_popup_time = obt_xml_node_int(n);
835 }
836
837 static void parse_resize(xmlNodePtr node, gpointer d)
838 {
839     xmlNodePtr n;
840
841     node = node->children;
842
843     if ((n = obt_xml_find_node(node, "drawContents")))
844         config_resize_redraw = obt_xml_node_bool(n);
845     if ((n = obt_xml_find_node(node, "popupShow"))) {
846         config_resize_popup_show = obt_xml_node_int(n);
847         if (obt_xml_node_contains(n, "Always"))
848             config_resize_popup_show = 2;
849         else if (obt_xml_node_contains(n, "Never"))
850             config_resize_popup_show = 0;
851         else if (obt_xml_node_contains(n, "Nonpixel"))
852             config_resize_popup_show = 1;
853     }
854     if ((n = obt_xml_find_node(node, "popupPosition"))) {
855         if (obt_xml_node_contains(n, "Top"))
856             config_resize_popup_pos = OB_RESIZE_POS_TOP;
857         else if (obt_xml_node_contains(n, "Center"))
858             config_resize_popup_pos = OB_RESIZE_POS_CENTER;
859         else if (obt_xml_node_contains(n, "Fixed")) {
860             config_resize_popup_pos = OB_RESIZE_POS_FIXED;
861
862             if ((n = obt_xml_find_node(node, "popupFixedPosition"))) {
863                 xmlNodePtr n2;
864
865                 if ((n2 = obt_xml_find_node(n->children, "x")))
866                     config_parse_gravity_coord(n2,
867                                                &config_resize_popup_fixed.x);
868                 if ((n2 = obt_xml_find_node(n->children, "y")))
869                     config_parse_gravity_coord(n2,
870                                                &config_resize_popup_fixed.y);
871
872                 config_resize_popup_fixed.x.pos =
873                     MAX(config_resize_popup_fixed.x.pos, 0);
874                 config_resize_popup_fixed.y.pos =
875                     MAX(config_resize_popup_fixed.y.pos, 0);
876             }
877         }
878     }
879 }
880
881 static void parse_dock(xmlNodePtr node, gpointer d)
882 {
883     xmlNodePtr n;
884
885     node = node->children;
886
887     if ((n = obt_xml_find_node(node, "position"))) {
888         if (obt_xml_node_contains(n, "TopLeft"))
889             config_dock_floating = FALSE,
890             config_dock_pos = OB_DIRECTION_NORTHWEST;
891         else if (obt_xml_node_contains(n, "Top"))
892             config_dock_floating = FALSE,
893             config_dock_pos = OB_DIRECTION_NORTH;
894         else if (obt_xml_node_contains(n, "TopRight"))
895             config_dock_floating = FALSE,
896             config_dock_pos = OB_DIRECTION_NORTHEAST;
897         else if (obt_xml_node_contains(n, "Right"))
898             config_dock_floating = FALSE,
899             config_dock_pos = OB_DIRECTION_EAST;
900         else if (obt_xml_node_contains(n, "BottomRight"))
901             config_dock_floating = FALSE,
902             config_dock_pos = OB_DIRECTION_SOUTHEAST;
903         else if (obt_xml_node_contains(n, "Bottom"))
904             config_dock_floating = FALSE,
905             config_dock_pos = OB_DIRECTION_SOUTH;
906         else if (obt_xml_node_contains(n, "BottomLeft"))
907             config_dock_floating = FALSE,
908             config_dock_pos = OB_DIRECTION_SOUTHWEST;
909         else if (obt_xml_node_contains(n, "Left"))
910             config_dock_floating = FALSE,
911             config_dock_pos = OB_DIRECTION_WEST;
912         else if (obt_xml_node_contains(n, "Floating"))
913             config_dock_floating = TRUE;
914     }
915     if (config_dock_floating) {
916         if ((n = obt_xml_find_node(node, "floatingX")))
917             config_dock_x = obt_xml_node_int(n);
918         if ((n = obt_xml_find_node(node, "floatingY")))
919             config_dock_y = obt_xml_node_int(n);
920     } else {
921         if ((n = obt_xml_find_node(node, "noStrut")))
922             config_dock_nostrut = obt_xml_node_bool(n);
923     }
924     if ((n = obt_xml_find_node(node, "stacking"))) {
925         if (obt_xml_node_contains(n, "normal"))
926             config_dock_layer = OB_STACKING_LAYER_NORMAL;
927         else if (obt_xml_node_contains(n, "below"))
928             config_dock_layer = OB_STACKING_LAYER_BELOW;
929         else if (obt_xml_node_contains(n, "above"))
930             config_dock_layer = OB_STACKING_LAYER_ABOVE;
931     }
932     if ((n = obt_xml_find_node(node, "direction"))) {
933         if (obt_xml_node_contains(n, "horizontal"))
934             config_dock_orient = OB_ORIENTATION_HORZ;
935         else if (obt_xml_node_contains(n, "vertical"))
936             config_dock_orient = OB_ORIENTATION_VERT;
937     }
938     if ((n = obt_xml_find_node(node, "autoHide")))
939         config_dock_hide = obt_xml_node_bool(n);
940     if ((n = obt_xml_find_node(node, "hideDelay")))
941         config_dock_hide_delay = obt_xml_node_int(n);
942     if ((n = obt_xml_find_node(node, "showDelay")))
943         config_dock_show_delay = obt_xml_node_int(n);
944     if ((n = obt_xml_find_node(node, "moveButton"))) {
945         gchar *str = obt_xml_node_string(n);
946         guint b = 0, s = 0;
947         if (translate_button(str, &s, &b)) {
948             config_dock_app_move_button = b;
949             config_dock_app_move_modifiers = s;
950         } else {
951             g_message(_("Invalid button \"%s\" specified in config file"), str);
952         }
953         g_free(str);
954     }
955 }
956
957 static void parse_menu(xmlNodePtr node, gpointer d)
958 {
959     xmlNodePtr n;
960     node = node->children;
961
962     if ((n = obt_xml_find_node(node, "hideDelay")))
963         config_menu_hide_delay = obt_xml_node_int(n);
964     if ((n = obt_xml_find_node(node, "middle")))
965         config_menu_middle = obt_xml_node_bool(n);
966     if ((n = obt_xml_find_node(node, "submenuShowDelay")))
967         config_submenu_show_delay = obt_xml_node_int(n);
968     if ((n = obt_xml_find_node(node, "submenuHideDelay")))
969         config_submenu_hide_delay = obt_xml_node_int(n);
970     if ((n = obt_xml_find_node(node, "manageDesktops")))
971         config_menu_manage_desktops = obt_xml_node_bool(n);
972     if ((n = obt_xml_find_node(node, "showIcons"))) {
973         config_menu_show_icons = obt_xml_node_bool(n);
974 #if !defined(USE_IMLIB2) && !defined(USE_LIBRSVG)
975         if (config_menu_show_icons)
976             g_message(_("Openbox was compiled without image loading support. Icons in menus will not be loaded."));
977 #endif
978     }
979
980     for (node = obt_xml_find_node(node, "file");
981          node;
982          node = obt_xml_find_node(node->next, "file"))
983     {
984             gchar *c = obt_xml_node_string(node);
985             config_menu_files = g_slist_append(config_menu_files,
986                                                obt_paths_expand_tilde(c));
987             g_free(c);
988     }
989 }
990
991 static void parse_resistance(xmlNodePtr node, gpointer d)
992 {
993     xmlNodePtr n;
994
995     node = node->children;
996     if ((n = obt_xml_find_node(node, "strength")))
997         config_resist_win = obt_xml_node_int(n);
998     if ((n = obt_xml_find_node(node, "screen_edge_strength")))
999         config_resist_edge = obt_xml_node_int(n);
1000 }
1001
1002 typedef struct
1003 {
1004     const gchar *key;
1005     const gchar *actname;
1006 } ObDefKeyBind;
1007
1008 static void bind_default_keyboard(void)
1009 {
1010     ObDefKeyBind *it;
1011     ObDefKeyBind binds[] = {
1012         { "A-Tab", "NextWindow" },
1013         { "S-A-Tab", "PreviousWindow" },
1014         { "A-F4", "Close" },
1015         { NULL, NULL }
1016     };
1017     for (it = binds; it->key; ++it) {
1018         GList *l = g_list_append(NULL, g_strdup(it->key));
1019         keyboard_bind(l, actions_parse_string(it->actname), TRUE);
1020     }
1021 }
1022
1023 typedef struct
1024 {
1025     const gchar *button;
1026     const gchar *context;
1027     const ObMouseAction mact;
1028     const gchar *actname;
1029 } ObDefMouseBind;
1030
1031 static void bind_default_mouse(void)
1032 {
1033     ObDefMouseBind *it;
1034     ObDefMouseBind binds[] = {
1035         { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1036         { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1037         { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1038         { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1039         { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1040         { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1041         { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
1042         { "Left", "Bottom", OB_MOUSE_ACTION_PRESS, "Focus" },
1043         { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1044         { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1045         { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1046         { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1047         { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
1048         { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
1049         { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
1050         { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
1051         { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
1052         { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
1053         { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
1054         { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
1055         { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
1056         { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1057         { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1058         { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1059         { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1060         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
1061         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
1062         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
1063         { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
1064         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
1065         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
1066         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
1067         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximize" },
1068         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
1069         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
1070         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
1071         { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1072         { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1073         { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1074         { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1075         { "Left", "Top", OB_MOUSE_ACTION_MOTION, "Resize" },
1076         { "Left", "Bottom", OB_MOUSE_ACTION_MOTION, "Resize" },
1077         { "Left", "Left", OB_MOUSE_ACTION_MOTION, "Resize" },
1078         { "Left", "Right", OB_MOUSE_ACTION_MOTION, "Resize" },
1079         { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
1080         { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
1081         { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
1082         { NULL, NULL, 0, NULL }
1083     };
1084
1085     for (it = binds; it->button; ++it)
1086         mouse_bind(it->button, frame_context_from_string(it->context),
1087                    it->mact, actions_parse_string(it->actname));
1088 }
1089
1090 void config_startup(ObtXmlInst *i)
1091 {
1092     config_focus_new = TRUE;
1093     config_focus_follow = FALSE;
1094     config_focus_delay = 0;
1095     config_focus_raise = FALSE;
1096     config_focus_last = TRUE;
1097     config_focus_under_mouse = FALSE;
1098     config_unfocus_leave = FALSE;
1099
1100     obt_xml_register(i, "focus", parse_focus, NULL);
1101
1102     config_place_policy = OB_PLACE_POLICY_SMART;
1103     config_place_center = TRUE;
1104     config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
1105
1106     config_primary_monitor_index = 1;
1107     config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
1108
1109     obt_xml_register(i, "placement", parse_placement, NULL);
1110
1111     STRUT_PARTIAL_SET(config_margins, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1112
1113     obt_xml_register(i, "margins", parse_margins, NULL);
1114
1115     config_theme = NULL;
1116
1117     config_animate_iconify = TRUE;
1118     config_title_layout = g_strdup("NLIMC");
1119     config_theme_keepborder = TRUE;
1120     config_theme_window_list_icon_size = 36;
1121
1122     config_font_activewindow = NULL;
1123     config_font_inactivewindow = NULL;
1124     config_font_menuitem = NULL;
1125     config_font_menutitle = NULL;
1126     config_font_activeosd = NULL;
1127     config_font_inactiveosd = NULL;
1128
1129     obt_xml_register(i, "theme", parse_theme, NULL);
1130
1131     config_desktops_num = 4;
1132     config_screen_firstdesk = 1;
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 }