dummy child of all mikabox branches at 3.4.7
[mikachu/openbox.git] /
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
38 ObPlacePolicy  config_place_policy;
39 gboolean       config_place_center;
40 ObPlaceMonitor config_place_monitor;
41
42 StrutPartial config_margins;
43
44 gchar   *config_theme;
45 gboolean config_theme_keepborder;
46
47 gchar   *config_title_layout;
48
49 gboolean config_animate_iconify;
50
51 RrFont *config_font_activewindow;
52 RrFont *config_font_inactivewindow;
53 RrFont *config_font_menuitem;
54 RrFont *config_font_menutitle;
55 RrFont *config_font_osd;
56
57 guint   config_desktops_num;
58 GSList *config_desktops_names;
59 guint   config_screen_firstdesk;
60 guint   config_desktop_popup_time;
61 gint    config_emulate_xinerama;
62
63 gboolean         config_resize_redraw;
64 gint             config_resize_popup_show;
65 ObResizePopupPos config_resize_popup_pos;
66 GravityPoint     config_resize_popup_fixed;
67
68 ObStackingLayer config_dock_layer;
69 gboolean        config_dock_floating;
70 gboolean        config_dock_nostrut;
71 ObDirection     config_dock_pos;
72 gint            config_dock_x;
73 gint            config_dock_y;
74 ObOrientation   config_dock_orient;
75 gboolean        config_dock_hide;
76 guint           config_dock_hide_delay;
77 guint           config_dock_show_delay;
78 guint           config_dock_app_move_button;
79 guint           config_dock_app_move_modifiers;
80
81 guint config_keyboard_reset_keycode;
82 guint config_keyboard_reset_state;
83
84 gint config_mouse_threshold;
85 gint config_mouse_dclicktime;
86 gint config_mouse_screenedgetime;
87
88 guint    config_menu_hide_delay;
89 gboolean config_menu_middle;
90 guint    config_submenu_show_delay;
91 gboolean config_menu_client_list_icons;
92 gboolean config_menu_manage_desktops;
93
94 GSList *config_menu_files;
95
96 gint     config_resist_win;
97 gint     config_resist_edge;
98
99 GSList *config_per_app_settings;
100
101 ObAppSettings* config_create_app_settings(void)
102 {
103     ObAppSettings *settings = g_new0(ObAppSettings, 1);
104     settings->type = -1;
105     settings->decor = -1;
106     settings->shade = -1;
107     settings->monitor = -1;
108     settings->focus = -1;
109     settings->desktop = 0;
110     settings->layer = -2;
111     settings->iconic = -1;
112     settings->skip_pager = -1;
113     settings->skip_taskbar = -1;
114     settings->fullscreen = -1;
115     settings->max_horz = -1;
116     settings->max_vert = -1;
117     return settings;
118 }
119
120 #define copy_if(setting, default) \
121   if (src->setting != default) dst->setting = src->setting
122 void config_app_settings_copy_non_defaults(const ObAppSettings *src,
123                                            ObAppSettings *dst)
124 {
125     g_assert(src != NULL);
126     g_assert(dst != NULL);
127
128     copy_if(type, (ObClientType)-1);
129     copy_if(decor, -1);
130     copy_if(shade, -1);
131     copy_if(focus, -1);
132     copy_if(desktop, 0);
133     copy_if(layer, -2);
134     copy_if(iconic, -1);
135     copy_if(skip_pager, -1);
136     copy_if(skip_taskbar, -1);
137     copy_if(fullscreen, -1);
138     copy_if(max_horz, -1);
139     copy_if(max_vert, -1);
140
141     if (src->pos_given) {
142         dst->pos_given = TRUE;
143         dst->pos_force = src->pos_force;
144         dst->position = src->position;
145         dst->monitor = src->monitor;
146     }
147 }
148
149 static void config_parse_gravity_coord(xmlNodePtr node, GravityCoord *c)
150 {
151     gchar *s = obt_parse_node_string(node);
152     if (!g_ascii_strcasecmp(s, "center"))
153         c->center = TRUE;
154     else {
155         if (s[0] == '-')
156             c->opposite = TRUE;
157         if (s[0] == '-' || s[0] == '+')
158             c->pos = atoi(s+1);
159         else
160             c->pos = atoi(s);
161     }
162     g_free(s);
163 }
164
165 /*
166   <applications>
167     <application name="aterm">
168       <decor>false</decor>
169     </application>
170     <application name="Rhythmbox">
171       <layer>above</layer>
172       <position>
173         <x>700</x>
174         <y>0</y>
175         <monitor>1</monitor>
176       </position>
177       .. there is a lot more settings available
178     </application>
179   </applications>
180 */
181
182 /* Manages settings for individual applications.
183    Some notes: monitor is the screen number in a multi monitor
184    (Xinerama) setup (starting from 0) or mouse, meaning the
185    monitor the pointer is on. Default: mouse.
186    Layer can be three values, above (Always on top), below
187    (Always on bottom) and everything else (normal behaviour).
188    Positions can be an integer value or center, which will
189    center the window in the specified axis. Position is within
190    the monitor, so <position><x>center</x></position><monitor>2</monitor>
191    will center the window on the second monitor.
192 */
193 static void parse_per_app_settings(xmlNodePtr node, gpointer d)
194 {
195     xmlNodePtr app = obt_parse_find_node(node->children, "application");
196     gchar *name = NULL, *class = NULL, *role = NULL, *type = NULL;
197     gboolean name_set, class_set, type_set;
198     gboolean x_pos_given;
199
200     while (app) {
201         name_set = class_set = type_set = x_pos_given = FALSE;
202
203         class_set = obt_parse_attr_string(app, "class", &class);
204         name_set = obt_parse_attr_string(app, "name", &name);
205         type_set = obt_parse_attr_string(app, "type", &type);
206         if (class_set || name_set) {
207             xmlNodePtr n, c;
208             ObAppSettings *settings = config_create_app_settings();;
209
210             if (name_set)
211                 settings->name = g_pattern_spec_new(name);
212
213             if (class_set)
214                 settings->class = g_pattern_spec_new(class);
215
216             if (type_set) {
217                 if (!g_ascii_strcasecmp(type, "normal"))
218                     settings->type = OB_CLIENT_TYPE_NORMAL;
219                 else if (!g_ascii_strcasecmp(type, "dialog"))
220                     settings->type = OB_CLIENT_TYPE_DIALOG;
221                 else if (!g_ascii_strcasecmp(type, "splash"))
222                     settings->type = OB_CLIENT_TYPE_SPLASH;
223                 else if (!g_ascii_strcasecmp(type, "utility"))
224                     settings->type = OB_CLIENT_TYPE_UTILITY;
225                 else if (!g_ascii_strcasecmp(type, "menu"))
226                     settings->type = OB_CLIENT_TYPE_MENU;
227                 else if (!g_ascii_strcasecmp(type, "toolbar"))
228                     settings->type = OB_CLIENT_TYPE_TOOLBAR;
229                 else if (!g_ascii_strcasecmp(type, "dock"))
230                     settings->type = OB_CLIENT_TYPE_DOCK;
231                 else if (!g_ascii_strcasecmp(type, "desktop"))
232                     settings->type = OB_CLIENT_TYPE_DESKTOP;
233             }
234
235             if (obt_parse_attr_string(app, "role", &role))
236                 settings->role = g_pattern_spec_new(role);
237
238             if ((n = obt_parse_find_node(app->children, "decor")))
239                 if (!obt_parse_node_contains(n, "default"))
240                     settings->decor = obt_parse_node_bool(n);
241
242             if ((n = obt_parse_find_node(app->children, "shade")))
243                 if (!obt_parse_node_contains(n, "default"))
244                     settings->shade = obt_parse_node_bool(n);
245
246             if ((n = obt_parse_find_node(app->children, "position"))) {
247                 if ((c = obt_parse_find_node(n->children, "x")))
248                     if (!obt_parse_node_contains(c, "default")) {
249                         config_parse_gravity_coord(c, &settings->position.x);
250                         x_pos_given = TRUE;
251                     }
252
253                 if (x_pos_given && (c = obt_parse_find_node(n->children, "y")))
254                     if (!obt_parse_node_contains(c, "default")) {
255                         config_parse_gravity_coord(c, &settings->position.y);
256                         settings->pos_given = TRUE;
257                     }
258
259                 if (settings->pos_given &&
260                     (c = obt_parse_find_node(n->children, "monitor")))
261                     if (!obt_parse_node_contains(c, "default")) {
262                         gchar *s = obt_parse_node_string(c);
263                         if (!g_ascii_strcasecmp(s, "mouse"))
264                             settings->monitor = 0;
265                         else
266                             settings->monitor = obt_parse_node_int(c) + 1;
267                         g_free(s);
268                     }
269
270                 obt_parse_attr_bool(n, "force", &settings->pos_force);
271             }
272
273             if ((n = obt_parse_find_node(app->children, "focus")))
274                 if (!obt_parse_node_contains(n, "default"))
275                     settings->focus = obt_parse_node_bool(n);
276
277             if ((n = obt_parse_find_node(app->children, "desktop"))) {
278                 if (!obt_parse_node_contains(n, "default")) {
279                     gchar *s = obt_parse_node_string(n);
280                     if (!g_ascii_strcasecmp(s, "all"))
281                         settings->desktop = DESKTOP_ALL;
282                     else {
283                         gint i = obt_parse_node_int(n);
284                         if (i > 0)
285                             settings->desktop = i;
286                     }
287                     g_free(s);
288                 }
289             }
290
291             if ((n = obt_parse_find_node(app->children, "layer")))
292                 if (!obt_parse_node_contains(n, "default")) {
293                     gchar *s = obt_parse_node_string(n);
294                     if (!g_ascii_strcasecmp(s, "above"))
295                         settings->layer = 1;
296                     else if (!g_ascii_strcasecmp(s, "below"))
297                         settings->layer = -1;
298                     else
299                         settings->layer = 0;
300                     g_free(s);
301                 }
302
303             if ((n = obt_parse_find_node(app->children, "iconic")))
304                 if (!obt_parse_node_contains(n, "default"))
305                     settings->iconic = obt_parse_node_bool(n);
306
307             if ((n = obt_parse_find_node(app->children, "skip_pager")))
308                 if (!obt_parse_node_contains(n, "default"))
309                     settings->skip_pager = obt_parse_node_bool(n);
310
311             if ((n = obt_parse_find_node(app->children, "skip_taskbar")))
312                 if (!obt_parse_node_contains(n, "default"))
313                     settings->skip_taskbar = obt_parse_node_bool(n);
314
315             if ((n = obt_parse_find_node(app->children, "fullscreen")))
316                 if (!obt_parse_node_contains(n, "default"))
317                     settings->fullscreen = obt_parse_node_bool(n);
318
319             if ((n = obt_parse_find_node(app->children, "maximized")))
320                 if (!obt_parse_node_contains(n, "default")) {
321                     gchar *s = obt_parse_node_string(n);
322                     if (!g_ascii_strcasecmp(s, "horizontal")) {
323                         settings->max_horz = TRUE;
324                         settings->max_vert = FALSE;
325                     } else if (!g_ascii_strcasecmp(s, "vertical")) {
326                         settings->max_horz = FALSE;
327                         settings->max_vert = TRUE;
328                     } else
329                         settings->max_horz = settings->max_vert =
330                             obt_parse_node_bool(n);
331                     g_free(s);
332                 }
333
334             config_per_app_settings = g_slist_append(config_per_app_settings,
335                                               (gpointer) settings);
336             g_free(name);
337             g_free(class);
338             g_free(role);
339             name = class = role = NULL;
340         }
341
342         app = obt_parse_find_node(app->next, "application");
343     }
344 }
345
346 /*
347
348 <keybind key="C-x">
349   <action name="ChangeDesktop">
350     <desktop>3</desktop>
351   </action>
352 </keybind>
353
354 */
355
356 static void parse_key(xmlNodePtr node, GList *keylist)
357 {
358     gchar *key;
359     xmlNodePtr n;
360     gboolean is_chroot = FALSE;
361
362     if (!obt_parse_attr_string(node, "key", &key))
363         return;
364
365     obt_parse_attr_bool(node, "chroot", &is_chroot);
366
367     keylist = g_list_append(keylist, key);
368
369     if ((n = obt_parse_find_node(node->children, "keybind"))) {
370         while (n) {
371             parse_key(n, keylist);
372             n = obt_parse_find_node(n->next, "keybind");
373         }
374     }
375     else if ((n = obt_parse_find_node(node->children, "action"))) {
376         while (n) {
377             ObActionsAct *action;
378
379             action = actions_parse(n);
380             if (action)
381                 keyboard_bind(keylist, action);
382             n = obt_parse_find_node(n->next, "action");
383         }
384     }
385
386     if (is_chroot)
387         keyboard_chroot(keylist);
388
389     g_free(key);
390     keylist = g_list_delete_link(keylist, g_list_last(keylist));
391 }
392
393 static void parse_keyboard(xmlNodePtr node, gpointer d)
394 {
395     xmlNodePtr n;
396     gchar *key;
397
398     keyboard_unbind_all();
399
400     if ((n = obt_parse_find_node(node->children, "chainQuitKey"))) {
401         key = obt_parse_node_string(n);
402         translate_key(key, &config_keyboard_reset_state,
403                       &config_keyboard_reset_keycode);
404         g_free(key);
405     }
406
407     if ((n = obt_parse_find_node(node->children, "keybind")))
408         while (n) {
409             parse_key(n, NULL);
410             n = obt_parse_find_node(n->next, "keybind");
411         }
412 }
413
414 /*
415
416 <context name="Titlebar">
417   <mousebind button="Left" action="Press">
418     <action name="Raise"></action>
419   </mousebind>
420 </context>
421
422 */
423
424 static void parse_mouse(xmlNodePtr node, gpointer d)
425 {
426     xmlNodePtr n, nbut, nact;
427     gchar *buttonstr;
428     gchar *contextstr;
429     ObMouseAction mact;
430
431     mouse_unbind_all();
432
433     node = node->children;
434
435     if ((n = obt_parse_find_node(node, "dragThreshold")))
436         config_mouse_threshold = obt_parse_node_int(n);
437     if ((n = obt_parse_find_node(node, "doubleClickTime")))
438         config_mouse_dclicktime = obt_parse_node_int(n);
439     if ((n = obt_parse_find_node(node, "screenEdgeWarpTime")))
440         config_mouse_screenedgetime = obt_parse_node_int(n);
441
442     n = obt_parse_find_node(node, "context");
443     while (n) {
444         if (!obt_parse_attr_string(n, "name", &contextstr))
445             goto next_n;
446         nbut = obt_parse_find_node(n->children, "mousebind");
447         while (nbut) {
448             if (!obt_parse_attr_string(nbut, "button", &buttonstr))
449                 goto next_nbut;
450             if (obt_parse_attr_contains(nbut, "action", "press")) {
451                 mact = OB_MOUSE_ACTION_PRESS;
452             } else if (obt_parse_attr_contains(nbut, "action", "release")) {
453                 mact = OB_MOUSE_ACTION_RELEASE;
454             } else if (obt_parse_attr_contains(nbut, "action", "click")) {
455                 mact = OB_MOUSE_ACTION_CLICK;
456             } else if (obt_parse_attr_contains(nbut, "action","doubleclick")) {
457                 mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
458             } else if (obt_parse_attr_contains(nbut, "action", "drag")) {
459                 mact = OB_MOUSE_ACTION_MOTION;
460             } else
461                 goto next_nbut;
462             nact = obt_parse_find_node(nbut->children, "action");
463             while (nact) {
464                 ObActionsAct *action;
465
466                 if ((action = actions_parse(nact)))
467                     mouse_bind(buttonstr, contextstr, mact, action);
468                 nact = obt_parse_find_node(nact->next, "action");
469             }
470             g_free(buttonstr);
471         next_nbut:
472             nbut = obt_parse_find_node(nbut->next, "mousebind");
473         }
474         g_free(contextstr);
475     next_n:
476         n = obt_parse_find_node(n->next, "context");
477     }
478 }
479
480 static void parse_focus(xmlNodePtr node, gpointer d)
481 {
482     xmlNodePtr n;
483
484     node = node->children;
485
486     if ((n = obt_parse_find_node(node, "focusNew")))
487         config_focus_new = obt_parse_node_bool(n);
488     if ((n = obt_parse_find_node(node, "followMouse")))
489         config_focus_follow = obt_parse_node_bool(n);
490     if ((n = obt_parse_find_node(node, "focusDelay")))
491         config_focus_delay = obt_parse_node_int(n);
492     if ((n = obt_parse_find_node(node, "raiseOnFocus")))
493         config_focus_raise = obt_parse_node_bool(n);
494     if ((n = obt_parse_find_node(node, "focusLast")))
495         config_focus_last = obt_parse_node_bool(n);
496     if ((n = obt_parse_find_node(node, "underMouse")))
497         config_focus_under_mouse = obt_parse_node_bool(n);
498 }
499
500 static void parse_placement(xmlNodePtr node, gpointer d)
501 {
502     xmlNodePtr n;
503
504     node = node->children;
505
506     if ((n = obt_parse_find_node(node, "policy"))) {
507         if (obt_parse_node_contains(n, "UnderMouse"))
508             config_place_policy = OB_PLACE_POLICY_MOUSE;
509         if (obt_parse_node_contains(n, "Random"))
510             config_place_policy = OB_PLACE_POLICY_RANDOM;
511     }
512     if ((n = obt_parse_find_node(node, "center")))
513         config_place_center = obt_parse_node_bool(n);
514     if ((n = obt_parse_find_node(node, "monitor"))) {
515         if (obt_parse_node_contains(n, "active"))
516             config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
517         else if (obt_parse_node_contains(n, "mouse"))
518             config_place_monitor = OB_PLACE_MONITOR_MOUSE;
519     }
520 }
521
522 static void parse_margins(xmlNodePtr node, gpointer d)
523 {
524     xmlNodePtr n;
525
526     node = node->children;
527
528     if ((n = obt_parse_find_node(node, "top")))
529         config_margins.top = MAX(0, obt_parse_node_int(n));
530     if ((n = obt_parse_find_node(node, "left")))
531         config_margins.left = MAX(0, obt_parse_node_int(n));
532     if ((n = obt_parse_find_node(node, "right")))
533         config_margins.right = MAX(0, obt_parse_node_int(n));
534     if ((n = obt_parse_find_node(node, "bottom")))
535         config_margins.bottom = MAX(0, obt_parse_node_int(n));
536 }
537
538 static void parse_theme(xmlNodePtr node, gpointer d)
539 {
540     xmlNodePtr n;
541
542     node = node->children;
543
544     if ((n = obt_parse_find_node(node, "name"))) {
545         gchar *c;
546
547         g_free(config_theme);
548         c = obt_parse_node_string(n);
549         config_theme = obt_paths_expand_tilde(c);
550         g_free(c);
551     }
552     if ((n = obt_parse_find_node(node, "titleLayout"))) {
553         gchar *c, *d;
554
555         g_free(config_title_layout);
556         config_title_layout = obt_parse_node_string(n);
557
558         /* replace duplicates with spaces */
559         for (c = config_title_layout; *c != '\0'; ++c)
560             for (d = c+1; *d != '\0'; ++d)
561                 if (*c == *d) *d = ' ';
562     }
563     if ((n = obt_parse_find_node(node, "keepBorder")))
564         config_theme_keepborder = obt_parse_node_bool(n);
565     if ((n = obt_parse_find_node(node, "animateIconify")))
566         config_animate_iconify = obt_parse_node_bool(n);
567
568     n = obt_parse_find_node(node, "font");
569     while (n) {
570         xmlNodePtr   fnode;
571         RrFont     **font;
572         gchar       *name = g_strdup(RrDefaultFontFamily);
573         gint         size = RrDefaultFontSize;
574         RrFontWeight weight = RrDefaultFontWeight;
575         RrFontSlant  slant = RrDefaultFontSlant;
576
577         if (obt_parse_attr_contains(n, "place", "ActiveWindow"))
578             font = &config_font_activewindow;
579         else if (obt_parse_attr_contains(n, "place", "InactiveWindow"))
580             font = &config_font_inactivewindow;
581         else if (obt_parse_attr_contains(n, "place", "MenuHeader"))
582             font = &config_font_menutitle;
583         else if (obt_parse_attr_contains(n, "place", "MenuItem"))
584             font = &config_font_menuitem;
585         else if (obt_parse_attr_contains(n, "place", "OnScreenDisplay"))
586             font = &config_font_osd;
587         else
588             goto next_font;
589
590         if ((fnode = obt_parse_find_node(n->children, "name"))) {
591             g_free(name);
592             name = obt_parse_node_string(fnode);
593         }
594         if ((fnode = obt_parse_find_node(n->children, "size"))) {
595             int s = obt_parse_node_int(fnode);
596             if (s > 0) size = s;
597         }
598         if ((fnode = obt_parse_find_node(n->children, "weight"))) {
599             gchar *w = obt_parse_node_string(fnode);
600             if (!g_ascii_strcasecmp(w, "Bold"))
601                 weight = RR_FONTWEIGHT_BOLD;
602             g_free(w);
603         }
604         if ((fnode = obt_parse_find_node(n->children, "slant"))) {
605             gchar *s = obt_parse_node_string(fnode);
606             if (!g_ascii_strcasecmp(s, "Italic"))
607                 slant = RR_FONTSLANT_ITALIC;
608             if (!g_ascii_strcasecmp(s, "Oblique"))
609                 slant = RR_FONTSLANT_OBLIQUE;
610             g_free(s);
611         }
612
613         *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
614         g_free(name);
615     next_font:
616         n = obt_parse_find_node(n->next, "font");
617     }
618 }
619
620 static void parse_desktops(xmlNodePtr node, gpointer d)
621 {
622     xmlNodePtr n;
623
624     node = node->children;
625
626     if ((n = obt_parse_find_node(node, "number"))) {
627         gint d = obt_parse_node_int(n);
628         if (d > 0)
629             config_desktops_num = (unsigned) d;
630     }
631     if ((n = obt_parse_find_node(node, "firstdesk"))) {
632         gint d = obt_parse_node_int(n);
633         if (d > 0)
634             config_screen_firstdesk = (unsigned) d;
635     }
636     if ((n = obt_parse_find_node(node, "emulatexinerama")))
637         config_emulate_xinerama = obt_parse_node_bool(n);
638     if ((n = obt_parse_find_node(node, "names"))) {
639         GSList *it;
640         xmlNodePtr nname;
641
642         for (it = config_desktops_names; it; it = it->next)
643             g_free(it->data);
644         g_slist_free(config_desktops_names);
645         config_desktops_names = NULL;
646
647         nname = obt_parse_find_node(n->children, "name");
648         while (nname) {
649             config_desktops_names =
650                 g_slist_append(config_desktops_names,
651                                obt_parse_node_string(nname));
652             nname = obt_parse_find_node(nname->next, "name");
653         }
654     }
655     if ((n = obt_parse_find_node(node, "popupTime")))
656         config_desktop_popup_time = obt_parse_node_int(n);
657 }
658
659 static void parse_resize(xmlNodePtr node, gpointer d)
660 {
661     xmlNodePtr n;
662
663     node = node->children;
664
665     if ((n = obt_parse_find_node(node, "drawContents")))
666         config_resize_redraw = obt_parse_node_bool(n);
667     if ((n = obt_parse_find_node(node, "popupShow"))) {
668         config_resize_popup_show = obt_parse_node_int(n);
669         if (obt_parse_node_contains(n, "Always"))
670             config_resize_popup_show = 2;
671         else if (obt_parse_node_contains(n, "Never"))
672             config_resize_popup_show = 0;
673         else if (obt_parse_node_contains(n, "Nonpixel"))
674             config_resize_popup_show = 1;
675     }
676     if ((n = obt_parse_find_node(node, "popupPosition"))) {
677         if (obt_parse_node_contains(n, "Top"))
678             config_resize_popup_pos = OB_RESIZE_POS_TOP;
679         else if (obt_parse_node_contains(n, "Center"))
680             config_resize_popup_pos = OB_RESIZE_POS_CENTER;
681         else if (obt_parse_node_contains(n, "Fixed")) {
682             config_resize_popup_pos = OB_RESIZE_POS_FIXED;
683
684             if ((n = obt_parse_find_node(node, "popupFixedPosition"))) {
685                 xmlNodePtr n2;
686
687                 if ((n2 = obt_parse_find_node(n->children, "x")))
688                     config_parse_gravity_coord(n2,
689                                                &config_resize_popup_fixed.x);
690                 if ((n2 = obt_parse_find_node(n->children, "y")))
691                     config_parse_gravity_coord(n2,
692                                                &config_resize_popup_fixed.y);
693
694                 config_resize_popup_fixed.x.pos =
695                     MAX(config_resize_popup_fixed.x.pos, 0);
696                 config_resize_popup_fixed.y.pos =
697                     MAX(config_resize_popup_fixed.y.pos, 0);
698             }
699         }
700     }
701 }
702
703 static void parse_dock(xmlNodePtr node, gpointer d)
704 {
705     xmlNodePtr n;
706
707     node = node->children;
708
709     if ((n = obt_parse_find_node(node, "position"))) {
710         if (obt_parse_node_contains(n, "TopLeft"))
711             config_dock_floating = FALSE,
712             config_dock_pos = OB_DIRECTION_NORTHWEST;
713         else if (obt_parse_node_contains(n, "Top"))
714             config_dock_floating = FALSE,
715             config_dock_pos = OB_DIRECTION_NORTH;
716         else if (obt_parse_node_contains(n, "TopRight"))
717             config_dock_floating = FALSE,
718             config_dock_pos = OB_DIRECTION_NORTHEAST;
719         else if (obt_parse_node_contains(n, "Right"))
720             config_dock_floating = FALSE,
721             config_dock_pos = OB_DIRECTION_EAST;
722         else if (obt_parse_node_contains(n, "BottomRight"))
723             config_dock_floating = FALSE,
724             config_dock_pos = OB_DIRECTION_SOUTHEAST;
725         else if (obt_parse_node_contains(n, "Bottom"))
726             config_dock_floating = FALSE,
727             config_dock_pos = OB_DIRECTION_SOUTH;
728         else if (obt_parse_node_contains(n, "BottomLeft"))
729             config_dock_floating = FALSE,
730             config_dock_pos = OB_DIRECTION_SOUTHWEST;
731         else if (obt_parse_node_contains(n, "Left"))
732             config_dock_floating = FALSE,
733             config_dock_pos = OB_DIRECTION_WEST;
734         else if (obt_parse_node_contains(n, "Floating"))
735             config_dock_floating = TRUE;
736     }
737     if (config_dock_floating) {
738         if ((n = obt_parse_find_node(node, "floatingX")))
739             config_dock_x = obt_parse_node_int(n);
740         if ((n = obt_parse_find_node(node, "floatingY")))
741             config_dock_y = obt_parse_node_int(n);
742     } else {
743         if ((n = obt_parse_find_node(node, "noStrut")))
744             config_dock_nostrut = obt_parse_node_bool(n);
745     }
746     if ((n = obt_parse_find_node(node, "stacking"))) {
747         if (obt_parse_node_contains(n, "normal"))
748             config_dock_layer = OB_STACKING_LAYER_NORMAL;
749         else if (obt_parse_node_contains(n, "below"))
750             config_dock_layer = OB_STACKING_LAYER_BELOW;
751         else if (obt_parse_node_contains(n, "above"))
752             config_dock_layer = OB_STACKING_LAYER_ABOVE;
753     }
754     if ((n = obt_parse_find_node(node, "direction"))) {
755         if (obt_parse_node_contains(n, "horizontal"))
756             config_dock_orient = OB_ORIENTATION_HORZ;
757         else if (obt_parse_node_contains(n, "vertical"))
758             config_dock_orient = OB_ORIENTATION_VERT;
759     }
760     if ((n = obt_parse_find_node(node, "autoHide")))
761         config_dock_hide = obt_parse_node_bool(n);
762     if ((n = obt_parse_find_node(node, "hideDelay")))
763         config_dock_hide_delay = obt_parse_node_int(n);
764     if ((n = obt_parse_find_node(node, "showDelay")))
765         config_dock_show_delay = obt_parse_node_int(n);
766     if ((n = obt_parse_find_node(node, "moveButton"))) {
767         gchar *str = obt_parse_node_string(n);
768         guint b, s;
769         if (translate_button(str, &s, &b)) {
770             config_dock_app_move_button = b;
771             config_dock_app_move_modifiers = s;
772         } else {
773             g_message(_("Invalid button \"%s\" specified in config file"), str);
774         }
775         g_free(str);
776     }
777 }
778
779 static void parse_menu(xmlNodePtr node, gpointer d)
780 {
781     xmlNodePtr n;
782     for (node = node->children; node; node = node->next) {
783         if (!xmlStrcasecmp(node->name, (const xmlChar*) "file")) {
784             gchar *c;
785
786             c = obt_parse_node_string(node);
787             config_menu_files = g_slist_append(config_menu_files,
788                                                obt_paths_expand_tilde(c));
789             g_free(c);
790         }
791         if ((n = obt_parse_find_node(node, "hideDelay")))
792             config_menu_hide_delay = obt_parse_node_int(n);
793         if ((n = obt_parse_find_node(node, "middle")))
794             config_menu_middle = obt_parse_node_bool(n);
795         if ((n = obt_parse_find_node(node, "submenuShowDelay")))
796             config_submenu_show_delay = obt_parse_node_int(n);
797         if ((n = obt_parse_find_node(node, "applicationIcons")))
798             config_menu_client_list_icons = obt_parse_node_bool(n);
799         if ((n = obt_parse_find_node(node, "manageDesktops")))
800             config_menu_manage_desktops = obt_parse_node_bool(n);
801     }
802 }
803
804 static void parse_resistance(xmlNodePtr node, gpointer d)
805 {
806     xmlNodePtr n;
807
808     node = node->children;
809     if ((n = obt_parse_find_node(node, "strength")))
810         config_resist_win = obt_parse_node_int(n);
811     if ((n = obt_parse_find_node(node, "screen_edge_strength")))
812         config_resist_edge = obt_parse_node_int(n);
813 }
814
815 typedef struct
816 {
817     const gchar *key;
818     const gchar *actname;
819 } ObDefKeyBind;
820
821 static void bind_default_keyboard(void)
822 {
823     ObDefKeyBind *it;
824     ObDefKeyBind binds[] = {
825         { "A-Tab", "NextWindow" },
826         { "S-A-Tab", "PreviousWindow" },
827         { "A-F4", "Close" },
828         { NULL, NULL }
829     };
830     for (it = binds; it->key; ++it) {
831         GList *l = g_list_append(NULL, g_strdup(it->key));
832         keyboard_bind(l, actions_parse_string(it->actname));
833     }
834 }
835
836 typedef struct
837 {
838     const gchar *button;
839     const gchar *context;
840     const ObMouseAction mact;
841     const gchar *actname;
842 } ObDefMouseBind;
843
844 static void bind_default_mouse(void)
845 {
846     ObDefMouseBind *it;
847     ObDefMouseBind binds[] = {
848         { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
849         { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
850         { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
851         { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
852         { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
853         { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
854         { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
855         { "Left", "Bottom", OB_MOUSE_ACTION_PRESS, "Focus" },
856         { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
857         { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
858         { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
859         { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
860         { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
861         { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
862         { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
863         { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
864         { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
865         { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
866         { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
867         { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
868         { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
869         { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
870         { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
871         { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
872         { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
873         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
874         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
875         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
876         { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
877         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
878         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
879         { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
880         { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximize" },
881         { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
882         { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
883         { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
884         { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
885         { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
886         { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
887         { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
888         { "Left", "Top", OB_MOUSE_ACTION_MOTION, "Resize" },
889         { "Left", "Bottom", OB_MOUSE_ACTION_MOTION, "Resize" },
890         { "Left", "Left", OB_MOUSE_ACTION_MOTION, "Resize" },
891         { "Left", "Right", OB_MOUSE_ACTION_MOTION, "Resize" },
892         { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
893         { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
894         { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
895         { NULL, NULL, 0, NULL }
896     };
897
898     for (it = binds; it->button; ++it)
899         mouse_bind(it->button, it->context, it->mact,
900                    actions_parse_string(it->actname));
901 }
902
903 void config_startup(ObtParseInst *i)
904 {
905     config_focus_new = TRUE;
906     config_focus_follow = FALSE;
907     config_focus_delay = 0;
908     config_focus_raise = FALSE;
909     config_focus_last = TRUE;
910     config_focus_under_mouse = FALSE;
911
912     obt_parse_register(i, "focus", parse_focus, NULL);
913
914     config_place_policy = OB_PLACE_POLICY_SMART;
915     config_place_center = TRUE;
916     config_place_monitor = OB_PLACE_MONITOR_ANY;
917
918     obt_parse_register(i, "placement", parse_placement, NULL);
919
920     STRUT_PARTIAL_SET(config_margins, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
921
922     obt_parse_register(i, "margins", parse_margins, NULL);
923
924     config_theme = NULL;
925
926     config_animate_iconify = TRUE;
927     config_title_layout = g_strdup("NLIMC");
928     config_theme_keepborder = TRUE;
929
930     config_font_activewindow = NULL;
931     config_font_inactivewindow = NULL;
932     config_font_menuitem = NULL;
933     config_font_menutitle = NULL;
934
935     obt_parse_register(i, "theme", parse_theme, NULL);
936
937     config_desktops_num = 4;
938     config_screen_firstdesk = 1;
939     config_emulate_xinerama = FALSE;
940     config_desktops_names = NULL;
941     config_desktop_popup_time = 875;
942
943     obt_parse_register(i, "desktops", parse_desktops, NULL);
944
945     config_resize_redraw = TRUE;
946     config_resize_popup_show = 1; /* nonpixel increments */
947     config_resize_popup_pos = OB_RESIZE_POS_CENTER;
948     GRAVITY_COORD_SET(config_resize_popup_fixed.x, 0, FALSE, FALSE);
949     GRAVITY_COORD_SET(config_resize_popup_fixed.y, 0, FALSE, FALSE);
950
951     obt_parse_register(i, "resize", parse_resize, NULL);
952
953     config_dock_layer = OB_STACKING_LAYER_ABOVE;
954     config_dock_pos = OB_DIRECTION_NORTHEAST;
955     config_dock_floating = FALSE;
956     config_dock_nostrut = FALSE;
957     config_dock_x = 0;
958     config_dock_y = 0;
959     config_dock_orient = OB_ORIENTATION_VERT;
960     config_dock_hide = FALSE;
961     config_dock_hide_delay = 300;
962     config_dock_show_delay = 300;
963     config_dock_app_move_button = 2; /* middle */
964     config_dock_app_move_modifiers = 0;
965
966     obt_parse_register(i, "dock", parse_dock, NULL);
967
968     translate_key("C-g", &config_keyboard_reset_state,
969                   &config_keyboard_reset_keycode);
970
971     bind_default_keyboard();
972
973     obt_parse_register(i, "keyboard", parse_keyboard, NULL);
974
975     config_mouse_threshold = 8;
976     config_mouse_dclicktime = 200;
977     config_mouse_screenedgetime = 400;
978
979     bind_default_mouse();
980
981     obt_parse_register(i, "mouse", parse_mouse, NULL);
982
983     config_resist_win = 10;
984     config_resist_edge = 20;
985
986     obt_parse_register(i, "resistance", parse_resistance, NULL);
987
988     config_menu_hide_delay = 250;
989     config_menu_middle = FALSE;
990     config_submenu_show_delay = 0;
991     config_menu_client_list_icons = TRUE;
992     config_menu_manage_desktops = TRUE;
993     config_menu_files = NULL;
994
995     obt_parse_register(i, "menu", parse_menu, NULL);
996
997     config_per_app_settings = NULL;
998
999     obt_parse_register(i, "applications", parse_per_app_settings, NULL);
1000 }
1001
1002 void config_shutdown(void)
1003 {
1004     GSList *it;
1005
1006     g_free(config_theme);
1007
1008     g_free(config_title_layout);
1009
1010     RrFontClose(config_font_activewindow);
1011     RrFontClose(config_font_inactivewindow);
1012     RrFontClose(config_font_menuitem);
1013     RrFontClose(config_font_menutitle);
1014     RrFontClose(config_font_osd);
1015
1016     for (it = config_desktops_names; it; it = g_slist_next(it))
1017         g_free(it->data);
1018     g_slist_free(config_desktops_names);
1019
1020     for (it = config_menu_files; it; it = g_slist_next(it))
1021         g_free(it->data);
1022     g_slist_free(config_menu_files);
1023
1024     for (it = config_per_app_settings; it; it = g_slist_next(it)) {
1025         ObAppSettings *itd = (ObAppSettings *)it->data;
1026         if (itd->name)  g_pattern_spec_free(itd->name);
1027         if (itd->role)  g_pattern_spec_free(itd->role);
1028         if (itd->class) g_pattern_spec_free(itd->class);
1029         g_free(it->data);
1030     }
1031     g_slist_free(config_per_app_settings);
1032 }