From 4fa3773267362f8ca9f653bb8ee7c98baa09d5fd Mon Sep 17 00:00:00 2001
From: Mark Tiefenbruck <mark@fluxbox.org>
Date: Fri, 15 Aug 2008 04:04:56 -0700
Subject: move size hint code to FbWinFrame

---
 src/FbWinFrame.cc | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/FbWinFrame.hh |  28 ++++++++++++
 src/WinClient.cc  | 132 ------------------------------------------------------
 src/WinClient.hh  |  29 ++----------
 src/Window.cc     |   6 ++-
 5 files changed, 167 insertions(+), 160 deletions(-)

diff --git a/src/FbWinFrame.cc b/src/FbWinFrame.cc
index afd5fb5..4734b2b 100644
--- a/src/FbWinFrame.cc
+++ b/src/FbWinFrame.cc
@@ -1459,6 +1459,138 @@ void FbWinFrame::applyDecorations() {
         frameExtentSig().notify();
 }
 
+/* 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
+ * that conforms to it's size hints.
+ *
+ * display_* give the values that would be displayed
+ * to the user when resizing.
+ * We use pointers for display_* since they are optional.
+ *
+ * See ICCCM section 4.1.2.3
+ */
+void FbWinFrame::applySizeHints(int &width, int &height,
+                                int *display_width, int *display_height,
+                                bool maximizing) {
+
+    int i = width, j = height;
+
+    // Check minimum size
+    if (width < 0 || width < static_cast<signed>(m_size_hints.min_width))
+        width = m_size_hints.min_width;
+
+    if (height < 0 || height < static_cast<signed>(m_size_hints.min_height))
+        height = m_size_hints.min_height;
+
+    // Check maximum size
+    if (m_size_hints.max_width > 0 && width > static_cast<signed>(m_size_hints.max_width))
+        width = m_size_hints.max_width;
+
+    if (m_size_hints.max_height > 0 && height > static_cast<signed>(m_size_hints.max_height))
+        height = m_size_hints.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 m_size_hints.base_width
+     *
+     * m_size_hints.min_aspect_x      width      m_size_hints.max_aspect_x
+     * ------------  <  -------  <  ------------
+     * m_size_hints.min_aspect_y      height     m_size_hints.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!
+     *
+     * When maximizing, we must not increase any of the sizes, because we
+     * would end up with the window partly off a screen, so a simpler formula
+     * is used in that case.
+     */
+
+    if (m_size_hints.min_aspect_y > 0 && m_size_hints.max_aspect_y > 0 &&
+        (height - m_size_hints.base_height) > 0) {
+        double widthd = static_cast<double>(width - m_size_hints.base_width);
+        double heightd = static_cast<double>(height - m_size_hints.base_height);
+
+        double min = static_cast<double>(m_size_hints.min_aspect_x) /
+            static_cast<double>(m_size_hints.min_aspect_y);
+
+        double max = static_cast<double>(m_size_hints.max_aspect_x) /
+            static_cast<double>(m_size_hints.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;
+                if (maximizing)
+                    heightd = widthd / min;
+                else
+                    closestPointToLine(widthd, heightd, widthd, heightd, min);
+            } else if (actual > max) {
+                changed = true;
+                if (maximizing)
+                    widthd = heightd * max;
+                else
+                    closestPointToLine(widthd, heightd, widthd, heightd, max);
+            }
+
+            if (changed) {
+                width = static_cast<int>(widthd) + m_size_hints.base_width;
+                height = static_cast<int>(heightd) + m_size_hints.base_height;
+            }
+        }
+    }
+
+    // enforce incremental size limits, wrt base size
+    // only calculate this if we really need to
+    i = (width - static_cast<signed>(m_size_hints.base_width)) /
+        static_cast<signed>(m_size_hints.width_inc);
+    width = i*static_cast<signed>(m_size_hints.width_inc) +
+        static_cast<signed>(m_size_hints.base_width);
+
+    j = (height - static_cast<signed>(m_size_hints.base_height)) /
+        static_cast<signed>(m_size_hints.height_inc);
+    height = j*static_cast<signed>(m_size_hints.height_inc) +
+        static_cast<signed>(m_size_hints.base_height);
+
+    if (display_width)
+        *display_width = i;
+
+    if (display_height)
+        *display_height = j;
+}
+
 bool FbWinFrame::setBorderWidth(bool do_move) {
     unsigned int border_width = theme()->border().width();
     unsigned int win_bw = m_decoration_mask & DECORM_BORDER ? border_width : 0;
diff --git a/src/FbWinFrame.hh b/src/FbWinFrame.hh
index e24612e..d2a27c9 100644
--- a/src/FbWinFrame.hh
+++ b/src/FbWinFrame.hh
@@ -95,6 +95,21 @@ public:
         DECOR_TAB = DECORM_BORDER|DECORM_MENU|DECORM_TAB
     };
 
+    typedef struct SizeHints {
+        unsigned int min_width;
+        unsigned int max_width;
+        unsigned int min_height;
+        unsigned int max_height;
+        unsigned int width_inc;
+        unsigned int height_inc;
+        unsigned int min_aspect_x;
+        unsigned int max_aspect_x;
+        unsigned int min_aspect_y;
+        unsigned int max_aspect_y;
+        unsigned int base_width;
+        unsigned int base_height;
+    } SizeHints;
+
     /// create a top level window
     FbWinFrame(BScreen &screen, FocusableTheme<FbWinFrameTheme> &theme,
                FbTk::ImageControl &imgctrl,
@@ -185,6 +200,18 @@ public:
     /// remove any handler for the windows
     void removeEventHandler();
 
+    /**
+     * Changes width and height to the nearest (lower) value
+     * that conforms to it's size hints.
+     *
+     * display_* give the values that would be displayed
+     * to the user when resizing.
+     * We use pointers for display_* since they are optional.
+     */
+    void applySizeHints(int &width, int &height, int *display_width = 0,
+            int *display_height = 0, bool maximizing = false);
+    void setSizeHints(const SizeHints &hint) { m_size_hints = hint; }
+
     void setDecorationMask(unsigned int mask) { m_decoration_mask = mask; }
     void applyDecorations();
 
@@ -392,6 +419,7 @@ private:
     // last gravity that this window was *actively* placed with
     int m_active_gravity;
     unsigned int m_active_orig_client_bw;
+    SizeHints m_size_hints;
 
     bool m_need_render;
     int m_button_size; ///< size for all titlebar buttons
diff --git a/src/WinClient.cc b/src/WinClient.cc
index 9aac38d..b9602ec 100644
--- a/src/WinClient.cc
+++ b/src/WinClient.cc
@@ -690,138 +690,6 @@ 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
- * that conforms to it's size hints.
- *
- * display_* give the values that would be displayed
- * to the user when resizing.
- * We use pointers for display_* since they are optional.
- *
- * See ICCCM section 4.1.2.3
- */
-void WinClient::applySizeHints(int &width, int &height,
-                               int *display_width, int *display_height,
-                               bool maximizing) {
-
-    int i = width, j = height;
-
-    // Check minimum size
-    if (width < 0 || width < static_cast<signed>(m_size_hints.min_width))
-        width = m_size_hints.min_width;
-
-    if (height < 0 || height < static_cast<signed>(m_size_hints.min_height))
-        height = m_size_hints.min_height;
-
-    // Check maximum size
-    if (m_size_hints.max_width > 0 && width > static_cast<signed>(m_size_hints.max_width))
-        width = m_size_hints.max_width;
-
-    if (m_size_hints.max_height > 0 && height > static_cast<signed>(m_size_hints.max_height))
-        height = m_size_hints.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 m_size_hints.base_width
-     *
-     * m_size_hints.min_aspect_x      width      m_size_hints.max_aspect_x
-     * ------------  <  -------  <  ------------
-     * m_size_hints.min_aspect_y      height     m_size_hints.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!
-     *
-     * When maximizing, we must not increase any of the sizes, because we
-     * would end up with the window partly off a screen, so a simpler formula
-     * is used in that case.
-     */
-
-    if (m_size_hints.min_aspect_y > 0 && m_size_hints.max_aspect_y > 0 &&
-        (height - m_size_hints.base_height) > 0) {
-        double widthd = static_cast<double>(width - m_size_hints.base_width);
-        double heightd = static_cast<double>(height - m_size_hints.base_height);
-
-        double min = static_cast<double>(m_size_hints.min_aspect_x) /
-            static_cast<double>(m_size_hints.min_aspect_y);
-
-        double max = static_cast<double>(m_size_hints.max_aspect_x) /
-            static_cast<double>(m_size_hints.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;
-                if (maximizing)
-                    heightd = widthd / min;
-                else
-                    closestPointToLine(widthd, heightd, widthd, heightd, min);
-            } else if (actual > max) {
-                changed = true;
-                if (maximizing)
-                    widthd = heightd * max;
-                else
-                    closestPointToLine(widthd, heightd, widthd, heightd, max);
-            }
-
-            if (changed) {
-                width = static_cast<int>(widthd) + m_size_hints.base_width;
-                height = static_cast<int>(heightd) + m_size_hints.base_height;
-            }
-        }
-    }
-
-    // enforce incremental size limits, wrt base size
-    // only calculate this if we really need to
-    i = (width - static_cast<signed>(m_size_hints.base_width)) /
-        static_cast<signed>(m_size_hints.width_inc);
-    width = i*static_cast<signed>(m_size_hints.width_inc) +
-        static_cast<signed>(m_size_hints.base_width);
-
-    j = (height - static_cast<signed>(m_size_hints.base_height)) /
-        static_cast<signed>(m_size_hints.height_inc);
-    height = j*static_cast<signed>(m_size_hints.height_inc) +
-        static_cast<signed>(m_size_hints.base_height);
-
-    if (display_width)
-        *display_width = i;
-
-    if (display_height)
-        *display_height = j;
-}
-
 // check if the given width and height satisfy the size hints
 bool WinClient::checkSizeHints(unsigned int width, unsigned int height) {
     if (width < m_size_hints.min_width || height < m_size_hints.min_height)
diff --git a/src/WinClient.hh b/src/WinClient.hh
index 51d3b3e..9c6dc9e 100644
--- a/src/WinClient.hh
+++ b/src/WinClient.hh
@@ -22,6 +22,7 @@
 #ifndef WINCLIENT_HH
 #define WINCLIENT_HH
 
+#include "FbWinFrame.hh"
 #include "Window.hh"
 #include "FbTk/FbWindow.hh"
 #include "FbTk/FbString.hh"
@@ -43,21 +44,6 @@ public:
         unsigned long decorations; // Motif wm decorations
     } MwmHints;
 
-    typedef struct SizeHints {
-        unsigned int min_width;
-        unsigned int max_width;
-        unsigned int min_height;
-        unsigned int max_height;
-        unsigned int width_inc;
-        unsigned int height_inc;
-        unsigned int min_aspect_x;
-        unsigned int max_aspect_x;
-        unsigned int min_aspect_y;
-        unsigned int max_aspect_y;
-        unsigned int base_width;
-        unsigned int base_height;
-    } SizeHints;
-
     WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin = 0);
 
     ~WinClient();
@@ -95,16 +81,6 @@ public:
     void setAttentionState(bool value);
     const std::string &title() const { return m_title; }
 
-    /**
-     * Changes width and height to the nearest (lower) value
-     * that conforms to it's size hints.
-     *
-     * display_* give the values that would be displayed
-     * to the user when resizing.
-     * We use pointers for display_* since they are optional.
-     */
-    void applySizeHints(int &width, int &height, int *display_width = 0,
-            int *display_height = 0, bool maximizing = false);
     bool checkSizeHints(unsigned int width, unsigned int height);
 
     void setGroupLeftWindow(Window win);
@@ -143,6 +119,7 @@ public:
     Window getGroupLeftWindow() const;
 
     const MwmHints *getMwmHint() const { return m_mwm_hint; }
+    const FbWinFrame::SizeHints &sizeHints() const { return m_size_hints; }
 
     unsigned int minWidth() const { return m_size_hints.min_width; }
     unsigned int minHeight() const { return m_size_hints.min_height; }
@@ -187,7 +164,7 @@ private:
 
     Focusable::WindowType m_window_type;
     MwmHints *m_mwm_hint;
-    SizeHints m_size_hints;
+    FbWinFrame::SizeHints m_size_hints;
 
     Strut *m_strut;
     // map transient_for X window to winclient transient 
diff --git a/src/Window.cc b/src/Window.cc
index 651b995..45c1e9d 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -552,7 +552,7 @@ void FluxboxWindow::init() {
 
     int real_width = frame().width();
     int real_height = frame().height() - frame().titlebarHeight() - frame().handleHeight();
-    m_client->applySizeHints(real_width, real_height);
+    frame().applySizeHints(real_width, real_height);
     real_height += frame().titlebarHeight() + frame().handleHeight();
 
     if (m_placed)
@@ -1066,6 +1066,7 @@ bool FluxboxWindow::setCurrentClient(WinClient &client, bool setinput) {
     // frame focused doesn't necessarily mean input focused
     frame().setLabelButtonFocus(*button);
     frame().setShapingClient(&client, false);
+    frame().setSizeHints(client.sizeHints());
     return ret;
 }
 
@@ -1090,6 +1091,7 @@ void FluxboxWindow::associateClientWindow(bool use_attrs,
         frame().resizeForClient(m_client->width(), m_client->height());
 
     frame().setActiveGravity(m_client->gravity(), m_client->old_bw);
+    frame().setSizeHints(m_client->sizeHints());
     frame().setClientWindow(*m_client);
 }
 
@@ -3728,7 +3730,7 @@ void FluxboxWindow::fixsize(int *user_w, int *user_h, bool maximizing) {
     // dy = new height (w/o decorations), similarly
     int dh = m_last_resize_h - decoration_height;
 
-    m_client->applySizeHints(dw, dh, user_w, user_h, maximizing);
+    frame().applySizeHints(dw, dh, user_w, user_h, maximizing);
 
     // update last resize
     m_last_resize_w = dw;
-- 
cgit v0.11.2