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;
454 if (!obt_xml_attr_string(node, "key", &keystring))
457 obt_xml_attr_bool(node, "chroot", &is_chroot);
459 keys = g_strsplit(keystring, " ", 0);
460 for (key = keys; *key; ++key) {
461 keylist = g_list_append(keylist, *key);
463 if ((n = obt_xml_find_node(node->children, "keybind"))) {
465 parse_key(n, keylist);
466 n = obt_xml_find_node(n->next, "keybind");
469 else if ((n = obt_xml_find_node(node->children, "action"))) {
471 ObActionsAct *action;
473 action = actions_parse(n);
475 keyboard_bind(keylist, action);
476 n = obt_xml_find_node(n->next, "action");
482 keyboard_chroot(keylist);
483 keylist = g_list_delete_link(keylist, g_list_last(keylist));
490 static void parse_keyboard(xmlNodePtr node, gpointer d)
495 keyboard_unbind_all();
497 if ((n = obt_xml_find_node(node->children, "chainQuitKey"))) {
498 key = obt_xml_node_string(n);
499 translate_key(key, &config_keyboard_reset_state,
500 &config_keyboard_reset_keycode);
504 if ((n = obt_xml_find_node(node->children, "keybind")))
507 n = obt_xml_find_node(n->next, "keybind");
510 if ((n = obt_xml_find_node(node->children, "rebindOnMappingNotify")))
511 config_keyboard_rebind_on_mapping_notify = obt_xml_node_bool(n);
516 <context name="Titlebar">
517 <mousebind button="Left" action="Press">
518 <action name="Raise"></action>
524 static void parse_mouse(xmlNodePtr node, gpointer d)
526 xmlNodePtr n, nbut, nact;
533 node = node->children;
535 if ((n = obt_xml_find_node(node, "dragThreshold")))
536 config_mouse_threshold = obt_xml_node_int(n);
537 if ((n = obt_xml_find_node(node, "doubleClickTime")))
538 config_mouse_dclicktime = obt_xml_node_int(n);
539 if ((n = obt_xml_find_node(node, "screenEdgeWarpTime"))) {
540 config_mouse_screenedgetime = obt_xml_node_int(n);
541 /* minimum value of 25 for this property, when it is 1 and you hit the
542 edge it basically never stops */
543 if (config_mouse_screenedgetime && config_mouse_screenedgetime < 25)
544 config_mouse_screenedgetime = 25;
546 if ((n = obt_xml_find_node(node, "screenEdgeWarpMouse")))
547 config_mouse_screenedgewarp = obt_xml_node_bool(n);
549 for (n = obt_xml_find_node(node, "context");
551 n = obt_xml_find_node(n->next, "context"))
556 if (!obt_xml_attr_string(n, "name", &cxstr))
559 modcxstr = g_strdup(cxstr); /* make a copy to mutilate */
560 while (frame_next_context_from_string(modcxstr, &cx)) {
562 gchar *s = strchr(modcxstr, ' ');
565 g_message(_("Invalid context \"%s\" in mouse binding"),
572 for (nbut = obt_xml_find_node(n->children, "mousebind");
574 nbut = obt_xml_find_node(nbut->next, "mousebind"))
577 gchar **button, **buttons;
579 if (!obt_xml_attr_string(nbut, "button", &buttonstr))
581 if (obt_xml_attr_contains(nbut, "action", "press"))
582 mact = OB_MOUSE_ACTION_PRESS;
583 else if (obt_xml_attr_contains(nbut, "action", "release"))
584 mact = OB_MOUSE_ACTION_RELEASE;
585 else if (obt_xml_attr_contains(nbut, "action", "click"))
586 mact = OB_MOUSE_ACTION_CLICK;
587 else if (obt_xml_attr_contains(nbut, "action","doubleclick"))
588 mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
589 else if (obt_xml_attr_contains(nbut, "action", "drag"))
590 mact = OB_MOUSE_ACTION_MOTION;
594 buttons = g_strsplit(buttonstr, " ", 0);
595 for (nact = obt_xml_find_node(nbut->children, "action");
597 nact = obt_xml_find_node(nact->next, "action"))
599 ObActionsAct *action;
601 /* actions_parse() creates one ref to the action, but we need
602 * exactly one ref per binding we use it for. */
603 if ((action = actions_parse(nact))) {
604 for (button = buttons; *button; ++button) {
605 actions_act_ref(action);
606 mouse_bind(*button, cx, mact, action);
608 actions_act_unref(action);
620 static void parse_focus(xmlNodePtr node, gpointer d)
624 node = node->children;
626 if ((n = obt_xml_find_node(node, "focusNew")))
627 config_focus_new = obt_xml_node_bool(n);
628 if ((n = obt_xml_find_node(node, "followMouse")))
629 config_focus_follow = obt_xml_node_bool(n);
630 if ((n = obt_xml_find_node(node, "focusDelay")))
631 config_focus_delay = obt_xml_node_int(n);
632 if ((n = obt_xml_find_node(node, "raiseOnFocus")))
633 config_focus_raise = obt_xml_node_bool(n);
634 if ((n = obt_xml_find_node(node, "focusLast")))
635 config_focus_last = obt_xml_node_bool(n);
636 if ((n = obt_xml_find_node(node, "underMouse")))
637 config_focus_under_mouse = obt_xml_node_bool(n);
638 if ((n = obt_xml_find_node(node, "unfocusOnLeave")))
639 config_unfocus_leave = obt_xml_node_bool(n);
640 if ((n = obt_xml_find_node(node, "directionalDistanceWeight")))
641 config_directional_distance_weight = obt_xml_node_int(n);
643 config_directional_distance_weight = 1U;
644 if ((n = obt_xml_find_node(node, "directionalAngleWeight")))
645 config_directional_angle_weight = obt_xml_node_int(n);
647 config_directional_angle_weight = 1U;
650 static void parse_placement(xmlNodePtr node, gpointer d)
654 node = node->children;
656 if ((n = obt_xml_find_node(node, "policy"))) {
657 if (obt_xml_node_contains(n, "UnderMouse"))
658 config_place_policy = OB_PLACE_POLICY_MOUSE;
660 if ((n = obt_xml_find_node(node, "center"))) {
661 config_place_center = obt_xml_node_bool(n);
663 if ((n = obt_xml_find_node(node, "monitor"))) {
664 if (obt_xml_node_contains(n, "active"))
665 config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
666 else if (obt_xml_node_contains(n, "mouse"))
667 config_place_monitor = OB_PLACE_MONITOR_MOUSE;
668 else if (obt_xml_node_contains(n, "any"))
669 config_place_monitor = OB_PLACE_MONITOR_ANY;
671 if ((n = obt_xml_find_node(node, "primaryMonitor"))) {
672 config_primary_monitor_index = obt_xml_node_int(n);
673 if (!config_primary_monitor_index) {
674 if (obt_xml_node_contains(n, "mouse"))
675 config_primary_monitor = OB_PLACE_MONITOR_MOUSE;
680 static void parse_margins(xmlNodePtr node, gpointer d)
684 node = node->children;
686 if ((n = obt_xml_find_node(node, "top")))
687 config_margins.top = MAX(0, obt_xml_node_int(n));
688 if ((n = obt_xml_find_node(node, "left")))
689 config_margins.left = MAX(0, obt_xml_node_int(n));
690 if ((n = obt_xml_find_node(node, "right")))
691 config_margins.right = MAX(0, obt_xml_node_int(n));
692 if ((n = obt_xml_find_node(node, "bottom")))
693 config_margins.bottom = MAX(0, obt_xml_node_int(n));
696 static void parse_theme(xmlNodePtr node, gpointer d)
700 node = node->children;
702 if ((n = obt_xml_find_node(node, "name"))) {
705 g_free(config_theme);
706 c = obt_xml_node_string(n);
707 config_theme = obt_paths_expand_tilde(c);
710 if ((n = obt_xml_find_node(node, "titleLayout"))) {
713 g_free(config_title_layout);
714 config_title_layout = obt_xml_node_string(n);
716 /* replace duplicates with spaces */
717 for (c = config_title_layout; *c != '\0'; ++c)
718 for (d = c+1; *d != '\0'; ++d)
719 if (*c == *d) *d = ' ';
721 if ((n = obt_xml_find_node(node, "keepBorder")))
722 config_theme_keepborder = obt_xml_node_bool(n);
723 if ((n = obt_xml_find_node(node, "animateIconify")))
724 config_animate_iconify = obt_xml_node_bool(n);
725 if ((n = obt_xml_find_node(node, "windowListIconSize"))) {
726 config_theme_window_list_icon_size = obt_xml_node_int(n);
727 if (config_theme_window_list_icon_size < 16)
728 config_theme_window_list_icon_size = 16;
729 else if (config_theme_window_list_icon_size > 96)
730 config_theme_window_list_icon_size = 96;
733 for (n = obt_xml_find_node(node, "font");
735 n = obt_xml_find_node(n->next, "font"))
739 gchar *name = g_strdup(RrDefaultFontFamily);
740 gint size = RrDefaultFontSize;
741 RrFontWeight weight = RrDefaultFontWeight;
742 RrFontSlant slant = RrDefaultFontSlant;
744 if (obt_xml_attr_contains(n, "place", "ActiveWindow"))
745 font = &config_font_activewindow;
746 else if (obt_xml_attr_contains(n, "place", "InactiveWindow"))
747 font = &config_font_inactivewindow;
748 else if (obt_xml_attr_contains(n, "place", "MenuHeader"))
749 font = &config_font_menutitle;
750 else if (obt_xml_attr_contains(n, "place", "MenuItem"))
751 font = &config_font_menuitem;
752 else if (obt_xml_attr_contains(n, "place", "ActiveOnScreenDisplay"))
753 font = &config_font_activeosd;
754 else if (obt_xml_attr_contains(n, "place", "OnScreenDisplay"))
755 font = &config_font_activeosd;
756 else if (obt_xml_attr_contains(n, "place","InactiveOnScreenDisplay"))
757 font = &config_font_inactiveosd;
761 if ((fnode = obt_xml_find_node(n->children, "name"))) {
763 name = obt_xml_node_string(fnode);
765 if ((fnode = obt_xml_find_node(n->children, "size"))) {
766 int s = obt_xml_node_int(fnode);
769 if ((fnode = obt_xml_find_node(n->children, "weight"))) {
770 gchar *w = obt_xml_node_string(fnode);
771 if (!g_ascii_strcasecmp(w, "Bold"))
772 weight = RR_FONTWEIGHT_BOLD;
775 if ((fnode = obt_xml_find_node(n->children, "slant"))) {
776 gchar *s = obt_xml_node_string(fnode);
777 if (!g_ascii_strcasecmp(s, "Italic"))
778 slant = RR_FONTSLANT_ITALIC;
779 if (!g_ascii_strcasecmp(s, "Oblique"))
780 slant = RR_FONTSLANT_OBLIQUE;
784 *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
789 static void parse_desktops(xmlNodePtr node, gpointer d)
793 node = node->children;
795 if ((n = obt_xml_find_node(node, "number"))) {
796 gint d = obt_xml_node_int(n);
798 config_desktops_num = (unsigned) d;
800 if ((n = obt_xml_find_node(node, "firstdesk"))) {
801 gint d = obt_xml_node_int(n);
803 config_screen_firstdesk = (unsigned) d;
805 if ((n = obt_xml_find_node(node, "names"))) {
809 for (it = config_desktops_names; it; it = it->next)
811 g_slist_free(config_desktops_names);
812 config_desktops_names = NULL;
814 for (nname = obt_xml_find_node(n->children, "name");
816 nname = obt_xml_find_node(nname->next, "name"))
818 config_desktops_names =
819 g_slist_append(config_desktops_names,
820 obt_xml_node_string(nname));
823 if ((n = obt_xml_find_node(node, "popupTime")))
824 config_desktop_popup_time = obt_xml_node_int(n);
827 static void parse_resize(xmlNodePtr node, gpointer d)
831 node = node->children;
833 if ((n = obt_xml_find_node(node, "drawContents")))
834 config_resize_redraw = obt_xml_node_bool(n);
835 if ((n = obt_xml_find_node(node, "popupShow"))) {
836 config_resize_popup_show = obt_xml_node_int(n);
837 if (obt_xml_node_contains(n, "Always"))
838 config_resize_popup_show = 2;
839 else if (obt_xml_node_contains(n, "Never"))
840 config_resize_popup_show = 0;
841 else if (obt_xml_node_contains(n, "Nonpixel"))
842 config_resize_popup_show = 1;
844 if ((n = obt_xml_find_node(node, "popupPosition"))) {
845 if (obt_xml_node_contains(n, "Top"))
846 config_resize_popup_pos = OB_RESIZE_POS_TOP;
847 else if (obt_xml_node_contains(n, "Center"))
848 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
849 else if (obt_xml_node_contains(n, "Fixed")) {
850 config_resize_popup_pos = OB_RESIZE_POS_FIXED;
852 if ((n = obt_xml_find_node(node, "popupFixedPosition"))) {
855 if ((n2 = obt_xml_find_node(n->children, "x")))
856 config_parse_gravity_coord(n2,
857 &config_resize_popup_fixed.x);
858 if ((n2 = obt_xml_find_node(n->children, "y")))
859 config_parse_gravity_coord(n2,
860 &config_resize_popup_fixed.y);
862 config_resize_popup_fixed.x.pos =
863 MAX(config_resize_popup_fixed.x.pos, 0);
864 config_resize_popup_fixed.y.pos =
865 MAX(config_resize_popup_fixed.y.pos, 0);
871 static void parse_dock(xmlNodePtr node, gpointer d)
875 node = node->children;
877 if ((n = obt_xml_find_node(node, "position"))) {
878 if (obt_xml_node_contains(n, "TopLeft"))
879 config_dock_floating = FALSE,
880 config_dock_pos = OB_DIRECTION_NORTHWEST;
881 else if (obt_xml_node_contains(n, "Top"))
882 config_dock_floating = FALSE,
883 config_dock_pos = OB_DIRECTION_NORTH;
884 else if (obt_xml_node_contains(n, "TopRight"))
885 config_dock_floating = FALSE,
886 config_dock_pos = OB_DIRECTION_NORTHEAST;
887 else if (obt_xml_node_contains(n, "Right"))
888 config_dock_floating = FALSE,
889 config_dock_pos = OB_DIRECTION_EAST;
890 else if (obt_xml_node_contains(n, "BottomRight"))
891 config_dock_floating = FALSE,
892 config_dock_pos = OB_DIRECTION_SOUTHEAST;
893 else if (obt_xml_node_contains(n, "Bottom"))
894 config_dock_floating = FALSE,
895 config_dock_pos = OB_DIRECTION_SOUTH;
896 else if (obt_xml_node_contains(n, "BottomLeft"))
897 config_dock_floating = FALSE,
898 config_dock_pos = OB_DIRECTION_SOUTHWEST;
899 else if (obt_xml_node_contains(n, "Left"))
900 config_dock_floating = FALSE,
901 config_dock_pos = OB_DIRECTION_WEST;
902 else if (obt_xml_node_contains(n, "Floating"))
903 config_dock_floating = TRUE;
905 if (config_dock_floating) {
906 if ((n = obt_xml_find_node(node, "floatingX")))
907 config_dock_x = obt_xml_node_int(n);
908 if ((n = obt_xml_find_node(node, "floatingY")))
909 config_dock_y = obt_xml_node_int(n);
911 if ((n = obt_xml_find_node(node, "noStrut")))
912 config_dock_nostrut = obt_xml_node_bool(n);
914 if ((n = obt_xml_find_node(node, "stacking"))) {
915 if (obt_xml_node_contains(n, "normal"))
916 config_dock_layer = OB_STACKING_LAYER_NORMAL;
917 else if (obt_xml_node_contains(n, "below"))
918 config_dock_layer = OB_STACKING_LAYER_BELOW;
919 else if (obt_xml_node_contains(n, "above"))
920 config_dock_layer = OB_STACKING_LAYER_ABOVE;
922 if ((n = obt_xml_find_node(node, "direction"))) {
923 if (obt_xml_node_contains(n, "horizontal"))
924 config_dock_orient = OB_ORIENTATION_HORZ;
925 else if (obt_xml_node_contains(n, "vertical"))
926 config_dock_orient = OB_ORIENTATION_VERT;
928 if ((n = obt_xml_find_node(node, "autoHide")))
929 config_dock_hide = obt_xml_node_bool(n);
930 if ((n = obt_xml_find_node(node, "hideDelay")))
931 config_dock_hide_delay = obt_xml_node_int(n);
932 if ((n = obt_xml_find_node(node, "showDelay")))
933 config_dock_show_delay = obt_xml_node_int(n);
934 if ((n = obt_xml_find_node(node, "moveButton"))) {
935 gchar *str = obt_xml_node_string(n);
937 if (translate_button(str, &s, &b)) {
938 config_dock_app_move_button = b;
939 config_dock_app_move_modifiers = s;
941 g_message(_("Invalid button \"%s\" specified in config file"), str);
947 static void parse_menu(xmlNodePtr node, gpointer d)
950 node = node->children;
952 if ((n = obt_xml_find_node(node, "hideDelay")))
953 config_menu_hide_delay = obt_xml_node_int(n);
954 if ((n = obt_xml_find_node(node, "middle")))
955 config_menu_middle = obt_xml_node_bool(n);
956 if ((n = obt_xml_find_node(node, "submenuShowDelay")))
957 config_submenu_show_delay = obt_xml_node_int(n);
958 if ((n = obt_xml_find_node(node, "submenuHideDelay")))
959 config_submenu_hide_delay = obt_xml_node_int(n);
960 if ((n = obt_xml_find_node(node, "manageDesktops")))
961 config_menu_manage_desktops = obt_xml_node_bool(n);
962 if ((n = obt_xml_find_node(node, "showIcons"))) {
963 config_menu_show_icons = obt_xml_node_bool(n);
964 #if !defined(USE_IMLIB2) && !defined(USE_LIBRSVG)
965 if (config_menu_show_icons)
966 g_message(_("Openbox was compiled without image loading support. Icons in menus will not be loaded."));
970 for (node = obt_xml_find_node(node, "file");
972 node = obt_xml_find_node(node->next, "file"))
974 gchar *c = obt_xml_node_string(node);
975 config_menu_files = g_slist_append(config_menu_files,
976 obt_paths_expand_tilde(c));
981 static void parse_resistance(xmlNodePtr node, gpointer d)
985 node = node->children;
986 if ((n = obt_xml_find_node(node, "strength")))
987 config_resist_win = obt_xml_node_int(n);
988 if ((n = obt_xml_find_node(node, "screen_edge_strength")))
989 config_resist_edge = obt_xml_node_int(n);
995 const gchar *actname;
998 static void bind_default_keyboard(void)
1001 ObDefKeyBind binds[] = {
1002 { "A-Tab", "NextWindow" },
1003 { "S-A-Tab", "PreviousWindow" },
1004 { "A-F4", "Close" },
1007 for (it = binds; it->key; ++it) {
1008 GList *l = g_list_append(NULL, g_strdup(it->key));
1009 keyboard_bind(l, actions_parse_string(it->actname));
1015 const gchar *button;
1016 const gchar *context;
1017 const ObMouseAction mact;
1018 const gchar *actname;
1021 static void bind_default_mouse(void)
1024 ObDefMouseBind binds[] = {
1025 { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1026 { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1027 { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1028 { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1029 { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1030 { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1031 { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
1032 { "Left", "Bottom", OB_MOUSE_ACTION_PRESS, "Focus" },
1033 { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1034 { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1035 { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1036 { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1037 { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
1038 { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
1039 { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
1040 { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
1041 { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
1042 { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
1043 { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
1044 { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
1045 { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
1046 { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1047 { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1048 { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1049 { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1050 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
1051 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
1052 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
1053 { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
1054 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
1055 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
1056 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
1057 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximize" },
1058 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
1059 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
1060 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
1061 { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1062 { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1063 { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1064 { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1065 { "Left", "Top", OB_MOUSE_ACTION_MOTION, "Resize" },
1066 { "Left", "Bottom", OB_MOUSE_ACTION_MOTION, "Resize" },
1067 { "Left", "Left", OB_MOUSE_ACTION_MOTION, "Resize" },
1068 { "Left", "Right", OB_MOUSE_ACTION_MOTION, "Resize" },
1069 { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
1070 { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
1071 { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
1072 { NULL, NULL, 0, NULL }
1075 for (it = binds; it->button; ++it)
1076 mouse_bind(it->button, frame_context_from_string(it->context),
1077 it->mact, actions_parse_string(it->actname));
1080 void config_startup(ObtXmlInst *i)
1082 config_focus_new = TRUE;
1083 config_focus_follow = FALSE;
1084 config_focus_delay = 0;
1085 config_focus_raise = FALSE;
1086 config_focus_last = TRUE;
1087 config_focus_under_mouse = FALSE;
1088 config_unfocus_leave = FALSE;
1090 obt_xml_register(i, "focus", parse_focus, NULL);
1092 config_place_policy = OB_PLACE_POLICY_SMART;
1093 config_place_center = TRUE;
1094 config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
1096 config_primary_monitor_index = 1;
1097 config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
1099 obt_xml_register(i, "placement", parse_placement, NULL);
1101 STRUT_PARTIAL_SET(config_margins, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1103 obt_xml_register(i, "margins", parse_margins, NULL);
1105 config_theme = NULL;
1107 config_animate_iconify = TRUE;
1108 config_title_layout = g_strdup("NLIMC");
1109 config_theme_keepborder = TRUE;
1110 config_theme_window_list_icon_size = 36;
1112 config_font_activewindow = NULL;
1113 config_font_inactivewindow = NULL;
1114 config_font_menuitem = NULL;
1115 config_font_menutitle = NULL;
1116 config_font_activeosd = NULL;
1117 config_font_inactiveosd = NULL;
1119 obt_xml_register(i, "theme", parse_theme, NULL);
1121 config_desktops_num = 4;
1122 config_screen_firstdesk = 1;
1123 config_desktops_names = NULL;
1124 config_desktop_popup_time = 875;
1126 obt_xml_register(i, "desktops", parse_desktops, NULL);
1128 config_resize_redraw = TRUE;
1129 config_resize_popup_show = 1; /* nonpixel increments */
1130 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
1131 GRAVITY_COORD_SET(config_resize_popup_fixed.x, 0, FALSE, FALSE);
1132 GRAVITY_COORD_SET(config_resize_popup_fixed.y, 0, FALSE, FALSE);
1134 obt_xml_register(i, "resize", parse_resize, NULL);
1136 config_dock_layer = OB_STACKING_LAYER_ABOVE;
1137 config_dock_pos = OB_DIRECTION_NORTHEAST;
1138 config_dock_floating = FALSE;
1139 config_dock_nostrut = FALSE;
1142 config_dock_orient = OB_ORIENTATION_VERT;
1143 config_dock_hide = FALSE;
1144 config_dock_hide_delay = 300;
1145 config_dock_show_delay = 300;
1146 config_dock_app_move_button = 2; /* middle */
1147 config_dock_app_move_modifiers = 0;
1149 obt_xml_register(i, "dock", parse_dock, NULL);
1151 translate_key("C-g", &config_keyboard_reset_state,
1152 &config_keyboard_reset_keycode);
1153 config_keyboard_rebind_on_mapping_notify = TRUE;
1155 bind_default_keyboard();
1157 obt_xml_register(i, "keyboard", parse_keyboard, NULL);
1159 config_mouse_threshold = 8;
1160 config_mouse_dclicktime = 500;
1161 config_mouse_screenedgetime = 400;
1162 config_mouse_screenedgewarp = FALSE;
1164 bind_default_mouse();
1166 obt_xml_register(i, "mouse", parse_mouse, NULL);
1168 config_resist_win = 10;
1169 config_resist_edge = 20;
1171 obt_xml_register(i, "resistance", parse_resistance, NULL);
1173 config_menu_hide_delay = 250;
1174 config_menu_middle = FALSE;
1175 config_submenu_show_delay = 100;
1176 config_submenu_hide_delay = 400;
1177 config_menu_manage_desktops = TRUE;
1178 config_menu_files = NULL;
1179 config_menu_show_icons = TRUE;
1181 obt_xml_register(i, "menu", parse_menu, NULL);
1183 config_per_app_settings = NULL;
1185 obt_xml_register(i, "applications", parse_per_app_settings, NULL);
1188 void config_shutdown(void)
1192 g_free(config_theme);
1194 g_free(config_title_layout);
1196 RrFontClose(config_font_activewindow);
1197 RrFontClose(config_font_inactivewindow);
1198 RrFontClose(config_font_menuitem);
1199 RrFontClose(config_font_menutitle);
1200 RrFontClose(config_font_activeosd);
1201 RrFontClose(config_font_inactiveosd);
1203 for (it = config_desktops_names; it; it = g_slist_next(it))
1205 g_slist_free(config_desktops_names);
1207 for (it = config_menu_files; it; it = g_slist_next(it))
1209 g_slist_free(config_menu_files);
1211 for (it = config_per_app_settings; it; it = g_slist_next(it)) {
1212 ObAppSettings *itd = (ObAppSettings *)it->data;
1213 if (itd->name) g_pattern_spec_free(itd->name);
1214 if (itd->role) g_pattern_spec_free(itd->role);
1215 if (itd->title) g_pattern_spec_free(itd->title);
1216 if (itd->class) g_pattern_spec_free(itd->class);
1217 if (itd->group_name) g_pattern_spec_free(itd->group_name);
1218 if (itd->group_class) g_pattern_spec_free(itd->group_class);
1219 g_slice_free(ObAppSettings, it->data);
1221 g_slist_free(config_per_app_settings);