From 4fa3773267362f8ca9f653bb8ee7c98baa09d5fd Mon Sep 17 00:00:00 2001 From: Mark Tiefenbruck 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(m_size_hints.min_width)) + width = m_size_hints.min_width; + + if (height < 0 || height < static_cast(m_size_hints.min_height)) + height = m_size_hints.min_height; + + // Check maximum size + if (m_size_hints.max_width > 0 && width > static_cast(m_size_hints.max_width)) + width = m_size_hints.max_width; + + if (m_size_hints.max_height > 0 && height > static_cast(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(width - m_size_hints.base_width); + double heightd = static_cast(height - m_size_hints.base_height); + + double min = static_cast(m_size_hints.min_aspect_x) / + static_cast(m_size_hints.min_aspect_y); + + double max = static_cast(m_size_hints.max_aspect_x) / + static_cast(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(widthd) + m_size_hints.base_width; + height = static_cast(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(m_size_hints.base_width)) / + static_cast(m_size_hints.width_inc); + width = i*static_cast(m_size_hints.width_inc) + + static_cast(m_size_hints.base_width); + + j = (height - static_cast(m_size_hints.base_height)) / + static_cast(m_size_hints.height_inc); + height = j*static_cast(m_size_hints.height_inc) + + static_cast(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 &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(m_size_hints.min_width)) - width = m_size_hints.min_width; - - if (height < 0 || height < static_cast(m_size_hints.min_height)) - height = m_size_hints.min_height; - - // Check maximum size - if (m_size_hints.max_width > 0 && width > static_cast(m_size_hints.max_width)) - width = m_size_hints.max_width; - - if (m_size_hints.max_height > 0 && height > static_cast(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(width - m_size_hints.base_width); - double heightd = static_cast(height - m_size_hints.base_height); - - double min = static_cast(m_size_hints.min_aspect_x) / - static_cast(m_size_hints.min_aspect_y); - - double max = static_cast(m_size_hints.max_aspect_x) / - static_cast(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(widthd) + m_size_hints.base_width; - height = static_cast(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(m_size_hints.base_width)) / - static_cast(m_size_hints.width_inc); - width = i*static_cast(m_size_hints.width_inc) + - static_cast(m_size_hints.base_width); - - j = (height - static_cast(m_size_hints.base_height)) / - static_cast(m_size_hints.height_inc); - height = j*static_cast(m_size_hints.height_inc) + - static_cast(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