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;
662 if ((n = obt_xml_find_node(node, "center"))) {
663 config_place_center = obt_xml_node_bool(n);
665 if ((n = obt_xml_find_node(node, "monitor"))) {
666 if (obt_xml_node_contains(n, "active"))
667 config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
668 else if (obt_xml_node_contains(n, "mouse"))
669 config_place_monitor = OB_PLACE_MONITOR_MOUSE;
670 else if (obt_xml_node_contains(n, "any"))
671 config_place_monitor = OB_PLACE_MONITOR_ANY;
673 if ((n = obt_xml_find_node(node, "primaryMonitor"))) {
674 config_primary_monitor_index = obt_xml_node_int(n);
675 if (!config_primary_monitor_index) {
676 if (obt_xml_node_contains(n, "mouse"))
677 config_primary_monitor = OB_PLACE_MONITOR_MOUSE;
682 static void parse_margins(xmlNodePtr node, gpointer d)
686 node = node->children;
688 if ((n = obt_xml_find_node(node, "top")))
689 config_margins.top = MAX(0, obt_xml_node_int(n));
690 if ((n = obt_xml_find_node(node, "left")))
691 config_margins.left = MAX(0, obt_xml_node_int(n));
692 if ((n = obt_xml_find_node(node, "right")))
693 config_margins.right = MAX(0, obt_xml_node_int(n));
694 if ((n = obt_xml_find_node(node, "bottom")))
695 config_margins.bottom = MAX(0, obt_xml_node_int(n));
698 static void parse_theme(xmlNodePtr node, gpointer d)
702 node = node->children;
704 if ((n = obt_xml_find_node(node, "name"))) {
707 g_free(config_theme);
708 c = obt_xml_node_string(n);
709 config_theme = obt_paths_expand_tilde(c);
712 if ((n = obt_xml_find_node(node, "titleLayout"))) {
715 g_free(config_title_layout);
716 config_title_layout = obt_xml_node_string(n);
718 /* replace duplicates with spaces */
719 for (c = config_title_layout; *c != '\0'; ++c)
720 for (d = c+1; *d != '\0'; ++d)
721 if (*c == *d) *d = ' ';
723 if ((n = obt_xml_find_node(node, "keepBorder")))
724 config_theme_keepborder = obt_xml_node_bool(n);
725 if ((n = obt_xml_find_node(node, "animateIconify")))
726 config_animate_iconify = obt_xml_node_bool(n);
727 if ((n = obt_xml_find_node(node, "windowListIconSize"))) {
728 config_theme_window_list_icon_size = obt_xml_node_int(n);
729 if (config_theme_window_list_icon_size < 16)
730 config_theme_window_list_icon_size = 16;
731 else if (config_theme_window_list_icon_size > 96)
732 config_theme_window_list_icon_size = 96;
735 for (n = obt_xml_find_node(node, "font");
737 n = obt_xml_find_node(n->next, "font"))
741 gchar *name = g_strdup(RrDefaultFontFamily);
742 gint size = RrDefaultFontSize;
743 RrFontWeight weight = RrDefaultFontWeight;
744 RrFontSlant slant = RrDefaultFontSlant;
746 if (obt_xml_attr_contains(n, "place", "ActiveWindow"))
747 font = &config_font_activewindow;
748 else if (obt_xml_attr_contains(n, "place", "InactiveWindow"))
749 font = &config_font_inactivewindow;
750 else if (obt_xml_attr_contains(n, "place", "MenuHeader"))
751 font = &config_font_menutitle;
752 else if (obt_xml_attr_contains(n, "place", "MenuItem"))
753 font = &config_font_menuitem;
754 else if (obt_xml_attr_contains(n, "place", "ActiveOnScreenDisplay"))
755 font = &config_font_activeosd;
756 else if (obt_xml_attr_contains(n, "place", "OnScreenDisplay"))
757 font = &config_font_activeosd;
758 else if (obt_xml_attr_contains(n, "place","InactiveOnScreenDisplay"))
759 font = &config_font_inactiveosd;
763 if ((fnode = obt_xml_find_node(n->children, "name"))) {
765 name = obt_xml_node_string(fnode);
767 if ((fnode = obt_xml_find_node(n->children, "size"))) {
768 int s = obt_xml_node_int(fnode);
771 if ((fnode = obt_xml_find_node(n->children, "weight"))) {
772 gchar *w = obt_xml_node_string(fnode);
773 if (!g_ascii_strcasecmp(w, "Bold"))
774 weight = RR_FONTWEIGHT_BOLD;
777 if ((fnode = obt_xml_find_node(n->children, "slant"))) {
778 gchar *s = obt_xml_node_string(fnode);
779 if (!g_ascii_strcasecmp(s, "Italic"))
780 slant = RR_FONTSLANT_ITALIC;
781 if (!g_ascii_strcasecmp(s, "Oblique"))
782 slant = RR_FONTSLANT_OBLIQUE;
786 *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
791 static void parse_desktops(xmlNodePtr node, gpointer d)
795 node = node->children;
797 if ((n = obt_xml_find_node(node, "number"))) {
798 gint d = obt_xml_node_int(n);
800 config_desktops_num = (unsigned) d;
802 if ((n = obt_xml_find_node(node, "firstdesk"))) {
803 gint d = obt_xml_node_int(n);
805 config_screen_firstdesk = (unsigned) d;
807 if ((n = obt_xml_find_node(node, "names"))) {
811 for (it = config_desktops_names; it; it = it->next)
813 g_slist_free(config_desktops_names);
814 config_desktops_names = NULL;
816 for (nname = obt_xml_find_node(n->children, "name");
818 nname = obt_xml_find_node(nname->next, "name"))
820 config_desktops_names =
821 g_slist_append(config_desktops_names,
822 obt_xml_node_string(nname));
825 if ((n = obt_xml_find_node(node, "popupTime")))
826 config_desktop_popup_time = obt_xml_node_int(n);
829 static void parse_resize(xmlNodePtr node, gpointer d)
833 node = node->children;
835 if ((n = obt_xml_find_node(node, "drawContents")))
836 config_resize_redraw = obt_xml_node_bool(n);
837 if ((n = obt_xml_find_node(node, "popupShow"))) {
838 config_resize_popup_show = obt_xml_node_int(n);
839 if (obt_xml_node_contains(n, "Always"))
840 config_resize_popup_show = 2;
841 else if (obt_xml_node_contains(n, "Never"))
842 config_resize_popup_show = 0;
843 else if (obt_xml_node_contains(n, "Nonpixel"))
844 config_resize_popup_show = 1;
846 if ((n = obt_xml_find_node(node, "popupPosition"))) {
847 if (obt_xml_node_contains(n, "Top"))
848 config_resize_popup_pos = OB_RESIZE_POS_TOP;
849 else if (obt_xml_node_contains(n, "Center"))
850 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
851 else if (obt_xml_node_contains(n, "Fixed")) {
852 config_resize_popup_pos = OB_RESIZE_POS_FIXED;
854 if ((n = obt_xml_find_node(node, "popupFixedPosition"))) {
857 if ((n2 = obt_xml_find_node(n->children, "x")))
858 config_parse_gravity_coord(n2,
859 &config_resize_popup_fixed.x);
860 if ((n2 = obt_xml_find_node(n->children, "y")))
861 config_parse_gravity_coord(n2,
862 &config_resize_popup_fixed.y);
864 config_resize_popup_fixed.x.pos =
865 MAX(config_resize_popup_fixed.x.pos, 0);
866 config_resize_popup_fixed.y.pos =
867 MAX(config_resize_popup_fixed.y.pos, 0);
873 static void parse_dock(xmlNodePtr node, gpointer d)
877 node = node->children;
879 if ((n = obt_xml_find_node(node, "position"))) {
880 if (obt_xml_node_contains(n, "TopLeft"))
881 config_dock_floating = FALSE,
882 config_dock_pos = OB_DIRECTION_NORTHWEST;
883 else if (obt_xml_node_contains(n, "Top"))
884 config_dock_floating = FALSE,
885 config_dock_pos = OB_DIRECTION_NORTH;
886 else if (obt_xml_node_contains(n, "TopRight"))
887 config_dock_floating = FALSE,
888 config_dock_pos = OB_DIRECTION_NORTHEAST;
889 else if (obt_xml_node_contains(n, "Right"))
890 config_dock_floating = FALSE,
891 config_dock_pos = OB_DIRECTION_EAST;
892 else if (obt_xml_node_contains(n, "BottomRight"))
893 config_dock_floating = FALSE,
894 config_dock_pos = OB_DIRECTION_SOUTHEAST;
895 else if (obt_xml_node_contains(n, "Bottom"))
896 config_dock_floating = FALSE,
897 config_dock_pos = OB_DIRECTION_SOUTH;
898 else if (obt_xml_node_contains(n, "BottomLeft"))
899 config_dock_floating = FALSE,
900 config_dock_pos = OB_DIRECTION_SOUTHWEST;
901 else if (obt_xml_node_contains(n, "Left"))
902 config_dock_floating = FALSE,
903 config_dock_pos = OB_DIRECTION_WEST;
904 else if (obt_xml_node_contains(n, "Floating"))
905 config_dock_floating = TRUE;
907 if (config_dock_floating) {
908 if ((n = obt_xml_find_node(node, "floatingX")))
909 config_dock_x = obt_xml_node_int(n);
910 if ((n = obt_xml_find_node(node, "floatingY")))
911 config_dock_y = obt_xml_node_int(n);
913 if ((n = obt_xml_find_node(node, "noStrut")))
914 config_dock_nostrut = obt_xml_node_bool(n);
916 if ((n = obt_xml_find_node(node, "stacking"))) {
917 if (obt_xml_node_contains(n, "normal"))
918 config_dock_layer = OB_STACKING_LAYER_NORMAL;
919 else if (obt_xml_node_contains(n, "below"))
920 config_dock_layer = OB_STACKING_LAYER_BELOW;
921 else if (obt_xml_node_contains(n, "above"))
922 config_dock_layer = OB_STACKING_LAYER_ABOVE;
924 if ((n = obt_xml_find_node(node, "direction"))) {
925 if (obt_xml_node_contains(n, "horizontal"))
926 config_dock_orient = OB_ORIENTATION_HORZ;
927 else if (obt_xml_node_contains(n, "vertical"))
928 config_dock_orient = OB_ORIENTATION_VERT;
930 if ((n = obt_xml_find_node(node, "autoHide")))
931 config_dock_hide = obt_xml_node_bool(n);
932 if ((n = obt_xml_find_node(node, "hideDelay")))
933 config_dock_hide_delay = obt_xml_node_int(n);
934 if ((n = obt_xml_find_node(node, "showDelay")))
935 config_dock_show_delay = obt_xml_node_int(n);
936 if ((n = obt_xml_find_node(node, "moveButton"))) {
937 gchar *str = obt_xml_node_string(n);
939 if (translate_button(str, &s, &b)) {
940 config_dock_app_move_button = b;
941 config_dock_app_move_modifiers = s;
943 g_message(_("Invalid button \"%s\" specified in config file"), str);
949 static void parse_menu(xmlNodePtr node, gpointer d)
952 node = node->children;
954 if ((n = obt_xml_find_node(node, "hideDelay")))
955 config_menu_hide_delay = obt_xml_node_int(n);
956 if ((n = obt_xml_find_node(node, "middle")))
957 config_menu_middle = obt_xml_node_bool(n);
958 if ((n = obt_xml_find_node(node, "submenuShowDelay")))
959 config_submenu_show_delay = obt_xml_node_int(n);
960 if ((n = obt_xml_find_node(node, "submenuHideDelay")))
961 config_submenu_hide_delay = obt_xml_node_int(n);
962 if ((n = obt_xml_find_node(node, "manageDesktops")))
963 config_menu_manage_desktops = obt_xml_node_bool(n);
964 if ((n = obt_xml_find_node(node, "showIcons"))) {
965 config_menu_show_icons = obt_xml_node_bool(n);
966 #if !defined(USE_IMLIB2) && !defined(USE_LIBRSVG)
967 if (config_menu_show_icons)
968 g_message(_("Openbox was compiled without image loading support. Icons in menus will not be loaded."));
972 for (node = obt_xml_find_node(node, "file");
974 node = obt_xml_find_node(node->next, "file"))
976 gchar *c = obt_xml_node_string(node);
977 config_menu_files = g_slist_append(config_menu_files,
978 obt_paths_expand_tilde(c));
983 static void parse_resistance(xmlNodePtr node, gpointer d)
987 node = node->children;
988 if ((n = obt_xml_find_node(node, "strength")))
989 config_resist_win = obt_xml_node_int(n);
990 if ((n = obt_xml_find_node(node, "screen_edge_strength")))
991 config_resist_edge = obt_xml_node_int(n);
997 const gchar *actname;
1000 static void bind_default_keyboard(void)
1003 ObDefKeyBind binds[] = {
1004 { "A-Tab", "NextWindow" },
1005 { "S-A-Tab", "PreviousWindow" },
1006 { "A-F4", "Close" },
1009 for (it = binds; it->key; ++it) {
1010 GList *l = g_list_append(NULL, g_strdup(it->key));
1011 keyboard_bind(l, actions_parse_string(it->actname), TRUE);
1017 const gchar *button;
1018 const gchar *context;
1019 const ObMouseAction mact;
1020 const gchar *actname;
1023 static void bind_default_mouse(void)
1026 ObDefMouseBind binds[] = {
1027 { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1028 { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1029 { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1030 { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1031 { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1032 { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1033 { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
1034 { "Left", "Bottom", OB_MOUSE_ACTION_PRESS, "Focus" },
1035 { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1036 { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1037 { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1038 { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1039 { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
1040 { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
1041 { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
1042 { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
1043 { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
1044 { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
1045 { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
1046 { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
1047 { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
1048 { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1049 { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1050 { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1051 { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1052 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
1053 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
1054 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
1055 { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
1056 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
1057 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
1058 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
1059 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximize" },
1060 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
1061 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
1062 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
1063 { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1064 { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1065 { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1066 { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1067 { "Left", "Top", OB_MOUSE_ACTION_MOTION, "Resize" },
1068 { "Left", "Bottom", OB_MOUSE_ACTION_MOTION, "Resize" },
1069 { "Left", "Left", OB_MOUSE_ACTION_MOTION, "Resize" },
1070 { "Left", "Right", OB_MOUSE_ACTION_MOTION, "Resize" },
1071 { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
1072 { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
1073 { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
1074 { NULL, NULL, 0, NULL }
1077 for (it = binds; it->button; ++it)
1078 mouse_bind(it->button, frame_context_from_string(it->context),
1079 it->mact, actions_parse_string(it->actname));
1082 void config_startup(ObtXmlInst *i)
1084 config_focus_new = TRUE;
1085 config_focus_follow = FALSE;
1086 config_focus_delay = 0;
1087 config_focus_raise = FALSE;
1088 config_focus_last = TRUE;
1089 config_focus_under_mouse = FALSE;
1090 config_unfocus_leave = FALSE;
1092 obt_xml_register(i, "focus", parse_focus, NULL);
1094 config_place_policy = OB_PLACE_POLICY_SMART;
1095 config_place_center = TRUE;
1096 config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
1098 config_primary_monitor_index = 1;
1099 config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
1101 obt_xml_register(i, "placement", parse_placement, NULL);
1103 STRUT_PARTIAL_SET(config_margins, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1105 obt_xml_register(i, "margins", parse_margins, NULL);
1107 config_theme = NULL;
1109 config_animate_iconify = TRUE;
1110 config_title_layout = g_strdup("NLIMC");
1111 config_theme_keepborder = TRUE;
1112 config_theme_window_list_icon_size = 36;
1114 config_font_activewindow = NULL;
1115 config_font_inactivewindow = NULL;
1116 config_font_menuitem = NULL;
1117 config_font_menutitle = NULL;
1118 config_font_activeosd = NULL;
1119 config_font_inactiveosd = NULL;
1121 obt_xml_register(i, "theme", parse_theme, NULL);
1123 config_desktops_num = 4;
1124 config_screen_firstdesk = 1;
1125 config_desktops_names = NULL;
1126 config_desktop_popup_time = 875;
1128 obt_xml_register(i, "desktops", parse_desktops, NULL);
1130 config_resize_redraw = TRUE;
1131 config_resize_popup_show = 1; /* nonpixel increments */
1132 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
1133 GRAVITY_COORD_SET(config_resize_popup_fixed.x, 0, FALSE, FALSE);
1134 GRAVITY_COORD_SET(config_resize_popup_fixed.y, 0, FALSE, FALSE);
1136 obt_xml_register(i, "resize", parse_resize, NULL);
1138 config_dock_layer = OB_STACKING_LAYER_ABOVE;
1139 config_dock_pos = OB_DIRECTION_NORTHEAST;
1140 config_dock_floating = FALSE;
1141 config_dock_nostrut = FALSE;
1144 config_dock_orient = OB_ORIENTATION_VERT;
1145 config_dock_hide = FALSE;
1146 config_dock_hide_delay = 300;
1147 config_dock_show_delay = 300;
1148 config_dock_app_move_button = 2; /* middle */
1149 config_dock_app_move_modifiers = 0;
1151 obt_xml_register(i, "dock", parse_dock, NULL);
1153 translate_key("C-g", &config_keyboard_reset_state,
1154 &config_keyboard_reset_keycode);
1155 config_keyboard_rebind_on_mapping_notify = TRUE;
1157 bind_default_keyboard();
1159 obt_xml_register(i, "keyboard", parse_keyboard, NULL);
1161 config_mouse_threshold = 8;
1162 config_mouse_dclicktime = 500;
1163 config_mouse_screenedgetime = 400;
1164 config_mouse_screenedgewarp = FALSE;
1166 bind_default_mouse();
1168 obt_xml_register(i, "mouse", parse_mouse, NULL);
1170 config_resist_win = 10;
1171 config_resist_edge = 20;
1173 obt_xml_register(i, "resistance", parse_resistance, NULL);
1175 config_menu_hide_delay = 250;
1176 config_menu_middle = FALSE;
1177 config_submenu_show_delay = 100;
1178 config_submenu_hide_delay = 400;
1179 config_menu_manage_desktops = TRUE;
1180 config_menu_files = NULL;
1181 config_menu_show_icons = TRUE;
1183 obt_xml_register(i, "menu", parse_menu, NULL);
1185 config_per_app_settings = NULL;
1187 obt_xml_register(i, "applications", parse_per_app_settings, NULL);
1190 void config_shutdown(void)
1194 g_free(config_theme);
1196 g_free(config_title_layout);
1198 RrFontClose(config_font_activewindow);
1199 RrFontClose(config_font_inactivewindow);
1200 RrFontClose(config_font_menuitem);
1201 RrFontClose(config_font_menutitle);
1202 RrFontClose(config_font_activeosd);
1203 RrFontClose(config_font_inactiveosd);
1205 for (it = config_desktops_names; it; it = g_slist_next(it))
1207 g_slist_free(config_desktops_names);
1209 for (it = config_menu_files; it; it = g_slist_next(it))
1211 g_slist_free(config_menu_files);
1213 for (it = config_per_app_settings; it; it = g_slist_next(it)) {
1214 ObAppSettings *itd = (ObAppSettings *)it->data;
1215 if (itd->name) g_pattern_spec_free(itd->name);
1216 if (itd->role) g_pattern_spec_free(itd->role);
1217 if (itd->title) g_pattern_spec_free(itd->title);
1218 if (itd->class) g_pattern_spec_free(itd->class);
1219 if (itd->group_name) g_pattern_spec_free(itd->group_name);
1220 if (itd->group_class) g_pattern_spec_free(itd->group_class);
1221 g_slice_free(ObAppSettings, it->data);
1223 g_slist_free(config_per_app_settings);