diff -Naur kdebase-3.5.8.orig/kwin/KWinInterface.h kdebase-3.5.8/kwin/KWinInterface.h
--- kdebase-3.5.8.orig/kwin/KWinInterface.h	2005-09-10 10:26:03.000000000 +0200
+++ kdebase-3.5.8/kwin/KWinInterface.h	2007-11-21 07:02:51.000000000 +0100
@@ -22,6 +22,9 @@
     virtual void nextDesktop() = 0;
     virtual void previousDesktop() = 0;
     virtual void circulateDesktopApplications() = 0;
+    virtual void updateOverlappingShadows(unsigned long window) = 0;
+    virtual void setShadowed(unsigned long window, bool shadowed) = 0;
+
     // kompmgr stuff
     virtual void startKompmgr() = 0;
     virtual void stopKompmgr() = 0;
diff -Naur kdebase-3.5.8.orig/kwin/activation.cpp kdebase-3.5.8/kwin/activation.cpp
--- kdebase-3.5.8.orig/kwin/activation.cpp	2007-11-21 07:02:36.000000000 +0100
+++ kdebase-3.5.8/kwin/activation.cpp	2007-11-21 07:02:51.000000000 +0100
@@ -227,6 +227,13 @@
         active_client->setActive( false, !c || !c->isModal() || c != active_client->transientFor() );
         }
     active_client = c;
+    if (set_active_client_recursion == 1)
+        {
+        // Only unset next_active_client if activateClient() wasn't called by
+        // Client::setActive() to set the active window to null before
+        // activating another window.
+        next_active_client = NULL;
+        }
     Q_ASSERT( c == NULL || c->isActive());
     if( active_client != NULL )
         last_active_client = active_client;
@@ -324,6 +331,7 @@
         Client* modal = c->findModal();
         if( modal != NULL && modal != c )	
             { 
+            next_active_client = modal;
             if( !modal->isOnDesktop( c->desktop()))
                 {
                 modal->setDesktop( c->desktop());
@@ -351,11 +359,14 @@
             c->setActive( true );
             focusToNull();
             }
+	if( c->wantsInput())
+	    next_active_client = c;
         flags &= ~ActivityFocus;
         handled = false; // no point, can't get clicks
         }
     if( !c->isShown( true )) // shouldn't happen, call activateClient() if needed
         {
+	next_active_client = c;
         kdWarning( 1212 ) << "takeActivity: not shown" << endl;
         return;
         }
@@ -856,7 +867,45 @@
     updateShadowSize();
     
     if ( active )
+    {
         Notify::raise( Notify::Activate );
+        if (options->shadowEnabled(true))
+            {
+            if (options->shadowEnabled(false))
+                {
+                // Wait for inactive shadow to expose occluded windows and give
+                // them a chance to redraw before painting the active shadow
+                removeShadow();
+                drawDelayedShadow();
+                if (!isDesktop() &&
+                       this != workspace()->topClientOnDesktop(desktop()))
+                    // If the newly activated window's isn't the desktop, wait
+                    // for its shadow to draw, then redraw any shadows
+                    // overlapping it.
+                    drawOverlappingShadows(true);
+                }
+            else
+                drawShadow();
+            }
+        }
+    else
+        {
+        removeShadow();
+
+        if (options->shadowEnabled(false))
+            if (this == workspace()->topClientOnDesktop(desktop()))
+                {
+                /* If the newly deactivated window is the top client on the
+                 * desktop, then the newly activated window is below it; ensure
+                 * that the deactivated window's shadow draws after the
+                 * activated window's shadow.
+                 */
+                if ((shadowAfterClient = workspace()->activeClient()))
+                    drawShadowAfter(shadowAfterClient);
+                }
+            else
+                drawDelayedShadow();
+        }
 
     if( !active )
         cancelAutoRaise();
diff -Naur kdebase-3.5.8.orig/kwin/client.cpp kdebase-3.5.8/kwin/client.cpp
--- kdebase-3.5.8.orig/kwin/client.cpp	2007-11-21 07:02:36.000000000 +0100
+++ kdebase-3.5.8/kwin/client.cpp	2007-11-21 07:02:51.000000000 +0100
@@ -11,9 +11,12 @@
 
 #include "client.h"
 
+#include <math.h>
+
 #include <qapplication.h>
 #include <qpainter.h>
 #include <qdatetime.h>
+#include <qimage.h>
 #include <kprocess.h>
 #include <unistd.h>
 #include <kstandarddirs.h>
@@ -39,9 +42,25 @@
 extern Atom qt_window_role;
 extern Atom qt_sm_client_id;
 
+// wait 200 ms before drawing shadow after move/resize
+static const int SHADOW_DELAY = 200;
+
 namespace KWinInternal
 {
 
+/* TODO: Remove this once X has real translucency.
+ *
+ * A list of the regions covered by all shadows and the Clients to which they
+ * belong. Used to redraw shadows when a window overlapping or underlying a
+ * shadow is moved, resized, or hidden.
+ */
+struct ShadowRegion
+    {
+    QRegion region;
+    Client *client;
+    };
+static QValueList<ShadowRegion> shadowRegions;
+
 /*
 
  Creating a client:
@@ -100,6 +119,13 @@
     autoRaiseTimer = 0;
     shadeHoverTimer = 0;
 
+    shadowDelayTimer = new QTimer(this);
+    opacityCache = &activeOpacityCache;
+    shadowAfterClient = NULL;
+    shadowWidget = NULL;
+    shadowMe = true;
+    connect(shadowDelayTimer, SIGNAL(timeout()), SLOT(drawShadow()));
+
     // set the initial mapping state
     mapping_state = WithdrawnState;
     desk = 0; // no desktop yet
@@ -145,7 +171,7 @@
     maxmode_restore = MaximizeRestore;
     
     cmap = None;
-    
+
     frame_geometry = QRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0)
     client_size = QSize( 100, 100 );
     custom_opacity = false;
@@ -188,6 +214,8 @@
     if (!custom_opacity) setOpacity(FALSE);
     if (moveResizeMode)
        leaveMoveResize();
+    removeShadow();
+    drawIntersectingShadows();
     finishWindowRules();
     ++postpone_geometry_updates;
     // grab X during the release to make removing of properties, setting to withdrawn state
@@ -248,6 +276,8 @@
     StackingUpdatesBlocker blocker( workspace());
     if (moveResizeMode)
        leaveMoveResize();
+    removeShadow();
+    drawIntersectingShadows();
     finishWindowRules();
     ++postpone_geometry_updates;
     setModal( false );
@@ -304,6 +334,7 @@
     if( do_show )
         decoration->widget()->show();
     updateFrameExtents();
+    updateOpacityCache();
     }
 
 void Client::destroyDecoration()
@@ -434,6 +465,12 @@
         QResizeEvent e( s, oldsize );
         QApplication::sendEvent( decoration->widget(), &e );
         }
+    if (!moveResizeMode && options->shadowEnabled(isActive()))
+        {
+        // If the user is manually resizing, let Client::leaveMoveResize()
+        // decide when to redraw the shadow
+        updateOpacityCache();
+        }
     }
 
 bool Client::noBorder() const
@@ -471,6 +508,7 @@
         noborder = true;
         updateDecoration( true );
         }
+    updateOpacityCache();
     if ( shape() )
         {
         XShapeCombineShape(qt_xdisplay(), frameId(), ShapeBounding,
@@ -862,6 +900,16 @@
         XMapWindow( qt_xdisplay(), wrapperId());
         XMapWindow( qt_xdisplay(), window());
         XDeleteProperty (qt_xdisplay(), client, atoms->net_wm_window_shade);
+	if (options->shadowEnabled(false))
+        {
+    	    for (ClientList::ConstIterator it = transients().begin();
+        	it != transients().end(); ++it)
+        	{
+            	    (*it)->removeShadow();
+            	    (*it)->drawDelayedShadow();
+                }
+        }
+
         if ( isActive() )
             workspace()->requestFocus( this );
         }
@@ -946,6 +994,589 @@
         }
     }
 
+void Client::setShadowed(bool shadowed)
+{
+    bool wasShadowed;
+
+    wasShadowed = isShadowed();
+    shadowMe = options->shadowEnabled(isActive()) ? shadowed : false;
+
+    if (shadowMe) {
+        if (!wasShadowed)
+            drawShadow();
+    }
+    else {
+        if (wasShadowed) {
+            removeShadow();
+
+            if (!activeOpacityCache.isNull())
+                activeOpacityCache.resize(0);
+            if (!inactiveOpacityCache.isNull())
+                inactiveOpacityCache.resize(0);
+        }
+    }
+}
+
+void Client::updateOpacityCache()
+{
+    if (!activeOpacityCache.isNull())
+        activeOpacityCache.resize(0);
+    if (!inactiveOpacityCache.isNull())
+        inactiveOpacityCache.resize(0);
+
+    if (!moveResizeMode) {
+        // If the user is manually resizing, let Client::finishMoveResize()
+        // decide when to redraw the shadow
+        removeShadow();
+        drawIntersectingShadows();
+        if (options->shadowEnabled(isActive()))
+            drawDelayedShadow();
+    }
+}
+
+/*!
+   Redraw shadows that were previously occluding or occluded by this window,
+   to avoid visual glitches.
+ */
+void Client::drawIntersectingShadows() {
+    //Client *reshadowClient;
+    QRegion region;
+    //QPtrList<Client> reshadowClients;
+    QValueList<Client *> reshadowClients;
+    QValueListIterator<ShadowRegion> it;
+    QValueListIterator<Client *> it2;
+
+    if (!options->shadowEnabled(false))
+        // No point in redrawing overlapping/overlapped shadows if only the
+        // active window has a shadow.
+        return;
+
+    region = shapeBoundingRegion;
+
+    // Generate list of Clients whose shadows need to be redrawn. That is,
+    // those that are currently intersecting or intersected by other windows or
+    // shadows.
+    for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it)
+        if ((isOnAllDesktops() || (*it).client->isOnCurrentDesktop()) &&
+                !(*it).region.intersect(region).isEmpty())
+            reshadowClients.append((*it).client);
+
+    // Redraw shadows for each of the Clients in the list generated above
+    for (it2 = reshadowClients.begin(); it2 != reshadowClients.end();
+            ++it2) {
+        (*it2)->removeShadow();
+        (*it2)->drawDelayedShadow();
+    }
+}
+
+/*!
+   Redraw shadows that are above the current window in the stacking order.
+   Furthermore, redraw them in the same order as they come in the stacking order
+   from bottom to top.
+ */
+void Client::drawOverlappingShadows(bool waitForMe)
+{
+    Client *aClient;
+    QRegion region;
+    QValueList<Client *> reshadowClients;
+    ClientList stacking_order;
+    ClientList::ConstIterator it;
+    QValueListIterator<ShadowRegion> it2;
+    QValueListIterator<Client *> it3;
+
+    if (!options->shadowEnabled(false))
+        // No point in redrawing overlapping/overlapped shadows if only the
+        // active window has a shadow.
+        return;
+
+    region = shapeBoundingRegion;
+
+    stacking_order = workspace()->stackingOrder();
+    for (it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
+        // Find the position of this window in the stacking order.
+        if ((*it) == this)
+            break;
+    }
+    ++it;
+    while (it != stacking_order.end()) {
+        if ((*it)->windowType() == NET::Dock) {
+            // This function is only interested in windows whose shadows don't
+            // have weird stacking rules.
+            ++it;
+            continue;
+        }
+
+        // Generate list of Clients whose shadows need to be redrawn. That is,
+        // those that are currently overlapping or overlapped by other windows
+        // or shadows. The list should be in order from bottom to top in the
+        // stacking order.
+        for (it2 = shadowRegions.begin(); it2 != shadowRegions.end(); ++it2) {
+            if ((*it2).client == (*it)) {
+                if ((isOnAllDesktops() || (*it2).client->isOnCurrentDesktop())
+                        && !(*it2).region.intersect(region).isEmpty())
+                    reshadowClients.append((*it2).client);
+            }
+        }
+        ++it;
+    }
+
+    // Redraw shadows for each of the Clients in the list generated above
+    for (it3 = reshadowClients.begin(); it3 != reshadowClients.end(); ++it3) {
+        (*it3)->removeShadow();
+        if (it3 == reshadowClients.begin()) {
+            if (waitForMe)
+                (*it3)->drawShadowAfter(this);
+            else
+                (*it3)->drawDelayedShadow();
+        }
+        else {
+            --it3;
+            aClient = (*it3);
+            ++it3;
+            (*it3)->drawShadowAfter(aClient);
+        }
+    }
+}
+
+/*!
+   Draw shadow after some time has elapsed, to give recently exposed windows a
+   chance to repaint before a shadow gradient is drawn over them.
+ */
+void Client::drawDelayedShadow()
+{
+    shadowDelayTimer->stop();
+    shadowDelayTimer->start(SHADOW_DELAY, true);
+}
+
+/*!
+   Draw shadow immediately after the specified Client's shadow finishes drawing.
+ */
+void Client::drawShadowAfter(Client *after)
+{
+    shadowAfterClient = after;
+    connect(after, SIGNAL(shadowDrawn()), SLOT(drawShadow()));
+}
+
+/*!
+   Draw a shadow under this window and XShape the shadow accordingly.
+ */
+void Client::drawShadow()
+{
+    Window shadows[2];
+    XRectangle *shapes;
+    int i, count, ordering;
+
+    // If we are waiting for another Client's shadow to be drawn, stop waiting now
+    if (shadowAfterClient != NULL) {
+        disconnect(shadowAfterClient, SIGNAL(shadowDrawn()), this, SLOT(drawShadow()));
+        shadowAfterClient = NULL;
+    }
+
+    if (!isOnCurrentDesktop())
+        return;
+
+    /* Store this window's ShapeBoundingRegion even if shadows aren't drawn for
+     * this type of window. Otherwise, drawIntersectingShadows() won't update
+     * properly when this window is moved/resized/hidden/closed.
+     */
+    shapes = XShapeGetRectangles(qt_xdisplay(), frameId(), ShapeBounding,
+            &count, &ordering);
+    if (!shapes)
+        // XShape extension not supported
+        shapeBoundingRegion = QRegion(x(), y(), width(), height());
+    else {
+        shapeBoundingRegion = QRegion();
+        for (i = 0; i < count; i++) {
+            // Translate XShaped window into a QRegion
+            QRegion shapeRectangle(shapes[i].x, shapes[i].y, shapes[i].width,
+                    shapes[i].height);
+            shapeBoundingRegion += shapeRectangle;
+        }
+        if (isShade())
+            // Since XResize() doesn't change a window's XShape regions, ensure that
+            // shapeBoundingRegion is not taller than the window's shaded height,
+            // or the bottom shadow will appear to be missing
+            shapeBoundingRegion &= QRegion(0, 0, width(), height());
+        shapeBoundingRegion.translate(x(), y());
+    }
+
+    if (!isShadowed() || hidden || isMinimized() ||
+            maximizeMode() == MaximizeFull ||
+            !options->shadowWindowType(windowType())) {
+        XFree(shapes);
+
+        // Tell whatever Clients are listening that this Client's shadow has been drawn.
+        // It hasn't, but there's no sense waiting for something that won't happen.
+        emit shadowDrawn();
+
+        return;
+    }
+
+    removeShadow();
+
+    QMemArray<QRgb> pixelData;
+    QPixmap shadowPixmap;
+    QRect shadow;
+    QRegion exposedRegion;
+    ShadowRegion shadowRegion;
+    int thickness, xOffset, yOffset;
+
+    thickness = options->shadowThickness(isActive());
+    xOffset = options->shadowXOffset(isActive());
+    yOffset = options->shadowYOffset(isActive());
+    opacityCache = active? &activeOpacityCache : &inactiveOpacityCache;
+
+    shadow.setRect(x() - thickness + xOffset, y() - thickness + yOffset,
+            width() + thickness * 2, height() + thickness * 2);
+    shadowPixmap.resize(shadow.size());
+
+    // Create a fake drop-down shadow effect via blended Xwindows
+    shadowWidget = new QWidget(0, 0, WStyle_Customize | WX11BypassWM);
+    shadowWidget->setGeometry(shadow);
+    XSelectInput(qt_xdisplay(), shadowWidget->winId(),
+            ButtonPressMask | ButtonReleaseMask | StructureNotifyMask);
+    shadowWidget->installEventFilter(this);
+
+    if (!shapes) {
+        // XShape extension not supported
+        exposedRegion = getExposedRegion(shapeBoundingRegion, shadow.x(),
+                shadow.y(), shadow.width(), shadow.height(), thickness,
+                xOffset, yOffset);
+        shadowRegion.region = exposedRegion;
+        shadowRegion.client = this;
+        shadowRegions.append(shadowRegion);
+
+        if (opacityCache->isNull())
+            imposeRegionShadow(shadowPixmap, shapeBoundingRegion,
+                    exposedRegion, thickness,
+                    options->shadowOpacity(isActive()));
+        else
+            imposeCachedShadow(shadowPixmap, exposedRegion);
+    }
+    else {
+        QMemArray<QRect> exposedRects;
+        QMemArray<QRect>::Iterator it, itEnd;
+        XRectangle *shadowShapes;
+
+        exposedRegion = getExposedRegion(shapeBoundingRegion, shadow.x(),
+                shadow.y(), shadow.width(), shadow.height(), thickness,
+                xOffset, yOffset);
+        shadowRegion.region = exposedRegion;
+        shadowRegion.client = this;
+        shadowRegions.append(shadowRegion);
+
+        // XShape the shadow
+        exposedRects = exposedRegion.rects();
+        i = 0;
+        itEnd = exposedRects.end();
+        shadowShapes = new XRectangle[exposedRects.count()];
+        for (it = exposedRects.begin(); it != itEnd; ++it) {
+            shadowShapes[i].x = (*it).x();
+            shadowShapes[i].y = (*it).y();
+            shadowShapes[i].width = (*it).width();
+            shadowShapes[i].height = (*it).height();
+            i++;
+        }
+        XShapeCombineRectangles(qt_xdisplay(), shadowWidget->winId(),
+                ShapeBounding, -x() + thickness - xOffset,
+                -y() + thickness - yOffset, shadowShapes, i, ShapeSet,
+                Unsorted);
+        delete [] shadowShapes;
+
+        if (opacityCache->isNull())
+            imposeRegionShadow(shadowPixmap, shapeBoundingRegion,
+                    exposedRegion, thickness,
+                    options->shadowOpacity(isActive()));
+        else
+            imposeCachedShadow(shadowPixmap, exposedRegion);
+    }
+
+    XFree(shapes);
+
+    // Set the background pixmap
+    //shadowPixmap.convertFromImage(shadowImage);
+    shadowWidget->setErasePixmap(shadowPixmap);
+
+    // Restack shadows under this window so that shadows drawn for a newly
+    // focused (but not raised) window don't overlap any windows above it.
+    if (isDock()) {
+        ClientList stacking_order = workspace()->stackingOrder();
+        for (ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
+            if ((*it)->isDesktop())
+                {
+                ++it;
+                shadows[0] = (*it)->frameId();
+                shadows[1] = shadowWidget->winId();
+                }
+    }
+    else {
+        shadows[0] = frameId();
+        if (shadowWidget != NULL)
+            shadows[1] = shadowWidget->winId();
+    }
+
+    XRestackWindows(qt_xdisplay(), shadows, 2);
+
+    // Don't use QWidget::show() so we don't confuse QEffects, thus causing
+    // broken focus.
+    XMapWindow(qt_xdisplay(), shadowWidget->winId());
+
+    // Tell whatever Clients are listening that this Client's shadow has been drawn.
+    emit shadowDrawn();
+}
+
+/*!
+   Remove shadow under this window.
+ */
+void Client::removeShadow()
+{
+    QValueList<ShadowRegion>::Iterator it;
+
+    shadowDelayTimer->stop();
+
+    if (shadowWidget != NULL) {
+        for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it)
+            if ((*it).client == this) {
+                shadowRegions.remove(it);
+                break;
+            }
+        delete shadowWidget;
+        shadowWidget = NULL;
+    }
+}
+
+/*!
+   Calculate regions in which the shadow will be visible given the window's
+   origin, height and width and the shadow's thickness, and X- and Y-offsets.
+ */
+QRegion Client::getExposedRegion(QRegion occludedRegion, int x, int y, int w,
+        int h, int thickness, int xOffset, int yOffset)
+{
+    QRegion exposedRegion;
+
+    exposedRegion = QRegion(x, y, w, h);
+    exposedRegion -= occludedRegion;
+
+    if (thickness > 0) {
+        // Limit exposedRegion to include only where a shadow of the specified
+        // thickness will be drawn
+        QMemArray<QRect> occludedRects;
+        QMemArray<QRect>::Iterator it, itEnd;
+        QRegion shadowRegion;
+
+        occludedRects = occludedRegion.rects();
+        itEnd = occludedRects.end();
+        for (it = occludedRects.begin(); it != itEnd; ++it) {
+            // Expand each of the occluded region's shape rectangles to contain
+            // where a shadow of the specified thickness will be drawn. Create
+            // a new QRegion that contains the expanded occluded region
+            it->setTop(it->top() - thickness + yOffset);
+            it->setLeft(it->left() - thickness + xOffset);
+            it->setRight(it->right() + thickness + xOffset);
+            it->setBottom(it->bottom() + thickness + yOffset);
+            shadowRegion += QRegion(*it);
+        }
+        exposedRegion -= exposedRegion - shadowRegion;
+    }
+
+    return exposedRegion;
+}
+
+/*!
+   Draw shadow gradient around this window using cached opacity values.
+ */
+void Client::imposeCachedShadow(QPixmap &pixmap, QRegion exposed)
+{
+    QRgb pixel;
+    double opacity;
+    int red, green, blue, pixelRed, pixelGreen, pixelBlue;
+    int subW, subH, w, h, x, y, zeroX, zeroY;
+    QImage image;
+    QMemArray<QRect>::Iterator it, itEnd;
+    QMemArray<QRect> rectangles;
+    QPixmap subPixmap;
+    Window rootWindow;
+    int thickness, windowX, windowY, xOffset, yOffset;
+
+    rectangles = exposed.rects();
+    rootWindow = qt_xrootwin();
+    thickness = options->shadowThickness(isActive());
+    windowX = this->x();
+    windowY = this->y();
+    xOffset = options->shadowXOffset(isActive());
+    yOffset = options->shadowYOffset(isActive());
+    options->shadowColour(isActive()).rgb(&red, &green, &blue);
+    w = pixmap.width();
+    h = pixmap.height();
+
+    itEnd = rectangles.end();
+    for (it = rectangles.begin(); it != itEnd; ++it) {
+        subW = (*it).width();
+        subH = (*it).height();
+        subPixmap = QPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(),
+                subW, subH);
+        zeroX = (*it).x() - windowX + thickness - xOffset;
+        zeroY = (*it).y() - windowY + thickness - yOffset;
+        image = subPixmap.convertToImage();
+
+        for (x = 0; x < subW; x++) {
+            for (y = 0; y < subH; y++) {
+                opacity = (*(opacityCache))[(zeroY + y) * w + zeroX + x];
+                pixel = image.pixel(x, y);
+                pixelRed = qRed(pixel);
+                pixelGreen = qGreen(pixel);
+                pixelBlue = qBlue(pixel);
+                image.setPixel(x, y,
+                        qRgb((int)(pixelRed + (red - pixelRed) * opacity),
+                            (int)(pixelGreen + (green - pixelGreen) * opacity),
+                            (int)(pixelBlue + (blue - pixelBlue) * opacity)));
+            }
+        }
+
+        subPixmap.convertFromImage(image);
+        bitBlt(&pixmap, zeroX, zeroY, &subPixmap);
+    }
+}
+
+/*!
+   Draw shadow around this window using calculated opacity values.
+ */
+void Client::imposeRegionShadow(QPixmap &pixmap, QRegion occluded,
+        QRegion exposed, int thickness, double maxOpacity)
+{
+    register int distance, intersectCount, i, j, x, y;
+    QRgb pixel;
+    double decay, factor, opacity;
+    int red, green, blue, pixelRed, pixelGreen, pixelBlue;
+    int halfMaxIntersects, lineIntersects, maxIntersects, maxY;
+    int irBottom, irLeft, irRight, irTop, yIncrement;
+    int subW, subH, w, h, zeroX, zeroY;
+    QImage image;
+    QMemArray<QRect>::Iterator it, itEnd;
+    QMemArray<QRect> rectangles;
+    QPixmap subPixmap;
+    Window rootWindow;
+    int windowX, windowY, xOffset, yOffset;
+
+    rectangles = exposed.rects();
+    rootWindow = qt_xrootwin();
+    windowX = this->x();
+    windowY = this->y();
+    xOffset = options->shadowXOffset(isActive());
+    yOffset = options->shadowYOffset(isActive());
+    options->shadowColour(isActive()).rgb(&red, &green, &blue);
+    maxIntersects = thickness * thickness * 4 + (thickness * 4) + 1;
+    halfMaxIntersects = maxIntersects / 2;
+    lineIntersects = thickness * 2 + 1;
+    factor = maxIntersects / maxOpacity;
+    decay = (lineIntersects / 0.0125 - factor) / pow((double)maxIntersects, 3.0);
+    w = pixmap.width();
+    h = pixmap.height();
+    xOffset = options->shadowXOffset(isActive());
+    yOffset = options->shadowYOffset(isActive());
+
+    opacityCache->resize(0);
+    opacityCache->resize(w * h);
+    occluded.translate(-windowX + thickness, -windowY + thickness);
+
+    itEnd = rectangles.end();
+    for (it = rectangles.begin(); it != itEnd; ++it) {
+        subW = (*it).width();
+        subH = (*it).height();
+        subPixmap = QPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(),
+                subW, subH);
+        maxY = subH;
+        zeroX = (*it).x() - windowX + thickness - xOffset;
+        zeroY = (*it).y() - windowY + thickness - yOffset;
+        image = subPixmap.convertToImage();
+
+        intersectCount = 0;
+        opacity = -1;
+        y = 0;
+        yIncrement = 1;
+        for (x = 0; x < subW; x++) {
+            irLeft = zeroX + x - thickness;
+            irRight = zeroX + x + thickness;
+
+            while (y != maxY) {
+                // horizontal row about to leave the intersect region, not
+                // necessarily the top row
+                irTop = zeroY + y - thickness * yIncrement;
+                // horizontal row that just came into the intersect region,
+                // not necessarily the bottom row
+                irBottom = zeroY + y + thickness * yIncrement;
+
+                if (opacity == -1) {
+                    // If occluded pixels caused an intersect count to be
+                    // skipped, recount it
+                    intersectCount = 0;
+
+                    for (j = irTop; j != irBottom; j += yIncrement) {
+                        // irTop is not necessarily larger than irBottom and
+                        // yIncrement isn't necessarily positive
+                        for (i = irLeft; i <= irRight; i++) {
+                            if (occluded.contains(QPoint(i, j)))
+                                intersectCount++;
+                        }
+                    }
+                }
+                else {
+                    if (intersectCount < 0)
+                        intersectCount = 0;
+
+                    for (i = irLeft; i <= irRight; i++) {
+                        if (occluded.contains(QPoint(i, irBottom)))
+                            intersectCount++;
+                    }
+                }
+
+                distance = maxIntersects - intersectCount;
+                opacity = intersectCount / (factor + pow((double)distance, 3.0) * decay);
+
+                (*(opacityCache))[(zeroY + y) * w + zeroX + x] = opacity;
+                pixel = image.pixel(x, y);
+                pixelRed = qRed(pixel);
+                pixelGreen = qGreen(pixel);
+                pixelBlue = qBlue(pixel);
+                image.setPixel(x, y,
+                        qRgb((int)(pixelRed + (red - pixelRed) * opacity),
+                            (int)(pixelGreen + (green - pixelGreen) * opacity),
+                            (int)(pixelBlue + (blue - pixelBlue) * opacity)));
+
+                for (i = irLeft; i <= irRight; i++) {
+                    if (occluded.contains(QPoint(i, irTop)))
+                        intersectCount--;
+                }
+
+                y += yIncrement;
+            }
+            y -= yIncrement;
+
+            irTop += yIncrement;
+            for (j = irTop; j != irBottom; j += yIncrement) {
+                if (occluded.contains(QPoint(irLeft, j)))
+                    intersectCount--;
+            }
+            irRight++;
+            for (j = irTop; j != irBottom; j += yIncrement) {
+                if (occluded.contains(QPoint(irRight, j)))
+                    intersectCount++;
+            }
+
+            yIncrement *= -1;
+            if (yIncrement < 0)
+                // Scan Y-axis bottom-up for next X-coordinate iteration
+                maxY = -1;
+            else
+                // Scan Y-axis top-down for next X-coordinate iteration
+                maxY = subH;
+        }
+
+        subPixmap.convertFromImage(image);
+        bitBlt(&pixmap, zeroX, zeroY, &subPixmap);
+    }
+}
+
 /*!
   Sets the client window's mapping state. Possible values are
   WithdrawnState, IconicState, NormalState.
@@ -989,6 +1620,8 @@
         XMapWindow( qt_xdisplay(), wrapper );
         XMapWindow( qt_xdisplay(), client );
         }
+    if (options->shadowEnabled(isActive()))
+        drawDelayedShadow();
     }
 
 /*!
@@ -1004,6 +1637,8 @@
 // which won't be missed, so this shouldn't be a problem. The chance the real UnmapNotify
 // will be missed is also very minimal, so I don't think it's needed to grab the server
 // here.
+    removeShadow();
+    drawIntersectingShadows();
     XSelectInput( qt_xdisplay(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
     XUnmapWindow( qt_xdisplay(), frame );
     XUnmapWindow( qt_xdisplay(), wrapper );
diff -Naur kdebase-3.5.8.orig/kwin/client.h kdebase-3.5.8/kwin/client.h
--- kdebase-3.5.8.orig/kwin/client.h	2007-11-21 07:02:36.000000000 +0100
+++ kdebase-3.5.8/kwin/client.h	2007-11-21 07:02:51.000000000 +0100
@@ -200,6 +200,19 @@
         void updateDecoration( bool check_workspace_pos, bool force = false );
         void checkBorderSizes();
 
+    // drop shadow
+        bool isShadowed() const;
+        void setShadowed(bool shadowed);
+        Window shadowId() const;
+        // Aieee, a friend function! Unpleasant, yes, but it's needed by
+        // raiseClient() to redraw a window's shadow when it is active prior to
+        // being raised.
+        friend void Workspace::raiseClient(Client *);
+        // Wouldn't you know it, friend functions breed. This one's needed to
+        // enable a DCOP function that causes all shadows obscuring a changed
+        // window to be redrawn.
+        friend void Workspace::updateOverlappingShadows(WId);
+
     // shape extensions
         bool shape() const;
         void updateShape();
@@ -312,6 +325,8 @@
         void autoRaise();
         void shadeHover();
         void shortcutActivated();
+	void updateOpacityCache();
+
 
     private:
         friend class Bridge; // FRAME
@@ -348,12 +363,29 @@
         bool buttonReleaseEvent( Window w, int button, int state, int x, int y, int x_root, int y_root );
         bool motionNotifyEvent( Window w, int state, int x, int y, int x_root, int y_root );
 
+    // drop shadows
+	void drawIntersectingShadows();
+	void drawOverlappingShadows(bool waitForMe);
+	QRegion getExposedRegion(QRegion occludedRegion, int x, int y,
+	    int w, int h, int thickness, int xOffset, int yOffset);
+	void imposeCachedShadow(QPixmap &pixmap, QRegion exposed);
+	void imposeRegionShadow(QPixmap &pixmap, QRegion occluded,
+	    QRegion exposed, int thickness, double maxOpacity = 0.75);
+
         void processDecorationButtonPress( int button, int state, int x, int y, int x_root, int y_root );
 
     private slots:
         void pingTimeout();
         void processKillerExited();
         void demandAttentionKNotify();
+	void drawShadow();
+	void drawShadowAfter(Client *after);
+	void drawDelayedShadow();
+	void removeShadow();
+
+    signals:
+	void shadowDrawn();
+
 
     private:
     // ICCCM 4.1.3.1, 4.1.4 , NETWM 2.5.1
@@ -531,6 +563,16 @@
         bool pending_geometry_update;
         bool shade_geometry_change;
         int border_left, border_right, border_top, border_bottom;
+
+        Client* shadowAfterClient;
+        QWidget* shadowWidget;
+        QMemArray<double> activeOpacityCache;
+        QMemArray<double> inactiveOpacityCache;
+        QMemArray<double>* opacityCache;
+        QRegion shapeBoundingRegion;
+        QTimer* shadowDelayTimer;
+        bool shadowMe;
+
         QRegion _mask;
         static bool check_active_modal; // see Client::checkActiveModal()
         KShortcut _shortcut;
@@ -880,6 +922,16 @@
     plainResize( s.width(), s.height(), force );
     }
 
+inline bool Client::isShadowed() const
+    {
+    return shadowMe;
+    }
+
+inline Window Client::shadowId() const
+    {
+    return shadowWidget != NULL ? shadowWidget->winId() : None;
+    }
+
 inline void Client::resizeWithChecks( const QSize& s, ForceGeometry_t force )
     {
     resizeWithChecks( s.width(), s.height(), force );
diff -Naur kdebase-3.5.8.orig/kwin/events.cpp kdebase-3.5.8/kwin/events.cpp
--- kdebase-3.5.8.orig/kwin/events.cpp	2007-10-08 11:51:32.000000000 +0200
+++ kdebase-3.5.8/kwin/events.cpp	2007-11-21 07:02:51.000000000 +0100
@@ -1077,6 +1077,217 @@
 // for the decoration window cannot be (easily) intercepted as X11 events
 bool Client::eventFilter( QObject* o, QEvent* e )
     {
+    if (o == shadowWidget)
+        {
+        if (e->type() == QEvent::MouseButtonRelease)
+            {
+            int buttonMask, buttonPressed, x, y, x_root, y_root;
+            unsigned int mask;
+            QMouseEvent *qe = (QMouseEvent *)e;
+            Window inner_window, parent_window, pointer_window, root_window;
+            XButtonEvent xe;
+
+            removeShadow();
+            switch (qe->button())
+                {
+                case Qt::MidButton:
+                    buttonMask = Button2Mask;
+                    buttonPressed = Button2;
+                    break;
+                case Qt::RightButton:
+                    buttonMask = Button3Mask;
+                    buttonPressed = Button3;
+                    break;
+                default:
+                    buttonMask = Button1Mask;
+                    buttonPressed = Button1;
+                    break;
+                }
+
+            // find the window under the cursor that should receive the
+            // simulated events
+            root_window = qt_xrootwin();
+            XQueryPointer(qt_xdisplay(), root_window, &root_window,
+                    &pointer_window, &x_root, &y_root, &x, &y, &mask);
+
+            if (pointer_window != None)
+                {
+                // Save the child window immediately under the window
+                // decoration, if any. This is so that we can send an event to
+                // the immediate descendant of a window's window decoration,
+                // which causes KWin to refocus windows properly
+                parent_window = pointer_window;
+                XQueryPointer(qt_xdisplay(), parent_window, &root_window,
+                        &pointer_window, &x_root, &y_root, &x, &y, &mask);
+                inner_window = pointer_window;
+
+                while (pointer_window != None)
+                    {
+                    // Recursively query for the child window under the pointer,
+                    // using the returned child window as the parent window for
+                    // the subsequent query. When no child window is left, we've
+                    // found the child that will receive the simulated event
+                    parent_window = pointer_window;
+                    XQueryPointer(qt_xdisplay(), parent_window, &root_window,
+                            &pointer_window, &x_root, &y_root, &x, &y, &mask);
+                    }
+                pointer_window = parent_window;
+                }
+            else
+                inner_window = None;
+
+            // simulate a mouse button press
+            xe.type = ButtonPress;
+            xe.display = qt_xdisplay();
+            xe.root = qt_xrootwin();
+            xe.subwindow = None;
+            xe.time = CurrentTime;
+            xe.x = x;
+            xe.y = y;
+            xe.x_root = x_root;
+            xe.y_root = y_root;
+            xe.state = 0;
+            xe.button = buttonPressed;
+            xe.same_screen = True;
+            if (inner_window != None && inner_window != pointer_window)
+                {
+                xe.window = inner_window;
+                XSendEvent(qt_xdisplay(), inner_window, True, ButtonPressMask,
+                        (XEvent *)&xe);
+                }
+            xe.window = pointer_window;
+            XSendEvent(qt_xdisplay(), pointer_window, True, ButtonPressMask,
+                    (XEvent *)&xe);
+
+            // simulate a mouse button release
+            xe.type = ButtonRelease;
+            xe.display = qt_xdisplay();
+            xe.root = qt_xrootwin();
+            xe.subwindow = None;
+            xe.time = CurrentTime;
+            xe.x = x;
+            xe.y = y;
+            xe.x_root = x_root;
+            xe.y_root = y_root;
+            xe.state = buttonMask;
+            xe.button = buttonPressed;
+            xe.same_screen = True;
+            if (inner_window != None && inner_window != pointer_window)
+                {
+                xe.window = inner_window;
+                XSendEvent(qt_xdisplay(), inner_window, True, ButtonReleaseMask,
+                        (XEvent *)&xe);
+                }
+            xe.window = pointer_window;
+            XSendEvent(qt_xdisplay(), pointer_window, True, ButtonReleaseMask,
+                    (XEvent *)&xe);
+
+            drawDelayedShadow();
+
+            return true;
+            }
+        else if (e->type() == QEvent::Wheel)
+            {
+            int x, y, x_root, y_root;
+            unsigned int buttonMask, buttonPressed, mask;
+            QWheelEvent *wheelEvent = (QWheelEvent *)e;
+            Window inner_window, parent_window, pointer_window,
+                root_window;
+            XButtonEvent xe;
+
+            removeShadow();
+
+            // state and button parameters passed to XSendEvent depend on the
+            // direction in which the mouse wheel was rolled
+            buttonMask = wheelEvent->delta() > 0 ? Button4Mask : Button5Mask;
+            buttonPressed = wheelEvent->delta() > 0 ? Button4 : Button5;
+
+            // find the window under the cursor that should receive the
+            // simulated events
+            root_window = qt_xrootwin();
+            XQueryPointer(qt_xdisplay(), root_window, &root_window,
+                    &pointer_window, &x_root, &y_root, &x, &y, &mask);
+
+            if (pointer_window != None)
+                {
+                // Save the child window immediately under the window
+                // decoration, if any. This is so that we can send an event to
+                // the immediate descendant of a window's window decoration,
+                // which causes KWin to refocus windows properly
+                parent_window = pointer_window;
+                XQueryPointer(qt_xdisplay(), parent_window, &root_window,
+                        &pointer_window, &x_root, &y_root, &x, &y, &mask);
+                inner_window = pointer_window;
+
+                while (pointer_window != None)
+                    {
+                    // Recursively query for the child window under the pointer,
+                    // using the returned child window as the parent window for
+                    // the subsequent query. When no child window is left, we've
+                    // found the child that will receive the simulated event
+                    parent_window = pointer_window;
+                    XQueryPointer(qt_xdisplay(), parent_window, &root_window,
+                            &pointer_window, &x_root, &y_root, &x, &y, &mask);
+                    }
+                pointer_window = parent_window;
+                }
+            else
+                inner_window = None;
+
+            // simulate a mouse button press
+            xe.type = ButtonPress;
+            xe.display = qt_xdisplay();
+            xe.root = qt_xrootwin();
+            xe.subwindow = None;
+            xe.time = CurrentTime;
+            xe.x = x;
+            xe.y = y;
+            xe.x_root = x_root;
+            xe.y_root = y_root;
+            xe.state = 0;
+            xe.same_screen = True;
+            if (inner_window != None && inner_window != pointer_window)
+                {
+                xe.button = buttonPressed;
+                xe.window = inner_window;
+                XSendEvent(qt_xdisplay(), inner_window, True, ButtonPressMask,
+                        (XEvent *)&xe);
+                }
+            xe.button = buttonPressed;
+            xe.window = pointer_window;
+            XSendEvent(qt_xdisplay(), pointer_window, True, ButtonPressMask,
+                    (XEvent *)&xe);
+
+            // simulate a mouse button release
+            xe.type = ButtonRelease;
+            xe.display = qt_xdisplay();
+            xe.root = qt_xrootwin();
+            xe.subwindow = None;
+            xe.time = CurrentTime;
+            xe.x = x;
+            xe.y = y;
+            xe.x_root = x_root;
+            xe.y_root = y_root;
+            xe.same_screen = True;
+            if (inner_window != None && inner_window != pointer_window)
+                {
+                xe.window = inner_window;
+                xe.state = buttonMask;
+                xe.button = buttonPressed;
+                XSendEvent(qt_xdisplay(), inner_window, True, ButtonReleaseMask,
+                        (XEvent *)&xe);
+                }
+            xe.state = buttonMask;
+            xe.button = buttonPressed;
+            xe.window = pointer_window;
+            XSendEvent(qt_xdisplay(), pointer_window, True, ButtonReleaseMask,
+                    (XEvent *)&xe);
+
+            drawDelayedShadow();
+
+            return true;
+            }
+        }
     if( decoration == NULL
         || o != decoration->widget())
         return false;
diff -Naur kdebase-3.5.8.orig/kwin/geometry.cpp kdebase-3.5.8/kwin/geometry.cpp
--- kdebase-3.5.8.orig/kwin/geometry.cpp	2007-11-21 07:02:36.000000000 +0100
+++ kdebase-3.5.8/kwin/geometry.cpp	2007-11-21 07:02:51.000000000 +0100
@@ -1028,6 +1028,15 @@
                 rect.moveLeft( area.right() - 5 );
             }
         }
+    if (!moveResizeMode && options->shadowEnabled(isActive()))
+        {
+        // If the user is manually resizing, let Client::leaveMoveResize()
+        // decide when to redraw the shadow
+        removeShadow();
+        drawIntersectingShadows();
+        if (options->shadowEnabled(isActive()))
+            drawDelayedShadow();
+        }
     }
 
 /*!
@@ -2286,6 +2295,7 @@
         }
     if ( maximizeMode() != MaximizeRestore )
         resetMaximize();
+    removeShadow();
     moveResizeMode = true;
     workspace()->setClientIsMoving(this);
     initialMoveResizeGeom = moveResizeGeom = geometry();
@@ -2354,6 +2364,11 @@
     moveResizeMode = false;
     delete eater;
     eater = 0;
+    if (options->shadowEnabled(isActive()))
+        {
+        drawIntersectingShadows();
+        updateOpacityCache();
+        }
     }
 
 // This function checks if it actually makes sense to perform a restricted move/resize.
diff -Naur kdebase-3.5.8.orig/kwin/kcmkwin/kwindecoration/kwindecoration.cpp kdebase-3.5.8/kwin/kcmkwin/kwindecoration/kwindecoration.cpp
--- kdebase-3.5.8.orig/kwin/kcmkwin/kwindecoration/kwindecoration.cpp	2006-01-19 18:01:03.000000000 +0100
+++ kdebase-3.5.8/kwin/kcmkwin/kwindecoration/kwindecoration.cpp	2007-11-21 07:02:51.000000000 +0100
@@ -28,6 +28,8 @@
 */
 
 #include <assert.h>
+#include <math.h>
+
 #include <qdir.h>
 #include <qfileinfo.h>
 #include <qlayout.h>
@@ -39,8 +41,10 @@
 #include <qlabel.h>
 #include <qfile.h>
 #include <qslider.h>
+#include <qspinbox.h>
 
 #include <kapplication.h>
+#include <kcolorbutton.h>
 #include <kcombobox.h>
 #include <kdebug.h>
 #include <kdesktopfile.h>
@@ -153,6 +157,164 @@
 	preview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
 	tabWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
 
+	// Page 3 (Window Shadows)
+	QHBox *inactiveShadowColourHBox, *shadowColourHBox;
+	QHBox *inactiveShadowOpacityHBox, *shadowOpacityHBox;
+	QHBox *inactiveShadowXOffsetHBox, *shadowXOffsetHBox;
+	QHBox *inactiveShadowYOffsetHBox, *shadowYOffsetHBox;
+	QHBox *inactiveShadowThicknessHBox, *shadowThicknessHBox;
+	QLabel *inactiveShadowColourLabel, *shadowColourLabel;
+	QLabel *inactiveShadowOpacityLabel, *shadowOpacityLabel;
+	QLabel *inactiveShadowXOffsetLabel, *shadowXOffsetLabel;
+	QLabel *inactiveShadowYOffsetLabel, *shadowYOffsetLabel;
+	QLabel *inactiveShadowThicknessLabel, *shadowThicknessLabel;
+
+	shadowPage = new QVBox(tabWidget);
+	shadowPage->setSpacing(KDialog::spacingHint());
+	shadowPage->setMargin(KDialog::marginHint());
+
+	cbWindowShadow = new QCheckBox(
+			i18n("&Draw a drop shadow under windows"), shadowPage);
+	QWhatsThis::add(cbWindowShadow,
+			i18n("Enabling this checkbox will allow you to choose a kind of "
+				 "drop shadow to draw under each window."));
+
+	activeShadowSettings = new QGroupBox(1, Qt::Horizontal,
+			i18n("Active Window Shadow"), shadowPage);
+	inactiveShadowSettings = new QGroupBox(1, Qt::Horizontal,
+			i18n("Inactive Window Shadows"), shadowPage);
+	whichShadowSettings = new QGroupBox(3, Qt::Horizontal,
+			i18n("Draw Shadow Under Normal Windows And..."), shadowPage);
+
+	cbShadowDocks = new QCheckBox(i18n("Docks and &panels"),
+			whichShadowSettings);
+	connect(cbShadowDocks, SIGNAL(toggled(bool)),
+			SLOT(slotSelectionChanged()));
+	cbShadowOverrides = new QCheckBox(i18n("O&verride windows"),
+			whichShadowSettings);
+	connect(cbShadowOverrides, SIGNAL(toggled(bool)),
+			SLOT(slotSelectionChanged()));
+	cbShadowTopMenus = new QCheckBox(i18n("&Top menu"),
+			whichShadowSettings);
+	connect(cbShadowTopMenus, SIGNAL(toggled(bool)),
+			SLOT(slotSelectionChanged()));
+	cbInactiveShadow = new QCheckBox(
+			i18n("Draw shadow under &inactive windows"), inactiveShadowSettings);
+	connect(cbInactiveShadow, SIGNAL(toggled(bool)),
+			SLOT(slotSelectionChanged()));
+
+	shadowColourHBox = new QHBox(activeShadowSettings);
+	shadowColourHBox->setSpacing(KDialog::spacingHint());
+	shadowColourLabel = new QLabel(i18n("Colour:"), shadowColourHBox);
+	shadowColourButton = new KColorButton(shadowColourHBox);
+	connect(shadowColourButton, SIGNAL(changed(const QColor &)), SLOT(slotSelectionChanged()));
+
+	inactiveShadowColourHBox = new QHBox(inactiveShadowSettings);
+	inactiveShadowColourHBox->setSpacing(KDialog::spacingHint());
+	inactiveShadowColourLabel = new QLabel(i18n("Colour:"), inactiveShadowColourHBox);
+	inactiveShadowColourButton = new KColorButton(inactiveShadowColourHBox);
+	connect(inactiveShadowColourButton, SIGNAL(changed(const QColor &)), SLOT(slotSelectionChanged()));
+
+	shadowOpacityHBox = new QHBox(activeShadowSettings);
+	shadowOpacityHBox->setSpacing(KDialog::spacingHint());
+	shadowOpacityLabel = new QLabel(i18n("Maximum opacity:"), shadowOpacityHBox);
+	shadowOpacitySlider = new QSlider(1, 100, 10, 50, Qt::Horizontal,
+			shadowOpacityHBox);
+	shadowOpacitySlider->setTickmarks(QSlider::Below);
+	shadowOpacitySlider->setTickInterval(10);
+	shadowOpacitySpinBox = new QSpinBox(1, 100, 1, shadowOpacityHBox);
+	shadowOpacitySpinBox->setSuffix(" %");
+	connect(shadowOpacitySlider, SIGNAL(valueChanged(int)), shadowOpacitySpinBox,
+			SLOT(setValue(int)));
+	connect(shadowOpacitySpinBox, SIGNAL(valueChanged(int)), shadowOpacitySlider,
+			SLOT(setValue(int)));
+	connect(shadowOpacitySlider, SIGNAL(valueChanged(int)),
+			SLOT(slotSelectionChanged()));
+
+	inactiveShadowOpacityHBox = new QHBox(inactiveShadowSettings);
+	inactiveShadowOpacityHBox->setSpacing(KDialog::spacingHint());
+	inactiveShadowOpacityLabel = new QLabel(i18n("Maximum opacity:"),
+			inactiveShadowOpacityHBox);
+	inactiveShadowOpacitySlider = new QSlider(1, 100, 10, 50, Qt::Horizontal,
+			inactiveShadowOpacityHBox);
+	inactiveShadowOpacitySlider->setTickmarks(QSlider::Below);
+	inactiveShadowOpacitySlider->setTickInterval(10);
+	inactiveShadowOpacitySpinBox = new QSpinBox(1, 100, 1,
+			inactiveShadowOpacityHBox);
+	inactiveShadowOpacitySpinBox->setSuffix(" %");
+	connect(inactiveShadowOpacitySlider, SIGNAL(valueChanged(int)),
+			inactiveShadowOpacitySpinBox,
+			SLOT(setValue(int)));
+	connect(inactiveShadowOpacitySpinBox, SIGNAL(valueChanged(int)),
+			inactiveShadowOpacitySlider,
+			SLOT(setValue(int)));
+	connect(inactiveShadowOpacitySlider, SIGNAL(valueChanged(int)),
+			SLOT(slotSelectionChanged()));
+
+	shadowXOffsetHBox = new QHBox(activeShadowSettings);
+	shadowXOffsetHBox->setSpacing(KDialog::spacingHint());
+	shadowXOffsetLabel = new QLabel(
+			i18n("Offset rightward (may be negative):"),
+			shadowXOffsetHBox);
+	shadowXOffsetSpinBox = new QSpinBox(-1024, 1024, 1, shadowXOffsetHBox);
+	shadowXOffsetSpinBox->setSuffix(i18n(" pixels"));
+	connect(shadowXOffsetSpinBox, SIGNAL(valueChanged(int)),
+			SLOT(slotSelectionChanged()));
+
+	inactiveShadowXOffsetHBox = new QHBox(inactiveShadowSettings);
+	inactiveShadowXOffsetHBox->setSpacing(KDialog::spacingHint());
+	inactiveShadowXOffsetLabel = new QLabel(
+			i18n("Offset rightward (may be negative):"),
+			inactiveShadowXOffsetHBox);
+	inactiveShadowXOffsetSpinBox = new QSpinBox(-1024, 1024, 1,
+			inactiveShadowXOffsetHBox);
+	inactiveShadowXOffsetSpinBox->setSuffix(i18n(" pixels"));
+	connect(inactiveShadowXOffsetSpinBox, SIGNAL(valueChanged(int)),
+			SLOT(slotSelectionChanged()));
+
+	shadowYOffsetHBox = new QHBox(activeShadowSettings);
+	shadowYOffsetHBox->setSpacing(KDialog::spacingHint());
+	shadowYOffsetLabel = new QLabel(
+			i18n("Offset downward (may be negative):"),
+			shadowYOffsetHBox);
+	shadowYOffsetSpinBox = new QSpinBox(-1024, 1024, 1, shadowYOffsetHBox);
+	shadowYOffsetSpinBox->setSuffix(i18n(" pixels"));
+	connect(shadowYOffsetSpinBox, SIGNAL(valueChanged(int)),
+			SLOT(slotSelectionChanged()));
+
+	inactiveShadowYOffsetHBox = new QHBox(inactiveShadowSettings);
+	inactiveShadowYOffsetHBox->setSpacing(KDialog::spacingHint());
+	inactiveShadowYOffsetLabel = new QLabel(
+			i18n("Offset downward (may be negative):"),
+			inactiveShadowYOffsetHBox);
+	inactiveShadowYOffsetSpinBox = new QSpinBox(-1024, 1024, 1,
+			inactiveShadowYOffsetHBox);
+	inactiveShadowYOffsetSpinBox->setSuffix(i18n(" pixels"));
+	connect(inactiveShadowYOffsetSpinBox, SIGNAL(valueChanged(int)),
+			SLOT(slotSelectionChanged()));
+
+	shadowThicknessHBox = new QHBox(activeShadowSettings);
+	shadowThicknessHBox->setSpacing(KDialog::spacingHint());
+	shadowThicknessLabel = new QLabel(
+			i18n("Thickness to either side of window:"),
+			shadowThicknessHBox);
+	shadowThicknessSpinBox = new QSpinBox(1, 100, 1,
+			shadowThicknessHBox);
+	shadowThicknessSpinBox->setSuffix(i18n(" pixels"));
+	connect(shadowThicknessSpinBox, SIGNAL(valueChanged(int)),
+			SLOT(slotSelectionChanged()));
+
+	inactiveShadowThicknessHBox = new QHBox(inactiveShadowSettings);
+	inactiveShadowThicknessHBox->setSpacing(KDialog::spacingHint());
+	inactiveShadowThicknessLabel = new QLabel(
+			i18n("Thickness to either side of window:"),
+			inactiveShadowThicknessHBox);
+	inactiveShadowThicknessSpinBox = new QSpinBox(1, 100, 1,
+			inactiveShadowThicknessHBox);
+	inactiveShadowThicknessSpinBox->setSuffix(i18n(" pixels"));
+	connect(inactiveShadowThicknessSpinBox, SIGNAL(valueChanged(int)),
+			SLOT(slotSelectionChanged()));
+
 	// Load all installed decorations into memory
 	// Set up the decoration lists and other UI settings
 	findDecorations();
@@ -162,6 +324,7 @@
 
 	tabWidget->insertTab( pluginPage, i18n("&Window Decoration") );
 	tabWidget->insertTab( buttonPage, i18n("&Buttons") );
+	tabWidget->insertTab( shadowPage, i18n("&Shadows") );
 
 	connect( buttonPositionWidget, SIGNAL(changed()), this, SLOT(slotButtonsChanged()) ); // update preview etc.
 	connect( buttonPositionWidget, SIGNAL(changed()), this, SLOT(slotSelectionChanged()) ); // emit changed()...
@@ -171,7 +334,12 @@
 	connect( cbUseCustomButtonPositions, SIGNAL(clicked()), SLOT(slotSelectionChanged()) );
 	connect(cbUseCustomButtonPositions, SIGNAL(toggled(bool)), buttonPositionWidget, SLOT(setEnabled(bool)));
 	connect(cbUseCustomButtonPositions, SIGNAL(toggled(bool)), this, SLOT(slotButtonsChanged()) );
+ 	connect(cbWindowShadow, SIGNAL(toggled(bool)), activeShadowSettings, SLOT(setEnabled(bool)));
+ 	connect(cbWindowShadow, SIGNAL(toggled(bool)), inactiveShadowSettings, SLOT(setEnabled(bool)));
+ 	connect(cbWindowShadow, SIGNAL(toggled(bool)), whichShadowSettings, SLOT(setEnabled(bool)));
+
 	connect( cbShowToolTips, SIGNAL(clicked()), SLOT(slotSelectionChanged()) );
+	connect( cbWindowShadow, SIGNAL(clicked()), SLOT(slotSelectionChanged()) );
 	connect( cBorder, SIGNAL( activated( int )), SLOT( slotBorderChanged( int )));
 //	connect( cbUseMiniWindows, SIGNAL(clicked()), SLOT(slotSelectionChanged()) );
 
@@ -465,6 +633,28 @@
             border_size = BorderNormal;
         checkSupportedBorderSizes();
 
+	// Shadows tab
+	// ===========
+	bool shadowEnabled = conf->readBoolEntry("ShadowEnabled", false);
+ 	cbWindowShadow->setChecked(shadowEnabled);
+	activeShadowSettings->setEnabled(shadowEnabled);
+	inactiveShadowSettings->setEnabled(shadowEnabled);
+	whichShadowSettings->setEnabled(shadowEnabled);
+	shadowColourButton->setColor(conf->readColorEntry("ShadowColour", &Qt::black));
+ 	shadowOpacitySlider->setValue((int)ceil(conf->readDoubleNumEntry("ShadowOpacity", 0.70) * 100));
+ 	shadowXOffsetSpinBox->setValue(conf->readNumEntry("ShadowXOffset", 0));
+ 	shadowYOffsetSpinBox->setValue(conf->readNumEntry("ShadowYOffset", 10));
+ 	cbShadowDocks->setChecked(conf->readBoolEntry("ShadowDocks", false));
+ 	cbShadowOverrides->setChecked(conf->readBoolEntry("ShadowOverrides", false));
+ 	cbShadowTopMenus->setChecked(conf->readBoolEntry("ShadowTopMenus", false));
+ 	shadowThicknessSpinBox->setValue(conf->readNumEntry("ShadowThickness", 10));
+ 	cbInactiveShadow->setChecked(conf->readBoolEntry("InactiveShadowEnabled", false));
+ 	inactiveShadowColourButton->setColor(conf->readColorEntry("InactiveShadowColour", &Qt::black));
+ 	inactiveShadowOpacitySlider->setValue((int)ceil(conf->readDoubleNumEntry("InactiveShadowOpacity", 0.70) * 100));
+ 	inactiveShadowXOffsetSpinBox->setValue(conf->readNumEntry("InactiveShadowXOffset", 0));
+ 	inactiveShadowYOffsetSpinBox->setValue(conf->readNumEntry("InactiveShadowYOffset", 5));
+ 	inactiveShadowThicknessSpinBox->setValue(conf->readNumEntry("InactiveShadowThickness", 5));
+
 	emit KCModule::changed(false);
 }
 
@@ -489,6 +679,27 @@
 	conf->writeEntry("ButtonsOnRight", buttonPositionWidget->buttonsRight() );
         conf->writeEntry("BorderSize", border_size );
 
+	// Shadow settings
+	conf->writeEntry("ShadowEnabled", cbWindowShadow->isChecked());
+	conf->writeEntry("ShadowColour", shadowColourButton->color());
+	conf->writeEntry("ShadowOpacity", shadowOpacitySlider->value() / 100.0);
+	conf->writeEntry("ShadowXOffset", shadowXOffsetSpinBox->value());
+	conf->writeEntry("ShadowYOffset", shadowYOffsetSpinBox->value());
+	conf->writeEntry("ShadowThickness", shadowThicknessSpinBox->value());
+	conf->writeEntry("ShadowDocks", cbShadowDocks->isChecked());
+	conf->writeEntry("ShadowOverrides", cbShadowOverrides->isChecked());
+	conf->writeEntry("ShadowTopMenus", cbShadowTopMenus->isChecked());
+	conf->writeEntry("InactiveShadowEnabled", cbInactiveShadow->isChecked());
+	conf->writeEntry("InactiveShadowColour", inactiveShadowColourButton->color());
+	conf->writeEntry("InactiveShadowOpacity",
+			inactiveShadowOpacitySlider->value() / 100.0);
+	conf->writeEntry("InactiveShadowXOffset",
+			inactiveShadowXOffsetSpinBox->value());
+	conf->writeEntry("InactiveShadowYOffset",
+			inactiveShadowYOffsetSpinBox->value());
+	conf->writeEntry("InactiveShadowThickness",
+			inactiveShadowThicknessSpinBox->value());
+
 	oldLibraryName = currentLibraryName;
 	currentLibraryName = libName;
 
@@ -541,6 +752,7 @@
 	cbUseCustomButtonPositions->setChecked( false );
 	buttonPositionWidget->setEnabled( false );
 	cbShowToolTips->setChecked( true );
+	cbWindowShadow->setChecked( false );
 //	cbUseMiniWindows->setChecked( false);
 // Don't set default for now
 //	decorationList->setSelected(
@@ -552,6 +764,21 @@
         border_size = BorderNormal;
         checkSupportedBorderSizes();
 
+	shadowColourButton->setColor(Qt::black);
+	shadowOpacitySlider->setValue(70);
+	shadowXOffsetSpinBox->setValue(0);
+	shadowYOffsetSpinBox->setValue(10);
+	shadowThicknessSpinBox->setValue(10);
+	cbShadowDocks->setChecked(false);
+	cbShadowOverrides->setChecked(false);
+	cbShadowTopMenus->setChecked(false);
+	cbInactiveShadow->setChecked(false);
+	inactiveShadowColourButton->setColor(Qt::black);
+	inactiveShadowOpacitySlider->setValue(70);
+	inactiveShadowXOffsetSpinBox->setValue(0);
+	inactiveShadowYOffsetSpinBox->setValue(5);
+	inactiveShadowThicknessSpinBox->setValue(5);
+
 	// Set plugin defaults
 	emit pluginDefaults();
 }
diff -Naur kdebase-3.5.8.orig/kwin/kcmkwin/kwindecoration/kwindecoration.h kdebase-3.5.8/kwin/kcmkwin/kwindecoration/kwindecoration.h
--- kdebase-3.5.8.orig/kwin/kcmkwin/kwindecoration/kwindecoration.h	2006-01-19 18:01:03.000000000 +0100
+++ kdebase-3.5.8/kwin/kcmkwin/kwindecoration/kwindecoration.h	2007-11-21 07:02:51.000000000 +0100
@@ -127,6 +127,19 @@
 		// Page 2
 		ButtonPositionWidget *buttonPositionWidget;
 		QVBox*	 buttonPage;
+
+		// Page 3
+		QVBox *shadowPage;
+		KColorButton *inactiveShadowColourButton, *shadowColourButton;
+		QCheckBox *cbShadowDocks, *cbShadowOverrides, *cbShadowTopMenus;
+		QCheckBox *cbInactiveShadow, *cbWindowShadow;
+		QGroupBox *activeShadowSettings, *inactiveShadowSettings;
+		QGroupBox *whichShadowSettings;
+		QSlider *inactiveShadowOpacitySlider, *shadowOpacitySlider;
+		QSpinBox *inactiveShadowOpacitySpinBox, *shadowOpacitySpinBox;
+		QSpinBox *inactiveShadowXOffsetSpinBox, *shadowXOffsetSpinBox;
+		QSpinBox *inactiveShadowYOffsetSpinBox, *shadowYOffsetSpinBox;
+		QSpinBox *inactiveShadowThicknessSpinBox, *shadowThicknessSpinBox;
 };
 
 
diff -Naur kdebase-3.5.8.orig/kwin/layers.cpp kdebase-3.5.8/kwin/layers.cpp
--- kdebase-3.5.8.orig/kwin/layers.cpp	2007-01-15 12:32:14.000000000 +0100
+++ kdebase-3.5.8/kwin/layers.cpp	2007-11-21 07:02:51.000000000 +0100
@@ -134,37 +134,89 @@
                                 // when passig pointers around.
 
     // restack the windows according to the stacking order
+#if 0
     Window* new_stack = new Window[ stacking_order.count() + 2 ];
     int pos = 0;
+#endif
+    NET::WindowType t;
+    Window shadow;
+    Window *dock_shadow_stack, *window_stack;
+    int i, numDocks, pos, topmenu_space_pos;
+ 
+    dock_shadow_stack = new Window[ stacking_order.count() * 2 ];
+    window_stack = new Window[ stacking_order.count() * 2 + 2 ];
+    i = 0;
+    pos = 0;
+    topmenu_space_pos = 1; // not 0, that's supportWindow !!!
+
     // Stack all windows under the support window. The support window is
     // not used for anything (besides the NETWM property), and it's not shown,
     // but it was lowered after kwin startup. Stacking all clients below
     // it ensures that no client will be ever shown above override-redirect
     // windows (e.g. popups).
+#if 0
     new_stack[ pos++ ] = supportWindow->winId();
     int topmenu_space_pos = 1; // not 0, that's supportWindow !!!
+#endif
+    window_stack[pos++] = supportWindow->winId();
     for( ClientList::ConstIterator it = stacking_order.fromLast();
          it != stacking_order.end();
          --it )
         {
+#if 0
         new_stack[ pos++ ] = (*it)->frameId();
         if( (*it)->belongsToLayer() >= DockLayer )
             topmenu_space_pos = pos;
-        }
+#endif
+	t = (*it)->windowType();
+	switch (t)
+		{
+		case NET::Dock:
+		    window_stack[pos++] = (*it)->frameId();
+		    if ((shadow = (*it)->shadowId()) != None)
+		    dock_shadow_stack[i++] = shadow;
+		break;
+		case NET::Desktop:
+		    numDocks = i;
+		    for (i = 0; i < numDocks; i++)
+		    // Shadows for dock windows go just above the desktop
+		    window_stack[pos++] = dock_shadow_stack[i];
+		    window_stack[pos++] = (*it)->frameId();
+		break;
+		case NET::TopMenu:
+		    topmenu_space_pos = pos;
+		    // fall through
+		default:
+		    window_stack[pos++] = (*it)->frameId();
+		    if ((shadow = (*it)->shadowId()) != None)
+			// If the current window also has a shadow, place it
+			// immediately under the current window
+			window_stack[pos++] = shadow;
+		}
+    	}
     if( topmenu_space != NULL )
         { // make sure the topmenu space is below all topmenus, fullscreens, etc.
         for( int i = pos;
              i > topmenu_space_pos;
              --i )
+#if 0
             new_stack[ i ] = new_stack[ i - 1 ];
         new_stack[ topmenu_space_pos ] = topmenu_space->winId();
+#endif
+            window_stack[ i ] = window_stack[ i - 1 ];
+	window_stack[ topmenu_space_pos ] = topmenu_space->winId();
         ++pos;
         }
     // TODO isn't it too inefficient to restart always all clients?
     // TODO don't restack not visible windows?
     assert( new_stack[ 0 ] = supportWindow->winId());
+#if 0
     XRestackWindows(qt_xdisplay(), new_stack, pos);
     delete [] new_stack;
+#endif
+    XRestackWindows(qt_xdisplay(), window_stack, pos);
+    delete [] dock_shadow_stack;
+    delete [] window_stack;
 
     if ( propagate_new_clients )
         {
@@ -342,6 +394,11 @@
 
     unconstrained_stacking_order.remove( c );
     unconstrained_stacking_order.append( c );
+    if (options->shadowEnabled(c->isActive()))
+        {
+        c->removeShadow();
+        c->drawDelayedShadow();
+        }
 
     if( !c->isSpecialWindow())
         {
diff -Naur kdebase-3.5.8.orig/kwin/lib/kdecoration.h kdebase-3.5.8/kwin/lib/kdecoration.h
--- kdebase-3.5.8.orig/kwin/lib/kdecoration.h	2005-09-10 10:26:02.000000000 +0200
+++ kdebase-3.5.8/kwin/lib/kdecoration.h	2007-11-21 07:02:51.000000000 +0100
@@ -97,6 +97,7 @@
         LowerOp,
         FullScreenOp,
         NoBorderOp,
+	ShadowOp,
         NoOp,
         SetupWindowShortcutOp,
         ApplicationRulesOp     ///< @since 3.5
@@ -116,7 +117,7 @@
 	ColorHandle,     ///< The color for the resize handle
 	NUM_COLORS
 	};
-    
+
     /**
      * These flags specify which settings changed when rereading settings.
      * Each setting in class KDecorationOptions specifies its matching flag.
@@ -130,7 +131,7 @@
         SettingTooltips   = 1 << 4, ///< The tooltip setting was changed
         SettingBorder     = 1 << 5  ///< The border size setting was changed
         };
-        
+
     /**
      * Border size. KDecorationOptions::preferredBorderSize() returns
      * one of these values.
@@ -261,7 +262,7 @@
     * The changed flags for this setting is SettingTooltips.
     */
     bool showTooltips() const;
-    
+
     /**
      * The preferred border size selected by the user, e.g. for accessibility
      * reasons, or when using high resolution displays. It's up to the decoration
@@ -322,9 +323,9 @@
 	 * Destroys the KDecoration.
 	 */
 	virtual ~KDecoration();
-	
+
 	// requests from decoration
-	
+
 	/**
 	 * Returns the KDecorationOptions object, which is used to access
 	 * configuration settings for the decoration.
@@ -417,7 +418,7 @@
 	 * to support older code). For a description of all window types,
 	 * see the definition of the NET::WindowType type. Note that
 	 * some window types never have decorated windows.
-	 * 
+	 *
 	 * An example of usage:
 	 * @code
 	 * const unsigned long supported_types = NET::NormalMask | NET::DesktopMask
@@ -671,7 +672,7 @@
 	/**
 	 * This function is called to reset the decoration on settings changes.
 	 * It is usually invoked by calling KDecorationFactory::resetDecorations().
-	 * 
+	 *
 	 * @param changed Specifies which settings were changed, given by the SettingXXX masks
 	 */
         virtual void reset( unsigned long changed );
diff -Naur kdebase-3.5.8.orig/kwin/manage.cpp kdebase-3.5.8/kwin/manage.cpp
--- kdebase-3.5.8.orig/kwin/manage.cpp	2007-11-21 07:02:36.000000000 +0100
+++ kdebase-3.5.8/kwin/manage.cpp	2007-11-21 07:02:51.000000000 +0100
@@ -356,6 +356,7 @@
         setSkipTaskbar( session->skipTaskbar, true );
         setSkipPager( session->skipPager );
         setShade( session->shaded ? ShadeNormal : ShadeNone );
+        setShadowed( session->shadowed );
         if( session->maximized != MaximizeRestore )
             {
             maximize( (MaximizeMode) session->maximized );
diff -Naur kdebase-3.5.8.orig/kwin/options.cpp kdebase-3.5.8/kwin/options.cpp
--- kdebase-3.5.8.orig/kwin/options.cpp	2007-11-21 07:02:36.000000000 +0100
+++ kdebase-3.5.8/kwin/options.cpp	2007-11-21 07:02:51.000000000 +0100
@@ -202,7 +202,24 @@
     if (resetKompmgr)
         config->writeEntry("ResetKompmgr",FALSE);
     
-    
+     // window drop shadows
+    config->setGroup("Style");
+    shadow_colour = config->readColorEntry("ShadowColour", &Qt::black);
+    shadow_docks = config->readBoolEntry("ShadowDocks", false);
+    shadow_overrides = config->readBoolEntry("ShadowOverrides", false);
+    shadow_topMenus = config->readBoolEntry("ShadowTopMenus", false);
+    shadow_inactive_colour = config->readColorEntry("InactiveShadowColour", &Qt::black);
+    shadow_inactive_enabled = config->readBoolEntry("InactiveShadowEnabled", false);
+    shadow_inactive_opacity = config->readDoubleNumEntry("InactiveShadowOpacity", 0.70);
+    shadow_inactive_thickness = config->readNumEntry("InactiveShadowThickness", 5);
+    shadow_inactive_x_offset = config->readNumEntry("InactiveShadowXOffset", 0);
+    shadow_inactive_y_offset = config->readNumEntry("InactiveShadowYOffset", 5);
+    shadow_enabled = config->readBoolEntry("ShadowEnabled", false);
+    shadow_opacity = config->readDoubleNumEntry("ShadowOpacity", 0.70);
+    shadow_thickness = config->readNumEntry("ShadowThickness", 10);
+    shadow_x_offset = config->readNumEntry("ShadowXOffset", 0);
+    shadow_y_offset = config->readNumEntry("ShadowYOffset", 10);
+
     
     // Read button tooltip animation effect from kdeglobals
     // Since we want to allow users to enable window decoration tooltips
@@ -252,6 +269,8 @@
         return HMaximizeOp;
     else if (name == "Lower")
         return LowerOp;
+    else if (name == "Shadow")
+        return ShadowOp;
     return NoOp;
     }
 
@@ -294,6 +313,69 @@
     return show_geometry_tip;
     }
 
+QColor &Options::shadowColour(bool active)
+    {
+    return active ? shadow_colour : shadow_inactive_colour;
+    }
+
+bool Options::shadowWindowType(NET::WindowType t)
+    {
+    bool retval;
+
+    switch (t)
+        {
+        case NET::Dialog:
+        case NET::Normal:
+            retval = true;
+            break;
+        case NET::Desktop:
+        case NET::Menu:
+        case NET::Toolbar:
+            retval = false;
+            break;
+        case NET::Dock:
+            retval = shadow_docks;
+            break;
+        case NET::Override:
+            retval = shadow_overrides;
+            break;
+        case NET::TopMenu:
+            retval = shadow_topMenus;
+            break;
+        default:
+            retval = false;
+            break;
+        }
+
+    return retval;
+    }
+
+bool Options::shadowEnabled(bool active)
+    {
+    return active ? shadow_enabled :
+        (shadow_enabled && shadow_inactive_enabled);
+    }
+
+double Options::shadowOpacity(bool active)
+    {
+    return active ? shadow_opacity : shadow_inactive_opacity;
+    }
+
+int Options::shadowThickness(bool active)
+    {
+    return active ? shadow_thickness : shadow_inactive_thickness;
+    }
+
+int Options::shadowXOffset(bool active)
+    {
+    return active ? shadow_x_offset : shadow_inactive_x_offset;
+    }
+
+int Options::shadowYOffset(bool active)
+    {
+    return active ? shadow_y_offset : shadow_inactive_y_offset;
+    }
+
 int Options::electricBorders()
     {
     return electric_borders;
diff -Naur kdebase-3.5.8.orig/kwin/options.h kdebase-3.5.8/kwin/options.h
--- kdebase-3.5.8.orig/kwin/options.h	2007-11-21 07:02:36.000000000 +0100
+++ kdebase-3.5.8/kwin/options.h	2007-11-21 07:02:51.000000000 +0100
@@ -268,6 +268,45 @@
         */
         bool showGeometryTip();
 
+        /**
+        * @returns A QColor representing the colour that window drop shadows should
+        *          be.
+        */
+        QColor &shadowColour(bool active=true);
+
+        /**
+        * @returns true if shadows should be drawn around windows of the
+        *          specified type
+        */
+        bool shadowWindowType(NET::WindowType t);
+
+        /**
+        * @returns true if window shadows should be drawn
+        */
+        bool shadowEnabled(bool active=true);
+
+        /**
+        * @returns Window shadow's opacity between 0.01 and 1.00.
+        */
+        double shadowOpacity(bool active=true);
+
+        /**
+        * @returns How thick a shadow should be to either side of of a window.
+        */
+        int shadowThickness(bool active=true);
+
+        /**
+        * @returns Number of pixels along the X-axis by which to offset window
+        *          shadows.
+        */
+        int shadowXOffset(bool active=true);
+
+        /**
+        * @returns Number of pixels along the Y-axis by which to offset window
+        *          shadows.
+        */
+        int shadowYOffset(bool active=true);
+
         enum { ElectricDisabled = 0, ElectricMoveOnly = 1, ElectricAlways = 2 };
         /**
         * @returns true if electric borders are enabled. With electric borders
@@ -336,6 +375,21 @@
         bool show_geometry_tip;
         bool topmenus;
         bool desktop_topmenu;
+        QColor shadow_colour;
+        QColor shadow_inactive_colour;
+        bool shadow_docks;
+        bool shadow_overrides;
+        bool shadow_topMenus;
+        bool shadow_inactive_enabled;
+        bool shadow_enabled;
+        double shadow_inactive_opacity;
+        double shadow_opacity;
+        int shadow_inactive_thickness;
+        int shadow_thickness;
+        int shadow_inactive_x_offset;
+        int shadow_x_offset;
+        int shadow_inactive_y_offset;
+        int shadow_y_offset;
         // List of window classes for which not to use focus stealing prevention
         QStringList ignoreFocusStealingClasses;
 
diff -Naur kdebase-3.5.8.orig/kwin/sm.cpp kdebase-3.5.8/kwin/sm.cpp
--- kdebase-3.5.8.orig/kwin/sm.cpp	2007-05-14 09:55:48.000000000 +0200
+++ kdebase-3.5.8/kwin/sm.cpp	2007-11-21 07:02:51.000000000 +0100
@@ -106,6 +106,7 @@
             // the config entry is called "sticky" for back. comp. reasons
             config->writeEntry( QString("sticky")+n, c->isOnAllDesktops() );
             config->writeEntry( QString("shaded")+n, c->isShade() );
+            config->writeEntry( QString("shadowed")+n, c->isShadowed() );
             // the config entry is called "staysOnTop" for back. comp. reasons
             config->writeEntry( QString("staysOnTop")+n, c->keepAbove() );
             config->writeEntry( QString("keepBelow")+n, c->keepBelow() );
@@ -172,6 +173,7 @@
         info->minimized = config->readBoolEntry( QString("iconified")+n, FALSE );
         info->onAllDesktops = config->readBoolEntry( QString("sticky")+n, FALSE );
         info->shaded = config->readBoolEntry( QString("shaded")+n, FALSE );
+        info->shadowed = config->readBoolEntry( QString("shadowed")+n, TRUE );
         info->keepAbove = config->readBoolEntry( QString("staysOnTop")+n, FALSE  );
         info->keepBelow = config->readBoolEntry( QString("keepBelow")+n, FALSE  );
         info->skipTaskbar = config->readBoolEntry( QString("skipTaskbar")+n, FALSE  );
diff -Naur kdebase-3.5.8.orig/kwin/sm.h kdebase-3.5.8/kwin/sm.h
--- kdebase-3.5.8.orig/kwin/sm.h	2005-09-10 10:26:03.000000000 +0200
+++ kdebase-3.5.8/kwin/sm.h	2007-11-21 07:02:51.000000000 +0100
@@ -39,6 +39,7 @@
     bool minimized;
     bool onAllDesktops;
     bool shaded;
+    bool shadowed;
     bool keepAbove;
     bool keepBelow;
     bool skipTaskbar;
diff -Naur kdebase-3.5.8.orig/kwin/useractions.cpp kdebase-3.5.8/kwin/useractions.cpp
--- kdebase-3.5.8.orig/kwin/useractions.cpp	2007-11-21 07:02:36.000000000 +0100
+++ kdebase-3.5.8/kwin/useractions.cpp	2007-11-21 07:02:51.000000000 +0100
@@ -65,6 +65,7 @@
         advanced_popup->insertItem( SmallIconSet( "window_fullscreen" ),
             i18n("&Fullscreen")+'\t'+keys->shortcut("Window Fullscreen").seq(0).toString(), Options::FullScreenOp );
         advanced_popup->insertItem( i18n("&No Border")+'\t'+keys->shortcut("Window No Border").seq(0).toString(), Options::NoBorderOp );
+	advanced_popup->insertItem( i18n("Shad&ow"), Options::ShadowOp );
         advanced_popup->insertItem( SmallIconSet("key_bindings"),
             i18n("Window &Shortcut...")+'\t'+keys->shortcut("Setup Window Shortcut").seq(0).toString(), Options::SetupWindowShortcutOp );
         advanced_popup->insertItem( SmallIconSet( "wizard" ), i18n("&Special Window Settings..."), Options::WindowRulesOp );
@@ -172,6 +173,10 @@
     advanced_popup->setItemEnabled( Options::FullScreenOp, active_popup_client->userCanSetFullScreen() );
     advanced_popup->setItemChecked( Options::NoBorderOp, active_popup_client->noBorder() );
     advanced_popup->setItemEnabled( Options::NoBorderOp, active_popup_client->userCanSetNoBorder() );
+    
+    advanced_popup->setItemEnabled( Options::ShadowOp, (options->shadowWindowType(active_popup_client->windowType()) && options->shadowEnabled(active_popup_client->isActive())) );
+    advanced_popup->setItemChecked( Options::ShadowOp, active_popup_client->isShadowed() );
+    
     popup->setItemEnabled( Options::MinimizeOp, active_popup_client->isMinimizable() );
     popup->setItemEnabled( Options::CloseOp, active_popup_client->isCloseable() );
     if (options->useTranslucency)
@@ -398,6 +403,9 @@
         case Options::ShadeOp:
             c->performMouseCommand( Options::MouseShade, QCursor::pos());
             break;
+        case Options::ShadowOp:
+            c->setShadowed( !c->isShadowed() );
+            break;
         case Options::OnAllDesktopsOp:
             c->setOnAllDesktops( !c->isOnAllDesktops() );
             break;
diff -Naur kdebase-3.5.8.orig/kwin/workspace.cpp kdebase-3.5.8/kwin/workspace.cpp
--- kdebase-3.5.8.orig/kwin/workspace.cpp	2007-11-21 07:02:36.000000000 +0100
+++ kdebase-3.5.8/kwin/workspace.cpp	2007-11-21 07:02:51.000000000 +0100
@@ -79,6 +79,7 @@
     rules_updates_disabled( false ),
     active_client     (0),
     last_active_client     (0),
+    next_active_client     (0),
     most_recently_raised (0),
     movingClient(0),
     pending_take_activity ( NULL ),
@@ -685,6 +686,24 @@
         }
     }
 
+void Workspace::updateOverlappingShadows(unsigned long window)
+    {
+    Client *client;
+    
+    if ((client = findClient(WindowMatchPredicate((WId)window))))
+        // Redraw overlapping shadows without waiting for the specified window
+        // to redraw its own shadow
+        client->drawOverlappingShadows(false);
+    }
+
+void Workspace::setShadowed(unsigned long window, bool shadowed)
+    {
+    Client *client;
+    
+    if ((client = findClient(WindowMatchPredicate((WId)window))))
+        client->setShadowed(shadowed);
+    }
+
 void Workspace::updateCurrentTopMenu()
     {
     if( !managingTopMenus())
diff -Naur kdebase-3.5.8.orig/kwin/workspace.h kdebase-3.5.8/kwin/workspace.h
--- kdebase-3.5.8.orig/kwin/workspace.h	2007-11-21 07:02:36.000000000 +0100
+++ kdebase-3.5.8/kwin/workspace.h	2007-11-21 07:02:51.000000000 +0100
@@ -230,6 +230,8 @@
         void unclutterDesktop();
         void doNotManage(QString);
         bool setCurrentDesktop( int new_desktop );
+        void updateOverlappingShadows(WId window);
+        void setShadowed(WId window, bool shadowed);
         void nextDesktop();
         void previousDesktop();
         void circulateDesktopApplications();
@@ -517,6 +519,7 @@
 
         Client* active_client;
         Client* last_active_client;
+        Client* next_active_client; // will be active after active_client deactivates
         Client* most_recently_raised; // used _only_ by raiseOrLowerClient()
         Client* movingClient;
         Client* pending_take_activity;
@@ -703,7 +706,15 @@
 
 inline Client* Workspace::activeClient() const
     {
-    return active_client;
+    // next_active_client is a kludge for drop shadows. If a window that is
+    // activated is not also raised (i.e. when focus follows mouse), then the
+    // newly activated window and its shadow won't cover visual artifacts that
+    // might exist in the inactive window's shadow. We work around this by
+    // (re)drawing the inactive window's shadow after the active window's shadow
+    // is drawn, but to do that the inactive window needs to know which window
+    // will become active next. next_active_client is a Client pointer for that
+    // purpose.
+    return next_active_client != NULL ? next_active_client : active_client;
     }
 
 inline Client* Workspace::mostRecentlyActivatedClient() const
