Revert the fix for the texture bleeding issue
This reverts commit9151bb7b9e
. This reverts commitac4dce1c20
. This reverts commit754b72d155
. In order to make the fix work, we need to redirect the client window instead of the frame window. However, we cannot to do that because Xwayland expects the toplevel window(in our case, the frame window) to be redirected. Another solution to the texture bleeding issue must be found. CCBUG: 257566 CCBUG: 360549
This commit is contained in:
parent
9151bb7b9e
commit
6e000314b3
15 changed files with 239 additions and 270 deletions
|
@ -319,6 +319,8 @@ void Compositor::setupX11Support()
|
|||
return;
|
||||
}
|
||||
claimCompositorSelection();
|
||||
xcb_composite_redirect_subwindows(con, kwinApp()->x11RootWindow(),
|
||||
XCB_COMPOSITE_REDIRECT_MANUAL);
|
||||
}
|
||||
|
||||
void Compositor::startupWithWorkspace()
|
||||
|
@ -427,6 +429,10 @@ void Compositor::stop()
|
|||
for (InternalClient *client : workspace()->internalClients()) {
|
||||
client->finishCompositing();
|
||||
}
|
||||
if (auto *con = kwinApp()->x11Connection()) {
|
||||
xcb_composite_unredirect_subwindows(con, kwinApp()->x11RootWindow(),
|
||||
XCB_COMPOSITE_REDIRECT_MANUAL);
|
||||
}
|
||||
while (!workspace()->deletedList().isEmpty()) {
|
||||
workspace()->deletedList().first()->discard();
|
||||
}
|
||||
|
|
|
@ -74,15 +74,10 @@ QImage Renderer::renderToImage(const QRect &geo)
|
|||
p.setRenderHint(QPainter::Antialiasing);
|
||||
p.setWindow(QRect(geo.topLeft(), geo.size() * dpr));
|
||||
p.setClipRect(geo);
|
||||
renderToPainter(&p, geo);
|
||||
client()->decoration()->paint(&p, geo);
|
||||
return image;
|
||||
}
|
||||
|
||||
void Renderer::renderToPainter(QPainter *painter, const QRect &rect)
|
||||
{
|
||||
client()->decoration()->paint(painter, rect);
|
||||
}
|
||||
|
||||
void Renderer::reparent(Deleted *deleted)
|
||||
{
|
||||
setParent(deleted);
|
||||
|
|
|
@ -73,7 +73,6 @@ protected:
|
|||
m_imageSizesDirty = false;
|
||||
}
|
||||
QImage renderToImage(const QRect &geo);
|
||||
void renderToPainter(QPainter *painter, const QRect &rect);
|
||||
|
||||
private:
|
||||
DecoratedClientImpl *m_client;
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
Copyright (C) 2019 Vlad Zahorodnii <vladzzag@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -96,6 +95,7 @@ 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();
|
||||
|
@ -171,6 +171,11 @@ QRect Deleted::bufferGeometry() const
|
|||
return m_bufferGeometry;
|
||||
}
|
||||
|
||||
QMargins Deleted::bufferMargins() const
|
||||
{
|
||||
return m_bufferMargins;
|
||||
}
|
||||
|
||||
QMargins Deleted::frameMargins() const
|
||||
{
|
||||
return m_frameMargins;
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
Copyright (C) 2019 Vlad Zahorodnii <vladzzag@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -45,6 +44,7 @@ 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;
|
||||
|
@ -202,6 +202,7 @@ private:
|
|||
void removeTransientFor(Deleted *parent);
|
||||
|
||||
QRect m_bufferGeometry;
|
||||
QMargins m_bufferMargins;
|
||||
QMargins m_frameMargins;
|
||||
|
||||
int delete_refcount;
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
Copyright (C) 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
Copyright (C) 2019 Vlad Zahorodnii <vladzzag@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -1952,8 +1951,8 @@ void EffectWindowImpl::setSceneWindow(Scene::Window* w)
|
|||
|
||||
QRegion EffectWindowImpl::shape() const
|
||||
{
|
||||
if (sw) {
|
||||
return sw->decorationShape() | sw->bufferShape().translated(toplevel->clientPos());
|
||||
if (isX11Client() && sceneWindow()) {
|
||||
return sceneWindow()->bufferShape();
|
||||
}
|
||||
return geometry();
|
||||
}
|
||||
|
|
|
@ -581,7 +581,7 @@ bool X11Client::windowEvent(xcb_generic_event_t *e)
|
|||
detectShape(window()); // workaround for #19644
|
||||
updateShape();
|
||||
}
|
||||
if (eventType == Xcb::Extensions::self()->damageNotifyEvent() && reinterpret_cast<xcb_damage_notify_event_t *>(e)->drawable == windowId())
|
||||
if (eventType == Xcb::Extensions::self()->damageNotifyEvent() && reinterpret_cast<xcb_damage_notify_event_t*>(e)->drawable == frameId())
|
||||
damageNotifyEvent();
|
||||
break;
|
||||
}
|
||||
|
|
184
geometry.cpp
184
geometry.cpp
|
@ -1946,7 +1946,7 @@ void X11Client::setFrameGeometry(int x, int y, int w, int h, ForceGeometry_t for
|
|||
// for example using X11Client::clientSize()
|
||||
|
||||
QRect frameGeometry(x, y, w, h);
|
||||
QRect serverGeometry;
|
||||
QRect bufferGeometry;
|
||||
|
||||
if (shade_geometry_change)
|
||||
; // nothing
|
||||
|
@ -1961,18 +1961,18 @@ void X11Client::setFrameGeometry(int x, int y, int w, int h, ForceGeometry_t for
|
|||
m_clientGeometry = frameRectToClientRect(frameGeometry);
|
||||
}
|
||||
if (isDecorated()) {
|
||||
serverGeometry = frameGeometry;
|
||||
bufferGeometry = frameGeometry;
|
||||
} else {
|
||||
serverGeometry = m_clientGeometry;
|
||||
bufferGeometry = m_clientGeometry;
|
||||
}
|
||||
geom = frameGeometry;
|
||||
if (!areGeometryUpdatesBlocked() && frameGeometry != rules()->checkGeometry(frameGeometry)) {
|
||||
qCDebug(KWIN_CORE) << "forced geometry fail:" << frameGeometry << ":" << rules()->checkGeometry(frameGeometry);
|
||||
}
|
||||
if (force == NormalGeometrySet && m_serverGeometry == serverGeometry && pendingGeometryUpdate() == PendingGeometryNone) {
|
||||
if (!canUpdateGeometry(frameGeometry, bufferGeometry, force)) {
|
||||
return;
|
||||
}
|
||||
m_serverGeometry = serverGeometry;
|
||||
m_bufferGeometry = bufferGeometry;
|
||||
geom = frameGeometry;
|
||||
if (areGeometryUpdatesBlocked()) {
|
||||
if (pendingGeometryUpdate() == PendingGeometryForced)
|
||||
{} // maximum, nothing needed
|
||||
|
@ -1982,88 +1982,11 @@ void X11Client::setFrameGeometry(int x, int y, int w, int h, ForceGeometry_t for
|
|||
setPendingGeometryUpdate(PendingGeometryNormal);
|
||||
return;
|
||||
}
|
||||
updateServerGeometry();
|
||||
updateWindowRules(Rules::Position|Rules::Size);
|
||||
|
||||
// keep track of old maximize mode
|
||||
// to detect changes
|
||||
screens()->setCurrent(this);
|
||||
workspace()->updateStackingOrder();
|
||||
|
||||
// Need to regenerate decoration pixmaps when the buffer size is changed.
|
||||
if (bufferGeometryBeforeUpdateBlocking().size() != bufferGeometry().size()) {
|
||||
discardWindowPixmap();
|
||||
}
|
||||
emit geometryShapeChanged(this, frameGeometryBeforeUpdateBlocking());
|
||||
addRepaintDuringGeometryUpdates();
|
||||
updateGeometryBeforeUpdateBlocking();
|
||||
// TODO: this signal is emitted too often
|
||||
emit geometryChanged();
|
||||
}
|
||||
|
||||
void X11Client::plainResize(int w, int h, ForceGeometry_t force)
|
||||
{
|
||||
QSize frameSize(w, h);
|
||||
QSize serverSize;
|
||||
|
||||
// this code is also duplicated in X11Client::setGeometry(), and it's also commented there
|
||||
if (shade_geometry_change)
|
||||
; // nothing
|
||||
else if (isShade()) {
|
||||
if (frameSize.height() == borderTop() + borderBottom()) {
|
||||
qCDebug(KWIN_CORE) << "Shaded geometry passed for size:";
|
||||
} else {
|
||||
m_clientGeometry.setSize(frameSizeToClientSize(frameSize));
|
||||
frameSize.setHeight(borderTop() + borderBottom());
|
||||
}
|
||||
} else {
|
||||
m_clientGeometry.setSize(frameSizeToClientSize(frameSize));
|
||||
}
|
||||
if (isDecorated()) {
|
||||
serverSize = frameSize;
|
||||
} else {
|
||||
serverSize = m_clientGeometry.size();
|
||||
}
|
||||
if (!areGeometryUpdatesBlocked() && frameSize != rules()->checkSize(frameSize)) {
|
||||
qCDebug(KWIN_CORE) << "forced size fail:" << frameSize << ":" << rules()->checkSize(frameSize);
|
||||
}
|
||||
geom.setSize(frameSize);
|
||||
// resuming geometry updates is handled only in setGeometry()
|
||||
Q_ASSERT(pendingGeometryUpdate() == PendingGeometryNone || areGeometryUpdatesBlocked());
|
||||
if (force == NormalGeometrySet && m_serverGeometry.size() == serverSize) {
|
||||
return;
|
||||
}
|
||||
m_serverGeometry.setSize(serverSize);
|
||||
if (areGeometryUpdatesBlocked()) {
|
||||
if (pendingGeometryUpdate() == PendingGeometryForced)
|
||||
{} // maximum, nothing needed
|
||||
else if (force == ForceGeometrySet)
|
||||
setPendingGeometryUpdate(PendingGeometryForced);
|
||||
else
|
||||
setPendingGeometryUpdate(PendingGeometryNormal);
|
||||
return;
|
||||
}
|
||||
updateServerGeometry();
|
||||
updateWindowRules(Rules::Position|Rules::Size);
|
||||
screens()->setCurrent(this);
|
||||
workspace()->updateStackingOrder();
|
||||
if (bufferGeometryBeforeUpdateBlocking().size() != bufferGeometry().size()) {
|
||||
discardWindowPixmap();
|
||||
}
|
||||
emit geometryShapeChanged(this, frameGeometryBeforeUpdateBlocking());
|
||||
addRepaintDuringGeometryUpdates();
|
||||
updateGeometryBeforeUpdateBlocking();
|
||||
// TODO: this signal is emitted too often
|
||||
emit geometryChanged();
|
||||
}
|
||||
|
||||
void X11Client::updateServerGeometry()
|
||||
{
|
||||
const QRect previousServerGeometry = m_frame.geometry();
|
||||
const bool resized = (previousServerGeometry.size() != m_serverGeometry.size() || pendingGeometryUpdate() == PendingGeometryForced);
|
||||
const QRect oldBufferGeometry = bufferGeometryBeforeUpdateBlocking();
|
||||
bool resized = (oldBufferGeometry.size() != m_bufferGeometry.size() || pendingGeometryUpdate() == PendingGeometryForced);
|
||||
if (resized) {
|
||||
resizeDecoration();
|
||||
m_frame.setGeometry(m_serverGeometry);
|
||||
m_frame.setGeometry(m_bufferGeometry);
|
||||
if (!isShade()) {
|
||||
QSize cs = clientSize();
|
||||
m_wrapper.setGeometry(QRect(clientPos(), cs));
|
||||
|
@ -2079,15 +2002,96 @@ void X11Client::updateServerGeometry()
|
|||
if (compositing()) // Defer the X update until we leave this mode
|
||||
needsXWindowMove = true;
|
||||
else
|
||||
m_frame.move(m_serverGeometry.topLeft()); // sendSyntheticConfigureNotify() on finish shall be sufficient
|
||||
m_frame.move(m_bufferGeometry.topLeft()); // sendSyntheticConfigureNotify() on finish shall be sufficient
|
||||
} else {
|
||||
m_frame.move(m_serverGeometry.topLeft());
|
||||
m_frame.move(m_bufferGeometry.topLeft());
|
||||
sendSyntheticConfigureNotify();
|
||||
}
|
||||
|
||||
// Unconditionally move the input window: it won't affect rendering
|
||||
m_decoInputExtent.move(pos() + inputPos());
|
||||
m_decoInputExtent.move(QPoint(x, y) + inputPos());
|
||||
}
|
||||
updateWindowRules(Rules::Position|Rules::Size);
|
||||
|
||||
// keep track of old maximize mode
|
||||
// to detect changes
|
||||
screens()->setCurrent(this);
|
||||
workspace()->updateStackingOrder();
|
||||
|
||||
// Need to regenerate decoration pixmaps when the buffer size is changed.
|
||||
if (oldBufferGeometry.size() != m_bufferGeometry.size()) {
|
||||
discardWindowPixmap();
|
||||
}
|
||||
emit geometryShapeChanged(this, frameGeometryBeforeUpdateBlocking());
|
||||
addRepaintDuringGeometryUpdates();
|
||||
updateGeometryBeforeUpdateBlocking();
|
||||
// TODO: this signal is emitted too often
|
||||
emit geometryChanged();
|
||||
}
|
||||
|
||||
void X11Client::plainResize(int w, int h, ForceGeometry_t force)
|
||||
{
|
||||
QSize frameSize(w, h);
|
||||
QSize bufferSize;
|
||||
|
||||
// this code is also duplicated in X11Client::setGeometry(), and it's also commented there
|
||||
if (shade_geometry_change)
|
||||
; // nothing
|
||||
else if (isShade()) {
|
||||
if (frameSize.height() == borderTop() + borderBottom()) {
|
||||
qCDebug(KWIN_CORE) << "Shaded geometry passed for size:";
|
||||
} else {
|
||||
m_clientGeometry.setSize(frameSizeToClientSize(frameSize));
|
||||
frameSize.setHeight(borderTop() + borderBottom());
|
||||
}
|
||||
} else {
|
||||
m_clientGeometry.setSize(frameSizeToClientSize(frameSize));
|
||||
}
|
||||
if (isDecorated()) {
|
||||
bufferSize = frameSize;
|
||||
} else {
|
||||
bufferSize = m_clientGeometry.size();
|
||||
}
|
||||
if (!areGeometryUpdatesBlocked() && frameSize != rules()->checkSize(frameSize)) {
|
||||
qCDebug(KWIN_CORE) << "forced size fail:" << frameSize << ":" << rules()->checkSize(frameSize);
|
||||
}
|
||||
// resuming geometry updates is handled only in setGeometry()
|
||||
Q_ASSERT(pendingGeometryUpdate() == PendingGeometryNone || areGeometryUpdatesBlocked());
|
||||
if (!canUpdateSize(frameSize, bufferSize, force)) {
|
||||
return;
|
||||
}
|
||||
m_bufferGeometry.setSize(bufferSize);
|
||||
geom.setSize(frameSize);
|
||||
if (areGeometryUpdatesBlocked()) {
|
||||
if (pendingGeometryUpdate() == PendingGeometryForced)
|
||||
{} // maximum, nothing needed
|
||||
else if (force == ForceGeometrySet)
|
||||
setPendingGeometryUpdate(PendingGeometryForced);
|
||||
else
|
||||
setPendingGeometryUpdate(PendingGeometryNormal);
|
||||
return;
|
||||
}
|
||||
resizeDecoration();
|
||||
m_frame.resize(m_bufferGeometry.size());
|
||||
if (!isShade()) {
|
||||
QSize cs = clientSize();
|
||||
m_wrapper.setGeometry(QRect(clientPos(), cs));
|
||||
m_client.setGeometry(0, 0, cs.width(), cs.height());
|
||||
}
|
||||
updateShape();
|
||||
|
||||
sendSyntheticConfigureNotify();
|
||||
updateWindowRules(Rules::Position|Rules::Size);
|
||||
screens()->setCurrent(this);
|
||||
workspace()->updateStackingOrder();
|
||||
if (bufferGeometryBeforeUpdateBlocking().size() != m_bufferGeometry.size()) {
|
||||
discardWindowPixmap();
|
||||
}
|
||||
emit geometryShapeChanged(this, frameGeometryBeforeUpdateBlocking());
|
||||
addRepaintDuringGeometryUpdates();
|
||||
updateGeometryBeforeUpdateBlocking();
|
||||
// TODO: this signal is emitted too often
|
||||
emit geometryChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2669,7 +2673,7 @@ void X11Client::leaveMoveResize()
|
|||
{
|
||||
if (needsXWindowMove) {
|
||||
// Do the deferred move
|
||||
m_frame.move(m_serverGeometry.topLeft());
|
||||
m_frame.move(m_bufferGeometry.topLeft());
|
||||
needsXWindowMove = false;
|
||||
}
|
||||
if (!isResize())
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
Copyright (C) 2009, 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
Copyright (C) 2019 Vlad Zahorodnii <vladzzag@gmail.com>
|
||||
|
||||
Based on glcompmgr code by Felix Bellaby.
|
||||
Using code from Compiz and Beryl.
|
||||
|
@ -1434,6 +1433,7 @@ void SceneOpenGL2Window::performPaint(int mask, QRegion region, WindowPaintData
|
|||
if (data.crossFadeProgress() != 1.0) {
|
||||
OpenGLWindowPixmap *previous = previousWindowPixmap<OpenGLWindowPixmap>();
|
||||
if (previous) {
|
||||
const QRect &oldGeometry = previous->contentsRect();
|
||||
for (const WindowQuad &quad : quads[ContentLeaf]) {
|
||||
// we need to create new window quads with normalize texture coordinates
|
||||
// normal quads divide the x/y position by width/height. This would not work as the texture
|
||||
|
@ -1442,7 +1442,12 @@ void SceneOpenGL2Window::performPaint(int mask, QRegion region, WindowPaintData
|
|||
// the previous Client's content space.
|
||||
WindowQuad newQuad(WindowQuadContents);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
newQuad[i] = WindowVertex(quad[i].x(), quad[i].y(), quad[i].u(), quad[i].v());
|
||||
const qreal xFactor = qreal(quad[i].textureX() - toplevel->clientPos().x())/qreal(toplevel->clientSize().width());
|
||||
const qreal yFactor = qreal(quad[i].textureY() - toplevel->clientPos().y())/qreal(toplevel->clientSize().height());
|
||||
WindowVertex vertex(quad[i].x(), quad[i].y(),
|
||||
(xFactor * oldGeometry.width() + oldGeometry.x())/qreal(previous->size().width()),
|
||||
(yFactor * oldGeometry.height() + oldGeometry.y())/qreal(previous->size().height()));
|
||||
newQuad[i] = vertex;
|
||||
}
|
||||
quads[PreviousContentLeaf].append(newQuad);
|
||||
}
|
||||
|
@ -2519,52 +2524,6 @@ static QImage rotate(const QImage &srcImage, const QRect &srcRect)
|
|||
return image;
|
||||
}
|
||||
|
||||
static void clamp_row(int left, int width, int right, const uint32_t *src, uint32_t *dest)
|
||||
{
|
||||
std::fill_n(dest, left, *src);
|
||||
std::copy(src, src + width, dest + left);
|
||||
std::fill_n(dest + left + width, right, *(src + width - 1));
|
||||
}
|
||||
|
||||
static void clamp_sides(int left, int width, int right, const uint32_t *src, uint32_t *dest)
|
||||
{
|
||||
std::fill_n(dest, left, *src);
|
||||
std::fill_n(dest + left + width, right, *(src + width - 1));
|
||||
}
|
||||
|
||||
static void clamp(QImage &image, const QRect &viewport)
|
||||
{
|
||||
Q_ASSERT(image.depth() == 32);
|
||||
|
||||
const QRect rect = image.rect();
|
||||
|
||||
const int left = viewport.left() - rect.left();
|
||||
const int top = viewport.top() - rect.top();
|
||||
const int right = rect.right() - viewport.right();
|
||||
const int bottom = rect.bottom() - viewport.bottom();
|
||||
|
||||
const int width = rect.width() - left - right;
|
||||
const int height = rect.height() - top - bottom;
|
||||
|
||||
const uint32_t *firstRow = reinterpret_cast<uint32_t *>(image.scanLine(top));
|
||||
const uint32_t *lastRow = reinterpret_cast<uint32_t *>(image.scanLine(top + height - 1));
|
||||
|
||||
for (int i = 0; i < top; ++i) {
|
||||
uint32_t *dest = reinterpret_cast<uint32_t *>(image.scanLine(i));
|
||||
clamp_row(left, width, right, firstRow + left, dest);
|
||||
}
|
||||
|
||||
for (int i = 0; i < height; ++i) {
|
||||
uint32_t *dest = reinterpret_cast<uint32_t *>(image.scanLine(top + i));
|
||||
clamp_sides(left, width, right, dest + left, dest);
|
||||
}
|
||||
|
||||
for (int i = 0; i < bottom; ++i) {
|
||||
uint32_t *dest = reinterpret_cast<uint32_t *>(image.scanLine(top + height + i));
|
||||
clamp_row(left, width, right, lastRow + left, dest);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneOpenGLDecorationRenderer::render()
|
||||
{
|
||||
const QRegion scheduled = getScheduled();
|
||||
|
@ -2587,68 +2546,21 @@ void SceneOpenGLDecorationRenderer::render()
|
|||
|
||||
const QRect geometry = dirty ? QRect(QPoint(0, 0), client()->client()->size()) : scheduled.boundingRect();
|
||||
|
||||
// We pad each part in the decoration atlas in order to avoid texture bleeding.
|
||||
const int padding = 1;
|
||||
|
||||
auto renderPart = [=](const QRect &geo, const QRect &partRect, const QPoint &position, bool rotated = false) {
|
||||
auto renderPart = [this](const QRect &geo, const QRect &partRect, const QPoint &offset, bool rotated = false) {
|
||||
if (!geo.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QRect rect = geo;
|
||||
|
||||
// We allow partial decoration updates and it might just so happen that the dirty region
|
||||
// is completely contained inside the decoration part, i.e. the dirty region doesn't touch
|
||||
// any of the decoration's edges. In that case, we should **not** pad the dirty region.
|
||||
if (rect.left() == partRect.left()) {
|
||||
rect.setLeft(rect.left() - padding);
|
||||
}
|
||||
if (rect.top() == partRect.top()) {
|
||||
rect.setTop(rect.top() - padding);
|
||||
}
|
||||
if (rect.right() == partRect.right()) {
|
||||
rect.setRight(rect.right() + padding);
|
||||
}
|
||||
if (rect.bottom() == partRect.bottom()) {
|
||||
rect.setBottom(rect.bottom() + padding);
|
||||
}
|
||||
|
||||
QRect viewport = geo.translated(-rect.x(), -rect.y());
|
||||
const qreal devicePixelRatio = client()->client()->screenScale();
|
||||
|
||||
QImage image(rect.size() * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
|
||||
image.setDevicePixelRatio(devicePixelRatio);
|
||||
image.fill(Qt::transparent);
|
||||
|
||||
QPainter painter(&image);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setViewport(QRect(viewport.topLeft(), viewport.size() * devicePixelRatio));
|
||||
painter.setWindow(QRect(geo.topLeft(), geo.size() * devicePixelRatio));
|
||||
painter.setClipRect(geo);
|
||||
renderToPainter(&painter, geo);
|
||||
painter.end();
|
||||
|
||||
clamp(image, QRect(viewport.topLeft() * devicePixelRatio, viewport.size() * devicePixelRatio));
|
||||
|
||||
QImage image = renderToImage(geo);
|
||||
if (rotated) {
|
||||
// TODO: get this done directly when rendering to the image
|
||||
image = rotate(image, QRect(QPoint(), rect.size()));
|
||||
viewport = QRect(viewport.y(), viewport.x(), viewport.height(), viewport.width());
|
||||
image = rotate(image, QRect(geo.topLeft() - partRect.topLeft(), geo.size()));
|
||||
}
|
||||
|
||||
const QPoint dirtyOffset = geo.topLeft() - partRect.topLeft();
|
||||
m_texture->update(image, (position + dirtyOffset - viewport.topLeft()) * image.devicePixelRatio());
|
||||
m_texture->update(image, (geo.topLeft() - partRect.topLeft() + offset) * image.devicePixelRatio());
|
||||
};
|
||||
|
||||
const QPoint topPosition(padding, padding);
|
||||
const QPoint bottomPosition(padding, topPosition.y() + top.height() + 2 * padding);
|
||||
const QPoint leftPosition(padding, bottomPosition.y() + bottom.height() + 2 * padding);
|
||||
const QPoint rightPosition(padding, leftPosition.y() + left.width() + 2 * padding);
|
||||
|
||||
renderPart(left.intersected(geometry), left, leftPosition, true);
|
||||
renderPart(top.intersected(geometry), top, topPosition);
|
||||
renderPart(right.intersected(geometry), right, rightPosition, true);
|
||||
renderPart(bottom.intersected(geometry), bottom, bottomPosition);
|
||||
renderPart(left.intersected(geometry), left, QPoint(0, top.height() + bottom.height() + 2), true);
|
||||
renderPart(top.intersected(geometry), top, QPoint(0, 0));
|
||||
renderPart(right.intersected(geometry), right, QPoint(0, top.height() + bottom.height() + left.width() + 3), true);
|
||||
renderPart(bottom.intersected(geometry), bottom, QPoint(0, top.height() + 1));
|
||||
}
|
||||
|
||||
static int align(int value, int align)
|
||||
|
@ -2665,12 +2577,7 @@ void SceneOpenGLDecorationRenderer::resizeTexture()
|
|||
size.rwidth() = qMax(qMax(top.width(), bottom.width()),
|
||||
qMax(left.height(), right.height()));
|
||||
size.rheight() = top.height() + bottom.height() +
|
||||
left.width() + right.width();
|
||||
|
||||
// Reserve some space for padding. We pad decoration parts to avoid texture bleeding.
|
||||
const int padding = 1;
|
||||
size.rwidth() += 2 * padding;
|
||||
size.rheight() += 4 * 2 * padding;
|
||||
left.width() + right.width() + 3;
|
||||
|
||||
size.rwidth() = align(size.width(), 128);
|
||||
|
||||
|
|
35
scene.cpp
35
scene.cpp
|
@ -3,7 +3,6 @@
|
|||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
Copyright (C) 2019 Vlad Zahorodnii <vladzzag@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -736,7 +735,7 @@ QRegion Scene::Window::bufferShape() const
|
|||
const QRect bufferGeometry = toplevel->bufferGeometry();
|
||||
|
||||
if (toplevel->shape()) {
|
||||
auto cookie = xcb_shape_get_rectangles_unchecked(connection(), toplevel->windowId(), XCB_SHAPE_SK_BOUNDING);
|
||||
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();
|
||||
|
@ -766,7 +765,15 @@ QRegion Scene::Window::clientShape() const
|
|||
return QRegion();
|
||||
}
|
||||
}
|
||||
return bufferShape();
|
||||
|
||||
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
|
||||
|
@ -880,18 +887,11 @@ WindowQuadList Scene::Window::makeDecorationQuads(const QRect *rects, const QReg
|
|||
{
|
||||
WindowQuadList list;
|
||||
|
||||
const int padding = 1;
|
||||
|
||||
const QPoint topSpritePosition(padding, padding);
|
||||
const QPoint bottomSpritePosition(padding, topSpritePosition.y() + rects[1].height() + 2 * padding);
|
||||
const QPoint leftSpritePosition(bottomSpritePosition.y() + rects[3].height() + 2 * padding, padding);
|
||||
const QPoint rightSpritePosition(leftSpritePosition.x() + rects[0].width() + 2 * padding, padding);
|
||||
|
||||
const QPoint offsets[4] = {
|
||||
QPoint(-rects[0].x(), -rects[0].y()) + leftSpritePosition,
|
||||
QPoint(-rects[1].x(), -rects[1].y()) + topSpritePosition,
|
||||
QPoint(-rects[2].x(), -rects[2].y()) + rightSpritePosition,
|
||||
QPoint(-rects[3].x(), -rects[3].y()) + bottomSpritePosition,
|
||||
QPoint(-rects[0].x() + rects[1].height() + rects[3].height() + 2, -rects[0].y()), // Left
|
||||
QPoint(-rects[1].x(), -rects[1].y()), // Top
|
||||
QPoint(-rects[2].x() + rects[1].height() + rects[3].height() + rects[0].width() + 3, -rects[2].y()), // Right
|
||||
QPoint(-rects[3].x(), -rects[3].y() + rects[1].height() + 1) // Bottom
|
||||
};
|
||||
|
||||
const Qt::Orientation orientations[4] = {
|
||||
|
@ -1039,9 +1039,9 @@ void WindowPixmap::create()
|
|||
}
|
||||
XServerGrabber grabber;
|
||||
xcb_pixmap_t pix = xcb_generate_id(connection());
|
||||
xcb_void_cookie_t namePixmapCookie = xcb_composite_name_window_pixmap_checked(connection(), toplevel()->windowId(), pix);
|
||||
Xcb::WindowAttributes windowAttributes(toplevel()->windowId());
|
||||
Xcb::WindowGeometry windowGeometry(toplevel()->windowId());
|
||||
xcb_void_cookie_t namePixmapCookie = xcb_composite_name_window_pixmap_checked(connection(), toplevel()->frameId(), pix);
|
||||
Xcb::WindowAttributes windowAttributes(toplevel()->frameId());
|
||||
Xcb::WindowGeometry windowGeometry(toplevel()->frameId());
|
||||
if (xcb_generic_error_t *error = xcb_request_check(connection(), namePixmapCookie)) {
|
||||
qCDebug(KWIN_CORE) << "Creating window pixmap failed: " << error->error_code;
|
||||
free(error);
|
||||
|
@ -1062,6 +1062,7 @@ void WindowPixmap::create()
|
|||
}
|
||||
m_pixmap = pix;
|
||||
m_pixmapSize = bufferGeometry.size();
|
||||
m_contentsRect = QRect(toplevel()->clientPos(), toplevel()->clientSize());
|
||||
m_window->unreferencePreviousPixmap();
|
||||
}
|
||||
|
||||
|
|
14
scene.h
14
scene.h
|
@ -3,7 +3,6 @@
|
|||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
Copyright (C) 2019 Vlad Zahorodnii <vladzzag@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -449,6 +448,12 @@ public:
|
|||
* The size of the pixmap.
|
||||
*/
|
||||
const QSize &size() const;
|
||||
/**
|
||||
* The geometry of the Client's content inside the pixmap. In case of a decorated Client the
|
||||
* pixmap also contains the decoration which is not rendered into this pixmap, though. This
|
||||
* contentsRect tells where inside the complete pixmap the real content is.
|
||||
*/
|
||||
const QRect &contentsRect() const;
|
||||
/**
|
||||
* @brief Returns the Toplevel this WindowPixmap belongs to.
|
||||
* Note: the Toplevel can change over the lifetime of the WindowPixmap in case the Toplevel is copied to Deleted.
|
||||
|
@ -508,6 +513,7 @@ private:
|
|||
xcb_pixmap_t m_pixmap;
|
||||
QSize m_pixmapSize;
|
||||
bool m_discarded;
|
||||
QRect m_contentsRect;
|
||||
QPointer<KWayland::Server::BufferInterface> m_buffer;
|
||||
QSharedPointer<QOpenGLFramebufferObject> m_fbo;
|
||||
QImage m_internalImage;
|
||||
|
@ -673,6 +679,12 @@ void WindowPixmap::markAsDiscarded()
|
|||
m_window->referencePreviousPixmap();
|
||||
}
|
||||
|
||||
inline
|
||||
const QRect &WindowPixmap::contentsRect() const
|
||||
{
|
||||
return m_contentsRect;
|
||||
}
|
||||
|
||||
inline
|
||||
const QSize &WindowPixmap::size() const
|
||||
{
|
||||
|
|
17
toplevel.cpp
17
toplevel.cpp
|
@ -3,7 +3,6 @@
|
|||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
Copyright (C) 2019 Vlad Zahorodnii <vladzzag@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -257,13 +256,12 @@ bool Toplevel::setupCompositing()
|
|||
if (damage_handle != XCB_NONE)
|
||||
return false;
|
||||
|
||||
if (kwinApp()->operationMode() == Application::OperationModeX11) {
|
||||
if (kwinApp()->operationMode() == Application::OperationModeX11 && !surface()) {
|
||||
damage_handle = xcb_generate_id(connection());
|
||||
xcb_damage_create(connection(), damage_handle, windowId(), XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY);
|
||||
xcb_composite_redirect_window(connection(), windowId(), XCB_COMPOSITE_REDIRECT_MANUAL);
|
||||
xcb_damage_create(connection(), damage_handle, frameId(), XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY);
|
||||
}
|
||||
|
||||
damage_region = QRegion(QRect(QPoint(), bufferGeometry().size()));
|
||||
damage_region = QRegion(0, 0, width(), height());
|
||||
effect_window = new EffectWindowImpl(this);
|
||||
|
||||
Compositor::self()->scene()->addToplevel(this);
|
||||
|
@ -280,10 +278,6 @@ void Toplevel::finishCompositing(ReleaseReason releaseReason)
|
|||
delete effect_window;
|
||||
}
|
||||
|
||||
if (kwinApp()->operationMode() == Application::OperationModeX11) {
|
||||
xcb_composite_unredirect_window(connection(), windowId(), XCB_COMPOSITE_REDIRECT_MANUAL);
|
||||
}
|
||||
|
||||
if (damage_handle != XCB_NONE &&
|
||||
releaseReason != ReleaseReason::Destroyed) {
|
||||
xcb_damage_destroy(connection(), damage_handle);
|
||||
|
@ -797,6 +791,11 @@ bool Toplevel::isLocalhost() const
|
|||
return m_clientMachine->isLocal();
|
||||
}
|
||||
|
||||
QMargins Toplevel::bufferMargins() const
|
||||
{
|
||||
return QMargins();
|
||||
}
|
||||
|
||||
QMargins Toplevel::frameMargins() const
|
||||
{
|
||||
return QMargins();
|
||||
|
|
11
toplevel.h
11
toplevel.h
|
@ -3,7 +3,6 @@
|
|||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
Copyright (C) 2019 Vlad Zahorodnii <vladzzag@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -316,6 +315,16 @@ 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.
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
|
||||
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
|
||||
Copyright (C) 2019 Vlad Zahorodnii <vladzzag@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -256,7 +255,7 @@ void X11Client::releaseWindow(bool on_shutdown)
|
|||
m_client.deleteProperty(atoms->kde_net_wm_user_creation_time);
|
||||
m_client.deleteProperty(atoms->net_frame_extents);
|
||||
m_client.deleteProperty(atoms->kde_net_wm_frame_strut);
|
||||
m_client.reparent(rootWindow(), m_serverGeometry.x(), m_serverGeometry.y());
|
||||
m_client.reparent(rootWindow(), m_bufferGeometry.x(), m_bufferGeometry.y());
|
||||
xcb_change_save_set(c, XCB_SET_MODE_DELETE, m_client);
|
||||
m_client.selectInput(XCB_EVENT_MASK_NO_EVENT);
|
||||
if (on_shutdown)
|
||||
|
@ -1986,7 +1985,12 @@ xcb_window_t X11Client::frameId() const
|
|||
|
||||
QRect X11Client::bufferGeometry() const
|
||||
{
|
||||
return m_clientGeometry;
|
||||
return m_bufferGeometry;
|
||||
}
|
||||
|
||||
QMargins X11Client::bufferMargins() const
|
||||
{
|
||||
return QMargins(borderLeft(), borderTop(), borderRight(), borderBottom());
|
||||
}
|
||||
|
||||
QPoint X11Client::framePosToClientPos(const QPoint &point) const
|
||||
|
@ -2212,21 +2216,64 @@ void X11Client::handleSync()
|
|||
addRepaintFull();
|
||||
}
|
||||
|
||||
bool X11Client::canUpdatePosition(const QPoint &frame, const QPoint &buffer, ForceGeometry_t force) const
|
||||
{
|
||||
// Obey forced geometry updates.
|
||||
if (force != NormalGeometrySet) {
|
||||
return true;
|
||||
}
|
||||
// Server-side geometry and our geometry are out of sync.
|
||||
if (bufferGeometry().topLeft() != buffer) {
|
||||
return true;
|
||||
}
|
||||
if (frameGeometry().topLeft() != frame) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool X11Client::canUpdateSize(const QSize &frame, const QSize &buffer, ForceGeometry_t force) const
|
||||
{
|
||||
// Obey forced geometry updates.
|
||||
if (force != NormalGeometrySet) {
|
||||
return true;
|
||||
}
|
||||
// Server-side geometry and our geometry are out of sync.
|
||||
if (bufferGeometry().size() != buffer) {
|
||||
return true;
|
||||
}
|
||||
if (frameGeometry().size() != frame) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool X11Client::canUpdateGeometry(const QRect &frame, const QRect &buffer, ForceGeometry_t force) const
|
||||
{
|
||||
if (canUpdatePosition(frame.topLeft(), buffer.topLeft(), force)) {
|
||||
return true;
|
||||
}
|
||||
if (canUpdateSize(frame.size(), buffer.size(), force)) {
|
||||
return true;
|
||||
}
|
||||
return pendingGeometryUpdate() != PendingGeometryNone;
|
||||
}
|
||||
|
||||
void X11Client::move(int x, int y, ForceGeometry_t force)
|
||||
{
|
||||
const QPoint framePosition(x, y);
|
||||
m_clientGeometry.moveTopLeft(framePosToClientPos(framePosition));
|
||||
const QPoint serverPosition = isDecorated() ? framePosition : m_clientGeometry.topLeft();
|
||||
const QPoint bufferPosition = isDecorated() ? framePosition : m_clientGeometry.topLeft();
|
||||
// resuming geometry updates is handled only in setGeometry()
|
||||
Q_ASSERT(pendingGeometryUpdate() == PendingGeometryNone || areGeometryUpdatesBlocked());
|
||||
if (!areGeometryUpdatesBlocked() && framePosition != rules()->checkPosition(framePosition)) {
|
||||
qCDebug(KWIN_CORE) << "forced position fail:" << framePosition << ":" << rules()->checkPosition(framePosition);
|
||||
}
|
||||
geom.moveTopLeft(framePosition);
|
||||
if (force == NormalGeometrySet && m_serverGeometry.topLeft() == serverPosition) {
|
||||
if (!canUpdatePosition(framePosition, bufferPosition, force)) {
|
||||
return;
|
||||
}
|
||||
m_serverGeometry.moveTopLeft(serverPosition);
|
||||
m_bufferGeometry.moveTopLeft(bufferPosition);
|
||||
geom.moveTopLeft(framePosition);
|
||||
if (areGeometryUpdatesBlocked()) {
|
||||
if (pendingGeometryUpdate() == PendingGeometryForced) {
|
||||
// Maximum, nothing needed.
|
||||
|
@ -2237,7 +2284,8 @@ void X11Client::move(int x, int y, ForceGeometry_t force)
|
|||
}
|
||||
return;
|
||||
}
|
||||
updateServerGeometry();
|
||||
m_frame.move(m_bufferGeometry.topLeft());
|
||||
sendSyntheticConfigureNotify();
|
||||
updateWindowRules(Rules::Position);
|
||||
screens()->setCurrent(this);
|
||||
workspace()->updateStackingOrder();
|
||||
|
|
28
x11client.h
28
x11client.h
|
@ -4,7 +4,6 @@
|
|||
|
||||
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
|
||||
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
|
||||
Copyright (C) 2019 Vlad Zahorodnii <vladzzag@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -58,25 +57,6 @@ enum class Predicate {
|
|||
InputIdMatch
|
||||
};
|
||||
|
||||
/**
|
||||
* The X11Client class represents a managed X11 client.
|
||||
*
|
||||
* Note that override-redirect clients are represented by instances of the Unmanaged class.
|
||||
*
|
||||
* Each X11 client has three geometries associated with it - frame, client, and server. The frame
|
||||
* geometry is the most easiest one to understand, it specifies visible bounds of the window from
|
||||
* the user's perspective. The frame geometry doesn't include server-side and client-side drop
|
||||
* shadows. Window operations such resizing, snapping, tiling and so on must operate on this kind
|
||||
* of geometry. The client geometry specifies a rectangle on the screen occupied by the client
|
||||
* window. The server-side decoration, if any, must be put around the client geometry. The server
|
||||
* geometry specifies the server-side geometry of the frame window.
|
||||
*
|
||||
* There is no strict order between the frame and the client geometry. Either one of them can be
|
||||
* inside the other one. However, it's always guaranteed that both of them are inside the server
|
||||
* geometry.
|
||||
*
|
||||
* The buffer geometry is an alias for the client geometry.
|
||||
*/
|
||||
class KWIN_EXPORT X11Client : public AbstractClient
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -110,6 +90,7 @@ public:
|
|||
xcb_window_t frameId() const override;
|
||||
|
||||
QRect bufferGeometry() const override;
|
||||
QMargins bufferMargins() const override;
|
||||
|
||||
QPoint framePosToClientPos(const QPoint &point) const override;
|
||||
QPoint clientPosToFramePos(const QPoint &point) const override;
|
||||
|
@ -465,6 +446,9 @@ private:
|
|||
void destroyDecoration() override;
|
||||
void updateFrameExtents();
|
||||
void setClientFrameExtents(const NETStrut &strut);
|
||||
bool canUpdatePosition(const QPoint &frame, const QPoint &buffer, ForceGeometry_t force) const;
|
||||
bool canUpdateSize(const QSize &frame, const QSize &buffer, ForceGeometry_t force) const;
|
||||
bool canUpdateGeometry(const QRect &frame, const QRect &buffer, ForceGeometry_t force) const;
|
||||
|
||||
void internalShow();
|
||||
void internalHide();
|
||||
|
@ -472,7 +456,7 @@ private:
|
|||
void map();
|
||||
void unmap();
|
||||
void updateHiddenPreview();
|
||||
void updateServerGeometry();
|
||||
|
||||
void updateInputShape();
|
||||
|
||||
xcb_timestamp_t readUserTimeMapTimestamp(const KStartupInfoId* asn_id, const KStartupInfoData* asn_data,
|
||||
|
@ -538,7 +522,7 @@ private:
|
|||
} m_fullscreenMode;
|
||||
|
||||
MaximizeMode max_mode;
|
||||
QRect m_serverGeometry = QRect(0, 0, 100, 100);
|
||||
QRect m_bufferGeometry = QRect(0, 0, 100, 100);
|
||||
QRect m_clientGeometry = QRect(0, 0, 100, 100);
|
||||
QRect geom_restore;
|
||||
QRect geom_fs_restore;
|
||||
|
|
Loading…
Reference in a new issue