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;
39 ObPlacePolicy config_place_policy;
40 gboolean config_place_center;
41 ObPlaceMonitor config_place_monitor;
43 guint config_primary_monitor_index;
44 ObPlaceMonitor config_primary_monitor;
46 StrutPartial config_margins;
49 gboolean config_theme_keepborder;
50 guint config_theme_window_list_icon_size;
52 gchar *config_title_layout;
54 gboolean config_animate_iconify;
56 RrFont *config_font_activewindow;
57 RrFont *config_font_inactivewindow;
58 RrFont *config_font_menuitem;
59 RrFont *config_font_menutitle;
60 RrFont *config_font_activeosd;
61 RrFont *config_font_inactiveosd;
63 guint config_desktops_num;
64 GSList *config_desktops_names;
65 guint config_screen_firstdesk;
66 guint config_desktop_popup_time;
68 gboolean config_resize_redraw;
69 gint config_resize_popup_show;
70 ObResizePopupPos config_resize_popup_pos;
71 GravityPoint config_resize_popup_fixed;
73 ObStackingLayer config_dock_layer;
74 gboolean config_dock_floating;
75 gboolean config_dock_nostrut;
76 ObDirection config_dock_pos;
79 ObOrientation config_dock_orient;
80 gboolean config_dock_hide;
81 guint config_dock_hide_delay;
82 guint config_dock_show_delay;
83 guint config_dock_app_move_button;
84 guint config_dock_app_move_modifiers;
86 guint config_keyboard_reset_keycode;
87 guint config_keyboard_reset_state;
88 gboolean config_keyboard_rebind_on_mapping_notify;
90 gint config_mouse_threshold;
91 gint config_mouse_dclicktime;
92 gint config_mouse_screenedgetime;
93 gboolean config_mouse_screenedgewarp;
95 guint config_menu_hide_delay;
96 gboolean config_menu_middle;
97 guint config_submenu_show_delay;
98 guint config_submenu_hide_delay;
99 gboolean config_menu_manage_desktops;
100 gboolean config_menu_show_icons;
102 GSList *config_menu_files;
104 gint config_resist_win;
105 gint config_resist_edge;
107 GSList *config_per_app_settings;
109 ObAppSettings* config_create_app_settings(void)
111 ObAppSettings *settings = g_slice_new0(ObAppSettings);
113 settings->decor = -1;
114 settings->shade = -1;
115 settings->monitor_type = OB_PLACE_MONITOR_ANY;
116 settings->monitor = -1;
117 settings->focus = -1;
118 settings->desktop = 0;
119 settings->layer = -2;
120 settings->iconic = -1;
121 settings->skip_pager = -1;
122 settings->skip_taskbar = -1;
123 settings->fullscreen = -1;
124 settings->max_horz = -1;
125 settings->max_vert = -1;
129 #define copy_if(setting, default) \
130 if (src->setting != default) dst->setting = src->setting
131 void config_app_settings_copy_non_defaults(const ObAppSettings *src,
134 g_assert(src != NULL);
135 g_assert(dst != NULL);
137 copy_if(type, (ObClientType)-1);
140 copy_if(monitor_type, OB_PLACE_MONITOR_ANY);
141 copy_if(monitor, -1);
146 copy_if(skip_pager, -1);
147 copy_if(skip_taskbar, -1);
148 copy_if(fullscreen, -1);
149 copy_if(max_horz, -1);
150 copy_if(max_vert, -1);
152 if (src->pos_given) {
153 dst->pos_given = TRUE;
154 dst->pos_force = src->pos_force;
155 dst->position = src->position;
156 /* monitor is copied above */
159 dst->width_num = src->width_num;
160 dst->width_denom = src->width_denom;
161 dst->height_num = src->height_num;
162 dst->height_denom = src->height_denom;
165 void config_parse_relative_number(gchar *s, gint *num, gint *denom)
167 *num = strtol(s, &s, 10);
171 } else if (*s == '/') {
176 void config_parse_gravity_coord(xmlNodePtr node, GravityCoord *c)
178 gchar *s = obt_xml_node_string(node);
179 if (!g_ascii_strcasecmp(s, "center"))
185 if (s[0] == '-' || s[0] == '+')
187 config_parse_relative_number(ps, &c->pos, &c->denom);
194 <application name="aterm">
197 <application name="Rhythmbox">
204 .. there is a lot more settings available
209 static void parse_single_per_app_settings(xmlNodePtr app,
210 ObAppSettings *settings)
213 gboolean x_pos_given = FALSE;
215 if ((n = obt_xml_find_node(app->children, "decor")))
216 if (!obt_xml_node_contains(n, "default"))
217 settings->decor = obt_xml_node_bool(n);
219 if ((n = obt_xml_find_node(app->children, "shade")))
220 if (!obt_xml_node_contains(n, "default"))
221 settings->shade = obt_xml_node_bool(n);
223 if ((n = obt_xml_find_node(app->children, "position"))) {
224 if ((c = obt_xml_find_node(n->children, "x"))) {
225 if (!obt_xml_node_contains(c, "default")) {
226 config_parse_gravity_coord(c, &settings->position.x);
231 if (x_pos_given && (c = obt_xml_find_node(n->children, "y"))) {
232 if (!obt_xml_node_contains(c, "default")) {
233 config_parse_gravity_coord(c, &settings->position.y);
234 settings->pos_given = TRUE;
238 /* monitor can be set without setting x or y */
239 if ((c = obt_xml_find_node(n->children, "monitor"))) {
240 if (!obt_xml_node_contains(c, "default")) {
241 gchar *s = obt_xml_node_string(c);
242 if (!g_ascii_strcasecmp(s, "mouse"))
243 settings->monitor_type = OB_PLACE_MONITOR_MOUSE;
244 else if (!g_ascii_strcasecmp(s, "active"))
245 settings->monitor_type = OB_PLACE_MONITOR_ACTIVE;
246 else if (!g_ascii_strcasecmp(s, "primary"))
247 settings->monitor_type = OB_PLACE_MONITOR_PRIMARY;
249 settings->monitor = obt_xml_node_int(c);
254 obt_xml_attr_bool(n, "force", &settings->pos_force);
257 if ((n = obt_xml_find_node(app->children, "size"))) {
258 if ((c = obt_xml_find_node(n->children, "width"))) {
259 if (!obt_xml_node_contains(c, "default")) {
260 gchar *s = obt_xml_node_string(c);
261 config_parse_relative_number(s,
262 &settings->width_num,
263 &settings->width_denom);
264 if (settings->width_num <= 0 || settings->width_denom < 0)
265 settings->width_num = settings->width_denom = 0;
270 if ((c = obt_xml_find_node(n->children, "height"))) {
271 if (!obt_xml_node_contains(c, "default")) {
272 gchar *s = obt_xml_node_string(c);
273 config_parse_relative_number(s,
274 &settings->height_num,
275 &settings->height_denom);
276 if (settings->height_num <= 0 || settings->height_denom < 0)
277 settings->height_num = settings->height_denom = 0;
283 if ((n = obt_xml_find_node(app->children, "focus"))) {
284 if (!obt_xml_node_contains(n, "default"))
285 settings->focus = obt_xml_node_bool(n);
288 if ((n = obt_xml_find_node(app->children, "desktop"))) {
289 if (!obt_xml_node_contains(n, "default")) {
290 gchar *s = obt_xml_node_string(n);
291 if (!g_ascii_strcasecmp(s, "all"))
292 settings->desktop = DESKTOP_ALL;
294 gint i = obt_xml_node_int(n);
296 settings->desktop = i;
302 if ((n = obt_xml_find_node(app->children, "layer"))) {
303 if (!obt_xml_node_contains(n, "default")) {
304 gchar *s = obt_xml_node_string(n);
305 if (!g_ascii_strcasecmp(s, "above"))
307 else if (!g_ascii_strcasecmp(s, "below"))
308 settings->layer = -1;
315 if ((n = obt_xml_find_node(app->children, "iconic")))
316 if (!obt_xml_node_contains(n, "default"))
317 settings->iconic = obt_xml_node_bool(n);
319 if ((n = obt_xml_find_node(app->children, "skip_pager")))
320 if (!obt_xml_node_contains(n, "default"))
321 settings->skip_pager = obt_xml_node_bool(n);
323 if ((n = obt_xml_find_node(app->children, "skip_taskbar")))
324 if (!obt_xml_node_contains(n, "default"))
325 settings->skip_taskbar = obt_xml_node_bool(n);
327 if ((n = obt_xml_find_node(app->children, "fullscreen")))
328 if (!obt_xml_node_contains(n, "default"))
329 settings->fullscreen = obt_xml_node_bool(n);
331 if ((n = obt_xml_find_node(app->children, "maximized"))) {
332 if (!obt_xml_node_contains(n, "default")) {
333 gchar *s = obt_xml_node_string(n);
334 if (!g_ascii_strcasecmp(s, "horizontal")) {
335 settings->max_horz = TRUE;
336 settings->max_vert = FALSE;
337 } else if (!g_ascii_strcasecmp(s, "vertical")) {
338 settings->max_horz = FALSE;
339 settings->max_vert = TRUE;
341 settings->max_horz = settings->max_vert =
342 obt_xml_node_bool(n);
348 /* Manages settings for individual applications.
349 Some notes: monitor is the screen number in a multi monitor
350 (Xinerama) setup (starting from 0), or mouse: the monitor the pointer
351 is on, active: the active monitor, primary: the primary monitor.
352 Layer can be three values, above (Always on top), below
353 (Always on bottom) and everything else (normal behaviour).
354 Positions can be an integer value or center, which will
355 center the window in the specified axis. Position is within
356 the monitor, so <position><x>center</x></position><monitor>2</monitor>
357 will center the window on the second monitor.
359 static void parse_per_app_settings(xmlNodePtr node, gpointer d)
361 xmlNodePtr app = obt_xml_find_node(node->children, "application");
362 for (; app; app = obt_xml_find_node(app->next, "application")) {
363 ObAppSettings *settings;
365 gboolean name_set, class_set, role_set, title_set,
366 type_set, group_name_set, group_class_set;
367 gchar *name = NULL, *class = NULL, *role = NULL, *title = NULL,
368 *type_str = NULL, *group_name = NULL, *group_class = NULL;
371 class_set = obt_xml_attr_string(app, "class", &class);
372 name_set = obt_xml_attr_string(app, "name", &name);
373 group_class_set = obt_xml_attr_string(app, "groupclass", &group_class);
374 group_name_set = obt_xml_attr_string(app, "groupname", &group_name);
375 type_set = obt_xml_attr_string(app, "type", &type_str);
376 role_set = obt_xml_attr_string(app, "role", &role);
377 title_set = obt_xml_attr_string(app, "title", &title);
379 /* validate the type tho */
381 if (!g_ascii_strcasecmp(type_str, "normal"))
382 type = OB_CLIENT_TYPE_NORMAL;
383 else if (!g_ascii_strcasecmp(type_str, "dialog"))
384 type = OB_CLIENT_TYPE_DIALOG;
385 else if (!g_ascii_strcasecmp(type_str, "splash"))
386 type = OB_CLIENT_TYPE_SPLASH;
387 else if (!g_ascii_strcasecmp(type_str, "utility"))
388 type = OB_CLIENT_TYPE_UTILITY;
389 else if (!g_ascii_strcasecmp(type_str, "menu"))
390 type = OB_CLIENT_TYPE_MENU;
391 else if (!g_ascii_strcasecmp(type_str, "toolbar"))
392 type = OB_CLIENT_TYPE_TOOLBAR;
393 else if (!g_ascii_strcasecmp(type_str, "dock"))
394 type = OB_CLIENT_TYPE_DOCK;
395 else if (!g_ascii_strcasecmp(type_str, "desktop"))
396 type = OB_CLIENT_TYPE_DESKTOP;
398 type_set = FALSE; /* not valid! */
401 if (!(class_set || name_set || role_set || title_set ||
402 type_set || group_class_set || group_name_set))
405 settings = config_create_app_settings();
408 settings->name = g_pattern_spec_new(name);
410 settings->class = g_pattern_spec_new(class);
412 settings->group_name = g_pattern_spec_new(group_name);
414 settings->group_class = g_pattern_spec_new(group_class);
416 settings->role = g_pattern_spec_new(role);
418 settings->title = g_pattern_spec_new(title);
420 settings->type = type;
430 parse_single_per_app_settings(app, settings);
431 config_per_app_settings = g_slist_append(config_per_app_settings,
439 <action name="ChangeDesktop">
446 static void parse_key(xmlNodePtr node, GList *keylist)
448 gchar *keystring, **keys, **key;
450 gboolean is_chroot = FALSE;
452 if (!obt_xml_attr_string(node, "key", &keystring))
455 obt_xml_attr_bool(node, "chroot", &is_chroot);
457 keys = g_strsplit(keystring, " ", 0);
458 for (key = keys; *key; ++key) {
459 keylist = g_list_append(keylist, *key);
461 if ((n = obt_xml_find_node(node->children, "keybind"))) {
463 parse_key(n, keylist);
464 n = obt_xml_find_node(n->next, "keybind");
467 else if ((n = obt_xml_find_node(node->children, "action"))) {
469 ObActionsAct *action;
471 action = actions_parse(n);
473 keyboard_bind(keylist, action);
474 n = obt_xml_find_node(n->next, "action");
480 keyboard_chroot(keylist);
481 keylist = g_list_delete_link(keylist, g_list_last(keylist));
488 static void parse_keyboard(xmlNodePtr node, gpointer d)
493 keyboard_unbind_all();
495 if ((n = obt_xml_find_node(node->children, "chainQuitKey"))) {
496 key = obt_xml_node_string(n);
497 translate_key(key, &config_keyboard_reset_state,
498 &config_keyboard_reset_keycode);
502 if ((n = obt_xml_find_node(node->children, "keybind")))
505 n = obt_xml_find_node(n->next, "keybind");
508 if ((n = obt_xml_find_node(node->children, "rebindOnMappingNotify")))
509 config_keyboard_rebind_on_mapping_notify = obt_xml_node_bool(n);
514 <context name="Titlebar">
515 <mousebind button="Left" action="Press">
516 <action name="Raise"></action>
522 static void parse_mouse(xmlNodePtr node, gpointer d)
524 xmlNodePtr n, nbut, nact;
531 node = node->children;
533 if ((n = obt_xml_find_node(node, "dragThreshold")))
534 config_mouse_threshold = obt_xml_node_int(n);
535 if ((n = obt_xml_find_node(node, "doubleClickTime")))
536 config_mouse_dclicktime = obt_xml_node_int(n);
537 if ((n = obt_xml_find_node(node, "screenEdgeWarpTime"))) {
538 config_mouse_screenedgetime = obt_xml_node_int(n);
539 /* minimum value of 25 for this property, when it is 1 and you hit the
540 edge it basically never stops */
541 if (config_mouse_screenedgetime && config_mouse_screenedgetime < 25)
542 config_mouse_screenedgetime = 25;
544 if ((n = obt_xml_find_node(node, "screenEdgeWarpMouse")))
545 config_mouse_screenedgewarp = obt_xml_node_bool(n);
547 n = obt_xml_find_node(node, "context");
552 if (!obt_xml_attr_string(n, "name", &cxstr))
555 modcxstr = g_strdup(cxstr); /* make a copy to mutilate */
556 while (frame_next_context_from_string(modcxstr, &cx)) {
558 gchar *s = strchr(modcxstr, ' ');
561 g_message(_("Invalid context \"%s\" in mouse binding"),
568 nbut = obt_xml_find_node(n->children, "mousebind");
570 gchar **button, **buttons;
572 if (!obt_xml_attr_string(nbut, "button", &buttonstr))
574 if (obt_xml_attr_contains(nbut, "action", "press"))
575 mact = OB_MOUSE_ACTION_PRESS;
576 else if (obt_xml_attr_contains(nbut, "action", "release"))
577 mact = OB_MOUSE_ACTION_RELEASE;
578 else if (obt_xml_attr_contains(nbut, "action", "click"))
579 mact = OB_MOUSE_ACTION_CLICK;
580 else if (obt_xml_attr_contains(nbut, "action","doubleclick"))
581 mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
582 else if (obt_xml_attr_contains(nbut, "action", "drag"))
583 mact = OB_MOUSE_ACTION_MOTION;
587 buttons = g_strsplit(buttonstr, " ", 0);
588 nact = obt_xml_find_node(nbut->children, "action");
590 ObActionsAct *action;
592 /* actions_parse() creates one ref to the action, but we need
593 * exactly one ref per binding we use it for. */
594 if ((action = actions_parse(nact))) {
595 for (button = buttons; *button; ++button) {
596 actions_act_ref(action);
597 mouse_bind(*button, cx, mact, action);
599 actions_act_unref(action);
601 nact = obt_xml_find_node(nact->next, "action");
606 nbut = obt_xml_find_node(nbut->next, "mousebind");
612 n = obt_xml_find_node(n->next, "context");
616 static void parse_focus(xmlNodePtr node, gpointer d)
620 node = node->children;
622 if ((n = obt_xml_find_node(node, "focusNew")))
623 config_focus_new = obt_xml_node_bool(n);
624 if ((n = obt_xml_find_node(node, "followMouse")))
625 config_focus_follow = obt_xml_node_bool(n);
626 if ((n = obt_xml_find_node(node, "focusDelay")))
627 config_focus_delay = obt_xml_node_int(n);
628 if ((n = obt_xml_find_node(node, "raiseOnFocus")))
629 config_focus_raise = obt_xml_node_bool(n);
630 if ((n = obt_xml_find_node(node, "focusLast")))
631 config_focus_last = obt_xml_node_bool(n);
632 if ((n = obt_xml_find_node(node, "underMouse")))
633 config_focus_under_mouse = obt_xml_node_bool(n);
634 if ((n = obt_xml_find_node(node, "unfocusOnLeave")))
635 config_unfocus_leave = obt_xml_node_bool(n);
638 static void parse_placement(xmlNodePtr node, gpointer d)
642 node = node->children;
644 if ((n = obt_xml_find_node(node, "policy"))) {
645 if (obt_xml_node_contains(n, "UnderMouse"))
646 config_place_policy = OB_PLACE_POLICY_MOUSE;
648 if ((n = obt_xml_find_node(node, "center"))) {
649 config_place_center = obt_xml_node_bool(n);
651 if ((n = obt_xml_find_node(node, "monitor"))) {
652 if (obt_xml_node_contains(n, "active"))
653 config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
654 else if (obt_xml_node_contains(n, "mouse"))
655 config_place_monitor = OB_PLACE_MONITOR_MOUSE;
656 else if (obt_xml_node_contains(n, "any"))
657 config_place_monitor = OB_PLACE_MONITOR_ANY;
659 if ((n = obt_xml_find_node(node, "primaryMonitor"))) {
660 config_primary_monitor_index = obt_xml_node_int(n);
661 if (!config_primary_monitor_index) {
662 if (obt_xml_node_contains(n, "mouse"))
663 config_primary_monitor = OB_PLACE_MONITOR_MOUSE;
668 static void parse_margins(xmlNodePtr node, gpointer d)
672 node = node->children;
674 if ((n = obt_xml_find_node(node, "top")))
675 config_margins.top = MAX(0, obt_xml_node_int(n));
676 if ((n = obt_xml_find_node(node, "left")))
677 config_margins.left = MAX(0, obt_xml_node_int(n));
678 if ((n = obt_xml_find_node(node, "right")))
679 config_margins.right = MAX(0, obt_xml_node_int(n));
680 if ((n = obt_xml_find_node(node, "bottom")))
681 config_margins.bottom = MAX(0, obt_xml_node_int(n));
684 static void parse_theme(xmlNodePtr node, gpointer d)
688 node = node->children;
690 if ((n = obt_xml_find_node(node, "name"))) {
693 g_free(config_theme);
694 c = obt_xml_node_string(n);
695 config_theme = obt_paths_expand_tilde(c);
698 if ((n = obt_xml_find_node(node, "titleLayout"))) {
701 g_free(config_title_layout);
702 config_title_layout = obt_xml_node_string(n);
704 /* replace duplicates with spaces */
705 for (c = config_title_layout; *c != '\0'; ++c)
706 for (d = c+1; *d != '\0'; ++d)
707 if (*c == *d) *d = ' ';
709 if ((n = obt_xml_find_node(node, "keepBorder")))
710 config_theme_keepborder = obt_xml_node_bool(n);
711 if ((n = obt_xml_find_node(node, "animateIconify")))
712 config_animate_iconify = obt_xml_node_bool(n);
713 if ((n = obt_xml_find_node(node, "windowListIconSize"))) {
714 config_theme_window_list_icon_size = obt_xml_node_int(n);
715 if (config_theme_window_list_icon_size < 16)
716 config_theme_window_list_icon_size = 16;
717 else if (config_theme_window_list_icon_size > 96)
718 config_theme_window_list_icon_size = 96;
721 n = obt_xml_find_node(node, "font");
725 gchar *name = g_strdup(RrDefaultFontFamily);
726 gint size = RrDefaultFontSize;
727 RrFontWeight weight = RrDefaultFontWeight;
728 RrFontSlant slant = RrDefaultFontSlant;
730 if (obt_xml_attr_contains(n, "place", "ActiveWindow"))
731 font = &config_font_activewindow;
732 else if (obt_xml_attr_contains(n, "place", "InactiveWindow"))
733 font = &config_font_inactivewindow;
734 else if (obt_xml_attr_contains(n, "place", "MenuHeader"))
735 font = &config_font_menutitle;
736 else if (obt_xml_attr_contains(n, "place", "MenuItem"))
737 font = &config_font_menuitem;
738 else if (obt_xml_attr_contains(n, "place", "ActiveOnScreenDisplay"))
739 font = &config_font_activeosd;
740 else if (obt_xml_attr_contains(n, "place", "OnScreenDisplay"))
741 font = &config_font_activeosd;
742 else if (obt_xml_attr_contains(n, "place","InactiveOnScreenDisplay"))
743 font = &config_font_inactiveosd;
747 if ((fnode = obt_xml_find_node(n->children, "name"))) {
749 name = obt_xml_node_string(fnode);
751 if ((fnode = obt_xml_find_node(n->children, "size"))) {
752 int s = obt_xml_node_int(fnode);
755 if ((fnode = obt_xml_find_node(n->children, "weight"))) {
756 gchar *w = obt_xml_node_string(fnode);
757 if (!g_ascii_strcasecmp(w, "Bold"))
758 weight = RR_FONTWEIGHT_BOLD;
761 if ((fnode = obt_xml_find_node(n->children, "slant"))) {
762 gchar *s = obt_xml_node_string(fnode);
763 if (!g_ascii_strcasecmp(s, "Italic"))
764 slant = RR_FONTSLANT_ITALIC;
765 if (!g_ascii_strcasecmp(s, "Oblique"))
766 slant = RR_FONTSLANT_OBLIQUE;
770 *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
773 n = obt_xml_find_node(n->next, "font");
777 static void parse_desktops(xmlNodePtr node, gpointer d)
781 node = node->children;
783 if ((n = obt_xml_find_node(node, "number"))) {
784 gint d = obt_xml_node_int(n);
786 config_desktops_num = (unsigned) d;
788 if ((n = obt_xml_find_node(node, "firstdesk"))) {
789 gint d = obt_xml_node_int(n);
791 config_screen_firstdesk = (unsigned) d;
793 if ((n = obt_xml_find_node(node, "names"))) {
797 for (it = config_desktops_names; it; it = it->next)
799 g_slist_free(config_desktops_names);
800 config_desktops_names = NULL;
802 nname = obt_xml_find_node(n->children, "name");
804 config_desktops_names =
805 g_slist_append(config_desktops_names,
806 obt_xml_node_string(nname));
807 nname = obt_xml_find_node(nname->next, "name");
810 if ((n = obt_xml_find_node(node, "popupTime")))
811 config_desktop_popup_time = obt_xml_node_int(n);
814 static void parse_resize(xmlNodePtr node, gpointer d)
818 node = node->children;
820 if ((n = obt_xml_find_node(node, "drawContents")))
821 config_resize_redraw = obt_xml_node_bool(n);
822 if ((n = obt_xml_find_node(node, "popupShow"))) {
823 config_resize_popup_show = obt_xml_node_int(n);
824 if (obt_xml_node_contains(n, "Always"))
825 config_resize_popup_show = 2;
826 else if (obt_xml_node_contains(n, "Never"))
827 config_resize_popup_show = 0;
828 else if (obt_xml_node_contains(n, "Nonpixel"))
829 config_resize_popup_show = 1;
831 if ((n = obt_xml_find_node(node, "popupPosition"))) {
832 if (obt_xml_node_contains(n, "Top"))
833 config_resize_popup_pos = OB_RESIZE_POS_TOP;
834 else if (obt_xml_node_contains(n, "Center"))
835 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
836 else if (obt_xml_node_contains(n, "Fixed")) {
837 config_resize_popup_pos = OB_RESIZE_POS_FIXED;
839 if ((n = obt_xml_find_node(node, "popupFixedPosition"))) {
842 if ((n2 = obt_xml_find_node(n->children, "x")))
843 config_parse_gravity_coord(n2,
844 &config_resize_popup_fixed.x);
845 if ((n2 = obt_xml_find_node(n->children, "y")))
846 config_parse_gravity_coord(n2,
847 &config_resize_popup_fixed.y);
849 config_resize_popup_fixed.x.pos =
850 MAX(config_resize_popup_fixed.x.pos, 0);
851 config_resize_popup_fixed.y.pos =
852 MAX(config_resize_popup_fixed.y.pos, 0);
858 static void parse_dock(xmlNodePtr node, gpointer d)
862 node = node->children;
864 if ((n = obt_xml_find_node(node, "position"))) {
865 if (obt_xml_node_contains(n, "TopLeft"))
866 config_dock_floating = FALSE,
867 config_dock_pos = OB_DIRECTION_NORTHWEST;
868 else if (obt_xml_node_contains(n, "Top"))
869 config_dock_floating = FALSE,
870 config_dock_pos = OB_DIRECTION_NORTH;
871 else if (obt_xml_node_contains(n, "TopRight"))
872 config_dock_floating = FALSE,
873 config_dock_pos = OB_DIRECTION_NORTHEAST;
874 else if (obt_xml_node_contains(n, "Right"))
875 config_dock_floating = FALSE,
876 config_dock_pos = OB_DIRECTION_EAST;
877 else if (obt_xml_node_contains(n, "BottomRight"))
878 config_dock_floating = FALSE,
879 config_dock_pos = OB_DIRECTION_SOUTHEAST;
880 else if (obt_xml_node_contains(n, "Bottom"))
881 config_dock_floating = FALSE,
882 config_dock_pos = OB_DIRECTION_SOUTH;
883 else if (obt_xml_node_contains(n, "BottomLeft"))
884 config_dock_floating = FALSE,
885 config_dock_pos = OB_DIRECTION_SOUTHWEST;
886 else if (obt_xml_node_contains(n, "Left"))
887 config_dock_floating = FALSE,
888 config_dock_pos = OB_DIRECTION_WEST;
889 else if (obt_xml_node_contains(n, "Floating"))
890 config_dock_floating = TRUE;
892 if (config_dock_floating) {
893 if ((n = obt_xml_find_node(node, "floatingX")))
894 config_dock_x = obt_xml_node_int(n);
895 if ((n = obt_xml_find_node(node, "floatingY")))
896 config_dock_y = obt_xml_node_int(n);
898 if ((n = obt_xml_find_node(node, "noStrut")))
899 config_dock_nostrut = obt_xml_node_bool(n);
901 if ((n = obt_xml_find_node(node, "stacking"))) {
902 if (obt_xml_node_contains(n, "normal"))
903 config_dock_layer = OB_STACKING_LAYER_NORMAL;
904 else if (obt_xml_node_contains(n, "below"))
905 config_dock_layer = OB_STACKING_LAYER_BELOW;
906 else if (obt_xml_node_contains(n, "above"))
907 config_dock_layer = OB_STACKING_LAYER_ABOVE;
909 if ((n = obt_xml_find_node(node, "direction"))) {
910 if (obt_xml_node_contains(n, "horizontal"))
911 config_dock_orient = OB_ORIENTATION_HORZ;
912 else if (obt_xml_node_contains(n, "vertical"))
913 config_dock_orient = OB_ORIENTATION_VERT;
915 if ((n = obt_xml_find_node(node, "autoHide")))
916 config_dock_hide = obt_xml_node_bool(n);
917 if ((n = obt_xml_find_node(node, "hideDelay")))
918 config_dock_hide_delay = obt_xml_node_int(n);
919 if ((n = obt_xml_find_node(node, "showDelay")))
920 config_dock_show_delay = obt_xml_node_int(n);
921 if ((n = obt_xml_find_node(node, "moveButton"))) {
922 gchar *str = obt_xml_node_string(n);
924 if (translate_button(str, &s, &b)) {
925 config_dock_app_move_button = b;
926 config_dock_app_move_modifiers = s;
928 g_message(_("Invalid button \"%s\" specified in config file"), str);
934 static void parse_menu(xmlNodePtr node, gpointer d)
937 node = node->children;
939 if ((n = obt_xml_find_node(node, "hideDelay")))
940 config_menu_hide_delay = obt_xml_node_int(n);
941 if ((n = obt_xml_find_node(node, "middle")))
942 config_menu_middle = obt_xml_node_bool(n);
943 if ((n = obt_xml_find_node(node, "submenuShowDelay")))
944 config_submenu_show_delay = obt_xml_node_int(n);
945 if ((n = obt_xml_find_node(node, "submenuHideDelay")))
946 config_submenu_hide_delay = obt_xml_node_int(n);
947 if ((n = obt_xml_find_node(node, "manageDesktops")))
948 config_menu_manage_desktops = obt_xml_node_bool(n);
949 if ((n = obt_xml_find_node(node, "showIcons"))) {
950 config_menu_show_icons = obt_xml_node_bool(n);
951 #if !defined(USE_IMLIB2) && !defined(USE_LIBRSVG)
952 if (config_menu_show_icons)
953 g_message(_("Openbox was compiled without image loading support. Icons in menus will not be loaded."));
957 while ((node = obt_xml_find_node(node, "file"))) {
958 gchar *c = obt_xml_node_string(node);
959 config_menu_files = g_slist_append(config_menu_files,
960 obt_paths_expand_tilde(c));
966 static void parse_resistance(xmlNodePtr node, gpointer d)
970 node = node->children;
971 if ((n = obt_xml_find_node(node, "strength")))
972 config_resist_win = obt_xml_node_int(n);
973 if ((n = obt_xml_find_node(node, "screen_edge_strength")))
974 config_resist_edge = obt_xml_node_int(n);
980 const gchar *actname;
983 static void bind_default_keyboard(void)
986 ObDefKeyBind binds[] = {
987 { "A-Tab", "NextWindow" },
988 { "S-A-Tab", "PreviousWindow" },
992 for (it = binds; it->key; ++it) {
993 GList *l = g_list_append(NULL, g_strdup(it->key));
994 keyboard_bind(l, actions_parse_string(it->actname));
1000 const gchar *button;
1001 const gchar *context;
1002 const ObMouseAction mact;
1003 const gchar *actname;
1006 static void bind_default_mouse(void)
1009 ObDefMouseBind binds[] = {
1010 { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1011 { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1012 { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1013 { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1014 { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1015 { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1016 { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
1017 { "Left", "Bottom", OB_MOUSE_ACTION_PRESS, "Focus" },
1018 { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1019 { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1020 { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1021 { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1022 { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
1023 { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
1024 { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
1025 { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
1026 { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
1027 { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
1028 { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
1029 { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
1030 { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
1031 { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1032 { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1033 { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1034 { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1035 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
1036 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
1037 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
1038 { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
1039 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
1040 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
1041 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
1042 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximize" },
1043 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
1044 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
1045 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
1046 { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1047 { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1048 { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1049 { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1050 { "Left", "Top", OB_MOUSE_ACTION_MOTION, "Resize" },
1051 { "Left", "Bottom", OB_MOUSE_ACTION_MOTION, "Resize" },
1052 { "Left", "Left", OB_MOUSE_ACTION_MOTION, "Resize" },
1053 { "Left", "Right", OB_MOUSE_ACTION_MOTION, "Resize" },
1054 { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
1055 { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
1056 { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
1057 { NULL, NULL, 0, NULL }
1060 for (it = binds; it->button; ++it)
1061 mouse_bind(it->button, frame_context_from_string(it->context),
1062 it->mact, actions_parse_string(it->actname));
1065 void config_startup(ObtXmlInst *i)
1067 config_focus_new = TRUE;
1068 config_focus_follow = FALSE;
1069 config_focus_delay = 0;
1070 config_focus_raise = FALSE;
1071 config_focus_last = TRUE;
1072 config_focus_under_mouse = FALSE;
1073 config_unfocus_leave = FALSE;
1075 obt_xml_register(i, "focus", parse_focus, NULL);
1077 config_place_policy = OB_PLACE_POLICY_SMART;
1078 config_place_center = TRUE;
1079 config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
1081 config_primary_monitor_index = 1;
1082 config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
1084 obt_xml_register(i, "placement", parse_placement, NULL);
1086 STRUT_PARTIAL_SET(config_margins, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1088 obt_xml_register(i, "margins", parse_margins, NULL);
1090 config_theme = NULL;
1092 config_animate_iconify = TRUE;
1093 config_title_layout = g_strdup("NLIMC");
1094 config_theme_keepborder = TRUE;
1095 config_theme_window_list_icon_size = 36;
1097 config_font_activewindow = NULL;
1098 config_font_inactivewindow = NULL;
1099 config_font_menuitem = NULL;
1100 config_font_menutitle = NULL;
1101 config_font_activeosd = NULL;
1102 config_font_inactiveosd = NULL;
1104 obt_xml_register(i, "theme", parse_theme, NULL);
1106 config_desktops_num = 4;
1107 config_screen_firstdesk = 1;
1108 config_desktops_names = NULL;
1109 config_desktop_popup_time = 875;
1111 obt_xml_register(i, "desktops", parse_desktops, NULL);
1113 config_resize_redraw = TRUE;
1114 config_resize_popup_show = 1; /* nonpixel increments */
1115 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
1116 GRAVITY_COORD_SET(config_resize_popup_fixed.x, 0, FALSE, FALSE);
1117 GRAVITY_COORD_SET(config_resize_popup_fixed.y, 0, FALSE, FALSE);
1119 obt_xml_register(i, "resize", parse_resize, NULL);
1121 config_dock_layer = OB_STACKING_LAYER_ABOVE;
1122 config_dock_pos = OB_DIRECTION_NORTHEAST;
1123 config_dock_floating = FALSE;
1124 config_dock_nostrut = FALSE;
1127 config_dock_orient = OB_ORIENTATION_VERT;
1128 config_dock_hide = FALSE;
1129 config_dock_hide_delay = 300;
1130 config_dock_show_delay = 300;
1131 config_dock_app_move_button = 2; /* middle */
1132 config_dock_app_move_modifiers = 0;
1134 obt_xml_register(i, "dock", parse_dock, NULL);
1136 translate_key("C-g", &config_keyboard_reset_state,
1137 &config_keyboard_reset_keycode);
1138 config_keyboard_rebind_on_mapping_notify = TRUE;
1140 bind_default_keyboard();
1142 obt_xml_register(i, "keyboard", parse_keyboard, NULL);
1144 config_mouse_threshold = 8;
1145 config_mouse_dclicktime = 500;
1146 config_mouse_screenedgetime = 400;
1147 config_mouse_screenedgewarp = FALSE;
1149 bind_default_mouse();
1151 obt_xml_register(i, "mouse", parse_mouse, NULL);
1153 config_resist_win = 10;
1154 config_resist_edge = 20;
1156 obt_xml_register(i, "resistance", parse_resistance, NULL);
1158 config_menu_hide_delay = 250;
1159 config_menu_middle = FALSE;
1160 config_submenu_show_delay = 100;
1161 config_submenu_hide_delay = 400;
1162 config_menu_manage_desktops = TRUE;
1163 config_menu_files = NULL;
1164 config_menu_show_icons = TRUE;
1166 obt_xml_register(i, "menu", parse_menu, NULL);
1168 config_per_app_settings = NULL;
1170 obt_xml_register(i, "applications", parse_per_app_settings, NULL);
1173 void config_shutdown(void)
1177 g_free(config_theme);
1179 g_free(config_title_layout);
1181 RrFontClose(config_font_activewindow);
1182 RrFontClose(config_font_inactivewindow);
1183 RrFontClose(config_font_menuitem);
1184 RrFontClose(config_font_menutitle);
1185 RrFontClose(config_font_activeosd);
1186 RrFontClose(config_font_inactiveosd);
1188 for (it = config_desktops_names; it; it = g_slist_next(it))
1190 g_slist_free(config_desktops_names);
1192 for (it = config_menu_files; it; it = g_slist_next(it))
1194 g_slist_free(config_menu_files);
1196 for (it = config_per_app_settings; it; it = g_slist_next(it)) {
1197 ObAppSettings *itd = (ObAppSettings *)it->data;
1198 if (itd->name) g_pattern_spec_free(itd->name);
1199 if (itd->role) g_pattern_spec_free(itd->role);
1200 if (itd->title) g_pattern_spec_free(itd->title);
1201 if (itd->class) g_pattern_spec_free(itd->class);
1202 if (itd->group_name) g_pattern_spec_free(itd->group_name);
1203 if (itd->group_class) g_pattern_spec_free(itd->group_class);
1204 g_slice_free(ObAppSettings, it->data);
1206 g_slist_free(config_per_app_settings);