summaryrefslogtreecommitdiffstats
path: root/kwin/client.cpp
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-09-07 19:42:15 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-09-07 19:42:15 +0000
commit9cc1e2c1aa2629d499e7555acd4906d6cc989cf9 (patch)
tree2a737f47bb029688c2f5ebef76869903cf4b4eec /kwin/client.cpp
parenteaa51fec106463800192924168eaf9f03f188655 (diff)
downloadtdebase-9cc1e2c1aa2629d499e7555acd4906d6cc989cf9.tar.gz
tdebase-9cc1e2c1aa2629d499e7555acd4906d6cc989cf9.zip
Merged in remaining kdebase bugfixes from the Chakra project
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1172677 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kwin/client.cpp')
-rw-r--r--kwin/client.cpp637
1 files changed, 636 insertions, 1 deletions
diff --git a/kwin/client.cpp b/kwin/client.cpp
index 5f281f2ab..0d2c5cfbf 100644
--- a/kwin/client.cpp
+++ b/kwin/client.cpp
@@ -11,9 +11,12 @@ License. See the file "COPYING" for the exact licensing terms.
#include "client.h"
+#include <math.h>
+
#include <tqapplication.h>
#include <tqpainter.h>
#include <tqdatetime.h>
+#include <tqimage.h>
#include <kprocess.h>
#include <unistd.h>
#include <kstandarddirs.h>
@@ -39,9 +42,25 @@ extern Time qt_x_time;
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
+ {
+ TQRegion region;
+ Client *client;
+ };
+static TQValueList<ShadowRegion> shadowRegions;
+
/*
Creating a client:
@@ -100,6 +119,13 @@ Client::Client( Workspace *ws )
autoRaiseTimer = 0;
shadeHoverTimer = 0;
+ shadowDelayTimer = new TQTimer(this);
+ opacityCache = &activeOpacityCache;
+ shadowAfterClient = NULL;
+ shadowWidget = NULL;
+ shadowMe = true;
+ connect(shadowDelayTimer, TQT_SIGNAL(timeout()), TQT_SLOT(drawShadow()));
+
// set the initial mapping state
mapping_state = WithdrawnState;
desk = 0; // no desktop yet
@@ -145,7 +171,7 @@ Client::Client( Workspace *ws )
maxmode_restore = MaximizeRestore;
cmap = None;
-
+
frame_geometry = TQRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0)
client_size = TQSize( 100, 100 );
custom_opacity = false;
@@ -188,6 +214,8 @@ void Client::releaseWindow( bool on_shutdown )
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 @@ void Client::destroyClient()
StackingUpdatesBlocker blocker( workspace());
if (moveResizeMode)
leaveMoveResize();
+ removeShadow();
+ drawIntersectingShadows();
finishWindowRules();
++postpone_geometry_updates;
setModal( false );
@@ -304,6 +334,7 @@ void Client::updateDecoration( bool check_workspace_pos, bool force )
if( do_show )
decoration->widget()->show();
updateFrameExtents();
+ updateOpacityCache();
}
void Client::destroyDecoration()
@@ -434,6 +465,12 @@ void Client::resizeDecoration( const TQSize& s )
TQResizeEvent e( s, oldsize );
TQApplication::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 @@ void Client::updateShape()
noborder = true;
updateDecoration( true );
}
+ updateOpacityCache();
if ( shape() )
{
XShapeCombineShape(qt_xdisplay(), frameId(), ShapeBounding,
@@ -862,6 +900,16 @@ void Client::setShade( ShadeMode mode )
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::updateVisibility()
}
}
+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;
+ TQRegion region;
+ //TQPtrList<Client> reshadowClients;
+ TQValueList<Client *> reshadowClients;
+ TQValueListIterator<ShadowRegion> it;
+ TQValueListIterator<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;
+ TQRegion region;
+ TQValueList<Client *> reshadowClients;
+ ClientList stacking_order;
+ ClientList::ConstIterator it;
+ TQValueListIterator<ShadowRegion> it2;
+ TQValueListIterator<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, TQT_SIGNAL(shadowDrawn()), TQT_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, TQT_SIGNAL(shadowDrawn()), this, TQT_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 = TQRegion(x(), y(), width(), height());
+ else {
+ shapeBoundingRegion = TQRegion();
+ for (i = 0; i < count; i++) {
+ // Translate XShaped window into a TQRegion
+ TQRegion 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 &= TQRegion(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();
+
+ TQMemArray<QRgb> pixelData;
+ TQPixmap shadowPixmap;
+ TQRect shadow;
+ TQRegion 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 TQWidget(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 {
+ TQMemArray<TQRect> exposedRects;
+ TQMemArray<TQRect>::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 TQWidget::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()
+{
+ TQValueList<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.
+ */
+TQRegion Client::getExposedRegion(TQRegion occludedRegion, int x, int y, int w,
+ int h, int thickness, int xOffset, int yOffset)
+{
+ TQRegion exposedRegion;
+
+ exposedRegion = TQRegion(x, y, w, h);
+ exposedRegion -= occludedRegion;
+
+ if (thickness > 0) {
+ // Limit exposedRegion to include only where a shadow of the specified
+ // thickness will be drawn
+ TQMemArray<TQRect> occludedRects;
+ TQMemArray<TQRect>::Iterator it, itEnd;
+ TQRegion 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 TQRegion 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 += TQRegion(*it);
+ }
+ exposedRegion -= exposedRegion - shadowRegion;
+ }
+
+ return exposedRegion;
+}
+
+/*!
+ Draw shadow gradient around this window using cached opacity values.
+ */
+void Client::imposeCachedShadow(TQPixmap &pixmap, TQRegion exposed)
+{
+ QRgb pixel;
+ double opacity;
+ int red, green, blue, pixelRed, pixelGreen, pixelBlue;
+ int subW, subH, w, h, x, y, zeroX, zeroY;
+ TQImage image;
+ TQMemArray<TQRect>::Iterator it, itEnd;
+ TQMemArray<TQRect> rectangles;
+ TQPixmap 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 = TQPixmap::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(TQPixmap &pixmap, TQRegion occluded,
+ TQRegion 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;
+ TQImage image;
+ TQMemArray<TQRect>::Iterator it, itEnd;
+ TQMemArray<TQRect> rectangles;
+ TQPixmap 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 = TQPixmap::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(TQPoint(i, j)))
+ intersectCount++;
+ }
+ }
+ }
+ else {
+ if (intersectCount < 0)
+ intersectCount = 0;
+
+ for (i = irLeft; i <= irRight; i++) {
+ if (occluded.contains(TQPoint(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(TQPoint(i, irTop)))
+ intersectCount--;
+ }
+
+ y += yIncrement;
+ }
+ y -= yIncrement;
+
+ irTop += yIncrement;
+ for (j = irTop; j != irBottom; j += yIncrement) {
+ if (occluded.contains(TQPoint(irLeft, j)))
+ intersectCount--;
+ }
+ irRight++;
+ for (j = irTop; j != irBottom; j += yIncrement) {
+ if (occluded.contains(TQPoint(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 @@ void Client::rawShow()
XMapWindow( qt_xdisplay(), wrapper );
XMapWindow( qt_xdisplay(), client );
}
+ if (options->shadowEnabled(isActive()))
+ drawDelayedShadow();
}
/*!
@@ -1004,6 +1637,8 @@ void Client::rawHide()
// 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 );