Decoration can announce whether it currently requires an alpha channel

A decoration can provide the AbilityAnnounceAlphaChannel in addition to
AbilityUsesAlphaChannel. If this ability is provided the decoration can
enable/disable the use of the alpha channel through setAlphaEnabled().

The base idea behind this mechanism is to be able to tell the compositor
that currently alpha is not needed. An example is the maximized state in
which the decoration is fully opaque so that there is no need to use the
translucency code path which would render all windows behind the deco.

In addition also the blur effect honors this setting so that behind a
known opaque decoration no blurring is performed.

Oxygen is adjusted to disable translucency in maximized state and Aurorae
is adjusted to allow themes to enable/disable translucency. For Plastik
translucency and with that also blurring is disabled.

REVIEW: 106810
This commit is contained in:
Martin Gräßlin 2012-10-12 11:34:05 +02:00
parent e66eb08140
commit 9308028fa4
21 changed files with 195 additions and 10 deletions

View file

@ -2422,6 +2422,20 @@ NET::WindowType Client::windowType(bool direct, int supportedTypes) const
return wt;
}
bool Client::decorationHasAlpha() const
{
if (!decoration || !workspace()->decorationHasAlpha()) {
// either no decoration or decoration has alpha disabled
return false;
}
if (workspace()->decorationSupportsAnnounceAlpha()) {
return decoration->isAlphaEnabled();
} else {
// decoration has alpha enabled and does not support alpha announcement
return true;
}
}
} // namespace
#include "client.moc"

View file

@ -274,6 +274,10 @@ class Client
* Use with care!
**/
Q_PROPERTY(bool blocksCompositing READ isBlockingCompositing WRITE setBlockingCompositing NOTIFY blockingCompositingChanged)
/**
* Whether the decoration is currently using an alpha channel.
**/
Q_PROPERTY(bool decorationHasAlpha READ decorationHasAlpha)
public:
Client(Workspace* ws);
Window wrapperId() const;
@ -607,6 +611,8 @@ public:
QRegion decorationPendingRegion() const;
bool decorationHasAlpha() const;
enum CoordinateMode {
DecorationRelative, // Relative to the top left corner of the decoration
WindowRelative // Relative to the top left corner of the window

View file

@ -180,6 +180,7 @@ bool AuroraeFactory::supports(Ability ability) const
switch (ability) {
case AbilityAnnounceButtons:
case AbilityUsesAlphaChannel:
case AbilityAnnounceAlphaChannel:
case AbilityButtonMenu:
case AbilityButtonSpacer:
case AbilityExtendIntoClientArea:
@ -238,6 +239,7 @@ AuroraeClient::AuroraeClient(KDecorationBridge *bridge, KDecorationFactory *fact
connect(AuroraeFactory::instance(), SIGNAL(buttonsChanged()), SIGNAL(buttonsChanged()));
connect(AuroraeFactory::instance(), SIGNAL(configChanged()), SIGNAL(configChanged()));
connect(AuroraeFactory::instance(), SIGNAL(titleFontChanged()), SIGNAL(fontChanged()));
connect(m_item, SIGNAL(alphaChanged()), SLOT(slotAlphaChanged()));
}
AuroraeClient::~AuroraeClient()
@ -273,6 +275,7 @@ void AuroraeClient::init()
pal2.setColor(widget()->backgroundRole(), Qt::transparent);
widget()->setPalette(pal2);
m_scene->addItem(m_item);
slotAlphaChanged();
AuroraeFactory::instance()->theme()->setCompositingActive(compositingActive());
}
@ -505,6 +508,8 @@ void AuroraeClient::themeChanged()
m_item->setHeight(m_scene->sceneRect().height());
}
m_scene->addItem(m_item);
connect(m_item, SIGNAL(alphaChanged()), SLOT(slotAlphaChanged()));
slotAlphaChanged();
}
int AuroraeClient::doubleClickInterval() const
@ -556,6 +561,17 @@ QVariant AuroraeClient::readConfig(const QString &key, const QVariant &defaultVa
return config->group(AuroraeFactory::instance()->currentThemeName()).readEntry(key, defaultValue);
}
void AuroraeClient::slotAlphaChanged()
{
QVariant alphaProperty = m_item->property("alpha");
if (alphaProperty.isValid() && alphaProperty.canConvert<bool>()) {
setAlphaEnabled(alphaProperty.toBool());
} else {
// by default all Aurorae themes use the alpha channel
setAlphaEnabled(true);
}
}
} // namespace Aurorae
extern "C"

View file

@ -171,6 +171,7 @@ private slots:
void doCloseWindow();
void doTitlebarDblClickOperation();
void doMaximzie(int button);
void slotAlphaChanged();
private:
QGraphicsView *m_view;

View file

@ -17,6 +17,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import QtQuick 1.1
Item {
signal alphaChanged()
property int paddingLeft
property int paddingRight
property int paddingTop
@ -29,6 +31,9 @@ Item {
property int borderRightMaximized
property int borderTopMaximized
property int borderBottomMaximized
property bool alpha: true
onAlphaChanged: alphaChanged()
MouseArea {
anchors.fill: parent
hoverEnabled: true

View file

@ -94,6 +94,7 @@ Decoration {
paddingRight: 0
paddingBottom: 0
paddingTop: 0
alpha: false
Rectangle {
color: root.titleBarColor
anchors {

View file

@ -125,6 +125,8 @@ namespace Oxygen
}
setAlphaEnabled(!isMaximized());
_initialized = true;
// first reset is needed to store Oxygen configuration
@ -1257,6 +1259,7 @@ namespace Oxygen
void Client::maximizeChange( void )
{
if( hasSizeGrip() ) sizeGrip().setVisible( !( isShade() || isMaximized() ) );
setAlphaEnabled(!isMaximized());
KCommonDecorationUnstable::maximizeChange();
}

View file

@ -164,6 +164,7 @@ namespace Oxygen
return true;
case AbilityUsesAlphaChannel:
case AbilityAnnounceAlphaChannel:
return true;
// tabs

View file

@ -207,7 +207,7 @@ QRegion BlurEffect::blurRegion(const EffectWindow *w) const
if (value.isValid()) {
const QRegion appRegion = qvariant_cast<QRegion>(value);
if (!appRegion.isEmpty()) {
if (w->hasDecoration() && effects->decorationSupportsBlurBehind()) {
if (w->decorationHasAlpha() && effects->decorationSupportsBlurBehind()) {
region = w->shape();
region -= w->decorationInnerRect();
}
@ -218,7 +218,7 @@ QRegion BlurEffect::blurRegion(const EffectWindow *w) const
// for the whole window.
region = w->shape();
}
} else if (w->hasDecoration() && effects->decorationSupportsBlurBehind()) {
} else if (w->decorationHasAlpha() && effects->decorationSupportsBlurBehind()) {
// If the client hasn't specified a blur region, we'll only enable
// the effect behind the decoration.
region = w->shape();

View file

@ -1281,6 +1281,10 @@ void KCommonDecoration::setKeepBelow(bool set)
{
return wrapper->setKeepBelow(set);
}
void KCommonDecoration::setAlphaEnabled(bool enabled)
{
wrapper->wrapSetAlphaEnabled(enabled);
}
// *** end of wrapping of everything from KDecoration *** //
const KDecoration* KCommonDecoration::decoration() const

View file

@ -355,6 +355,19 @@ public:
protected:
virtual void timerEvent(QTimerEvent *event);
protected Q_SLOTS:
/**
* A decoration providing AbilityAnnounceAlphaChannel can use this method to enable/disable the
* use of alpha channel. This is useful if for a normal window the decoration renders its own
* shadows or round corners and thus needs alpha channel. But in maximized state the decoration
* is fully opaque. By disabling the alpha channel the Compositor can optimize the rendering.
*
* @param enabled If @c true alpha channel is enabled, if @c false alpha channel is disabled
* @see KDecoration::setAlphaEnabled
* @since 4.10
**/
void setAlphaEnabled(bool enabled);
private Q_SLOTS:
/* look out for buttons that have been destroyed. */
void objDestroyed(QObject *obj);

View file

@ -121,3 +121,8 @@ void KCommonDecorationWrapper::padding(int &left, int &right, int &top, int &bot
bottom = decoration->layoutMetric(KCommonDecoration::LM_OuterPaddingBottom);
}
void KCommonDecorationWrapper::wrapSetAlphaEnabled(bool enabled)
{
setAlphaEnabled(enabled);
}

View file

@ -60,6 +60,8 @@ public:
virtual void reset(unsigned long changed);
virtual void padding(int &left, int &right, int &top, int &bottom) const;
void wrapSetAlphaEnabled(bool enabled);
private:
KCommonDecoration* decoration;
};

View file

@ -54,13 +54,23 @@ inheriting KCommonDecoration and adding the new API matching KDecoration2.
*/
class KDecorationPrivate
{
public:
KDecorationPrivate()
: alphaEnabled(false)
{
}
bool alphaEnabled;
};
KDecorationOptions* KDecoration::options_;
KDecoration::KDecoration(KDecorationBridge* bridge, KDecorationFactory* factory)
: bridge_(bridge),
w_(NULL),
factory_(factory)
factory_(factory),
d(new KDecorationPrivate())
{
factory->addDecoration(this);
}
@ -69,6 +79,7 @@ KDecoration::~KDecoration()
{
factory()->removeDecoration(this);
delete w_;
delete d;
}
const KDecorationOptions* KDecoration::options()
@ -391,6 +402,19 @@ QRect KDecoration::transparentRect() const
return QRect();
}
void KDecoration::setAlphaEnabled(bool enabled)
{
if (d->alphaEnabled == enabled) {
return;
}
d->alphaEnabled = enabled;
emit alphaEnabledChanged(enabled);
}
bool KDecoration::isAlphaEnabled() const
{
return d->alphaEnabled;
}
KDecorationUnstable::KDecorationUnstable(KDecorationBridge* bridge, KDecorationFactory* factory)
: KDecoration(bridge, factory)

View file

@ -220,6 +220,8 @@ public:
/// @since 4.4
AbilityUsesBlurBehind = 3003, ///< The decoration wants the background to be blurred, when the blur plugin is enabled.
/// @since 4.6
AbilityAnnounceAlphaChannel = 4004, ///< The decoration can tell whether it currently uses an alpha channel or not. Requires AbilityUsesAlphaChannel.
/// @since 4.10
// Tabbing
AbilityTabbing = 4000, ///< The decoration supports tabbing
// TODO colors for individual button types
@ -706,6 +708,22 @@ public:
*/
void processMousePressEvent(QMouseEvent* e);
/**
* Whether the alpha channel is currently enabled. The value of this property is
* only relevant in case the decoration provides the AbilityAnnounceAlphaChannel.
*
* The compositor can make use of this information to optimize the rendering of the
* decoration.
*
* The default value of this property is @c false. That means if a decoration wants to make
* use alpha channel it has to call setAlphaEnabled with @c true.
*
* @see setAlphaEnabled
* @see alphaEnabledChanged
* @since 4.10
**/
bool isAlphaEnabled() const;
// requests to decoration
/**
@ -790,6 +808,17 @@ Q_SIGNALS:
*/
void keepBelowChanged(bool);
/**
* This signal is emitted whenever the decoration changes it's alpha enabled
* change. Only relevant in case the decoration provides AbilityAnnounceAlphaChannel.
*
* @param enabled The new state of alpha channel usage
* @see setAlphaEnabled
* @see isAlphaEnabled
* @since 4.10
**/
void alphaEnabledChanged(bool enabled);
public:
/**
* This method is not any more invoked from KWin core since version 4.8.
@ -941,6 +970,20 @@ public Q_SLOTS:
*/
void emitKeepBelowChanged(bool below);
protected Q_SLOTS:
/**
* A decoration providing AbilityAnnounceAlphaChannel can use this method to enable/disable the
* use of alpha channel. This is useful if for a normal window the decoration renders its own
* shadows or round corners and thus needs alpha channel. But in maximized state the decoration
* is fully opaque. By disabling the alpha channel the Compositor can optimize the rendering.
*
* @param enabled If @c true alpha channel is enabled, if @c false alpha channel is disabled
* @see isAlphaEnabled
* @see alphaEnabledChanged
* @since 4.10
**/
void setAlphaEnabled(bool enabled);
private:
KDecorationBridge* bridge_;
QWidget* w_;

View file

@ -736,6 +736,7 @@ WINDOW_HELPER_DEFAULT(bool, acceptsFocus, "wantsInput", true) // We don't actual
WINDOW_HELPER_DEFAULT(QPixmap, icon, "icon", QPixmap())
WINDOW_HELPER_DEFAULT(bool, isSkipSwitcher, "skipSwitcher", false)
WINDOW_HELPER_DEFAULT(bool, isCurrentTab, "isCurrentTab", false)
WINDOW_HELPER_DEFAULT(bool, decorationHasAlpha, "decorationHasAlpha", false)
#undef WINDOW_HELPER_DEFAULT

View file

@ -1320,6 +1320,11 @@ class KWIN_EXPORT EffectWindow : public QObject
Q_PROPERTY(QStringList activities READ activities)
Q_PROPERTY(bool onCurrentActivity READ isOnCurrentActivity)
Q_PROPERTY(bool onAllActivities READ isOnAllActivities)
/**
* Whether the decoration currently uses an alpha channel.
* @since 4.10
**/
Q_PROPERTY(bool decorationHasAlpha READ decorationHasAlpha)
public:
/** Flags explaining why painting should be disabled */
enum {
@ -1407,6 +1412,7 @@ public:
*/
virtual QRect decorationInnerRect() const = 0;
bool hasDecoration() const;
bool decorationHasAlpha() const;
virtual QByteArray readProperty(long atom, long type, int format) const = 0;
virtual void deleteProperty(long atom) const = 0;

View file

@ -258,8 +258,22 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
// Clip out the decoration for opaque windows; the decoration is drawn in the second pass
if (w->isOpaque()) {
Client *c = NULL;
if (topw->isClient()) {
c = static_cast<Client*>(topw);
}
// the window is fully opaque
data.clip = w->clientShape().translated(w->x(), w->y());
if (c && c->decorationHasAlpha()) {
// decoration uses alpha channel, so we may not exclude it in clipping
data.clip = w->clientShape().translated(w->x(), w->y());
} else {
// decoration is fully opaque
if (c && c->isShade()) {
data.clip = QRegion();
} else {
data.clip = w->shape().translated(w->x(), w->y());
}
}
} else if (topw->hasAlpha() && topw->opacity() == 1.0) {
// the window is partially opaque
data.clip = (w->clientShape() & topw->opaqueRegion().translated(topw->clientPos())).translated(w->x(), w->y());

View file

@ -1247,6 +1247,7 @@ GLTexture *SceneOpenGL::Window::textureForType(SceneOpenGL::Window::TextureType
//***************************************
SceneOpenGL2Window::SceneOpenGL2Window(Toplevel *c)
: SceneOpenGL::Window(c)
, m_blendingEnabled(false)
{
}
@ -1284,8 +1285,18 @@ void SceneOpenGL2Window::prepareStates(TextureType type, qreal opacity, qreal br
// setup blending of transparent windows
bool opaque = isOpaque() && opacity == 1.0;
bool alpha = toplevel->hasAlpha() || type != Content;
if (type != Content)
opaque = false;
if (type != Content) {
if (type == Shadow) {
opaque = false;
} else {
if (opacity == 1.0 && toplevel->isClient()) {
opaque = !(static_cast<Client*>(toplevel)->decorationHasAlpha());
} else {
// TODO: add support in Deleted
opaque = false;
}
}
}
if (!opaque) {
glEnable(GL_BLEND);
if (options->isColorCorrected()) {
@ -1299,6 +1310,7 @@ void SceneOpenGL2Window::prepareStates(TextureType type, qreal opacity, qreal br
}
}
}
m_blendingEnabled = !opaque;
const qreal rgb = brightness * opacity;
const qreal a = opacity;
@ -1313,13 +1325,12 @@ void SceneOpenGL2Window::prepareStates(TextureType type, qreal opacity, qreal br
void SceneOpenGL2Window::restoreStates(TextureType type, qreal opacity, qreal brightness, qreal saturation, int screen)
{
Q_UNUSED(type);
Q_UNUSED(opacity);
Q_UNUSED(brightness);
Q_UNUSED(saturation);
Q_UNUSED(screen);
bool opaque = isOpaque() && opacity == 1.0;
if (type != Content)
opaque = false;
if (!opaque) {
if (m_blendingEnabled) {
glDisable(GL_BLEND);
}
ShaderManager::instance()->getBoundShader()->setUniform(GLShader::AlphaToOne, 0);

View file

@ -288,6 +288,12 @@ protected:
virtual void endRenderWindow(const WindowPaintData &data);
virtual void prepareStates(TextureType type, qreal opacity, qreal brightness, qreal saturation, int screen);
virtual void restoreStates(TextureType type, qreal opacity, qreal brightness, qreal saturation, int screen);
private:
/**
* Whether prepareStates enabled blending and restore states should disable again.
**/
bool m_blendingEnabled;
};
#ifdef KWIN_HAVE_OPENGL_1

View file

@ -440,6 +440,7 @@ public:
bool hasDecorationShadows() const;
Qt::Corner decorationCloseButtonCorner();
bool decorationHasAlpha() const;
bool decorationSupportsAnnounceAlpha() const;
bool decorationSupportsTabbing() const; // Returns true if the decoration supports tabs.
bool decorationSupportsFrameOverlap() const;
bool decorationSupportsBlurBehind() const;
@ -1133,6 +1134,14 @@ inline bool Workspace::decorationHasAlpha() const
return mgr->factory()->supports(AbilityUsesAlphaChannel);
}
inline bool Workspace::decorationSupportsAnnounceAlpha() const
{
if (!hasDecorationPlugin()) {
return false;
}
return mgr->factory()->supports(AbilityAnnounceAlphaChannel);
}
inline bool Workspace::decorationSupportsTabbing() const
{
if (!hasDecorationPlugin()) {