move size hint code to methods in size hint struct, restructure them a little
This commit is contained in:
parent
4fa3773267
commit
6053ecc1b5
5 changed files with 138 additions and 178 deletions
|
@ -1459,138 +1459,6 @@ void FbWinFrame::applyDecorations() {
|
||||||
frameExtentSig().notify();
|
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) {
|
bool FbWinFrame::setBorderWidth(bool do_move) {
|
||||||
unsigned int border_width = theme()->border().width();
|
unsigned int border_width = theme()->border().width();
|
||||||
unsigned int win_bw = m_decoration_mask & DECORM_BORDER ? border_width : 0;
|
unsigned int win_bw = m_decoration_mask & DECORM_BORDER ? border_width : 0;
|
||||||
|
@ -1800,3 +1668,124 @@ int FbWinFrame::yOffset() const {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 closestPointToAspect(unsigned int &ret_x, unsigned int &ret_y,
|
||||||
|
unsigned int point_x, unsigned int point_y,
|
||||||
|
unsigned int aspect_x, unsigned int aspect_y) {
|
||||||
|
double u = static_cast<double>(point_x * aspect_x + point_y * aspect_y) /
|
||||||
|
static_cast<double>(aspect_x * aspect_x + aspect_y * aspect_y);
|
||||||
|
|
||||||
|
ret_x = static_cast<unsigned int>(u * aspect_x);
|
||||||
|
ret_y = static_cast<unsigned int>(u * aspect_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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::SizeHints::apply(unsigned int &width, unsigned int &height,
|
||||||
|
bool maximizing) const {
|
||||||
|
|
||||||
|
// 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 size
|
||||||
|
*
|
||||||
|
* 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!
|
||||||
|
*
|
||||||
|
* 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 (min_aspect_y > 0 && width*min_aspect_y < min_aspect_x*height) {
|
||||||
|
if (maximizing)
|
||||||
|
height = width * min_aspect_y / min_aspect_x;
|
||||||
|
else
|
||||||
|
closestPointToAspect(width, height, width, height,
|
||||||
|
min_aspect_x, min_aspect_y);
|
||||||
|
} else if (max_aspect_x > 0 && width*max_aspect_y > max_aspect_x*height) {
|
||||||
|
if (maximizing)
|
||||||
|
width = height * max_aspect_x / max_aspect_y;
|
||||||
|
else
|
||||||
|
closestPointToAspect(width, height, width, height,
|
||||||
|
max_aspect_x, max_aspect_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check minimum size
|
||||||
|
if (width < min_width)
|
||||||
|
width = min_width;
|
||||||
|
|
||||||
|
if (height < min_height)
|
||||||
|
height = min_height;
|
||||||
|
|
||||||
|
// Check maximum size
|
||||||
|
if (max_width > 0 && width > max_width)
|
||||||
|
width = max_width;
|
||||||
|
|
||||||
|
if (max_height > 0 && height > max_height)
|
||||||
|
height = max_height;
|
||||||
|
|
||||||
|
// enforce incremental size limits, wrt base size
|
||||||
|
width -= (width - base_width) % width_inc;
|
||||||
|
height -= (height - base_height) % height_inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the given width and height satisfy the size hints
|
||||||
|
bool FbWinFrame::SizeHints::valid(unsigned int w, unsigned int h) const {
|
||||||
|
if (w < min_width || h < min_height)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (w > max_width || h > max_height)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((w - base_width) % width_inc != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((h - base_height) % height_inc != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (min_aspect_x * h > w * min_aspect_y)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (max_aspect_x * h < w * max_aspect_y)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FbWinFrame::SizeHints::displaySize(int &i, int &j,
|
||||||
|
unsigned int width, unsigned int height) const {
|
||||||
|
i = static_cast<signed>(width - base_width) / width_inc;
|
||||||
|
j = static_cast<signed>(height - base_height) / height_inc;
|
||||||
|
}
|
||||||
|
|
|
@ -96,6 +96,11 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct SizeHints {
|
typedef struct SizeHints {
|
||||||
|
void apply(unsigned int &w, unsigned int &h,
|
||||||
|
bool maximizing = false) const;
|
||||||
|
bool valid(unsigned int width, unsigned int height) const;
|
||||||
|
void displaySize(int &i, int &j,
|
||||||
|
unsigned int width, unsigned int height) const;
|
||||||
unsigned int min_width;
|
unsigned int min_width;
|
||||||
unsigned int max_width;
|
unsigned int max_width;
|
||||||
unsigned int min_height;
|
unsigned int min_height;
|
||||||
|
@ -200,16 +205,7 @@ public:
|
||||||
/// remove any handler for the windows
|
/// remove any handler for the windows
|
||||||
void removeEventHandler();
|
void removeEventHandler();
|
||||||
|
|
||||||
/**
|
const SizeHints &sizeHints() const { return m_size_hints; }
|
||||||
* 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 setSizeHints(const SizeHints &hint) { m_size_hints = hint; }
|
||||||
|
|
||||||
void setDecorationMask(unsigned int mask) { m_decoration_mask = mask; }
|
void setDecorationMask(unsigned int mask) { m_decoration_mask = mask; }
|
||||||
|
|
|
@ -690,31 +690,6 @@ void WinClient::updateWMProtocols() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (width > m_size_hints.max_width || height > m_size_hints.max_height)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ((width - m_size_hints.base_width) % m_size_hints.width_inc != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ((height - m_size_hints.base_height) % m_size_hints.height_inc != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
double ratio = (double)width / (double)height;
|
|
||||||
|
|
||||||
if (m_size_hints.min_aspect_y > 0 && (double)m_size_hints.min_aspect_x / (double)m_size_hints.min_aspect_y > ratio)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_size_hints.max_aspect_y > 0 && (double)m_size_hints.max_aspect_x / (double)m_size_hints.max_aspect_y < ratio)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WinClient::removeTransientFromWaitingList() {
|
void WinClient::removeTransientFromWaitingList() {
|
||||||
|
|
||||||
// holds the windows that dont have empty
|
// holds the windows that dont have empty
|
||||||
|
|
|
@ -81,8 +81,6 @@ public:
|
||||||
void setAttentionState(bool value);
|
void setAttentionState(bool value);
|
||||||
const std::string &title() const { return m_title; }
|
const std::string &title() const { return m_title; }
|
||||||
|
|
||||||
bool checkSizeHints(unsigned int width, unsigned int height);
|
|
||||||
|
|
||||||
void setGroupLeftWindow(Window win);
|
void setGroupLeftWindow(Window win);
|
||||||
|
|
||||||
void saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs, int nelements);
|
void saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs, int nelements);
|
||||||
|
|
|
@ -550,9 +550,9 @@ void FluxboxWindow::init() {
|
||||||
}
|
}
|
||||||
#endif // DEBUG
|
#endif // DEBUG
|
||||||
|
|
||||||
int real_width = frame().width();
|
unsigned int real_width = frame().width();
|
||||||
int real_height = frame().height() - frame().titlebarHeight() - frame().handleHeight();
|
unsigned int real_height = frame().height() - frame().titlebarHeight() - frame().handleHeight();
|
||||||
frame().applySizeHints(real_width, real_height);
|
frame().sizeHints().apply(real_width, real_height);
|
||||||
real_height += frame().titlebarHeight() + frame().handleHeight();
|
real_height += frame().titlebarHeight() + frame().handleHeight();
|
||||||
|
|
||||||
if (m_placed)
|
if (m_placed)
|
||||||
|
@ -2483,12 +2483,12 @@ void FluxboxWindow::configureRequestEvent(XConfigureRequestEvent &cr) {
|
||||||
// make sure the new width/height would be ok with all clients, or else they
|
// make sure the new width/height would be ok with all clients, or else they
|
||||||
// could try to resize the window back and forth
|
// could try to resize the window back and forth
|
||||||
if (cr.value_mask & CWWidth || cr.value_mask & CWHeight) {
|
if (cr.value_mask & CWWidth || cr.value_mask & CWHeight) {
|
||||||
int new_w = (cr.value_mask & CWWidth) ? cr.width : cw;
|
unsigned int new_w = (cr.value_mask & CWWidth) ? cr.width : cw;
|
||||||
int new_h = (cr.value_mask & CWHeight) ? cr.height : ch;
|
unsigned int new_h = (cr.value_mask & CWHeight) ? cr.height : ch;
|
||||||
ClientList::iterator it = clientList().begin();
|
ClientList::iterator it = clientList().begin();
|
||||||
ClientList::iterator it_end = clientList().end();
|
ClientList::iterator it_end = clientList().end();
|
||||||
for (; it != it_end; ++it) {
|
for (; it != it_end; ++it) {
|
||||||
if (*it != client && !(*it)->checkSizeHints(new_w, new_h))
|
if (*it != client && !(*it)->sizeHints().valid(new_w, new_h))
|
||||||
cr.value_mask = cr.value_mask & ~(CWWidth | CWHeight);
|
cr.value_mask = cr.value_mask & ~(CWWidth | CWHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3725,12 +3725,14 @@ void FluxboxWindow::fixsize(int *user_w, int *user_h, bool maximizing) {
|
||||||
|
|
||||||
// dx is new width = current width + difference between new and old x values
|
// dx is new width = current width + difference between new and old x values
|
||||||
//int dx = frame().width() + frame().x() - m_last_resize_x;
|
//int dx = frame().width() + frame().x() - m_last_resize_x;
|
||||||
int dw = m_last_resize_w;
|
unsigned int dw = m_last_resize_w;
|
||||||
|
|
||||||
// dy = new height (w/o decorations), similarly
|
// dy = new height (w/o decorations), similarly
|
||||||
int dh = m_last_resize_h - decoration_height;
|
unsigned int dh = m_last_resize_h - decoration_height;
|
||||||
|
|
||||||
frame().applySizeHints(dw, dh, user_w, user_h, maximizing);
|
frame().sizeHints().apply(dw, dh, maximizing);
|
||||||
|
if (user_w && user_h)
|
||||||
|
frame().sizeHints().displaySize(*user_w, *user_h, dw, dh);
|
||||||
|
|
||||||
// update last resize
|
// update last resize
|
||||||
m_last_resize_w = dw;
|
m_last_resize_w = dw;
|
||||||
|
|
Loading…
Reference in a new issue