diff --git a/atoms.cpp b/atoms.cpp index f53ef31d83..a0a1e082f2 100644 --- a/atoms.cpp +++ b/atoms.cpp @@ -120,6 +120,9 @@ Atoms::Atoms() atoms[n] = &kde_net_wm_shadow; names[n++] = (char*) "_KDE_NET_WM_SHADOW"; + atoms[n] = &kde_net_wm_opaque_region; + names[n++] = (char*) "_KDE_NET_WM_OPAQUE_REGION"; + assert(n <= max); XInternAtoms(display(), names, n, false, atoms_return); diff --git a/atoms.h b/atoms.h index e51411fc25..bd80adc8b4 100644 --- a/atoms.h +++ b/atoms.h @@ -62,6 +62,7 @@ public: Atom net_wm_sync_request; Atom kde_net_wm_block_compositing; Atom kde_net_wm_shadow; + Atom kde_net_wm_opaque_region; }; diff --git a/events.cpp b/events.cpp index 94ddfaa1d5..4001347332 100644 --- a/events.cpp +++ b/events.cpp @@ -1648,6 +1648,8 @@ void Toplevel::propertyNotifyEvent(XPropertyEvent* e) getWindowRole(); else if (e->atom == atoms->kde_net_wm_shadow) getShadow(); + else if (e->atom == atoms->kde_net_wm_opaque_region) + getWmOpaqueRegion(); break; } emit propertyNotify(this, e->atom); diff --git a/manage.cpp b/manage.cpp index 1f410721aa..586c3edb54 100644 --- a/manage.cpp +++ b/manage.cpp @@ -136,6 +136,7 @@ bool Client::manage(Window w, bool isMapped) getWindowProtocols(); getWmNormalHints(); // Get xSizeHint getMotifHints(); + getWmOpaqueRegion(); // TODO: Try to obey all state information from info->state() diff --git a/scene.cpp b/scene.cpp index 34062590fb..dd2b72548b 100644 --- a/scene.cpp +++ b/scene.cpp @@ -273,7 +273,15 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region) topw->resetRepaints(topw->shadow()->shadowRegion().boundingRect()); } // Clip out the decoration for opaque windows; the decoration is drawn in the second pass - data.clip = w->isOpaque() ? w->clientShape().translated(w->x(), w->y()) : QRegion(); + if (w->isOpaque()) { + // the window is fully opaque + data.clip = w->clientShape().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(w->x(), w->y()); + } else { + data.clip = QRegion(); + } data.quads = w->buildQuads(); // preparation step effects->prePaintWindow(effectWindow(w), data, time_diff); @@ -314,7 +322,9 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region) // a higher opaque window data->region -= allclips; - if (!(data->mask & PAINT_WINDOW_TRANSLUCENT)) { + // Here we rely on WindowPrePaintData::setTranslucent() to remove + // the clip if needed. + if (!data->clip.isEmpty()) { // clip away this region for all windows below this one allclips |= data->clip; // Paint the opaque window @@ -326,7 +336,8 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region) data->region -= data->clip; // if prePaintWindow didn't change the clipping area we only have to paint // the decoration - if (data-> clip == data.key()->clientShape().translated(data.key()->x(), data.key()->y())) { + if ((data-> clip ^ + data.key()->clientShape().translated(data.key()->x(), data.key()->y())).isEmpty()) { data->mask |= PAINT_DECORATION_ONLY; } } diff --git a/toplevel.cpp b/toplevel.cpp index 8ec1b829fe..89e29086fd 100644 --- a/toplevel.cpp +++ b/toplevel.cpp @@ -131,6 +131,7 @@ void Toplevel::copyToDeleted(Toplevel* c) client_machine = c->wmClientMachine(false); wmClientLeaderWin = c->wmClientLeader(); window_role = c->windowRole(); + opaque_region = c->opaqueRegion(); // this needs to be done already here, otherwise 'c' could very likely // call discardWindowPixmap() in something called during cleanup c->window_pix = None; @@ -396,6 +397,44 @@ const Shadow *Toplevel::shadow() const } } +void Toplevel::getWmOpaqueRegion() +{ + const int length=32768; + unsigned long bytes_after_return=0; + QRegion new_opaque_region; + do { + unsigned long* data; + Atom type; + int rformat; + unsigned long nitems; + if (XGetWindowProperty(display(), client, + atoms->kde_net_wm_opaque_region, 0, length, false, XA_CARDINAL, + &type, &rformat, &nitems, &bytes_after_return, + reinterpret_cast< unsigned char** >(&data)) == Success) { + if (type != XA_CARDINAL || rformat != 32 || nitems%4) { + // it can happen, that the window does not provide this property + XFree(data); + break; + } + + for (unsigned int i = 0; i < nitems;) { + const int x = data[i++]; + const int y = data[i++]; + const int w = data[i++]; + const int h = data[i++]; + + new_opaque_region += QRect(x,y,w,h); + } + XFree(data); + } else { + kWarning(1212) << "XGetWindowProperty failed"; + break; + } + } while (bytes_after_return > 0); + + opaque_region = new_opaque_region; +} + } // namespace #include "toplevel.moc" diff --git a/toplevel.h b/toplevel.h index 2f71d23dbd..c7866547be 100644 --- a/toplevel.h +++ b/toplevel.h @@ -156,6 +156,13 @@ public: **/ void getShadow(); + /** + * This method returns the area that the Toplevel window reports to be opaque. + * It is supposed to only provide valueable information if @link hasAlpha is @c true . + * @see hasAlpha + **/ + const QRegion& opaqueRegion() const; + signals: void opacityChanged(KWin::Toplevel* toplevel, qreal oldOpacity); void damaged(KWin::Toplevel* toplevel, const QRect& damage); @@ -177,6 +184,13 @@ protected: void addDamageFull(); void getWmClientLeader(); void getWmClientMachine(); + + /** + * This function fetches the opaque region from this Toplevel. + * Will only be called on corresponding property changes and for initialization. + **/ + void getWmOpaqueRegion(); + void getResourceClass(); void getWindowRole(); virtual void debug(QDebug& stream) const = 0; @@ -214,6 +228,7 @@ private: QByteArray window_role; bool unredirect; bool unredirectSuspend; // when unredirected, but pixmap is needed temporarily + QRegion opaque_region; // when adding new data members, check also copyToDeleted() }; @@ -397,6 +412,11 @@ inline bool Toplevel::hasAlpha() const return depth() == 32; } +inline const QRegion& Toplevel::opaqueRegion() const +{ + return opaque_region; +} + inline EffectWindowImpl* Toplevel::effectWindow() { diff --git a/unmanaged.cpp b/unmanaged.cpp index 3fae012d3e..c1e8c1c5d1 100644 --- a/unmanaged.cpp +++ b/unmanaged.cpp @@ -72,6 +72,7 @@ bool Unmanaged::track(Window w) if (Extensions::shapeAvailable()) XShapeSelectInput(display(), w, ShapeNotifyMask); detectShape(w); + getWmOpaqueRegion(); setupCompositing(); ungrabXServer(); if (effects)