Allow specifying only one of width and height in per-app settings size
[openbox.git] / openbox / config.c
blob8e1bcf899c0ea24c89e244e2f366d469a49ed007
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.
20 #include "config.h"
21 #include "keyboard.h"
22 #include "mouse.h"
23 #include "actions.h"
24 #include "translate.h"
25 #include "client.h"
26 #include "screen.h"
27 #include "openbox.h"
28 #include "gettext.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 ObPlaceMonitor config_place_monitor;
42 guint config_primary_monitor_index;
43 ObPlaceMonitor config_primary_monitor;
45 StrutPartial config_margins;
47 gchar *config_theme;
48 gboolean config_theme_keepborder;
49 guint config_theme_window_list_icon_size;
51 gchar *config_title_layout;
53 gboolean config_animate_iconify;
55 RrFont *config_font_activewindow;
56 RrFont *config_font_inactivewindow;
57 RrFont *config_font_menuitem;
58 RrFont *config_font_menutitle;
59 RrFont *config_font_activeosd;
60 RrFont *config_font_inactiveosd;
62 guint config_desktops_num;
63 GSList *config_desktops_names;
64 guint config_screen_firstdesk;
65 guint config_desktop_popup_time;
67 gboolean config_resize_redraw;
68 gint config_resize_popup_show;
69 ObResizePopupPos config_resize_popup_pos;
70 GravityPoint config_resize_popup_fixed;
72 ObStackingLayer config_dock_layer;
73 gboolean config_dock_floating;
74 gboolean config_dock_nostrut;
75 ObDirection config_dock_pos;
76 gint config_dock_x;
77 gint config_dock_y;
78 ObOrientation config_dock_orient;
79 gboolean config_dock_hide;
80 guint config_dock_hide_delay;
81 guint config_dock_show_delay;
82 guint config_dock_app_move_button;
83 guint config_dock_app_move_modifiers;
85 guint config_keyboard_reset_keycode;
86 guint config_keyboard_reset_state;
88 gint config_mouse_threshold;
89 gint config_mouse_dclicktime;
90 gint config_mouse_screenedgetime;
91 gboolean config_mouse_screenedgewarp;
93 guint config_menu_hide_delay;
94 gboolean config_menu_middle;
95 guint config_submenu_show_delay;
96 guint config_submenu_hide_delay;
97 gboolean config_menu_manage_desktops;
98 gboolean config_menu_show_icons;
100 GSList *config_menu_files;
102 gint config_resist_win;
103 gint config_resist_edge;
105 GSList *config_per_app_settings;
107 ObAppSettings* config_create_app_settings(void)
109 ObAppSettings *settings = g_slice_new0(ObAppSettings);
110 settings->type = -1;
111 settings->decor = -1;
112 settings->shade = -1;
113 settings->monitor_type = OB_PLACE_MONITOR_ANY;
114 settings->monitor = -1;
115 settings->focus = -1;
116 settings->desktop = 0;
117 settings->layer = -2;
118 settings->iconic = -1;
119 settings->skip_pager = -1;
120 settings->skip_taskbar = -1;
121 settings->fullscreen = -1;
122 settings->max_horz = -1;
123 settings->max_vert = -1;
124 return settings;
127 #define copy_if(setting, default) \
128 if (src->setting != default) dst->setting = src->setting
129 void config_app_settings_copy_non_defaults(const ObAppSettings *src,
130 ObAppSettings *dst)
132 g_assert(src != NULL);
133 g_assert(dst != NULL);
135 copy_if(type, (ObClientType)-1);
136 copy_if(decor, -1);
137 copy_if(shade, -1);
138 copy_if(monitor_type, OB_PLACE_MONITOR_ANY);
139 copy_if(monitor, -1);
140 copy_if(focus, -1);
141 copy_if(desktop, 0);
142 copy_if(layer, -2);
143 copy_if(iconic, -1);
144 copy_if(skip_pager, -1);
145 copy_if(skip_taskbar, -1);
146 copy_if(fullscreen, -1);
147 copy_if(max_horz, -1);
148 copy_if(max_vert, -1);
150 if (src->pos_given) {
151 dst->pos_given = TRUE;
152 dst->pos_force = src->pos_force;
153 dst->position = src->position;
154 /* monitor is copied above */
157 dst->width_num = src->width_num;
158 dst->width_denom = src->width_denom;
159 dst->height_num = src->height_num;
160 dst->height_denom = src->height_denom;
163 void config_parse_relative_number(gchar *s, gint *num, gint *denom)
165 *num = strtol(s, &s, 10);
167 if (*s == '%') {
168 *denom = 100;
169 } else if (*s == '/') {
170 *denom = atoi(s+1);
174 void config_parse_gravity_coord(xmlNodePtr node, GravityCoord *c)
176 gchar *s = obt_xml_node_string(node);
177 if (!g_ascii_strcasecmp(s, "center"))
178 c->center = TRUE;
179 else {
180 gchar *ps = s;
181 if (s[0] == '-')
182 c->opposite = TRUE;
183 if (s[0] == '-' || s[0] == '+')
184 ps++;
185 config_parse_relative_number(ps, &c->pos, &c->denom);
187 g_free(s);
191 <applications>
192 <application name="aterm">
193 <decor>false</decor>
194 </application>
195 <application name="Rhythmbox">
196 <layer>above</layer>
197 <position>
198 <x>700</x>
199 <y>0</y>
200 <monitor>1</monitor>
201 </position>
202 .. there is a lot more settings available
203 </application>
204 </applications>
207 static void parse_single_per_app_settings(xmlNodePtr app,
208 ObAppSettings *settings)
210 xmlNodePtr n, c;
211 gboolean x_pos_given = FALSE;
213 if ((n = obt_xml_find_node(app->children, "decor")))
214 if (!obt_xml_node_contains(n, "default"))
215 settings->decor = obt_xml_node_bool(n);
217 if ((n = obt_xml_find_node(app->children, "shade")))
218 if (!obt_xml_node_contains(n, "default"))
219 settings->shade = obt_xml_node_bool(n);
221 if ((n = obt_xml_find_node(app->children, "position"))) {
222 if ((c = obt_xml_find_node(n->children, "x"))) {
223 if (!obt_xml_node_contains(c, "default")) {
224 config_parse_gravity_coord(c, &settings->position.x);
225 x_pos_given = TRUE;
229 if (x_pos_given && (c = obt_xml_find_node(n->children, "y"))) {
230 if (!obt_xml_node_contains(c, "default")) {
231 config_parse_gravity_coord(c, &settings->position.y);
232 settings->pos_given = TRUE;
236 /* monitor can be set without setting x or y */
237 if ((c = obt_xml_find_node(n->children, "monitor"))) {
238 if (!obt_xml_node_contains(c, "default")) {
239 gchar *s = obt_xml_node_string(c);
240 if (!g_ascii_strcasecmp(s, "mouse"))
241 settings->monitor_type = OB_PLACE_MONITOR_MOUSE;
242 else if (!g_ascii_strcasecmp(s, "active"))
243 settings->monitor_type = OB_PLACE_MONITOR_ACTIVE;
244 else if (!g_ascii_strcasecmp(s, "primary"))
245 settings->monitor_type = OB_PLACE_MONITOR_PRIMARY;
246 else
247 settings->monitor = obt_xml_node_int(c);
248 g_free(s);
252 obt_xml_attr_bool(n, "force", &settings->pos_force);
255 if ((n = obt_xml_find_node(app->children, "size"))) {
256 if ((c = obt_xml_find_node(n->children, "width"))) {
257 if (!obt_xml_node_contains(c, "default")) {
258 gchar *s = obt_xml_node_string(c);
259 config_parse_relative_number(s,
260 &settings->width_num,
261 &settings->width_denom);
262 if (settings->width_num <= 0 || settings->width_denom < 0)
263 settings->width_num = settings->width_denom = 0;
264 g_free(s);
268 if ((c = obt_xml_find_node(n->children, "height"))) {
269 if (!obt_xml_node_contains(c, "default")) {
270 gchar *s = obt_xml_node_string(c);
271 config_parse_relative_number(s,
272 &settings->height_num,
273 &settings->height_denom);
274 if (settings->height_num <= 0 || settings->height_denom < 0)
275 settings->height_num = settings->height_denom = 0;
276 g_free(s);
281 if ((n = obt_xml_find_node(app->children, "focus"))) {
282 if (!obt_xml_node_contains(n, "default"))
283 settings->focus = obt_xml_node_bool(n);
286 if ((n = obt_xml_find_node(app->children, "desktop"))) {
287 if (!obt_xml_node_contains(n, "default")) {
288 gchar *s = obt_xml_node_string(n);
289 if (!g_ascii_strcasecmp(s, "all"))
290 settings->desktop = DESKTOP_ALL;
291 else {
292 gint i = obt_xml_node_int(n);
293 if (i > 0)
294 settings->desktop = i;
296 g_free(s);
300 if ((n = obt_xml_find_node(app->children, "layer"))) {
301 if (!obt_xml_node_contains(n, "default")) {
302 gchar *s = obt_xml_node_string(n);
303 if (!g_ascii_strcasecmp(s, "above"))
304 settings->layer = 1;
305 else if (!g_ascii_strcasecmp(s, "below"))
306 settings->layer = -1;
307 else
308 settings->layer = 0;
309 g_free(s);
313 if ((n = obt_xml_find_node(app->children, "iconic")))
314 if (!obt_xml_node_contains(n, "default"))
315 settings->iconic = obt_xml_node_bool(n);
317 if ((n = obt_xml_find_node(app->children, "skip_pager")))
318 if (!obt_xml_node_contains(n, "default"))
319 settings->skip_pager = obt_xml_node_bool(n);
321 if ((n = obt_xml_find_node(app->children, "skip_taskbar")))
322 if (!obt_xml_node_contains(n, "default"))
323 settings->skip_taskbar = obt_xml_node_bool(n);
325 if ((n = obt_xml_find_node(app->children, "fullscreen")))
326 if (!obt_xml_node_contains(n, "default"))
327 settings->fullscreen = obt_xml_node_bool(n);
329 if ((n = obt_xml_find_node(app->children, "maximized"))) {
330 if (!obt_xml_node_contains(n, "default")) {
331 gchar *s = obt_xml_node_string(n);
332 if (!g_ascii_strcasecmp(s, "horizontal")) {
333 settings->max_horz = TRUE;
334 settings->max_vert = FALSE;
335 } else if (!g_ascii_strcasecmp(s, "vertical")) {
336 settings->max_horz = FALSE;
337 settings->max_vert = TRUE;
338 } else
339 settings->max_horz = settings->max_vert =
340 obt_xml_node_bool(n);
341 g_free(s);
346 /* Manages settings for individual applications.
347 Some notes: monitor is the screen number in a multi monitor
348 (Xinerama) setup (starting from 0), or mouse: the monitor the pointer
349 is on, active: the active monitor, primary: the primary monitor.
350 Layer can be three values, above (Always on top), below
351 (Always on bottom) and everything else (normal behaviour).
352 Positions can be an integer value or center, which will
353 center the window in the specified axis. Position is within
354 the monitor, so <position><x>center</x></position><monitor>2</monitor>
355 will center the window on the second monitor.
357 static void parse_per_app_settings(xmlNodePtr node, gpointer d)
359 xmlNodePtr app = obt_xml_find_node(node->children, "application");
360 for (; app; app = obt_xml_find_node(app->next, "application")) {
361 ObAppSettings *settings;
363 gboolean name_set, class_set, role_set, title_set,
364 type_set, group_name_set, group_class_set;
365 gchar *name = NULL, *class = NULL, *role = NULL, *title = NULL,
366 *type_str = NULL, *group_name = NULL, *group_class = NULL;
367 ObClientType type;
369 class_set = obt_xml_attr_string(app, "class", &class);
370 name_set = obt_xml_attr_string(app, "name", &name);
371 group_class_set = obt_xml_attr_string(app, "groupclass", &group_class);
372 group_name_set = obt_xml_attr_string(app, "groupname", &group_name);
373 type_set = obt_xml_attr_string(app, "type", &type_str);
374 role_set = obt_xml_attr_string(app, "role", &role);
375 title_set = obt_xml_attr_string(app, "title", &title);
377 /* validate the type tho */
378 if (type_set) {
379 if (!g_ascii_strcasecmp(type_str, "normal"))
380 type = OB_CLIENT_TYPE_NORMAL;
381 else if (!g_ascii_strcasecmp(type_str, "dialog"))
382 type = OB_CLIENT_TYPE_DIALOG;
383 else if (!g_ascii_strcasecmp(type_str, "splash"))
384 type = OB_CLIENT_TYPE_SPLASH;
385 else if (!g_ascii_strcasecmp(type_str, "utility"))
386 type = OB_CLIENT_TYPE_UTILITY;
387 else if (!g_ascii_strcasecmp(type_str, "menu"))
388 type = OB_CLIENT_TYPE_MENU;
389 else if (!g_ascii_strcasecmp(type_str, "toolbar"))
390 type = OB_CLIENT_TYPE_TOOLBAR;
391 else if (!g_ascii_strcasecmp(type_str, "dock"))
392 type = OB_CLIENT_TYPE_DOCK;
393 else if (!g_ascii_strcasecmp(type_str, "desktop"))
394 type = OB_CLIENT_TYPE_DESKTOP;
395 else
396 type_set = FALSE; /* not valid! */
399 if (!(class_set || name_set || role_set || title_set ||
400 type_set || group_class_set || group_name_set))
401 continue;
403 settings = config_create_app_settings();
405 if (name_set)
406 settings->name = g_pattern_spec_new(name);
407 if (class_set)
408 settings->class = g_pattern_spec_new(class);
409 if (group_name_set)
410 settings->group_name = g_pattern_spec_new(group_name);
411 if (group_class_set)
412 settings->group_class = g_pattern_spec_new(group_class);
413 if (role_set)
414 settings->role = g_pattern_spec_new(role);
415 if (title_set)
416 settings->title = g_pattern_spec_new(title);
417 if (type_set)
418 settings->type = type;
420 g_free(name);
421 g_free(class);
422 g_free(group_name);
423 g_free(group_class);
424 g_free(role);
425 g_free(title);
426 g_free(type_str);
428 parse_single_per_app_settings(app, settings);
429 config_per_app_settings = g_slist_append(config_per_app_settings,
430 (gpointer)settings);
436 <keybind key="C-x">
437 <action name="ChangeDesktop">
438 <desktop>3</desktop>
439 </action>
440 </keybind>
444 static void parse_key(xmlNodePtr node, GList *keylist)
446 gchar *keystring, **keys, **key;
447 xmlNodePtr n;
448 gboolean is_chroot = FALSE;
450 if (!obt_xml_attr_string(node, "key", &keystring))
451 return;
453 obt_xml_attr_bool(node, "chroot", &is_chroot);
455 keys = g_strsplit(keystring, " ", 0);
456 for (key = keys; *key; ++key) {
457 keylist = g_list_append(keylist, *key);
459 if ((n = obt_xml_find_node(node->children, "keybind"))) {
460 while (n) {
461 parse_key(n, keylist);
462 n = obt_xml_find_node(n->next, "keybind");
465 else if ((n = obt_xml_find_node(node->children, "action"))) {
466 while (n) {
467 ObActionsAct *action;
469 action = actions_parse(n);
470 if (action)
471 keyboard_bind(keylist, action);
472 n = obt_xml_find_node(n->next, "action");
477 if (is_chroot)
478 keyboard_chroot(keylist);
479 keylist = g_list_delete_link(keylist, g_list_last(keylist));
482 g_strfreev(keys);
483 g_free(keystring);
486 static void parse_keyboard(xmlNodePtr node, gpointer d)
488 xmlNodePtr n;
489 gchar *key;
491 keyboard_unbind_all();
493 if ((n = obt_xml_find_node(node->children, "chainQuitKey"))) {
494 key = obt_xml_node_string(n);
495 translate_key(key, &config_keyboard_reset_state,
496 &config_keyboard_reset_keycode);
497 g_free(key);
500 if ((n = obt_xml_find_node(node->children, "keybind")))
501 while (n) {
502 parse_key(n, NULL);
503 n = obt_xml_find_node(n->next, "keybind");
509 <context name="Titlebar">
510 <mousebind button="Left" action="Press">
511 <action name="Raise"></action>
512 </mousebind>
513 </context>
517 static void parse_mouse(xmlNodePtr node, gpointer d)
519 xmlNodePtr n, nbut, nact;
520 gchar *buttonstr;
521 gchar *cxstr;
522 ObMouseAction mact;
524 mouse_unbind_all();
526 node = node->children;
528 if ((n = obt_xml_find_node(node, "dragThreshold")))
529 config_mouse_threshold = obt_xml_node_int(n);
530 if ((n = obt_xml_find_node(node, "doubleClickTime")))
531 config_mouse_dclicktime = obt_xml_node_int(n);
532 if ((n = obt_xml_find_node(node, "screenEdgeWarpTime"))) {
533 config_mouse_screenedgetime = obt_xml_node_int(n);
534 /* minimum value of 25 for this property, when it is 1 and you hit the
535 edge it basically never stops */
536 if (config_mouse_screenedgetime && config_mouse_screenedgetime < 25)
537 config_mouse_screenedgetime = 25;
539 if ((n = obt_xml_find_node(node, "screenEdgeWarpMouse")))
540 config_mouse_screenedgewarp = obt_xml_node_bool(n);
542 n = obt_xml_find_node(node, "context");
543 while (n) {
544 gchar *modcxstr;
545 ObFrameContext cx;
547 if (!obt_xml_attr_string(n, "name", &cxstr))
548 goto next_n;
550 modcxstr = g_strdup(cxstr); /* make a copy to mutilate */
551 while (frame_next_context_from_string(modcxstr, &cx)) {
552 if (!cx) {
553 gchar *s = strchr(modcxstr, ' ');
554 if (s) {
555 *s = '\0';
556 g_message(_("Invalid context \"%s\" in mouse binding"),
557 modcxstr);
558 *s = ' ';
560 continue;
563 nbut = obt_xml_find_node(n->children, "mousebind");
564 while (nbut) {
565 if (!obt_xml_attr_string(nbut, "button", &buttonstr))
566 goto next_nbut;
567 if (obt_xml_attr_contains(nbut, "action", "press"))
568 mact = OB_MOUSE_ACTION_PRESS;
569 else if (obt_xml_attr_contains(nbut, "action", "release"))
570 mact = OB_MOUSE_ACTION_RELEASE;
571 else if (obt_xml_attr_contains(nbut, "action", "click"))
572 mact = OB_MOUSE_ACTION_CLICK;
573 else if (obt_xml_attr_contains(nbut, "action","doubleclick"))
574 mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
575 else if (obt_xml_attr_contains(nbut, "action", "drag"))
576 mact = OB_MOUSE_ACTION_MOTION;
577 else
578 goto next_nbut;
580 nact = obt_xml_find_node(nbut->children, "action");
581 while (nact) {
582 ObActionsAct *action;
584 if ((action = actions_parse(nact)))
585 mouse_bind(buttonstr, cx, mact, action);
586 nact = obt_xml_find_node(nact->next, "action");
588 g_free(buttonstr);
589 next_nbut:
590 nbut = obt_xml_find_node(nbut->next, "mousebind");
593 g_free(modcxstr);
594 g_free(cxstr);
595 next_n:
596 n = obt_xml_find_node(n->next, "context");
600 static void parse_focus(xmlNodePtr node, gpointer d)
602 xmlNodePtr n;
604 node = node->children;
606 if ((n = obt_xml_find_node(node, "focusNew")))
607 config_focus_new = obt_xml_node_bool(n);
608 if ((n = obt_xml_find_node(node, "followMouse")))
609 config_focus_follow = obt_xml_node_bool(n);
610 if ((n = obt_xml_find_node(node, "focusDelay")))
611 config_focus_delay = obt_xml_node_int(n);
612 if ((n = obt_xml_find_node(node, "raiseOnFocus")))
613 config_focus_raise = obt_xml_node_bool(n);
614 if ((n = obt_xml_find_node(node, "focusLast")))
615 config_focus_last = obt_xml_node_bool(n);
616 if ((n = obt_xml_find_node(node, "underMouse")))
617 config_focus_under_mouse = obt_xml_node_bool(n);
618 if ((n = obt_xml_find_node(node, "unfocusOnLeave")))
619 config_unfocus_leave = obt_xml_node_bool(n);
622 static void parse_placement(xmlNodePtr node, gpointer d)
624 xmlNodePtr n;
626 node = node->children;
628 if ((n = obt_xml_find_node(node, "policy")))
629 if (obt_xml_node_contains(n, "UnderMouse"))
630 config_place_policy = OB_PLACE_POLICY_MOUSE;
631 if ((n = obt_xml_find_node(node, "monitor"))) {
632 if (obt_xml_node_contains(n, "active"))
633 config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
634 else if (obt_xml_node_contains(n, "mouse"))
635 config_place_monitor = OB_PLACE_MONITOR_MOUSE;
636 else if (obt_xml_node_contains(n, "any"))
637 config_place_monitor = OB_PLACE_MONITOR_ANY;
639 if ((n = obt_xml_find_node(node, "primaryMonitor"))) {
640 config_primary_monitor_index = obt_xml_node_int(n);
641 if (!config_primary_monitor_index) {
642 if (obt_xml_node_contains(n, "mouse"))
643 config_primary_monitor = OB_PLACE_MONITOR_MOUSE;
648 static void parse_margins(xmlNodePtr node, gpointer d)
650 xmlNodePtr n;
652 node = node->children;
654 if ((n = obt_xml_find_node(node, "top")))
655 config_margins.top = MAX(0, obt_xml_node_int(n));
656 if ((n = obt_xml_find_node(node, "left")))
657 config_margins.left = MAX(0, obt_xml_node_int(n));
658 if ((n = obt_xml_find_node(node, "right")))
659 config_margins.right = MAX(0, obt_xml_node_int(n));
660 if ((n = obt_xml_find_node(node, "bottom")))
661 config_margins.bottom = MAX(0, obt_xml_node_int(n));
664 static void parse_theme(xmlNodePtr node, gpointer d)
666 xmlNodePtr n;
668 node = node->children;
670 if ((n = obt_xml_find_node(node, "name"))) {
671 gchar *c;
673 g_free(config_theme);
674 c = obt_xml_node_string(n);
675 config_theme = obt_paths_expand_tilde(c);
676 g_free(c);
678 if ((n = obt_xml_find_node(node, "titleLayout"))) {
679 gchar *c, *d;
681 g_free(config_title_layout);
682 config_title_layout = obt_xml_node_string(n);
684 /* replace duplicates with spaces */
685 for (c = config_title_layout; *c != '\0'; ++c)
686 for (d = c+1; *d != '\0'; ++d)
687 if (*c == *d) *d = ' ';
689 if ((n = obt_xml_find_node(node, "keepBorder")))
690 config_theme_keepborder = obt_xml_node_bool(n);
691 if ((n = obt_xml_find_node(node, "animateIconify")))
692 config_animate_iconify = obt_xml_node_bool(n);
693 if ((n = obt_xml_find_node(node, "windowListIconSize"))) {
694 config_theme_window_list_icon_size = obt_xml_node_int(n);
695 if (config_theme_window_list_icon_size < 16)
696 config_theme_window_list_icon_size = 16;
697 else if (config_theme_window_list_icon_size > 96)
698 config_theme_window_list_icon_size = 96;
701 n = obt_xml_find_node(node, "font");
702 while (n) {
703 xmlNodePtr fnode;
704 RrFont **font;
705 gchar *name = g_strdup(RrDefaultFontFamily);
706 gint size = RrDefaultFontSize;
707 RrFontWeight weight = RrDefaultFontWeight;
708 RrFontSlant slant = RrDefaultFontSlant;
710 if (obt_xml_attr_contains(n, "place", "ActiveWindow"))
711 font = &config_font_activewindow;
712 else if (obt_xml_attr_contains(n, "place", "InactiveWindow"))
713 font = &config_font_inactivewindow;
714 else if (obt_xml_attr_contains(n, "place", "MenuHeader"))
715 font = &config_font_menutitle;
716 else if (obt_xml_attr_contains(n, "place", "MenuItem"))
717 font = &config_font_menuitem;
718 else if (obt_xml_attr_contains(n, "place", "ActiveOnScreenDisplay"))
719 font = &config_font_activeosd;
720 else if (obt_xml_attr_contains(n, "place", "OnScreenDisplay"))
721 font = &config_font_activeosd;
722 else if (obt_xml_attr_contains(n, "place","InactiveOnScreenDisplay"))
723 font = &config_font_inactiveosd;
724 else
725 goto next_font;
727 if ((fnode = obt_xml_find_node(n->children, "name"))) {
728 g_free(name);
729 name = obt_xml_node_string(fnode);
731 if ((fnode = obt_xml_find_node(n->children, "size"))) {
732 int s = obt_xml_node_int(fnode);
733 if (s > 0) size = s;
735 if ((fnode = obt_xml_find_node(n->children, "weight"))) {
736 gchar *w = obt_xml_node_string(fnode);
737 if (!g_ascii_strcasecmp(w, "Bold"))
738 weight = RR_FONTWEIGHT_BOLD;
739 g_free(w);
741 if ((fnode = obt_xml_find_node(n->children, "slant"))) {
742 gchar *s = obt_xml_node_string(fnode);
743 if (!g_ascii_strcasecmp(s, "Italic"))
744 slant = RR_FONTSLANT_ITALIC;
745 if (!g_ascii_strcasecmp(s, "Oblique"))
746 slant = RR_FONTSLANT_OBLIQUE;
747 g_free(s);
750 *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
751 g_free(name);
752 next_font:
753 n = obt_xml_find_node(n->next, "font");
757 static void parse_desktops(xmlNodePtr node, gpointer d)
759 xmlNodePtr n;
761 node = node->children;
763 if ((n = obt_xml_find_node(node, "number"))) {
764 gint d = obt_xml_node_int(n);
765 if (d > 0)
766 config_desktops_num = (unsigned) d;
768 if ((n = obt_xml_find_node(node, "firstdesk"))) {
769 gint d = obt_xml_node_int(n);
770 if (d > 0)
771 config_screen_firstdesk = (unsigned) d;
773 if ((n = obt_xml_find_node(node, "names"))) {
774 GSList *it;
775 xmlNodePtr nname;
777 for (it = config_desktops_names; it; it = it->next)
778 g_free(it->data);
779 g_slist_free(config_desktops_names);
780 config_desktops_names = NULL;
782 nname = obt_xml_find_node(n->children, "name");
783 while (nname) {
784 config_desktops_names =
785 g_slist_append(config_desktops_names,
786 obt_xml_node_string(nname));
787 nname = obt_xml_find_node(nname->next, "name");
790 if ((n = obt_xml_find_node(node, "popupTime")))
791 config_desktop_popup_time = obt_xml_node_int(n);
794 static void parse_resize(xmlNodePtr node, gpointer d)
796 xmlNodePtr n;
798 node = node->children;
800 if ((n = obt_xml_find_node(node, "drawContents")))
801 config_resize_redraw = obt_xml_node_bool(n);
802 if ((n = obt_xml_find_node(node, "popupShow"))) {
803 config_resize_popup_show = obt_xml_node_int(n);
804 if (obt_xml_node_contains(n, "Always"))
805 config_resize_popup_show = 2;
806 else if (obt_xml_node_contains(n, "Never"))
807 config_resize_popup_show = 0;
808 else if (obt_xml_node_contains(n, "Nonpixel"))
809 config_resize_popup_show = 1;
811 if ((n = obt_xml_find_node(node, "popupPosition"))) {
812 if (obt_xml_node_contains(n, "Top"))
813 config_resize_popup_pos = OB_RESIZE_POS_TOP;
814 else if (obt_xml_node_contains(n, "Center"))
815 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
816 else if (obt_xml_node_contains(n, "Fixed")) {
817 config_resize_popup_pos = OB_RESIZE_POS_FIXED;
819 if ((n = obt_xml_find_node(node, "popupFixedPosition"))) {
820 xmlNodePtr n2;
822 if ((n2 = obt_xml_find_node(n->children, "x")))
823 config_parse_gravity_coord(n2,
824 &config_resize_popup_fixed.x);
825 if ((n2 = obt_xml_find_node(n->children, "y")))
826 config_parse_gravity_coord(n2,
827 &config_resize_popup_fixed.y);
829 config_resize_popup_fixed.x.pos =
830 MAX(config_resize_popup_fixed.x.pos, 0);
831 config_resize_popup_fixed.y.pos =
832 MAX(config_resize_popup_fixed.y.pos, 0);
838 static void parse_dock(xmlNodePtr node, gpointer d)
840 xmlNodePtr n;
842 node = node->children;
844 if ((n = obt_xml_find_node(node, "position"))) {
845 if (obt_xml_node_contains(n, "TopLeft"))
846 config_dock_floating = FALSE,
847 config_dock_pos = OB_DIRECTION_NORTHWEST;
848 else if (obt_xml_node_contains(n, "Top"))
849 config_dock_floating = FALSE,
850 config_dock_pos = OB_DIRECTION_NORTH;
851 else if (obt_xml_node_contains(n, "TopRight"))
852 config_dock_floating = FALSE,
853 config_dock_pos = OB_DIRECTION_NORTHEAST;
854 else if (obt_xml_node_contains(n, "Right"))
855 config_dock_floating = FALSE,
856 config_dock_pos = OB_DIRECTION_EAST;
857 else if (obt_xml_node_contains(n, "BottomRight"))
858 config_dock_floating = FALSE,
859 config_dock_pos = OB_DIRECTION_SOUTHEAST;
860 else if (obt_xml_node_contains(n, "Bottom"))
861 config_dock_floating = FALSE,
862 config_dock_pos = OB_DIRECTION_SOUTH;
863 else if (obt_xml_node_contains(n, "BottomLeft"))
864 config_dock_floating = FALSE,
865 config_dock_pos = OB_DIRECTION_SOUTHWEST;
866 else if (obt_xml_node_contains(n, "Left"))
867 config_dock_floating = FALSE,
868 config_dock_pos = OB_DIRECTION_WEST;
869 else if (obt_xml_node_contains(n, "Floating"))
870 config_dock_floating = TRUE;
872 if (config_dock_floating) {
873 if ((n = obt_xml_find_node(node, "floatingX")))
874 config_dock_x = obt_xml_node_int(n);
875 if ((n = obt_xml_find_node(node, "floatingY")))
876 config_dock_y = obt_xml_node_int(n);
877 } else {
878 if ((n = obt_xml_find_node(node, "noStrut")))
879 config_dock_nostrut = obt_xml_node_bool(n);
881 if ((n = obt_xml_find_node(node, "stacking"))) {
882 if (obt_xml_node_contains(n, "normal"))
883 config_dock_layer = OB_STACKING_LAYER_NORMAL;
884 else if (obt_xml_node_contains(n, "below"))
885 config_dock_layer = OB_STACKING_LAYER_BELOW;
886 else if (obt_xml_node_contains(n, "above"))
887 config_dock_layer = OB_STACKING_LAYER_ABOVE;
889 if ((n = obt_xml_find_node(node, "direction"))) {
890 if (obt_xml_node_contains(n, "horizontal"))
891 config_dock_orient = OB_ORIENTATION_HORZ;
892 else if (obt_xml_node_contains(n, "vertical"))
893 config_dock_orient = OB_ORIENTATION_VERT;
895 if ((n = obt_xml_find_node(node, "autoHide")))
896 config_dock_hide = obt_xml_node_bool(n);
897 if ((n = obt_xml_find_node(node, "hideDelay")))
898 config_dock_hide_delay = obt_xml_node_int(n);
899 if ((n = obt_xml_find_node(node, "showDelay")))
900 config_dock_show_delay = obt_xml_node_int(n);
901 if ((n = obt_xml_find_node(node, "moveButton"))) {
902 gchar *str = obt_xml_node_string(n);
903 guint b, s;
904 if (translate_button(str, &s, &b)) {
905 config_dock_app_move_button = b;
906 config_dock_app_move_modifiers = s;
907 } else {
908 g_message(_("Invalid button \"%s\" specified in config file"), str);
910 g_free(str);
914 static void parse_menu(xmlNodePtr node, gpointer d)
916 xmlNodePtr n;
917 node = node->children;
919 if ((n = obt_xml_find_node(node, "hideDelay")))
920 config_menu_hide_delay = obt_xml_node_int(n);
921 if ((n = obt_xml_find_node(node, "middle")))
922 config_menu_middle = obt_xml_node_bool(n);
923 if ((n = obt_xml_find_node(node, "submenuShowDelay")))
924 config_submenu_show_delay = obt_xml_node_int(n);
925 if ((n = obt_xml_find_node(node, "submenuHideDelay")))
926 config_submenu_hide_delay = obt_xml_node_int(n);
927 if ((n = obt_xml_find_node(node, "manageDesktops")))
928 config_menu_manage_desktops = obt_xml_node_bool(n);
929 if ((n = obt_xml_find_node(node, "showIcons"))) {
930 config_menu_show_icons = obt_xml_node_bool(n);
931 #if !defined(USE_IMLIB2) && !defined(USE_LIBRSVG)
932 if (config_menu_show_icons)
933 g_message(_("Openbox was compiled without image loading support. Icons in menus will not be loaded."));
934 #endif
937 while ((node = obt_xml_find_node(node, "file"))) {
938 gchar *c = obt_xml_node_string(node);
939 config_menu_files = g_slist_append(config_menu_files,
940 obt_paths_expand_tilde(c));
941 g_free(c);
942 node = node->next;
946 static void parse_resistance(xmlNodePtr node, gpointer d)
948 xmlNodePtr n;
950 node = node->children;
951 if ((n = obt_xml_find_node(node, "strength")))
952 config_resist_win = obt_xml_node_int(n);
953 if ((n = obt_xml_find_node(node, "screen_edge_strength")))
954 config_resist_edge = obt_xml_node_int(n);
957 typedef struct
959 const gchar *key;
960 const gchar *actname;
961 } ObDefKeyBind;
963 static void bind_default_keyboard(void)
965 ObDefKeyBind *it;
966 ObDefKeyBind binds[] = {
967 { "A-Tab", "NextWindow" },
968 { "S-A-Tab", "PreviousWindow" },
969 { "A-F4", "Close" },
970 { NULL, NULL }
972 for (it = binds; it->key; ++it) {
973 GList *l = g_list_append(NULL, g_strdup(it->key));
974 keyboard_bind(l, actions_parse_string(it->actname));
978 typedef struct
980 const gchar *button;
981 const gchar *context;
982 const ObMouseAction mact;
983 const gchar *actname;
984 } ObDefMouseBind;
986 static void bind_default_mouse(void)
988 ObDefMouseBind *it;
989 ObDefMouseBind binds[] = {
990 { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
991 { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
992 { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
993 { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
994 { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
995 { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
996 { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
997 { "Left", "Bottom", OB_MOUSE_ACTION_PRESS, "Focus" },
998 { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
999 { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1000 { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1001 { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
1002 { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
1003 { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
1004 { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
1005 { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
1006 { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
1007 { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
1008 { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
1009 { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
1010 { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
1011 { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1012 { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1013 { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1014 { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
1015 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
1016 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
1017 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
1018 { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
1019 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
1020 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
1021 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
1022 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximize" },
1023 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
1024 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
1025 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
1026 { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1027 { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1028 { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1029 { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
1030 { "Left", "Top", OB_MOUSE_ACTION_MOTION, "Resize" },
1031 { "Left", "Bottom", OB_MOUSE_ACTION_MOTION, "Resize" },
1032 { "Left", "Left", OB_MOUSE_ACTION_MOTION, "Resize" },
1033 { "Left", "Right", OB_MOUSE_ACTION_MOTION, "Resize" },
1034 { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
1035 { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
1036 { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
1037 { NULL, NULL, 0, NULL }
1040 for (it = binds; it->button; ++it)
1041 mouse_bind(it->button, frame_context_from_string(it->context),
1042 it->mact, actions_parse_string(it->actname));
1045 void config_startup(ObtXmlInst *i)
1047 config_focus_new = TRUE;
1048 config_focus_follow = FALSE;
1049 config_focus_delay = 0;
1050 config_focus_raise = FALSE;
1051 config_focus_last = TRUE;
1052 config_focus_under_mouse = FALSE;
1053 config_unfocus_leave = FALSE;
1055 obt_xml_register(i, "focus", parse_focus, NULL);
1057 config_place_policy = OB_PLACE_POLICY_SMART;
1058 config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
1060 config_primary_monitor_index = 1;
1061 config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
1063 obt_xml_register(i, "placement", parse_placement, NULL);
1065 STRUT_PARTIAL_SET(config_margins, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1067 obt_xml_register(i, "margins", parse_margins, NULL);
1069 config_theme = NULL;
1071 config_animate_iconify = TRUE;
1072 config_title_layout = g_strdup("NLIMC");
1073 config_theme_keepborder = TRUE;
1074 config_theme_window_list_icon_size = 36;
1076 config_font_activewindow = NULL;
1077 config_font_inactivewindow = NULL;
1078 config_font_menuitem = NULL;
1079 config_font_menutitle = NULL;
1080 config_font_activeosd = NULL;
1081 config_font_inactiveosd = NULL;
1083 obt_xml_register(i, "theme", parse_theme, NULL);
1085 config_desktops_num = 4;
1086 config_screen_firstdesk = 1;
1087 config_desktops_names = NULL;
1088 config_desktop_popup_time = 875;
1090 obt_xml_register(i, "desktops", parse_desktops, NULL);
1092 config_resize_redraw = TRUE;
1093 config_resize_popup_show = 1; /* nonpixel increments */
1094 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
1095 GRAVITY_COORD_SET(config_resize_popup_fixed.x, 0, FALSE, FALSE);
1096 GRAVITY_COORD_SET(config_resize_popup_fixed.y, 0, FALSE, FALSE);
1098 obt_xml_register(i, "resize", parse_resize, NULL);
1100 config_dock_layer = OB_STACKING_LAYER_ABOVE;
1101 config_dock_pos = OB_DIRECTION_NORTHEAST;
1102 config_dock_floating = FALSE;
1103 config_dock_nostrut = FALSE;
1104 config_dock_x = 0;
1105 config_dock_y = 0;
1106 config_dock_orient = OB_ORIENTATION_VERT;
1107 config_dock_hide = FALSE;
1108 config_dock_hide_delay = 300;
1109 config_dock_show_delay = 300;
1110 config_dock_app_move_button = 2; /* middle */
1111 config_dock_app_move_modifiers = 0;
1113 obt_xml_register(i, "dock", parse_dock, NULL);
1115 translate_key("C-g", &config_keyboard_reset_state,
1116 &config_keyboard_reset_keycode);
1118 bind_default_keyboard();
1120 obt_xml_register(i, "keyboard", parse_keyboard, NULL);
1122 config_mouse_threshold = 8;
1123 config_mouse_dclicktime = 500;
1124 config_mouse_screenedgetime = 400;
1125 config_mouse_screenedgewarp = FALSE;
1127 bind_default_mouse();
1129 obt_xml_register(i, "mouse", parse_mouse, NULL);
1131 config_resist_win = 10;
1132 config_resist_edge = 20;
1134 obt_xml_register(i, "resistance", parse_resistance, NULL);
1136 config_menu_hide_delay = 250;
1137 config_menu_middle = FALSE;
1138 config_submenu_show_delay = 100;
1139 config_submenu_hide_delay = 400;
1140 config_menu_manage_desktops = TRUE;
1141 config_menu_files = NULL;
1142 config_menu_show_icons = TRUE;
1144 obt_xml_register(i, "menu", parse_menu, NULL);
1146 config_per_app_settings = NULL;
1148 obt_xml_register(i, "applications", parse_per_app_settings, NULL);
1151 void config_shutdown(void)
1153 GSList *it;
1155 g_free(config_theme);
1157 g_free(config_title_layout);
1159 RrFontClose(config_font_activewindow);
1160 RrFontClose(config_font_inactivewindow);
1161 RrFontClose(config_font_menuitem);
1162 RrFontClose(config_font_menutitle);
1163 RrFontClose(config_font_activeosd);
1164 RrFontClose(config_font_inactiveosd);
1166 for (it = config_desktops_names; it; it = g_slist_next(it))
1167 g_free(it->data);
1168 g_slist_free(config_desktops_names);
1170 for (it = config_menu_files; it; it = g_slist_next(it))
1171 g_free(it->data);
1172 g_slist_free(config_menu_files);
1174 for (it = config_per_app_settings; it; it = g_slist_next(it)) {
1175 ObAppSettings *itd = (ObAppSettings *)it->data;
1176 if (itd->name) g_pattern_spec_free(itd->name);
1177 if (itd->role) g_pattern_spec_free(itd->role);
1178 if (itd->title) g_pattern_spec_free(itd->title);
1179 if (itd->class) g_pattern_spec_free(itd->class);
1180 if (itd->group_name) g_pattern_spec_free(itd->group_name);
1181 if (itd->group_class) g_pattern_spec_free(itd->group_class);
1182 g_slice_free(ObAppSettings, it->data);
1184 g_slist_free(config_per_app_settings);