From ab6e83e9356bea6006aaf524681797f0ef6cb18e Mon Sep 17 00:00:00 2001
From: rathnor <rathnor>
Date: Thu, 1 Apr 2004 14:06:42 +0000
Subject: honour aspect ratio hints

---
 ChangeLog        |  9 ++++---
 src/WinClient.cc | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 83 insertions(+), 8 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 6d6a60a..b468e10 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,12 +1,15 @@
 (Format: Year/Month/Day)
 Changes for 0.9.9:
+*04/04/01:
+  * Support aspect ratio hints (Simon)
+    WinClient.cc
 *04/03/31:
   * Fixed _MOTIF_WM_HINTS decoration toggle bug (Henrik)  
     Window.cc
 *04/03/30:
-  * Fixed optional decoration on transient windows (Thanks Scott Moser <ssmoser at us dot ibm dot com>)
-
-  Screen.hh/cc, Window.cc, nls/C/Configmenu.m
+  * Fixed optional decoration on transient windows 
+    (Thanks Scott Moser <ssmoser at us dot ibm dot com>)
+    Screen.hh/cc, Window.cc, nls/C/Configmenu.m
 *04/03/28:
   * Fixed window snaping to screen objects (Henrik)
     Window.cc
diff --git a/src/WinClient.cc b/src/WinClient.cc
index 2524106..2265f2f 100644
--- a/src/WinClient.cc
+++ b/src/WinClient.cc
@@ -19,7 +19,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: WinClient.cc,v 1.37 2003/12/30 20:56:41 fluxgen Exp $
+// $Id: WinClient.cc,v 1.38 2004/04/01 14:06:42 rathnor Exp $
 
 #include "WinClient.hh"
 
@@ -45,8 +45,8 @@ WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin):FbTk::Fb
                      min_width(1), min_height(1),
                      max_width(0), max_height(0),
                      width_inc(1), height_inc(1),
-                     min_aspect_x(1), min_aspect_y(1),
-                     max_aspect_x(1), max_aspect_y(1),
+                     min_aspect_x(0), min_aspect_y(0),
+                     max_aspect_x(0), max_aspect_y(0),
                      base_width(1), base_height(1),
                      initial_state(0),
                      normal_hint_flags(0),
@@ -441,7 +441,7 @@ void WinClient::updateWMNormalHints() {
         max_width = 0; // unbounded
         max_height = 0;
         min_aspect_x = min_aspect_y =
-            max_aspect_x = max_aspect_y = 1;
+            max_aspect_x = max_aspect_y = 0;
         m_win_gravity = NorthWestGravity;
     } else {
         normal_hint_flags = sizehint.flags;
@@ -488,7 +488,7 @@ void WinClient::updateWMNormalHints() {
             max_aspect_y = sizehint.max_aspect.y;
         } else
             min_aspect_x = min_aspect_y =
-                max_aspect_x = max_aspect_y = 1;
+                max_aspect_x = max_aspect_y = 0;
 
         if (sizehint.flags & PWinGravity)
             m_win_gravity = sizehint.win_gravity;
@@ -630,6 +630,26 @@ void WinClient::updateWMProtocols() {
 
 }
 
+/* For aspect ratios
+   Note that its slightly simplified in that only the
+   line gradient is given - this is because for aspect
+   ratios, we always have the line going through the origin
+   
+   * Based on this formula:
+   http://astronomy.swin.edu.au/~pbourke/geometry/pointline/
+
+   Note that a gradient from origin goes through ( grad , 1 )
+ */
+
+void closestPointToLine(double &ret_x, double &ret_y, 
+                        double point_x, double point_y,
+                        double gradient) {
+    double u = (point_x * gradient + point_y) /
+        (gradient*gradient + 1);
+
+    ret_x = u*gradient;
+    ret_y = u;
+}
 
 /**
  * Changes width and height to the nearest (lower) value
@@ -660,6 +680,58 @@ void WinClient::applySizeHints(int &width, int &height,
     if (max_height > 0 && height > static_cast<signed>(max_height))
         height = max_height;
 
+    // we apply aspect ratios before incrementals
+    // Too difficult to exactly satisfy both incremental+aspect 
+    // in most situations 
+    // (they really shouldn't happen at the same time anyway).
+
+    /* aspect ratios are applied exclusive to the base_width
+     *
+     * min_aspect_x      width      max_aspect_x
+     * ------------  <  -------  <  ------------
+     * min_aspect_y      height     max_aspect_y
+     *
+     * beware of integer maximum (so I'll use doubles instead and divide)
+     *
+     * The trick is how to get back to the aspect ratio with minimal
+     * change - do we modify x, y or both?
+     * A: we minimise the distance between the current point, and
+     *    the target aspect ratio (consider them as x,y coordinates)
+     *  Consider that the aspect ratio is a line, and the current
+     *  w/h is a point, so we're just using the formula for
+     *  shortest distance from a point to a line!
+     */
+
+    if (min_aspect_y > 0 && max_aspect_y > 0 &&
+        (height - base_height) > 0) {
+        double widthd = static_cast<double>(width - base_width);
+        double heightd = static_cast<double>(height - base_height);
+
+        double min = static_cast<double>(min_aspect_x) / 
+            static_cast<double>(min_aspect_y); 
+
+        double max = static_cast<double>(max_aspect_x) / 
+            static_cast<double>(max_aspect_y); 
+
+        double actual = widthd / heightd;
+
+        if (max > 0 && min > 0 && actual > 0) { // don't even try otherwise
+            bool changed = false;
+            if (actual < min) {
+                changed = true;
+                closestPointToLine(widthd, heightd, widthd, heightd, min);
+            } else if (actual > max) {
+                changed = true;
+                closestPointToLine(widthd, heightd, widthd, heightd, max);
+            }
+
+            if (changed) {
+                width = static_cast<int>(widthd) + base_width;
+                height = static_cast<int>(heightd) + base_height;
+            }
+        }
+    }
+
     // enforce incremental size limits, wrt base size
     // only calculate this if we really need to
     i = (width - base_width) / width_inc;
-- 
cgit v0.11.2