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;
454 if (!obt_xml_attr_string(node, "key", &keystring))
457 obt_xml_attr_bool(node, "chroot", &is_chroot);
458 obt_xml_attr_bool(node, "grab", &grab);
460 keys = g_strsplit(keystring, " ", 0);
461 for (key = keys; *key; ++key) {
462 keylist = g_list_append(keylist, *key);
464 if ((n = obt_xml_find_node(node->children, "keybind"))) {
466 parse_key(n, keylist);
467 n = obt_xml_find_node(n->next, "keybind");
470 else if ((n = obt_xml_find_node(node->children, "action"))) {
472 ObActionsAct *action;
474 action = actions_parse(n);
476 keyboard_bind(keylist, action, grab);
477 n = obt_xml_find_node(n->next, "action");
483 keyboard_chroot(keylist);
484 keylist = g_list_delete_link(keylist, g_list_last(keylist));
491 static void parse_keyboard(xmlNodePtr node, gpointer d)
496 keyboard_unbind_all();
498 if ((n = obt_xml_find_node(node->children, "chainQuitKey"))) {
499 key = obt_xml_node_string(n);
500 translate_key(key, &config_keyboard_reset_state,
501 &config_keyboard_reset_keycode);
505 if ((n = obt_xml_find_node(node->children, "keybind")))
508 n = obt_xml_find_node(n->next, "keybind");
511 if ((n = obt_xml_find_node(node->children, "rebindOnMappingNotify")))
512 config_keyboard_rebind_on_mapping_notify = obt_xml_node_bool(n);
517 <context name="Titlebar">
518 <mousebind button="Left" action="Press">
519 <action name="Raise"></action>
525 static void parse_mouse(xmlNodePtr node, gpointer d)
527 xmlNodePtr n, nbut, nact;
534 node = node->children;
536 if ((n = obt_xml_find_node(node, "dragThreshold")))
537 config_mouse_threshold = obt_xml_node_int(n);
538 if ((n = obt_xml_find_node(node, "doubleClickTime")))
539 config_mouse_dclicktime = obt_xml_node_int(n);
540 if ((n = obt_xml_find_node(node, "screenEdgeWarpTime"))) {
541 config_mouse_screenedgetime = obt_xml_node_int(n);
542 /* minimum value of 25 for this property, when it is 1 and you hit the
543 edge it basically never stops */
544 if (config_mouse_screenedgetime && config_mouse_screenedgetime < 25)
545 config_mouse_screenedgetime = 25;
547 if ((n = obt_xml_find_node(node, "screenEdgeWarpMouse")))
548 config_mouse_screenedgewarp = obt_xml_node_bool(n);
550 for (n = obt_xml_find_node(node, "context");
552 n = obt_xml_find_node(n->next, "context"))
557 if (!obt_xml_attr_string(n, "name", &cxstr))
560 modcxstr = g_strdup(cxstr); /* make a copy to mutilate */
561 while (frame_next_context_from_string(modcxstr, &cx)) {
563 gchar *s = strchr(modcxstr, ' ');
566 g_message(_("Invalid context \"%s\" in mouse binding"),
573 for (nbut = obt_xml_find_node(n->children, "mousebind");
575 nbut = obt_xml_find_node(nbut->next, "mousebind"))
578 gchar **button, **buttons;
580 if (!obt_xml_attr_string(nbut, "button", &buttonstr))
582 if (obt_xml_attr_contains(nbut, "action", "press"))
583 mact = OB_MOUSE_ACTION_PRESS;
584 else if (obt_xml_attr_contains(nbut, "action", "release"))
585 mact = OB_MOUSE_ACTION_RELEASE;
586 else if (obt_xml_attr_contains(nbut, "action", "click"))
587 mact = OB_MOUSE_ACTION_CLICK;
588 else if (obt_xml_attr_contains(nbut, "action","doubleclick"))
589 mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
590 else if (obt_xml_attr_contains(nbut, "action", "drag"))
591 mact = OB_MOUSE_ACTION_MOTION;
595 buttons = g_strsplit(buttonstr, " ", 0);
596 for (nact = obt_xml_find_node(nbut->children, "action");
598 nact = obt_xml_find_node(nact->next, "action"))
600 ObActionsAct *action;
602 /* actions_parse() creates one ref to the action, but we need
603 * exactly one ref per binding we use it for. */
604 if ((action = actions_parse(nact))) {
605 for (button = buttons; *button; ++button) {
606 actions_act_ref(action);
607 mouse_bind(*button, cx, mact, action);
609 actions_act_unref(action);
621 static void parse_focus(xmlNodePtr node, gpointer d)
625 node = node->children;
627 if ((n = obt_xml_find_node(node, "focusNew")))
628 config_focus_new = obt_xml_node_bool(n);
629 if ((n = obt_xml_find_node(node, "followMouse")))
630 config_focus_follow = obt_xml_node_bool(n);
631 if ((n = obt_xml_find_node(node, "focusDelay")))
632 config_focus_delay = obt_xml_node_int(n);
633 if ((n = obt_xml_find_node(node, "raiseOnFocus")))
634 config_focus_raise = obt_xml_node_bool(n);
635 if ((n = obt_xml_find_node(node, "focusLast")))
636 config_focus_last = obt_xml_node_bool(n);
637 if ((n = obt_xml_find_node(node, "underMouse")))
638 config_focus_under_mouse = obt_xml_node_bool(n);
639 if ((n = obt_xml_find_node(node, "unfocusOnLeave")))
640 config_unfocus_leave = obt_xml_node_bool(n);
643 static void parse_placement(xmlNodePtr node, gpointer d)
647 node = node->children;
649 if ((n = obt_xml_find_node(node, "policy"))) {
650 if (obt_xml_node_contains(n, "UnderMouse"))
651 config_place_policy = OB_PLACE_POLICY_MOUSE;
652 if (obt_xml_node_contains(n, "Random"))
653 config_place_policy = OB_PLACE_POLICY_RANDOM;
655 if ((n = obt_xml_find_node(node, "center"))) {
656 config_place_center = obt_xml_node_bool(n);
658 if ((n = obt_xml_find_node(node, "monitor"))) {
659 if (obt_xml_node_contains(n, "active"))
660 config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
661 else if (obt_xml_node_contains(n, "mouse"))
662 config_place_monitor = OB_PLACE_MONITOR_MOUSE;
663 else if (obt_xml_node_contains(n, "any"))
664 config_place_monitor = OB_PLACE_MONITOR_ANY;
666 if ((n = obt_xml_find_node(node, "primaryMonitor"))) {
667 config_primary_monitor_index = obt_xml_node_int(n);
668 if (!config_primary_monitor_index) {
669 if (obt_xml_node_contains(n, "mouse"))
670 config_primary_monitor = OB_PLACE_MONITOR_MOUSE;
675 static void parse_margins(xmlNodePtr node, gpointer d)
679 node = node->children;
681 if ((n = obt_xml_find_node(node, "top")))
682 config_margins.top = MAX(0, obt_xml_node_int(n));
683 if ((n = obt_xml_find_node(node, "left")))
684 config_margins.left = MAX(0, obt_xml_node_int(n));
685 if ((n = obt_xml_find_node(node, "right")))
686 config_margins.right = MAX(0, obt_xml_node_int(n));
687 if ((n = obt_xml_find_node(node, "bottom")))
688 config_margins.bottom = MAX(0, obt_xml_node_int(n));
691 static void parse_theme(xmlNodePtr node, gpointer d)
695 node = node->children;
697 if ((n = obt_xml_find_node(node, "name"))) {
700 g_free(config_theme);
701 c = obt_xml_node_string(n);
702 config_theme = obt_paths_expand_tilde(c);
705 if ((n = obt_xml_find_node(node, "titleLayout"))) {
708 g_free(config_title_layout);
709 config_title_layout = obt_xml_node_string(n);
711 /* replace duplicates with spaces */
712 for (c = config_title_layout; *c != '\0'; ++c)
713 for (d = c+1; *d != '\0'; ++d)
714 if (*c == *d) *d = ' ';
716 if ((n = obt_xml_find_node(node, "keepBorder")))
717 config_theme_keepborder = obt_xml_node_bool(n);
718 if ((n = obt_xml_find_node(node, "animateIconify")))
719 config_animate_iconify = obt_xml_node_bool(n);
720 if ((n = obt_xml_find_node(node, "windowListIconSize"))) {
721 config_theme_window_list_icon_size = obt_xml_node_int(n);
722 if (config_theme_window_list_icon_size < 16)
723 config_theme_window_list_icon_size = 16;
724 else if (config_theme_window_list_icon_size > 96)
725 config_theme_window_list_icon_size = 96;
728 for (n = obt_xml_find_node(node, "font");
730 n = obt_xml_find_node(n->next, "font"))
734 gchar *name = g_strdup(RrDefaultFontFamily);
735 gint size = RrDefaultFontSize;
736 RrFontWeight weight = RrDefaultFontWeight;
737 RrFontSlant slant = RrDefaultFontSlant;
739 if (obt_xml_attr_contains(n, "place", "ActiveWindow"))
740 font = &config_font_activewindow;
741 else if (obt_xml_attr_contains(n, "place", "InactiveWindow"))
742 font = &config_font_inactivewindow;
743 else if (obt_xml_attr_contains(n, "place", "MenuHeader"))
744 font = &config_font_menutitle;
745 else if (obt_xml_attr_contains(n, "place", "MenuItem"))
746 font = &config_font_menuitem;
747 else if (obt_xml_attr_contains(n, "place", "ActiveOnScreenDisplay"))
748 font = &config_font_activeosd;
749 else if (obt_xml_attr_contains(n, "place", "OnScreenDisplay"))
750 font = &config_font_activeosd;
751 else if (obt_xml_attr_contains(n, "place","InactiveOnScreenDisplay"))
752 font = &config_font_inactiveosd;
756 if ((fnode = obt_xml_find_node(n->children, "name"))) {
758 name = obt_xml_node_string(fnode);
760 if ((fnode = obt_xml_find_node(n->children, "size"))) {
761 int s = obt_xml_node_int(fnode);
764 if ((fnode = obt_xml_find_node(n->children, "weight"))) {
765 gchar *w = obt_xml_node_string(fnode);
766 if (!g_ascii_strcasecmp(w, "Bold"))
767 weight = RR_FONTWEIGHT_BOLD;
770 if ((fnode = obt_xml_find_node(n->children, "slant"))) {
771 gchar *s = obt_xml_node_string(fnode);
772 if (!g_ascii_strcasecmp(s, "Italic"))
773 slant = RR_FONTSLANT_ITALIC;
774 if (!g_ascii_strcasecmp(s, "Oblique"))
775 slant = RR_FONTSLANT_OBLIQUE;
779 *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
782 if ((fnode = obt_xml_find_node(n->children, "description"))) {
783 gchar *s = obt_xml_node_string(fnode);
784 RrFontDescriptionFromString(*font, s);
790 static void parse_desktops(xmlNodePtr node, gpointer d)
794 node = node->children;
796 if ((n = obt_xml_find_node(node, "number"))) {
797 gint d = obt_xml_node_int(n);
799 config_desktops_num = (unsigned) d;
801 if ((n = obt_xml_find_node(node, "firstdesk"))) {
802 gint d = obt_xml_node_int(n);
804 config_screen_firstdesk = (unsigned) d;
806 if ((n = obt_xml_find_node(node, "emulatexinerama")))
807 config_emulate_xinerama = obt_xml_node_bool(n);
808 if ((n = obt_xml_find_node(node, "names"))) {
812 for (it = config_desktops_names; it; it = it->next)
814 g_slist_free(config_desktops_names);
815 config_desktops_names = NULL;
817 for (nname = obt_xml_find_node(n->children, "name");
819 nname = obt_xml_find_node(nname->next, "name"))
821 config_desktops_names =
822 g_slist_append(config_desktops_names,
823 obt_xml_node_string(nname));
826 if ((n = obt_xml_find_node(node, "popupTime")))
827 config_desktop_popup_time = obt_xml_node_int(n);
830 static void parse_resize(xmlNodePtr node, gpointer d)
834 node = node->children;
836 if ((n = obt_xml_find_node(node, "drawContents")))
837 config_resize_redraw = obt_xml_node_bool(n);
838 if ((n = obt_xml_find_node(node, "popupShow"))) {
839 config_resize_popup_show = obt_xml_node_int(n);
840 if (obt_xml_node_contains(n, "Always"))
841 config_resize_popup_show = 2;
842 else if (obt_xml_node_contains(n, "Never"))
843 config_resize_popup_show = 0;
844 else if (obt_xml_node_contains(n, "Nonpixel"))
845 config_resize_popup_show = 1;
847 if ((n = obt_xml_find_node(node, "popupPosition"))) {
848 if (obt_xml_node_contains(n, "Top"))
849 config_resize_popup_pos = OB_RESIZE_POS_TOP;
850 else if (obt_xml_node_contains(n, "Center"))
851 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
852 else if (obt_xml_node_contains(n, "Fixed")) {
853 config_resize_popup_pos = OB_RESIZE_POS_FIXED;
855 if ((n = obt_xml_find_node(node, "popupFixedPosition"))) {
858 if ((n2 = obt_xml_find_node(n->children, "x")))
859 config_parse_gravity_coord(n2,
860 &config_resize_popup_fixed.x);
861 if ((n2 = obt_xml_find_node(n->children, "y")))
862 config_parse_gravity_coord(n2,
863 &config_resize_popup_fixed.y);
865 config_resize_popup_fixed.x.pos =
866 MAX(config_resize_popup_fixed.x.pos, 0);
867 config_resize_popup_fixed.y.pos =
868 MAX(config_resize_popup_fixed.y.pos, 0);
874 static void parse_dock(xmlNodePtr node, gpointer d)
878 node = node->children;
880 if ((n = obt_xml_find_node(node, "position"))) {
881 if (obt_xml_node_contains(n, "TopLeft"))
882 config_dock_floating = FALSE,
883 config_dock_pos = OB_DIRECTION_NORTHWEST;
884 else if (obt_xml_node_contains(n, "Top"))
885 config_dock_floating = FALSE,
886 config_dock_pos = OB_DIRECTION_NORTH;
887 else if (obt_xml_node_contains(n, "TopRight"))
888 config_dock_floating = FALSE,
889 config_dock_pos = OB_DIRECTION_NORTHEAST;
890 else if (obt_xml_node_contains(n, "Right"))
891 config_dock_floating = FALSE,
892 config_dock_pos = OB_DIRECTION_EAST;
893 else if (obt_xml_node_contains(n, "BottomRight"))
894 config_dock_floating = FALSE,
895 config_dock_pos = OB_DIRECTION_SOUTHEAST;
896 else if (obt_xml_node_contains(n, "Bottom"))
897 config_dock_floating = FALSE,
898 config_dock_pos = OB_DIRECTION_SOUTH;
899 else if (obt_xml_node_contains(n, "BottomLeft"))
900 config_dock_floating = FALSE,
901 config_dock_pos = OB_DIRECTION_SOUTHWEST;
902 else if (obt_xml_node_contains(n, "Left"))
903 config_dock_floating = FALSE,
904 config_dock_pos = OB_DIRECTION_WEST;
905 else if (obt_xml_node_contains(n, "Floating"))
906 config_dock_floating = TRUE;
908 if (config_dock_floating) {
909 if ((n = obt_xml_find_node(node, "floatingX")))
910 config_dock_x = obt_xml_node_int(n);
911 if ((n = obt_xml_find_node(node, "floatingY")))
912 config_dock_y = obt_xml_node_int(n);
914 if ((n = obt_xml_find_node(node, "noStrut")))
915 config_dock_nostrut = obt_xml_node_bool(n);
917 if ((n = obt_xml_find_node(node, "stacking"))) {
918 if (obt_xml_node_contains(n, "normal"))
919 config_dock_layer = OB_STACKING_LAYER_NORMAL;
920 else if (obt_xml_node_contains(n, "below"))
921 config_dock_layer = OB_STACKING_LAYER_BELOW;
922 else if (obt_xml_node_contains(n, "above"))
923 config_dock_layer = OB_STACKING_LAYER_ABOVE;
925 if ((n = obt_xml_find_node(node, "direction"))) {
926 if (obt_xml_node_contains(n, "horizontal"))
927 config_dock_orient = OB_ORIENTATION_HORZ;
928 else if (obt_xml_node_contains(n, "vertical"))
929 config_dock_orient = OB_ORIENTATION_VERT;
931 if ((n = obt_xml_find_node(node, "autoHide")))
932 config_dock_hide = obt_xml_node_bool(n);
933 if ((n = obt_xml_find_node(node, "hideDelay")))
934 config_dock_hide_delay = obt_xml_node_int(n);
935 if ((n = obt_xml_find_node(node, "showDelay")))
936 config_dock_show_delay = obt_xml_node_int(n);
937 if ((n = obt_xml_find_node(node, "moveButton"))) {
938 gchar *str = obt_xml_node_string(n);
940 if (translate_button(str, &s, &b)) {
941 config_dock_app_move_button = b;
942 config_dock_app_move_modifiers = s;
944 g_message(_("Invalid button \"%s\" specified in config file"), str);
950 static void parse_menu(xmlNodePtr node, gpointer d)
953 node = node->children;
955 if ((n = obt_xml_find_node(node, "hideDelay")))
956 config_menu_hide_delay = obt_xml_node_int(n);
957 if ((n = obt_xml_find_node(node, "middle")))
958 config_menu_middle = obt_xml_node_bool(n);
959 if ((n = obt_xml_find_node(node, "submenuShowDelay")))
960 config_submenu_show_delay = obt_xml_node_int(n);
961 if ((n = obt_xml_find_node(node, "submenuHideDelay")))
962 config_submenu_hide_delay = obt_xml_node_int(n);
963 if ((n = obt_xml_find_node(node, "manageDesktops")))
964 config_menu_manage_desktops = obt_xml_node_bool(n);
965 if ((n = obt_xml_find_node(node, "showIcons"))) {
966 config_menu_show_icons = obt_xml_node_bool(n);
967 #if !defined(USE_IMLIB2) && !defined(USE_LIBRSVG)
968 if (config_menu_show_icons)
969 g_message(_("Openbox was compiled without image loading support. Icons in menus will not be loaded."));
973 for (node = obt_xml_find_node(node, "file");
975 node = obt_xml_find_node(node->next, "file"))
977 gchar *c = obt_xml_node_string(node);
978 config_menu_files = g_slist_append(config_menu_files,
979 obt_paths_expand_tilde(c));
984 static void parse_resistance(xmlNodePtr node, gpointer d)
988 node = node->children;
989 if ((n = obt_xml_find_node(node, "strength")))
990 config_resist_win = obt_xml_node_int(n);
991 if ((n = obt_xml_find_node(node, "screen_edge_strength")))
992 config_resist_edge = obt_xml_node_int(n);
998 const gchar *actname;
1001 static void bind_default_keyboard(void)
1004 ObDefKeyBind binds[] = {
1005 { "A-Tab", "NextWindow" },
1006 { "S-A-Tab", "PreviousWindow" },
1007 { "A-F4", "Close" },
1010 for (it = binds; it->key; ++it) {
1011 GList *l = g_list_append(NULL, g_strdup(it->key));
1012 keyboard_bind(l, actions_parse_string(it->actname), TRUE);
1018 const gchar *button;
1019 const gchar *context;
1020 const ObMouseAction mact;
1021 const gchar *actname;
1024 static void bind_default_mouse(void)
1027 ObDefMouseBind binds[] = {
1028 { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1029 { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1030 { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
1031 { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1032 { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1033 { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
1034 { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
1035 { "Left", "Bottom", OB_MOUSE_ACTION_PRESS, "Focus" },
1036 { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1037 { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1038 { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1039 { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1040 { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
1041 { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
1042 { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
1043 { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
1044 { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
1045 { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
1046 { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
1047 { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
1048 { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
1049 { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1050 { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1051 { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1052 { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1053 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
1054 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
1055 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
1056 { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
1057 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
1058 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
1059 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
1060 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximize" },
1061 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
1062 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
1063 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
1064 { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1065 { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1066 { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1067 { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1068 { "Left", "Top", OB_MOUSE_ACTION_MOTION, "Resize" },
1069 { "Left", "Bottom", OB_MOUSE_ACTION_MOTION, "Resize" },
1070 { "Left", "Left", OB_MOUSE_ACTION_MOTION, "Resize" },
1071 { "Left", "Right", OB_MOUSE_ACTION_MOTION, "Resize" },
1072 { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
1073 { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
1074 { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
1075 { NULL, NULL, 0, NULL }
1078 for (it = binds; it->button; ++it)
1079 mouse_bind(it->button, frame_context_from_string(it->context),
1080 it->mact, actions_parse_string(it->actname));
1083 void config_startup(ObtXmlInst *i)
1085 config_focus_new = TRUE;
1086 config_focus_follow = FALSE;
1087 config_focus_delay = 0;
1088 config_focus_raise = FALSE;
1089 config_focus_last = TRUE;
1090 config_focus_under_mouse = FALSE;
1091 config_unfocus_leave = FALSE;
1093 obt_xml_register(i, "focus", parse_focus, NULL);
1095 config_place_policy = OB_PLACE_POLICY_SMART;
1096 config_place_center = TRUE;
1097 config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
1099 config_primary_monitor_index = 1;
1100 config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
1102 obt_xml_register(i, "placement", parse_placement, NULL);
1104 STRUT_PARTIAL_SET(config_margins, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1106 obt_xml_register(i, "margins", parse_margins, NULL);
1108 config_theme = NULL;
1110 config_animate_iconify = TRUE;
1111 config_title_layout = g_strdup("NLIMC");
1112 config_theme_keepborder = TRUE;
1113 config_theme_window_list_icon_size = 36;
1115 config_font_activewindow = NULL;
1116 config_font_inactivewindow = NULL;
1117 config_font_menuitem = NULL;
1118 config_font_menutitle = NULL;
1119 config_font_activeosd = NULL;
1120 config_font_inactiveosd = NULL;
1122 obt_xml_register(i, "theme", parse_theme, NULL);
1124 config_desktops_num = 4;
1125 config_screen_firstdesk = 1;
1126 config_emulate_xinerama = FALSE;
1127 config_desktops_names = NULL;
1128 config_desktop_popup_time = 875;
1130 obt_xml_register(i, "desktops", parse_desktops, NULL);
1132 config_resize_redraw = TRUE;
1133 config_resize_popup_show = 1; /* nonpixel increments */
1134 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
1135 GRAVITY_COORD_SET(config_resize_popup_fixed.x, 0, FALSE, FALSE);
1136 GRAVITY_COORD_SET(config_resize_popup_fixed.y, 0, FALSE, FALSE);
1138 obt_xml_register(i, "resize", parse_resize, NULL);
1140 config_dock_layer = OB_STACKING_LAYER_ABOVE;
1141 config_dock_pos = OB_DIRECTION_NORTHEAST;
1142 config_dock_floating = FALSE;
1143 config_dock_nostrut = FALSE;
1146 config_dock_orient = OB_ORIENTATION_VERT;
1147 config_dock_hide = FALSE;
1148 config_dock_hide_delay = 300;
1149 config_dock_show_delay = 300;
1150 config_dock_app_move_button = 2; /* middle */
1151 config_dock_app_move_modifiers = 0;
1153 obt_xml_register(i, "dock", parse_dock, NULL);
1155 translate_key("C-g", &config_keyboard_reset_state,
1156 &config_keyboard_reset_keycode);
1157 config_keyboard_rebind_on_mapping_notify = TRUE;
1159 bind_default_keyboard();
1161 obt_xml_register(i, "keyboard", parse_keyboard, NULL);
1163 config_mouse_threshold = 8;
1164 config_mouse_dclicktime = 500;
1165 config_mouse_screenedgetime = 400;
1166 config_mouse_screenedgewarp = FALSE;
1168 bind_default_mouse();
1170 obt_xml_register(i, "mouse", parse_mouse, NULL);
1172 config_resist_win = 10;
1173 config_resist_edge = 20;
1175 obt_xml_register(i, "resistance", parse_resistance, NULL);
1177 config_menu_hide_delay = 250;
1178 config_menu_middle = FALSE;
1179 config_submenu_show_delay = 100;
1180 config_submenu_hide_delay = 400;
1181 config_menu_manage_desktops = TRUE;
1182 config_menu_files = NULL;
1183 config_menu_show_icons = TRUE;
1185 obt_xml_register(i, "menu", parse_menu, NULL);
1187 config_per_app_settings = NULL;
1189 obt_xml_register(i, "applications", parse_per_app_settings, NULL);
1192 void config_shutdown(void)
1196 g_free(config_theme);
1198 g_free(config_title_layout);
1200 RrFontClose(config_font_activewindow);
1201 RrFontClose(config_font_inactivewindow);
1202 RrFontClose(config_font_menuitem);
1203 RrFontClose(config_font_menutitle);
1204 RrFontClose(config_font_activeosd);
1205 RrFontClose(config_font_inactiveosd);
1207 for (it = config_desktops_names; it; it = g_slist_next(it))
1209 g_slist_free(config_desktops_names);
1211 for (it = config_menu_files; it; it = g_slist_next(it))
1213 g_slist_free(config_menu_files);
1215 for (it = config_per_app_settings; it; it = g_slist_next(it)) {
1216 ObAppSettings *itd = (ObAppSettings *)it->data;
1217 if (itd->name) g_pattern_spec_free(itd->name);
1218 if (itd->role) g_pattern_spec_free(itd->role);
1219 if (itd->title) g_pattern_spec_free(itd->title);
1220 if (itd->class) g_pattern_spec_free(itd->class);
1221 if (itd->group_name) g_pattern_spec_free(itd->group_name);
1222 if (itd->group_class) g_pattern_spec_free(itd->group_class);
1223 g_slice_free(ObAppSettings, it->data);
1225 g_slist_free(config_per_app_settings);