diff --git a/effects/backgroundcontrast/contrast.cpp b/effects/backgroundcontrast/contrast.cpp index d0b304aced..d753b7119a 100644 --- a/effects/backgroundcontrast/contrast.cpp +++ b/effects/backgroundcontrast/contrast.cpp @@ -22,7 +22,6 @@ #include "contrast.h" #include "contrastshader.h" // KConfigSkeleton -#include "contrastconfig.h" #include @@ -75,6 +74,9 @@ void ContrastEffect::reconfigure(ReconfigureFlags flags) { Q_UNUSED(flags) + if (shader) + shader->init(); + if (!shader || !shader->isValid()) XDeleteProperty(display(), rootWindow(), net_wm_contrast_region); } @@ -85,21 +87,22 @@ void ContrastEffect::updateContrastRegion(EffectWindow *w) const float colorTransform[16]; const QByteArray value = w->readProperty(net_wm_contrast_region, XA_CARDINAL, 32); - if (value.size() > 0 && !((value.size() - (16 * sizeof(float))) % ((4 * sizeof(long))))) { - const long *cardinals = reinterpret_cast(value.constData()); + if (value.size() > 0 && !((value.size() - (3 * sizeof(uint32_t))) % ((4 * sizeof(uint32_t))))) { + const uint32_t *cardinals = reinterpret_cast(value.constData()); + qWarning()<<"GGG"<setColorMatrix(colorMatrix); + qreal contrast = ((qreal)cardinals[i++]) / 100; + qreal intensity = ((qreal)cardinals[i++]) / 100; + qreal saturation = ((qreal)cardinals[i++]) / 100; + + shader->setColorMatrix(colorMatrix(contrast, intensity, saturation)); } if (region.isEmpty() && !value.isNull()) { @@ -116,6 +119,52 @@ void ContrastEffect::slotWindowAdded(EffectWindow *w) updateContrastRegion(w); } +void ContrastEffect::slotPropertyNotify(EffectWindow *w, long atom) +{ + if (w && atom == net_wm_contrast_region) { + updateContrastRegion(w); + } +} + +QMatrix4x4 ContrastEffect::colorMatrix(qreal contrast, qreal intensity, qreal saturation) +{ + QMatrix4x4 satMatrix; //saturation + QMatrix4x4 intMatrix; //intensity + QMatrix4x4 contMatrix; //contrast + + //Saturation matrix + if (!qFuzzyCompare(saturation, 1.0)) { + const qreal rval = (1.0 - saturation) * .2126; + const qreal gval = (1.0 - saturation) * .7152; + const qreal bval = (1.0 - saturation) * .0722; + + satMatrix = QMatrix4x4(rval + saturation, rval, rval, 0.0, + gval, gval + saturation, gval, 0.0, + bval, bval, bval + saturation, 0.0, + 0, 0, 0, 1.0); + } + + //IntensityMatrix + if (!qFuzzyCompare(intensity, 1.0)) { + intMatrix.scale(intensity, intensity, intensity); + } + + //Contrast Matrix + if (!qFuzzyCompare(contrast, 1.0)) { + const float transl = (1.0 - contrast) / 2.0; + + contMatrix = QMatrix4x4(contrast, 0, 0, 0.0, + 0, contrast, 0, 0.0, + 0, 0, contrast, 0.0, + transl, transl, transl, 1.0); + } + + QMatrix4x4 colorMatrix = contMatrix * satMatrix * intMatrix; + //colorMatrix = colorMatrix.transposed(); + + return colorMatrix; +} + bool ContrastEffect::enabledByDefault() { GLPlatform *gl = GLPlatform::instance(); @@ -209,6 +258,63 @@ void ContrastEffect::uploadGeometry(GLVertexBuffer *vbo, const QRegion ®ion) vbo->setAttribLayout(layout, 2, sizeof(QVector2D)); } +void ContrastEffect::prePaintScreen(ScreenPrePaintData &data, int time) +{ + m_paintedArea = QRegion(); + m_currentContrast = QRegion(); + + effects->prePaintScreen(data, time); +} + +void ContrastEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) +{ + // this effect relies on prePaintWindow being called in the bottom to top order + + effects->prePaintWindow(w, data, time); + + if (!w->isPaintingEnabled()) { + return; + } + if (!shader || !shader->isValid()) { + return; + } + + const QRegion oldPaint = data.paint; + + // we don't have to blur a region we don't see + m_currentContrast -= data.clip; + // if we have to paint a non-opaque part of this window that intersects with the + // currently blurred region (which is not cached) we have to redraw the whole region + if ((data.paint-data.clip).intersects(m_currentContrast)) { + data.paint |= m_currentContrast; + } + + // in case this window has regions to be blurred + const QRect screen(0, 0, displayWidth(), displayHeight()); + const QRegion contrastArea = contrastRegion(w).translated(w->pos()) & screen; + + // we are not caching the window + + // if this window or an window underneath the modified area is painted again we have to + // do everything + if (m_paintedArea.intersects(contrastArea) || data.paint.intersects(contrastArea)) { + data.paint |= contrastArea; + + // we have to check again whether we do not damage a blurred area + // of a window we do not cache + if (contrastArea.intersects(m_currentContrast)) { + data.paint |= m_currentContrast; + } + } + + m_currentContrast |= contrastArea; + + + // m_paintedArea keep track of all repainted areas + m_paintedArea -= data.clip; + m_paintedArea |= data.paint; +} + bool ContrastEffect::shouldContrast(const EffectWindow *w, int mask, const WindowPaintData &data) const { if (!shader || !shader->isValid()) diff --git a/effects/backgroundcontrast/contrast.h b/effects/backgroundcontrast/contrast.h index 86d8cd8572..4362b60ff6 100644 --- a/effects/backgroundcontrast/contrast.h +++ b/effects/backgroundcontrast/contrast.h @@ -1,6 +1,5 @@ /* * Copyright © 2010 Fredrik Höglund - * Copyright 2014 Marco Martin * * 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 @@ -43,7 +42,10 @@ public: static bool supported(); static bool enabledByDefault(); + static QMatrix4x4 colorMatrix(qreal contrast, qreal intensity, qreal saturation); void reconfigure(ReconfigureFlags flags); + void prePaintScreen(ScreenPrePaintData &data, int time); + void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time); void drawWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data); void paintEffectFrame(EffectFrame *frame, QRegion region, double opacity, double frameOpacity); @@ -51,6 +53,7 @@ public: public Q_SLOTS: void slotWindowAdded(KWin::EffectWindow *w); + void slotPropertyNotify(KWin::EffectWindow *w, long atom); void slotScreenGeometryChanged(); private: @@ -64,6 +67,8 @@ private: private: ContrastShader *shader; long net_wm_contrast_region; + QRegion m_paintedArea; // actually painted area which is greater than m_damagedArea + QRegion m_currentContrast; // keeps track of the currently contrasted area of non-caching windows(from bottom to top) }; inline diff --git a/effects/backgroundcontrast/contrastshader.cpp b/effects/backgroundcontrast/contrastshader.cpp index 07d9377bcb..f814283fe8 100644 --- a/effects/backgroundcontrast/contrastshader.cpp +++ b/effects/backgroundcontrast/contrastshader.cpp @@ -47,10 +47,7 @@ ContrastShader::~ContrastShader() ContrastShader *ContrastShader::create() { if (ContrastShader::supported()) { - ContrastShader *s = new ContrastShader(); - s->reset(); - s->init(); - return s; + return new ContrastShader(); } return NULL; @@ -137,6 +134,7 @@ void ContrastShader::unbind() void ContrastShader::init() { + reset(); #ifdef KWIN_HAVE_OPENGLES diff --git a/effects/backgroundcontrast/contrastshader.h b/effects/backgroundcontrast/contrastshader.h index a6212ff8f2..cf8de81bf5 100644 --- a/effects/backgroundcontrast/contrastshader.h +++ b/effects/backgroundcontrast/contrastshader.h @@ -34,6 +34,8 @@ public: ContrastShader(); virtual ~ContrastShader(); + void init(); + static ContrastShader *create(); bool isValid() const { @@ -54,8 +56,7 @@ protected: void setIsValid(bool value) { mValid = value; } - virtual void init(); - virtual void reset(); + void reset(); private: bool mValid;