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.
24 #include "translate.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;
38 guint config_directional_distance_weight;
39 guint config_directional_angle_weight;
41 ObPlacePolicy config_place_policy;
42 gboolean config_place_center;
43 ObPlaceMonitor config_place_monitor;
45 guint config_primary_monitor_index;
46 ObPlaceMonitor config_primary_monitor;
48 StrutPartial config_margins;
51 gboolean config_theme_keepborder;
52 guint config_theme_window_list_icon_size;
54 gchar *config_title_layout;
56 gboolean config_animate_iconify;
58 RrFont *config_font_activewindow;
59 RrFont *config_font_inactivewindow;
60 RrFont *config_font_menuitem;
61 RrFont *config_font_menutitle;
62 RrFont *config_font_activeosd;
63 RrFont *config_font_inactiveosd;
65 guint config_desktops_num;
66 GSList *config_desktops_names;
67 guint config_screen_firstdesk;
68 guint config_desktop_popup_time;
70 gboolean config_resize_redraw;
71 gint config_resize_popup_show;
72 ObResizePopupPos config_resize_popup_pos;
73 GravityPoint config_resize_popup_fixed;
75 ObStackingLayer config_dock_layer;
76 gboolean config_dock_floating;
77 gboolean config_dock_nostrut;
78 ObDirection config_dock_pos;
81 ObOrientation config_dock_orient;
82 gboolean config_dock_hide;
83 guint config_dock_hide_delay;
84 guint config_dock_show_delay;
85 guint config_dock_app_move_button;
86 guint config_dock_app_move_modifiers;
88 guint config_keyboard_reset_keycode;
89 guint config_keyboard_reset_state;
90 gboolean config_keyboard_rebind_on_mapping_notify;
92 gint config_mouse_threshold;
93 gint config_mouse_dclicktime;
94 gint config_mouse_screenedgetime;
95 gboolean config_mouse_screenedgewarp;
97 guint config_menu_hide_delay;
98 gboolean config_menu_middle;
99 guint config_submenu_show_delay;
100 guint config_submenu_hide_delay;
101 gboolean config_menu_manage_desktops;
102 gboolean config_menu_show_icons;
104 GSList *config_menu_files;
106 gint config_resist_win;
107 gint config_resist_edge;
109 GSList *config_per_app_settings;
111 ObAppSettings* config_create_app_settings(void)
113 ObAppSettings *settings = g_slice_new0(ObAppSettings);
115 settings->decor = -1;
116 settings->shade = -1;
117 settings->monitor_type = OB_PLACE_MONITOR_ANY;
118 settings->monitor = -1;
119 settings->focus = -1;
120 settings->desktop = 0;
121 settings->layer = -2;
122 settings->iconic = -1;
123 settings->skip_pager = -1;
124 settings->skip_taskbar = -1;
125 settings->fullscreen = -1;
126 settings->max_horz = -1;
127 settings->max_vert = -1;
131 #define copy_if(setting, default) \
132 if (src->setting != default) dst->setting = src->setting
133 void config_app_settings_copy_non_defaults(const ObAppSettings *src,
136 g_assert(src != NULL);
137 g_assert(dst != NULL);
139 copy_if(type, (ObClientType)-1);
142 copy_if(monitor_type, OB_PLACE_MONITOR_ANY);
143 copy_if(monitor, -1);
148 copy_if(skip_pager, -1);
149 copy_if(skip_taskbar, -1);
150 copy_if(fullscreen, -1);
151 copy_if(max_horz, -1);
152 copy_if(max_vert, -1);
154 if (src->pos_given) {
155 dst->pos_given = TRUE;
156 dst->pos_force = src->pos_force;
157 dst->position = src->position;
158 /* monitor is copied above */
161 dst->width_num = src->width_num;
162 dst->width_denom = src->width_denom;
163 dst->height_num = src->height_num;
164 dst->height_denom = src->height_denom;
167 void config_parse_relative_number(gchar *s, gint *num, gint *denom)
169 *num = strtol(s, &s, 10);
173 } else if (*s == '/') {
178 void config_parse_gravity_coord(xmlNodePtr node, GravityCoord *c)
180 gchar *s = obt_xml_node_string(node);
181 if (!g_ascii_strcasecmp(s, "center"))
187 if (s[0] == '-' || s[0] == '+')
189 config_parse_relative_number(ps, &c->pos, &c->denom);
196 <application name="aterm">
199 <application name="Rhythmbox">
206 .. there is a lot more settings available
211 static void parse_single_per_app_settings(xmlNodePtr app,
212 ObAppSettings *settings)
215 gboolean x_pos_given = FALSE;
217 if ((n = obt_xml_find_node(app->children, "decor")))
218 if (!obt_xml_node_contains(n, "default"))
219 settings->decor = obt_xml_node_bool(n);
221 if ((n = obt_xml_find_node(app->children, "shade")))
222 if (!obt_xml_node_contains(n, "default"))
223 settings->shade = obt_xml_node_bool(n);
225 if ((n = obt_xml_find_node(app->children, "position"))) {
226 if ((c = obt_xml_find_node(n->children, "x"))) {
227 if (!obt_xml_node_contains(c, "default")) {
228 config_parse_gravity_coord(c, &settings->position.x);
233 if (x_pos_given && (c = obt_xml_find_node(n->children, "y"))) {
234 if (!obt_xml_node_contains(c, "default")) {
235 config_parse_gravity_coord(c, &settings->position.y);
236 settings->pos_given = TRUE;
240 /* monitor can be set without setting x or y */
241 if ((c = obt_xml_find_node(n->children, "monitor"))) {
242 if (!obt_xml_node_contains(c, "default")) {
243 gchar *s = obt_xml_node_string(c);
244 if (!g_ascii_strcasecmp(s, "mouse"))
245 settings->monitor_type = OB_PLACE_MONITOR_MOUSE;
246 else if (!g_ascii_strcasecmp(s, "active"))
247 settings->monitor_type = OB_PLACE_MONITOR_ACTIVE;
248 else if (!g_ascii_strcasecmp(s, "primary"))
249 settings->monitor_type = OB_PLACE_MONITOR_PRIMARY;
251 settings->monitor = obt_xml_node_int(c);
256 obt_xml_attr_bool(n, "force", &settings->pos_force);
259 if ((n = obt_xml_find_node(app->children, "size"))) {
260 if ((c = obt_xml_find_node(n->children, "width"))) {
261 if (!obt_xml_node_contains(c, "default")) {
262 gchar *s = obt_xml_node_string(c);
263 config_parse_relative_number(s,
264 &settings->width_num,
265 &settings->width_denom);
266 if (settings->width_num <= 0 || settings->width_denom < 0)
267 settings->width_num = settings->width_denom = 0;
272 if ((c = obt_xml_find_node(n->children, "height"))) {
273 if (!obt_xml_node_contains(c, "default")) {
274 gchar *s = obt_xml_node_string(c);
275 config_parse_relative_number(s,
276 &settings->height_num,
277 &settings->height_denom);
278 if (settings->height_num <= 0 || settings->height_denom < 0)
279 settings->height_num = settings->height_denom = 0;
285 if ((n = obt_xml_find_node(app->children, "focus"))) {
286 if (!obt_xml_node_contains(n, "default"))
287 settings->focus = obt_xml_node_bool(n);
290 if ((n = obt_xml_find_node(app->children, "desktop"))) {
291 if (!obt_xml_node_contains(n, "default")) {
292 gchar *s = obt_xml_node_string(n);
293 if (!g_ascii_strcasecmp(s, "all"))
294 settings->desktop = DESKTOP_ALL;
296 gint i = obt_xml_node_int(n);
298 settings->desktop = i;
304 if ((n = obt_xml_find_node(app->children, "layer"))) {
305 if (!obt_xml_node_contains(n, "default")) {
306 gchar *s = obt_xml_node_string(n);
307 if (!g_ascii_strcasecmp(s, "above"))
309 else if (!g_ascii_strcasecmp(s, "below"))
310 settings->layer = -1;
317 if ((n = obt_xml_find_node(app->children, "iconic")))
318 if (!obt_xml_node_contains(n, "default"))
319 settings->iconic = obt_xml_node_bool(n);
321 if ((n = obt_xml_find_node(app->children, "skip_pager")))
322 if (!obt_xml_node_contains(n, "default"))
323 settings->skip_pager = obt_xml_node_bool(n);
325 if ((n = obt_xml_find_node(app->children, "skip_taskbar")))
326 if (!obt_xml_node_contains(n, "default"))
327 settings->skip_taskbar = obt_xml_node_bool(n);
329 if ((n = obt_xml_find_node(app->children, "fullscreen")))
330 if (!obt_xml_node_contains(n, "default"))
331 settings->fullscreen = obt_xml_node_bool(n);
333 if ((n = obt_xml_find_node(app->children, "maximized"))) {
334 if (!obt_xml_node_contains(n, "default")) {
335 gchar *s = obt_xml_node_string(n);
336 if (!g_ascii_strcasecmp(s, "horizontal")) {
337 settings->max_horz = TRUE;
338 settings->max_vert = FALSE;
339 } else if (!g_ascii_strcasecmp(s, "vertical")) {
340 settings->max_horz = FALSE;
341 settings->max_vert = TRUE;
343 settings->max_horz = settings->max_vert =
344 obt_xml_node_bool(n);
350 /* Manages settings for individual applications.
351 Some notes: monitor is the screen number in a multi monitor
352 (Xinerama) setup (starting from 0), or mouse: the monitor the pointer
353 is on, active: the active monitor, primary: the primary monitor.
354 Layer can be three values, above (Always on top), below
355 (Always on bottom) and everything else (normal behaviour).
356 Positions can be an integer value or center, which will
357 center the window in the specified axis. Position is within
358 the monitor, so <position><x>center</x></position><monitor>2</monitor>
359 will center the window on the second monitor.
361 static void parse_per_app_settings(xmlNodePtr node, gpointer d)
363 xmlNodePtr app = obt_xml_find_node(node->children, "application");
364 for (; app; app = obt_xml_find_node(app->next, "application")) {
365 ObAppSettings *settings;
367 gboolean name_set, class_set, role_set, title_set,
368 type_set, group_name_set, group_class_set;
369 gchar *name = NULL, *class = NULL, *role = NULL, *title = NULL,
370 *type_str = NULL, *group_name = NULL, *group_class = NULL;
373 class_set = obt_xml_attr_string(app, "class", &class);
374 name_set = obt_xml_attr_string(app, "name", &name);
375 group_class_set = obt_xml_attr_string(app, "groupclass", &group_class);
376 group_name_set = obt_xml_attr_string(app, "groupname", &group_name);
377 type_set = obt_xml_attr_string(app, "type", &type_str);
378 role_set = obt_xml_attr_string(app, "role", &role);
379 title_set = obt_xml_attr_string(app, "title", &title);
381 /* validate the type tho */
383 if (!g_ascii_strcasecmp(type_str, "normal"))
384 type = OB_CLIENT_TYPE_NORMAL;
385 else if (!g_ascii_strcasecmp(type_str, "dialog"))
386 type = OB_CLIENT_TYPE_DIALOG;
387 else if (!g_ascii_strcasecmp(type_str, "splash"))
388 type = OB_CLIENT_TYPE_SPLASH;
389 else if (!g_ascii_strcasecmp(type_str, "utility"))
390 type = OB_CLIENT_TYPE_UTILITY;
391 else if (!g_ascii_strcasecmp(type_str, "menu"))
392 type = OB_CLIENT_TYPE_MENU;
393 else if (!g_ascii_strcasecmp(type_str, "toolbar"))
394 type = OB_CLIENT_TYPE_TOOLBAR;
395 else if (!g_ascii_strcasecmp(type_str, "dock"))
396 type = OB_CLIENT_TYPE_DOCK;
397 else if (!g_ascii_strcasecmp(type_str, "desktop"))
398 type = OB_CLIENT_TYPE_DESKTOP;
400 type_set = FALSE; /* not valid! */
403 if (!(class_set || name_set || role_set || title_set ||
404 type_set || group_class_set || group_name_set))
407 settings = config_create_app_settings();
410 settings->name = g_pattern_spec_new(name);
412 settings->class = g_pattern_spec_new(class);
414 settings->group_name = g_pattern_spec_new(group_name);
416 settings->group_class = g_pattern_spec_new(group_class);
418 settings->role = g_pattern_spec_new(role);
420 settings->title = g_pattern_spec_new(title);
422 settings->type = type;
432 parse_single_per_app_settings(app, settings);
433 config_per_app_settings = g_slist_append(config_per_app_settings,
441 <action name="ChangeDesktop">
448 static void parse_key(xmlNodePtr node, GList *keylist)
450 gchar *keystring, **keys, **key;
452 gboolean is_chroot = FALSE;
453 gboolean grab = TRUE;
455 if (!obt_xml_attr_string(node, "key", &keystring))
458 obt_xml_attr_bool(node, "chroot", &is_chroot);
459 obt_xml_attr_bool(node, "grab", &grab);
461 keys = g_strsplit(keystring, " ", 0);
462 for (key = keys; *key; ++key) {
463 keylist = g_list_append(keylist, *key);
465 if ((n = obt_xml_find_node(node->children, "keybind"))) {
467 parse_key(n, keylist);
468 n = obt_xml_find_node(n->next, "keybind");
471 else if ((n = obt_xml_find_node(node->children, "action"))) {
473 ObActionsAct *action;
475 action = actions_parse(n);
477 keyboard_bind(keylist, action, grab);
478 n = obt_xml_find_node(n->next, "action");
484 keyboard_chroot(keylist);
485 keylist = g_list_delete_link(keylist, g_list_last(keylist));
492 static void parse_keyboard(xmlNodePtr node, gpointer d)
497 keyboard_unbind_all();
499 if ((n = obt_xml_find_node(node->children, "chainQuitKey"))) {
500 key = obt_xml_node_string(n);
501 translate_key(key, &config_keyboard_reset_state,
502 &config_keyboard_reset_keycode);
506 if ((n = obt_xml_find_node(node->children, "keybind")))
509 n = obt_xml_find_node(n->next, "keybind");
512 if ((n = obt_xml_find_node(node->children, "rebindOnMappingNotify")))
513 config_keyboard_rebind_on_mapping_notify = obt_xml_node_bool(n);
518 <context name="Titlebar">
519 <mousebind button="Left" action="Press">
520 <action name="Raise"></action>
526 static void parse_mouse(xmlNodePtr node, gpointer d)
528 xmlNodePtr n, nbut, nact;
535 node = node->children;
537 if ((n = obt_xml_find_node(node, "dragThreshold")))
538 config_mouse_threshold = obt_xml_node_int(n);
539 if ((n = obt_xml_find_node(node, "doubleClickTime")))
540 config_mouse_dclicktime = obt_xml_node_int(n);
541 if ((n = obt_xml_find_node(node, "screenEdgeWarpTime"))) {
542 config_mouse_screenedgetime = obt_xml_node_int(n);
543 /* minimum value of 25 for this property, when it is 1 and you hit the
544 edge it basically never stops */
545 if (config_mouse_screenedgetime && config_mouse_screenedgetime < 25)
546 config_mouse_screenedgetime = 25;
548 if ((n = obt_xml_find_node(node, "screenEdgeWarpMouse")))
549 config_mouse_screenedgewarp = obt_xml_node_bool(n);
551 for (n = obt_xml_find_node(node, "context");
553 n = obt_xml_find_node(n->next, "context"))
558 if (!obt_xml_attr_string(n, "name", &cxstr))
561 modcxstr = g_strdup(cxstr); /* make a copy to mutilate */
562 while (frame_next_context_from_string(modcxstr, &cx)) {
564 gchar *s = strchr(modcxstr, ' ');
567 g_message(_("Invalid context \"%s\" in mouse binding"),
574 for (nbut = obt_xml_find_node(n->children, "mousebind");
576 nbut = obt_xml_find_node(nbut->next, "mousebind"))
579 gchar **button, **buttons;
581 if (!obt_xml_attr_string(nbut, "button", &buttonstr))
583 if (obt_xml_attr_contains(nbut, "action", "press"))
584 mact = OB_MOUSE_ACTION_PRESS;
585 else if (obt_xml_attr_contains(nbut, "action", "release"))
586 mact = OB_MOUSE_ACTION_RELEASE;
587 else if (obt_xml_attr_contains(nbut, "action", "click"))
588 mact = OB_MOUSE_ACTION_CLICK;
589 else if (obt_xml_attr_contains(nbut, "action","doubleclick"))
590 mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
591 else if (obt_xml_attr_contains(nbut, "action", "drag"))
592 mact = OB_MOUSE_ACTION_MOTION;
596 buttons = g_strsplit(buttonstr, " ", 0);
597 for (nact = obt_xml_find_node(nbut->children, "action");
599 nact = obt_xml_find_node(nact->next, "action"))
601 ObActionsAct *action;
603 /* actions_parse() creates one ref to the action, but we need
604 * exactly one ref per binding we use it for. */
605 if ((action = actions_parse(nact))) {
606 for (button = buttons; *button; ++button) {
607 actions_act_ref(action);
608 mouse_bind(*button, cx, mact, action);
610 actions_act_unref(action);
622 static void parse_focus(xmlNodePtr node, gpointer d)
626 node = node->children;
628 if ((n = obt_xml_find_node(node, "focusNew")))
629 config_focus_new = obt_xml_node_bool(n);
630 if ((n = obt_xml_find_node(node, "followMouse")))
631 config_focus_follow = obt_xml_node_bool(n);
632 if ((n = obt_xml_find_node(node, "focusDelay")))
633 config_focus_delay = obt_xml_node_int(n);
634 if ((n = obt_xml_find_node(node, "raiseOnFocus")))
635 config_focus_raise = obt_xml_node_bool(n);
636 if ((n = obt_xml_find_node(node, "focusLast")))
637 config_focus_last = obt_xml_node_bool(n);
638 if ((n = obt_xml_find_node(node, "underMouse")))
639 config_focus_under_mouse = obt_xml_node_bool(n);
640 if ((n = obt_xml_find_node(node, "unfocusOnLeave")))
641 config_unfocus_leave = obt_xml_node_bool(n);
642 if ((n = obt_xml_find_node(node, "directionalDistanceWeight")))
643 config_directional_distance_weight = obt_xml_node_int(n);
645 config_directional_distance_weight = 1U;
646 if ((n = obt_xml_find_node(node, "directionalAngleWeight")))
647 config_directional_angle_weight = obt_xml_node_int(n);
649 config_directional_angle_weight = 1U;
652 static void parse_placement(xmlNodePtr node, gpointer d)
656 node = node->children;
658 if ((n = obt_xml_find_node(node, "policy"))) {
659 if (obt_xml_node_contains(n, "UnderMouse"))
660 config_place_policy = OB_PLACE_POLICY_MOUSE;
661 if (obt_xml_node_contains(n, "Random"))
662 config_place_policy = OB_PLACE_POLICY_RANDOM;
664 if ((n = obt_xml_find_node(node, "center"))) {
665 config_place_center = obt_xml_node_bool(n);
667 if ((n = obt_xml_find_node(node, "monitor"))) {
668 if (obt_xml_node_contains(n, "active"))
669 config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
670 else if (obt_xml_node_contains(n, "mouse"))
671 config_place_monitor = OB_PLACE_MONITOR_MOUSE;
672 else if (obt_xml_node_contains(n, "any"))
673 config_place_monitor = OB_PLACE_MONITOR_ANY;
675 if ((n = obt_xml_find_node(node, "primaryMonitor"))) {
676 config_primary_monitor_index = obt_xml_node_int(n);
677 if (!config_primary_monitor_index) {
678 if (obt_xml_node_contains(n, "mouse"))
679 config_primary_monitor = OB_PLACE_MONITOR_MOUSE;
684 static void parse_margins(xmlNodePtr node, gpointer d)
688 node = node->children;
690 if ((n = obt_xml_find_node(node, "top")))
691 config_margins.top = MAX(0, obt_xml_node_int(n));
692 if ((n = obt_xml_find_node(node, "left")))
693 config_margins.left = MAX(0, obt_xml_node_int(n));
694 if ((n = obt_xml_find_node(node, "right")))
695 config_margins.right = MAX(0, obt_xml_node_int(n));
696 if ((n = obt_xml_find_node(node, "bottom")))
697 config_margins.bottom = MAX(0, obt_xml_node_int(n));
700 static void parse_theme(xmlNodePtr node, gpointer d)
704 node = node->children;
706 if ((n = obt_xml_find_node(node, "name"))) {
709 g_free(config_theme);
710 c = obt_xml_node_string(n);
711 config_theme = obt_paths_expand_tilde(c);
714 if ((n = obt_xml_find_node(node, "titleLayout"))) {
717 g_free(config_title_layout);
718 config_title_layout = obt_xml_node_string(n);
720 /* replace duplicates with spaces */
721 for (c = config_title_layout; *c != '\0'; ++c)
722 for (d = c+1; *d != '\0'; ++d)
723 if (*c == *d) *d = ' ';
725 if ((n = obt_xml_find_node(node, "keepBorder")))
726 config_theme_keepborder = obt_xml_node_bool(n);
727 if ((n = obt_xml_find_node(node, "animateIconify")))
728 config_animate_iconify = obt_xml_node_bool(n);
729 if ((n = obt_xml_find_node(node, "windowListIconSize"))) {
730 config_theme_window_list_icon_size = obt_xml_node_int(n);
731 if (config_theme_window_list_icon_size < 16)
732 config_theme_window_list_icon_size = 16;
733 else if (config_theme_window_list_icon_size > 96)
734 config_theme_window_list_icon_size = 96;
737 for (n = obt_xml_find_node(node, "font");
739 n = obt_xml_find_node(n->next, "font"))
743 gchar *name = g_strdup(RrDefaultFontFamily);
744 gint size = RrDefaultFontSize;
745 RrFontWeight weight = RrDefaultFontWeight;
746 RrFontSlant slant = RrDefaultFontSlant;
748 if (obt_xml_attr_contains(n, "place", "ActiveWindow"))
749 font = &config_font_activewindow;
750 else if (obt_xml_attr_contains(n, "place", "InactiveWindow"))
751 font = &config_font_inactivewindow;
752 else if (obt_xml_attr_contains(n, "place", "MenuHeader"))
753 font = &config_font_menutitle;
754 else if (obt_xml_attr_contains(n, "place", "MenuItem"))
755 font = &config_font_menuitem;
756 else if (obt_xml_attr_contains(n, "place", "ActiveOnScreenDisplay"))
757 font = &config_font_activeosd;
758 else if (obt_xml_attr_contains(n, "place", "OnScreenDisplay"))
759 font = &config_font_activeosd;
760 else if (obt_xml_attr_contains(n, "place","InactiveOnScreenDisplay"))
761 font = &config_font_inactiveosd;
765 if ((fnode = obt_xml_find_node(n->children, "name"))) {
767 name = obt_xml_node_string(fnode);
769 if ((fnode = obt_xml_find_node(n->children, "size"))) {
770 int s = obt_xml_node_int(fnode);
773 if ((fnode = obt_xml_find_node(n->children, "weight"))) {
774 gchar *w = obt_xml_node_string(fnode);
775 if (!g_ascii_strcasecmp(w, "Bold"))
776 weight = RR_FONTWEIGHT_BOLD;
779 if ((fnode = obt_xml_find_node(n->children, "slant"))) {
780 gchar *s = obt_xml_node_string(fnode);
781 if (!g_ascii_strcasecmp(s, "Italic"))
782 slant = RR_FONTSLANT_ITALIC;
783 if (!g_ascii_strcasecmp(s, "Oblique"))
784 slant = RR_FONTSLANT_OBLIQUE;
788 *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
791 if ((fnode = obt_xml_find_node(n->children, "description"))) {
792 gchar *s = obt_xml_node_string(fnode);
793 RrFontDescriptionFromString(*font, s);
799 static void parse_desktops(xmlNodePtr node, gpointer d)
803 node = node->children;
805 if ((n = obt_xml_find_node(node, "number"))) {
806 gint d = obt_xml_node_int(n);
808 config_desktops_num = (unsigned) d;
810 if ((n = obt_xml_find_node(node, "firstdesk"))) {
811 gint d = obt_xml_node_int(n);
813 config_screen_firstdesk = (unsigned) d;
815 if ((n = obt_xml_find_node(node, "names"))) {
819 for (it = config_desktops_names; it; it = it->next)
821 g_slist_free(config_desktops_names);
822 config_desktops_names = NULL;
824 for (nname = obt_xml_find_node(n->children, "name");
826 nname = obt_xml_find_node(nname->next, "name"))
828 config_desktops_names =
829 g_slist_append(config_desktops_names,
830 obt_xml_node_string(nname));
833 if ((n = obt_xml_find_node(node, "popupTime")))
834 config_desktop_popup_time = obt_xml_node_int(n);
837 static void parse_resize(xmlNodePtr node, gpointer d)
841 node = node->children;
843 if ((n = obt_xml_find_node(node, "drawContents")))
844 config_resize_redraw = obt_xml_node_bool(n);
845 if ((n = obt_xml_find_node(node, "popupShow"))) {
846 config_resize_popup_show = obt_xml_node_int(n);
847 if (obt_xml_node_contains(n, "Always"))
848 config_resize_popup_show = 2;
849 else if (obt_xml_node_contains(n, "Never"))
850 config_resize_popup_show = 0;
851 else if (obt_xml_node_contains(n, "Nonpixel"))
852 config_resize_popup_show = 1;
854 if ((n = obt_xml_find_node(node, "popupPosition"))) {
855 if (obt_xml_node_contains(n, "Top"))
856 config_resize_popup_pos = OB_RESIZE_POS_TOP;
857 else if (obt_xml_node_contains(n, "Center"))
858 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
859 else if (obt_xml_node_contains(n, "Fixed")) {
860 config_resize_popup_pos = OB_RESIZE_POS_FIXED;
862 if ((n = obt_xml_find_node(node, "popupFixedPosition"))) {
865 if ((n2 = obt_xml_find_node(n->children, "x")))
866 config_parse_gravity_coord(n2,
867 &config_resize_popup_fixed.x);
868 if ((n2 = obt_xml_find_node(n->children, "y")))
869 config_parse_gravity_coord(n2,
870 &config_resize_popup_fixed.y);
872 config_resize_popup_fixed.x.pos =
873 MAX(config_resize_popup_fixed.x.pos, 0);
874 config_resize_popup_fixed.y.pos =
875 MAX(config_resize_popup_fixed.y.pos, 0);
881 static void parse_dock(xmlNodePtr node, gpointer d)
885 node = node->children;
887 if ((n = obt_xml_find_node(node, "position"))) {
888 if (obt_xml_node_contains(n, "TopLeft"))
889 config_dock_floating = FALSE,
890 config_dock_pos = OB_DIRECTION_NORTHWEST;
891 else if (obt_xml_node_contains(n, "Top"))
892 config_dock_floating = FALSE,
893 config_dock_pos = OB_DIRECTION_NORTH;
894 else if (obt_xml_node_contains(n, "TopRight"))
895 config_dock_floating = FALSE,
896 config_dock_pos = OB_DIRECTION_NORTHEAST;
897 else if (obt_xml_node_contains(n, "Right"))
898 config_dock_floating = FALSE,
899 config_dock_pos = OB_DIRECTION_EAST;
900 else if (obt_xml_node_contains(n, "BottomRight"))
901 config_dock_floating = FALSE,
902 config_dock_pos = OB_DIRECTION_SOUTHEAST;
903 else if (obt_xml_node_contains(n, "Bottom"))
904 config_dock_floating = FALSE,
905 config_dock_pos = OB_DIRECTION_SOUTH;
906 else if (obt_xml_node_contains(n, "BottomLeft"))
907 config_dock_floating = FALSE,
908 config_dock_pos = OB_DIRECTION_SOUTHWEST;
909 else if (obt_xml_node_contains(n, "Left"))
910 config_dock_floating = FALSE,
911 config_dock_pos = OB_DIRECTION_WEST;
912 else if (obt_xml_node_contains(n, "Floating"))
913 config_dock_floating = TRUE;
915 if (config_dock_floating) {
916 if ((n = obt_xml_find_node(node, "floatingX")))
917 config_dock_x = obt_xml_node_int(n);
918 if ((n = obt_xml_find_node(node, "floatingY")))
919 config_dock_y = obt_xml_node_int(n);
921 if ((n = obt_xml_find_node(node, "noStrut")))
922 config_dock_nostrut = obt_xml_node_bool(n);
924 if ((n = obt_xml_find_node(node, "stacking"))) {
925 if (obt_xml_node_contains(n, "normal"))
926 config_dock_layer = OB_STACKING_LAYER_NORMAL;
927 else if (obt_xml_node_contains(n, "below"))
928 config_dock_layer = OB_STACKING_LAYER_BELOW;
929 else if (obt_xml_node_contains(n, "above"))
930 config_dock_layer = OB_STACKING_LAYER_ABOVE;
932 if ((n = obt_xml_find_node(node, "direction"))) {
933 if (obt_xml_node_contains(n, "horizontal"))
934 config_dock_orient = OB_ORIENTATION_HORZ;
935 else if (obt_xml_node_contains(n, "vertical"))
936 config_dock_orient = OB_ORIENTATION_VERT;
938 if ((n = obt_xml_find_node(node, "autoHide")))
939 config_dock_hide = obt_xml_node_bool(n);
940 if ((n = obt_xml_find_node(node, "hideDelay")))
941 config_dock_hide_delay = obt_xml_node_int(n);
942 if ((n = obt_xml_find_node(node, "showDelay")))
943 config_dock_show_delay = obt_xml_node_int(n);
944 if ((n = obt_xml_find_node(node, "moveButton"))) {
945 gchar *str = obt_xml_node_string(n);
947 if (translate_button(str, &s, &b)) {
948 config_dock_app_move_button = b;
949 config_dock_app_move_modifiers = s;
951 g_message(_("Invalid button \"%s\" specified in config file"), str);
957 static void parse_menu(xmlNodePtr node, gpointer d)
960 node = node->children;
962 if ((n = obt_xml_find_node(node, "hideDelay")))
963 config_menu_hide_delay = obt_xml_node_int(n);
964 if ((n = obt_xml_find_node(node, "middle")))
965 config_menu_middle = obt_xml_node_bool(n);
966 if ((n = obt_xml_find_node(node, "submenuShowDelay")))
967 config_submenu_show_delay = obt_xml_node_int(n);
968 if ((n = obt_xml_find_node(node, "submenuHideDelay")))
969 config_submenu_hide_delay = obt_xml_node_int(n);
970 if ((n = obt_xml_find_node(node, "manageDesktops")))
971 config_menu_manage_desktops = obt_xml_node_bool(n);
972 if ((n = obt_xml_find_node(node, "showIcons"))) {
973 config_menu_show_icons = obt_xml_node_bool(n);
974 #if !defined(USE_IMLIB2) && !defined(USE_LIBRSVG)
975 if (config_menu_show_icons)
976 g_message(_("Openbox was compiled without image loading support. Icons in menus will not be loaded."));
980 for (node = obt_xml_find_node(node, "file");
982 node = obt_xml_find_node(node->next, "file"))
984 gchar *c = obt_xml_node_string(node);
985 config_menu_files = g_slist_append(config_menu_files,
986 obt_paths_expand_tilde(c));
991 static void parse_resistance(xmlNodePtr node, gpointer d)
995 node = node->children;
996 if ((n = obt_xml_find_node(node, "strength")))
997 config_resist_win = obt_xml_node_int(n);
998 if ((n = obt_xml_find_node(node, "screen_edge_strength")))
999 config_resist_edge = obt_xml_node_int(n);
1005 const gchar *actname;
1008 static void bind_default_keyboard(void)
1011 ObDefKeyBind binds[] = {
1012 { "A-Tab", "NextWindow" },
1013 { "S-A-Tab", "PreviousWindow" },
1014 { "A-F4", "Close" },
1017 for (it = binds; it->key; ++it) {
1018 GList *l = g_list_append(NULL, g_strdup(it->key));
1019 keyboard_bind(l, actions_parse_string(it->actname), TRUE);
1025 const gchar *button;
1026 const gchar *context;
1027 const ObMouseAction mact;
1028 const gchar *actname;
1031 static void bind_default_mouse(void)
1034 ObDefMouseBind binds[] = {
1035 { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1036 { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1037 { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1038 { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1039 { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1040 { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1041 { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
1042 { "Left", "Bottom", OB_MOUSE_ACTION_PRESS, "Focus" },
1043 { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1044 { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1045 { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1046 { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1047 { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
1048 { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
1049 { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
1050 { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
1051 { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
1052 { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
1053 { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
1054 { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
1055 { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
1056 { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1057 { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1058 { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1059 { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1060 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
1061 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
1062 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
1063 { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
1064 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
1065 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
1066 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
1067 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximize" },
1068 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
1069 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
1070 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
1071 { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1072 { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1073 { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1074 { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1075 { "Left", "Top", OB_MOUSE_ACTION_MOTION, "Resize" },
1076 { "Left", "Bottom", OB_MOUSE_ACTION_MOTION, "Resize" },
1077 { "Left", "Left", OB_MOUSE_ACTION_MOTION, "Resize" },
1078 { "Left", "Right", OB_MOUSE_ACTION_MOTION, "Resize" },
1079 { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
1080 { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
1081 { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
1082 { NULL, NULL, 0, NULL }
1085 for (it = binds; it->button; ++it)
1086 mouse_bind(it->button, frame_context_from_string(it->context),
1087 it->mact, actions_parse_string(it->actname));
1090 void config_startup(ObtXmlInst *i)
1092 config_focus_new = TRUE;
1093 config_focus_follow = FALSE;
1094 config_focus_delay = 0;
1095 config_focus_raise = FALSE;
1096 config_focus_last = TRUE;
1097 config_focus_under_mouse = FALSE;
1098 config_unfocus_leave = FALSE;
1100 obt_xml_register(i, "focus", parse_focus, NULL);
1102 config_place_policy = OB_PLACE_POLICY_SMART;
1103 config_place_center = TRUE;
1104 config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
1106 config_primary_monitor_index = 1;
1107 config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
1109 obt_xml_register(i, "placement", parse_placement, NULL);
1111 STRUT_PARTIAL_SET(config_margins, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1113 obt_xml_register(i, "margins", parse_margins, NULL);
1115 config_theme = NULL;
1117 config_animate_iconify = TRUE;
1118 config_title_layout = g_strdup("NLIMC");
1119 config_theme_keepborder = TRUE;
1120 config_theme_window_list_icon_size = 36;
1122 config_font_activewindow = NULL;
1123 config_font_inactivewindow = NULL;
1124 config_font_menuitem = NULL;
1125 config_font_menutitle = NULL;
1126 config_font_activeosd = NULL;
1127 config_font_inactiveosd = NULL;
1129 obt_xml_register(i, "theme", parse_theme, NULL);
1131 config_desktops_num = 4;
1132 config_screen_firstdesk = 1;
1133 config_desktops_names = NULL;
1134 config_desktop_popup_time = 875;
1136 obt_xml_register(i, "desktops", parse_desktops, NULL);
1138 config_resize_redraw = TRUE;
1139 config_resize_popup_show = 1; /* nonpixel increments */
1140 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
1141 GRAVITY_COORD_SET(config_resize_popup_fixed.x, 0, FALSE, FALSE);
1142 GRAVITY_COORD_SET(config_resize_popup_fixed.y, 0, FALSE, FALSE);
1144 obt_xml_register(i, "resize", parse_resize, NULL);
1146 config_dock_layer = OB_STACKING_LAYER_ABOVE;
1147 config_dock_pos = OB_DIRECTION_NORTHEAST;
1148 config_dock_floating = FALSE;
1149 config_dock_nostrut = FALSE;
1152 config_dock_orient = OB_ORIENTATION_VERT;
1153 config_dock_hide = FALSE;
1154 config_dock_hide_delay = 300;
1155 config_dock_show_delay = 300;
1156 config_dock_app_move_button = 2; /* middle */
1157 config_dock_app_move_modifiers = 0;
1159 obt_xml_register(i, "dock", parse_dock, NULL);
1161 translate_key("C-g", &config_keyboard_reset_state,
1162 &config_keyboard_reset_keycode);
1163 config_keyboard_rebind_on_mapping_notify = TRUE;
1165 bind_default_keyboard();
1167 obt_xml_register(i, "keyboard", parse_keyboard, NULL);
1169 config_mouse_threshold = 8;
1170 config_mouse_dclicktime = 500;
1171 config_mouse_screenedgetime = 400;
1172 config_mouse_screenedgewarp = FALSE;
1174 bind_default_mouse();
1176 obt_xml_register(i, "mouse", parse_mouse, NULL);
1178 config_resist_win = 10;
1179 config_resist_edge = 20;
1181 obt_xml_register(i, "resistance", parse_resistance, NULL);
1183 config_menu_hide_delay = 250;
1184 config_menu_middle = FALSE;
1185 config_submenu_show_delay = 100;
1186 config_submenu_hide_delay = 400;
1187 config_menu_manage_desktops = TRUE;
1188 config_menu_files = NULL;
1189 config_menu_show_icons = TRUE;
1191 obt_xml_register(i, "menu", parse_menu, NULL);
1193 config_per_app_settings = NULL;
1195 obt_xml_register(i, "applications", parse_per_app_settings, NULL);
1198 void config_shutdown(void)
1202 g_free(config_theme);
1204 g_free(config_title_layout);
1206 RrFontClose(config_font_activewindow);
1207 RrFontClose(config_font_inactivewindow);
1208 RrFontClose(config_font_menuitem);
1209 RrFontClose(config_font_menutitle);
1210 RrFontClose(config_font_activeosd);
1211 RrFontClose(config_font_inactiveosd);
1213 for (it = config_desktops_names; it; it = g_slist_next(it))
1215 g_slist_free(config_desktops_names);
1217 for (it = config_menu_files; it; it = g_slist_next(it))
1219 g_slist_free(config_menu_files);
1221 for (it = config_per_app_settings; it; it = g_slist_next(it)) {
1222 ObAppSettings *itd = (ObAppSettings *)it->data;
1223 if (itd->name) g_pattern_spec_free(itd->name);
1224 if (itd->role) g_pattern_spec_free(itd->role);
1225 if (itd->title) g_pattern_spec_free(itd->title);
1226 if (itd->class) g_pattern_spec_free(itd->class);
1227 if (itd->group_name) g_pattern_spec_free(itd->group_name);
1228 if (itd->group_class) g_pattern_spec_free(itd->group_class);
1229 g_slice_free(ObAppSettings, it->data);
1231 g_slist_free(config_per_app_settings);