move size hint code to FbWinFrame
This commit is contained in:
parent
80059c6dae
commit
4fa3773267
5 changed files with 167 additions and 160 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
132
src/WinClient.cc
132
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue