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()) {