Don't segfault when there's no target in If
[openbox.git] / openbox / config.c
blob76f48569aee10c31625821117f2450ec968ae596
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 config.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
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.
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.
17 See the COPYING file for a copy of the GNU General Public License.
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"
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;
39 ObPlacePolicy config_place_policy;
40 gboolean config_place_center;
41 ObPlaceMonitor config_place_monitor;
43 guint config_primary_monitor_index;
44 ObPlaceMonitor config_primary_monitor;
46 StrutPartial config_margins;
48 gchar *config_theme;
49 gboolean config_theme_keepborder;
50 guint config_theme_window_list_icon_size;
52 gchar *config_title_layout;
54 gboolean config_animate_iconify;
56 RrFont *config_font_activewindow;
57 RrFont *config_font_inactivewindow;
58 RrFont *config_font_menuitem;
59 RrFont *config_font_menutitle;
60 RrFont *config_font_activeosd;
61 RrFont *config_font_inactiveosd;
63 guint config_desktops_num;
64 GSList *config_desktops_names;
65 guint config_screen_firstdesk;
66 guint config_desktop_popup_time;
68 gboolean config_resize_redraw;
69 gint config_resize_popup_show;
70 ObResizePopupPos config_resize_popup_pos;
71 GravityPoint config_resize_popup_fixed;
73 ObStackingLayer config_dock_layer;
74 gboolean config_dock_floating;
75 gboolean config_dock_nostrut;
76 ObDirection config_dock_pos;
77 gint config_dock_x;
78 gint config_dock_y;
79 ObOrientation config_dock_orient;
80 gboolean config_dock_hide;
81 guint config_dock_hide_delay;
82 guint config_dock_show_delay;
83 guint config_dock_app_move_button;
84 guint config_dock_app_move_modifiers;
86 guint config_keyboard_reset_keycode;
87 guint config_keyboard_reset_state;
89 gint config_mouse_threshold;
90 gint config_mouse_dclicktime;
91 gint config_mouse_screenedgetime;
92 gboolean config_mouse_screenedgewarp;
94 guint config_menu_hide_delay;
95 gboolean config_menu_middle;
96 guint config_submenu_show_delay;
97 guint config_submenu_hide_delay;
98 gboolean config_menu_manage_desktops;
99 gboolean config_menu_show_icons;
101 GSList *config_menu_files;
103 gint config_resist_win;
104 gint config_resist_edge;
106 GSList *config_per_app_settings;
108 ObAppSettings* config_create_app_settings(void)
110 ObAppSettings *settings = g_slice_new0(ObAppSettings);
111 settings->type = -1;
112 settings->decor = -1;
113 settings->shade = -1;
114 settings->monitor_type = OB_PLACE_MONITOR_ANY;
115 settings->monitor = -1;
116 settings->focus = -1;
117 settings->desktop = 0;
118 settings->layer = -2;
119 settings->iconic = -1;
120 settings->skip_pager = -1;
121 settings->skip_taskbar = -1;
122 settings->fullscreen = -1;
123 settings->max_horz = -1;
124 settings->max_vert = -1;
125 return settings;
128 #define copy_if(setting, default) \
129 if (src->setting != default) dst->setting = src->setting
130 void config_app_settings_copy_non_defaults(const ObAppSettings *src,
131 ObAppSettings *dst)
133 g_assert(src != NULL);
134 g_assert(dst != NULL);
136 copy_if(type, (ObClientType)-1);
137 copy_if(decor, -1);
138 copy_if(shade, -1);
139 copy_if(monitor_type, OB_PLACE_MONITOR_ANY);
140 copy_if(monitor, -1);
141 copy_if(focus, -1);
142 copy_if(desktop, 0);
143 copy_if(layer, -2);
144 copy_if(iconic, -1);
145 copy_if(skip_pager, -1);
146 copy_if(skip_taskbar, -1);
147 copy_if(fullscreen, -1);
148 copy_if(max_horz, -1);
149 copy_if(max_vert, -1);
151 if (src->pos_given) {
152 dst->pos_given = TRUE;
153 dst->pos_force = src->pos_force;
154 dst->position = src->position;
155 /* monitor is copied above */
158 dst->width_num = src->width_num;
159 dst->width_denom = src->width_denom;
160 dst->height_num = src->height_num;
161 dst->height_denom = src->height_denom;
164 void config_parse_relative_number(gchar *s, gint *num, gint *denom)
166 *num = strtol(s, &s, 10);
168 if (*s == '%') {
169 *denom = 100;
170 } else if (*s == '/') {
171 *denom = atoi(s+1);
175 void config_parse_gravity_coord(xmlNodePtr node, GravityCoord *c)
177 gchar *s = obt_xml_node_string(node);
178 if (!g_ascii_strcasecmp(s, "center"))
179 c->center = TRUE;
180 else {
181 gchar *ps = s;
182 if (s[0] == '-')
183 c->opposite = TRUE;
184 if (s[0] == '-' || s[0] == '+')
185 ps++;
186 config_parse_relative_number(ps, &c->pos, &c->denom);
188 g_free(s);
192 <applications>
193 <application name="aterm">
194 <decor>false</decor>
195 </application>
196 <application name="Rhythmbox">
197 <layer>above</layer>
198 <position>
199 <x>700</x>
200 <y>0</y>
201 <monitor>1</monitor>
202 </position>
203 .. there is a lot more settings available
204 </application>
205 </applications>
208 static void parse_single_per_app_settings(xmlNodePtr app,
209 ObAppSettings *settings)
211 xmlNodePtr n, c;
212 gboolean x_pos_given = FALSE;
214 if ((n = obt_xml_find_node(app->children, "decor")))
215 if (!obt_xml_node_contains(n, "default"))
216 settings->decor = obt_xml_node_bool(n);
218 if ((n = obt_xml_find_node(app->children, "shade")))
219 if (!obt_xml_node_contains(n, "default"))
220 settings->shade = obt_xml_node_bool(n);
222 if ((n = obt_xml_find_node(app->children, "position"))) {
223 if ((c = obt_xml_find_node(n->children, "x"))) {
224 if (!obt_xml_node_contains(c, "default")) {
225 config_parse_gravity_coord(c, &settings->position.x);
226 x_pos_given = TRUE;
230 if (x_pos_given && (c = obt_xml_find_node(n->children, "y"))) {
231 if (!obt_xml_node_contains(c, "default")) {
232 config_parse_gravity_coord(c, &settings->position.y);
233 settings->pos_given = TRUE;
237 /* monitor can be set without setting x or y */
238 if ((c = obt_xml_find_node(n->children, "monitor"))) {
239 if (!obt_xml_node_contains(c, "default")) {
240 gchar *s = obt_xml_node_string(c);
241 if (!g_ascii_strcasecmp(s, "mouse"))
242 settings->monitor_type = OB_PLACE_MONITOR_MOUSE;
243 else if (!g_ascii_strcasecmp(s, "active"))
244 settings->monitor_type = OB_PLACE_MONITOR_ACTIVE;
245 else if (!g_ascii_strcasecmp(s, "primary"))
246 settings->monitor_type = OB_PLACE_MONITOR_PRIMARY;
247 else
248 settings->monitor = obt_xml_node_int(c);
249 g_free(s);
253 obt_xml_attr_bool(n, "force", &settings->pos_force);
256 if ((n = obt_xml_find_node(app->children, "size"))) {
257 if ((c = obt_xml_find_node(n->children, "width"))) {
258 if (!obt_xml_node_contains(c, "default")) {
259 gchar *s = obt_xml_node_string(c);
260 config_parse_relative_number(s,
261 &settings->width_num,
262 &settings->width_denom);
263 if (settings->width_num <= 0 || settings->width_denom < 0)
264 settings->width_num = settings->width_denom = 0;
265 g_free(s);
269 if ((c = obt_xml_find_node(n->children, "height"))) {
270 if (!obt_xml_node_contains(c, "default")) {
271 gchar *s = obt_xml_node_string(c);
272 config_parse_relative_number(s,
273 &settings->height_num,
274 &settings->height_denom);
275 if (settings->height_num <= 0 || settings->height_denom < 0)
276 settings->height_num = settings->height_denom = 0;
277 g_free(s);
282 if ((n = obt_xml_find_node(app->children, "focus"))) {
283 if (!obt_xml_node_contains(n, "default"))
284 settings->focus = obt_xml_node_bool(n);
287 if ((n = obt_xml_find_node(app->children, "desktop"))) {
288 if (!obt_xml_node_contains(n, "default")) {
289 gchar *s = obt_xml_node_string(n);
290 if (!g_ascii_strcasecmp(s, "all"))
291 settings->desktop = DESKTOP_ALL;
292 else {
293 gint i = obt_xml_node_int(n);
294 if (i > 0)
295 settings->desktop = i;
297 g_free(s);
301 if ((n = obt_xml_find_node(app->children, "layer"))) {
302 if (!obt_xml_node_contains(n, "default")) {
303 gchar *s = obt_xml_node_string(n);
304 if (!g_ascii_strcasecmp(s, "above"))
305 settings->layer = 1;
306 else if (!g_ascii_strcasecmp(s, "below"))
307 settings->layer = -1;
308 else
309 settings->layer = 0;
310 g_free(s);
314 if ((n = obt_xml_find_node(app->children, "iconic")))
315 if (!obt_xml_node_contains(n, "default"))
316 settings->iconic = obt_xml_node_bool(n);
318 if ((n = obt_xml_find_node(app->children, "skip_pager")))
319 if (!obt_xml_node_contains(n, "default"))
320 settings->skip_pager = obt_xml_node_bool(n);
322 if ((n = obt_xml_find_node(app->children, "skip_taskbar")))
323 if (!obt_xml_node_contains(n, "default"))
324 settings->skip_taskbar = obt_xml_node_bool(n);
326 if ((n = obt_xml_find_node(app->children, "fullscreen")))
327 if (!obt_xml_node_contains(n, "default"))
328 settings->fullscreen = obt_xml_node_bool(n);
330 if ((n = obt_xml_find_node(app->children, "maximized"))) {
331 if (!obt_xml_node_contains(n, "default")) {
332 gchar *s = obt_xml_node_string(n);
333 if (!g_ascii_strcasecmp(s, "horizontal")) {
334 settings->max_horz = TRUE;
335 settings->max_vert = FALSE;
336 } else if (!g_ascii_strcasecmp(s, "vertical")) {
337 settings->max_horz = FALSE;
338 settings->max_vert = TRUE;
339 } else
340 settings->max_horz = settings->max_vert =
341 obt_xml_node_bool(n);
342 g_free(s);
347 /* Manages settings for individual applications.
348 Some notes: monitor is the screen number in a multi monitor
349 (Xinerama) setup (starting from 0), or mouse: the monitor the pointer
350 is on, active: the active monitor, primary: the primary monitor.
351 Layer can be three values, above (Always on top), below
352 (Always on bottom) and everything else (normal behaviour).
353 Positions can be an integer value or center, which will
354 center the window in the specified axis. Position is within
355 the monitor, so <position><x>center</x></position><monitor>2</monitor>
356 will center the window on the second monitor.
358 static void parse_per_app_settings(xmlNodePtr node, gpointer d)
360 xmlNodePtr app = obt_xml_find_node(node->children, "application");
361 for (; app; app = obt_xml_find_node(app->next, "application")) {
362 ObAppSettings *settings;
364 gboolean name_set, class_set, role_set, title_set,
365 type_set, group_name_set, group_class_set;
366 gchar *name = NULL, *class = NULL, *role = NULL, *title = NULL,
367 *type_str = NULL, *group_name = NULL, *group_class = NULL;
368 ObClientType type;
370 class_set = obt_xml_attr_string(app, "class", &class);
371 name_set = obt_xml_attr_string(app, "name", &name);
372 group_class_set = obt_xml_attr_string(app, "groupclass", &group_class);
373 group_name_set = obt_xml_attr_string(app, "groupname", &group_name);
374 type_set = obt_xml_attr_string(app, "type", &type_str);
375 role_set = obt_xml_attr_string(app, "role", &role);
376 title_set = obt_xml_attr_string(app, "title", &title);
378 /* validate the type tho */
379 if (type_set) {
380 if (!g_ascii_strcasecmp(type_str, "normal"))
381 type = OB_CLIENT_TYPE_NORMAL;
382 else if (!g_ascii_strcasecmp(type_str, "dialog"))
383 type = OB_CLIENT_TYPE_DIALOG;
384 else if (!g_ascii_strcasecmp(type_str, "splash"))
385 type = OB_CLIENT_TYPE_SPLASH;
386 else if (!g_ascii_strcasecmp(type_str, "utility"))
387 type = OB_CLIENT_TYPE_UTILITY;
388 else if (!g_ascii_strcasecmp(type_str, "menu"))
389 type = OB_CLIENT_TYPE_MENU;
390 else if (!g_ascii_strcasecmp(type_str, "toolbar"))
391 type = OB_CLIENT_TYPE_TOOLBAR;
392 else if (!g_ascii_strcasecmp(type_str, "dock"))
393 type = OB_CLIENT_TYPE_DOCK;
394 else if (!g_ascii_strcasecmp(type_str, "desktop"))
395 type = OB_CLIENT_TYPE_DESKTOP;
396 else
397 type_set = FALSE; /* not valid! */
400 if (!(class_set || name_set || role_set || title_set ||
401 type_set || group_class_set || group_name_set))
402 continue;
404 settings = config_create_app_settings();
406 if (name_set)
407 settings->name = g_pattern_spec_new(name);
408 if (class_set)
409 settings->class = g_pattern_spec_new(class);
410 if (group_name_set)
411 settings->group_name = g_pattern_spec_new(group_name);
412 if (group_class_set)
413 settings->group_class = g_pattern_spec_new(group_class);
414 if (role_set)
415 settings->role = g_pattern_spec_new(role);
416 if (title_set)
417 settings->title = g_pattern_spec_new(title);
418 if (type_set)
419 settings->type = type;
421 g_free(name);
422 g_free(class);
423 g_free(group_name);
424 g_free(group_class);
425 g_free(role);
426 g_free(title);
427 g_free(type_str);
429 parse_single_per_app_settings(app, settings);
430 config_per_app_settings = g_slist_append(config_per_app_settings,
431 (gpointer)settings);
437 <keybind key="C-x">
438 <action name="ChangeDesktop">
439 <desktop>3</desktop>
440 </action>
441 </keybind>
445 static void parse_key(xmlNodePtr node, GList *keylist)
447 gchar *keystring, **keys, **key;
448 xmlNodePtr n;
449 gboolean is_chroot = FALSE;
451 if (!obt_xml_attr_string(node, "key", &keystring))
452 return;
454 obt_xml_attr_bool(node, "chroot", &is_chroot);
456 keys = g_strsplit(keystring, " ", 0);
457 for (key = keys; *key; ++key) {
458 keylist = g_list_append(keylist, *key);
460 if ((n = obt_xml_find_node(node->children, "keybind"))) {
461 while (n) {
462 parse_key(n, keylist);
463 n = obt_xml_find_node(n->next, "keybind");
466 else if ((n = obt_xml_find_node(node->children, "action"))) {
467 while (n) {
468 ObActionsAct *action;
470 action = actions_parse(n);
471 if (action)
472 keyboard_bind(keylist, action);
473 n = obt_xml_find_node(n->next, "action");
478 if (is_chroot)
479 keyboard_chroot(keylist);
480 keylist = g_list_delete_link(keylist, g_list_last(keylist));
483 g_strfreev(keys);
484 g_free(keystring);
487 static void parse_keyboard(xmlNodePtr node, gpointer d)
489 xmlNodePtr n;
490 gchar *key;
492 keyboard_unbind_all();
494 if ((n = obt_xml_find_node(node->children, "chainQuitKey"))) {
495 key = obt_xml_node_string(n);
496 translate_key(key, &config_keyboard_reset_state,
497 &config_keyboard_reset_keycode);
498 g_free(key);
501 if ((n = obt_xml_find_node(node->children, "keybind")))
502 while (n) {
503 parse_key(n, NULL);
504 n = obt_xml_find_node(n->next, "keybind");
510 <context name="Titlebar">
511 <mousebind button="Left" action="Press">
512 <action name="Raise"></action>
513 </mousebind>
514 </context>
518 static void parse_mouse(xmlNodePtr node, gpointer d)
520 xmlNodePtr n, nbut, nact;
521 gchar *buttonstr;
522 gchar *cxstr;
523 ObMouseAction mact;
525 mouse_unbind_all();
527 node = node->children;
529 if ((n = obt_xml_find_node(node, "dragThreshold")))
530 config_mouse_threshold = obt_xml_node_int(n);
531 if ((n = obt_xml_find_node(node, "doubleClickTime")))
532 config_mouse_dclicktime = obt_xml_node_int(n);
533 if ((n = obt_xml_find_node(node, "screenEdgeWarpTime"))) {
534 config_mouse_screenedgetime = obt_xml_node_int(n);
535 /* minimum value of 25 for this property, when it is 1 and you hit the
536 edge it basically never stops */
537 if (config_mouse_screenedgetime && config_mouse_screenedgetime < 25)
538 config_mouse_screenedgetime = 25;
540 if ((n = obt_xml_find_node(node, "screenEdgeWarpMouse")))
541 config_mouse_screenedgewarp = obt_xml_node_bool(n);
543 n = obt_xml_find_node(node, "context");
544 while (n) {
545 gchar *modcxstr;
546 ObFrameContext cx;
548 if (!obt_xml_attr_string(n, "name", &cxstr))
549 goto next_n;
551 modcxstr = g_strdup(cxstr); /* make a copy to mutilate */
552 while (frame_next_context_from_string(modcxstr, &cx)) {
553 if (!cx) {
554 gchar *s = strchr(modcxstr, ' ');
555 if (s) {
556 *s = '\0';
557 g_message(_("Invalid context \"%s\" in mouse binding"),
558 modcxstr);
559 *s = ' ';
561 continue;
564 nbut = obt_xml_find_node(n->children, "mousebind");
565 while (nbut) {
566 if (!obt_xml_attr_string(nbut, "button", &buttonstr))
567 goto next_nbut;
568 if (obt_xml_attr_contains(nbut, "action", "press"))
569 mact = OB_MOUSE_ACTION_PRESS;
570 else if (obt_xml_attr_contains(nbut, "action", "release"))
571 mact = OB_MOUSE_ACTION_RELEASE;
572 else if (obt_xml_attr_contains(nbut, "action", "click"))
573 mact = OB_MOUSE_ACTION_CLICK;
574 else if (obt_xml_attr_contains(nbut, "action","doubleclick"))
575 mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
576 else if (obt_xml_attr_contains(nbut, "action", "drag"))
577 mact = OB_MOUSE_ACTION_MOTION;
578 else
579 goto next_nbut;
581 nact = obt_xml_find_node(nbut->children, "action");
582 while (nact) {
583 ObActionsAct *action;
585 if ((action = actions_parse(nact)))
586 mouse_bind(buttonstr, cx, mact, action);
587 nact = obt_xml_find_node(nact->next, "action");
589 g_free(buttonstr);
590 next_nbut:
591 nbut = obt_xml_find_node(nbut->next, "mousebind");
594 g_free(modcxstr);
595 g_free(cxstr);
596 next_n:
597 n = obt_xml_find_node(n->next, "context");
601 static void parse_focus(xmlNodePtr node, gpointer d)
603 xmlNodePtr n;
605 node = node->children;
607 if ((n = obt_xml_find_node(node, "focusNew")))
608 config_focus_new = obt_xml_node_bool(n);
609 if ((n = obt_xml_find_node(node, "followMouse")))
610 config_focus_follow = obt_xml_node_bool(n);
611 if ((n = obt_xml_find_node(node, "focusDelay")))
612 config_focus_delay = obt_xml_node_int(n);
613 if ((n = obt_xml_find_node(node, "raiseOnFocus")))
614 config_focus_raise = obt_xml_node_bool(n);
615 if ((n = obt_xml_find_node(node, "focusLast")))
616 config_focus_last = obt_xml_node_bool(n);
617 if ((n = obt_xml_find_node(node, "underMouse")))
618 config_focus_under_mouse = obt_xml_node_bool(n);
619 if ((n = obt_xml_find_node(node, "unfocusOnLeave")))
620 config_unfocus_leave = obt_xml_node_bool(n);
623 static void parse_placement(xmlNodePtr node, gpointer d)
625 xmlNodePtr n;
627 node = node->children;
629 if ((n = obt_xml_find_node(node, "policy"))) {
630 if (obt_xml_node_contains(n, "UnderMouse"))
631 config_place_policy = OB_PLACE_POLICY_MOUSE;
633 if ((n = obt_xml_find_node(node, "center"))) {
634 config_place_center = obt_xml_node_bool(n);
636 if ((n = obt_xml_find_node(node, "monitor"))) {
637 if (obt_xml_node_contains(n, "active"))
638 config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
639 else if (obt_xml_node_contains(n, "mouse"))
640 config_place_monitor = OB_PLACE_MONITOR_MOUSE;
641 else if (obt_xml_node_contains(n, "any"))
642 config_place_monitor = OB_PLACE_MONITOR_ANY;
644 if ((n = obt_xml_find_node(node, "primaryMonitor"))) {
645 config_primary_monitor_index = obt_xml_node_int(n);
646 if (!config_primary_monitor_index) {
647 if (obt_xml_node_contains(n, "mouse"))
648 config_primary_monitor = OB_PLACE_MONITOR_MOUSE;
653 static void parse_margins(xmlNodePtr node, gpointer d)
655 xmlNodePtr n;
657 node = node->children;
659 if ((n = obt_xml_find_node(node, "top")))
660 config_margins.top = MAX(0, obt_xml_node_int(n));
661 if ((n = obt_xml_find_node(node, "left")))
662 config_margins.left = MAX(0, obt_xml_node_int(n));
663 if ((n = obt_xml_find_node(node, "right")))
664 config_margins.right = MAX(0, obt_xml_node_int(n));
665 if ((n = obt_xml_find_node(node, "bottom")))
666 config_margins.bottom = MAX(0, obt_xml_node_int(n));
669 static void parse_theme(xmlNodePtr node, gpointer d)
671 xmlNodePtr n;
673 node = node->children;
675 if ((n = obt_xml_find_node(node, "name"))) {
676 gchar *c;
678 g_free(config_theme);
679 c = obt_xml_node_string(n);
680 config_theme = obt_paths_expand_tilde(c);
681 g_free(c);
683 if ((n = obt_xml_find_node(node, "titleLayout"))) {
684 gchar *c, *d;
686 g_free(config_title_layout);
687 config_title_layout = obt_xml_node_string(n);
689 /* replace duplicates with spaces */
690 for (c = config_title_layout; *c != '\0'; ++c)
691 for (d = c+1; *d != '\0'; ++d)
692 if (*c == *d) *d = ' ';
694 if ((n = obt_xml_find_node(node, "keepBorder")))
695 config_theme_keepborder = obt_xml_node_bool(n);
696 if ((n = obt_xml_find_node(node, "animateIconify")))
697 config_animate_iconify = obt_xml_node_bool(n);
698 if ((n = obt_xml_find_node(node, "windowListIconSize"))) {
699 config_theme_window_list_icon_size = obt_xml_node_int(n);
700 if (config_theme_window_list_icon_size < 16)
701 config_theme_window_list_icon_size = 16;
702 else if (config_theme_window_list_icon_size > 96)
703 config_theme_window_list_icon_size = 96;
706 n = obt_xml_find_node(node, "font");
707 while (n) {
708 xmlNodePtr fnode;
709 RrFont **font;
710 gchar *name = g_strdup(RrDefaultFontFamily);
711 gint size = RrDefaultFontSize;
712 RrFontWeight weight = RrDefaultFontWeight;
713 RrFontSlant slant = RrDefaultFontSlant;
715 if (obt_xml_attr_contains(n, "place", "ActiveWindow"))
716 font = &config_font_activewindow;
717 else if (obt_xml_attr_contains(n, "place", "InactiveWindow"))
718 font = &config_font_inactivewindow;
719 else if (obt_xml_attr_contains(n, "place", "MenuHeader"))
720 font = &config_font_menutitle;
721 else if (obt_xml_attr_contains(n, "place", "MenuItem"))
722 font = &config_font_menuitem;
723 else if (obt_xml_attr_contains(n, "place", "ActiveOnScreenDisplay"))
724 font = &config_font_activeosd;
725 else if (obt_xml_attr_contains(n, "place", "OnScreenDisplay"))
726 font = &config_font_activeosd;
727 else if (obt_xml_attr_contains(n, "place","InactiveOnScreenDisplay"))
728 font = &config_font_inactiveosd;
729 else
730 goto next_font;
732 if ((fnode = obt_xml_find_node(n->children, "name"))) {
733 g_free(name);
734 name = obt_xml_node_string(fnode);
736 if ((fnode = obt_xml_find_node(n->children, "size"))) {
737 int s = obt_xml_node_int(fnode);
738 if (s > 0) size = s;
740 if ((fnode = obt_xml_find_node(n->children, "weight"))) {
741 gchar *w = obt_xml_node_string(fnode);
742 if (!g_ascii_strcasecmp(w, "Bold"))
743 weight = RR_FONTWEIGHT_BOLD;
744 g_free(w);
746 if ((fnode = obt_xml_find_node(n->children, "slant"))) {
747 gchar *s = obt_xml_node_string(fnode);
748 if (!g_ascii_strcasecmp(s, "Italic"))
749 slant = RR_FONTSLANT_ITALIC;
750 if (!g_ascii_strcasecmp(s, "Oblique"))
751 slant = RR_FONTSLANT_OBLIQUE;
752 g_free(s);
755 *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
756 g_free(name);
757 next_font:
758 n = obt_xml_find_node(n->next, "font");
762 static void parse_desktops(xmlNodePtr node, gpointer d)
764 xmlNodePtr n;
766 node = node->children;
768 if ((n = obt_xml_find_node(node, "number"))) {
769 gint d = obt_xml_node_int(n);
770 if (d > 0)
771 config_desktops_num = (unsigned) d;
773 if ((n = obt_xml_find_node(node, "firstdesk"))) {
774 gint d = obt_xml_node_int(n);
775 if (d > 0)
776 config_screen_firstdesk = (unsigned) d;
778 if ((n = obt_xml_find_node(node, "names"))) {
779 GSList *it;
780 xmlNodePtr nname;
782 for (it = config_desktops_names; it; it = it->next)
783 g_free(it->data);
784 g_slist_free(config_desktops_names);
785 config_desktops_names = NULL;
787 nname = obt_xml_find_node(n->children, "name");
788 while (nname) {
789 config_desktops_names =
790 g_slist_append(config_desktops_names,
791 obt_xml_node_string(nname));
792 nname = obt_xml_find_node(nname->next, "name");
795 if ((n = obt_xml_find_node(node, "popupTime")))
796 config_desktop_popup_time = obt_xml_node_int(n);
799 static void parse_resize(xmlNodePtr node, gpointer d)
801 xmlNodePtr n;
803 node = node->children;
805 if ((n = obt_xml_find_node(node, "drawContents")))
806 config_resize_redraw = obt_xml_node_bool(n);
807 if ((n = obt_xml_find_node(node, "popupShow"))) {
808 config_resize_popup_show = obt_xml_node_int(n);
809 if (obt_xml_node_contains(n, "Always"))
810 config_resize_popup_show = 2;
811 else if (obt_xml_node_contains(n, "Never"))
812 config_resize_popup_show = 0;
813 else if (obt_xml_node_contains(n, "Nonpixel"))
814 config_resize_popup_show = 1;
816 if ((n = obt_xml_find_node(node, "popupPosition"))) {
817 if (obt_xml_node_contains(n, "Top"))
818 config_resize_popup_pos = OB_RESIZE_POS_TOP;
819 else if (obt_xml_node_contains(n, "Center"))
820 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
821 else if (obt_xml_node_contains(n, "Fixed")) {
822 config_resize_popup_pos = OB_RESIZE_POS_FIXED;
824 if ((n = obt_xml_find_node(node, "popupFixedPosition"))) {
825 xmlNodePtr n2;
827 if ((n2 = obt_xml_find_node(n->children, "x")))
828 config_parse_gravity_coord(n2,
829 &config_resize_popup_fixed.x);
830 if ((n2 = obt_xml_find_node(n->children, "y")))
831 config_parse_gravity_coord(n2,
832 &config_resize_popup_fixed.y);
834 config_resize_popup_fixed.x.pos =
835 MAX(config_resize_popup_fixed.x.pos, 0);
836 config_resize_popup_fixed.y.pos =
837 MAX(config_resize_popup_fixed.y.pos, 0);
843 static void parse_dock(xmlNodePtr node, gpointer d)
845 xmlNodePtr n;
847 node = node->children;
849 if ((n = obt_xml_find_node(node, "position"))) {
850 if (obt_xml_node_contains(n, "TopLeft"))
851 config_dock_floating = FALSE,
852 config_dock_pos = OB_DIRECTION_NORTHWEST;
853 else if (obt_xml_node_contains(n, "Top"))
854 config_dock_floating = FALSE,
855 config_dock_pos = OB_DIRECTION_NORTH;
856 else if (obt_xml_node_contains(n, "TopRight"))
857 config_dock_floating = FALSE,
858 config_dock_pos = OB_DIRECTION_NORTHEAST;
859 else if (obt_xml_node_contains(n, "Right"))
860 config_dock_floating = FALSE,
861 config_dock_pos = OB_DIRECTION_EAST;
862 else if (obt_xml_node_contains(n, "BottomRight"))
863 config_dock_floating = FALSE,
864 config_dock_pos = OB_DIRECTION_SOUTHEAST;
865 else if (obt_xml_node_contains(n, "Bottom"))
866 config_dock_floating = FALSE,
867 config_dock_pos = OB_DIRECTION_SOUTH;
868 else if (obt_xml_node_contains(n, "BottomLeft"))
869 config_dock_floating = FALSE,
870 config_dock_pos = OB_DIRECTION_SOUTHWEST;
871 else if (obt_xml_node_contains(n, "Left"))
872 config_dock_floating = FALSE,
873 config_dock_pos = OB_DIRECTION_WEST;
874 else if (obt_xml_node_contains(n, "Floating"))
875 config_dock_floating = TRUE;
877 if (config_dock_floating) {
878 if ((n = obt_xml_find_node(node, "floatingX")))
879 config_dock_x = obt_xml_node_int(n);
880 if ((n = obt_xml_find_node(node, "floatingY")))
881 config_dock_y = obt_xml_node_int(n);
882 } else {
883 if ((n = obt_xml_find_node(node, "noStrut")))
884 config_dock_nostrut = obt_xml_node_bool(n);
886 if ((n = obt_xml_find_node(node, "stacking"))) {
887 if (obt_xml_node_contains(n, "normal"))
888 config_dock_layer = OB_STACKING_LAYER_NORMAL;
889 else if (obt_xml_node_contains(n, "below"))
890 config_dock_layer = OB_STACKING_LAYER_BELOW;
891 else if (obt_xml_node_contains(n, "above"))
892 config_dock_layer = OB_STACKING_LAYER_ABOVE;
894 if ((n = obt_xml_find_node(node, "direction"))) {
895 if (obt_xml_node_contains(n, "horizontal"))
896 config_dock_orient = OB_ORIENTATION_HORZ;
897 else if (obt_xml_node_contains(n, "vertical"))
898 config_dock_orient = OB_ORIENTATION_VERT;
900 if ((n = obt_xml_find_node(node, "autoHide")))
901 config_dock_hide = obt_xml_node_bool(n);
902 if ((n = obt_xml_find_node(node, "hideDelay")))
903 config_dock_hide_delay = obt_xml_node_int(n);
904 if ((n = obt_xml_find_node(node, "showDelay")))
905 config_dock_show_delay = obt_xml_node_int(n);
906 if ((n = obt_xml_find_node(node, "moveButton"))) {
907 gchar *str = obt_xml_node_string(n);
908 guint b, s;
909 if (translate_button(str, &s, &b)) {
910 config_dock_app_move_button = b;
911 config_dock_app_move_modifiers = s;
912 } else {
913 g_message(_("Invalid button \"%s\" specified in config file"), str);
915 g_free(str);
919 static void parse_menu(xmlNodePtr node, gpointer d)
921 xmlNodePtr n;
922 node = node->children;
924 if ((n = obt_xml_find_node(node, "hideDelay")))
925 config_menu_hide_delay = obt_xml_node_int(n);
926 if ((n = obt_xml_find_node(node, "middle")))
927 config_menu_middle = obt_xml_node_bool(n);
928 if ((n = obt_xml_find_node(node, "submenuShowDelay")))
929 config_submenu_show_delay = obt_xml_node_int(n);
930 if ((n = obt_xml_find_node(node, "submenuHideDelay")))
931 config_submenu_hide_delay = obt_xml_node_int(n);
932 if ((n = obt_xml_find_node(node, "manageDesktops")))
933 config_menu_manage_desktops = obt_xml_node_bool(n);
934 if ((n = obt_xml_find_node(node, "showIcons"))) {
935 config_menu_show_icons = obt_xml_node_bool(n);
936 #if !defined(USE_IMLIB2) && !defined(USE_LIBRSVG)
937 if (config_menu_show_icons)
938 g_message(_("Openbox was compiled without image loading support. Icons in menus will not be loaded."));
939 #endif
942 while ((node = obt_xml_find_node(node, "file"))) {
943 gchar *c = obt_xml_node_string(node);
944 config_menu_files = g_slist_append(config_menu_files,
945 obt_paths_expand_tilde(c));
946 g_free(c);
947 node = node->next;
951 static void parse_resistance(xmlNodePtr node, gpointer d)
953 xmlNodePtr n;
955 node = node->children;
956 if ((n = obt_xml_find_node(node, "strength")))
957 config_resist_win = obt_xml_node_int(n);
958 if ((n = obt_xml_find_node(node, "screen_edge_strength")))
959 config_resist_edge = obt_xml_node_int(n);
962 typedef struct
964 const gchar *key;
965 const gchar *actname;
966 } ObDefKeyBind;
968 static void bind_default_keyboard(void)
970 ObDefKeyBind *it;
971 ObDefKeyBind binds[] = {
972 { "A-Tab", "NextWindow" },
973 { "S-A-Tab", "PreviousWindow" },
974 { "A-F4", "Close" },
975 { NULL, NULL }
977 for (it = binds; it->key; ++it) {
978 GList *l = g_list_append(NULL, g_strdup(it->key));
979 keyboard_bind(l, actions_parse_string(it->actname));
983 typedef struct
985 const gchar *button;
986 const gchar *context;
987 const ObMouseAction mact;
988 const gchar *actname;
989 } ObDefMouseBind;
991 static void bind_default_mouse(void)
993 ObDefMouseBind *it;
994 ObDefMouseBind binds[] = {
995 { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
996 { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
997 { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
998 { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
999 { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1000 { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1001 { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
1002 { "Left", "Bottom", OB_MOUSE_ACTION_PRESS, "Focus" },
1003 { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1004 { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1005 { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1006 { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1007 { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
1008 { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
1009 { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
1010 { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
1011 { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
1012 { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
1013 { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
1014 { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
1015 { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
1016 { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1017 { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1018 { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1019 { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1020 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
1021 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
1022 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
1023 { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
1024 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
1025 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
1026 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
1027 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximize" },
1028 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
1029 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
1030 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
1031 { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1032 { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1033 { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1034 { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1035 { "Left", "Top", OB_MOUSE_ACTION_MOTION, "Resize" },
1036 { "Left", "Bottom", OB_MOUSE_ACTION_MOTION, "Resize" },
1037 { "Left", "Left", OB_MOUSE_ACTION_MOTION, "Resize" },
1038 { "Left", "Right", OB_MOUSE_ACTION_MOTION, "Resize" },
1039 { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
1040 { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
1041 { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
1042 { NULL, NULL, 0, NULL }
1045 for (it = binds; it->button; ++it)
1046 mouse_bind(it->button, frame_context_from_string(it->context),
1047 it->mact, actions_parse_string(it->actname));
1050 void config_startup(ObtXmlInst *i)
1052 config_focus_new = TRUE;
1053 config_focus_follow = FALSE;
1054 config_focus_delay = 0;
1055 config_focus_raise = FALSE;
1056 config_focus_last = TRUE;
1057 config_focus_under_mouse = FALSE;
1058 config_unfocus_leave = FALSE;
1060 obt_xml_register(i, "focus", parse_focus, NULL);
1062 config_place_policy = OB_PLACE_POLICY_SMART;
1063 config_place_center = TRUE;
1064 config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
1066 config_primary_monitor_index = 1;
1067 config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
1069 obt_xml_register(i, "placement", parse_placement, NULL);
1071 STRUT_PARTIAL_SET(config_margins, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1073 obt_xml_register(i, "margins", parse_margins, NULL);
1075 config_theme = NULL;
1077 config_animate_iconify = TRUE;
1078 config_title_layout = g_strdup("NLIMC");
1079 config_theme_keepborder = TRUE;
1080 config_theme_window_list_icon_size = 36;
1082 config_font_activewindow = NULL;
1083 config_font_inactivewindow = NULL;
1084 config_font_menuitem = NULL;
1085 config_font_menutitle = NULL;
1086 config_font_activeosd = NULL;
1087 config_font_inactiveosd = NULL;
1089 obt_xml_register(i, "theme", parse_theme, NULL);
1091 config_desktops_num = 4;
1092 config_screen_firstdesk = 1;
1093 config_desktops_names = NULL;
1094 config_desktop_popup_time = 875;
1096 obt_xml_register(i, "desktops", parse_desktops, NULL);
1098 config_resize_redraw = TRUE;
1099 config_resize_popup_show = 1; /* nonpixel increments */
1100 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
1101 GRAVITY_COORD_SET(config_resize_popup_fixed.x, 0, FALSE, FALSE);
1102 GRAVITY_COORD_SET(config_resize_popup_fixed.y, 0, FALSE, FALSE);
1104 obt_xml_register(i, "resize", parse_resize, NULL);
1106 config_dock_layer = OB_STACKING_LAYER_ABOVE;
1107 config_dock_pos = OB_DIRECTION_NORTHEAST;
1108 config_dock_floating = FALSE;
1109 config_dock_nostrut = FALSE;
1110 config_dock_x = 0;
1111 config_dock_y = 0;
1112 config_dock_orient = OB_ORIENTATION_VERT;
1113 config_dock_hide = FALSE;
1114 config_dock_hide_delay = 300;
1115 config_dock_show_delay = 300;
1116 config_dock_app_move_button = 2; /* middle */
1117 config_dock_app_move_modifiers = 0;
1119 obt_xml_register(i, "dock", parse_dock, NULL);
1121 translate_key("C-g", &config_keyboard_reset_state,
1122 &config_keyboard_reset_keycode);
1124 bind_default_keyboard();
1126 obt_xml_register(i, "keyboard", parse_keyboard, NULL);
1128 config_mouse_threshold = 8;
1129 config_mouse_dclicktime = 500;
1130 config_mouse_screenedgetime = 400;
1131 config_mouse_screenedgewarp = FALSE;
1133 bind_default_mouse();
1135 obt_xml_register(i, "mouse", parse_mouse, NULL);
1137 config_resist_win = 10;
1138 config_resist_edge = 20;
1140 obt_xml_register(i, "resistance", parse_resistance, NULL);
1142 config_menu_hide_delay = 250;
1143 config_menu_middle = FALSE;
1144 config_submenu_show_delay = 100;
1145 config_submenu_hide_delay = 400;
1146 config_menu_manage_desktops = TRUE;
1147 config_menu_files = NULL;
1148 config_menu_show_icons = TRUE;
1150 obt_xml_register(i, "menu", parse_menu, NULL);
1152 config_per_app_settings = NULL;
1154 obt_xml_register(i, "applications", parse_per_app_settings, NULL);
1157 void config_shutdown(void)
1159 GSList *it;
1161 g_free(config_theme);
1163 g_free(config_title_layout);
1165 RrFontClose(config_font_activewindow);
1166 RrFontClose(config_font_inactivewindow);
1167 RrFontClose(config_font_menuitem);
1168 RrFontClose(config_font_menutitle);
1169 RrFontClose(config_font_activeosd);
1170 RrFontClose(config_font_inactiveosd);
1172 for (it = config_desktops_names; it; it = g_slist_next(it))
1173 g_free(it->data);
1174 g_slist_free(config_desktops_names);
1176 for (it = config_menu_files; it; it = g_slist_next(it))
1177 g_free(it->data);
1178 g_slist_free(config_menu_files);
1180 for (it = config_per_app_settings; it; it = g_slist_next(it)) {
1181 ObAppSettings *itd = (ObAppSettings *)it->data;
1182 if (itd->name) g_pattern_spec_free(itd->name);
1183 if (itd->role) g_pattern_spec_free(itd->role);
1184 if (itd->title) g_pattern_spec_free(itd->title);
1185 if (itd->class) g_pattern_spec_free(itd->class);
1186 if (itd->group_name) g_pattern_spec_free(itd->group_name);
1187 if (itd->group_class) g_pattern_spec_free(itd->group_class);
1188 g_slice_free(ObAppSettings, it->data);
1190 g_slist_free(config_per_app_settings);