From 9308028fa44d12c0301caedd35c9af9266eb841c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Fri, 12 Oct 2012 11:34:05 +0200 Subject: [PATCH] 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 --- client.cpp | 14 ++++++ client.h | 6 +++ clients/aurorae/src/aurorae.cpp | 16 +++++++ clients/aurorae/src/aurorae.h | 1 + clients/aurorae/src/qml/Decoration.qml | 5 +++ .../plastik/package/contents/ui/main.qml | 1 + clients/oxygen/oxygenclient.cpp | 3 ++ clients/oxygen/oxygenfactory.cpp | 1 + effects/blur/blur.cpp | 4 +- libkdecorations/kcommondecoration.cpp | 4 ++ libkdecorations/kcommondecoration.h | 13 ++++++ libkdecorations/kcommondecoration_p.cpp | 5 +++ libkdecorations/kcommondecoration_p.h | 2 + libkdecorations/kdecoration.cpp | 26 ++++++++++- libkdecorations/kdecoration.h | 43 +++++++++++++++++++ libkwineffects/kwineffects.cpp | 1 + libkwineffects/kwineffects.h | 6 +++ scene.cpp | 16 ++++++- scene_opengl.cpp | 23 +++++++--- scene_opengl.h | 6 +++ workspace.h | 9 ++++ 21 files changed, 195 insertions(+), 10 deletions(-) diff --git a/client.cpp b/client.cpp index 33322ddca2..8aa072f015 100644 --- a/client.cpp +++ b/client.cpp @@ -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" diff --git a/client.h b/client.h index b54f174e22..ced58d7c38 100644 --- a/client.h +++ b/client.h @@ -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 diff --git a/clients/aurorae/src/aurorae.cpp b/clients/aurorae/src/aurorae.cpp index 67bb7ee76a..a3dd78b7e6 100644 --- a/clients/aurorae/src/aurorae.cpp +++ b/clients/aurorae/src/aurorae.cpp @@ -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()) { + setAlphaEnabled(alphaProperty.toBool()); + } else { + // by default all Aurorae themes use the alpha channel + setAlphaEnabled(true); + } +} + } // namespace Aurorae extern "C" diff --git a/clients/aurorae/src/aurorae.h b/clients/aurorae/src/aurorae.h index 936474b0f3..6e187eaeb9 100644 --- a/clients/aurorae/src/aurorae.h +++ b/clients/aurorae/src/aurorae.h @@ -171,6 +171,7 @@ private slots: void doCloseWindow(); void doTitlebarDblClickOperation(); void doMaximzie(int button); + void slotAlphaChanged(); private: QGraphicsView *m_view; diff --git a/clients/aurorae/src/qml/Decoration.qml b/clients/aurorae/src/qml/Decoration.qml index 28b316ef65..b885278be7 100644 --- a/clients/aurorae/src/qml/Decoration.qml +++ b/clients/aurorae/src/qml/Decoration.qml @@ -17,6 +17,8 @@ along with this program. If not, see . 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 diff --git a/clients/aurorae/themes/plastik/package/contents/ui/main.qml b/clients/aurorae/themes/plastik/package/contents/ui/main.qml index f2213cc536..d18d7a78e7 100644 --- a/clients/aurorae/themes/plastik/package/contents/ui/main.qml +++ b/clients/aurorae/themes/plastik/package/contents/ui/main.qml @@ -94,6 +94,7 @@ Decoration { paddingRight: 0 paddingBottom: 0 paddingTop: 0 + alpha: false Rectangle { color: root.titleBarColor anchors { diff --git a/clients/oxygen/oxygenclient.cpp b/clients/oxygen/oxygenclient.cpp index 0b39d7dc06..05e786ee83 100644 --- a/clients/oxygen/oxygenclient.cpp +++ b/clients/oxygen/oxygenclient.cpp @@ -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(); } diff --git a/clients/oxygen/oxygenfactory.cpp b/clients/oxygen/oxygenfactory.cpp index 5502a6a6b4..73d3ac780d 100644 --- a/clients/oxygen/oxygenfactory.cpp +++ b/clients/oxygen/oxygenfactory.cpp @@ -164,6 +164,7 @@ namespace Oxygen return true; case AbilityUsesAlphaChannel: + case AbilityAnnounceAlphaChannel: return true; // tabs diff --git a/effects/blur/blur.cpp b/effects/blur/blur.cpp index 08e76f142d..3b10b9bc42 100644 --- a/effects/blur/blur.cpp +++ b/effects/blur/blur.cpp @@ -207,7 +207,7 @@ QRegion BlurEffect::blurRegion(const EffectWindow *w) const if (value.isValid()) { const QRegion appRegion = qvariant_cast(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(); diff --git a/libkdecorations/kcommondecoration.cpp b/libkdecorations/kcommondecoration.cpp index e3e884b56f..9f30c8d320 100644 --- a/libkdecorations/kcommondecoration.cpp +++ b/libkdecorations/kcommondecoration.cpp @@ -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 diff --git a/libkdecorations/kcommondecoration.h b/libkdecorations/kcommondecoration.h index 3fe9fcfe75..97bdfff095 100644 --- a/libkdecorations/kcommondecoration.h +++ b/libkdecorations/kcommondecoration.h @@ -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); diff --git a/libkdecorations/kcommondecoration_p.cpp b/libkdecorations/kcommondecoration_p.cpp index 86111c0ca6..2e24ebddb2 100644 --- a/libkdecorations/kcommondecoration_p.cpp +++ b/libkdecorations/kcommondecoration_p.cpp @@ -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); +} + diff --git a/libkdecorations/kcommondecoration_p.h b/libkdecorations/kcommondecoration_p.h index 1ee7d109e1..a462987f4d 100644 --- a/libkdecorations/kcommondecoration_p.h +++ b/libkdecorations/kcommondecoration_p.h @@ -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; }; diff --git a/libkdecorations/kdecoration.cpp b/libkdecorations/kdecoration.cpp index 71f4f8deb0..125d6c82da 100644 --- a/libkdecorations/kdecoration.cpp +++ b/libkdecorations/kdecoration.cpp @@ -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) diff --git a/libkdecorations/kdecoration.h b/libkdecorations/kdecoration.h index 7b1f3e0053..aefa91fe27 100644 --- a/libkdecorations/kdecoration.h +++ b/libkdecorations/kdecoration.h @@ -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_; diff --git a/libkwineffects/kwineffects.cpp b/libkwineffects/kwineffects.cpp index d8246ff14c..4895ca0e1e 100644 --- a/libkwineffects/kwineffects.cpp +++ b/libkwineffects/kwineffects.cpp @@ -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 diff --git a/libkwineffects/kwineffects.h b/libkwineffects/kwineffects.h index db8f96f4f0..32bcf501bd 100644 --- a/libkwineffects/kwineffects.h +++ b/libkwineffects/kwineffects.h @@ -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; diff --git a/scene.cpp b/scene.cpp index 7c3b0f9ae4..2e4190afac 100644 --- a/scene.cpp +++ b/scene.cpp @@ -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(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()); diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 290477f082..4792c11699 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -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(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); diff --git a/scene_opengl.h b/scene_opengl.h index fe4f1b5dd3..57d99ecc63 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -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 diff --git a/workspace.h b/workspace.h index 9f36c65c1d..d0f6f9bfd6 100644 --- a/workspace.h +++ b/workspace.h @@ -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()) {