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