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.
21 #include "config_value.h"
25 #include "action_list.h"
26 #include "action_parser.h"
27 #include "translate.h"
32 #include "obt/paths.h"
34 gboolean config_focus_new;
35 gboolean config_focus_follow;
36 guint config_focus_delay;
37 gboolean config_focus_raise;
38 gboolean config_focus_last;
39 gboolean config_focus_under_mouse;
40 gboolean config_unfocus_leave;
42 ObPlacePolicy config_place_policy;
43 gboolean config_place_center;
44 ObPlaceMonitor config_place_monitor;
46 guint config_primary_monitor_index;
47 ObPlaceMonitor config_primary_monitor;
49 StrutPartial config_margins;
52 gboolean config_theme_keepborder;
53 guint config_theme_window_list_icon_size;
55 gchar *config_title_layout;
57 gboolean config_animate_iconify;
59 RrFont *config_font_activewindow;
60 RrFont *config_font_inactivewindow;
61 RrFont *config_font_menuitem;
62 RrFont *config_font_menutitle;
63 RrFont *config_font_activeosd;
64 RrFont *config_font_inactiveosd;
66 guint config_desktops_num;
67 GSList *config_desktops_names;
68 guint config_screen_firstdesk;
69 guint config_desktop_popup_time;
71 gboolean config_resize_redraw;
72 gint config_resize_popup_show;
73 ObResizePopupPos config_resize_popup_pos;
74 GravityPoint config_resize_popup_fixed;
76 ObStackingLayer config_dock_layer;
77 gboolean config_dock_floating;
78 gboolean config_dock_nostrut;
79 ObDirection config_dock_pos;
82 ObOrientation config_dock_orient;
83 gboolean config_dock_hide;
84 guint config_dock_hide_delay;
85 guint config_dock_show_delay;
86 guint config_dock_app_move_button;
87 guint config_dock_app_move_modifiers;
89 guint config_keyboard_reset_keycode;
90 guint config_keyboard_reset_state;
92 gint config_mouse_threshold;
93 gint config_mouse_dclicktime;
94 gint config_mouse_screenedgetime;
95 gboolean config_mouse_screenedgewarp;
97 guint config_menu_hide_delay;
98 gboolean config_menu_middle;
99 guint config_submenu_show_delay;
100 guint config_submenu_hide_delay;
101 gboolean config_menu_manage_desktops;
102 gboolean config_menu_show_icons;
104 GSList *config_menu_files;
106 gint config_resist_win;
107 gint config_resist_edge;
109 GSList *config_per_app_settings;
111 ObAppSettings* config_create_app_settings(void)
113 ObAppSettings *settings = g_slice_new0(ObAppSettings);
115 settings->decor = -1;
116 settings->shade = -1;
117 settings->monitor = -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, -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 */
162 <application name="aterm">
165 <application name="Rhythmbox">
172 .. there is a lot more settings available
177 /* Manages settings for individual applications.
178 Some notes: monitor is the screen number in a multi monitor
179 (Xinerama) setup (starting from 0) or mouse, meaning the
180 monitor the pointer is on. Default: mouse.
181 Layer can be three values, above (Always on top), below
182 (Always on bottom) and everything else (normal behaviour).
183 Positions can be an integer value or center, which will
184 center the window in the specified axis. Position is within
185 the monitor, so <position><x>center</x></position><monitor>2</monitor>
186 will center the window on the second monitor.
188 static void parse_per_app_settings(xmlNodePtr node, gpointer d)
190 xmlNodePtr app = obt_xml_find_sibling(node->children, "application");
191 gchar *name = NULL, *class = NULL, *role = NULL, *title = NULL,
193 gboolean name_set, class_set, type_set, role_set, title_set;
195 gboolean x_pos_given;
200 class_set = obt_xml_attr_string(app, "class", &class);
201 name_set = obt_xml_attr_string(app, "name", &name);
202 type_set = obt_xml_attr_string(app, "type", &type_str);
203 role_set = obt_xml_attr_string(app, "role", &role);
204 title_set = obt_xml_attr_string(app, "title", &title);
206 /* validate the type tho */
208 if (!g_ascii_strcasecmp(type_str, "normal"))
209 type = OB_CLIENT_TYPE_NORMAL;
210 else if (!g_ascii_strcasecmp(type_str, "dialog"))
211 type = OB_CLIENT_TYPE_DIALOG;
212 else if (!g_ascii_strcasecmp(type_str, "splash"))
213 type = OB_CLIENT_TYPE_SPLASH;
214 else if (!g_ascii_strcasecmp(type_str, "utility"))
215 type = OB_CLIENT_TYPE_UTILITY;
216 else if (!g_ascii_strcasecmp(type_str, "menu"))
217 type = OB_CLIENT_TYPE_MENU;
218 else if (!g_ascii_strcasecmp(type_str, "toolbar"))
219 type = OB_CLIENT_TYPE_TOOLBAR;
220 else if (!g_ascii_strcasecmp(type_str, "dock"))
221 type = OB_CLIENT_TYPE_DOCK;
222 else if (!g_ascii_strcasecmp(type_str, "desktop"))
223 type = OB_CLIENT_TYPE_DESKTOP;
225 type_set = FALSE; /* not valid! */
228 if (class_set || name_set || role_set || title_set || type_set) {
230 ObAppSettings *settings = config_create_app_settings();
233 settings->name = g_pattern_spec_new(name);
236 settings->class = g_pattern_spec_new(class);
239 settings->role = g_pattern_spec_new(role);
242 settings->title = g_pattern_spec_new(title);
245 settings->type = type;
247 if ((n = obt_xml_find_sibling(app->children, "decor")))
248 if (!obt_xml_node_contains(n, "default"))
249 settings->decor = obt_xml_node_bool(n);
251 if ((n = obt_xml_find_sibling(app->children, "shade")))
252 if (!obt_xml_node_contains(n, "default"))
253 settings->shade = obt_xml_node_bool(n);
255 if ((n = obt_xml_find_sibling(app->children, "position"))) {
256 if ((c = obt_xml_find_sibling(n->children, "x")))
257 if (!obt_xml_node_contains(c, "default")) {
258 ObConfigValue *v = config_value_new_string(
259 obt_xml_node_string(node));
260 config_value_gravity_coord(v, &settings->position.x);
261 config_value_unref(v);
265 if (x_pos_given && (c = obt_xml_find_sibling(n->children, "y")))
266 if (!obt_xml_node_contains(c, "default")) {
267 ObConfigValue *v = config_value_new_string(
268 obt_xml_node_string(node));
269 config_value_gravity_coord(v, &settings->position.y);
270 config_value_unref(v);
271 settings->pos_given = TRUE;
274 if (settings->pos_given &&
275 (c = obt_xml_find_sibling(n->children, "monitor")))
276 if (!obt_xml_node_contains(c, "default")) {
277 gchar *s = obt_xml_node_string(c);
278 if (!g_ascii_strcasecmp(s, "mouse"))
279 settings->monitor = 0;
281 settings->monitor = obt_xml_node_int(c);
285 obt_xml_attr_bool(n, "force", &settings->pos_force);
288 if ((n = obt_xml_find_sibling(app->children, "focus")))
289 if (!obt_xml_node_contains(n, "default"))
290 settings->focus = obt_xml_node_bool(n);
292 if ((n = obt_xml_find_sibling(app->children, "desktop"))) {
293 if (!obt_xml_node_contains(n, "default")) {
294 gchar *s = obt_xml_node_string(n);
295 if (!g_ascii_strcasecmp(s, "all"))
296 settings->desktop = DESKTOP_ALL;
298 gint i = obt_xml_node_int(n);
300 settings->desktop = i;
306 if ((n = obt_xml_find_sibling(app->children, "layer")))
307 if (!obt_xml_node_contains(n, "default")) {
308 gchar *s = obt_xml_node_string(n);
309 if (!g_ascii_strcasecmp(s, "above"))
311 else if (!g_ascii_strcasecmp(s, "below"))
312 settings->layer = -1;
318 if ((n = obt_xml_find_sibling(app->children, "iconic")))
319 if (!obt_xml_node_contains(n, "default"))
320 settings->iconic = obt_xml_node_bool(n);
322 if ((n = obt_xml_find_sibling(app->children, "skip_pager")))
323 if (!obt_xml_node_contains(n, "default"))
324 settings->skip_pager = obt_xml_node_bool(n);
326 if ((n = obt_xml_find_sibling(app->children, "skip_taskbar")))
327 if (!obt_xml_node_contains(n, "default"))
328 settings->skip_taskbar = obt_xml_node_bool(n);
330 if ((n = obt_xml_find_sibling(app->children, "fullscreen")))
331 if (!obt_xml_node_contains(n, "default"))
332 settings->fullscreen = obt_xml_node_bool(n);
334 if ((n = obt_xml_find_sibling(app->children, "maximized")))
335 if (!obt_xml_node_contains(n, "default")) {
336 gchar *s = obt_xml_node_string(n);
337 if (!g_ascii_strcasecmp(s, "horizontal")) {
338 settings->max_horz = TRUE;
339 settings->max_vert = FALSE;
340 } else if (!g_ascii_strcasecmp(s, "vertical")) {
341 settings->max_horz = FALSE;
342 settings->max_vert = TRUE;
344 settings->max_horz = settings->max_vert =
345 obt_xml_node_bool(n);
349 config_per_app_settings = g_slist_append(config_per_app_settings,
350 (gpointer) settings);
356 name = class = role = title = type_str = NULL;
359 app = obt_xml_find_sibling(app->next, "application");
366 <action name="ChangeDesktop">
373 static void parse_keybind(xmlNodePtr node, GList *keylist)
375 gchar *keystring, **keys, **key;
377 gboolean is_chroot = FALSE;
379 if (!obt_xml_attr_string(node, "key", &keystring))
382 obt_xml_attr_bool(node, "chroot", &is_chroot);
384 keys = g_strsplit(keystring, " ", 0);
385 for (key = keys; *key; ++key) {
386 keylist = g_list_append(keylist, *key);
388 if ((n = obt_xml_find_sibling(node->children, "keybind"))) {
390 parse_keybind(n, keylist);
391 n = obt_xml_find_sibling(n->next, "keybind");
394 else if ((n = obt_xml_find_sibling(node->children, "action"))) {
397 ObActionList *actions;
400 c = xmlNodeGetContent(node);
401 p = action_parser_new();
402 actions = action_parser_read_string(p, (gchar*)c);
404 action_parser_unref(p);
407 keyboard_bind(keylist, actions);
409 action_list_unref(actions);
410 n = obt_xml_find_sibling(n->next, "action");
416 keyboard_chroot(keylist);
417 keylist = g_list_delete_link(keylist, g_list_last(keylist));
424 static void parse_keyboard(xmlNodePtr node, gpointer d)
429 if ((n = obt_xml_find_sibling(node->children, "chainQuitKey"))) {
430 key = obt_xml_node_string(n);
431 translate_key(key, &config_keyboard_reset_state,
432 &config_keyboard_reset_keycode);
439 <context name="Titlebar">
440 <mousebind button="Left" action="Press">
441 <action name="Raise"></action>
447 static void parse_mouse(xmlNodePtr node, gpointer d)
453 node = node->children;
455 if ((n = obt_xml_find_sibling(node, "dragThreshold")))
456 config_mouse_threshold = obt_xml_node_int(n);
457 if ((n = obt_xml_find_sibling(node, "doubleClickTime")))
458 config_mouse_dclicktime = obt_xml_node_int(n);
459 if ((n = obt_xml_find_sibling(node, "screenEdgeWarpTime"))) {
460 config_mouse_screenedgetime = obt_xml_node_int(n);
461 /* minimum value of 25 for this property, when it is 1 and you hit the
462 edge it basically never stops */
463 if (config_mouse_screenedgetime && config_mouse_screenedgetime < 25)
464 config_mouse_screenedgetime = 25;
466 if ((n = obt_xml_find_sibling(node, "screenEdgeWarpMouse")))
467 config_mouse_screenedgewarp = obt_xml_node_bool(n);
470 static void parse_context(xmlNodePtr n, gpointer d)
472 xmlNodePtr nbut, nact;
479 if (!obt_xml_attr_string(n, "name", &cxstr))
482 modcxstr = g_strdup(cxstr); /* make a copy to mutilate */
483 while (frame_next_context_from_string(modcxstr, &cx)) {
485 gchar *s = strchr(modcxstr, ' ');
488 g_message(_("Invalid context \"%s\" in mouse binding"),
495 nbut = obt_xml_find_sibling(n->children, "mousebind");
497 if (!obt_xml_attr_string(nbut, "button", &buttonstr))
499 if (obt_xml_attr_contains(nbut, "action", "press"))
500 mact = OB_MOUSE_ACTION_PRESS;
501 else if (obt_xml_attr_contains(nbut, "action", "release"))
502 mact = OB_MOUSE_ACTION_RELEASE;
503 else if (obt_xml_attr_contains(nbut, "action", "click"))
504 mact = OB_MOUSE_ACTION_CLICK;
505 else if (obt_xml_attr_contains(nbut, "action","doubleclick"))
506 mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
507 else if (obt_xml_attr_contains(nbut, "action", "drag"))
508 mact = OB_MOUSE_ACTION_MOTION;
512 nact = obt_xml_find_sibling(nbut->children, "action");
514 ObActionList *actions;
518 c = xmlNodeGetContent(nact);
519 p = action_parser_new();
520 if ((actions = action_parser_read_string(p, (gchar*)c)))
521 mouse_bind(buttonstr, cx, mact, actions);
522 nact = obt_xml_find_sibling(nact->next, "action");
523 action_list_unref(actions);
525 action_parser_unref(p);
529 nbut = obt_xml_find_sibling(nbut->next, "mousebind");
537 static void parse_desktops(xmlNodePtr node, gpointer d)
541 node = node->children;
543 if ((n = obt_xml_find_sibling(node, "number"))) {
544 gint d = obt_xml_node_int(n);
546 config_desktops_num = (unsigned) d;
548 if ((n = obt_xml_find_sibling(node, "firstdesk"))) {
549 gint d = obt_xml_node_int(n);
551 config_screen_firstdesk = (unsigned) d;
553 if ((n = obt_xml_find_sibling(node, "names"))) {
557 for (it = config_desktops_names; it; it = it->next)
559 g_slist_free(config_desktops_names);
560 config_desktops_names = NULL;
562 nname = obt_xml_find_sibling(n->children, "name");
564 config_desktops_names =
565 g_slist_append(config_desktops_names,
566 obt_xml_node_string(nname));
567 nname = obt_xml_find_sibling(nname->next, "name");
570 if ((n = obt_xml_find_sibling(node, "popupTime")))
571 config_desktop_popup_time = obt_xml_node_int(n);
574 static void parse_resize(xmlNodePtr node, gpointer d)
578 node = node->children;
580 if ((n = obt_xml_find_sibling(node, "drawContents")))
581 config_resize_redraw = obt_xml_node_bool(n);
582 if ((n = obt_xml_find_sibling(node, "popupShow"))) {
583 config_resize_popup_show = obt_xml_node_int(n);
584 if (obt_xml_node_contains(n, "Always"))
585 config_resize_popup_show = 2;
586 else if (obt_xml_node_contains(n, "Never"))
587 config_resize_popup_show = 0;
588 else if (obt_xml_node_contains(n, "Nonpixel"))
589 config_resize_popup_show = 1;
591 if ((n = obt_xml_find_sibling(node, "popupPosition"))) {
592 if (obt_xml_node_contains(n, "Top"))
593 config_resize_popup_pos = OB_RESIZE_POS_TOP;
594 else if (obt_xml_node_contains(n, "Center"))
595 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
596 else if (obt_xml_node_contains(n, "Fixed")) {
597 config_resize_popup_pos = OB_RESIZE_POS_FIXED;
599 if ((n = obt_xml_find_sibling(node, "popupFixedPosition"))) {
602 if ((n2 = obt_xml_find_sibling(n->children, "x"))) {
603 ObConfigValue *v = config_value_new_string(
604 obt_xml_node_string(n2));
605 config_value_gravity_coord(v,
606 &config_resize_popup_fixed.x);
607 config_value_unref(v);
609 if ((n2 = obt_xml_find_sibling(n->children, "y"))) {
610 ObConfigValue *v = config_value_new_string(
611 obt_xml_node_string(n2));
612 config_value_gravity_coord(v,
613 &config_resize_popup_fixed.y);
614 config_value_unref(v);
617 config_resize_popup_fixed.x.pos =
618 MAX(config_resize_popup_fixed.x.pos, 0);
619 config_resize_popup_fixed.y.pos =
620 MAX(config_resize_popup_fixed.y.pos, 0);
626 static void parse_dock(xmlNodePtr node, gpointer d)
630 node = node->children;
632 if ((n = obt_xml_find_sibling(node, "position"))) {
633 if (obt_xml_node_contains(n, "TopLeft"))
634 config_dock_floating = FALSE,
635 config_dock_pos = OB_DIRECTION_NORTHWEST;
636 else if (obt_xml_node_contains(n, "Top"))
637 config_dock_floating = FALSE,
638 config_dock_pos = OB_DIRECTION_NORTH;
639 else if (obt_xml_node_contains(n, "TopRight"))
640 config_dock_floating = FALSE,
641 config_dock_pos = OB_DIRECTION_NORTHEAST;
642 else if (obt_xml_node_contains(n, "Right"))
643 config_dock_floating = FALSE,
644 config_dock_pos = OB_DIRECTION_EAST;
645 else if (obt_xml_node_contains(n, "BottomRight"))
646 config_dock_floating = FALSE,
647 config_dock_pos = OB_DIRECTION_SOUTHEAST;
648 else if (obt_xml_node_contains(n, "Bottom"))
649 config_dock_floating = FALSE,
650 config_dock_pos = OB_DIRECTION_SOUTH;
651 else if (obt_xml_node_contains(n, "BottomLeft"))
652 config_dock_floating = FALSE,
653 config_dock_pos = OB_DIRECTION_SOUTHWEST;
654 else if (obt_xml_node_contains(n, "Left"))
655 config_dock_floating = FALSE,
656 config_dock_pos = OB_DIRECTION_WEST;
657 else if (obt_xml_node_contains(n, "Floating"))
658 config_dock_floating = TRUE;
660 if (config_dock_floating) {
661 if ((n = obt_xml_find_sibling(node, "floatingX")))
662 config_dock_x = obt_xml_node_int(n);
663 if ((n = obt_xml_find_sibling(node, "floatingY")))
664 config_dock_y = obt_xml_node_int(n);
666 if ((n = obt_xml_find_sibling(node, "noStrut")))
667 config_dock_nostrut = obt_xml_node_bool(n);
669 if ((n = obt_xml_find_sibling(node, "stacking"))) {
670 if (obt_xml_node_contains(n, "normal"))
671 config_dock_layer = OB_STACKING_LAYER_NORMAL;
672 else if (obt_xml_node_contains(n, "below"))
673 config_dock_layer = OB_STACKING_LAYER_BELOW;
674 else if (obt_xml_node_contains(n, "above"))
675 config_dock_layer = OB_STACKING_LAYER_ABOVE;
677 if ((n = obt_xml_find_sibling(node, "direction"))) {
678 if (obt_xml_node_contains(n, "horizontal"))
679 config_dock_orient = OB_ORIENTATION_HORZ;
680 else if (obt_xml_node_contains(n, "vertical"))
681 config_dock_orient = OB_ORIENTATION_VERT;
683 if ((n = obt_xml_find_sibling(node, "autoHide")))
684 config_dock_hide = obt_xml_node_bool(n);
685 if ((n = obt_xml_find_sibling(node, "hideDelay")))
686 config_dock_hide_delay = obt_xml_node_int(n);
687 if ((n = obt_xml_find_sibling(node, "showDelay")))
688 config_dock_show_delay = obt_xml_node_int(n);
689 if ((n = obt_xml_find_sibling(node, "moveButton"))) {
690 gchar *str = obt_xml_node_string(n);
692 if (translate_button(str, &s, &b)) {
693 config_dock_app_move_button = b;
694 config_dock_app_move_modifiers = s;
696 g_message(_("Invalid button \"%s\" specified in config file"), str);
702 static void parse_menu(xmlNodePtr node, gpointer d)
705 node = node->children;
707 if ((n = obt_xml_find_sibling(node, "hideDelay")))
708 config_menu_hide_delay = obt_xml_node_int(n);
709 if ((n = obt_xml_find_sibling(node, "middle")))
710 config_menu_middle = obt_xml_node_bool(n);
711 if ((n = obt_xml_find_sibling(node, "submenuShowDelay")))
712 config_submenu_show_delay = obt_xml_node_int(n);
713 if ((n = obt_xml_find_sibling(node, "submenuHideDelay")))
714 config_submenu_hide_delay = obt_xml_node_int(n);
715 if ((n = obt_xml_find_sibling(node, "manageDesktops")))
716 config_menu_manage_desktops = obt_xml_node_bool(n);
717 if ((n = obt_xml_find_sibling(node, "showIcons"))) {
718 config_menu_show_icons = obt_xml_node_bool(n);
720 if (config_menu_show_icons)
721 g_message(_("Openbox was compiled without Imlib2 image loading support. Icons in menus will not be loaded."));
725 while ((node = obt_xml_find_sibling(node, "file"))) {
726 gchar *c = obt_xml_node_string(node);
727 config_menu_files = g_slist_append(config_menu_files,
728 obt_paths_expand_tilde(c));
734 static void parse_resistance(xmlNodePtr node, gpointer d)
738 node = node->children;
739 if ((n = obt_xml_find_sibling(node, "strength")))
740 config_resist_win = obt_xml_node_int(n);
741 if ((n = obt_xml_find_sibling(node, "screen_edge_strength")))
742 config_resist_edge = obt_xml_node_int(n);
748 const gchar *actiontext;
751 static void bind_default_keyboard(void)
754 ObDefKeyBind binds[] = {
755 { "A-Tab", "NextWindow" },
756 { "S-A-Tab", "PreviousWindow" },
762 p = action_parser_new();
763 for (it = binds; it->key; ++it) {
764 GList *l = g_list_append(NULL, g_strdup(it->key));
765 ObActionList *actions = action_parser_read_string(p, it->actiontext);
766 keyboard_bind(l, actions);
767 action_list_unref(actions);
769 action_parser_unref(p);
775 const gchar *context;
776 const ObMouseAction mact;
777 const gchar *actname;
780 static void bind_default_mouse(void)
783 ObDefMouseBind binds[] = {
784 { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
785 { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
786 { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
787 { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
788 { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
789 { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
790 { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
791 { "Left", "Bottom", OB_MOUSE_ACTION_PRESS, "Focus" },
792 { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
793 { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
794 { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
795 { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
796 { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
797 { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
798 { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
799 { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
800 { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
801 { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
802 { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
803 { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
804 { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
805 { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
806 { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
807 { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
808 { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
809 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
810 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
811 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
812 { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
813 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
814 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
815 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
816 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Maximize" },
817 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
818 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Omnipresent" },
819 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Shade" },
820 { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
821 { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
822 { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
823 { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
824 { "Left", "Top", OB_MOUSE_ACTION_MOTION, "Resize" },
825 { "Left", "Bottom", OB_MOUSE_ACTION_MOTION, "Resize" },
826 { "Left", "Left", OB_MOUSE_ACTION_MOTION, "Resize" },
827 { "Left", "Right", OB_MOUSE_ACTION_MOTION, "Resize" },
828 { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
829 { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
830 { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
831 { NULL, NULL, 0, NULL }
834 ObActionList *actions;
836 p = action_parser_new();
837 for (it = binds; it->button; ++it) {
838 actions = action_parser_read_string(p, it->actname);
839 mouse_bind(it->button, frame_context_from_string(it->context),
841 action_list_unref(actions);
843 action_parser_unref(p);
846 static ObtXmlInst *config_inst = NULL;
848 void config_startup()
852 void config_shutdown(void)
856 g_free(config_theme);
858 g_free(config_title_layout);
860 RrFontClose(config_font_activewindow);
861 RrFontClose(config_font_inactivewindow);
862 RrFontClose(config_font_menuitem);
863 RrFontClose(config_font_menutitle);
864 RrFontClose(config_font_activeosd);
865 RrFontClose(config_font_inactiveosd);
867 for (it = config_desktops_names; it; it = g_slist_next(it))
869 g_slist_free(config_desktops_names);
871 for (it = config_menu_files; it; it = g_slist_next(it))
873 g_slist_free(config_menu_files);
875 for (it = config_per_app_settings; it; it = g_slist_next(it)) {
876 ObAppSettings *itd = (ObAppSettings *)it->data;
877 if (itd->name) g_pattern_spec_free(itd->name);
878 if (itd->role) g_pattern_spec_free(itd->role);
879 if (itd->title) g_pattern_spec_free(itd->title);
880 if (itd->class) g_pattern_spec_free(itd->class);
881 g_slice_free(ObAppSettings, it->data);
883 g_slist_free(config_per_app_settings);
886 void config_load_config(void)
888 xmlNodePtr n, root, e;
892 config_inst = obt_xml_instance_new();
893 ok = obt_xml_load_cache_file(config_inst, "openbox", "config", "config");
894 root = obt_xml_root(config_inst);
897 n = obt_xml_path_get_node(root, "focus", "");
898 config_focus_new = obt_xml_path_bool(n, "focusNew", "yes");
899 config_focus_follow = obt_xml_path_bool(n, "followMouse", "no");
900 config_focus_delay = obt_xml_path_int(n, "focusDelay", "0");
901 config_focus_raise = obt_xml_path_bool(n, "raiseOnFocus", "no");
902 config_focus_last = obt_xml_path_bool(n, "focusLast", "yes");
903 config_focus_under_mouse = obt_xml_path_bool(n, "underMouse", "no");
904 config_unfocus_leave = obt_xml_path_bool(n, "unfocusOnLeave", "no");
907 n = obt_xml_path_get_node(root, "placement", "");
908 e = obt_xml_path_get_node(n, "policy", "smart");
909 if (obt_xml_node_contains(e, "smart"))
910 config_place_policy = OB_PLACE_POLICY_SMART;
911 else if (obt_xml_node_contains(e, "undermouse"))
912 config_place_policy = OB_PLACE_POLICY_MOUSE;
914 config_place_policy = OB_PLACE_POLICY_SMART;
915 config_place_center = obt_xml_path_bool(n, "center", "true");
916 e = obt_xml_path_get_node(n, "monitor", "primary");
917 if (obt_xml_node_contains(e, "primary"))
918 config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
919 else if (obt_xml_node_contains(e, "active"))
920 config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
921 else if (obt_xml_node_contains(e, "mouse"))
922 config_place_monitor = OB_PLACE_MONITOR_MOUSE;
923 else if (obt_xml_node_contains(e, "any"))
924 config_place_monitor = OB_PLACE_MONITOR_ANY;
926 config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
927 e = obt_xml_path_get_node(n, "primaryMonitor", "1");
928 if (obt_xml_node_contains(e, "active")) {
929 config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
930 config_primary_monitor_index = 1;
932 else if (obt_xml_node_contains(e, "mouse")) {
933 config_primary_monitor = OB_PLACE_MONITOR_MOUSE;
934 config_primary_monitor_index = 1;
937 config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
938 config_primary_monitor_index = obt_xml_node_int(e);
942 n = obt_xml_path_get_node(root, "margins", "");
943 STRUT_PARTIAL_SET(config_margins, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
944 config_margins.top = MAX(0, obt_xml_path_int(n, "top", "0"));
945 config_margins.left = MAX(0, obt_xml_path_int(n, "left", "0"));
946 config_margins.right = MAX(0, obt_xml_path_int(n, "right", "0"));
947 config_margins.bottom = MAX(0, obt_xml_path_int(n, "bottom", "0"));
950 n = obt_xml_path_get_node(root, "theme", "");
951 g_free(config_theme);
952 c = obt_xml_path_string(n, "name", NULL);
953 config_theme = obt_paths_expand_tilde(c);
956 g_free(config_title_layout);
957 config_title_layout = obt_xml_path_string(n, "titleLayout", "NLIMC");
958 /* replace duplicates with spaces */
959 for (c = config_title_layout; *c != '\0'; ++c)
960 for (d = c+1; *d != '\0'; ++d)
961 if (*c == *d) *d = ' ';
963 config_animate_iconify = obt_xml_path_bool(n, "animateIconify", "true");
964 config_theme_keepborder = obt_xml_path_bool(n, "keepBorder", "true");
965 config_theme_window_list_icon_size =
966 MAX(16, MIN(96, obt_xml_path_int(n, "windowListIconSize", 36)));
968 RrFontClose(config_font_activewindow);
969 config_font_activewindow = read_font(n, "font:place=ActiveWindow");
970 RrFontClose(config_font_inactivewindow);
971 config_font_inactivewindow = read_font(n, "font:place=InactiveWindow");
972 RrFontClose(config_font_menuitem);
973 config_font_menuitem = read_font(n, "font:place=MenuItem");
974 RrFontClose(config_font_menutitle);
975 config_font_menutitle = read_font(n, "font:place=MenuHeader");
976 RrFontClose(config_font_activeosd);
977 config_font_activeosd = read_font(n, "font:place=ActiveOnScreenDisplay");
978 RrFontClose(config_font_inactiveosd);
979 config_font_inactiveosd = read_font(n, "font:place=InactiveOnScreenDisplay");
981 obt_xml_register(config_inst, "theme", parse_theme, NULL);
982 static void parse_theme(xmlNodePtr node, gpointer d)
985 n = obt_xml_find_sibling(node, "font");
989 gchar *name = g_strdup(RrDefaultFontFamily);
990 gint size = RrDefaultFontSize;
991 RrFontWeight weight = RrDefaultFontWeight;
992 RrFontSlant slant = RrDefaultFontSlant;
994 if (obt_xml_attr_contains(n, "place", "ActiveWindow"))
995 font = &config_font_activewindow;
996 else if (obt_xml_attr_contains(n, "place", "InactiveWindow"))
997 font = &config_font_inactivewindow;
998 else if (obt_xml_attr_contains(n, "place", "MenuHeader"))
999 font = &config_font_menutitle;
1000 else if (obt_xml_attr_contains(n, "place", "MenuItem"))
1001 font = &config_font_menuitem;
1002 else if (obt_xml_attr_contains(n, "place", "ActiveOnScreenDisplay"))
1003 font = &config_font_activeosd;
1004 else if (obt_xml_attr_contains(n, "place", "OnScreenDisplay"))
1005 font = &config_font_activeosd;
1006 else if (obt_xml_attr_contains(n, "place","InactiveOnScreenDisplay"))
1007 font = &config_font_inactiveosd;
1011 if ((fnode = obt_xml_find_sibling(n->children, "name"))) {
1013 name = obt_xml_node_string(fnode);
1015 if ((fnode = obt_xml_find_sibling(n->children, "size"))) {
1016 int s = obt_xml_node_int(fnode);
1017 if (s > 0) size = s;
1019 if ((fnode = obt_xml_find_sibling(n->children, "weight"))) {
1020 gchar *w = obt_xml_node_string(fnode);
1021 if (!g_ascii_strcasecmp(w, "Bold"))
1022 weight = RR_FONTWEIGHT_BOLD;
1025 if ((fnode = obt_xml_find_sibling(n->children, "slant"))) {
1026 gchar *s = obt_xml_node_string(fnode);
1027 if (!g_ascii_strcasecmp(s, "Italic"))
1028 slant = RR_FONTSLANT_ITALIC;
1029 if (!g_ascii_strcasecmp(s, "Oblique"))
1030 slant = RR_FONTSLANT_OBLIQUE;
1034 *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
1037 n = obt_xml_find_sibling(n->next, "font");
1041 config_desktops_num = 4;
1042 config_screen_firstdesk = 1;
1043 config_desktops_names = NULL;
1044 config_desktop_popup_time = 875;
1046 obt_xml_register(config_inst, "desktops", parse_desktops, NULL);
1048 config_resize_redraw = TRUE;
1049 config_resize_popup_show = 1; /* nonpixel increments */
1050 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
1051 GRAVITY_COORD_SET(config_resize_popup_fixed.x, 0, FALSE, FALSE);
1052 GRAVITY_COORD_SET(config_resize_popup_fixed.y, 0, FALSE, FALSE);
1054 obt_xml_register(config_inst, "resize", parse_resize, NULL);
1056 config_dock_layer = OB_STACKING_LAYER_ABOVE;
1057 config_dock_pos = OB_DIRECTION_NORTHEAST;
1058 config_dock_floating = FALSE;
1059 config_dock_nostrut = FALSE;
1062 config_dock_orient = OB_ORIENTATION_VERT;
1063 config_dock_hide = FALSE;
1064 config_dock_hide_delay = 300;
1065 config_dock_show_delay = 300;
1066 config_dock_app_move_button = 2; /* middle */
1067 config_dock_app_move_modifiers = 0;
1069 obt_xml_register(config_inst, "dock", parse_dock, NULL);
1071 translate_key("C-g", &config_keyboard_reset_state,
1072 &config_keyboard_reset_keycode);
1074 obt_xml_register(config_inst, "keyboard", parse_keyboard, NULL);
1076 config_mouse_threshold = 8;
1077 config_mouse_dclicktime = 200;
1078 config_mouse_screenedgetime = 400;
1079 config_mouse_screenedgewarp = FALSE;
1081 obt_xml_register(config_inst, "mouse", parse_mouse, NULL);
1083 config_resist_win = 10;
1084 config_resist_edge = 20;
1086 obt_xml_register(config_inst, "resistance", parse_resistance, NULL);
1088 config_menu_hide_delay = 250;
1089 config_menu_middle = FALSE;
1090 config_submenu_show_delay = 100;
1091 config_submenu_hide_delay = 400;
1092 config_menu_manage_desktops = TRUE;
1093 config_menu_files = NULL;
1094 config_menu_show_icons = TRUE;
1096 obt_xml_register(config_inst, "menu", parse_menu, NULL);
1100 obt_xml_tree_from_root(config_inst);
1101 obt_xml_close(config_inst);
1105 void config_save_config(void)
1110 root = obt_xml_root(config_inst);
1112 n = obt_xml_path_get_node(root, "focus", "");
1113 obt_xml_path_set_bool(n, "focusNew", config_focus_new);
1114 obt_xml_path_set_bool(n, "followMouse", config_focus_follow);
1115 obt_xml_path_set_int(n, "focusDelay", config_focus_delay);
1116 obt_xml_path_set_bool(n, "raiseOnFocus", config_focus_raise);
1117 obt_xml_path_set_bool(n, "focusLast", config_focus_last);
1118 obt_xml_path_set_bool(n, "underMouse", config_focus_under_mouse);
1119 obt_xml_path_set_bool(n, "unfocusOnLeave", config_unfocus_leave);
1121 n = obt_xml_path_get_node(root, "placement", "");
1122 switch (config_place_policy) {
1123 case OB_PLACE_POLICY_SMART: e = "smart"; break;
1124 case OB_PLACE_POLICY_MOUSE: e = "mouse"; break;
1126 obt_xml_path_set_string(n, "policy", e);
1127 obt_xml_path_set_bool(n, "center", config_place_center);
1128 switch (config_place_monitor) {
1129 case OB_PLACE_MONITOR_PRIMARY: e = "primary"; break;
1130 case OB_PLACE_MONITOR_ACTIVE: e = "active"; break;
1131 case OB_PLACE_MONITOR_MOUSE: e = "mouse"; break;
1132 case OB_PLACE_MONITOR_ANY: e = "any"; break;
1134 obt_xml_path_set_string(n, "monitor", e);
1135 if (config_primary_monitor_index)
1136 obt_xml_path_set_int(
1137 n, "primaryMonitor", config_primary_monitor_index);
1139 switch (config_primary_monitor) {
1140 case OB_PLACE_MONITOR_ACTIVE: e = "active"; break;
1141 case OB_PLACE_MONITOR_MOUSE: e = "mouse"; break;
1142 case OB_PLACE_MONITOR_PRIMARY:
1143 case OB_PLACE_MONITOR_ANY: g_assert_not_reached();
1145 obt_xml_path_set_string(n, "primaryMonitor", e);
1148 n = obt_xml_path_get_node(root, "margins", "");
1149 obt_xml_path_set_int(n, "top", config_margins.top);
1150 obt_xml_path_set_int(n, "left", config_margins.left);
1151 obt_xml_path_set_int(n, "right", config_margins.right);
1152 obt_xml_path_set_int(n, "bottom", config_margins.bottom);
1154 if (!obt_xml_save_cache_file(config_inst, "openbox", "config", TRUE))
1155 g_warning("Unable to save configuration in XDG cache directory.");
1156 obt_xml_instance_unref(config_inst);
1160 gboolean config_load_keys(void)
1162 ObtXmlInst *i = obt_xml_instance_new();
1165 ok = obt_xml_load_config_file(i, "openbox", "keys", "keys");
1167 bind_default_keyboard();
1171 r = obt_xml_root(i);
1172 if ((n = obt_xml_find_sibling(r->children, "keybind")))
1174 parse_keybind(n, NULL);
1175 n = obt_xml_find_sibling(n->next, "keybind");
1178 obt_xml_instance_unref(i);
1182 gboolean config_load_mouse(void)
1184 ObtXmlInst *i = obt_xml_instance_new();
1187 obt_xml_register(i, "context", parse_context, NULL);
1189 ok = obt_xml_load_config_file(i, "openbox", "mouse", "mouse");
1191 bind_default_mouse();
1193 obt_xml_tree_from_root(i);
1196 obt_xml_instance_unref(i);
1200 gboolean config_load_windows(void)
1202 ObtXmlInst *i = obt_xml_instance_new();
1205 config_per_app_settings = NULL;
1206 obt_xml_register(i, "applications", parse_per_app_settings, NULL);
1208 ok = obt_xml_load_config_file(
1209 i, "openbox", "applications", "applications");
1211 obt_xml_tree_from_root(i);
1214 obt_xml_instance_unref(i);