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;
67 gint config_emulate_xinerama;
69 gboolean config_resize_redraw;
70 gint config_resize_popup_show;
71 ObResizePopupPos config_resize_popup_pos;
72 GravityPoint config_resize_popup_fixed;
74 ObStackingLayer config_dock_layer;
75 gboolean config_dock_floating;
76 gboolean config_dock_nostrut;
77 ObDirection config_dock_pos;
80 ObOrientation config_dock_orient;
81 gboolean config_dock_hide;
82 guint config_dock_hide_delay;
83 guint config_dock_show_delay;
84 guint config_dock_app_move_button;
85 guint config_dock_app_move_modifiers;
87 guint config_keyboard_reset_keycode;
88 guint config_keyboard_reset_state;
89 gboolean config_keyboard_rebind_on_mapping_notify;
91 gint config_mouse_threshold;
92 gint config_mouse_dclicktime;
93 gint config_mouse_screenedgetime;
94 gboolean config_mouse_screenedgewarp;
96 guint config_menu_hide_delay;
97 gboolean config_menu_middle;
98 guint config_submenu_show_delay;
99 guint config_submenu_hide_delay;
100 gboolean config_menu_manage_desktops;
101 gboolean config_menu_show_icons;
103 GSList *config_menu_files;
105 gint config_resist_win;
106 gint config_resist_edge;
108 GSList *config_per_app_settings;
110 ObAppSettings* config_create_app_settings(void)
112 ObAppSettings *settings = g_slice_new0(ObAppSettings);
114 settings->decor = -1;
115 settings->shade = -1;
116 settings->monitor_type = OB_PLACE_MONITOR_ANY;
117 settings->monitor = -1;
118 settings->focus = -1;
119 settings->desktop = 0;
120 settings->layer = -2;
121 settings->iconic = -1;
122 settings->skip_pager = -1;
123 settings->skip_taskbar = -1;
124 settings->fullscreen = -1;
125 settings->max_horz = -1;
126 settings->max_vert = -1;
130 #define copy_if(setting, default) \
131 if (src->setting != default) dst->setting = src->setting
132 void config_app_settings_copy_non_defaults(const ObAppSettings *src,
135 g_assert(src != NULL);
136 g_assert(dst != NULL);
138 copy_if(type, (ObClientType)-1);
141 copy_if(monitor_type, OB_PLACE_MONITOR_ANY);
142 copy_if(monitor, -1);
147 copy_if(skip_pager, -1);
148 copy_if(skip_taskbar, -1);
149 copy_if(fullscreen, -1);
150 copy_if(max_horz, -1);
151 copy_if(max_vert, -1);
153 if (src->pos_given) {
154 dst->pos_given = TRUE;
155 dst->pos_force = src->pos_force;
156 dst->position = src->position;
157 /* monitor is copied above */
160 dst->width_num = src->width_num;
161 dst->width_denom = src->width_denom;
162 dst->height_num = src->height_num;
163 dst->height_denom = src->height_denom;
166 void config_parse_relative_number(gchar *s, gint *num, gint *denom)
168 *num = strtol(s, &s, 10);
172 } else if (*s == '/') {
177 void config_parse_gravity_coord(xmlNodePtr node, GravityCoord *c)
179 gchar *s = obt_xml_node_string(node);
180 if (!g_ascii_strcasecmp(s, "center"))
186 if (s[0] == '-' || s[0] == '+')
188 config_parse_relative_number(ps, &c->pos, &c->denom);
195 <application name="aterm">
198 <application name="Rhythmbox">
205 .. there is a lot more settings available
210 static void parse_single_per_app_settings(xmlNodePtr app,
211 ObAppSettings *settings)
214 gboolean x_pos_given = FALSE;
216 if ((n = obt_xml_find_node(app->children, "decor")))
217 if (!obt_xml_node_contains(n, "default"))
218 settings->decor = obt_xml_node_bool(n);
220 if ((n = obt_xml_find_node(app->children, "shade")))
221 if (!obt_xml_node_contains(n, "default"))
222 settings->shade = obt_xml_node_bool(n);
224 if ((n = obt_xml_find_node(app->children, "position"))) {
225 if ((c = obt_xml_find_node(n->children, "x"))) {
226 if (!obt_xml_node_contains(c, "default")) {
227 config_parse_gravity_coord(c, &settings->position.x);
232 if (x_pos_given && (c = obt_xml_find_node(n->children, "y"))) {
233 if (!obt_xml_node_contains(c, "default")) {
234 config_parse_gravity_coord(c, &settings->position.y);
235 settings->pos_given = TRUE;
239 /* monitor can be set without setting x or y */
240 if ((c = obt_xml_find_node(n->children, "monitor"))) {
241 if (!obt_xml_node_contains(c, "default")) {
242 gchar *s = obt_xml_node_string(c);
243 if (!g_ascii_strcasecmp(s, "mouse"))
244 settings->monitor_type = OB_PLACE_MONITOR_MOUSE;
245 else if (!g_ascii_strcasecmp(s, "active"))
246 settings->monitor_type = OB_PLACE_MONITOR_ACTIVE;
247 else if (!g_ascii_strcasecmp(s, "primary"))
248 settings->monitor_type = OB_PLACE_MONITOR_PRIMARY;
250 settings->monitor = obt_xml_node_int(c);
255 obt_xml_attr_bool(n, "force", &settings->pos_force);
258 if ((n = obt_xml_find_node(app->children, "size"))) {
259 if ((c = obt_xml_find_node(n->children, "width"))) {
260 if (!obt_xml_node_contains(c, "default")) {
261 gchar *s = obt_xml_node_string(c);
262 config_parse_relative_number(s,
263 &settings->width_num,
264 &settings->width_denom);
265 if (settings->width_num <= 0 || settings->width_denom < 0)
266 settings->width_num = settings->width_denom = 0;
271 if ((c = obt_xml_find_node(n->children, "height"))) {
272 if (!obt_xml_node_contains(c, "default")) {
273 gchar *s = obt_xml_node_string(c);
274 config_parse_relative_number(s,
275 &settings->height_num,
276 &settings->height_denom);
277 if (settings->height_num <= 0 || settings->height_denom < 0)
278 settings->height_num = settings->height_denom = 0;
284 if ((n = obt_xml_find_node(app->children, "focus"))) {
285 if (!obt_xml_node_contains(n, "default"))
286 settings->focus = obt_xml_node_bool(n);
289 if ((n = obt_xml_find_node(app->children, "desktop"))) {
290 if (!obt_xml_node_contains(n, "default")) {
291 gchar *s = obt_xml_node_string(n);
292 if (!g_ascii_strcasecmp(s, "all"))
293 settings->desktop = DESKTOP_ALL;
295 gint i = obt_xml_node_int(n);
297 settings->desktop = i;
303 if ((n = obt_xml_find_node(app->children, "layer"))) {
304 if (!obt_xml_node_contains(n, "default")) {
305 gchar *s = obt_xml_node_string(n);
306 if (!g_ascii_strcasecmp(s, "above"))
308 else if (!g_ascii_strcasecmp(s, "below"))
309 settings->layer = -1;
316 if ((n = obt_xml_find_node(app->children, "iconic")))
317 if (!obt_xml_node_contains(n, "default"))
318 settings->iconic = obt_xml_node_bool(n);
320 if ((n = obt_xml_find_node(app->children, "skip_pager")))
321 if (!obt_xml_node_contains(n, "default"))
322 settings->skip_pager = obt_xml_node_bool(n);
324 if ((n = obt_xml_find_node(app->children, "skip_taskbar")))
325 if (!obt_xml_node_contains(n, "default"))
326 settings->skip_taskbar = obt_xml_node_bool(n);
328 if ((n = obt_xml_find_node(app->children, "fullscreen")))
329 if (!obt_xml_node_contains(n, "default"))
330 settings->fullscreen = obt_xml_node_bool(n);
332 if ((n = obt_xml_find_node(app->children, "maximized"))) {
333 if (!obt_xml_node_contains(n, "default")) {
334 gchar *s = obt_xml_node_string(n);
335 if (!g_ascii_strcasecmp(s, "horizontal")) {
336 settings->max_horz = TRUE;
337 settings->max_vert = FALSE;
338 } else if (!g_ascii_strcasecmp(s, "vertical")) {
339 settings->max_horz = FALSE;
340 settings->max_vert = TRUE;
342 settings->max_horz = settings->max_vert =
343 obt_xml_node_bool(n);
349 /* Manages settings for individual applications.
350 Some notes: monitor is the screen number in a multi monitor
351 (Xinerama) setup (starting from 0), or mouse: the monitor the pointer
352 is on, active: the active monitor, primary: the primary monitor.
353 Layer can be three values, above (Always on top), below
354 (Always on bottom) and everything else (normal behaviour).
355 Positions can be an integer value or center, which will
356 center the window in the specified axis. Position is within
357 the monitor, so <position><x>center</x></position><monitor>2</monitor>
358 will center the window on the second monitor.
360 static void parse_per_app_settings(xmlNodePtr node, gpointer d)
362 xmlNodePtr app = obt_xml_find_node(node->children, "application");
363 for (; app; app = obt_xml_find_node(app->next, "application")) {
364 ObAppSettings *settings;
366 gboolean name_set, class_set, role_set, title_set,
367 type_set, group_name_set, group_class_set;
368 gchar *name = NULL, *class = NULL, *role = NULL, *title = NULL,
369 *type_str = NULL, *group_name = NULL, *group_class = NULL;
372 class_set = obt_xml_attr_string(app, "class", &class);
373 name_set = obt_xml_attr_string(app, "name", &name);
374 group_class_set = obt_xml_attr_string(app, "groupclass", &group_class);
375 group_name_set = obt_xml_attr_string(app, "groupname", &group_name);
376 type_set = obt_xml_attr_string(app, "type", &type_str);
377 role_set = obt_xml_attr_string(app, "role", &role);
378 title_set = obt_xml_attr_string(app, "title", &title);
380 /* validate the type tho */
382 if (!g_ascii_strcasecmp(type_str, "normal"))
383 type = OB_CLIENT_TYPE_NORMAL;
384 else if (!g_ascii_strcasecmp(type_str, "dialog"))
385 type = OB_CLIENT_TYPE_DIALOG;
386 else if (!g_ascii_strcasecmp(type_str, "splash"))
387 type = OB_CLIENT_TYPE_SPLASH;
388 else if (!g_ascii_strcasecmp(type_str, "utility"))
389 type = OB_CLIENT_TYPE_UTILITY;
390 else if (!g_ascii_strcasecmp(type_str, "menu"))
391 type = OB_CLIENT_TYPE_MENU;
392 else if (!g_ascii_strcasecmp(type_str, "toolbar"))
393 type = OB_CLIENT_TYPE_TOOLBAR;
394 else if (!g_ascii_strcasecmp(type_str, "dock"))
395 type = OB_CLIENT_TYPE_DOCK;
396 else if (!g_ascii_strcasecmp(type_str, "desktop"))
397 type = OB_CLIENT_TYPE_DESKTOP;
399 type_set = FALSE; /* not valid! */
402 if (!(class_set || name_set || role_set || title_set ||
403 type_set || group_class_set || group_name_set))
406 settings = config_create_app_settings();
409 settings->name = g_pattern_spec_new(name);
411 settings->class = g_pattern_spec_new(class);
413 settings->group_name = g_pattern_spec_new(group_name);
415 settings->group_class = g_pattern_spec_new(group_class);
417 settings->role = g_pattern_spec_new(role);
419 settings->title = g_pattern_spec_new(title);
421 settings->type = type;
431 parse_single_per_app_settings(app, settings);
432 config_per_app_settings = g_slist_append(config_per_app_settings,
440 <action name="ChangeDesktop">
447 static void parse_key(xmlNodePtr node, GList *keylist)
449 gchar *keystring, **keys, **key;
451 gboolean is_chroot = FALSE;
452 gboolean grab = TRUE;
453 gboolean repeat = FALSE;
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);
460 obt_xml_attr_bool(node, "repeat", &repeat);
462 keys = g_strsplit(keystring, " ", 0);
463 for (key = keys; *key; ++key) {
464 keylist = g_list_append(keylist, *key);
466 if ((n = obt_xml_find_node(node->children, "keybind"))) {
468 parse_key(n, keylist);
469 n = obt_xml_find_node(n->next, "keybind");
472 else if ((n = obt_xml_find_node(node->children, "action"))) {
474 ObActionsAct *action;
476 action = actions_parse(n);
478 keyboard_bind(keylist, action, grab, !repeat);
479 n = obt_xml_find_node(n->next, "action");
485 keyboard_chroot(keylist);
486 keylist = g_list_delete_link(keylist, g_list_last(keylist));
493 static void parse_keyboard(xmlNodePtr node, gpointer d)
498 keyboard_unbind_all();
500 if ((n = obt_xml_find_node(node->children, "chainQuitKey"))) {
501 key = obt_xml_node_string(n);
502 translate_key(key, &config_keyboard_reset_state,
503 &config_keyboard_reset_keycode);
507 if ((n = obt_xml_find_node(node->children, "keybind")))
510 n = obt_xml_find_node(n->next, "keybind");
513 if ((n = obt_xml_find_node(node->children, "rebindOnMappingNotify")))
514 config_keyboard_rebind_on_mapping_notify = obt_xml_node_bool(n);
519 <context name="Titlebar">
520 <mousebind button="Left" action="Press">
521 <action name="Raise"></action>
527 static void parse_mouse(xmlNodePtr node, gpointer d)
529 xmlNodePtr n, nbut, nact;
536 node = node->children;
538 if ((n = obt_xml_find_node(node, "dragThreshold")))
539 config_mouse_threshold = obt_xml_node_int(n);
540 if ((n = obt_xml_find_node(node, "doubleClickTime")))
541 config_mouse_dclicktime = obt_xml_node_int(n);
542 if ((n = obt_xml_find_node(node, "screenEdgeWarpTime"))) {
543 config_mouse_screenedgetime = obt_xml_node_int(n);
544 /* minimum value of 25 for this property, when it is 1 and you hit the
545 edge it basically never stops */
546 if (config_mouse_screenedgetime && config_mouse_screenedgetime < 25)
547 config_mouse_screenedgetime = 25;
549 if ((n = obt_xml_find_node(node, "screenEdgeWarpMouse")))
550 config_mouse_screenedgewarp = obt_xml_node_bool(n);
552 for (n = obt_xml_find_node(node, "context");
554 n = obt_xml_find_node(n->next, "context"))
559 if (!obt_xml_attr_string(n, "name", &cxstr))
562 modcxstr = g_strdup(cxstr); /* make a copy to mutilate */
563 while (frame_next_context_from_string(modcxstr, &cx)) {
565 gchar *s = strchr(modcxstr, ' ');
568 g_message(_("Invalid context \"%s\" in mouse binding"),
575 for (nbut = obt_xml_find_node(n->children, "mousebind");
577 nbut = obt_xml_find_node(nbut->next, "mousebind"))
580 gchar **button, **buttons;
582 if (!obt_xml_attr_string(nbut, "button", &buttonstr))
584 if (obt_xml_attr_contains(nbut, "action", "press"))
585 mact = OB_MOUSE_ACTION_PRESS;
586 else if (obt_xml_attr_contains(nbut, "action", "release"))
587 mact = OB_MOUSE_ACTION_RELEASE;
588 else if (obt_xml_attr_contains(nbut, "action", "click"))
589 mact = OB_MOUSE_ACTION_CLICK;
590 else if (obt_xml_attr_contains(nbut, "action","doubleclick"))
591 mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
592 else if (obt_xml_attr_contains(nbut, "action", "drag"))
593 mact = OB_MOUSE_ACTION_MOTION;
597 buttons = g_strsplit(buttonstr, " ", 0);
598 for (nact = obt_xml_find_node(nbut->children, "action");
600 nact = obt_xml_find_node(nact->next, "action"))
602 ObActionsAct *action;
604 /* actions_parse() creates one ref to the action, but we need
605 * exactly one ref per binding we use it for. */
606 if ((action = actions_parse(nact))) {
607 for (button = buttons; *button; ++button) {
608 actions_act_ref(action);
609 mouse_bind(*button, cx, mact, action);
611 actions_act_unref(action);
623 static void parse_focus(xmlNodePtr node, gpointer d)
627 node = node->children;
629 if ((n = obt_xml_find_node(node, "focusNew")))
630 config_focus_new = obt_xml_node_bool(n);
631 if ((n = obt_xml_find_node(node, "followMouse")))
632 config_focus_follow = obt_xml_node_bool(n);
633 if ((n = obt_xml_find_node(node, "focusDelay")))
634 config_focus_delay = obt_xml_node_int(n);
635 if ((n = obt_xml_find_node(node, "raiseOnFocus")))
636 config_focus_raise = obt_xml_node_bool(n);
637 if ((n = obt_xml_find_node(node, "focusLast")))
638 config_focus_last = obt_xml_node_bool(n);
639 if ((n = obt_xml_find_node(node, "underMouse")))
640 config_focus_under_mouse = obt_xml_node_bool(n);
641 if ((n = obt_xml_find_node(node, "unfocusOnLeave")))
642 config_unfocus_leave = obt_xml_node_bool(n);
645 static void parse_placement(xmlNodePtr node, gpointer d)
649 node = node->children;
651 if ((n = obt_xml_find_node(node, "policy"))) {
652 if (obt_xml_node_contains(n, "UnderMouse"))
653 config_place_policy = OB_PLACE_POLICY_MOUSE;
654 if (obt_xml_node_contains(n, "Random"))
655 config_place_policy = OB_PLACE_POLICY_RANDOM;
657 if ((n = obt_xml_find_node(node, "center"))) {
658 config_place_center = obt_xml_node_bool(n);
660 if ((n = obt_xml_find_node(node, "monitor"))) {
661 if (obt_xml_node_contains(n, "active"))
662 config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
663 else if (obt_xml_node_contains(n, "mouse"))
664 config_place_monitor = OB_PLACE_MONITOR_MOUSE;
665 else if (obt_xml_node_contains(n, "any"))
666 config_place_monitor = OB_PLACE_MONITOR_ANY;
668 if ((n = obt_xml_find_node(node, "primaryMonitor"))) {
669 config_primary_monitor_index = obt_xml_node_int(n);
670 if (!config_primary_monitor_index) {
671 if (obt_xml_node_contains(n, "mouse"))
672 config_primary_monitor = OB_PLACE_MONITOR_MOUSE;
677 static void parse_margins(xmlNodePtr node, gpointer d)
681 node = node->children;
683 if ((n = obt_xml_find_node(node, "top")))
684 config_margins.top = MAX(0, obt_xml_node_int(n));
685 if ((n = obt_xml_find_node(node, "left")))
686 config_margins.left = MAX(0, obt_xml_node_int(n));
687 if ((n = obt_xml_find_node(node, "right")))
688 config_margins.right = MAX(0, obt_xml_node_int(n));
689 if ((n = obt_xml_find_node(node, "bottom")))
690 config_margins.bottom = MAX(0, obt_xml_node_int(n));
693 static void parse_theme(xmlNodePtr node, gpointer d)
697 node = node->children;
699 if ((n = obt_xml_find_node(node, "name"))) {
702 g_free(config_theme);
703 c = obt_xml_node_string(n);
704 config_theme = obt_paths_expand_tilde(c);
707 if ((n = obt_xml_find_node(node, "titleLayout"))) {
710 g_free(config_title_layout);
711 config_title_layout = obt_xml_node_string(n);
713 /* replace duplicates with spaces */
714 for (c = config_title_layout; *c != '\0'; ++c)
715 for (d = c+1; *d != '\0'; ++d)
716 if (*c == *d) *d = ' ';
718 if ((n = obt_xml_find_node(node, "keepBorder")))
719 config_theme_keepborder = obt_xml_node_bool(n);
720 if ((n = obt_xml_find_node(node, "animateIconify")))
721 config_animate_iconify = obt_xml_node_bool(n);
722 if ((n = obt_xml_find_node(node, "windowListIconSize"))) {
723 config_theme_window_list_icon_size = obt_xml_node_int(n);
724 if (config_theme_window_list_icon_size < 16)
725 config_theme_window_list_icon_size = 16;
726 else if (config_theme_window_list_icon_size > 96)
727 config_theme_window_list_icon_size = 96;
730 for (n = obt_xml_find_node(node, "font");
732 n = obt_xml_find_node(n->next, "font"))
736 gchar *name = g_strdup(RrDefaultFontFamily);
737 gint size = RrDefaultFontSize;
738 RrFontWeight weight = RrDefaultFontWeight;
739 RrFontSlant slant = RrDefaultFontSlant;
741 if (obt_xml_attr_contains(n, "place", "ActiveWindow"))
742 font = &config_font_activewindow;
743 else if (obt_xml_attr_contains(n, "place", "InactiveWindow"))
744 font = &config_font_inactivewindow;
745 else if (obt_xml_attr_contains(n, "place", "MenuHeader"))
746 font = &config_font_menutitle;
747 else if (obt_xml_attr_contains(n, "place", "MenuItem"))
748 font = &config_font_menuitem;
749 else if (obt_xml_attr_contains(n, "place", "ActiveOnScreenDisplay"))
750 font = &config_font_activeosd;
751 else if (obt_xml_attr_contains(n, "place", "OnScreenDisplay"))
752 font = &config_font_activeosd;
753 else if (obt_xml_attr_contains(n, "place","InactiveOnScreenDisplay"))
754 font = &config_font_inactiveosd;
758 if ((fnode = obt_xml_find_node(n->children, "name"))) {
760 name = obt_xml_node_string(fnode);
762 if ((fnode = obt_xml_find_node(n->children, "size"))) {
763 int s = obt_xml_node_int(fnode);
766 if (obt_xml_attr_contains(fnode, "type", "absolute"))
770 if ((fnode = obt_xml_find_node(n->children, "weight"))) {
771 gchar *w = obt_xml_node_string(fnode);
772 if (!g_ascii_strcasecmp(w, "Bold"))
773 weight = RR_FONTWEIGHT_BOLD;
776 if ((fnode = obt_xml_find_node(n->children, "slant"))) {
777 gchar *s = obt_xml_node_string(fnode);
778 if (!g_ascii_strcasecmp(s, "Italic"))
779 slant = RR_FONTSLANT_ITALIC;
780 if (!g_ascii_strcasecmp(s, "Oblique"))
781 slant = RR_FONTSLANT_OBLIQUE;
785 *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
788 if ((fnode = obt_xml_find_node(n->children, "description"))) {
789 gchar *s = obt_xml_node_string(fnode);
790 RrFontDescriptionFromString(*font, s);
796 static void parse_desktops(xmlNodePtr node, gpointer d)
800 node = node->children;
802 if ((n = obt_xml_find_node(node, "number"))) {
803 gint d = obt_xml_node_int(n);
805 config_desktops_num = (unsigned) d;
807 if ((n = obt_xml_find_node(node, "firstdesk"))) {
808 gint d = obt_xml_node_int(n);
810 config_screen_firstdesk = (unsigned) d;
812 if ((n = obt_xml_find_node(node, "emulatexinerama")))
813 config_emulate_xinerama = obt_xml_node_bool(n);
814 if ((n = obt_xml_find_node(node, "names"))) {
818 for (it = config_desktops_names; it; it = it->next)
820 g_slist_free(config_desktops_names);
821 config_desktops_names = NULL;
823 for (nname = obt_xml_find_node(n->children, "name");
825 nname = obt_xml_find_node(nname->next, "name"))
827 config_desktops_names =
828 g_slist_append(config_desktops_names,
829 obt_xml_node_string(nname));
832 if ((n = obt_xml_find_node(node, "popupTime")))
833 config_desktop_popup_time = obt_xml_node_int(n);
836 static void parse_resize(xmlNodePtr node, gpointer d)
840 node = node->children;
842 if ((n = obt_xml_find_node(node, "drawContents")))
843 config_resize_redraw = obt_xml_node_bool(n);
844 if ((n = obt_xml_find_node(node, "popupShow"))) {
845 config_resize_popup_show = obt_xml_node_int(n);
846 if (obt_xml_node_contains(n, "Always"))
847 config_resize_popup_show = 2;
848 else if (obt_xml_node_contains(n, "Never"))
849 config_resize_popup_show = 0;
850 else if (obt_xml_node_contains(n, "Nonpixel"))
851 config_resize_popup_show = 1;
853 if ((n = obt_xml_find_node(node, "popupPosition"))) {
854 if (obt_xml_node_contains(n, "Top"))
855 config_resize_popup_pos = OB_RESIZE_POS_TOP;
856 else if (obt_xml_node_contains(n, "Center"))
857 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
858 else if (obt_xml_node_contains(n, "Fixed")) {
859 config_resize_popup_pos = OB_RESIZE_POS_FIXED;
861 if ((n = obt_xml_find_node(node, "popupFixedPosition"))) {
864 if ((n2 = obt_xml_find_node(n->children, "x")))
865 config_parse_gravity_coord(n2,
866 &config_resize_popup_fixed.x);
867 if ((n2 = obt_xml_find_node(n->children, "y")))
868 config_parse_gravity_coord(n2,
869 &config_resize_popup_fixed.y);
871 config_resize_popup_fixed.x.pos =
872 MAX(config_resize_popup_fixed.x.pos, 0);
873 config_resize_popup_fixed.y.pos =
874 MAX(config_resize_popup_fixed.y.pos, 0);
880 static void parse_dock(xmlNodePtr node, gpointer d)
884 node = node->children;
886 if ((n = obt_xml_find_node(node, "position"))) {
887 if (obt_xml_node_contains(n, "TopLeft"))
888 config_dock_floating = FALSE,
889 config_dock_pos = OB_DIRECTION_NORTHWEST;
890 else if (obt_xml_node_contains(n, "Top"))
891 config_dock_floating = FALSE,
892 config_dock_pos = OB_DIRECTION_NORTH;
893 else if (obt_xml_node_contains(n, "TopRight"))
894 config_dock_floating = FALSE,
895 config_dock_pos = OB_DIRECTION_NORTHEAST;
896 else if (obt_xml_node_contains(n, "Right"))
897 config_dock_floating = FALSE,
898 config_dock_pos = OB_DIRECTION_EAST;
899 else if (obt_xml_node_contains(n, "BottomRight"))
900 config_dock_floating = FALSE,
901 config_dock_pos = OB_DIRECTION_SOUTHEAST;
902 else if (obt_xml_node_contains(n, "Bottom"))
903 config_dock_floating = FALSE,
904 config_dock_pos = OB_DIRECTION_SOUTH;
905 else if (obt_xml_node_contains(n, "BottomLeft"))
906 config_dock_floating = FALSE,
907 config_dock_pos = OB_DIRECTION_SOUTHWEST;
908 else if (obt_xml_node_contains(n, "Left"))
909 config_dock_floating = FALSE,
910 config_dock_pos = OB_DIRECTION_WEST;
911 else if (obt_xml_node_contains(n, "Floating"))
912 config_dock_floating = TRUE;
914 if (config_dock_floating) {
915 if ((n = obt_xml_find_node(node, "floatingX")))
916 config_dock_x = obt_xml_node_int(n);
917 if ((n = obt_xml_find_node(node, "floatingY")))
918 config_dock_y = obt_xml_node_int(n);
920 if ((n = obt_xml_find_node(node, "noStrut")))
921 config_dock_nostrut = obt_xml_node_bool(n);
923 if ((n = obt_xml_find_node(node, "stacking"))) {
924 if (obt_xml_node_contains(n, "normal"))
925 config_dock_layer = OB_STACKING_LAYER_NORMAL;
926 else if (obt_xml_node_contains(n, "below"))
927 config_dock_layer = OB_STACKING_LAYER_BELOW;
928 else if (obt_xml_node_contains(n, "above"))
929 config_dock_layer = OB_STACKING_LAYER_ABOVE;
931 if ((n = obt_xml_find_node(node, "direction"))) {
932 if (obt_xml_node_contains(n, "horizontal"))
933 config_dock_orient = OB_ORIENTATION_HORZ;
934 else if (obt_xml_node_contains(n, "vertical"))
935 config_dock_orient = OB_ORIENTATION_VERT;
937 if ((n = obt_xml_find_node(node, "autoHide")))
938 config_dock_hide = obt_xml_node_bool(n);
939 if ((n = obt_xml_find_node(node, "hideDelay")))
940 config_dock_hide_delay = obt_xml_node_int(n);
941 if ((n = obt_xml_find_node(node, "showDelay")))
942 config_dock_show_delay = obt_xml_node_int(n);
943 if ((n = obt_xml_find_node(node, "moveButton"))) {
944 gchar *str = obt_xml_node_string(n);
946 if (translate_button(str, &s, &b)) {
947 config_dock_app_move_button = b;
948 config_dock_app_move_modifiers = s;
950 g_message(_("Invalid button \"%s\" specified in config file"), str);
956 static void parse_menu(xmlNodePtr node, gpointer d)
959 node = node->children;
961 if ((n = obt_xml_find_node(node, "hideDelay")))
962 config_menu_hide_delay = obt_xml_node_int(n);
963 if ((n = obt_xml_find_node(node, "middle")))
964 config_menu_middle = obt_xml_node_bool(n);
965 if ((n = obt_xml_find_node(node, "submenuShowDelay")))
966 config_submenu_show_delay = obt_xml_node_int(n);
967 if ((n = obt_xml_find_node(node, "submenuHideDelay")))
968 config_submenu_hide_delay = obt_xml_node_int(n);
969 if ((n = obt_xml_find_node(node, "manageDesktops")))
970 config_menu_manage_desktops = obt_xml_node_bool(n);
971 if ((n = obt_xml_find_node(node, "showIcons"))) {
972 config_menu_show_icons = obt_xml_node_bool(n);
973 #if !defined(USE_IMLIB2) && !defined(USE_LIBRSVG)
974 if (config_menu_show_icons)
975 g_message(_("Openbox was compiled without image loading support. Icons in menus will not be loaded."));
979 for (node = obt_xml_find_node(node, "file");
981 node = obt_xml_find_node(node->next, "file"))
983 gchar *c = obt_xml_node_string(node);
984 config_menu_files = g_slist_append(config_menu_files,
985 obt_paths_expand_tilde(c));
990 static void parse_resistance(xmlNodePtr node, gpointer d)
994 node = node->children;
995 if ((n = obt_xml_find_node(node, "strength")))
996 config_resist_win = obt_xml_node_int(n);
997 if ((n = obt_xml_find_node(node, "screen_edge_strength")))
998 config_resist_edge = obt_xml_node_int(n);
1004 const gchar *actname;
1007 static void bind_default_keyboard(void)
1010 ObDefKeyBind binds[] = {
1011 { "A-Tab", "NextWindow" },
1012 { "S-A-Tab", "PreviousWindow" },
1013 { "A-F4", "Close" },
1016 for (it = binds; it->key; ++it) {
1017 GList *l = g_list_append(NULL, g_strdup(it->key));
1018 keyboard_bind(l, actions_parse_string(it->actname), TRUE, TRUE);
1024 const gchar *button;
1025 const gchar *context;
1026 const ObMouseAction mact;
1027 const gchar *actname;
1030 static void bind_default_mouse(void)
1033 ObDefMouseBind binds[] = {
1034 { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1035 { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1036 { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1037 { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1038 { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1039 { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1040 { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
1041 { "Left", "Bottom", OB_MOUSE_ACTION_PRESS, "Focus" },
1042 { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1043 { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1044 { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1045 { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1046 { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
1047 { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
1048 { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
1049 { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
1050 { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
1051 { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
1052 { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
1053 { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
1054 { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
1055 { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1056 { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1057 { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1058 { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1059 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
1060 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
1061 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
1062 { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
1063 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
1064 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
1065 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
1066 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximize" },
1067 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
1068 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
1069 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
1070 { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1071 { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1072 { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1073 { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1074 { "Left", "Top", OB_MOUSE_ACTION_MOTION, "Resize" },
1075 { "Left", "Bottom", OB_MOUSE_ACTION_MOTION, "Resize" },
1076 { "Left", "Left", OB_MOUSE_ACTION_MOTION, "Resize" },
1077 { "Left", "Right", OB_MOUSE_ACTION_MOTION, "Resize" },
1078 { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
1079 { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
1080 { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
1081 { NULL, NULL, 0, NULL }
1084 for (it = binds; it->button; ++it)
1085 mouse_bind(it->button, frame_context_from_string(it->context),
1086 it->mact, actions_parse_string(it->actname));
1089 void config_startup(ObtXmlInst *i)
1091 config_focus_new = TRUE;
1092 config_focus_follow = FALSE;
1093 config_focus_delay = 0;
1094 config_focus_raise = FALSE;
1095 config_focus_last = TRUE;
1096 config_focus_under_mouse = FALSE;
1097 config_unfocus_leave = FALSE;
1099 obt_xml_register(i, "focus", parse_focus, NULL);
1101 config_place_policy = OB_PLACE_POLICY_SMART;
1102 config_place_center = TRUE;
1103 config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
1105 config_primary_monitor_index = 1;
1106 config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
1108 obt_xml_register(i, "placement", parse_placement, NULL);
1110 STRUT_PARTIAL_SET(config_margins, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1112 obt_xml_register(i, "margins", parse_margins, NULL);
1114 config_theme = NULL;
1116 config_animate_iconify = TRUE;
1117 config_title_layout = g_strdup("NLIMC");
1118 config_theme_keepborder = TRUE;
1119 config_theme_window_list_icon_size = 36;
1121 config_font_activewindow = NULL;
1122 config_font_inactivewindow = NULL;
1123 config_font_menuitem = NULL;
1124 config_font_menutitle = NULL;
1125 config_font_activeosd = NULL;
1126 config_font_inactiveosd = NULL;
1128 obt_xml_register(i, "theme", parse_theme, NULL);
1130 config_desktops_num = 4;
1131 config_screen_firstdesk = 1;
1132 config_emulate_xinerama = FALSE;
1133 config_desktops_names = NULL;
1134 config_desktop_popup_time = 875;
1136 obt_xml_register(i, "desktops", parse_desktops, NULL);
1138 config_resize_redraw = TRUE;
1139 config_resize_popup_show = 1; /* nonpixel increments */
1140 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
1141 GRAVITY_COORD_SET(config_resize_popup_fixed.x, 0, FALSE, FALSE);
1142 GRAVITY_COORD_SET(config_resize_popup_fixed.y, 0, FALSE, FALSE);
1144 obt_xml_register(i, "resize", parse_resize, NULL);
1146 config_dock_layer = OB_STACKING_LAYER_ABOVE;
1147 config_dock_pos = OB_DIRECTION_NORTHEAST;
1148 config_dock_floating = FALSE;
1149 config_dock_nostrut = FALSE;
1152 config_dock_orient = OB_ORIENTATION_VERT;
1153 config_dock_hide = FALSE;
1154 config_dock_hide_delay = 300;
1155 config_dock_show_delay = 300;
1156 config_dock_app_move_button = 2; /* middle */
1157 config_dock_app_move_modifiers = 0;
1159 obt_xml_register(i, "dock", parse_dock, NULL);
1161 translate_key("C-g", &config_keyboard_reset_state,
1162 &config_keyboard_reset_keycode);
1163 config_keyboard_rebind_on_mapping_notify = TRUE;
1165 bind_default_keyboard();
1167 obt_xml_register(i, "keyboard", parse_keyboard, NULL);
1169 config_mouse_threshold = 8;
1170 config_mouse_dclicktime = 500;
1171 config_mouse_screenedgetime = 400;
1172 config_mouse_screenedgewarp = FALSE;
1174 bind_default_mouse();
1176 obt_xml_register(i, "mouse", parse_mouse, NULL);
1178 config_resist_win = 10;
1179 config_resist_edge = 20;
1181 obt_xml_register(i, "resistance", parse_resistance, NULL);
1183 config_menu_hide_delay = 250;
1184 config_menu_middle = FALSE;
1185 config_submenu_show_delay = 100;
1186 config_submenu_hide_delay = 400;
1187 config_menu_manage_desktops = TRUE;
1188 config_menu_files = NULL;
1189 config_menu_show_icons = TRUE;
1191 obt_xml_register(i, "menu", parse_menu, NULL);
1193 config_per_app_settings = NULL;
1195 obt_xml_register(i, "applications", parse_per_app_settings, NULL);
1198 void config_shutdown(void)
1202 g_free(config_theme);
1204 g_free(config_title_layout);
1206 RrFontClose(config_font_activewindow);
1207 RrFontClose(config_font_inactivewindow);
1208 RrFontClose(config_font_menuitem);
1209 RrFontClose(config_font_menutitle);
1210 RrFontClose(config_font_activeosd);
1211 RrFontClose(config_font_inactiveosd);
1213 for (it = config_desktops_names; it; it = g_slist_next(it))
1215 g_slist_free(config_desktops_names);
1217 for (it = config_menu_files; it; it = g_slist_next(it))
1219 g_slist_free(config_menu_files);
1221 for (it = config_per_app_settings; it; it = g_slist_next(it)) {
1222 ObAppSettings *itd = (ObAppSettings *)it->data;
1223 if (itd->name) g_pattern_spec_free(itd->name);
1224 if (itd->role) g_pattern_spec_free(itd->role);
1225 if (itd->title) g_pattern_spec_free(itd->title);
1226 if (itd->class) g_pattern_spec_free(itd->class);
1227 if (itd->group_name) g_pattern_spec_free(itd->group_name);
1228 if (itd->group_class) g_pattern_spec_free(itd->group_class);
1229 g_slice_free(ObAppSettings, it->data);
1231 g_slist_free(config_per_app_settings);