Use Xcb::GeometryHints instead of XGetWMNormalHints

Xcb::GeometryHints is a convenient wrapper around the size hints
as described in ICCCM combined with the sanity checks so far applied
by KWin after reading the property.

Instead of accessing the members of the property structure, we are
now using the convenience methods.

During ::manage no further actions are triggered when reading the
size hints. Only when they are read later on the previous checks
are applied. During ::manage they can be ignored as it had a dedicated
isManaged check.

The method ::resizeWithCheck got a new argument of type xcb_gravity_t
which defaults to 0. This is needed from ::configureRequest which so
far temporarily changed the xSizeHints structure. By passing as an
argument this is no longer needed.

REVIEW: 122185
icc-effect-5.14.5
Martin Gräßlin 2015-01-21 16:05:29 +01:00
parent 48fcaa5656
commit 2076e458d3
6 changed files with 72 additions and 108 deletions

View File

@ -473,8 +473,8 @@ public:
void plainResize(int w, int h, ForceGeometry_t force = NormalGeometrySet);
void plainResize(const QSize& s, ForceGeometry_t force = NormalGeometrySet);
/// resizeWithChecks() resizes according to gravity, and checks workarea position
void resizeWithChecks(int w, int h, ForceGeometry_t force = NormalGeometrySet);
void resizeWithChecks(const QSize& s, ForceGeometry_t force = NormalGeometrySet);
void resizeWithChecks(int w, int h, xcb_gravity_t gravity = XCB_GRAVITY_BIT_FORGET, ForceGeometry_t force = NormalGeometrySet);
void resizeWithChecks(const QSize& s, xcb_gravity_t gravity = XCB_GRAVITY_BIT_FORGET, ForceGeometry_t force = NormalGeometrySet);
void keepInArea(QRect area, bool partial = false);
void setElectricBorderMode(QuickTileMode mode);
QuickTileMode electricBorderMode() const;
@ -928,7 +928,7 @@ private:
QPoint invertedMoveOffset;
QRect moveResizeGeom;
QRect initialMoveResizeGeom;
XSizeHints xSizeHint;
Xcb::GeometryHints m_geometryHints;
void sendSyntheticConfigureNotify();
enum MappingState {
Withdrawn, ///< Not handled, as per ICCCM WithdrawnState
@ -1268,9 +1268,9 @@ inline void Client::plainResize(const QSize& s, ForceGeometry_t force)
plainResize(s.width(), s.height(), force);
}
inline void Client::resizeWithChecks(const QSize& s, ForceGeometry_t force)
inline void Client::resizeWithChecks(const QSize& s, xcb_gravity_t gravity, ForceGeometry_t force)
{
resizeWithChecks(s.width(), s.height(), force);
resizeWithChecks(s.width(), s.height(), gravity, force);
}
inline bool Client::hasUserTimeSupport() const

View File

@ -1288,13 +1288,13 @@ QSize Client::sizeForClientSize(const QSize& wsize, Sizemode mode, bool noframe)
int w1 = w;
int h1 = h;
int width_inc = xSizeHint.width_inc;
int height_inc = xSizeHint.height_inc;
int basew_inc = xSizeHint.base_width;
int baseh_inc = xSizeHint.base_height;
if (!(xSizeHint.flags & PBaseSize)) {
basew_inc = xSizeHint.min_width;
baseh_inc = xSizeHint.min_height;
int width_inc = m_geometryHints.resizeIncrements().width();
int height_inc = m_geometryHints.resizeIncrements().height();
int basew_inc = m_geometryHints.baseSize().width();
int baseh_inc = m_geometryHints.baseSize().height();
if (!m_geometryHints.hasBaseSize()) {
basew_inc = m_geometryHints.minSize().width();
baseh_inc = m_geometryHints.minSize().height();
}
w = int((w - basew_inc) / width_inc) * width_inc + basew_inc;
h = int((h - baseh_inc) / height_inc) * height_inc + baseh_inc;
@ -1313,20 +1313,21 @@ QSize Client::sizeForClientSize(const QSize& wsize, Sizemode mode, bool noframe)
* maxAspectX * dheight < maxAspectY * dwidth
*
*/
if (xSizeHint.flags & PAspect) {
double min_aspect_w = xSizeHint.min_aspect.x; // use doubles, because the values can be MAX_INT
double min_aspect_h = xSizeHint.min_aspect.y; // and multiplying would go wrong otherwise
double max_aspect_w = xSizeHint.max_aspect.x;
double max_aspect_h = xSizeHint.max_aspect.y;
if (m_geometryHints.hasAspect()) {
double min_aspect_w = m_geometryHints.minAspect().width(); // use doubles, because the values can be MAX_INT
double min_aspect_h = m_geometryHints.minAspect().height(); // and multiplying would go wrong otherwise
double max_aspect_w = m_geometryHints.maxAspect().width();
double max_aspect_h = m_geometryHints.maxAspect().height();
// According to ICCCM 4.1.2.3 PMinSize should be a fallback for PBaseSize for size increments,
// but not for aspect ratio. Since this code comes from FVWM, handles both at the same time,
// and I have no idea how it works, let's hope nobody relies on that.
w -= xSizeHint.base_width;
h -= xSizeHint.base_height;
int max_width = max_size.width() - xSizeHint.base_width;
int min_width = min_size.width() - xSizeHint.base_width;
int max_height = max_size.height() - xSizeHint.base_height;
int min_height = min_size.height() - xSizeHint.base_height;
const QSize baseSize = m_geometryHints.baseSize();
w -= baseSize.width();
h -= baseSize.height();
int max_width = max_size.width() - baseSize.width();
int min_width = min_size.width() - baseSize.width();
int max_height = max_size.height() - baseSize.height();
int min_height = min_size.height() - baseSize.height();
#define ASPECT_CHECK_GROW_W \
if ( min_aspect_w * h > min_aspect_h * w ) \
{ \
@ -1407,8 +1408,8 @@ QSize Client::sizeForClientSize(const QSize& wsize, Sizemode mode, bool noframe)
#undef ASPECT_CHECK_SHRINK_W_GROW_H
#undef ASPECT_CHECK_GROW_W
#undef ASPECT_CHECK_GROW_H
w += xSizeHint.base_width;
h += xSizeHint.base_height;
w += baseSize.width();
h += baseSize.height();
}
if (!rules()->checkStrictGeometry(!isFullScreen())) {
// disobey increments and aspect by explicit rule
@ -1428,52 +1429,15 @@ QSize Client::sizeForClientSize(const QSize& wsize, Sizemode mode, bool noframe)
*/
void Client::getWmNormalHints()
{
long msize;
const bool hadFixedAspect = xSizeHint.flags & PAspect;
if (XGetWMNormalHints(display(), window(), &xSizeHint, &msize) == 0)
xSizeHint.flags = 0;
// set defined values for the fields, even if they're not in flags
const bool hadFixedAspect = m_geometryHints.hasAspect();
// roundtrip to X server
m_geometryHints.fetch();
m_geometryHints.read();
if (!(xSizeHint.flags & PMinSize))
xSizeHint.min_width = xSizeHint.min_height = 0;
if (xSizeHint.flags & PBaseSize) {
// PBaseSize is a fallback for PMinSize according to ICCCM 4.1.2.3
// The other way around PMinSize is not a complete fallback for PBaseSize,
// so that's not handled here.
if (!(xSizeHint.flags & PMinSize)) {
xSizeHint.min_width = xSizeHint.base_width;
xSizeHint.min_height = xSizeHint.base_height;
}
} else
xSizeHint.base_width = xSizeHint.base_height = 0;
if (!(xSizeHint.flags & PMaxSize))
xSizeHint.max_width = xSizeHint.max_height = INT_MAX;
else {
xSizeHint.max_width = qMax(xSizeHint.max_width, 1);
xSizeHint.max_height = qMax(xSizeHint.max_height, 1);
if (!hadFixedAspect && m_geometryHints.hasAspect()) {
// align to eventual new contraints
maximize(max_mode);
}
if (xSizeHint.flags & PResizeInc) {
xSizeHint.width_inc = qMax(xSizeHint.width_inc, 1);
xSizeHint.height_inc = qMax(xSizeHint.height_inc, 1);
} else {
xSizeHint.width_inc = 1;
xSizeHint.height_inc = 1;
}
if (xSizeHint.flags & PAspect) {
// no dividing by zero
xSizeHint.min_aspect.y = qMax(xSizeHint.min_aspect.y, 1);
xSizeHint.max_aspect.y = qMax(xSizeHint.max_aspect.y, 1);
if (!hadFixedAspect)
maximize(max_mode); // align to eventual new contraints
} else {
xSizeHint.min_aspect.x = 1;
xSizeHint.min_aspect.y = INT_MAX;
xSizeHint.max_aspect.x = INT_MAX;
xSizeHint.max_aspect.y = 1;
}
if (!(xSizeHint.flags & PWinGravity))
xSizeHint.win_gravity = NorthWestGravity;
// Update min/max size of this group
if (tabGroup())
tabGroup()->updateMinMaxSize();
@ -1501,17 +1465,17 @@ void Client::getWmNormalHints()
QSize Client::minSize() const
{
return rules()->checkMinSize(QSize(xSizeHint.min_width, xSizeHint.min_height));
return rules()->checkMinSize(m_geometryHints.minSize());
}
QSize Client::maxSize() const
{
return rules()->checkMaxSize(QSize(xSizeHint.max_width, xSizeHint.max_height));
return rules()->checkMaxSize(m_geometryHints.maxSize());
}
QSize Client::basicUnit() const
{
return QSize(xSizeHint.width_inc, xSizeHint.height_inc);
return m_geometryHints.resizeIncrements();
}
/*!
@ -1543,7 +1507,7 @@ const QPoint Client::calculateGravitation(bool invert, int gravity) const
dx = dy = 0;
if (gravity == 0) // default (nonsense) value for the argument
gravity = xSizeHint.win_gravity;
gravity = m_geometryHints.windowGravity();
// dx, dy specify how the client window moves to make space for the frame
switch(gravity) {
@ -1645,7 +1609,7 @@ void Client::configureRequest(int value_mask, int rx, int ry, int rw, int rh, in
qCDebug(KWIN_CORE) << "PERMITTED" << this << bool(value_mask & (CWX|CWWidth|CWY|CWHeight));
if (gravity == 0) // default (nonsense) value for the argument
gravity = xSizeHint.win_gravity;
gravity = m_geometryHints.windowGravity();
if (value_mask & (CWX | CWY)) {
QPoint new_pos = calculateGravitation(true, gravity); // undo gravitation
if (value_mask & CWX)
@ -1707,11 +1671,8 @@ void Client::configureRequest(int value_mask, int rx, int ry, int rw, int rh, in
if (ns != size()) { // don't restore if some app sets its own size again
QRect origClientGeometry(pos() + clientPos(), clientSize());
GeometryUpdatesBlocker blocker(this);
int save_gravity = xSizeHint.win_gravity;
xSizeHint.win_gravity = gravity;
resizeWithChecks(ns);
xSizeHint.win_gravity = save_gravity;
updateFullScreenHack(QRect(calculateGravitation(true, xSizeHint.win_gravity), QSize(nw, nh)));
resizeWithChecks(ns, xcb_gravity_t(gravity));
updateFullScreenHack(QRect(calculateGravitation(true, m_geometryHints.windowGravity()), QSize(nw, nh)));
if (!from_tool && (!isSpecialWindow() || isToolbar()) && !isFullScreen()) {
// try to keep the window in its xinerama screen if possible,
// if that fails at least keep it visible somewhere
@ -1730,7 +1691,7 @@ void Client::configureRequest(int value_mask, int rx, int ry, int rw, int rh, in
// Handling of the real ConfigureRequest event forces sending it, as there it's necessary.
}
void Client::resizeWithChecks(int w, int h, ForceGeometry_t force)
void Client::resizeWithChecks(int w, int h, xcb_gravity_t gravity, ForceGeometry_t force)
{
assert(!shade_geometry_change);
if (isShade()) {
@ -1749,7 +1710,10 @@ void Client::resizeWithChecks(int w, int h, ForceGeometry_t force)
QSize tmp = adjustedSize(QSize(w, h)); // checks size constraints, including min/max size
w = tmp.width();
h = tmp.height();
switch(xSizeHint.win_gravity) {
if (gravity == 0) {
gravity = m_geometryHints.windowGravity();
}
switch(gravity) {
case NorthWestGravity: // top left corner doesn't move
default:
break;
@ -2171,17 +2135,19 @@ void Client::changeMaximize(bool vertical, bool horizontal, bool adjust)
// if the client insist on a fix aspect ratio, we check whether the maximizing will get us
// out of screen bounds and take that as a "full maximization with aspect check" then
if ((xSizeHint.flags & PAspect) && // fixed aspect
if (m_geometryHints.hasAspect() && // fixed aspect
(max_mode == MaximizeVertical || max_mode == MaximizeHorizontal) && // ondimensional maximization
rules()->checkStrictGeometry(true)) { // obey aspect
const QSize minAspect = m_geometryHints.minAspect();
const QSize maxAspect = m_geometryHints.maxAspect();
if (max_mode == MaximizeVertical || (old_mode & MaximizeVertical)) {
const double fx = xSizeHint.min_aspect.x; // use doubles, because the values can be MAX_INT
const double fy = xSizeHint.max_aspect.y; // use doubles, because the values can be MAX_INT
const double fx = minAspect.width(); // use doubles, because the values can be MAX_INT
const double fy = maxAspect.height(); // use doubles, because the values can be MAX_INT
if (fx*clientArea.height()/fy > clientArea.width()) // too big
max_mode = old_mode & MaximizeHorizontal ? MaximizeRestore : MaximizeFull;
} else { // max_mode == MaximizeHorizontal
const double fx = xSizeHint.max_aspect.x;
const double fy = xSizeHint.min_aspect.y;
const double fx = maxAspect.width();
const double fy = minAspect.height();
if (fy*clientArea.width()/fx > clientArea.height()) // too big
max_mode = old_mode & MaximizeVertical ? MaximizeRestore : MaximizeFull;
}
@ -2328,7 +2294,7 @@ void Client::changeMaximize(bool vertical, bool horizontal, bool adjust)
restore.moveTop(geom_restore.y());
geom_restore = restore; // relevant for mouse pos calculation, bug #298646
}
if (xSizeHint.flags & PAspect) {
if (m_geometryHints.hasAspect()) {
restore.setSize(adjustedSize(restore.size(), SizemodeAny));
}
setGeometry(restore, geom_mode);
@ -2539,7 +2505,7 @@ void Client::positionGeometryTip()
return; // some effect paints this for us
if (options->showGeometryTip()) {
if (!geometryTip) {
geometryTip = new GeometryTip(&xSizeHint);
geometryTip = new GeometryTip(&m_geometryHints);
}
QRect wgeom(moveResizeGeom); // position of the frame, size of the window itself
wgeom.setWidth(wgeom.width() - (width() - clientSize().width()));

View File

@ -19,12 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "geometrytip.h"
#include <QX11Info>
namespace KWin
{
GeometryTip::GeometryTip(const XSizeHints* xSizeHints):
GeometryTip::GeometryTip(const Xcb::GeometryHints* xSizeHints):
QLabel(0)
{
setObjectName(QLatin1String("kwingeometry"));
@ -47,9 +46,9 @@ void GeometryTip::setGeometry(const QRect& geom)
int h = geom.height();
if (sizeHints) {
if (sizeHints->flags & PResizeInc) {
w = (w - sizeHints->base_width) / sizeHints->width_inc;
h = (h - sizeHints->base_height) / sizeHints->height_inc;
if (sizeHints->hasResizeIncrements()) {
w = (w - sizeHints->baseSize().width()) / sizeHints->resizeIncrements().width();
h = (h - sizeHints->baseSize().height()) / sizeHints->resizeIncrements().height();
}
}

View File

@ -20,10 +20,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef KWIN_GEOMETRY_TIP_H
#define KWIN_GEOMETRY_TIP_H
#include "xcbutils.h"
#include <QLabel>
#include <X11/Xutil.h>
#include <fixx11h.h>
namespace KWin
{
@ -32,12 +31,12 @@ class GeometryTip: public QLabel
{
Q_OBJECT
public:
GeometryTip(const XSizeHints* xSizeHints);
GeometryTip(const Xcb::GeometryHints* xSizeHints);
~GeometryTip();
void setGeometry(const QRect& geom);
private:
const XSizeHints* sizeHints;
const Xcb::GeometryHints* sizeHints;
};
} // namespace

View File

@ -107,6 +107,7 @@ bool Client::manage(xcb_window_t w, bool isMapped)
auto firstInTabBoxCookie = fetchFirstInTabBox();
auto transientCookie = fetchTransient();
auto activitiesCookie = fetchActivities();
m_geometryHints.init(window());
info = new WinInfo(this, m_client, rootWindow(), properties, properties2);
// If it's already mapped, ignore hint
@ -140,7 +141,7 @@ bool Client::manage(xcb_window_t w, bool isMapped)
modal = (info->state() & NET::Modal) != 0; // Needs to be valid before handling groups
readTransientProperty(transientCookie);
getIcons();
getWmNormalHints(); // Get xSizeHint
m_geometryHints.read();
getMotifHints();
getWmOpaqueRegion();
readSkipCloseAnimation(skipCloseAnimationCookie);
@ -304,8 +305,7 @@ bool Client::manage(xcb_window_t w, bool isMapped)
else
usePosition = true;
if (!rules()->checkIgnoreGeometry(!usePosition, true)) {
if (((xSizeHint.flags & PPosition)) ||
(xSizeHint.flags & USPosition)) {
if (m_geometryHints.hasPosition()) {
placementDone = true;
// Disobey xinerama placement option for now (#70943)
area = workspace()->clientArea(PlacementArea, geom.center(), desktop());
@ -317,12 +317,12 @@ bool Client::manage(xcb_window_t w, bool isMapped)
// // Keep in mind that we now actually have a size :-)
// }
if (xSizeHint.flags & PMaxSize)
if (m_geometryHints.hasMaxSize())
geom.setSize(geom.size().boundedTo(
rules()->checkMaxSize(QSize(xSizeHint.max_width, xSizeHint.max_height))));
if (xSizeHint.flags & PMinSize)
rules()->checkMaxSize(m_geometryHints.maxSize())));
if (m_geometryHints.hasMinSize())
geom.setSize(geom.size().expandedTo(
rules()->checkMinSize(QSize(xSizeHint.min_width, xSizeHint.min_height))));
rules()->checkMinSize(m_geometryHints.minSize())));
if (isMovable() && (geom.x() > area.right() || geom.y() > area.bottom()))
placementDone = false; // Weird, do not trust.

View File

@ -716,8 +716,8 @@ void Client::growHorizontal()
QRect geom = geometry();
geom.setRight(workspace()->packPositionRight(this, geom.right(), true));
QSize adjsize = adjustedSize(geom.size(), SizemodeFixedW);
if (geometry().size() == adjsize && geom.size() != adjsize && xSizeHint.width_inc > 1) { // take care of size increments
int newright = workspace()->packPositionRight(this, geom.right() + xSizeHint.width_inc - 1, true);
if (geometry().size() == adjsize && geom.size() != adjsize && m_geometryHints.resizeIncrements().width() > 1) { // take care of size increments
int newright = workspace()->packPositionRight(this, geom.right() + m_geometryHints.resizeIncrements().width() - 1, true);
// check that it hasn't grown outside of the area, due to size increments
// TODO this may be wrong?
if (workspace()->clientArea(MovementArea,
@ -760,8 +760,8 @@ void Client::growVertical()
QRect geom = geometry();
geom.setBottom(workspace()->packPositionDown(this, geom.bottom(), true));
QSize adjsize = adjustedSize(geom.size(), SizemodeFixedH);
if (geometry().size() == adjsize && geom.size() != adjsize && xSizeHint.height_inc > 1) { // take care of size increments
int newbottom = workspace()->packPositionDown(this, geom.bottom() + xSizeHint.height_inc - 1, true);
if (geometry().size() == adjsize && geom.size() != adjsize && m_geometryHints.resizeIncrements().height() > 1) { // take care of size increments
int newbottom = workspace()->packPositionDown(this, geom.bottom() + m_geometryHints.resizeIncrements().height() - 1, true);
// check that it hasn't grown outside of the area, due to size increments
if (workspace()->clientArea(MovementArea,
QPoint(geometry().center().x(), (y() + newbottom) / 2), desktop()).bottom() >= newbottom)