Adjust scene for client-side decorated clients
Summary: Currently our Scene is quite naive about geometry. It assumes that the window frame wraps the attached buffer/client. While this is true for X11 clients, such geometry model is not suitable for client-side decorated clients, in our case for xdg-shell clients that set window geometry other than the bounding rectangle of the main surface. In general, the proposed solution doesn't make any concrete assumptions about the order between frame and buffer geometry, however we may still need to reconsider the design of Scene once it starts to generate quads for sub-surfaces. Reviewers: #kwin, davidedmundson Reviewed By: #kwin, davidedmundson Subscribers: davidedmundson, romangg, kwin Tags: #kwin Maniphest Tasks: T10867 Differential Revision: https://phabricator.kde.org/D24462
This commit is contained in:
parent
14dc76f624
commit
fb2d4c113f
14 changed files with 185 additions and 99 deletions
|
@ -385,6 +385,7 @@ public:
|
|||
|
||||
bool wantsTabFocus() const;
|
||||
|
||||
QMargins frameMargins() const override;
|
||||
QPoint clientPos() const override {
|
||||
return QPoint(borderLeft(), borderTop());
|
||||
}
|
||||
|
@ -835,14 +836,6 @@ public:
|
|||
*/
|
||||
virtual bool supportsWindowRules() const;
|
||||
|
||||
/**
|
||||
* Returns the extents of the server-side decoration.
|
||||
*
|
||||
* Note that the returned margins object will have all margins set to 0 if
|
||||
* the client doesn't have a server-side decoration.
|
||||
*/
|
||||
QMargins frameMargins() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
virtual void closeWindow() = 0;
|
||||
|
||||
|
|
12
deleted.cpp
12
deleted.cpp
|
@ -95,6 +95,8 @@ void Deleted::copyToDeleted(Toplevel* c)
|
|||
Q_ASSERT(dynamic_cast< Deleted* >(c) == nullptr);
|
||||
Toplevel::copyToDeleted(c);
|
||||
m_bufferGeometry = c->bufferGeometry();
|
||||
m_bufferMargins = c->bufferMargins();
|
||||
m_frameMargins = c->frameMargins();
|
||||
m_bufferScale = c->bufferScale();
|
||||
desk = c->desktop();
|
||||
m_desktops = c->desktops();
|
||||
|
@ -169,6 +171,16 @@ QRect Deleted::bufferGeometry() const
|
|||
return m_bufferGeometry;
|
||||
}
|
||||
|
||||
QMargins Deleted::bufferMargins() const
|
||||
{
|
||||
return m_bufferMargins;
|
||||
}
|
||||
|
||||
QMargins Deleted::frameMargins() const
|
||||
{
|
||||
return m_frameMargins;
|
||||
}
|
||||
|
||||
qreal Deleted::bufferScale() const
|
||||
{
|
||||
return m_bufferScale;
|
||||
|
|
|
@ -44,6 +44,8 @@ public:
|
|||
void unrefWindow();
|
||||
void discard();
|
||||
QRect bufferGeometry() const override;
|
||||
QMargins bufferMargins() const override;
|
||||
QMargins frameMargins() const override;
|
||||
qreal bufferScale() const override;
|
||||
int desktop() const override;
|
||||
QStringList activities() const override;
|
||||
|
@ -200,6 +202,8 @@ private:
|
|||
void removeTransientFor(Deleted *parent);
|
||||
|
||||
QRect m_bufferGeometry;
|
||||
QMargins m_bufferMargins;
|
||||
QMargins m_frameMargins;
|
||||
|
||||
int delete_refcount;
|
||||
int desk;
|
||||
|
|
|
@ -1951,7 +1951,10 @@ void EffectWindowImpl::setSceneWindow(Scene::Window* w)
|
|||
|
||||
QRegion EffectWindowImpl::shape() const
|
||||
{
|
||||
return sw ? sw->shape() : geometry();
|
||||
if (isX11Client() && sceneWindow()) {
|
||||
return sceneWindow()->bufferShape();
|
||||
}
|
||||
return geometry();
|
||||
}
|
||||
|
||||
QRect EffectWindowImpl::decorationInnerRect() const
|
||||
|
|
|
@ -1512,7 +1512,8 @@ void SceneOpenGL2Window::performPaint(int mask, QRegion region, WindowPaintData
|
|||
// render sub-surfaces
|
||||
auto wp = windowPixmap<OpenGLWindowPixmap>();
|
||||
const auto &children = wp ? wp->children() : QVector<WindowPixmap*>();
|
||||
windowMatrix.translate(toplevel->clientPos().x(), toplevel->clientPos().y());
|
||||
const QPoint mainSurfaceOffset = bufferOffset();
|
||||
windowMatrix.translate(mainSurfaceOffset.x(), mainSurfaceOffset.y());
|
||||
for (auto pixmap : children) {
|
||||
if (pixmap->subSurface().isNull() || pixmap->subSurface()->surface().isNull() || !pixmap->subSurface()->surface()->isMapped()) {
|
||||
continue;
|
||||
|
|
|
@ -287,14 +287,17 @@ void SceneQPainter::Window::performPaint(int mask, QRegion region, WindowPaintDa
|
|||
renderWindowDecorations(painter);
|
||||
|
||||
// render content
|
||||
const QRect target = QRect(toplevel->clientPos(), toplevel->clientSize());
|
||||
QSize srcSize = pixmap->image().size();
|
||||
if (pixmap->surface() && pixmap->surface()->scale() == 1 && srcSize != toplevel->clientSize()) {
|
||||
QRect source;
|
||||
QRect target;
|
||||
if (toplevel->isClient()) {
|
||||
// special case for XWayland windows
|
||||
srcSize = toplevel->clientSize();
|
||||
source = QRect(toplevel->clientPos(), toplevel->clientSize());
|
||||
target = source;
|
||||
} else {
|
||||
source = pixmap->image().rect();
|
||||
target = toplevel->bufferGeometry().translated(-pos());
|
||||
}
|
||||
const QRect src = QRect(toplevel->clientPos() + toplevel->clientContentPos(), srcSize);
|
||||
painter->drawImage(target, pixmap->image(), src);
|
||||
painter->drawImage(target, pixmap->image(), source);
|
||||
|
||||
// render subsurfaces
|
||||
const auto &children = pixmap->children();
|
||||
|
@ -302,7 +305,7 @@ void SceneQPainter::Window::performPaint(int mask, QRegion region, WindowPaintDa
|
|||
if (pixmap->subSurface().isNull() || pixmap->subSurface()->surface().isNull() || !pixmap->subSurface()->surface()->isMapped()) {
|
||||
continue;
|
||||
}
|
||||
paintSubSurface(painter, toplevel->clientPos(), static_cast<QPainterWindowPixmap*>(pixmap));
|
||||
paintSubSurface(painter, bufferOffset(), static_cast<QPainterWindowPixmap*>(pixmap));
|
||||
}
|
||||
|
||||
if (!opaque) {
|
||||
|
|
|
@ -462,10 +462,10 @@ void SceneXrender::Window::performPaint(int mask, QRegion region, WindowPaintDat
|
|||
if (toplevel->shape()) {
|
||||
// "xeyes" + decoration
|
||||
transformed_shape -= cr;
|
||||
transformed_shape += shape();
|
||||
transformed_shape += bufferShape();
|
||||
}
|
||||
} else {
|
||||
transformed_shape = shape();
|
||||
transformed_shape = bufferShape();
|
||||
}
|
||||
if (toplevel->shadow()) {
|
||||
transformed_shape |= toplevel->shadow()->shadowRegion();
|
||||
|
|
177
scene.cpp
177
scene.cpp
|
@ -278,22 +278,14 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
|||
if (client) {
|
||||
opaqueFullscreen = client->isFullScreen();
|
||||
}
|
||||
X11Client *cc = dynamic_cast<X11Client *>(client);
|
||||
// the window is fully opaque
|
||||
if (cc && cc->decorationHasAlpha()) {
|
||||
// decoration uses alpha channel, so we may not exclude it in clipping
|
||||
data.clip = window->clientShape().translated(window->x(), window->y());
|
||||
} else {
|
||||
// decoration is fully opaque
|
||||
if (client && client->isShade()) {
|
||||
data.clip = QRegion();
|
||||
} else {
|
||||
data.clip = window->shape().translated(window->x(), window->y());
|
||||
}
|
||||
if (!(client && client->decorationHasAlpha())) {
|
||||
data.clip = window->decorationShape().translated(window->pos());
|
||||
}
|
||||
data.clip |= window->clientShape().translated(window->pos() + window->bufferOffset());
|
||||
} else if (toplevel->hasAlpha() && toplevel->opacity() == 1.0) {
|
||||
// the window is partially opaque
|
||||
data.clip = (window->clientShape() & toplevel->opaqueRegion().translated(toplevel->clientPos())).translated(window->x(), window->y());
|
||||
const QRegion clientShape = window->clientShape().translated(window->pos() + window->bufferOffset());
|
||||
const QRegion opaqueShape = toplevel->opaqueRegion().translated(window->pos() + toplevel->clientPos());
|
||||
data.clip = clientShape & opaqueShape;
|
||||
} else {
|
||||
data.clip = QRegion();
|
||||
}
|
||||
|
@ -687,7 +679,6 @@ Scene::Window::Window(Toplevel * c)
|
|||
, m_previousPixmap()
|
||||
, m_referencePixmapCounter(0)
|
||||
, disable_painting(0)
|
||||
, shape_valid(false)
|
||||
, cached_quad_list(nullptr)
|
||||
{
|
||||
}
|
||||
|
@ -731,47 +722,70 @@ void Scene::Window::discardShape()
|
|||
{
|
||||
// it is created on-demand and cached, simply
|
||||
// reset the flag
|
||||
shape_valid = false;
|
||||
m_bufferShapeIsValid = false;
|
||||
invalidateQuadsCache();
|
||||
}
|
||||
|
||||
// Find out the shape of the window using the XShape extension
|
||||
// or if shape is not set then simply it's the window geometry.
|
||||
const QRegion &Scene::Window::shape() const
|
||||
QRegion Scene::Window::bufferShape() const
|
||||
{
|
||||
if (!shape_valid) {
|
||||
if (toplevel->shape()) {
|
||||
auto cookie = xcb_shape_get_rectangles_unchecked(connection(), toplevel->frameId(), XCB_SHAPE_SK_BOUNDING);
|
||||
ScopedCPointer<xcb_shape_get_rectangles_reply_t> reply(xcb_shape_get_rectangles_reply(connection(), cookie, nullptr));
|
||||
if (!reply.isNull()) {
|
||||
shape_region = QRegion();
|
||||
auto *rects = xcb_shape_get_rectangles_rectangles(reply.data());
|
||||
for (int i = 0;
|
||||
i < xcb_shape_get_rectangles_rectangles_length(reply.data());
|
||||
++i)
|
||||
shape_region += QRegion(rects[ i ].x, rects[ i ].y,
|
||||
rects[ i ].width, rects[ i ].height);
|
||||
// make sure the shape is sane (X is async, maybe even XShape is broken)
|
||||
shape_region &= QRegion(0, 0, width(), height());
|
||||
} else
|
||||
shape_region = QRegion();
|
||||
} else
|
||||
shape_region = QRegion(0, 0, width(), height());
|
||||
shape_valid = true;
|
||||
if (m_bufferShapeIsValid) {
|
||||
return m_bufferShape;
|
||||
}
|
||||
return shape_region;
|
||||
|
||||
const QRect bufferGeometry = toplevel->bufferGeometry();
|
||||
|
||||
if (toplevel->shape()) {
|
||||
auto cookie = xcb_shape_get_rectangles_unchecked(connection(), toplevel->frameId(), XCB_SHAPE_SK_BOUNDING);
|
||||
ScopedCPointer<xcb_shape_get_rectangles_reply_t> reply(xcb_shape_get_rectangles_reply(connection(), cookie, nullptr));
|
||||
if (!reply.isNull()) {
|
||||
m_bufferShape = QRegion();
|
||||
const xcb_rectangle_t *rects = xcb_shape_get_rectangles_rectangles(reply.data());
|
||||
const int rectCount = xcb_shape_get_rectangles_rectangles_length(reply.data());
|
||||
for (int i = 0; i < rectCount; ++i) {
|
||||
m_bufferShape += QRegion(rects[i].x, rects[i].y, rects[i].width, rects[i].height);
|
||||
}
|
||||
// make sure the shape is sane (X is async, maybe even XShape is broken)
|
||||
m_bufferShape &= QRegion(0, 0, bufferGeometry.width(), bufferGeometry.height());
|
||||
} else {
|
||||
m_bufferShape = QRegion();
|
||||
}
|
||||
} else {
|
||||
m_bufferShape = QRegion(0, 0, bufferGeometry.width(), bufferGeometry.height());
|
||||
}
|
||||
|
||||
m_bufferShapeIsValid = true;
|
||||
|
||||
return m_bufferShape;
|
||||
}
|
||||
|
||||
QRegion Scene::Window::clientShape() const
|
||||
{
|
||||
if (AbstractClient *c = dynamic_cast< AbstractClient * > (toplevel)) {
|
||||
if (c->isShade())
|
||||
if (AbstractClient *client = qobject_cast<AbstractClient *>(toplevel)) {
|
||||
if (client->isShade()) {
|
||||
return QRegion();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: cache
|
||||
const QRegion r = shape() & QRect(toplevel->clientPos(), toplevel->clientSize());
|
||||
return r.isEmpty() ? QRegion() : r;
|
||||
const QRegion shape = bufferShape();
|
||||
const QMargins bufferMargins = toplevel->bufferMargins();
|
||||
if (bufferMargins.isNull()) {
|
||||
return shape;
|
||||
}
|
||||
|
||||
const QRect clippingRect = QRect(QPoint(0, 0), toplevel->bufferGeometry().size()) - toplevel->bufferMargins();
|
||||
return shape & clippingRect;
|
||||
}
|
||||
|
||||
QRegion Scene::Window::decorationShape() const
|
||||
{
|
||||
return QRegion(toplevel->decorationRect()) - toplevel->transparentRect();
|
||||
}
|
||||
|
||||
QPoint Scene::Window::bufferOffset() const
|
||||
{
|
||||
const QRect bufferGeometry = toplevel->bufferGeometry();
|
||||
const QRect frameGeometry = toplevel->frameGeometry();
|
||||
return bufferGeometry.topLeft() - frameGeometry.topLeft();
|
||||
}
|
||||
|
||||
bool Scene::Window::isVisible() const
|
||||
|
@ -835,19 +849,14 @@ WindowQuadList Scene::Window::buildQuads(bool force) const
|
|||
{
|
||||
if (cached_quad_list != nullptr && !force)
|
||||
return *cached_quad_list;
|
||||
WindowQuadList ret;
|
||||
|
||||
const qreal scale = toplevel->bufferScale();
|
||||
WindowQuadList ret = makeContentsQuads();
|
||||
|
||||
if (toplevel->clientPos() == QPoint(0, 0) && toplevel->clientSize() == toplevel->decorationRect().size())
|
||||
ret = makeQuads(WindowQuadContents, shape(), QPoint(0,0), scale); // has no decoration
|
||||
else {
|
||||
if (!toplevel->frameMargins().isNull()) {
|
||||
AbstractClient *client = dynamic_cast<AbstractClient*>(toplevel);
|
||||
QRegion contents = clientShape();
|
||||
QRegion center = toplevel->transparentRect();
|
||||
QRegion decoration = (client ? QRegion(client->decorationRect()) : shape()) - center;
|
||||
const QRegion decoration = decorationShape();
|
||||
qreal decorationScale = 1.0;
|
||||
ret = makeQuads(WindowQuadContents, contents, toplevel->clientContentPos(), scale);
|
||||
|
||||
QRect rects[4];
|
||||
bool isShadedClient = false;
|
||||
|
@ -932,32 +941,48 @@ WindowQuadList Scene::Window::makeDecorationQuads(const QRect *rects, const QReg
|
|||
return list;
|
||||
}
|
||||
|
||||
WindowQuadList Scene::Window::makeContentsQuads() const
|
||||
{
|
||||
const QRegion contentsRegion = clientShape();
|
||||
if (contentsRegion.isEmpty()) {
|
||||
return WindowQuadList();
|
||||
}
|
||||
|
||||
const QPointF geometryOffset = bufferOffset();
|
||||
const qreal textureScale = toplevel->bufferScale();
|
||||
|
||||
WindowQuadList quads;
|
||||
quads.reserve(contentsRegion.rectCount());
|
||||
|
||||
for (const QRectF &rect : contentsRegion) {
|
||||
WindowQuad quad(WindowQuadContents);
|
||||
|
||||
const qreal x0 = rect.left() + geometryOffset.x();
|
||||
const qreal y0 = rect.top() + geometryOffset.y();
|
||||
const qreal x1 = rect.right() + geometryOffset.x();
|
||||
const qreal y1 = rect.bottom() + geometryOffset.y();
|
||||
|
||||
const qreal u0 = rect.left() * textureScale;
|
||||
const qreal v0 = rect.top() * textureScale;
|
||||
const qreal u1 = rect.right() * textureScale;
|
||||
const qreal v1 = rect.bottom() * textureScale;
|
||||
|
||||
quad[0] = WindowVertex(QPointF(x0, y0), QPointF(u0, v0));
|
||||
quad[1] = WindowVertex(QPointF(x1, y0), QPointF(u1, v0));
|
||||
quad[2] = WindowVertex(QPointF(x1, y1), QPointF(u1, v1));
|
||||
quad[3] = WindowVertex(QPointF(x0, y1), QPointF(u0, v1));
|
||||
|
||||
quads << quad;
|
||||
}
|
||||
|
||||
return quads;
|
||||
}
|
||||
|
||||
void Scene::Window::invalidateQuadsCache()
|
||||
{
|
||||
cached_quad_list.reset();
|
||||
}
|
||||
|
||||
WindowQuadList Scene::Window::makeQuads(WindowQuadType type, const QRegion& reg, const QPoint &textureOffset, qreal scale) const
|
||||
{
|
||||
WindowQuadList ret;
|
||||
ret.reserve(reg.rectCount());
|
||||
for (const QRect &r : reg) {
|
||||
WindowQuad quad(type);
|
||||
// TODO asi mam spatne pravy dolni roh - bud tady, nebo v jinych castech
|
||||
quad[ 0 ] = WindowVertex(QPointF(r.x(), r.y()),
|
||||
QPointF(r.x() + textureOffset.x(), r.y() + textureOffset.y()) * scale);
|
||||
quad[ 1 ] = WindowVertex(QPointF(r.x() + r.width(), r.y()),
|
||||
QPointF(r.x() + r.width() + textureOffset.x(), r.y() + textureOffset.y()) * scale);
|
||||
quad[ 2 ] = WindowVertex(QPointF(r.x() + r.width(), r.y() + r.height()),
|
||||
QPointF(r.x() + r.width() + textureOffset.x(), r.y() + r.height() + textureOffset.y()) * scale);
|
||||
quad[ 3 ] = WindowVertex(QPointF(r.x(), r.y() + r.height()),
|
||||
QPointF(r.x() + textureOffset.x(), r.y() + r.height() + textureOffset.y()) * scale);
|
||||
|
||||
ret.append(quad);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Scene::Window::updateShadow(Shadow* shadow)
|
||||
{
|
||||
if (m_shadow == shadow) {
|
||||
|
@ -1029,14 +1054,14 @@ void WindowPixmap::create()
|
|||
xcb_free_pixmap(connection(), pix);
|
||||
return;
|
||||
}
|
||||
if (!windowGeometry ||
|
||||
windowGeometry->width != toplevel()->width() || windowGeometry->height != toplevel()->height()) {
|
||||
const QRect bufferGeometry = toplevel()->bufferGeometry();
|
||||
if (windowGeometry.size() != bufferGeometry.size()) {
|
||||
qCDebug(KWIN_CORE) << "Creating window pixmap failed: " << this;
|
||||
xcb_free_pixmap(connection(), pix);
|
||||
return;
|
||||
}
|
||||
m_pixmap = pix;
|
||||
m_pixmapSize = QSize(toplevel()->width(), toplevel()->height());
|
||||
m_pixmapSize = bufferGeometry.size();
|
||||
m_contentsRect = QRect(toplevel()->clientPos(), toplevel()->clientSize());
|
||||
m_window->unreferencePreviousPixmap();
|
||||
}
|
||||
|
|
10
scene.h
10
scene.h
|
@ -330,8 +330,10 @@ public:
|
|||
// is the window fully opaque
|
||||
bool isOpaque() const;
|
||||
// shape of the window
|
||||
const QRegion &shape() const;
|
||||
QRegion bufferShape() const;
|
||||
QRegion clientShape() const;
|
||||
QRegion decorationShape() const;
|
||||
QPoint bufferOffset() const;
|
||||
void discardShape();
|
||||
void updateToplevel(Toplevel* c);
|
||||
// creates initial quad list for the window
|
||||
|
@ -343,8 +345,8 @@ public:
|
|||
void unreferencePreviousPixmap();
|
||||
void invalidateQuadsCache();
|
||||
protected:
|
||||
WindowQuadList makeQuads(WindowQuadType type, const QRegion& reg, const QPoint &textureOffset = QPoint(0, 0), qreal textureScale = 1.0) const;
|
||||
WindowQuadList makeDecorationQuads(const QRect *rects, const QRegion ®ion, qreal textureScale = 1.0) const;
|
||||
WindowQuadList makeContentsQuads() const;
|
||||
/**
|
||||
* @brief Returns the WindowPixmap for this Window.
|
||||
*
|
||||
|
@ -377,8 +379,8 @@ private:
|
|||
QScopedPointer<WindowPixmap> m_previousPixmap;
|
||||
int m_referencePixmapCounter;
|
||||
int disable_painting;
|
||||
mutable QRegion shape_region;
|
||||
mutable bool shape_valid;
|
||||
mutable QRegion m_bufferShape;
|
||||
mutable bool m_bufferShapeIsValid = false;
|
||||
mutable QScopedPointer<WindowQuadList> cached_quad_list;
|
||||
Q_DISABLE_COPY(Window)
|
||||
};
|
||||
|
|
10
toplevel.cpp
10
toplevel.cpp
|
@ -804,5 +804,15 @@ bool Toplevel::isLocalhost() const
|
|||
return m_clientMachine->isLocal();
|
||||
}
|
||||
|
||||
QMargins Toplevel::bufferMargins() const
|
||||
{
|
||||
return QMargins();
|
||||
}
|
||||
|
||||
QMargins Toplevel::frameMargins() const
|
||||
{
|
||||
return QMargins();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
|
19
toplevel.h
19
toplevel.h
|
@ -314,11 +314,30 @@ public:
|
|||
* occupies on the screen, in global screen coordinates.
|
||||
*/
|
||||
virtual QRect bufferGeometry() const = 0;
|
||||
/**
|
||||
* Returns the extents of invisible portions in the pixmap.
|
||||
*
|
||||
* An X11 pixmap may contain invisible space around the actual contents of the
|
||||
* client. That space is reserved for server-side decoration, which we usually
|
||||
* want to skip when building contents window quads.
|
||||
*
|
||||
* Default implementation returns a margins object with all margins set to 0.
|
||||
*/
|
||||
virtual QMargins bufferMargins() const;
|
||||
/**
|
||||
* Returns the geometry of the Toplevel, excluding invisible portions, e.g.
|
||||
* server-side and client-side drop shadows, etc.
|
||||
*/
|
||||
QRect frameGeometry() const;
|
||||
/**
|
||||
* Returns the extents of the server-side decoration.
|
||||
*
|
||||
* Note that the returned margins object will have all margins set to 0 if
|
||||
* the client doesn't have a server-side decoration.
|
||||
*
|
||||
* Default implementation returns a margins object with all margins set to 0.
|
||||
*/
|
||||
virtual QMargins frameMargins() const;
|
||||
/**
|
||||
* The geometry of the Toplevel which accepts input events. This might be larger
|
||||
* than the actual geometry, e.g. to support resizing outside the window.
|
||||
|
|
|
@ -1976,6 +1976,11 @@ QRect X11Client::bufferGeometry() const
|
|||
return geom;
|
||||
}
|
||||
|
||||
QMargins X11Client::bufferMargins() const
|
||||
{
|
||||
return QMargins(borderLeft(), borderTop(), borderRight(), borderBottom());
|
||||
}
|
||||
|
||||
Xcb::Property X11Client::fetchShowOnScreenEdge() const
|
||||
{
|
||||
return Xcb::Property(false, window(), atoms->kde_screen_edge_show, XCB_ATOM_CARDINAL, 0, 1);
|
||||
|
|
|
@ -90,6 +90,7 @@ public:
|
|||
xcb_window_t frameId() const override;
|
||||
|
||||
QRect bufferGeometry() const override;
|
||||
QMargins bufferMargins() const override;
|
||||
|
||||
bool isTransient() const override;
|
||||
bool groupTransient() const override;
|
||||
|
|
|
@ -566,6 +566,14 @@ public:
|
|||
}
|
||||
return QRect(geometry->x, geometry->y, geometry->width, geometry->height);
|
||||
}
|
||||
|
||||
inline QSize size() {
|
||||
const xcb_get_geometry_reply_t *geometry = data();
|
||||
if (!geometry) {
|
||||
return QSize();
|
||||
}
|
||||
return QSize(geometry->width, geometry->height);
|
||||
}
|
||||
};
|
||||
|
||||
XCB_WRAPPER_DATA(TreeData, xcb_query_tree, xcb_window_t)
|
||||
|
|
Loading…
Reference in a new issue