All pastes #433643 Raw Edit

Miscellany

public text v1 · immutable
·published 2007-04-10 22:34 UTC
rendered paste body
diff --git a/include/compiz.h b/include/compiz.h
index 027a0e3..8ed0668 100644
--- a/include/compiz.h
+++ b/include/compiz.h
@@ -26,7 +26,7 @@
 #ifndef _COMPIZ_H
 #define _COMPIZ_H
 
-#define ABIVERSION 20070403
+#define ABIVERSION 20070405
 
 #include <stdio.h>
 #include <sys/time.h>
@@ -1150,6 +1150,12 @@ typedef void (*DonePaintScreenProc) (CompScreen *screen);
 #define PAINT_SCREEN_TRANSFORMED_MASK		   (1 << 2)
 #define PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK (1 << 3)
 #define PAINT_SCREEN_CLEAR_MASK			   (1 << 4)
+#define PAINT_SCREEN_ORDER_BACK_TO_FRONT_MASK	   (1 << 5)
+#define PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK	   (1 << 6)
+/* A plugin that sets PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK will get reversed painting.
+   A plugin that sets  both PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK and PAINT_SCREEN_ORDER_BACK_TO_FRONT_MASK
+   will get both normal and reversed painting one after the other,
+   and will check paint window mask to avoid painting the window twice. This allows more complex drawing order.*/
 
 typedef Bool (*PaintScreenProc) (CompScreen		 *screen,
 				 const ScreenPaintAttrib *sAttrib,
@@ -1215,6 +1221,13 @@ typedef void (*ApplyScreenTransformProc) (CompScreen		  *screen,
 */
 #define PAINT_WINDOW_BLEND_MASK			(1 << 19)
 
+/*
+ flags that indicate the painting order which is used
+ in paintScreen when drawing the window.
+*/
+#define PAINT_WINDOW_BACK_TO_FRONT_MASK		(1 << 20)
+#define PAINT_WINDOW_FRONT_TO_BACK_MASK		(1 << 21)
+
 
 typedef Bool (*PaintWindowProc) (CompWindow		 *window,
 				 const WindowPaintAttrib *attrib,
@@ -1252,6 +1265,10 @@ typedef void (*PaintBackgroundProc) (CompScreen   *screen,
 				     Region	  region,
 				     unsigned int mask);
 
+typedef void (*SetClipPlanesProc) (CompScreen *screen, Region region, int output);
+
+void setClipPlanes (CompScreen *screen, Region region, int output);
+
 void
 preparePaintScreen (CompScreen *screen,
 		    int	       msSinceLastPaint);
@@ -1922,6 +1939,7 @@ struct _CompScreen {
     GetOutputExtentsForWindowProc  getOutputExtentsForWindow;
     GetAllowedActionsForWindowProc getAllowedActionsForWindow;
     FocusWindowProc		   focusWindow;
+    SetClipPlanesProc		   setClipPlanes;
 
     PaintCursorProc      paintCursor;
     DamageCursorRectProc damageCursorRect;
diff --git a/plugins/cube.c b/plugins/cube.c
index 6784a45..56e6935 100644
--- a/plugins/cube.c
+++ b/plugins/cube.c
@@ -52,6 +52,14 @@
 
 #define CUBE_IN_DEFAULT FALSE
 
+typedef enum _RotationMode
+{
+    NoRotation = 0,
+    RotationChange,
+    RotationManual
+} RotationMode;
+
+
 static char *cubeImages[] = {
     "freedesktop"
 };
@@ -85,6 +93,21 @@ static char *cubeImages[] = {
 #define CUBE_ACCELERATION_MAX       20.0f
 #define CUBE_ACCELERATION_PRECISION 0.1f
 
+#define CUBE_FADE_TIME_DEFAULT			1.0
+#define CUBE_FADE_TIME_MAX			10.0
+#define CUBE_FADE_TIME_MIN			0.0
+#define CUBE_FADE_TIME_PRECISION		0.1
+
+#define CUBE_OPACITY_MIN 0.0
+#define CUBE_OPACITY_MAX 100.0
+#define CUBE_OPACITY_PRECISION 1.0
+
+#define CUBE_TRANSPARENT_MANUAL_ONLY_DEFAULT FALSE
+
+#define CUBE_ACTIVE_OPACITY_DEFAULT	30
+
+#define CUBE_INACTIVE_OPACITY_DEFAULT	100
+
 #define CUBE_SPEED_DEFAULT   1.5f
 #define CUBE_SPEED_MIN       0.1f
 #define CUBE_SPEED_MAX       50.0f
@@ -108,22 +131,59 @@ typedef struct _CubeDisplay {
     int		    screenPrivateIndex;
 
     CompOption opt[CUBE_DISPLAY_OPTION_NUM];
+    
+    HandleCompizEventProc handleCompizEvent;
 } CubeDisplay;
 
-#define CUBE_SCREEN_OPTION_COLOR	      0
-#define CUBE_SCREEN_OPTION_IN		      1
-#define CUBE_SCREEN_OPTION_SCALE_IMAGE	      2
-#define CUBE_SCREEN_OPTION_IMAGES	      3
-#define CUBE_SCREEN_OPTION_SKYDOME	      4
-#define CUBE_SCREEN_OPTION_SKYDOME_IMG	      5
-#define CUBE_SCREEN_OPTION_SKYDOME_ANIM	      6
-#define CUBE_SCREEN_OPTION_SKYDOME_GRAD_START 7
-#define CUBE_SCREEN_OPTION_SKYDOME_GRAD_END   8
-#define CUBE_SCREEN_OPTION_ACCELERATION	      9
-#define CUBE_SCREEN_OPTION_SPEED	      10
-#define CUBE_SCREEN_OPTION_TIMESTEP	      11
-#define CUBE_SCREEN_OPTION_MIPMAP	      12
-#define CUBE_SCREEN_OPTION_NUM                13
+#define CUBE_SCREEN_OPTION_COLOR	           0
+#define CUBE_SCREEN_OPTION_IN		           1
+#define CUBE_SCREEN_OPTION_SCALE_IMAGE	           2
+#define CUBE_SCREEN_OPTION_IMAGES	           3
+#define CUBE_SCREEN_OPTION_SKYDOME	           4
+#define CUBE_SCREEN_OPTION_SKYDOME_IMG	           5
+#define CUBE_SCREEN_OPTION_SKYDOME_ANIM	           6
+#define CUBE_SCREEN_OPTION_SKYDOME_GRAD_START      7
+#define CUBE_SCREEN_OPTION_SKYDOME_GRAD_END        8
+#define CUBE_SCREEN_OPTION_ACCELERATION	           9
+#define CUBE_SCREEN_OPTION_SPEED	           10
+#define CUBE_SCREEN_OPTION_TIMESTEP	           11
+#define CUBE_SCREEN_OPTION_MIPMAP	           12
+#define CUBE_SCREEN_OPTION_ACTIVE_OPACITY          13
+#define CUBE_SCREEN_OPTION_INACTIVE_OPACITY        14
+#define CUBE_SCREEN_OPTION_FADE_TIME               15
+#define CUBE_SCREEN_OPTION_TRANSPARENT_MANUAL_ONLY 16
+#define CUBE_SCREEN_OPTION_NUM                     17
+
+#define MULTM(x,y,z) \
+z[0] = x[0] * y[0] + x[4] * y[1] + x[8] * y[2] + x[12] * y[3]; \
+z[1] = x[1] * y[0] + x[5] * y[1] + x[9] * y[2] + x[13] * y[3]; \
+z[2] = x[2] * y[0] + x[6] * y[1] + x[10] * y[2] + x[14] * y[3]; \
+z[3] = x[3] * y[0] + x[7] * y[1] + x[11] * y[2] + x[15] * y[3]; \
+z[4] = x[0] * y[4] + x[4] * y[5] + x[8] * y[6] + x[12] * y[7]; \
+z[5] = x[1] * y[4] + x[5] * y[5] + x[9] * y[6] + x[13] * y[7]; \
+z[6] = x[2] * y[4] + x[6] * y[5] + x[10] * y[6] + x[14] * y[7]; \
+z[7] = x[3] * y[4] + x[7] * y[5] + x[11] * y[6] + x[15] * y[7]; \
+z[8] = x[0] * y[8] + x[4] * y[9] + x[8] * y[10] + x[12] * y[11]; \
+z[9] = x[1] * y[8] + x[5] * y[9] + x[9] * y[10] + x[13] * y[11]; \
+z[10] = x[2] * y[8] + x[6] * y[9] + x[10] * y[10] + x[14] * y[11]; \
+z[11] = x[3] * y[8] + x[7] * y[9] + x[11] * y[10] + x[15] * y[11]; \
+z[12] = x[0] * y[12] + x[4] * y[13] + x[8] * y[14] + x[12] * y[15]; \
+z[13] = x[1] * y[12] + x[5] * y[13] + x[9] * y[14] + x[13] * y[15]; \
+z[14] = x[2] * y[12] + x[6] * y[13] + x[10] * y[14] + x[14] * y[15]; \
+z[15] = x[3] * y[12] + x[7] * y[13] + x[11] * y[14] + x[15] * y[15];
+
+#define MULTMV(m, v) { \
+float v0 = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3]; \
+float v1 = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3]; \
+float v2 = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3]; \
+float v3 = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3]; \
+v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; }
+
+#define DIVV(v) \
+v[0] /= v[3]; \
+v[1] /= v[3]; \
+v[2] /= v[3]; \
+v[3] /= v[3];
 
 typedef struct _CubeScreen {
     PreparePaintScreenProc     preparePaintScreen;
@@ -133,6 +193,9 @@ typedef struct _CubeScreen {
     ApplyScreenTransformProc   applyScreenTransform;
     SetScreenOptionProc	       setScreenOption;
     OutputChangeNotifyProc     outputChangeNotify;
+    SetClipPlanesProc          setClipPlanes;
+    PaintBackgroundProc        paintBackground;
+    PaintWindowProc            paintWindow;
 
     CompOption opt[CUBE_SCREEN_OPTION_NUM];
 
@@ -173,11 +236,18 @@ typedef struct _CubeScreen {
     Bool cleared[64];
 
     Bool fullscreenOutput;
+    RotationMode rotationMode;
 
     float outputXScale;
     float outputYScale;
     float outputXOffset;
     float outputYOffset;
+    
+    Bool disableCaps;
+    Bool paintAllViewports;
+    
+    float desktopOpacity;
+    float toOpacity;
 
 #ifdef USE_LIBRSVG
     cairo_t	    *cr;
@@ -971,8 +1041,14 @@ cubeSetScreenOption (CompPlugin      *plugin,
 	}
 	break;
     case CUBE_SCREEN_OPTION_MIPMAP:
+    case CUBE_SCREEN_OPTION_TRANSPARENT_MANUAL_ONLY:
 	if (compSetBoolOption (o, value))
 	    return TRUE;
+    case CUBE_SCREEN_OPTION_FADE_TIME:
+    case CUBE_SCREEN_OPTION_ACTIVE_OPACITY:
+    case CUBE_SCREEN_OPTION_INACTIVE_OPACITY:
+	if (compSetFloatOption (o,value))
+	    return TRUE;
     default:
 	break;
     }
@@ -1106,6 +1182,46 @@ cubeScreenInitOptions (CubeScreen *cs,
     o->longDesc	  = N_("Generate mipmaps when possible for higher quality scaling");
     o->type	  = CompOptionTypeBool;
     o->value.b    = CUBE_MIPMAP_DEFAULT;
+
+    o = &cs->opt[CUBE_SCREEN_OPTION_FADE_TIME];
+    o->name = "fade_time";
+    o->shortDesc = N_("Fade Time");
+    o->longDesc = N_("Desktop Window Opacity Fade Time.");
+    o->type = CompOptionTypeFloat;
+    o->value.f = CUBE_FADE_TIME_DEFAULT;
+    o->rest.f.min = CUBE_FADE_TIME_MIN;
+    o->rest.f.max = CUBE_FADE_TIME_MAX;
+    o->rest.f.precision = CUBE_FADE_TIME_PRECISION;
+
+    o = &cs->opt[CUBE_SCREEN_OPTION_ACTIVE_OPACITY];
+    o->name = "active_opacity";
+    o->shortDesc = N_("Opacity During Rotation");
+    o->longDesc = N_("Opacity of desktop window during rotation.");
+    o->type = CompOptionTypeFloat;
+    o->value.f = CUBE_ACTIVE_OPACITY_DEFAULT;
+    o->rest.f.min = CUBE_OPACITY_MIN;
+    o->rest.f.max = CUBE_OPACITY_MAX;
+    o->rest.f.precision = CUBE_OPACITY_PRECISION;
+
+
+    o = &cs->opt[CUBE_SCREEN_OPTION_INACTIVE_OPACITY];
+    o->name = "inactive_opacity";
+    o->shortDesc = N_("Opacity When Not Rotating");
+    o->longDesc = N_("Opacity of desktop window when not rotating.");
+    o->type = CompOptionTypeFloat;
+    o->value.f = CUBE_INACTIVE_OPACITY_DEFAULT;
+    o->rest.f.min = CUBE_OPACITY_MIN;
+    o->rest.f.max = CUBE_OPACITY_MAX;
+    o->rest.f.precision = CUBE_OPACITY_PRECISION;
+
+    o = &cs->opt[CUBE_SCREEN_OPTION_TRANSPARENT_MANUAL_ONLY];
+    o->name = "transparent_manual_only";
+    o->shortDesc = N_("Transparency Only\non Mouse Rotate");
+    o->longDesc =
+	N_
+	("Initiates Cube transparency only if rotation is mouse driven.");
+    o->type = CompOptionTypeBool;
+    o->value.b = CUBE_TRANSPARENT_MANUAL_ONLY_DEFAULT;
 }
 
 static int
@@ -1172,6 +1288,39 @@ cubePreparePaintScreen (CompScreen *s,
 
     memset (cs->cleared, 0, sizeof (Bool) * s->nOutputDev);
 
+    //transparency, mostly copied/ported from beryl's cube.c, orig. by onestone
+    if (cs->rotationMode != NoRotation && ((cs->rotationMode == RotationManual) || 
+		!(cs->opt[CUBE_SCREEN_OPTION_TRANSPARENT_MANUAL_ONLY].value.b)))
+    {
+	cs->toOpacity = 
+	      (cs->opt[CUBE_SCREEN_OPTION_ACTIVE_OPACITY].value.f / 100.0f) * OPAQUE;
+    }
+    else
+	cs->toOpacity =
+	    (cs->opt[CUBE_SCREEN_OPTION_INACTIVE_OPACITY].value.f / 100.0f) * OPAQUE;
+
+    if (cs->opt[CUBE_SCREEN_OPTION_FADE_TIME].value.f == 0.0f)
+	cs->desktopOpacity = cs->toOpacity;
+
+    else if (cs->desktopOpacity != cs->toOpacity)
+    {
+	float steps = (msSinceLastPaint * OPAQUE / 1000.0) /
+	    cs->opt[CUBE_SCREEN_OPTION_FADE_TIME].value.f;
+	if (steps < 12)
+	    steps = 12;
+
+	if (cs->toOpacity > cs->desktopOpacity)
+	{
+	    cs->desktopOpacity += steps;
+	    cs->desktopOpacity = MIN(cs->toOpacity, cs->desktopOpacity);
+	}
+	if (cs->toOpacity < cs->desktopOpacity)
+	{
+	    cs->desktopOpacity -= steps;
+	    cs->desktopOpacity = MAX(cs->toOpacity, cs->desktopOpacity);
+	}
+    }
+
     UNWRAP (cs, s, preparePaintScreen);
     (*s->preparePaintScreen) (s, msSinceLastPaint);
     WRAP (cs, s, preparePaintScreen, cubePreparePaintScreen);
@@ -1190,7 +1339,7 @@ cubePaintScreen (CompScreen		 *s,
 
     CUBE_SCREEN (s);
 
-    if (cs->grabIndex)
+    if (cs->grabIndex || cs->desktopOpacity != OPAQUE)
     {
 	mask &= ~PAINT_SCREEN_REGION_MASK;
 	mask |= PAINT_SCREEN_TRANSFORMED_MASK;
@@ -1208,7 +1357,7 @@ cubeDonePaintScreen (CompScreen *s)
 {
     CUBE_SCREEN (s);
 
-    if (cs->grabIndex)
+    if (cs->grabIndex || cs->desktopOpacity != cs->toOpacity)
 	damageScreen (s);
 
     UNWRAP (cs, s, donePaintScreen);
@@ -1217,7 +1366,130 @@ cubeDonePaintScreen (CompScreen *s)
 }
 
 static void
-cubeMoveViewportAndPaint (CompScreen		  *s,
+cubePaintBackground(CompScreen * s, Region region, unsigned int mask)
+{
+    CUBE_SCREEN(s);
+
+    if (cs->desktopOpacity != OPAQUE)
+    {
+	if (s->desktopWindowCount)
+	{
+	    glColor4us(0, 0, 0, 0);
+	    glEnable(GL_BLEND);
+	}
+	else
+	{
+	    glColor4us(0xffff, 0xffff, 0xffff, cs->desktopOpacity);
+	    glEnable(GL_BLEND);
+	    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+	}
+    }
+
+    UNWRAP (cs, s, paintBackground);
+    (*s->paintBackground) (s, region, mask);
+    WRAP (cs, s, paintBackground, cubePaintBackground);
+
+    if (cs->desktopOpacity != OPAQUE)
+    {
+	if (s->desktopWindowCount)
+	{
+	    glColor3usv(defaultColor);
+	    glDisable(GL_BLEND);
+	}
+	else
+	{
+	    glColor3usv(defaultColor);
+	    glDisable(GL_BLEND);
+	    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+	    screenTexEnvMode(s, GL_REPLACE);
+	}
+    }
+}
+
+static Bool
+cubePaintWindow (CompWindow		  *w,
+		 const WindowPaintAttrib  *attrib,
+		 const CompTransform	  *transform,
+		 Region			  region,
+		 unsigned int		  mask)
+{
+    Bool status;
+    CompScreen* s = w->screen;
+    CUBE_SCREEN(s);
+    
+    WindowPaintAttrib wa = *attrib;
+
+    if (w->type & CompWindowTypeDesktopMask)
+    {
+	if (cs->desktopOpacity == 0)
+	    return TRUE;
+	wa.opacity = cs->desktopOpacity;
+    }
+
+
+    UNWRAP (cs, s, paintWindow);
+    status = (*s->paintWindow) (w, &wa, transform, region, mask);
+    WRAP (cs, s, paintWindow, cubePaintWindow);
+    
+    return status;
+}
+
+static Bool
+cubeCheckFTB (CompScreen *s, 
+              const ScreenPaintAttrib *sAttrib, 
+              const CompTransform  *transform,
+              int output)
+{
+    float mvp[16];
+    CompTransform sTransform = *transform;
+    
+    (*s->applyScreenTransform) (s, sAttrib, output, &sTransform);
+    transformToScreenSpace (s, output, -sAttrib->zTranslate, &sTransform);
+
+    MULTM(s->projection, sTransform.m, mvp);
+
+    float pntA[4] = { s->outputDev[output].region.extents.x1,
+                      s->outputDev[output].region.extents.y1,
+                      0, 1};
+
+    float pntB[4] = { s->outputDev[output].region.extents.x2,
+                      s->outputDev[output].region.extents.y1,
+                      0, 1};
+
+    float pntC[4] = { s->outputDev[output].region.extents.x1 + s->outputDev[output].width / 2.0f,
+                      s->outputDev[output].region.extents.y1 + s->outputDev[output].height / 2.0f,
+                      0, 1};
+
+    MULTMV(mvp, pntA);
+    DIVV(pntA);
+
+    MULTMV(mvp, pntB);
+    DIVV(pntB);
+
+    MULTMV(mvp, pntC);
+    DIVV(pntC);
+
+    float vecA[3] = { pntC[0] - pntA[0],
+                      pntC[1] - pntA[1],
+                      pntC[2] - pntA[2]};
+    
+    float vecB[3] = { pntC[0] - pntB[0], 
+                      pntC[1] - pntB[1],
+                      pntC[2] - pntB[2]};
+
+    float ortho[3] = { vecA[1] * vecB[2] - vecA[2] * vecB[1],
+	               vecA[2] * vecB[0] - vecA[0] * vecB[2],
+	               vecA[0] * vecB[1] - vecA[1] * vecB[0]};
+
+    if (ortho[2] > 0.0f)	//The viewport is reversed, should be painted front to back.
+	return TRUE;
+    
+    return FALSE;
+}
+
+static void
+cubeMoveViewportAndPaint (CompScreen		  *s, 
 			  const ScreenPaintAttrib *sAttrib,
 			  const CompTransform	  *transform,
 			  int			  output,
@@ -1226,6 +1498,13 @@ cubeMoveViewportAndPaint (CompScreen		  *s,
 {
     CUBE_SCREEN (s);
 
+    Bool ftb = cubeCheckFTB(s, sAttrib, transform, output);
+    
+    if (ftb && !(mask & PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK))
+	return;
+    if (!ftb && (mask & PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK))
+	return;
+    
     if (cs->nOutput > 1)
     {
 	int cubeOutput, dView;
@@ -1266,6 +1545,72 @@ cubeMoveViewportAndPaint (CompScreen		  *s,
 }
 
 static void
+cubePaintAllViewports (CompScreen              *s,
+                       ScreenPaintAttrib       *sa,
+	               const CompTransform     *transform,
+                       Region		       region,
+                       int                     output,
+                       unsigned int            mask,
+                       int                     xMove,
+                       int                     size, 
+                       int                     hsize)
+{
+    CUBE_SCREEN(s);
+
+    int i;
+	    
+    // xMove ==> dx for the viewport which is the nearest to the viewer in z axis.
+    // xMove +/- hsize / 2 ==> dx for the viewport which is the farest to the viewer in z axis.
+    
+    if ((sa->xRotate < 0.0f && hsize % 2 == 1) ||
+        (sa->xRotate > 0.0f && hsize % 2 == 0))
+    {
+	for (i = 0; i <= hsize / 2; i++)
+	{
+	    xMove += hsize / 2 + i;
+	    sa->yRotate -= cs->invert * (hsize / 2 + i) * 360.0f / size;
+	    cubeMoveViewportAndPaint (s, sa, transform, output, mask,
+				      xMove);
+	    sa->yRotate += cs->invert * (hsize / 2 + i) * 360.0f / size;
+	    xMove -= hsize / 2 + i;
+	
+	    if (i == 0 || i * 2 == hsize)	// same viewport.
+		continue;
+	
+	    xMove += hsize / 2 - i;
+	    sa->yRotate -= cs->invert * (hsize / 2 - i) * 360.0f / size;
+	    cubeMoveViewportAndPaint (s, sa, transform, output, mask,
+				      xMove);
+	    sa->yRotate += cs->invert * (hsize / 2 - i) * 360.0f / size;
+	    xMove -= hsize / 2 - i;
+	}
+    }
+    
+    else
+    {
+	for (i = 0; i <= hsize / 2; i++)
+	{
+	    xMove -= hsize / 2 + i;
+	    sa->yRotate -= cs->invert * (-hsize / 2 - i) * 360.0f / size;
+	    cubeMoveViewportAndPaint (s, sa, transform, output, mask,
+				      xMove);
+	    sa->yRotate += cs->invert * (-hsize / 2 - i) * 360.0f / size;
+	    xMove += hsize / 2 + i;
+	
+	    if (i == 0 || i * 2 == hsize)	// same viewport.
+		continue;
+	
+	    xMove -= hsize / 2 - i;
+	    sa->yRotate -= cs->invert * (-hsize / 2 + i) * 360.0f / size;
+	    cubeMoveViewportAndPaint (s, sa, transform, output, mask,
+				      xMove);
+	    sa->yRotate += cs->invert * (-hsize / 2 + i) * 360.0f / size;
+	    xMove += hsize / 2 - i;
+	}
+    }
+}
+
+static void
 cubePaintTransformedScreen (CompScreen		    *s,
 			    const ScreenPaintAttrib *sAttrib,
 			    const CompTransform	    *transform,
@@ -1277,12 +1622,21 @@ cubePaintTransformedScreen (CompScreen		    *s,
     int		      hsize, xMove = 0;
     float	      size;
     Bool	      clear;
+    Bool wasCulled = FALSE;
+    GLenum filter = s->display->textureFilter;
 
     CUBE_SCREEN (s);
 
     hsize = s->hsize * cs->nOutput;
     size  = hsize;
 
+    if (cs->desktopOpacity != OPAQUE)
+    {
+	wasCulled = glIsEnabled(GL_CULL_FACE);
+	if (wasCulled)
+	    glDisable(GL_CULL_FACE);
+    }
+
     if (!cs->fullscreenOutput)
     {
 	cs->outputXScale = (float) s->width / s->outputDev[output].width;
@@ -1358,22 +1712,6 @@ cubePaintTransformedScreen (CompScreen		    *s,
 	/* distance we move the camera back when unfolding the cube.
 	   currently hardcoded to 1.5 but it should probably be optional. */
 	sa.zCamera -= cs->unfold * 1.5f;
-
-	sa.xRotate = sAttrib->xRotate * cs->invert;
-	if (sa.xRotate > 0.0f)
-	{
-	    cs->xrotations = (int) (hsize * sa.xRotate) / 360;
-	    sa.xRotate = sa.xRotate - (360.0f * cs->xrotations) / hsize;
-	}
-	else
-	{
-	    cs->xrotations = (int) (hsize * sa.xRotate) / 360;
-	    sa.xRotate = sa.xRotate -
-		(360.0f * cs->xrotations) / hsize + 360.0f / hsize;
-	    cs->xrotations--;
-	}
-
-	sa.xRotate = sa.xRotate / size * hsize;
     }
     else
     {
@@ -1385,29 +1723,43 @@ cubePaintTransformedScreen (CompScreen		    *s,
 	    sa.vRotate = sAttrib->vRotate;
 
 	sa.zTranslate = -cs->invert * cs->distance;
-	sa.xRotate = sAttrib->xRotate * cs->invert;
-	if (sa.xRotate > 0.0f)
-	{
-	    cs->xrotations = (int) (size * sa.xRotate) / 360;
-	    sa.xRotate = sa.xRotate - (360.0f * cs->xrotations) / size;
-	}
-	else
-	{
-	    cs->xrotations = (int) (size * sa.xRotate) / 360;
-	    sa.xRotate = sa.xRotate -
-		(360.0f * cs->xrotations) / size + 360.0f / size;
-	    cs->xrotations--;
-	}
     }
-
-    if (!clear && cs->grabIndex == 0 && hsize > 2 &&
-	(cs->invert != 1 || sa.vRotate != 0.0f || sa.yTranslate != 0.0f))
+    
+    sa.xRotate = sAttrib->xRotate;
+	
+    if (sa.xRotate > 0.0f)
+	cs->xrotations = (int) (hsize * sa.xRotate + 180) / 360;
+    else
+	cs->xrotations = (int) (hsize * sa.xRotate - 180) / 360;
+    
+    sa.xRotate -= (360.0f * cs->xrotations) / size;
+    sa.xRotate *= cs->invert;
+    
+    xMove = cs->xrotations;
+    
+    if (cs->grabIndex && cs->opt[CUBE_SCREEN_OPTION_MIPMAP].value.b)
+	s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;
+    
+    if (cs->invert == 1)
+	mask |= PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK;	// Outside cube - start with FTB faces.
+	                                              	// Inside cube - start with BTF faces.
+    
+    if (cs->paintAllViewports || cs->desktopOpacity != OPAQUE || cs->invert == -1)
+	cubePaintAllViewports(s, &sa, transform, region, output, mask, xMove, size, hsize);
+    
+    if (cs->invert == 1)
+	mask &= ~PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK;	// Outside cube - continue with caps and then BTF faces.
+    else
+	mask |= PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK;	// Inside cube - continue with caps and then FTB faces.
+    
+    if (!clear && cs->grabIndex == 0 && hsize > 2 && !cs->disableCaps &&
+	(cs->invert != 1 || sa.vRotate != 0.0f || sa.yTranslate != 0.0f || cs->desktopOpacity != OPAQUE))
     {
 	CompTransform sTransform = *transform;
 
 	screenLighting (s, TRUE);
 
-	glColor3usv (cs->color);
+	glColor4us (cs->color[0], cs->color[1], cs->color[2], cs->desktopOpacity);
 
 	glPushMatrix ();
 
@@ -1427,29 +1779,45 @@ cubePaintTransformedScreen (CompScreen		    *s,
 	    glTranslatef (cs->outputXOffset, -cs->outputYOffset, 0.0f);
 	    glScalef (cs->outputXScale, cs->outputYScale, 1.0f);
 	}
-
-	glVertexPointer (3, GL_FLOAT, 0, cs->vertices);
-
-	glNormal3f (0.0f, -1.0f, 0.0f);
-
-	if (cs->invert == 1 && hsize == 4 && cs->texture.name)
+	
+	if (cs->desktopOpacity != OPAQUE)
 	{
-	    enableTexture (s, &cs->texture, COMP_TEXTURE_FILTER_GOOD);
-	    glTexCoordPointer (2, GL_FLOAT, 0, cs->tc);
-	    glDrawArrays (GL_TRIANGLE_FAN, 0, cs->nvertices >> 1);
-	    disableTexture (s, &cs->texture);
-	    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+	    glEnable(GL_BLEND);
+	    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 	}
-	else
+
+	glVertexPointer (3, GL_FLOAT, 0, cs->vertices);
+	
+	int i;
+	for (i = 0; i < 2; i++)
 	{
-	    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
-	    glDrawArrays (GL_TRIANGLE_FAN, 0, cs->nvertices >> 1);
-	}
+	    if ((i == 0 && sAttrib->vRotate < 0.0f) ||
+	        (i == 1 && sAttrib->vRotate > 0.0f))
+	    {
+		glNormal3f (0.0f, -1.0f, 0.0f);
 
-	glNormal3f (0.0f, 1.0f, 0.0f);
+		if (cs->invert == 1 && hsize == 4 && cs->texture.name)
+		{
+		    enableTexture (s, &cs->texture, COMP_TEXTURE_FILTER_GOOD);
+		    glTexCoordPointer (2, GL_FLOAT, 0, cs->tc);
+		    glDrawArrays (GL_TRIANGLE_FAN, 0, cs->nvertices >> 1);
+		    disableTexture (s, &cs->texture);
+		    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+		}
+		else
+		{
+		    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+		    glDrawArrays (GL_TRIANGLE_FAN, 0, cs->nvertices >> 1);
+		}
+	    }
+	    else
+	    {
+	        glNormal3f (0.0f, 1.0f, 0.0f);
 
-	glDrawArrays (GL_TRIANGLE_FAN, cs->nvertices >> 1,
-		      cs->nvertices >> 1);
+	        glDrawArrays (GL_TRIANGLE_FAN, cs->nvertices >> 1,
+		              cs->nvertices >> 1);
+	    }
+	}
 
 	glNormal3f (0.0f, 0.0f, -1.0f);
 
@@ -1457,130 +1825,155 @@ cubePaintTransformedScreen (CompScreen		    *s,
 
 	glColor4usv (defaultColor);
 	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+	
+	glDisable(GL_BLEND);
+	glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
     }
 
-    /* outside cube */
-    if (cs->invert == 1)
-    {
-	if (cs->grabIndex || hsize > 4)
-	{
-	    GLenum filter;
-	    int    i;
+    if ((cs->paintAllViewports || cs->desktopOpacity != OPAQUE) && cs->invert == 1)
+	cubePaintAllViewports(s, &sa, transform, region, output, mask, xMove, size, hsize);
 
-	    xMove = cs->xrotations - ((hsize >> 1) - 1);
-	    sa.yRotate += (360.0f / size) * ((hsize >> 1) - 1);
+    WRAP (cs, s, paintTransformedScreen, cubePaintTransformedScreen);
+    
+    if (cs->desktopOpacity != OPAQUE && wasCulled)
+	glEnable(GL_CULL_FACE);
+    
+    s->display->textureFilter = filter;
+}
 
-	    filter = s->display->textureFilter;
-	    if (cs->grabIndex && cs->opt[CUBE_SCREEN_OPTION_MIPMAP].value.b)
-		s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;
+static void cubeSetClipPlanes (CompScreen *s, Region region, int output)
+{
+    CUBE_SCREEN(s);
 
-	    for (i = 0; i < hsize; i++)
-	    {
-		cubeMoveViewportAndPaint (s, &sa, transform, output, mask,
-					  xMove);
+    glTranslatef(cs->outputXOffset, -cs->outputYOffset, 0.0f);
+    glScalef( cs->outputXScale, cs->outputYScale, 1.0f);
 
-		sa.yRotate -= 360.0f / size;
-		xMove++;
-	    }
+    UNWRAP(cs, s, setClipPlanes);
+    (*s->setClipPlanes) (s, region, output);
+    WRAP(cs, s, setClipPlanes, cubeSetClipPlanes);
 
-	    s->display->textureFilter = filter;
-	}
-	else
-	{
-	    if (sAttrib->xRotate != 0.0f)
-	    {
-		xMove = cs->xrotations;
+	
+    if (cs->invert == 1)
+    {
+	GLdouble clipPlane0[] = { 1.0, 0.0, 0.5 / cs->distance, 0.0 };
+	GLdouble clipPlane1[] = { -1.0,  0.0, 0.5 / cs->distance, 0.0 };
+	GLdouble clipPlane2[] = { 0.0,  -1.0, 0.5 / cs->distance, 0.0 };
+	GLdouble clipPlane3[] = { 0.0,  1.0, 0.5 / cs->distance, 0.0 };
+	glClipPlane (GL_CLIP_PLANE0, clipPlane0);
+	glClipPlane (GL_CLIP_PLANE1, clipPlane1);
+	glClipPlane (GL_CLIP_PLANE2, clipPlane2);
+	glClipPlane (GL_CLIP_PLANE3, clipPlane3);
+    }
+    else
+    {
+	GLdouble clipPlane0[] = { -1.0, 0.0, -0.5 / cs->distance, 0.0 };
+	GLdouble clipPlane1[] = { 1.0,  0.0, -0.5 / cs->distance, 0.0 };
+	GLdouble clipPlane2[] = { 0.0,  1.0, -0.5 / cs->distance, 0.0 };
+	GLdouble clipPlane3[] = { 0.0,  -1.0, -0.5 / cs->distance, 0.0 };
+	glClipPlane (GL_CLIP_PLANE0, clipPlane0);
+	glClipPlane (GL_CLIP_PLANE1, clipPlane1);
+	glClipPlane (GL_CLIP_PLANE2, clipPlane2);
+	glClipPlane (GL_CLIP_PLANE3, clipPlane3);
+    }
+}
 
-		cubeMoveViewportAndPaint (s, &sa, transform, output, mask,
-					  xMove);
+static void
+cubeApplyScreenTransform (CompScreen		  *s,
+			  const ScreenPaintAttrib *sAttrib,
+			  int			  output,
+			  CompTransform	          *transform)
+{
+    CUBE_SCREEN (s);
 
-		xMove++;
-	    }
+    matrixTranslate (transform, cs->outputXOffset, -cs->outputYOffset, 0.0f);
+    matrixScale (transform, cs->outputXScale, cs->outputYScale, 1.0f);
 
-	    sa.yRotate -= 360.0f / size;
+    UNWRAP (cs, s, applyScreenTransform);
+    (*s->applyScreenTransform) (s, sAttrib, output, transform);
+    WRAP (cs, s, applyScreenTransform, cubeApplyScreenTransform);
 
-	    cubeMoveViewportAndPaint (s, &sa, transform, output, mask, xMove);
-	}
-    }
-    else
-    {
-	if (sa.xRotate > 180.0f / size)
-	{
-	    sa.yRotate -= 360.0f / size;
-	    cs->xrotations++;
-	}
+    matrixScale (transform, 1.0f / cs->outputXScale,
+		 1.0f / cs->outputYScale, 1.0f);
+    matrixTranslate (transform, -cs->outputXOffset, cs->outputYOffset, 0.0f);
+}
 
-	sa.yRotate -= 360.0f / size;
-	xMove = -1 - cs->xrotations;
+static void cubeHandleCompizEvent(CompDisplay * d, char *pluginName,
+				 char *eventName, CompOption * option, int nOption)
+{
+    CUBE_DISPLAY(d);
 
-	if (cs->grabIndex)
+    UNWRAP (cd, d, handleCompizEvent);
+    (*d->handleCompizEvent) (d, pluginName, eventName, option, nOption);
+    WRAP (cd, d, handleCompizEvent, cubeHandleCompizEvent);
+	
+    if (strcmp(pluginName, "3d") == 0)
+    {
+	if (strcmp(eventName, "disableCapsEvent") == 0)
 	{
-	    GLenum filter;
-	    int    i;
-
-	    filter = s->display->textureFilter;
-	    if (cs->opt[CUBE_SCREEN_OPTION_MIPMAP].value.b)
-		s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;
+	    Window xid = getIntOptionNamed(option, nOption, "root", 0);
+	    CompScreen *s = findScreenAtDisplay(d, xid);
 
-	    if (sa.xRotate > 180.0f / size)
-	    {
-		xMove -= ((hsize >> 1) - 2);
-		sa.yRotate -= (360.0f / size) * ((hsize >> 1) - 2);
-	    }
-	    else
+	    if (s)
 	    {
-		xMove -= ((hsize >> 1) - 1);
-		sa.yRotate -= (360.0f / size) * ((hsize >> 1) - 1);
+		CUBE_SCREEN(s);
+		cs->disableCaps = getBoolOptionNamed(option, nOption, "disableCaps", FALSE);
 	    }
+	}
+	
+	else if (strcmp(eventName, "paintAllViewportsEvent") == 0)
+	{
+	    Window xid = getIntOptionNamed(option, nOption, "root", 0);
+	    CompScreen *s = findScreenAtDisplay(d, xid);
 
-	    for (i = 0; i < hsize; i++)
+	    if (s)
 	    {
-		cubeMoveViewportAndPaint (s, &sa, transform, output, mask,
-					  xMove);
-
-		sa.yRotate += 360.0f / size;
-		xMove++;
+		CUBE_SCREEN(s);
+		cs->paintAllViewports = getBoolOptionNamed(option, nOption, "paintAllViewports", FALSE);
 	    }
-
-	    s->display->textureFilter = filter;
 	}
-	else
+    }
+    if (strcmp(pluginName, "rotate") == 0)
+    {
+	if (strcmp(eventName, "rotateEvent") == 0)
 	{
-	    cubeMoveViewportAndPaint (s, &sa, transform, output, mask, xMove);
-
-	    sa.yRotate += 360.0f / size;
-	    xMove = -cs->xrotations;
-
-	    cubeMoveViewportAndPaint (s, &sa, transform, output, mask, xMove);
-
-	    sa.yRotate += 360.0f / size;
-	    xMove = 1 - cs->xrotations;
+	    Window xid = getIntOptionNamed(option, nOption, "root", 0);
+	    CompScreen *s = findScreenAtDisplay(d, xid);
 
-	    cubeMoveViewportAndPaint (s, &sa, transform, output, mask, xMove);
+	    if (s)
+	    {
+		CUBE_SCREEN(s);
+		Bool rotate = getBoolOptionNamed(option, nOption, "rotating", FALSE);
+		Bool manual = getBoolOptionNamed(option, nOption, "manual", FALSE);
+
+		if (rotate && manual)
+		    cs->rotationMode = RotationManual;
+		else if (rotate)
+		    cs->rotationMode = RotationChange;
+		else
+		    cs->rotationMode = NoRotation;
+		damageScreen(s);
+	    }
 	}
     }
-
-    WRAP (cs, s, paintTransformedScreen, cubePaintTransformedScreen);
 }
 
 static void
-cubeApplyScreenTransform (CompScreen		  *s,
-			  const ScreenPaintAttrib *sAttrib,
-			  int			  output,
-			  CompTransform	          *transform)
+cubeFoldEvent(CompScreen *s, Bool unfolded)
 {
-    CUBE_SCREEN (s);
+    CompOption o[2];
 
-    matrixTranslate (transform, cs->outputXOffset, -cs->outputYOffset, 0.0f);
-    matrixScale (transform, cs->outputXScale, cs->outputYScale, 1.0f);
+    o[0].type = CompOptionTypeInt;
+    o[0].name = "root";
+    o[0].value.i = s->root;
 
-    UNWRAP (cs, s, applyScreenTransform);
-    (*s->applyScreenTransform) (s, sAttrib, output, transform);
-    WRAP (cs, s, applyScreenTransform, cubeApplyScreenTransform);
+    o[1].type = CompOptionTypeBool;
+    o[1].name = "unfolded";
+    o[1].value.b = unfolded;
 
-    matrixScale (transform, 1.0f / cs->outputXScale,
-		 1.0f / cs->outputYScale, 1.0f);
-    matrixTranslate (transform, -cs->outputXOffset, cs->outputYOffset, 0.0f);
+    (*s->display->handleCompizEvent) (s->display, 
+				      "cube", 
+				      "unfoldEvent", 
+				      o, 2);
 }
 
 static Bool
@@ -1611,6 +2004,7 @@ cubeUnfold (CompDisplay     *d,
 
 	if (cs->grabIndex)
 	{
+	    cubeFoldEvent (s, TRUE);
 	    cs->unfolded = TRUE;
 	    damageScreen (s);
 	}
@@ -1646,6 +2040,7 @@ cubeFold (CompDisplay     *d,
 
 	if (cs->grabIndex)
 	{
+	    cubeFoldEvent (s, FALSE);
 	    cs->unfolded = FALSE;
 	    damageScreen (s);
 	}
@@ -1869,6 +2264,8 @@ cubeInitDisplay (CompPlugin  *p,
     cubeDisplayInitOptions (cd, d->display);
 
     d->privates[displayPrivateIndex].ptr = cd;
+    
+    WRAP (cd, d, handleCompizEvent, cubeHandleCompizEvent);
 
     return TRUE;
 }
@@ -1883,6 +2280,7 @@ cubeFiniDisplay (CompPlugin  *p,
 #endif
 
     CUBE_DISPLAY (d);
+    UNWRAP (cd, d, handleCompizEvent);
 
     freeScreenPrivateIndex (d, cd->screenPrivateIndex);
 
@@ -1941,6 +2339,12 @@ cubeInitScreen (CompPlugin *p,
     cs->unfoldVelocity = 0.0f;
 
     cs->fullscreenOutput = TRUE;
+    
+    cs->disableCaps = FALSE;
+    cs->paintAllViewports = FALSE;
+    cs->rotationMode = NoRotation;
+    
+    cs->desktopOpacity = (CUBE_INACTIVE_OPACITY_DEFAULT / 100.0f) * OPAQUE;
 
     memset (cs->cleared, 0, sizeof (cs->cleared));
 
@@ -1958,6 +2362,9 @@ cubeInitScreen (CompPlugin *p,
     WRAP (cs, s, applyScreenTransform, cubeApplyScreenTransform);
     WRAP (cs, s, setScreenOption, cubeSetGlobalScreenOption);
     WRAP (cs, s, outputChangeNotify, cubeOutputChangeNotify);
+    WRAP (cs, s, setClipPlanes, cubeSetClipPlanes);
+    WRAP (cs, s, paintBackground, cubePaintBackground);
+    WRAP (cs, s, paintWindow, cubePaintWindow);
 
     cubeUpdateOutputs (s);
 
@@ -1992,6 +2399,9 @@ cubeFiniScreen (CompPlugin *p,
     UNWRAP (cs, s, applyScreenTransform);
     UNWRAP (cs, s, setScreenOption);
     UNWRAP (cs, s, outputChangeNotify);
+    UNWRAP (cs, s, setClipPlanes);
+    UNWRAP (cs, s, paintBackground);
+    UNWRAP (cs, s, paintWindow);
 
     finiTexture (s, &cs->texture);
     finiTexture (s, &cs->sky);
@@ -2067,3 +2477,4 @@ getCompPluginInfo (void)
 {
     return &cubeVTable;
 }
+
diff --git a/plugins/rotate.c b/plugins/rotate.c
index c19030b..b74c40c 100644
--- a/plugins/rotate.c
+++ b/plugins/rotate.c
@@ -400,6 +400,30 @@ rotateReleaseMoveWindow (CompScreen *s)
     rs->moveWindow = None;
 }
 
+static void rotateEvent(CompScreen *s, 
+			Bool       rotating, 
+			Bool       manual)
+{
+    CompOption o[3];
+
+    o[0].type = CompOptionTypeInt;
+    o[0].name = "root";
+    o[0].value.i = s->root;
+
+    o[1].type = CompOptionTypeBool;
+    o[1].name = "rotating";
+    o[1].value.b = rotating;
+
+    o[2].type = CompOptionTypeBool;
+    o[2].name = "manual";
+    o[2].value.b = manual;
+
+    (*s->display->handleCompizEvent)(s->display, 
+				     "rotate", 
+				     "rotateEvent", 
+				     o, 3);
+}
+
 static void
 rotatePreparePaintScreen (CompScreen *s,
 			  int	     msSinceLastPaint)
@@ -485,6 +509,8 @@ rotatePreparePaintScreen (CompScreen *s,
 		    else
 			tx = (s->hsize * xrot / 360.0f) + 0.5f;
 
+		    rotateEvent (s, FALSE, FALSE);
+
 		    moveScreenViewport (s, tx, 0, TRUE);
 
 		    rs->xrot = 0.0f;
@@ -638,6 +664,10 @@ rotateInitiate (CompDisplay     *d,
 	rs->moving = FALSE;
 	rs->slow   = FALSE;
 
+	/* notify other plugins that rotation starts - if action is
+	   non-NULL, we are called from the 'Initiate rotate' binding */
+	rotateEvent (s, TRUE, (action != NULL));
+
 	if (!rs->grabIndex)
 	{
 	    rs->grabIndex = pushScreenGrab (s, s->invisibleCursor, "rotate");
diff --git a/src/paint.c b/src/paint.c
index a618328..9c0e252 100644
--- a/src/paint.c
+++ b/src/paint.c
@@ -157,7 +157,9 @@ paintScreenRegion (CompScreen	       *screen,
     static Region tmpRegion = NULL;
     CompWindow    *w;
     CompCursor	  *c;
-    int		  count, windowMask, backgroundMask;
+    int		  count, windowMask, backgroundMask, occlusionMask;
+    Bool ftb = (mask & PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK) && 
+	      !(mask & PAINT_SCREEN_ORDER_BACK_TO_FRONT_MASK);	// Do FTB drawing only if FTB flag is set and BTF flag isn't
 
     if (!tmpRegion)
     {
@@ -179,10 +181,29 @@ paintScreenRegion (CompScreen	       *screen,
 	count	       = 0;
     }
 
+    if (ftb)
+    {
+	windowMask |= PAINT_WINDOW_FRONT_TO_BACK_MASK;
+	occlusionMask = PAINT_WINDOW_OCCLUSION_DETECTION_MASK | 
+	               PAINT_WINDOW_FRONT_TO_BACK_MASK;
+    }
+    else
+    {
+	windowMask |= PAINT_WINDOW_BACK_TO_FRONT_MASK;
+	occlusionMask = PAINT_WINDOW_OCCLUSION_DETECTION_MASK | 
+	               PAINT_WINDOW_BACK_TO_FRONT_MASK;
+    }
+    
+
     XSubtractRegion (region, &emptyRegion, tmpRegion);
 
-    /* detect occlusions */
-    for (w = screen->reverseWindows; w; w = w->prev)
+    /* detect occlusions (order is reversed from true painting order). */
+    if (ftb)
+	w = screen->windows;
+    else
+	w = screen->reverseWindows;
+
+    for (; w; w = (ftb)? w->next: w->prev)
     {
 	if (w->destroyed)
 	    continue;
@@ -197,7 +218,7 @@ paintScreenRegion (CompScreen	       *screen,
 	XSubtractRegion (tmpRegion, &emptyRegion, w->clip);
 
 	if ((*screen->paintWindow) (w, &w->paint, transform, tmpRegion,
-				    PAINT_WINDOW_OCCLUSION_DETECTION_MASK))
+				   occlusionMask))
 	{
 	    /* unredirect top most fullscreen windows. */
 	    if (count == 0					      &&
@@ -216,8 +237,13 @@ paintScreenRegion (CompScreen	       *screen,
 
     (*screen->paintBackground) (screen, tmpRegion, backgroundMask);
 
-    /* paint all windows from bottom to top */
-    for (w = screen->windows; w; w = w->next)
+    /* paint all windows with the order specified by the masks. */
+    if (ftb)
+	w = screen->reverseWindows;
+    else
+	w = screen->windows;
+
+    for (; w; w = (ftb)? w->prev: w->next)
     {
 	if (w->destroyed)
 	    continue;
@@ -231,9 +257,22 @@ paintScreenRegion (CompScreen	       *screen,
 	(*screen->paintWindow) (w, &w->paint, transform, w->clip, windowMask);
     }
 
-    /* paint cursors */
-    for (c = screen->cursors; c; c = c->next)
-	(*screen->paintCursor) (c, transform, tmpRegion, 0);
+    if ((mask & PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK) &&
+	(mask & PAINT_SCREEN_ORDER_BACK_TO_FRONT_MASK))
+    {
+	/* when both modes are set, we first paint in Back-To-Front mode (already done), 
+           and after that we paint the screen in Front-To-Back mode, by removing the 
+           Back-To-Front mask. 
+           Painting the cursors will be done after the Front-To-Back drawing*/
+	paintScreenRegion (screen, transform, region, output, 
+	                   mask & (~PAINT_SCREEN_ORDER_BACK_TO_FRONT_MASK));	
+    }
+    else
+    {
+	/* paint cursors */
+	for (c = screen->cursors; c; c = c->next)
+	    (*screen->paintCursor) (c, transform, tmpRegion, 0);
+    }
 }
 
 
@@ -259,29 +298,10 @@ paintTransformedScreen (CompScreen		*screen,
 
     if ((mask & CLIP_PLANE_MASK) == CLIP_PLANE_MASK)
     {
-	GLdouble h = screen->height;
-
-	GLdouble p1[2] = { region->extents.x1, h - region->extents.y2 };
-	GLdouble p2[2] = { region->extents.x2, h - region->extents.y1 };
-
-	GLdouble halfW = screen->outputDev[output].width / 2.0;
-	GLdouble halfH = screen->outputDev[output].height / 2.0;
-
-	GLdouble cx = screen->outputDev[output].region.extents.x1 + halfW;
-	GLdouble cy = (h - screen->outputDev[output].region.extents.y2) + halfH;
-
-	GLdouble top[4]    = { 0.0, halfH / (cy - p1[1]), 0.0, 0.5 };
-	GLdouble bottom[4] = { 0.0, halfH / (cy - p2[1]), 0.0, 0.5 };
-	GLdouble left[4]   = { halfW / (cx - p1[0]), 0.0, 0.0, 0.5 };
-	GLdouble right[4]  = { halfW / (cx - p2[0]), 0.0, 0.0, 0.5 };
-
 	glPushMatrix ();
 	glLoadMatrixf (sTransform.m);
 
-	glClipPlane (GL_CLIP_PLANE0, top);
-	glClipPlane (GL_CLIP_PLANE1, bottom);
-	glClipPlane (GL_CLIP_PLANE2, left);
-	glClipPlane (GL_CLIP_PLANE3, right);
+	(*screen->setClipPlanes) (screen, region, output);
 
 	glEnable (GL_CLIP_PLANE0);
 	glEnable (GL_CLIP_PLANE1);
@@ -1154,3 +1174,27 @@ paintBackground (CompScreen   *s,
 
     free (data);
 }
+
+void setClipPlanes (CompScreen *screen, Region region, int output)
+{
+    GLdouble h = screen->height;
+
+    GLdouble p1[2] = { region->extents.x1, h - region->extents.y2 };
+    GLdouble p2[2] = { region->extents.x2, h - region->extents.y1 };
+
+    GLdouble halfW = screen->outputDev[output].width / 2.0;
+    GLdouble halfH = screen->outputDev[output].height / 2.0;
+
+    GLdouble cx = screen->outputDev[output].region.extents.x1 + halfW;
+    GLdouble cy = (h - screen->outputDev[output].region.extents.y2) + halfH;
+
+    GLdouble top[4]    = { 0.0, halfH / (cy - p1[1]), 0.0, 0.5 };
+    GLdouble bottom[4] = { 0.0, halfH / (cy - p2[1]), 0.0, 0.5 };
+    GLdouble left[4]   = { halfW / (cx - p1[0]), 0.0, 0.0, 0.5 };
+    GLdouble right[4]  = { halfW / (cx - p2[0]), 0.0, 0.0, 0.5 };
+
+    glClipPlane (GL_CLIP_PLANE0, top);
+    glClipPlane (GL_CLIP_PLANE1, bottom);
+    glClipPlane (GL_CLIP_PLANE2, left);
+    glClipPlane (GL_CLIP_PLANE3, right);
+}
diff --git a/src/screen.c b/src/screen.c
index 63d7189..482f0da 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -1688,6 +1688,7 @@ addScreen (CompDisplay *display,
     s->getOutputExtentsForWindow  = getOutputExtentsForWindow;
     s->getAllowedActionsForWindow = getAllowedActionsForWindow;
     s->focusWindow		  = focusWindow;
+    s->setClipPlanes		  = setClipPlanes;
 
     s->paintCursor      = paintCursor;
     s->damageCursorRect	= damageCursorRect;