move size hint code to FbWinFrame

This commit is contained in:
Mark Tiefenbruck 2008-08-15 04:04:56 -07:00
parent 80059c6dae
commit 4fa3773267
5 changed files with 167 additions and 160 deletions

View file

@ -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;

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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;