Introduce support for DecorationShadow

Surprisingly the DecorationShadow is modelled after the Shadow in KWin.
It provides the same offsets and a QImage exactly like the OpenGL
implementation needs it. This makes it easy to hook it into our existing
Shadow implementation with only a few changes.

Shadow now first tries to create a Shadow from the Decoration and only
if that fails it tries the X11 property. The pixmaps are not initialized
for the DecorationShadow and because of that currently only the OpenGL
backend gets initialized for DecorationShadows. The other backends might
need adjustments and also a transition to just using one image.
icc-effect-5.14.5
Martin Gräßlin 2014-07-24 08:39:25 +02:00
parent b12d11a06c
commit 08d146de91
6 changed files with 182 additions and 13 deletions

View File

@ -503,6 +503,7 @@ void Client::updateDecoration(bool check_workspace_pos, bool force)
createDecoration(oldgeom);
} else
destroyDecoration();
getShadow();
if (check_workspace_pos)
checkWorkspacePosition(oldgeom);
updateInputWindow();
@ -515,6 +516,7 @@ void Client::createDecoration(const QRect& oldgeom)
m_decoration = Decoration::DecorationBridge::self()->createDecoration(this);
if (m_decoration) {
m_decoration->update();
connect(m_decoration, &KDecoration2::Decoration::shadowChanged, this, &Toplevel::getShadow);
}
move(calculateGravitation(false));

View File

@ -1836,14 +1836,14 @@ void SceneOpenGLShadow::buildQuads()
{
// prepare window quads
m_shadowQuads.clear();
const QSizeF top(shadowPixmap(ShadowElementTop).size());
const QSizeF topRight(shadowPixmap(ShadowElementTopRight).size());
const QSizeF right(shadowPixmap(ShadowElementRight).size());
const QSizeF bottomRight(shadowPixmap(ShadowElementBottomRight).size());
const QSizeF bottom(shadowPixmap(ShadowElementBottom).size());
const QSizeF bottomLeft(shadowPixmap(ShadowElementBottomLeft).size());
const QSizeF left(shadowPixmap(ShadowElementLeft).size());
const QSizeF topLeft(shadowPixmap(ShadowElementTopLeft).size());
const QSizeF top(elementSize(ShadowElementTop));
const QSizeF topRight(elementSize(ShadowElementTopRight));
const QSizeF right(elementSize(ShadowElementRight));
const QSizeF bottomRight(elementSize(ShadowElementBottomRight));
const QSizeF bottom(elementSize(ShadowElementBottom));
const QSizeF bottomLeft(elementSize(ShadowElementBottomLeft));
const QSizeF left(elementSize(ShadowElementLeft));
const QSizeF topLeft(elementSize(ShadowElementTopLeft));
if ((left.width() - leftOffset() > topLevel()->width()) ||
(right.width() - rightOffset() > topLevel()->width()) ||
(top.height() - topOffset() > topLevel()->height()) ||
@ -1943,6 +1943,14 @@ void SceneOpenGLShadow::buildQuads()
bool SceneOpenGLShadow::prepareBackend()
{
if (hasDecorationShadow()) {
// simplifies a lot by going directly to
effects->makeOpenGLContextCurrent();
delete m_texture;
m_texture = new GLTexture(decorationShadowImage());
return true;
}
const QSize top(shadowPixmap(ShadowElementTop).size());
const QSize topRight(shadowPixmap(ShadowElementTopRight).size());
const QSize right(shadowPixmap(ShadowElementRight).size());

View File

@ -615,6 +615,10 @@ SceneQPainterShadow::~SceneQPainterShadow()
bool SceneQPainterShadow::prepareBackend()
{
if (hasDecorationShadow()) {
// TODO: implement for QPainter
return false;
}
return true;
}

View File

@ -1296,6 +1296,10 @@ void SceneXRenderShadow::buildQuads()
bool SceneXRenderShadow::prepareBackend()
{
if (hasDecorationShadow()) {
// TODO: implement for XRender
return false;
}
const uint32_t values[] = {XCB_RENDER_REPEAT_NORMAL};
for (int i=0; i<ShadowElementsCount; ++i) {
delete m_pictures[i];

View File

@ -20,16 +20,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "shadow.h"
// kwin
#include "atoms.h"
#include "client.h"
#include "composite.h"
#include "effects.h"
#include "toplevel.h"
#include <KDecoration2/Decoration>
#include <KDecoration2/DecorationShadow>
namespace KWin
{
Shadow::Shadow(Toplevel *toplevel)
: m_topLevel(toplevel)
, m_cachedSize(toplevel->geometry().size())
, m_decorationShadow(nullptr)
{
connect(m_topLevel, SIGNAL(geometryChanged()), SLOT(geometryChanged()));
}
@ -43,6 +48,20 @@ Shadow *Shadow::createShadow(Toplevel *toplevel)
if (!effects) {
return NULL;
}
Shadow *shadow = crateShadowFromDecoration(toplevel);
if (!shadow) {
shadow = createShadowFromX11(toplevel);
}
if (shadow) {
if (toplevel->effectWindow() && toplevel->effectWindow()->sceneWindow()) {
toplevel->effectWindow()->sceneWindow()->updateShadow(shadow);
}
}
return shadow;
}
Shadow *Shadow::createShadowFromX11(Toplevel *toplevel)
{
auto data = Shadow::readX11ShadowProperty(toplevel->window());
if (!data.isEmpty()) {
Shadow *shadow = Compositor::self()->scene()->createShadow(toplevel);
@ -51,15 +70,29 @@ Shadow *Shadow::createShadow(Toplevel *toplevel)
delete shadow;
return NULL;
}
if (toplevel->effectWindow() && toplevel->effectWindow()->sceneWindow()) {
toplevel->effectWindow()->sceneWindow()->updateShadow(shadow);
}
return shadow;
} else {
return NULL;
}
}
Shadow *Shadow::crateShadowFromDecoration(Toplevel *toplevel)
{
Client *c = qobject_cast<Client*>(toplevel);
if (!c) {
return nullptr;
}
if (!c->decoration()) {
return nullptr;
}
Shadow *shadow = Compositor::self()->scene()->createShadow(toplevel);
if (!shadow->init(c->decoration())) {
delete shadow;
return nullptr;
}
return shadow;
}
QVector< uint32_t > Shadow::readX11ShadowProperty(xcb_window_t id)
{
QVector<uint32_t> ret;
@ -119,6 +152,55 @@ bool Shadow::init(const QVector< uint32_t > &data)
return true;
}
bool Shadow::init(KDecoration2::Decoration *decoration)
{
if (m_decorationShadow) {
// disconnect previous connections
disconnect(m_decorationShadow, &KDecoration2::DecorationShadow::topLeftChanged, m_topLevel, &Toplevel::getShadow);
disconnect(m_decorationShadow, &KDecoration2::DecorationShadow::topChanged, m_topLevel, &Toplevel::getShadow);
disconnect(m_decorationShadow, &KDecoration2::DecorationShadow::topRightChanged, m_topLevel, &Toplevel::getShadow);
disconnect(m_decorationShadow, &KDecoration2::DecorationShadow::rightChanged, m_topLevel, &Toplevel::getShadow);
disconnect(m_decorationShadow, &KDecoration2::DecorationShadow::bottomRightChanged, m_topLevel, &Toplevel::getShadow);
disconnect(m_decorationShadow, &KDecoration2::DecorationShadow::bottomChanged, m_topLevel, &Toplevel::getShadow);
disconnect(m_decorationShadow, &KDecoration2::DecorationShadow::bottomLeftChanged, m_topLevel, &Toplevel::getShadow);
disconnect(m_decorationShadow, &KDecoration2::DecorationShadow::leftChanged, m_topLevel, &Toplevel::getShadow);
disconnect(m_decorationShadow, &KDecoration2::DecorationShadow::shadowChanged, m_topLevel, &Toplevel::getShadow);
disconnect(m_decorationShadow, &KDecoration2::DecorationShadow::paddingLeftChanged, m_topLevel, &Toplevel::getShadow);
disconnect(m_decorationShadow, &KDecoration2::DecorationShadow::paddingTopChanged, m_topLevel, &Toplevel::getShadow);
disconnect(m_decorationShadow, &KDecoration2::DecorationShadow::paddingRightChanged, m_topLevel, &Toplevel::getShadow);
disconnect(m_decorationShadow, &KDecoration2::DecorationShadow::paddingBottomChanged, m_topLevel, &Toplevel::getShadow);
}
m_decorationShadow = static_cast<const KDecoration2::Decoration*>(decoration)->shadow();
if (!m_decorationShadow) {
return false;
}
// setup connections - all just mapped to recreate
connect(m_decorationShadow, &KDecoration2::DecorationShadow::topLeftChanged, m_topLevel, &Toplevel::getShadow);
connect(m_decorationShadow, &KDecoration2::DecorationShadow::topChanged, m_topLevel, &Toplevel::getShadow);
connect(m_decorationShadow, &KDecoration2::DecorationShadow::topRightChanged, m_topLevel, &Toplevel::getShadow);
connect(m_decorationShadow, &KDecoration2::DecorationShadow::rightChanged, m_topLevel, &Toplevel::getShadow);
connect(m_decorationShadow, &KDecoration2::DecorationShadow::bottomRightChanged, m_topLevel, &Toplevel::getShadow);
connect(m_decorationShadow, &KDecoration2::DecorationShadow::bottomChanged, m_topLevel, &Toplevel::getShadow);
connect(m_decorationShadow, &KDecoration2::DecorationShadow::bottomLeftChanged, m_topLevel, &Toplevel::getShadow);
connect(m_decorationShadow, &KDecoration2::DecorationShadow::leftChanged, m_topLevel, &Toplevel::getShadow);
connect(m_decorationShadow, &KDecoration2::DecorationShadow::shadowChanged, m_topLevel, &Toplevel::getShadow);
connect(m_decorationShadow, &KDecoration2::DecorationShadow::paddingLeftChanged, m_topLevel, &Toplevel::getShadow);
connect(m_decorationShadow, &KDecoration2::DecorationShadow::paddingTopChanged, m_topLevel, &Toplevel::getShadow);
connect(m_decorationShadow, &KDecoration2::DecorationShadow::paddingRightChanged, m_topLevel, &Toplevel::getShadow);
connect(m_decorationShadow, &KDecoration2::DecorationShadow::paddingBottomChanged, m_topLevel, &Toplevel::getShadow);
m_topOffset = m_decorationShadow->paddingTop();
m_rightOffset = m_decorationShadow->paddingRight();
m_bottomOffset = m_decorationShadow->paddingBottom();
m_leftOffset = m_decorationShadow->paddingLeft();
updateShadowRegion();
if (!prepareBackend()) {
return false;
}
buildQuads();
return true;
}
void Shadow::updateShadowRegion()
{
const QRect top(0, - m_topOffset, m_topLevel->width(), m_topOffset);
@ -210,14 +292,30 @@ void Shadow::buildQuads()
bool Shadow::updateShadow()
{
auto data = Shadow::readX11ShadowProperty(m_topLevel->window());
if (data.isEmpty()) {
auto clear = [this]() {
if (m_topLevel && m_topLevel->effectWindow() && m_topLevel->effectWindow()->sceneWindow() &&
m_topLevel->effectWindow()->sceneWindow()->shadow()) {
m_topLevel->effectWindow()->sceneWindow()->updateShadow(0);
m_topLevel->effectWindow()->buildQuads(true);
}
deleteLater();
};
if (m_decorationShadow) {
if (Client *c = qobject_cast<Client*>(m_topLevel)) {
if (c->decoration()) {
if (init(c->decoration())) {
if (m_topLevel && m_topLevel->effectWindow())
m_topLevel->effectWindow()->buildQuads(true);
return true;
}
}
}
clear();
return false;
}
auto data = Shadow::readX11ShadowProperty(m_topLevel->window());
if (data.isEmpty()) {
clear();
return false;
}
init(data);
@ -241,4 +339,40 @@ void Shadow::geometryChanged()
buildQuads();
}
QImage Shadow::decorationShadowImage() const
{
if (!m_decorationShadow) {
return QImage();
}
return m_decorationShadow->shadow();
}
QSize Shadow::elementSize(Shadow::ShadowElements element) const
{
if (m_decorationShadow) {
switch (element) {
case ShadowElementTop:
return m_decorationShadow->top();
case ShadowElementTopRight:
return m_decorationShadow->topRight();
case ShadowElementRight:
return m_decorationShadow->right();
case ShadowElementBottomRight:
return m_decorationShadow->bottomRight();
case ShadowElementBottom:
return m_decorationShadow->bottom();
case ShadowElementBottomLeft:
return m_decorationShadow->bottomLeft();
case ShadowElementLeft:
return m_decorationShadow->left();
case ShadowElementTopLeft:
return m_decorationShadow->topLeft();
default:
return QSize();
}
} else {
return m_shadowElements[element].size();
}
}
} // namespace

View File

@ -25,6 +25,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kwineffects.h>
#include <qvarlengtharray.h>
namespace KDecoration2
{
class Decoration;
class DecorationShadow;
}
namespace KWin {
class Toplevel;
@ -96,6 +102,11 @@ public:
**/
void setToplevel(Toplevel *toplevel);
bool hasDecorationShadow() const {
return m_decorationShadow;
}
QImage decorationShadowImage() const;
public Q_SLOTS:
void geometryChanged();
@ -116,6 +127,7 @@ protected:
inline const QPixmap &shadowPixmap(ShadowElements element) const {
return m_shadowElements[element];
};
QSize elementSize(ShadowElements element) const;
int topOffset() const {
return m_topOffset;
@ -141,8 +153,11 @@ protected:
WindowQuadList m_shadowQuads;
private:
static Shadow *createShadowFromX11(Toplevel *toplevel);
static Shadow *crateShadowFromDecoration(Toplevel *toplevel);
static QVector<uint32_t> readX11ShadowProperty(xcb_window_t id);
bool init(const QVector<uint32_t> &data);
bool init(KDecoration2::Decoration *decoration);
Toplevel *m_topLevel;
// shadow pixmaps
QPixmap m_shadowElements[ShadowElementsCount];
@ -154,6 +169,8 @@ private:
// caches
QRegion m_shadowRegion;
QSize m_cachedSize;
// Decoration based shadows
KDecoration2::DecorationShadow *m_decorationShadow;
};
}