Allow specifying only one of width and height in per-app settings size
[mikachu/openbox.git] / openbox / config.c
index 656ad3c..8e1bcf8 100644 (file)
@@ -37,7 +37,6 @@ gboolean config_focus_under_mouse;
 gboolean config_unfocus_leave;
 
 ObPlacePolicy  config_place_policy;
-gboolean       config_place_center;
 ObPlaceMonitor config_place_monitor;
 
 guint          config_primary_monitor_index;
@@ -111,6 +110,7 @@ ObAppSettings* config_create_app_settings(void)
     settings->type = -1;
     settings->decor = -1;
     settings->shade = -1;
+    settings->monitor_type = OB_PLACE_MONITOR_ANY;
     settings->monitor = -1;
     settings->focus = -1;
     settings->desktop = 0;
@@ -135,6 +135,7 @@ void config_app_settings_copy_non_defaults(const ObAppSettings *src,
     copy_if(type, (ObClientType)-1);
     copy_if(decor, -1);
     copy_if(shade, -1);
+    copy_if(monitor_type, OB_PLACE_MONITOR_ANY);
     copy_if(monitor, -1);
     copy_if(focus, -1);
     copy_if(desktop, 0);
@@ -152,6 +153,11 @@ void config_app_settings_copy_non_defaults(const ObAppSettings *src,
         dst->position = src->position;
         /* monitor is copied above */
     }
+
+    dst->width_num = src->width_num;
+    dst->width_denom = src->width_denom;
+    dst->height_num = src->height_num;
+    dst->height_denom = src->height_denom;
 }
 
 void config_parse_relative_number(gchar *s, gint *num, gint *denom)
@@ -198,10 +204,149 @@ void config_parse_gravity_coord(xmlNodePtr node, GravityCoord *c)
   </applications>
 */
 
+static void parse_single_per_app_settings(xmlNodePtr app,
+                                          ObAppSettings *settings)
+{
+    xmlNodePtr n, c;
+    gboolean x_pos_given = FALSE;
+
+    if ((n = obt_xml_find_node(app->children, "decor")))
+        if (!obt_xml_node_contains(n, "default"))
+            settings->decor = obt_xml_node_bool(n);
+
+    if ((n = obt_xml_find_node(app->children, "shade")))
+        if (!obt_xml_node_contains(n, "default"))
+            settings->shade = obt_xml_node_bool(n);
+
+    if ((n = obt_xml_find_node(app->children, "position"))) {
+        if ((c = obt_xml_find_node(n->children, "x"))) {
+            if (!obt_xml_node_contains(c, "default")) {
+                config_parse_gravity_coord(c, &settings->position.x);
+                x_pos_given = TRUE;
+            }
+        }
+
+        if (x_pos_given && (c = obt_xml_find_node(n->children, "y"))) {
+            if (!obt_xml_node_contains(c, "default")) {
+                config_parse_gravity_coord(c, &settings->position.y);
+                settings->pos_given = TRUE;
+            }
+        }
+
+        /* monitor can be set without setting x or y */
+        if ((c = obt_xml_find_node(n->children, "monitor"))) {
+            if (!obt_xml_node_contains(c, "default")) {
+                gchar *s = obt_xml_node_string(c);
+                if (!g_ascii_strcasecmp(s, "mouse"))
+                    settings->monitor_type = OB_PLACE_MONITOR_MOUSE;
+                else if (!g_ascii_strcasecmp(s, "active"))
+                    settings->monitor_type = OB_PLACE_MONITOR_ACTIVE;
+                else if (!g_ascii_strcasecmp(s, "primary"))
+                    settings->monitor_type = OB_PLACE_MONITOR_PRIMARY;
+                else
+                    settings->monitor = obt_xml_node_int(c);
+                g_free(s);
+            }
+        }
+
+        obt_xml_attr_bool(n, "force", &settings->pos_force);
+    }
+
+    if ((n = obt_xml_find_node(app->children, "size"))) {
+        if ((c = obt_xml_find_node(n->children, "width"))) {
+            if (!obt_xml_node_contains(c, "default")) {
+                gchar *s = obt_xml_node_string(c);
+                config_parse_relative_number(s,
+                                             &settings->width_num,
+                                             &settings->width_denom);
+                if (settings->width_num <= 0 || settings->width_denom < 0)
+                    settings->width_num = settings->width_denom = 0;
+                g_free(s);
+            }
+        }
+
+        if ((c = obt_xml_find_node(n->children, "height"))) {
+            if (!obt_xml_node_contains(c, "default")) {
+                gchar *s = obt_xml_node_string(c);
+                config_parse_relative_number(s,
+                                             &settings->height_num,
+                                             &settings->height_denom);
+                if (settings->height_num <= 0 || settings->height_denom < 0)
+                    settings->height_num = settings->height_denom = 0;
+                g_free(s);
+            }
+        }
+    }
+
+    if ((n = obt_xml_find_node(app->children, "focus"))) {
+        if (!obt_xml_node_contains(n, "default"))
+            settings->focus = obt_xml_node_bool(n);
+    }
+
+    if ((n = obt_xml_find_node(app->children, "desktop"))) {
+        if (!obt_xml_node_contains(n, "default")) {
+            gchar *s = obt_xml_node_string(n);
+            if (!g_ascii_strcasecmp(s, "all"))
+                settings->desktop = DESKTOP_ALL;
+            else {
+                gint i = obt_xml_node_int(n);
+                if (i > 0)
+                    settings->desktop = i;
+            }
+            g_free(s);
+        }
+    }
+
+    if ((n = obt_xml_find_node(app->children, "layer"))) {
+        if (!obt_xml_node_contains(n, "default")) {
+            gchar *s = obt_xml_node_string(n);
+            if (!g_ascii_strcasecmp(s, "above"))
+                settings->layer = 1;
+            else if (!g_ascii_strcasecmp(s, "below"))
+                settings->layer = -1;
+            else
+                settings->layer = 0;
+            g_free(s);
+        }
+    }
+
+    if ((n = obt_xml_find_node(app->children, "iconic")))
+        if (!obt_xml_node_contains(n, "default"))
+            settings->iconic = obt_xml_node_bool(n);
+
+    if ((n = obt_xml_find_node(app->children, "skip_pager")))
+        if (!obt_xml_node_contains(n, "default"))
+            settings->skip_pager = obt_xml_node_bool(n);
+
+    if ((n = obt_xml_find_node(app->children, "skip_taskbar")))
+        if (!obt_xml_node_contains(n, "default"))
+            settings->skip_taskbar = obt_xml_node_bool(n);
+
+    if ((n = obt_xml_find_node(app->children, "fullscreen")))
+        if (!obt_xml_node_contains(n, "default"))
+            settings->fullscreen = obt_xml_node_bool(n);
+
+    if ((n = obt_xml_find_node(app->children, "maximized"))) {
+        if (!obt_xml_node_contains(n, "default")) {
+            gchar *s = obt_xml_node_string(n);
+            if (!g_ascii_strcasecmp(s, "horizontal")) {
+                settings->max_horz = TRUE;
+                settings->max_vert = FALSE;
+            } else if (!g_ascii_strcasecmp(s, "vertical")) {
+                settings->max_horz = FALSE;
+                settings->max_vert = TRUE;
+            } else
+                settings->max_horz = settings->max_vert =
+                    obt_xml_node_bool(n);
+            g_free(s);
+        }
+    }
+}
+
 /* Manages settings for individual applications.
    Some notes: monitor is the screen number in a multi monitor
-   (Xinerama) setup (starting from 0) or mouse, meaning the
-   monitor the pointer is on. Default: mouse.
+   (Xinerama) setup (starting from 0), or mouse: the monitor the pointer
+   is on, active: the active monitor, primary: the primary monitor.
    Layer can be three values, above (Always on top), below
    (Always on bottom) and everything else (normal behaviour).
    Positions can be an integer value or center, which will
@@ -212,17 +357,19 @@ void config_parse_gravity_coord(xmlNodePtr node, GravityCoord *c)
 static void parse_per_app_settings(xmlNodePtr node, gpointer d)
 {
     xmlNodePtr app = obt_xml_find_node(node->children, "application");
-    gchar *name = NULL, *class = NULL, *role = NULL, *title = NULL,
-        *type_str = NULL;
-    gboolean name_set, class_set, type_set, role_set, title_set;
-    ObClientType type;
-    gboolean x_pos_given;
+    for (; app; app = obt_xml_find_node(app->next, "application")) {
+        ObAppSettings *settings;
 
-    while (app) {
-        x_pos_given = FALSE;
+        gboolean name_set, class_set, role_set, title_set,
+            type_set, group_name_set, group_class_set;
+        gchar *name = NULL, *class = NULL, *role = NULL, *title = NULL,
+            *type_str = NULL, *group_name = NULL, *group_class = NULL;
+        ObClientType type;
 
         class_set = obt_xml_attr_string(app, "class", &class);
         name_set = obt_xml_attr_string(app, "name", &name);
+        group_class_set = obt_xml_attr_string(app, "groupclass", &group_class);
+        group_name_set = obt_xml_attr_string(app, "groupname", &group_name);
         type_set = obt_xml_attr_string(app, "type", &type_str);
         role_set = obt_xml_attr_string(app, "role", &role);
         title_set = obt_xml_attr_string(app, "title", &title);
@@ -249,131 +396,38 @@ static void parse_per_app_settings(xmlNodePtr node, gpointer d)
                 type_set = FALSE; /* not valid! */
         }
 
-        if (class_set || name_set || role_set || title_set || type_set) {
-            xmlNodePtr n, c;
-            ObAppSettings *settings = config_create_app_settings();
-
-            if (name_set)
-                settings->name = g_pattern_spec_new(name);
-
-            if (class_set)
-                settings->class = g_pattern_spec_new(class);
-
-            if (role_set)
-                settings->role = g_pattern_spec_new(role);
-
-            if (title_set)
-                settings->title = g_pattern_spec_new(title);
-
-            if (type_set)
-                settings->type = type;
-
-            if ((n = obt_xml_find_node(app->children, "decor")))
-                if (!obt_xml_node_contains(n, "default"))
-                    settings->decor = obt_xml_node_bool(n);
-
-            if ((n = obt_xml_find_node(app->children, "shade")))
-                if (!obt_xml_node_contains(n, "default"))
-                    settings->shade = obt_xml_node_bool(n);
-
-            if ((n = obt_xml_find_node(app->children, "position"))) {
-                if ((c = obt_xml_find_node(n->children, "x")))
-                    if (!obt_xml_node_contains(c, "default")) {
-                        config_parse_gravity_coord(c, &settings->position.x);
-                        x_pos_given = TRUE;
-                    }
-
-                if (x_pos_given && (c = obt_xml_find_node(n->children, "y")))
-                    if (!obt_xml_node_contains(c, "default")) {
-                        config_parse_gravity_coord(c, &settings->position.y);
-                        settings->pos_given = TRUE;
-                    }
-
-                if (settings->pos_given &&
-                    (c = obt_xml_find_node(n->children, "monitor")))
-                    if (!obt_xml_node_contains(c, "default")) {
-                        gchar *s = obt_xml_node_string(c);
-                        if (!g_ascii_strcasecmp(s, "mouse"))
-                            settings->monitor = 0;
-                        else
-                            settings->monitor = obt_xml_node_int(c);
-                        g_free(s);
-                    }
-
-                obt_xml_attr_bool(n, "force", &settings->pos_force);
-            }
-
-            if ((n = obt_xml_find_node(app->children, "focus")))
-                if (!obt_xml_node_contains(n, "default"))
-                    settings->focus = obt_xml_node_bool(n);
-
-            if ((n = obt_xml_find_node(app->children, "desktop"))) {
-                if (!obt_xml_node_contains(n, "default")) {
-                    gchar *s = obt_xml_node_string(n);
-                    if (!g_ascii_strcasecmp(s, "all"))
-                        settings->desktop = DESKTOP_ALL;
-                    else {
-                        gint i = obt_xml_node_int(n);
-                        if (i > 0)
-                            settings->desktop = i;
-                    }
-                    g_free(s);
-                }
-            }
-
-            if ((n = obt_xml_find_node(app->children, "layer")))
-                if (!obt_xml_node_contains(n, "default")) {
-                    gchar *s = obt_xml_node_string(n);
-                    if (!g_ascii_strcasecmp(s, "above"))
-                        settings->layer = 1;
-                    else if (!g_ascii_strcasecmp(s, "below"))
-                        settings->layer = -1;
-                    else
-                        settings->layer = 0;
-                    g_free(s);
-                }
+        if (!(class_set || name_set || role_set || title_set ||
+              type_set || group_class_set || group_name_set))
+            continue;
+
+        settings = config_create_app_settings();
+
+        if (name_set)
+            settings->name = g_pattern_spec_new(name);
+        if (class_set)
+            settings->class = g_pattern_spec_new(class);
+        if (group_name_set)
+            settings->group_name = g_pattern_spec_new(group_name);
+        if (group_class_set)
+            settings->group_class = g_pattern_spec_new(group_class);
+        if (role_set)
+            settings->role = g_pattern_spec_new(role);
+        if (title_set)
+            settings->title = g_pattern_spec_new(title);
+        if (type_set)
+            settings->type = type;
 
-            if ((n = obt_xml_find_node(app->children, "iconic")))
-                if (!obt_xml_node_contains(n, "default"))
-                    settings->iconic = obt_xml_node_bool(n);
-
-            if ((n = obt_xml_find_node(app->children, "skip_pager")))
-                if (!obt_xml_node_contains(n, "default"))
-                    settings->skip_pager = obt_xml_node_bool(n);
-
-            if ((n = obt_xml_find_node(app->children, "skip_taskbar")))
-                if (!obt_xml_node_contains(n, "default"))
-                    settings->skip_taskbar = obt_xml_node_bool(n);
-
-            if ((n = obt_xml_find_node(app->children, "fullscreen")))
-                if (!obt_xml_node_contains(n, "default"))
-                    settings->fullscreen = obt_xml_node_bool(n);
-
-            if ((n = obt_xml_find_node(app->children, "maximized")))
-                if (!obt_xml_node_contains(n, "default")) {
-                    gchar *s = obt_xml_node_string(n);
-                    if (!g_ascii_strcasecmp(s, "horizontal")) {
-                        settings->max_horz = TRUE;
-                        settings->max_vert = FALSE;
-                    } else if (!g_ascii_strcasecmp(s, "vertical")) {
-                        settings->max_horz = FALSE;
-                        settings->max_vert = TRUE;
-                    } else
-                        settings->max_horz = settings->max_vert =
-                            obt_xml_node_bool(n);
-                    g_free(s);
-                }
-
-            config_per_app_settings = g_slist_append(config_per_app_settings,
-                                                     (gpointer) settings);
-            g_free(name);
-            g_free(class);
-            g_free(role);
-            g_free(title);
-            name = class = role = title = NULL;
-        }
-
-        app = obt_xml_find_node(app->next, "application");
+        g_free(name);
+        g_free(class);
+        g_free(group_name);
+        g_free(group_class);
+        g_free(role);
+        g_free(title);
+        g_free(type_str);
+
+        parse_single_per_app_settings(app, settings);
+        config_per_app_settings = g_slist_append(config_per_app_settings,
+                                                 (gpointer)settings);
     }
 }
 
@@ -389,39 +443,44 @@ static void parse_per_app_settings(xmlNodePtr node, gpointer d)
 
 static void parse_key(xmlNodePtr node, GList *keylist)
 {
-    gchar *key;
+    gchar *keystring, **keys, **key;
     xmlNodePtr n;
     gboolean is_chroot = FALSE;
 
-    if (!obt_xml_attr_string(node, "key", &key))
+    if (!obt_xml_attr_string(node, "key", &keystring))
         return;
 
     obt_xml_attr_bool(node, "chroot", &is_chroot);
 
-    keylist = g_list_append(keylist, key);
+    keys = g_strsplit(keystring, " ", 0);
+    for (key = keys; *key; ++key) {
+        keylist = g_list_append(keylist, *key);
 
-    if ((n = obt_xml_find_node(node->children, "keybind"))) {
-        while (n) {
-            parse_key(n, keylist);
-            n = obt_xml_find_node(n->next, "keybind");
+        if ((n = obt_xml_find_node(node->children, "keybind"))) {
+            while (n) {
+                parse_key(n, keylist);
+                n = obt_xml_find_node(n->next, "keybind");
+            }
         }
-    }
-    else if ((n = obt_xml_find_node(node->children, "action"))) {
-        while (n) {
-            ObActionsAct *action;
-
-            action = actions_parse(n);
-            if (action)
-                keyboard_bind(keylist, action);
-            n = obt_xml_find_node(n->next, "action");
+        else if ((n = obt_xml_find_node(node->children, "action"))) {
+            while (n) {
+                ObActionsAct *action;
+
+                action = actions_parse(n);
+                if (action)
+                    keyboard_bind(keylist, action);
+                n = obt_xml_find_node(n->next, "action");
+            }
         }
-    }
 
-    if (is_chroot)
-        keyboard_chroot(keylist);
 
-    g_free(key);
-    keylist = g_list_delete_link(keylist, g_list_last(keylist));
+        if (is_chroot)
+            keyboard_chroot(keylist);
+        keylist = g_list_delete_link(keylist, g_list_last(keylist));
+    }
+
+    g_strfreev(keys);
+    g_free(keystring);
 }
 
 static void parse_keyboard(xmlNodePtr node, gpointer d)
@@ -526,8 +585,8 @@ static void parse_mouse(xmlNodePtr node, gpointer d)
                         mouse_bind(buttonstr, cx, mact, action);
                     nact = obt_xml_find_node(nact->next, "action");
                 }
-            next_nbut:
             g_free(buttonstr);
+            next_nbut:
             nbut = obt_xml_find_node(nbut->next, "mousebind");
             }
         }
@@ -569,13 +628,13 @@ static void parse_placement(xmlNodePtr node, gpointer d)
     if ((n = obt_xml_find_node(node, "policy")))
         if (obt_xml_node_contains(n, "UnderMouse"))
             config_place_policy = OB_PLACE_POLICY_MOUSE;
-    if ((n = obt_xml_find_node(node, "center")))
-        config_place_center = obt_xml_node_bool(n);
     if ((n = obt_xml_find_node(node, "monitor"))) {
         if (obt_xml_node_contains(n, "active"))
             config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
         else if (obt_xml_node_contains(n, "mouse"))
             config_place_monitor = OB_PLACE_MONITOR_MOUSE;
+        else if (obt_xml_node_contains(n, "any"))
+            config_place_monitor = OB_PLACE_MONITOR_ANY;
     }
     if ((n = obt_xml_find_node(node, "primaryMonitor"))) {
         config_primary_monitor_index = obt_xml_node_int(n);
@@ -869,9 +928,9 @@ static void parse_menu(xmlNodePtr node, gpointer d)
         config_menu_manage_desktops = obt_xml_node_bool(n);
     if ((n = obt_xml_find_node(node, "showIcons"))) {
         config_menu_show_icons = obt_xml_node_bool(n);
-#ifndef USE_IMLIB2
+#if !defined(USE_IMLIB2) && !defined(USE_LIBRSVG)
         if (config_menu_show_icons)
-            g_message(_("Openbox was compiled without Imlib2 image loading support. Icons in menus will not be loaded."));
+            g_message(_("Openbox was compiled without image loading support. Icons in menus will not be loaded."));
 #endif
     }
 
@@ -996,8 +1055,7 @@ void config_startup(ObtXmlInst *i)
     obt_xml_register(i, "focus", parse_focus, NULL);
 
     config_place_policy = OB_PLACE_POLICY_SMART;
-    config_place_center = TRUE;
-    config_place_monitor = OB_PLACE_MONITOR_ANY;
+    config_place_monitor = OB_PLACE_MONITOR_PRIMARY;
 
     config_primary_monitor_index = 1;
     config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
@@ -1062,7 +1120,7 @@ void config_startup(ObtXmlInst *i)
     obt_xml_register(i, "keyboard", parse_keyboard, NULL);
 
     config_mouse_threshold = 8;
-    config_mouse_dclicktime = 200;
+    config_mouse_dclicktime = 500;
     config_mouse_screenedgetime = 400;
     config_mouse_screenedgewarp = FALSE;
 
@@ -1115,10 +1173,12 @@ void config_shutdown(void)
 
     for (it = config_per_app_settings; it; it = g_slist_next(it)) {
         ObAppSettings *itd = (ObAppSettings *)it->data;
-        if (itd->name)  g_pattern_spec_free(itd->name);
-        if (itd->role)  g_pattern_spec_free(itd->role);
+        if (itd->name) g_pattern_spec_free(itd->name);
+        if (itd->role) g_pattern_spec_free(itd->role);
         if (itd->title) g_pattern_spec_free(itd->title);
         if (itd->class) g_pattern_spec_free(itd->class);
+        if (itd->group_name) g_pattern_spec_free(itd->group_name);
+        if (itd->group_class) g_pattern_spec_free(itd->group_class);
         g_slice_free(ObAppSettings, it->data);
     }
     g_slist_free(config_per_app_settings);