Fix negative ResizeRelative values with terminal windows (Fix bug 5228)
[dana/openbox.git] / openbox / actions / resizerelative.c
index f705c29..a473910 100644 (file)
@@ -2,54 +2,61 @@
 #include "openbox/client.h"
 #include "openbox/screen.h"
 #include "openbox/frame.h"
-#include <stdlib.h> /* for atoi */
+#include "openbox/config.h"
 
 typedef struct {
     gint left;
+    gint left_denom;
     gint right;
+    gint right_denom;
     gint top;
+    gint top_denom;
     gint bottom;
+    gint bottom_denom;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
+static gpointer setup_func(xmlNodePtr node);
 static void     free_func(gpointer options);
 static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_resizerelative_startup(void)
 {
-    actions_register("ResizeRelative",
-                     setup_func,
-                     free_func,
-                     run_func,
-                     NULL, NULL);
+    actions_register("ResizeRelative", setup_func, free_func, run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static void xml_node_relative(xmlNodePtr n, gint *num, gint *denom)
+{
+    gchar *s;
+
+    s = obt_xml_node_string(n);
+    config_parse_relative_number(s, num, denom);
+    g_free(s);
+}
+
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
 
-    o = g_new0(Options, 1);
+    o = g_slice_new0(Options);
 
-    if ((n = parse_find_node("left", node)))
-        o->left = parse_int(doc, n);
-    if ((n = parse_find_node("right", node)))
-        o->right = parse_int(doc, n);
-    if ((n = parse_find_node("top", node)) ||
-        (n = parse_find_node("up", node)))
-        o->top = parse_int(doc, n);
-    if ((n = parse_find_node("bottom", node)) ||
-        (n = parse_find_node("down", node)))
-        o->bottom = parse_int(doc, n);
+    if ((n = obt_xml_find_node(node, "left")))
+        xml_node_relative(n, &o->left, &o->left_denom);
+    if ((n = obt_xml_find_node(node, "right")))
+        xml_node_relative(n, &o->right, &o->right_denom);
+    if ((n = obt_xml_find_node(node, "top")) ||
+        (n = obt_xml_find_node(node, "up")))
+        xml_node_relative(n, &o->top, &o->top_denom);
+    if ((n = obt_xml_find_node(node, "bottom")) ||
+        (n = obt_xml_find_node(node, "down")))
+        xml_node_relative(n, &o->bottom, &o->bottom_denom);
 
     return o;
 }
 
-static void free_func(gpointer options)
+static void free_func(gpointer o)
 {
-    Options *o = options;
-
-    g_free(o);
+    g_slice_free(Options, o);
 }
 
 /* Always return FALSE because its not interactive */
@@ -60,17 +67,37 @@ static gboolean run_func(ObActionsData *data, gpointer options)
     if (data->client) {
         ObClient *c = data->client;
         gint x, y, ow, xoff, nw, oh, yoff, nh, lw, lh;
+        gint left = o->left, right = o->right, top = o->top, bottom = o->bottom;
+
+        if (o->left_denom)
+            left = left * c->area.width / o->left_denom;
+        if (o->right_denom)
+            right = right * c->area.width / o->right_denom;
+        if (o->top_denom)
+            top = top * c->area.height / o->top_denom;
+        if (o->bottom_denom)
+            bottom = bottom * c->area.height / o->bottom_denom;
+
+        if (left && ABS(left) < c->size_inc.width)
+            left = left < 0 ? -c->size_inc.width : c->size_inc.width;
+        if (right && ABS(right) < c->size_inc.width)
+            right = right < 0 ? -c->size_inc.width : c->size_inc.width;
+        if (top && ABS(top) < c->size_inc.height)
+            top = top < 0 ? -c->size_inc.height : c->size_inc.height;
+        if (bottom && ABS(bottom) < c->size_inc.height)
+            bottom = bottom < 0 ? -c->size_inc.height : c->size_inc.height;
 
+        // When resizing, if the resize has a non-zero value then make sure it
+        // is at least as big as the size increment so the window does actually
+        // resize.
         x = c->area.x;
         y = c->area.y;
         ow = c->area.width;
-        xoff = -o->left * c->size_inc.width;
-        nw = ow + o->right * c->size_inc.width
-            + o->left * c->size_inc.width;
+        xoff = -left;
+        nw = ow + right + left;
         oh = c->area.height;
-        yoff = -o->top * c->size_inc.height;
-        nh = oh + o->bottom * c->size_inc.height
-            + o->top * c->size_inc.height;
+        yoff = -top;
+        nh = oh + bottom + top;
 
         client_try_configure(c, &x, &y, &nw, &nh, &lw, &lh, TRUE);
         xoff = xoff == 0 ? 0 :