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();
|
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;
|
||||||
|
|
|
@ -95,6 +95,21 @@ public:
|
||||||
DECOR_TAB = DECORM_BORDER|DECORM_MENU|DECORM_TAB
|
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
|
/// create a top level window
|
||||||
FbWinFrame(BScreen &screen, FocusableTheme<FbWinFrameTheme> &theme,
|
FbWinFrame(BScreen &screen, FocusableTheme<FbWinFrameTheme> &theme,
|
||||||
FbTk::ImageControl &imgctrl,
|
FbTk::ImageControl &imgctrl,
|
||||||
|
@ -185,6 +200,18 @@ public:
|
||||||
/// remove any handler for the windows
|
/// remove any handler for the windows
|
||||||
void removeEventHandler();
|
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 setDecorationMask(unsigned int mask) { m_decoration_mask = mask; }
|
||||||
void applyDecorations();
|
void applyDecorations();
|
||||||
|
|
||||||
|
@ -392,6 +419,7 @@ private:
|
||||||
// last gravity that this window was *actively* placed with
|
// last gravity that this window was *actively* placed with
|
||||||
int m_active_gravity;
|
int m_active_gravity;
|
||||||
unsigned int m_active_orig_client_bw;
|
unsigned int m_active_orig_client_bw;
|
||||||
|
SizeHints m_size_hints;
|
||||||
|
|
||||||
bool m_need_render;
|
bool m_need_render;
|
||||||
int m_button_size; ///< size for all titlebar buttons
|
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
|
// check if the given width and height satisfy the size hints
|
||||||
bool WinClient::checkSizeHints(unsigned int width, unsigned int height) {
|
bool WinClient::checkSizeHints(unsigned int width, unsigned int height) {
|
||||||
if (width < m_size_hints.min_width || height < m_size_hints.min_height)
|
if (width < m_size_hints.min_width || height < m_size_hints.min_height)
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#ifndef WINCLIENT_HH
|
#ifndef WINCLIENT_HH
|
||||||
#define WINCLIENT_HH
|
#define WINCLIENT_HH
|
||||||
|
|
||||||
|
#include "FbWinFrame.hh"
|
||||||
#include "Window.hh"
|
#include "Window.hh"
|
||||||
#include "FbTk/FbWindow.hh"
|
#include "FbTk/FbWindow.hh"
|
||||||
#include "FbTk/FbString.hh"
|
#include "FbTk/FbString.hh"
|
||||||
|
@ -43,21 +44,6 @@ public:
|
||||||
unsigned long decorations; // Motif wm decorations
|
unsigned long decorations; // Motif wm decorations
|
||||||
} MwmHints;
|
} 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(Window win, BScreen &screen, FluxboxWindow *fbwin = 0);
|
||||||
|
|
||||||
~WinClient();
|
~WinClient();
|
||||||
|
@ -95,16 +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; }
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
bool checkSizeHints(unsigned int width, unsigned int height);
|
||||||
|
|
||||||
void setGroupLeftWindow(Window win);
|
void setGroupLeftWindow(Window win);
|
||||||
|
@ -143,6 +119,7 @@ public:
|
||||||
Window getGroupLeftWindow() const;
|
Window getGroupLeftWindow() const;
|
||||||
|
|
||||||
const MwmHints *getMwmHint() const { return m_mwm_hint; }
|
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 minWidth() const { return m_size_hints.min_width; }
|
||||||
unsigned int minHeight() const { return m_size_hints.min_height; }
|
unsigned int minHeight() const { return m_size_hints.min_height; }
|
||||||
|
@ -187,7 +164,7 @@ private:
|
||||||
|
|
||||||
Focusable::WindowType m_window_type;
|
Focusable::WindowType m_window_type;
|
||||||
MwmHints *m_mwm_hint;
|
MwmHints *m_mwm_hint;
|
||||||
SizeHints m_size_hints;
|
FbWinFrame::SizeHints m_size_hints;
|
||||||
|
|
||||||
Strut *m_strut;
|
Strut *m_strut;
|
||||||
// map transient_for X window to winclient transient
|
// map transient_for X window to winclient transient
|
||||||
|
|
|
@ -552,7 +552,7 @@ void FluxboxWindow::init() {
|
||||||
|
|
||||||
int real_width = frame().width();
|
int real_width = frame().width();
|
||||||
int real_height = frame().height() - frame().titlebarHeight() - frame().handleHeight();
|
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();
|
real_height += frame().titlebarHeight() + frame().handleHeight();
|
||||||
|
|
||||||
if (m_placed)
|
if (m_placed)
|
||||||
|
@ -1066,6 +1066,7 @@ bool FluxboxWindow::setCurrentClient(WinClient &client, bool setinput) {
|
||||||
// frame focused doesn't necessarily mean input focused
|
// frame focused doesn't necessarily mean input focused
|
||||||
frame().setLabelButtonFocus(*button);
|
frame().setLabelButtonFocus(*button);
|
||||||
frame().setShapingClient(&client, false);
|
frame().setShapingClient(&client, false);
|
||||||
|
frame().setSizeHints(client.sizeHints());
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1090,6 +1091,7 @@ void FluxboxWindow::associateClientWindow(bool use_attrs,
|
||||||
frame().resizeForClient(m_client->width(), m_client->height());
|
frame().resizeForClient(m_client->width(), m_client->height());
|
||||||
|
|
||||||
frame().setActiveGravity(m_client->gravity(), m_client->old_bw);
|
frame().setActiveGravity(m_client->gravity(), m_client->old_bw);
|
||||||
|
frame().setSizeHints(m_client->sizeHints());
|
||||||
frame().setClientWindow(*m_client);
|
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
|
// dy = new height (w/o decorations), similarly
|
||||||
int dh = m_last_resize_h - decoration_height;
|
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
|
// update last resize
|
||||||
m_last_resize_w = dw;
|
m_last_resize_w = dw;
|
||||||
|
|
Loading…
Reference in a new issue