Don't make desktop switching interactive when no mods used. (Fix bug #5203)
[openbox.git] / openbox / config.c
blob0d9eb689f2e7f4e7ad8ecc4073529413c1541371
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 gboolean config_place_center;
41 ObPlaceMonitor config_place_monitor;
43 guint config_primary_monitor_index;
44 ObPlaceMonitor config_primary_monitor;
46 StrutPartial config_margins;
48 gchar *config_theme;
49 gboolean config_theme_keepborder;
50 guint config_theme_window_list_icon_size;
52 gchar *config_title_layout;
54 gboolean config_animate_iconify;
56 RrFont *config_font_activewindow;
57 RrFont *config_font_inactivewindow;
58 RrFont *config_font_menuitem;
59 RrFont *config_font_menutitle;
60 RrFont *config_font_activeosd;
61 RrFont *config_font_inactiveosd;
63 guint config_desktops_num;
64 GSList *config_desktops_names;
65 guint config_screen_firstdesk;
66 guint config_desktop_popup_time;
68 gboolean config_resize_redraw;
69 gint config_resize_popup_show;
70 ObResizePopupPos config_resize_popup_pos;
71 GravityPoint config_resize_popup_fixed;
73 ObStackingLayer config_dock_layer;
74 gboolean config_dock_floating;
75 gboolean config_dock_nostrut;
76 ObDirection config_dock_pos;
77 gint config_dock_x;
78 gint config_dock_y;
79 ObOrientation config_dock_orient;
80 gboolean config_dock_hide;
81 guint config_dock_hide_delay;
82 guint config_dock_show_delay;
83 guint config_dock_app_move_button;
84 guint config_dock_app_move_modifiers;
86 guint config_keyboard_reset_keycode;
87 guint config_keyboard_reset_state;
89 gint config_mouse_threshold;
90 gint config_mouse_dclicktime;
91 gint config_mouse_screenedgetime;
92 gboolean config_mouse_screenedgewarp;
94 guint config_menu_hide_delay;
95 gboolean config_menu_middle;
96 guint config_submenu_show_delay;
97 guint config_submenu_hide_delay;
98 gboolean config_menu_manage_desktops;
99 gboolean config_menu_show_icons;
101 GSList *config_menu_files;
103 gint config_resist_win;
104 gint config_resist_edge;
106 GSList *config_per_app_settings;
108 ObAppSettings* config_create_app_settings(void)
110 ObAppSettings *settings = g_slice_new0(ObAppSettings);
111 settings->type = -1;
112 settings->decor = -1;
113 settings->shade = -1;
114 settings->monitor_type = OB_PLACE_MONITOR_ANY;
115 settings->monitor = -1;
116 settings->focus = -1;
117 settings->desktop = 0;
118 settings->layer = -2;
119 settings->iconic = -1;
120 settings->skip_pager = -1;
121 settings->skip_taskbar = -1;
122 settings->fullscreen = -1;
123 settings->max_horz = -1;
124 settings->max_vert = -1;
125 return settings;
128 #define copy_if(setting, default) \
129 if (src->setting != default) dst->setting = src->setting
130 void config_app_settings_copy_non_defaults(const ObAppSettings *src,
131 ObAppSettings *dst)
133 g_assert(src != NULL);
134 g_assert(dst != NULL);
136 copy_if(type, (ObClientType)-1);
137 copy_if(decor, -1);
138 copy_if(shade, -1);
139 copy_if(monitor_type, OB_PLACE_MONITOR_ANY);
140 copy_if(monitor, -1);
141 copy_if(focus, -1);
142 copy_if(desktop, 0);
143 copy_if(layer, -2);
144 copy_if(iconic, -1);
145 copy_if(skip_pager, -1);
146 copy_if(skip_taskbar, -1);
147 copy_if(fullscreen, -1);
148 copy_if(max_horz, -1);
149 copy_if(max_vert, -1);
151 if (src->pos_given) {
152 dst->pos_given = TRUE;
153 dst->pos_force = src->pos_force;
154 dst->position = src->position;
155 /* monitor is copied above */
159 void config_parse_relative_number(gchar *s, gint *num, gint *denom)
161 *num = strtol(s, &s, 10);
163 if (*s == '%') {
164 *denom = 100;
165 } else if (*s == '/') {
166 *denom = atoi(s+1);
170 void config_parse_gravity_coord(xmlNodePtr node, GravityCoord *c)
172 gchar *s = obt_xml_node_string(node);
173 if (!g_ascii_strcasecmp(s, "center"))
174 c->center = TRUE;
175 else {
176 gchar *ps = s;
177 if (s[0] == '-')
178 c->opposite = TRUE;
179 if (s[0] == '-' || s[0] == '+')
180 ps++;
181 config_parse_relative_number(ps, &c->pos, &c->denom);
183 g_free(s);
187 <applications>
188 <application name="aterm">
189 <decor>false</decor>
190 </application>
191 <application name="Rhythmbox">
192 <layer>above</layer>
193 <position>
194 <x>700</x>
195 <y>0</y>
196 <monitor>1</monitor>
197 </position>
198 .. there is a lot more settings available
199 </application>
200 </applications>
203 /* Manages settings for individual applications.
204 Some notes: monitor is the screen number in a multi monitor
205 (Xinerama) setup (starting from 0), or mouse: the monitor the pointer
206 is on, active: the active monitor, primary: the primary monitor.
207 Layer can be three values, above (Always on top), below
208 (Always on bottom) and everything else (normal behaviour).
209 Positions can be an integer value or center, which will
210 center the window in the specified axis. Position is within
211 the monitor, so <position><x>center</x></position><monitor>2</monitor>
212 will center the window on the second monitor.
214 static void parse_per_app_settings(xmlNodePtr node, gpointer d)
216 xmlNodePtr app = obt_xml_find_node(node->children, "application");
217 gchar *name = NULL, *class = NULL, *role = NULL, *title = NULL,
218 *type_str = NULL;
219 gboolean name_set, class_set, type_set, role_set, title_set;
220 ObClientType type;
221 gboolean x_pos_given;
223 while (app) {
224 x_pos_given = FALSE;
226 class_set = obt_xml_attr_string(app, "class", &class);
227 name_set = obt_xml_attr_string(app, "name", &name);
228 type_set = obt_xml_attr_string(app, "type", &type_str);
229 role_set = obt_xml_attr_string(app, "role", &role);
230 title_set = obt_xml_attr_string(app, "title", &title);
232 /* validate the type tho */
233 if (type_set) {
234 if (!g_ascii_strcasecmp(type_str, "normal"))
235 type = OB_CLIENT_TYPE_NORMAL;
236 else if (!g_ascii_strcasecmp(type_str, "dialog"))
237 type = OB_CLIENT_TYPE_DIALOG;
238 else if (!g_ascii_strcasecmp(type_str, "splash"))
239 type = OB_CLIENT_TYPE_SPLASH;
240 else if (!g_ascii_strcasecmp(type_str, "utility"))
241 type = OB_CLIENT_TYPE_UTILITY;
242 else if (!g_ascii_strcasecmp(type_str, "menu"))
243 type = OB_CLIENT_TYPE_MENU;
244 else if (!g_ascii_strcasecmp(type_str, "toolbar"))
245 type = OB_CLIENT_TYPE_TOOLBAR;
246 else if (!g_ascii_strcasecmp(type_str, "dock"))
247 type = OB_CLIENT_TYPE_DOCK;
248 else if (!g_ascii_strcasecmp(type_str, "desktop"))
249 type = OB_CLIENT_TYPE_DESKTOP;
250 else
251 type_set = FALSE; /* not valid! */
254 if (class_set || name_set || role_set || title_set || type_set) {
255 xmlNodePtr n, c;
256 ObAppSettings *settings = config_create_app_settings();
258 if (name_set)
259 settings->name = g_pattern_spec_new(name);
261 if (class_set)
262 settings->class = g_pattern_spec_new(class);
264 if (role_set)
265 settings->role = g_pattern_spec_new(role);
267 if (title_set)
268 settings->title = g_pattern_spec_new(title);
270 if (type_set)
271 settings->type = type;
273 if ((n = obt_xml_find_node(app->children, "decor")))
274 if (!obt_xml_node_contains(n, "default"))
275 settings->decor = obt_xml_node_bool(n);
277 if ((n = obt_xml_find_node(app->children, "shade")))
278 if (!obt_xml_node_contains(n, "default"))
279 settings->shade = obt_xml_node_bool(n);
281 if ((n = obt_xml_find_node(app->children, "position"))) {
282 if ((c = obt_xml_find_node(n->children, "x")))
283 if (!obt_xml_node_contains(c, "default")) {
284 config_parse_gravity_coord(c, &settings->position.x);
285 x_pos_given = TRUE;
288 if (x_pos_given && (c = obt_xml_find_node(n->children, "y")))
289 if (!obt_xml_node_contains(c, "default")) {
290 config_parse_gravity_coord(c, &settings->position.y);
291 settings->pos_given = TRUE;
294 /* monitor can be set without setting x or y */
295 if ((c = obt_xml_find_node(n->children, "monitor")))
296 if (!obt_xml_node_contains(c, "default")) {
297 gchar *s = obt_xml_node_string(c);
298 if (!g_ascii_strcasecmp(s, "mouse"))
299 settings->monitor_type =
300 OB_PLACE_MONITOR_MOUSE;
301 else if (!g_ascii_strcasecmp(s, "active"))
302 settings->monitor_type =
303 OB_PLACE_MONITOR_ACTIVE;
304 else if (!g_ascii_strcasecmp(s, "primary"))
305 settings->monitor_type =
306 OB_PLACE_MONITOR_PRIMARY;
307 else
308 settings->monitor = obt_xml_node_int(c);
309 g_free(s);
312 obt_xml_attr_bool(n, "force", &settings->pos_force);
315 if ((n = obt_xml_find_node(app->children, "focus")))
316 if (!obt_xml_node_contains(n, "default"))
317 settings->focus = obt_xml_node_bool(n);
319 if ((n = obt_xml_find_node(app->children, "desktop"))) {
320 if (!obt_xml_node_contains(n, "default")) {
321 gchar *s = obt_xml_node_string(n);
322 if (!g_ascii_strcasecmp(s, "all"))
323 settings->desktop = DESKTOP_ALL;
324 else {
325 gint i = obt_xml_node_int(n);
326 if (i > 0)
327 settings->desktop = i;
329 g_free(s);
333 if ((n = obt_xml_find_node(app->children, "layer")))
334 if (!obt_xml_node_contains(n, "default")) {
335 gchar *s = obt_xml_node_string(n);
336 if (!g_ascii_strcasecmp(s, "above"))
337 settings->layer = 1;
338 else if (!g_ascii_strcasecmp(s, "below"))
339 settings->layer = -1;
340 else
341 settings->layer = 0;
342 g_free(s);
345 if ((n = obt_xml_find_node(app->children, "iconic")))
346 if (!obt_xml_node_contains(n, "default"))
347 settings->iconic = obt_xml_node_bool(n);
349 if ((n = obt_xml_find_node(app->children, "skip_pager")))
350 if (!obt_xml_node_contains(n, "default"))
351 settings->skip_pager = obt_xml_node_bool(n);
353 if ((n = obt_xml_find_node(app->children, "skip_taskbar")))
354 if (!obt_xml_node_contains(n, "default"))
355 settings->skip_taskbar = obt_xml_node_bool(n);
357 if ((n = obt_xml_find_node(app->children, "fullscreen")))
358 if (!obt_xml_node_contains(n, "default"))
359 settings->fullscreen = obt_xml_node_bool(n);
361 if ((n = obt_xml_find_node(app->children, "maximized")))
362 if (!obt_xml_node_contains(n, "default")) {
363 gchar *s = obt_xml_node_string(n);
364 if (!g_ascii_strcasecmp(s, "horizontal")) {
365 settings->max_horz = TRUE;
366 settings->max_vert = FALSE;
367 } else if (!g_ascii_strcasecmp(s, "vertical")) {
368 settings->max_horz = FALSE;
369 settings->max_vert = TRUE;
370 } else
371 settings->max_horz = settings->max_vert =
372 obt_xml_node_bool(n);
373 g_free(s);
376 config_per_app_settings = g_slist_append(config_per_app_settings,
377 (gpointer) settings);
378 g_free(name);
379 g_free(class);
380 g_free(role);
381 g_free(title);
382 g_free(type_str);
383 name = class = role = title = type_str = NULL;
386 app = obt_xml_find_node(app->next, "application");
392 <keybind key="C-x">
393 <action name="ChangeDesktop">
394 <desktop>3</desktop>
395 </action>
396 </keybind>
400 static void parse_key(xmlNodePtr node, GList *keylist)
402 gchar *keystring, **keys, **key;
403 xmlNodePtr n;
404 gboolean is_chroot = FALSE;
406 if (!obt_xml_attr_string(node, "key", &keystring))
407 return;
409 obt_xml_attr_bool(node, "chroot", &is_chroot);
411 keys = g_strsplit(keystring, " ", 0);
412 for (key = keys; *key; ++key) {
413 keylist = g_list_append(keylist, *key);
415 if ((n = obt_xml_find_node(node->children, "keybind"))) {
416 while (n) {
417 parse_key(n, keylist);
418 n = obt_xml_find_node(n->next, "keybind");
421 else if ((n = obt_xml_find_node(node->children, "action"))) {
422 while (n) {
423 ObActionsAct *action;
425 action = actions_parse(n);
426 if (action)
427 keyboard_bind(keylist, action);
428 n = obt_xml_find_node(n->next, "action");
433 if (is_chroot)
434 keyboard_chroot(keylist);
435 keylist = g_list_delete_link(keylist, g_list_last(keylist));
438 g_strfreev(keys);
439 g_free(keystring);
442 static void parse_keyboard(xmlNodePtr node, gpointer d)
444 xmlNodePtr n;
445 gchar *key;
447 keyboard_unbind_all();
449 if ((n = obt_xml_find_node(node->children, "chainQuitKey"))) {
450 key = obt_xml_node_string(n);
451 translate_key(key, &config_keyboard_reset_state,
452 &config_keyboard_reset_keycode);
453 g_free(key);
456 if ((n = obt_xml_find_node(node->children, "keybind")))
457 while (n) {
458 parse_key(n, NULL);
459 n = obt_xml_find_node(n->next, "keybind");
465 <context name="Titlebar">
466 <mousebind button="Left" action="Press">
467 <action name="Raise"></action>
468 </mousebind>
469 </context>
473 static void parse_mouse(xmlNodePtr node, gpointer d)
475 xmlNodePtr n, nbut, nact;
476 gchar *buttonstr;
477 gchar *cxstr;
478 ObMouseAction mact;
480 mouse_unbind_all();
482 node = node->children;
484 if ((n = obt_xml_find_node(node, "dragThreshold")))
485 config_mouse_threshold = obt_xml_node_int(n);
486 if ((n = obt_xml_find_node(node, "doubleClickTime")))
487 config_mouse_dclicktime = obt_xml_node_int(n);
488 if ((n = obt_xml_find_node(node, "screenEdgeWarpTime"))) {
489 config_mouse_screenedgetime = obt_xml_node_int(n);
490 /* minimum value of 25 for this property, when it is 1 and you hit the
491 edge it basically never stops */
492 if (config_mouse_screenedgetime && config_mouse_screenedgetime < 25)
493 config_mouse_screenedgetime = 25;
495 if ((n = obt_xml_find_node(node, "screenEdgeWarpMouse")))
496 config_mouse_screenedgewarp = obt_xml_node_bool(n);
498 n = obt_xml_find_node(node, "context");
499 while (n) {
500 gchar *modcxstr;
501 ObFrameContext cx;
503 if (!obt_xml_attr_string(n, "name", &cxstr))
504 goto next_n;
506 modcxstr = g_strdup(cxstr); /* make a copy to mutilate */
507 while (frame_next_context_from_string(modcxstr, &cx)) {
508 if (!cx) {
509 gchar *s = strchr(modcxstr, ' ');
510 if (s) {
511 *s = '\0';
512 g_message(_("Invalid context \"%s\" in mouse binding"),
513 modcxstr);
514 *s = ' ';
516 continue;
519 nbut = obt_xml_find_node(n->children, "mousebind");
520 while (nbut) {
521 if (!obt_xml_attr_string(nbut, "button", &buttonstr))
522 goto next_nbut;
523 if (obt_xml_attr_contains(nbut, "action", "press"))
524 mact = OB_MOUSE_ACTION_PRESS;
525 else if (obt_xml_attr_contains(nbut, "action", "release"))
526 mact = OB_MOUSE_ACTION_RELEASE;
527 else if (obt_xml_attr_contains(nbut, "action", "click"))
528 mact = OB_MOUSE_ACTION_CLICK;
529 else if (obt_xml_attr_contains(nbut, "action","doubleclick"))
530 mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
531 else if (obt_xml_attr_contains(nbut, "action", "drag"))
532 mact = OB_MOUSE_ACTION_MOTION;
533 else
534 goto next_nbut;
536 nact = obt_xml_find_node(nbut->children, "action");
537 while (nact) {
538 ObActionsAct *action;
540 if ((action = actions_parse(nact)))
541 mouse_bind(buttonstr, cx, mact, action);
542 nact = obt_xml_find_node(nact->next, "action");
544 g_free(buttonstr);
545 next_nbut:
546 nbut = obt_xml_find_node(nbut->next, "mousebind");
549 g_free(modcxstr);
550 g_free(cxstr);
551 next_n:
552 n = obt_xml_find_node(n->next, "context");
556 static void parse_focus(xmlNodePtr node, gpointer d)
558 xmlNodePtr n;
560 node = node->children;
562 if ((n = obt_xml_find_node(node, "focusNew")))
563 config_focus_new = obt_xml_node_bool(n);
564 if ((n = obt_xml_find_node(node, "followMouse")))
565 config_focus_follow = obt_xml_node_bool(n);
566 if ((n = obt_xml_find_node(node, "focusDelay")))
567 config_focus_delay = obt_xml_node_int(n);
568 if ((n = obt_xml_find_node(node, "raiseOnFocus")))
569 config_focus_raise = obt_xml_node_bool(n);
570 if ((n = obt_xml_find_node(node, "focusLast")))
571 config_focus_last = obt_xml_node_bool(n);
572 if ((n = obt_xml_find_node(node, "underMouse")))
573 config_focus_under_mouse = obt_xml_node_bool(n);
574 if ((n = obt_xml_find_node(node, "unfocusOnLeave")))
575 config_unfocus_leave = obt_xml_node_bool(n);
578 static void parse_placement(xmlNodePtr node, gpointer d)
580 xmlNodePtr n;
582 node = node->children;
584 if ((n = obt_xml_find_node(node, "policy")))
585 if (obt_xml_node_contains(n, "UnderMouse"))
586 config_place_policy = OB_PLACE_POLICY_MOUSE;
587 if ((n = obt_xml_find_node(node, "center")))
588 config_place_center = obt_xml_node_bool(n);
589 if ((n = obt_xml_find_node(node, "monitor"))) {
590 if (obt_xml_node_contains(n, "active"))
591 config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
592 else if (obt_xml_node_contains(n, "mouse"))
593 config_place_monitor = OB_PLACE_MONITOR_MOUSE;
594 else if (obt_xml_node_contains(n, "any"))
595 config_place_monitor = OB_PLACE_MONITOR_ANY;
597 if ((n = obt_xml_find_node(node, "primaryMonitor"))) {
598 config_primary_monitor_index = obt_xml_node_int(n);
599 if (!config_primary_monitor_index) {
600 if (obt_xml_node_contains(n, "mouse"))
601 config_primary_monitor = OB_PLACE_MONITOR_MOUSE;
606 static void parse_margins(xmlNodePtr node, gpointer d)
608 xmlNodePtr n;
610 node = node->children;
612 if ((n = obt_xml_find_node(node, "top")))
613 config_margins.top = MAX(0, obt_xml_node_int(n));
614 if ((n = obt_xml_find_node(node, "left")))
615 config_margins.left = MAX(0, obt_xml_node_int(n));
616 if ((n = obt_xml_find_node(node, "right")))
617 config_margins.right = MAX(0, obt_xml_node_int(n));
618 if ((n = obt_xml_find_node(node, "bottom")))
619 config_margins.bottom = MAX(0, obt_xml_node_int(n));
622 static void parse_theme(xmlNodePtr node, gpointer d)
624 xmlNodePtr n;
626 node = node->children;
628 if ((n = obt_xml_find_node(node, "name"))) {
629 gchar *c;
631 g_free(config_theme);
632 c = obt_xml_node_string(n);
633 config_theme = obt_paths_expand_tilde(c);
634 g_free(c);
636 if ((n = obt_xml_find_node(node, "titleLayout"))) {
637 gchar *c, *d;
639 g_free(config_title_layout);
640 config_title_layout = obt_xml_node_string(n);
642 /* replace duplicates with spaces */
643 for (c = config_title_layout; *c != '\0'; ++c)
644 for (d = c+1; *d != '\0'; ++d)
645 if (*c == *d) *d = ' ';
647 if ((n = obt_xml_find_node(node, "keepBorder")))
648 config_theme_keepborder = obt_xml_node_bool(n);
649 if ((n = obt_xml_find_node(node, "animateIconify")))
650 config_animate_iconify = obt_xml_node_bool(n);
651 if ((n = obt_xml_find_node(node, "windowListIconSize"))) {
652 config_theme_window_list_icon_size = obt_xml_node_int(n);
653 if (config_theme_window_list_icon_size < 16)
654 config_theme_window_list_icon_size = 16;
655 else if (config_theme_window_list_icon_size > 96)
656 config_theme_window_list_icon_size = 96;
659 n = obt_xml_find_node(node, "font");
660 while (n) {
661 xmlNodePtr fnode;
662 RrFont **font;
663 gchar *name = g_strdup(RrDefaultFontFamily);
664 gint size = RrDefaultFontSize;
665 RrFontWeight weight = RrDefaultFontWeight;
666 RrFontSlant slant = RrDefaultFontSlant;
668 if (obt_xml_attr_contains(n, "place", "ActiveWindow"))
669 font = &config_font_activewindow;
670 else if (obt_xml_attr_contains(n, "place", "InactiveWindow"))
671 font = &config_font_inactivewindow;
672 else if (obt_xml_attr_contains(n, "place", "MenuHeader"))
673 font = &config_font_menutitle;
674 else if (obt_xml_attr_contains(n, "place", "MenuItem"))
675 font = &config_font_menuitem;
676 else if (obt_xml_attr_contains(n, "place", "ActiveOnScreenDisplay"))
677 font = &config_font_activeosd;
678 else if (obt_xml_attr_contains(n, "place", "OnScreenDisplay"))
679 font = &config_font_activeosd;
680 else if (obt_xml_attr_contains(n, "place","InactiveOnScreenDisplay"))
681 font = &config_font_inactiveosd;
682 else
683 goto next_font;
685 if ((fnode = obt_xml_find_node(n->children, "name"))) {
686 g_free(name);
687 name = obt_xml_node_string(fnode);
689 if ((fnode = obt_xml_find_node(n->children, "size"))) {
690 int s = obt_xml_node_int(fnode);
691 if (s > 0) size = s;
693 if ((fnode = obt_xml_find_node(n->children, "weight"))) {
694 gchar *w = obt_xml_node_string(fnode);
695 if (!g_ascii_strcasecmp(w, "Bold"))
696 weight = RR_FONTWEIGHT_BOLD;
697 g_free(w);
699 if ((fnode = obt_xml_find_node(n->children, "slant"))) {
700 gchar *s = obt_xml_node_string(fnode);
701 if (!g_ascii_strcasecmp(s, "Italic"))
702 slant = RR_FONTSLANT_ITALIC;
703 if (!g_ascii_strcasecmp(s, "Oblique"))
704 slant = RR_FONTSLANT_OBLIQUE;
705 g_free(s);
708 *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
709 g_free(name);
710 next_font:
711 n = obt_xml_find_node(n->next, "font");
715 static void parse_desktops(xmlNodePtr node, gpointer d)
717 xmlNodePtr n;
719 node = node->children;
721 if ((n = obt_xml_find_node(node, "number"))) {
722 gint d = obt_xml_node_int(n);
723 if (d > 0)
724 config_desktops_num = (unsigned) d;
726 if ((n = obt_xml_find_node(node, "firstdesk"))) {
727 gint d = obt_xml_node_int(n);
728 if (d > 0)
729 config_screen_firstdesk = (unsigned) d;
731 if ((n = obt_xml_find_node(node, "names"))) {
732 GSList *it;
733 xmlNodePtr nname;
735 for (it = config_desktops_names; it; it = it->next)
736 g_free(it->data);
737 g_slist_free(config_desktops_names);
738 config_desktops_names = NULL;
740 nname = obt_xml_find_node(n->children, "name");
741 while (nname) {
742 config_desktops_names =
743 g_slist_append(config_desktops_names,
744 obt_xml_node_string(nname));
745 nname = obt_xml_find_node(nname->next, "name");
748 if ((n = obt_xml_find_node(node, "popupTime")))
749 config_desktop_popup_time = obt_xml_node_int(n);
752 static void parse_resize(xmlNodePtr node, gpointer d)
754 xmlNodePtr n;
756 node = node->children;
758 if ((n = obt_xml_find_node(node, "drawContents")))
759 config_resize_redraw = obt_xml_node_bool(n);
760 if ((n = obt_xml_find_node(node, "popupShow"))) {
761 config_resize_popup_show = obt_xml_node_int(n);
762 if (obt_xml_node_contains(n, "Always"))
763 config_resize_popup_show = 2;
764 else if (obt_xml_node_contains(n, "Never"))
765 config_resize_popup_show = 0;
766 else if (obt_xml_node_contains(n, "Nonpixel"))
767 config_resize_popup_show = 1;
769 if ((n = obt_xml_find_node(node, "popupPosition"))) {
770 if (obt_xml_node_contains(n, "Top"))
771 config_resize_popup_pos = OB_RESIZE_POS_TOP;
772 else if (obt_xml_node_contains(n, "Center"))
773 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
774 else if (obt_xml_node_contains(n, "Fixed")) {
775 config_resize_popup_pos = OB_RESIZE_POS_FIXED;
777 if ((n = obt_xml_find_node(node, "popupFixedPosition"))) {
778 xmlNodePtr n2;
780 if ((n2 = obt_xml_find_node(n->children, "x")))
781 config_parse_gravity_coord(n2,
782 &config_resize_popup_fixed.x);
783 if ((n2 = obt_xml_find_node(n->children, "y")))
784 config_parse_gravity_coord(n2,
785 &config_resize_popup_fixed.y);
787 config_resize_popup_fixed.x.pos =
788 MAX(config_resize_popup_fixed.x.pos, 0);
789 config_resize_popup_fixed.y.pos =
790 MAX(config_resize_popup_fixed.y.pos, 0);
796 static void parse_dock(xmlNodePtr node, gpointer d)
798 xmlNodePtr n;
800 node = node->children;
802 if ((n = obt_xml_find_node(node, "position"))) {
803 if (obt_xml_node_contains(n, "TopLeft"))
804 config_dock_floating = FALSE,
805 config_dock_pos = OB_DIRECTION_NORTHWEST;
806 else if (obt_xml_node_contains(n, "Top"))
807 config_dock_floating = FALSE,
808 config_dock_pos = OB_DIRECTION_NORTH;
809 else if (obt_xml_node_contains(n, "TopRight"))
810 config_dock_floating = FALSE,
811 config_dock_pos = OB_DIRECTION_NORTHEAST;
812 else if (obt_xml_node_contains(n, "Right"))
813 config_dock_floating = FALSE,
814 config_dock_pos = OB_DIRECTION_EAST;
815 else if (obt_xml_node_contains(n, "BottomRight"))
816 config_dock_floating = FALSE,
817 config_dock_pos = OB_DIRECTION_SOUTHEAST;
818 else if (obt_xml_node_contains(n, "Bottom"))
819 config_dock_floating = FALSE,
820 config_dock_pos = OB_DIRECTION_SOUTH;
821 else if (obt_xml_node_contains(n, "BottomLeft"))
822 config_dock_floating = FALSE,
823 config_dock_pos = OB_DIRECTION_SOUTHWEST;
824 else if (obt_xml_node_contains(n, "Left"))
825 config_dock_floating = FALSE,
826 config_dock_pos = OB_DIRECTION_WEST;
827 else if (obt_xml_node_contains(n, "Floating"))
828 config_dock_floating = TRUE;
830 if (config_dock_floating) {
831 if ((n = obt_xml_find_node(node, "floatingX")))
832 config_dock_x = obt_xml_node_int(n);
833 if ((n = obt_xml_find_node(node, "floatingY")))
834 config_dock_y = obt_xml_node_int(n);
835 } else {
836 if ((n = obt_xml_find_node(node, "noStrut")))
837 config_dock_nostrut = obt_xml_node_bool(n);
839 if ((n = obt_xml_find_node(node, "stacking"))) {
840 if (obt_xml_node_contains(n, "normal"))
841 config_dock_layer = OB_STACKING_LAYER_NORMAL;
842 else if (obt_xml_node_contains(n, "below"))
843 config_dock_layer = OB_STACKING_LAYER_BELOW;
844 else if (obt_xml_node_contains(n, "above"))
845 config_dock_layer = OB_STACKING_LAYER_ABOVE;
847 if ((n = obt_xml_find_node(node, "direction"))) {
848 if (obt_xml_node_contains(n, "horizontal"))
849 config_dock_orient = OB_ORIENTATION_HORZ;
850 else if (obt_xml_node_contains(n, "vertical"))
851 config_dock_orient = OB_ORIENTATION_VERT;
853 if ((n = obt_xml_find_node(node, "autoHide")))
854 config_dock_hide = obt_xml_node_bool(n);
855 if ((n = obt_xml_find_node(node, "hideDelay")))
856 config_dock_hide_delay = obt_xml_node_int(n);
857 if ((n = obt_xml_find_node(node, "showDelay")))
858 config_dock_show_delay = obt_xml_node_int(n);
859 if ((n = obt_xml_find_node(node, "moveButton"))) {
860 gchar *str = obt_xml_node_string(n);
861 guint b, s;
862 if (translate_button(str, &s, &b)) {
863 config_dock_app_move_button = b;
864 config_dock_app_move_modifiers = s;
865 } else {
866 g_message(_("Invalid button \"%s\" specified in config file"), str);
868 g_free(str);
872 static void parse_menu(xmlNodePtr node, gpointer d)
874 xmlNodePtr n;
875 node = node->children;
877 if ((n = obt_xml_find_node(node, "hideDelay")))
878 config_menu_hide_delay = obt_xml_node_int(n);
879 if ((n = obt_xml_find_node(node, "middle")))
880 config_menu_middle = obt_xml_node_bool(n);
881 if ((n = obt_xml_find_node(node, "submenuShowDelay")))
882 config_submenu_show_delay = obt_xml_node_int(n);
883 if ((n = obt_xml_find_node(node, "submenuHideDelay")))
884 config_submenu_hide_delay = obt_xml_node_int(n);
885 if ((n = obt_xml_find_node(node, "manageDesktops")))
886 config_menu_manage_desktops = obt_xml_node_bool(n);
887 if ((n = obt_xml_find_node(node, "showIcons"))) {
888 config_menu_show_icons = obt_xml_node_bool(n);
889 #ifndef USE_IMLIB2
890 if (config_menu_show_icons)
891 g_message(_("Openbox was compiled without Imlib2 image loading support. Icons in menus will not be loaded."));
892 #endif
895 while ((node = obt_xml_find_node(node, "file"))) {
896 gchar *c = obt_xml_node_string(node);
897 config_menu_files = g_slist_append(config_menu_files,
898 obt_paths_expand_tilde(c));
899 g_free(c);
900 node = node->next;
904 static void parse_resistance(xmlNodePtr node, gpointer d)
906 xmlNodePtr n;
908 node = node->children;
909 if ((n = obt_xml_find_node(node, "strength")))
910 config_resist_win = obt_xml_node_int(n);
911 if ((n = obt_xml_find_node(node, "screen_edge_strength")))
912 config_resist_edge = obt_xml_node_int(n);
915 typedef struct
917 const gchar *key;
918 const gchar *actname;
919 } ObDefKeyBind;
921 static void bind_default_keyboard(void)
923 ObDefKeyBind *it;
924 ObDefKeyBind binds[] = {
925 { "A-Tab", "NextWindow" },
926 { "S-A-Tab", "PreviousWindow" },
927 { "A-F4", "Close" },
928 { NULL, NULL }
930 for (it = binds; it->key; ++it) {
931 GList *l = g_list_append(NULL, g_strdup(it->key));
932 keyboard_bind(l, actions_parse_string(it->actname));
936 typedef struct
938 const gchar *button;
939 const gchar *context;
940 const ObMouseAction mact;
941 const gchar *actname;
942 } ObDefMouseBind;
944 static void bind_default_mouse(void)
946 ObDefMouseBind *it;
947 ObDefMouseBind binds[] = {
948 { "Left", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
949 { "Middle", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
950 { "Right", "Client", OB_MOUSE_ACTION_PRESS, "Focus" },
951 { "Left", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
952 { "Middle", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
953 { "Right", "Desktop", OB_MOUSE_ACTION_PRESS, "Focus" },
954 { "Left", "Titlebar", OB_MOUSE_ACTION_PRESS, "Focus" },
955 { "Left", "Bottom", OB_MOUSE_ACTION_PRESS, "Focus" },
956 { "Left", "BLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
957 { "Left", "BRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
958 { "Left", "TLCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
959 { "Left", "TRCorner", OB_MOUSE_ACTION_PRESS, "Focus" },
960 { "Left", "Close", OB_MOUSE_ACTION_PRESS, "Focus" },
961 { "Left", "Maximize", OB_MOUSE_ACTION_PRESS, "Focus" },
962 { "Left", "Iconify", OB_MOUSE_ACTION_PRESS, "Focus" },
963 { "Left", "Icon", OB_MOUSE_ACTION_PRESS, "Focus" },
964 { "Left", "AllDesktops", OB_MOUSE_ACTION_PRESS, "Focus" },
965 { "Left", "Shade", OB_MOUSE_ACTION_PRESS, "Focus" },
966 { "Left", "Client", OB_MOUSE_ACTION_CLICK, "Raise" },
967 { "Left", "Titlebar", OB_MOUSE_ACTION_CLICK, "Raise" },
968 { "Middle", "Titlebar", OB_MOUSE_ACTION_CLICK, "Lower" },
969 { "Left", "BLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
970 { "Left", "BRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
971 { "Left", "TLCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
972 { "Left", "TRCorner", OB_MOUSE_ACTION_CLICK, "Raise" },
973 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Raise" },
974 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "Raise" },
975 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Raise" },
976 { "Left", "Icon", OB_MOUSE_ACTION_CLICK, "Raise" },
977 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "Raise" },
978 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "Raise" },
979 { "Left", "Close", OB_MOUSE_ACTION_CLICK, "Close" },
980 { "Left", "Maximize", OB_MOUSE_ACTION_CLICK, "ToggleMaximize" },
981 { "Left", "Iconify", OB_MOUSE_ACTION_CLICK, "Iconify" },
982 { "Left", "AllDesktops", OB_MOUSE_ACTION_CLICK, "ToggleOmnipresent" },
983 { "Left", "Shade", OB_MOUSE_ACTION_CLICK, "ToggleShade" },
984 { "Left", "TLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
985 { "Left", "TRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
986 { "Left", "BLCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
987 { "Left", "BRCorner", OB_MOUSE_ACTION_MOTION, "Resize" },
988 { "Left", "Top", OB_MOUSE_ACTION_MOTION, "Resize" },
989 { "Left", "Bottom", OB_MOUSE_ACTION_MOTION, "Resize" },
990 { "Left", "Left", OB_MOUSE_ACTION_MOTION, "Resize" },
991 { "Left", "Right", OB_MOUSE_ACTION_MOTION, "Resize" },
992 { "Left", "Titlebar", OB_MOUSE_ACTION_MOTION, "Move" },
993 { "A-Left", "Frame", OB_MOUSE_ACTION_MOTION, "Move" },
994 { "A-Middle", "Frame", OB_MOUSE_ACTION_MOTION, "Resize" },
995 { NULL, NULL, 0, NULL }
998 for (it = binds; it->button; ++it)
999 mouse_bind(it->button, frame_context_from_string(it->context),
1000 it->mact, actions_parse_string(it->actname));
1003 void config_startup(ObtXmlInst *i)
1005 config_focus_new = TRUE;
1006 config_focus_follow = FALSE;
1007 config_focus_delay = 0;
1008 config_focus_raise = FALSE;
1009 config_focus_last = TRUE;
1010 config_focus_under_mouse = FALSE;
1011 config_unfocus_leave = FALSE;
1013 obt_xml_register(i, "focus", parse_focus, NULL);
1015 config_place_policy = OB_PLACE_POLICY_SMART;
1016 config_place_center = TRUE;
1017 config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
1019 config_primary_monitor_index = 1;
1020 config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
1022 obt_xml_register(i, "placement", parse_placement, NULL);
1024 STRUT_PARTIAL_SET(config_margins, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1026 obt_xml_register(i, "margins", parse_margins, NULL);
1028 config_theme = NULL;
1030 config_animate_iconify = TRUE;
1031 config_title_layout = g_strdup("NLIMC");
1032 config_theme_keepborder = TRUE;
1033 config_theme_window_list_icon_size = 36;
1035 config_font_activewindow = NULL;
1036 config_font_inactivewindow = NULL;
1037 config_font_menuitem = NULL;
1038 config_font_menutitle = NULL;
1039 config_font_activeosd = NULL;
1040 config_font_inactiveosd = NULL;
1042 obt_xml_register(i, "theme", parse_theme, NULL);
1044 config_desktops_num = 4;
1045 config_screen_firstdesk = 1;
1046 config_desktops_names = NULL;
1047 config_desktop_popup_time = 875;
1049 obt_xml_register(i, "desktops", parse_desktops, NULL);
1051 config_resize_redraw = TRUE;
1052 config_resize_popup_show = 1; /* nonpixel increments */
1053 config_resize_popup_pos = OB_RESIZE_POS_CENTER;
1054 GRAVITY_COORD_SET(config_resize_popup_fixed.x, 0, FALSE, FALSE);
1055 GRAVITY_COORD_SET(config_resize_popup_fixed.y, 0, FALSE, FALSE);
1057 obt_xml_register(i, "resize", parse_resize, NULL);
1059 config_dock_layer = OB_STACKING_LAYER_ABOVE;
1060 config_dock_pos = OB_DIRECTION_NORTHEAST;
1061 config_dock_floating = FALSE;
1062 config_dock_nostrut = FALSE;
1063 config_dock_x = 0;
1064 config_dock_y = 0;
1065 config_dock_orient = OB_ORIENTATION_VERT;
1066 config_dock_hide = FALSE;
1067 config_dock_hide_delay = 300;
1068 config_dock_show_delay = 300;
1069 config_dock_app_move_button = 2; /* middle */
1070 config_dock_app_move_modifiers = 0;
1072 obt_xml_register(i, "dock", parse_dock, NULL);
1074 translate_key("C-g", &config_keyboard_reset_state,
1075 &config_keyboard_reset_keycode);
1077 bind_default_keyboard();
1079 obt_xml_register(i, "keyboard", parse_keyboard, NULL);
1081 config_mouse_threshold = 8;
1082 config_mouse_dclicktime = 500;
1083 config_mouse_screenedgetime = 400;
1084 config_mouse_screenedgewarp = FALSE;
1086 bind_default_mouse();
1088 obt_xml_register(i, "mouse", parse_mouse, NULL);
1090 config_resist_win = 10;
1091 config_resist_edge = 20;
1093 obt_xml_register(i, "resistance", parse_resistance, NULL);
1095 config_menu_hide_delay = 250;
1096 config_menu_middle = FALSE;
1097 config_submenu_show_delay = 100;
1098 config_submenu_hide_delay = 400;
1099 config_menu_manage_desktops = TRUE;
1100 config_menu_files = NULL;
1101 config_menu_show_icons = TRUE;
1103 obt_xml_register(i, "menu", parse_menu, NULL);
1105 config_per_app_settings = NULL;
1107 obt_xml_register(i, "applications", parse_per_app_settings, NULL);
1110 void config_shutdown(void)
1112 GSList *it;
1114 g_free(config_theme);
1116 g_free(config_title_layout);
1118 RrFontClose(config_font_activewindow);
1119 RrFontClose(config_font_inactivewindow);
1120 RrFontClose(config_font_menuitem);
1121 RrFontClose(config_font_menutitle);
1122 RrFontClose(config_font_activeosd);
1123 RrFontClose(config_font_inactiveosd);
1125 for (it = config_desktops_names; it; it = g_slist_next(it))
1126 g_free(it->data);
1127 g_slist_free(config_desktops_names);
1129 for (it = config_menu_files; it; it = g_slist_next(it))
1130 g_free(it->data);
1131 g_slist_free(config_menu_files);
1133 for (it = config_per_app_settings; it; it = g_slist_next(it)) {
1134 ObAppSettings *itd = (ObAppSettings *)it->data;
1135 if (itd->name) g_pattern_spec_free(itd->name);
1136 if (itd->role) g_pattern_spec_free(itd->role);
1137 if (itd->title) g_pattern_spec_free(itd->title);
1138 if (itd->class) g_pattern_spec_free(itd->class);
1139 g_slice_free(ObAppSettings, it->data);
1141 g_slist_free(config_per_app_settings);