diff --git a/gtk/window-decorator/gtk-window-decorator.c b/gtk/window-decorator/gtk-window-decorator.c
index d018a42..e19d770 100644
--- a/gtk/window-decorator/gtk-window-decorator.c
+++ b/gtk/window-decorator/gtk-window-decorator.c
@@ -236,6 +236,7 @@ int right_click_action  = RIGHT_CLICK_ACTION_DEFAULT;
 int wheel_action        = WHEEL_ACTION_DEFAULT;
 
 static gboolean minimal = FALSE;
+static gboolean reduced_resources = FALSE;
 
 static double decoration_alpha = 0.5;
 
@@ -304,8 +305,9 @@ static decor_shadow_t *switcher_shadow = NULL;
 static GdkPixmap *decor_normal_pixmap = NULL;
 static GdkPixmap *decor_active_pixmap = NULL;
 
-static Atom frame_window_atom;
 static Atom win_decor_atom;
+static Atom win_decor_active_atom;
+static Atom frame_window_atom;
 static Atom win_blur_decor_atom;
 static Atom wm_move_resize_atom;
 static Atom restack_window_atom;
@@ -371,6 +373,24 @@ static struct _pos {
     { 6, 2, 16, 16,   0, 0, 0, 0, 0, 0 }
 };
 
+static char *wm_action_name[3][3] = {
+    {
+	"_COMPIZ_WM_WINDOW_SIZE_TOPLEFT_DECOR",
+	"_COMPIZ_WM_WINDOW_SIZE_TOP_DECOR",
+	"_COMPIZ_WM_WINDOW_SIZE_TOPRIGHT_DECOR"
+    }, {
+	"_COMPIZ_WM_WINDOW_SIZE_LEFT_DECOR",
+	"_COMPIZ_WM_WINDOW_MOVE_DECOR",
+	"_COMPIZ_WM_WINDOW_SIZE_RIGHT_DECOR"
+    }, {
+	"_COMPIZ_WM_WINDOW_SIZE_BOTTOMLEFT_DECOR",
+	"_COMPIZ_WM_WINDOW_SIZE_BOTTOM_DECOR",
+	"_COMPIZ_WM_WINDOW_SIZE_BOTTOMRIGHT_DECOR"
+    }
+};
+static Atom wm_action_atom[3][3];
+static Atom wm_action_notify_atom[3][3];
+
 typedef struct _decor_color {
     double r;
     double g;
@@ -384,8 +404,9 @@ typedef struct _decor {
     Window	      event_windows[3][3];
     Window	      button_windows[BUTTON_NUM];
     guint	      button_states[BUTTON_NUM];
-    GdkPixmap	      *pixmap;
     GdkPixmap	      *buffer_pixmap;
+    GdkPixmap	      *pixmap;
+    GdkPixmap	      *active_pixmap;
     GdkGC	      *gc;
     decor_layout_t    border_layout;
     decor_context_t   *context;
@@ -477,32 +498,26 @@ static Window    switcher_selected_window = None;
 static XRenderPictFormat *xformat;
 
 static void
-decor_update_blur_property (decor_t *d,
-			    int     width,
-			    int     height,
-			    Region  top_region,
-			    int     top_offset,
-			    Region  bottom_region,
-			    int     bottom_offset,
-			    Region  left_region,
-			    int     left_offset,
-			    Region  right_region,
-			    int     right_offset)
+decor_update_box_property (decor_t *d,
+			   XID     xid,
+			   Atom    property,
+			   int     value0,
+			   int     value1,
+			   int     width,
+			   int     height,
+			   Region  top_region,
+			   int     top_offset,
+			   Region  bottom_region,
+			   int     bottom_offset,
+			   Region  left_region,
+			   int     left_offset,
+			   Region  right_region,
+			   int     right_offset)
 {
     Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
     long    *data = NULL;
     int     size = 0;
 
-    if (blur_type != BLUR_TYPE_ALL)
-    {
-	bottom_region = NULL;
-	left_region   = NULL;
-	right_region  = NULL;
-
-	if (blur_type != BLUR_TYPE_TITLEBAR)
-	    top_region = NULL;
-    }
-
     if (top_region)
 	size += top_region->numRects;
     if (bottom_region)
@@ -517,15 +532,18 @@ decor_update_blur_property (decor_t *d,
 
     if (data)
     {
-	decor_region_to_blur_property (data, 4, 0, width, height,
-				       top_region, top_offset,
-				       bottom_region, bottom_offset,
-				       left_region, left_offset,
-				       right_region, right_offset);
+	data[0] = value0;
+	data[1] = value1;
+
+	decor_region_to_box_property (data + 2, width, height,
+				      top_region, top_offset,
+				      bottom_region, bottom_offset,
+				      left_region, left_offset,
+				      right_region, right_offset);
 
 	gdk_error_trap_push ();
-	XChangeProperty (xdisplay, d->prop_xid,
-			 win_blur_decor_atom,
+	XChangeProperty (xdisplay, xid,
+			 property,
 			 XA_INTEGER,
 			 32, PropModeReplace, (guchar *) data,
 			 2 + size * 6);
@@ -537,13 +555,52 @@ decor_update_blur_property (decor_t *d,
     else
     {
 	gdk_error_trap_push ();
-	XDeleteProperty (xdisplay, d->prop_xid, win_blur_decor_atom);
+	XDeleteProperty (xdisplay, xid, property);
 	gdk_display_sync (gdk_display_get_default ());
 	gdk_error_trap_pop ();
     }
 }
 
 static void
+decor_update_blur_property (decor_t *d,
+			    int     width,
+			    int     height,
+			    Region  top_region,
+			    int     top_offset,
+			    Region  bottom_region,
+			    int     bottom_offset,
+			    Region  left_region,
+			    int     left_offset,
+			    Region  right_region,
+			    int     right_offset)
+{
+    if (blur_type != BLUR_TYPE_ALL)
+    {
+	bottom_region = NULL;
+	left_region   = NULL;
+	right_region  = NULL;
+
+	if (blur_type != BLUR_TYPE_TITLEBAR)
+	    top_region = NULL;
+    }
+
+    decor_update_box_property (d,
+			       d->prop_xid,
+			       win_blur_decor_atom,
+			       4, 0,
+			       width,
+			       height,
+			       top_region,
+			       top_offset,
+			       bottom_region,
+			       bottom_offset,
+			       left_region,
+			       left_offset,
+			       right_region,
+			       right_offset);
+}
+
+static void
 decor_update_window_property (decor_t *d)
 {
     long	    data[256];
@@ -572,6 +629,24 @@ decor_update_window_property (decor_t *d)
 
     extents.top += titlebar_height;
 
+    if (d->active_pixmap)
+    {
+	decor_quads_to_property (data, GDK_PIXMAP_XID (d->active_pixmap),
+				 &extents, &extents,
+				 ICON_SPACE + d->button_width,
+				 0,
+				 quads, nQuad);
+
+	gdk_error_trap_push ();
+	XChangeProperty (xdisplay, d->prop_xid,
+			 win_decor_active_atom,
+			 win_decor_atom,
+			 32, PropModeReplace, (guchar *) data,
+			 BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
+	gdk_display_sync (gdk_display_get_default ());
+	gdk_error_trap_pop ();
+    }
+
     decor_quads_to_property (data, GDK_PIXMAP_XID (d->pixmap),
 			     &extents, &extents,
 			     ICON_SPACE + d->button_width,
@@ -581,7 +656,7 @@ decor_update_window_property (decor_t *d)
     gdk_error_trap_push ();
     XChangeProperty (xdisplay, d->prop_xid,
 		     win_decor_atom,
-		     XA_INTEGER,
+		     win_decor_atom,
 		     32, PropModeReplace, (guchar *) data,
 		     BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
     gdk_display_sync (gdk_display_get_default ());
@@ -650,7 +725,7 @@ decor_update_switcher_property (decor_t *d)
     gdk_error_trap_push ();
     XChangeProperty (xdisplay, d->prop_xid,
 		     win_decor_atom,
-		     XA_INTEGER,
+		     win_decor_atom,
 		     32, PropModeReplace, (guchar *) data,
 		     BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
     gdk_display_sync (gdk_display_get_default ());
@@ -976,7 +1051,9 @@ button_state_paint (cairo_t	  *cr,
 }
 
 static void
-draw_window_decoration (decor_t *d)
+draw_window_decoration_to_pixmap (decor_t   *d,
+				  GdkPixmap *pixmap,
+				  gint      active)
 {
     cairo_t       *cr;
     GtkStyle	  *style;
@@ -987,7 +1064,7 @@ draw_window_decoration (decor_t *d)
     int		  top;
     int		  button_x;
 
-    if (!d->pixmap)
+    if (!pixmap)
 	return;
 
     style = gtk_widget_get_style (style_window);
@@ -1003,7 +1080,7 @@ draw_window_decoration (decor_t *d)
     if (d->buffer_pixmap)
 	cr = gdk_cairo_create (GDK_DRAWABLE (d->buffer_pixmap));
     else
-	cr = gdk_cairo_create (GDK_DRAWABLE (d->pixmap));
+	cr = gdk_cairo_create (GDK_DRAWABLE (pixmap));
 
     cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
@@ -1020,7 +1097,7 @@ draw_window_decoration (decor_t *d)
 
     draw_shadow_background (d, cr, d->shadow, d->context);
 
-    if (d->active)
+    if (active)
     {
 	decor_color_t *title_color = _title_color;
 
@@ -1145,7 +1222,7 @@ draw_window_decoration (decor_t *d)
 
     cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
 
-    if (d->active)
+    if (active)
     {
 	gdk_cairo_set_source_color_alpha (cr,
 					  &style->fg[GTK_STATE_NORMAL],
@@ -1219,7 +1296,7 @@ draw_window_decoration (decor_t *d)
 
 	button_x -= 17;
 
-	if (d->active)
+	if (active)
 	{
 	    cairo_move_to (cr, x, y);
 	    draw_close_button (d, cr, 3.0);
@@ -1247,7 +1324,7 @@ draw_window_decoration (decor_t *d)
 
 	cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
 
-	if (d->active)
+	if (active)
 	{
 	    gdk_cairo_set_source_color_alpha (cr,
 					      &style->fg[GTK_STATE_NORMAL],
@@ -1288,7 +1365,7 @@ draw_window_decoration (decor_t *d)
 
 	button_x -= 17;
 
-	if (d->active)
+	if (active)
 	{
 	    gdk_cairo_set_source_color_alpha (cr,
 					      &style->fg[GTK_STATE_NORMAL],
@@ -1311,7 +1388,7 @@ draw_window_decoration (decor_t *d)
 
     if (d->layout)
     {
-	if (d->active)
+	if (active)
 	{
 	    cairo_move_to (cr,
 			   d->context->left_space + 21.0,
@@ -1348,7 +1425,7 @@ draw_window_decoration (decor_t *d)
 	cairo_rectangle (cr, 0.0, 0.0, 16.0, 16.0);
 	cairo_clip (cr);
 
-	if (d->active)
+	if (active)
 	    cairo_paint (cr);
 	else
 	    cairo_paint_with_alpha (cr, alpha);
@@ -1357,7 +1434,7 @@ draw_window_decoration (decor_t *d)
     cairo_destroy (cr);
 
     if (d->buffer_pixmap)
-	gdk_draw_drawable  (d->pixmap,
+	gdk_draw_drawable  (pixmap,
 			    d->gc,
 			    d->buffer_pixmap,
 			    0,
@@ -1366,6 +1443,20 @@ draw_window_decoration (decor_t *d)
 			    0,
 			    d->width,
 			    d->height);
+}
+
+static void
+draw_window_decoration (decor_t *d)
+{
+    if (d->active_pixmap)
+    {
+	draw_window_decoration_to_pixmap (d, d->pixmap, FALSE);
+	draw_window_decoration_to_pixmap (d, d->active_pixmap, TRUE);
+    }
+    else
+    {
+	draw_window_decoration_to_pixmap (d, d->pixmap, d->active);
+    }		
 
     if (d->prop_xid)
     {
@@ -1430,6 +1521,24 @@ decor_update_meta_window_property (decor_t	  *d,
     extents.top += titlebar_height;
     max_extents.top += max_titlebar_height;
 
+    if (d->active_pixmap)
+    {
+	decor_quads_to_property (data, GDK_PIXMAP_XID (d->active_pixmap),
+				 &extents, &max_extents,
+				 ICON_SPACE + d->button_width,
+				 0,
+				 quads, nQuad);
+
+	gdk_error_trap_push ();
+	XChangeProperty (xdisplay, d->prop_xid,
+			 win_decor_active_atom,
+			 win_decor_atom,
+			 32, PropModeReplace, (guchar *) data,
+			 BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
+	gdk_display_sync (gdk_display_get_default ());
+	gdk_error_trap_pop ();
+    }
+
     decor_quads_to_property (data, GDK_PIXMAP_XID (d->pixmap),
 			     &extents, &max_extents,
 			     ICON_SPACE + d->button_width,
@@ -1439,7 +1548,7 @@ decor_update_meta_window_property (decor_t	  *d,
     gdk_error_trap_push ();
     XChangeProperty (xdisplay, d->prop_xid,
 		     win_decor_atom,
-		     XA_INTEGER,
+		     win_decor_atom,
 		     32, PropModeReplace, (guchar *) data,
 		     BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
     gdk_display_sync (gdk_display_get_default ());
@@ -1823,9 +1932,6 @@ meta_get_decoration_geometry (decor_t		*d,
     if (d->actions & WNCK_WINDOW_ACTION_SHADE)
 	*flags |= META_FRAME_ALLOWS_SHADE;
 
-    if (d->active)
-	*flags |= META_FRAME_HAS_FOCUS;
-
 #define META_MAXIMIZED (WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY | \
 			WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY)
 
@@ -1880,17 +1986,25 @@ meta_get_decoration_geometry (decor_t		*d,
 }
 
 static void
-meta_draw_window_decoration (decor_t *d)
+meta_draw_window_decoration_to_pixmap (decor_t        *d,
+				       GdkPixmap      *pixmap,
+				       MetaTheme      *theme,
+				       gint           active,
+				       gint           bg,
+				       Region         *top_region_return,
+				       Region         *bottom_region_return,
+				       Region         *left_region_return,
+				       Region         *right_region_return,
+				       MetaFrameFlags *flags_return)
 {
     Display	      *xdisplay =
 	GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
-    GdkPixmap	      *pixmap;
+    GdkPixmap         *pix;
     Picture	      src;
     MetaButtonState   button_states[META_BUTTON_TYPE_LAST];
     MetaButtonLayout  button_layout;
     MetaFrameGeometry fgeom;
     MetaFrameFlags    flags;
-    MetaTheme	      *theme;
     GtkStyle	      *style;
     cairo_t	      *cr;
     gint	      size, i;
@@ -1900,14 +2014,14 @@ meta_draw_window_decoration (decor_t *d)
     Region	      bottom_region = NULL;
     Region	      left_region = NULL;
     Region	      right_region = NULL;
-    double	      alpha = (d->active) ? meta_active_opacity : meta_opacity;
-    gboolean	      shade_alpha = (d->active) ? meta_active_shade_opacity :
+    double	      alpha = (active) ? meta_active_opacity : meta_opacity;
+    gboolean	      shade_alpha = (active) ? meta_active_shade_opacity :
 	meta_shade_opacity;
     MetaFrameStyle    *frame_style;
     GdkColor	      bg_color;
     double	      bg_alpha;
 
-    if (!d->pixmap || !d->picture)
+    if (!pixmap || !d->picture)
 	return;
 
     if (decoration_alpha == 1.0)
@@ -1915,20 +2029,19 @@ meta_draw_window_decoration (decor_t *d)
 
     style = gtk_widget_get_style (style_window);
 
-    drawable = d->buffer_pixmap ? d->buffer_pixmap : d->pixmap;
+    drawable = d->buffer_pixmap ? d->buffer_pixmap : pixmap;
 
     cr = gdk_cairo_create (GDK_DRAWABLE (drawable));
 
     cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
-    theme = meta_theme_get_current ();
-
     meta_get_decoration_geometry (d, theme, &flags, &fgeom, &button_layout,
 				  &clip);
 
-    /* we only have to redraw the shadow background when decoration
-       changed size */
-    if (d->prop_xid || !d->buffer_pixmap)
+    if (active)
+	flags |= META_FRAME_HAS_FOCUS;
+
+    if (bg)
 	draw_shadow_background (d, cr, d->shadow, d->context);
 
     for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
@@ -1962,14 +2075,14 @@ meta_draw_window_decoration (decor_t *d)
 
     if (rect.width && size)
     {
-	pixmap = create_pixmap (rect.width, size);
+	pix = create_pixmap (rect.width, size);
 
-	cr = gdk_cairo_create (GDK_DRAWABLE (pixmap));
+	cr = gdk_cairo_create (GDK_DRAWABLE (pix));
 	gdk_cairo_set_source_color_alpha (cr, &bg_color, bg_alpha);
 	cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
 	src = XRenderCreatePicture (xdisplay,
-				    GDK_PIXMAP_XID (pixmap),
+				    GDK_PIXMAP_XID (pix),
 				    xformat, 0, NULL);
 
 	if (fgeom.top_height)
@@ -1980,7 +2093,7 @@ meta_draw_window_decoration (decor_t *d)
 
 	    meta_theme_draw_frame (theme,
 				   style_window,
-				   pixmap,
+				   pix,
 				   &rect,
 				   0, 0,
 				   META_FRAME_TYPE_NORMAL,
@@ -2019,7 +2132,7 @@ meta_draw_window_decoration (decor_t *d)
 
 	    meta_theme_draw_frame (theme,
 				   style_window,
-				   pixmap,
+				   pix,
 				   &rect,
 				   0,
 				   -(clip.height - fgeom.bottom_height),
@@ -2053,7 +2166,7 @@ meta_draw_window_decoration (decor_t *d)
 
 	cairo_destroy (cr);
 
-	g_object_unref (G_OBJECT (pixmap));
+	g_object_unref (G_OBJECT (pix));
 
 	XRenderFreePicture (xdisplay, src);
     }
@@ -2064,14 +2177,14 @@ meta_draw_window_decoration (decor_t *d)
 
     if (size && rect.height)
     {
-	pixmap = create_pixmap (size, rect.height);
+	pix = create_pixmap (size, rect.height);
 
-	cr = gdk_cairo_create (GDK_DRAWABLE (pixmap));
+	cr = gdk_cairo_create (GDK_DRAWABLE (pix));
 	gdk_cairo_set_source_color_alpha (cr, &bg_color, bg_alpha);
 	cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
 	src = XRenderCreatePicture (xdisplay,
-				    GDK_PIXMAP_XID (pixmap),
+				    GDK_PIXMAP_XID (pix),
 				    xformat, 0, NULL);
 
 	if (fgeom.left_width)
@@ -2082,7 +2195,7 @@ meta_draw_window_decoration (decor_t *d)
 
 	    meta_theme_draw_frame (theme,
 				   style_window,
-				   pixmap,
+				   pix,
 				   &rect,
 				   0,
 				   -fgeom.top_height,
@@ -2122,7 +2235,7 @@ meta_draw_window_decoration (decor_t *d)
 
 	    meta_theme_draw_frame (theme,
 				   style_window,
-				   pixmap,
+				   pix,
 				   &rect,
 				   -(clip.width - fgeom.right_width),
 				   -fgeom.top_height,
@@ -2156,13 +2269,13 @@ meta_draw_window_decoration (decor_t *d)
 
 	cairo_destroy (cr);
 
-	g_object_unref (G_OBJECT (pixmap));
+	g_object_unref (G_OBJECT (pix));
 
 	XRenderFreePicture (xdisplay, src);
     }
 
     if (d->buffer_pixmap)
-	gdk_draw_drawable  (d->pixmap,
+	gdk_draw_drawable  (pixmap,
 			    d->gc,
 			    d->buffer_pixmap,
 			    0,
@@ -2172,16 +2285,119 @@ meta_draw_window_decoration (decor_t *d)
 			    d->width,
 			    d->height);
 
-    if (d->prop_xid)
+    /* translate from frame to client window space */
+    if (top_region_return)
     {
-	/* translate from frame to client window space */
 	if (top_region)
 	    XOffsetRegion (top_region, -fgeom.left_width, -fgeom.top_height);
+
+	*top_region_return = top_region;
+    }
+    else if (top_region)
+    {
+	XDestroyRegion (top_region);
+    }
+
+    if (bottom_region_return)
+    {
 	if (bottom_region)
 	    XOffsetRegion (bottom_region, -fgeom.left_width, 0);
+
+	*bottom_region_return = bottom_region;
+    }
+    else if (bottom_region)
+    {
+	XDestroyRegion (bottom_region);
+    }
+
+    if (left_region_return)
+    {
 	if (left_region)
 	    XOffsetRegion (left_region, -fgeom.left_width, 0);
 
+	*left_region_return = left_region;
+    }
+    else if (left_region)
+    {
+	XDestroyRegion (left_region);
+    }
+
+    if (right_region_return)
+    {
+        *right_region_return = right_region;
+    }
+    else if (right_region)
+    {
+	XDestroyRegion (right_region);
+    }
+
+    *flags_return = flags;
+}
+
+static void
+meta_draw_window_decoration (decor_t *d)
+{
+    MetaTheme      *theme = meta_theme_get_current ();
+    MetaFrameFlags flags;
+    Region         top_region = NULL;
+    Region         bottom_region = NULL;
+    Region         left_region = NULL;
+    Region         right_region = NULL;
+    Region         *top_region_ptr = NULL;
+    Region         *bottom_region_ptr = NULL;
+    Region         *left_region_ptr = NULL;
+    Region         *right_region_ptr = NULL;
+    gint           bg = FALSE;
+
+    if (d->prop_xid)
+    {
+	bg = TRUE;
+
+	top_region_ptr    = &top_region;
+	bottom_region_ptr = &bottom_region;
+	left_region_ptr   = &left_region;
+	right_region_ptr  = &right_region;
+    }
+    else if (!d->buffer_pixmap)
+    {
+	bg = TRUE;
+    }
+
+    if (d->active_pixmap)
+    {
+	meta_draw_window_decoration_to_pixmap (d,
+					       d->pixmap,
+					       theme,
+					       FALSE,
+					       bg,
+					       NULL, NULL, NULL, NULL, &flags);
+	meta_draw_window_decoration_to_pixmap (d,
+					       d->active_pixmap,
+					       theme,
+					       TRUE,
+					       FALSE,
+					       top_region_ptr,
+					       bottom_region_ptr,
+					       left_region_ptr,
+					       right_region_ptr,
+					       &flags);
+    }
+    else
+    {
+	meta_draw_window_decoration_to_pixmap (d,
+					       d->pixmap,
+					       theme,
+					       d->active,
+					       bg,
+					       top_region_ptr,
+					       bottom_region_ptr,
+					       left_region_ptr,
+					       right_region_ptr,
+					       &flags);
+    }
+
+    if (d->prop_xid)
+    {
 	decor_update_meta_window_property (d, theme, flags,
 					   top_region,
 					   bottom_region,
@@ -2564,7 +2780,7 @@ update_default_decorations (GdkScreen *screen)
 
 	XChangeProperty (xdisplay, xroot,
 			 bareAtom,
-			 XA_INTEGER,
+			 win_decor_atom,
 			 32, PropModeReplace, (guchar *) data,
 			 BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
 
@@ -2572,12 +2788,12 @@ update_default_decorations (GdkScreen *screen)
 	{
 	    XChangeProperty (xdisplay, xroot,
 			     normalAtom,
-			     XA_INTEGER,
+			     win_decor_atom,
 			     32, PropModeReplace, (guchar *) data,
 			     BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
 	    XChangeProperty (xdisplay, xroot,
 			     activeAtom,
-			     XA_INTEGER,
+			     win_decor_atom,
 			     32, PropModeReplace, (guchar *) data,
 			     BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
 	}
@@ -2635,7 +2851,7 @@ update_default_decorations (GdkScreen *screen)
 
 	XChangeProperty (xdisplay, xroot,
 			 normalAtom,
-			 XA_INTEGER,
+			 win_decor_atom,
 			 32, PropModeReplace, (guchar *) data,
 			 BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
     }
@@ -2661,7 +2877,7 @@ update_default_decorations (GdkScreen *screen)
 
 	XChangeProperty (xdisplay, xroot,
 			 activeAtom,
-			 XA_INTEGER,
+			 win_decor_atom,
 			 32, PropModeReplace, (guchar *) data,
 			 BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
     }
@@ -3081,13 +3297,21 @@ update_event_windows (WnckWindow *win)
 {
     Display *xdisplay;
     decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
-    gint    x0, y0, width, height, x, y, w, h;
+    Region  move_xregion;
+    REGION  xregion;
+    gint    x0, y0, x1, y1, width, height, x, y, w, h;
     gint    i, j, k, l;
     gint    actions = d->actions;
 
     xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 
-    wnck_window_get_client_window_geometry (win, &x0, &y0, &width, &height);
+    wnck_window_get_geometry (win, &x0, &y0, &width, &height);
+    wnck_window_get_client_window_geometry (win, &x1, &y1, &width, &height);
+
+    move_xregion = XCreateRegion ();
+
+    xregion.rects = &xregion.extents;
+    xregion.numRects = xregion.size = 1;
 
     if (d->state & WNCK_WINDOW_STATE_SHADED)
     {
@@ -3134,6 +3358,16 @@ update_event_windows (WnckWindow *win)
 		XMapWindow (xdisplay, d->event_windows[i][j]);
 		XMoveResizeWindow (xdisplay, d->event_windows[i][j],
 				   x, y, w, h);
+
+		xregion.extents.x1 = x;
+		xregion.extents.y1 = y;
+		xregion.extents.x2 = x + w;
+		xregion.extents.y2 = y + h;
+
+		if (i == 1 && j == 1)
+		    XUnionRegion (move_xregion, &xregion, move_xregion);
+		else
+		    XSubtractRegion (move_xregion, &xregion, move_xregion);
 	    }
 	    else
 	    {
@@ -3181,6 +3415,13 @@ update_event_windows (WnckWindow *win)
 	{
 	    XMapWindow (xdisplay, d->button_windows[i]);
 	    XMoveResizeWindow (xdisplay, d->button_windows[i], x, y, w, h);
+
+	    xregion.extents.x1 = x;
+	    xregion.extents.y1 = y;
+	    xregion.extents.x2 = x + w;
+	    xregion.extents.y2 = y + h;
+
+	    XSubtractRegion (move_xregion, &xregion, move_xregion);
 	}
 	else
 	{
@@ -3188,6 +3429,28 @@ update_event_windows (WnckWindow *win)
 	}
     }
 
+    XOffsetRegion (move_xregion, x0 - x1, y0 - y1);
+
+    xregion.extents.x1 = 0;
+    xregion.extents.y1 = 0;
+    xregion.extents.x2 = width;
+    xregion.extents.y2 = height;
+
+    XSubtractRegion (move_xregion, &xregion, move_xregion);
+
+    decor_update_box_property (d,
+			       wnck_window_get_xid (win),
+			       wm_action_atom[1][1],
+			       0,
+			       1,
+			       width, height,
+			       move_xregion, width / 2,
+			       NULL, 0,
+			       NULL, 0,
+			       NULL, 0);
+
+    XDestroyRegion (move_xregion);
+
     gdk_display_sync (gdk_display_get_default ());
     gdk_error_trap_pop ();
 }
@@ -3488,7 +3751,7 @@ static gboolean
 update_window_decoration_size (WnckWindow *win)
 {
     decor_t   *d = g_object_get_data (G_OBJECT (win), "decor");
-    GdkPixmap *pixmap, *buffer_pixmap = NULL;
+    GdkPixmap *pixmap, *active_pixmap = NULL, *buffer_pixmap = NULL;
     Picture   picture;
     gint      width, height;
     gint      w, h, name_width;
@@ -3510,10 +3773,21 @@ update_window_decoration_size (WnckWindow *win)
     if (!pixmap)
 	return FALSE;
 
+    if (!reduced_resources)
+    {
+	active_pixmap = create_pixmap (width, height);
+	if (!active_pixmap)
+	{
+	    g_object_unref (G_OBJECT (pixmap));
+	    return FALSE;
+	}
+    }
+
     buffer_pixmap = create_pixmap (width, height);
     if (!buffer_pixmap)
     {
 	g_object_unref (G_OBJECT (pixmap));
+	g_object_unref (G_OBJECT (active_pixmap));
 	return FALSE;
     }
 
@@ -3523,6 +3797,9 @@ update_window_decoration_size (WnckWindow *win)
     if (d->pixmap)
 	g_object_unref (G_OBJECT (d->pixmap));
 
+    if (d->active_pixmap)
+	g_object_unref (G_OBJECT (d->active_pixmap));
+
     if (d->buffer_pixmap)
 	g_object_unref (G_OBJECT (d->buffer_pixmap));
 
@@ -3532,7 +3809,8 @@ update_window_decoration_size (WnckWindow *win)
     if (d->picture)
 	XRenderFreePicture (xdisplay, d->picture);
 
-    d->pixmap	     = pixmap;
+    d->pixmap        = pixmap;
+    d->active_pixmap = active_pixmap;
     d->buffer_pixmap = buffer_pixmap;
     d->gc	     = gdk_gc_new (pixmap);
 
@@ -3792,6 +4070,7 @@ update_switcher_window (WnckWindow *win,
     g_object_ref (G_OBJECT (buffer_pixmap));
 
     d->pixmap	     = pixmap;
+    d->active_pixmap = NULL;
     d->buffer_pixmap = buffer_pixmap;
     d->gc	     = gdk_gc_new (pixmap);
 
@@ -3822,6 +4101,12 @@ remove_frame_window (WnckWindow *win)
 	d->pixmap = NULL;
     }
 
+    if (d->active_pixmap)
+    {
+	g_object_unref (G_OBJECT (d->active_pixmap));
+	d->active_pixmap = NULL;
+    }
+
     if (d->buffer_pixmap)
     {
 	g_object_unref (G_OBJECT (d->buffer_pixmap));
@@ -3999,10 +4284,11 @@ active_window_changed (WnckScreen *screen)
     if (win)
     {
 	d = g_object_get_data (G_OBJECT (win), "decor");
-	if (d && d->pixmap)
+	if (d)
 	{
 	    d->active = wnck_window_is_active (win);
-	    queue_decor_draw (d);
+	    if (d->pixmap && !d->active_pixmap)
+		queue_decor_draw (d);
 	}
     }
 
@@ -4010,10 +4296,11 @@ active_window_changed (WnckScreen *screen)
     if (win)
     {
 	d = g_object_get_data (G_OBJECT (win), "decor");
-	if (d && d->pixmap)
+	if (d)
 	{
 	    d->active = wnck_window_is_active (win);
-	    queue_decor_draw (d);
+	    if (d->pixmap && !d->active_pixmap)
+		queue_decor_draw (d);
 	}
     }
 }
@@ -4746,7 +5033,8 @@ unstick_button_event (WnckWindow *win,
 static void
 handle_title_button_event (WnckWindow   *win,
 			   int          action,
-			   XButtonEvent *event)
+			   int          button,
+			   Time         time)
 {
     switch (action) {
     case CLICK_ACTION_SHADE:
@@ -4772,7 +5060,7 @@ handle_title_button_event (WnckWindow   *win,
 	restack_window (win, Below);
 	break;
     case CLICK_ACTION_MENU:
-	action_menu_map (win, event->button, event->time);
+	action_menu_map (win, button, time);
 	break;
     }
 }
@@ -4812,16 +5100,16 @@ dist (double x1, double y1,
     return sqrt (square (x1 - x2) + square (y1 - y2));
 }
 
+static int    last_button_num = 0;
+static Window last_button_xwindow = None;
+static Time   last_button_time = 0;
+static int    last_button_x = 0;
+static int    last_button_y = 0;
+
 static void
 title_event (WnckWindow *win,
 	     XEvent     *xevent)
 {
-    static int	  last_button_num = 0;
-    static Window last_button_xwindow = None;
-    static Time	  last_button_time = 0;
-    static int	  last_button_x = 0;
-    static int	  last_button_y = 0;
-
     if (xevent->type != ButtonPress)
 	return;
 
@@ -4834,7 +5122,8 @@ title_event (WnckWindow *win,
 		  last_button_x, last_button_y) < DOUBLE_CLICK_DISTANCE)
 	{
 	    handle_title_button_event (win, double_click_action,
-				       &xevent->xbutton);
+				       xevent->xbutton.button,
+				       xevent->xbutton.time);
 
 	    last_button_num	= 0;
 	    last_button_xwindow = None;
@@ -4858,12 +5147,14 @@ title_event (WnckWindow *win,
     else if (xevent->xbutton.button == 2)
     {
 	handle_title_button_event (win, middle_click_action,
-				   &xevent->xbutton);
+				   xevent->xbutton.button,
+				   xevent->xbutton.time);
     }
     else if (xevent->xbutton.button == 3)
     {
 	handle_title_button_event (win, right_click_action,
-				   &xevent->xbutton);
+				   xevent->xbutton.button,
+				   xevent->xbutton.time);
     }
     else if (xevent->xbutton.button == 4 ||
 	     xevent->xbutton.button == 5)
@@ -4887,11 +5178,13 @@ frame_common_event (WnckWindow *win,
 	break;
     case 2:
 	handle_title_button_event (win, middle_click_action,
-				   &xevent->xbutton);
+				   xevent->xbutton.button,
+				   xevent->xbutton.time);
 	break;
     case 3:
 	handle_title_button_event (win, right_click_action,
-				   &xevent->xbutton);
+				   xevent->xbutton.button,
+				   xevent->xbutton.time);
 	break;
     }
 }
@@ -5301,6 +5594,48 @@ event_filter_func (GdkXEvent *gdkxevent,
 		}
 	    }
 	}
+	else if (xevent->xclient.message_type == wm_action_notify_atom[1][1])
+	{
+	    WnckWindow *win;
+	    gulong     id = (gulong)
+		g_hash_table_lookup (frame_table,
+				     GINT_TO_POINTER (xevent->xclient.window));
+
+	    win = wnck_window_get (id);
+	    if (win)
+	    {
+		if (xevent->xclient.window    == last_button_xwindow &&
+		    xevent->xclient.data.l[0] == last_button_num     &&
+		    xevent->xclient.data.l[3] <
+		    last_button_time + double_click_timeout          &&
+		    dist (xevent->xclient.data.l[1],
+			  xevent->xclient.data.l[2],
+			  last_button_x,
+			  last_button_y) < DOUBLE_CLICK_DISTANCE)
+		{
+		    handle_title_button_event (win,
+					       double_click_action,
+					       xevent->xclient.data.l[0],
+					       xevent->xclient.data.l[3]);
+
+		    last_button_num	= 0;
+		    last_button_xwindow = None;
+		    last_button_time    = 0;
+		    last_button_x	= 0;
+		    last_button_y	= 0;
+		}
+		else
+		{
+		    last_button_num	= xevent->xclient.data.l[0];
+		    last_button_xwindow = xevent->xclient.window;
+		    last_button_time    = xevent->xclient.data.l[3];
+		    last_button_x	= xevent->xclient.data.l[1];
+		    last_button_y	= xevent->xclient.data.l[2];
+
+		    restack_window (win, Above);
+		}
+	    }
+	}
     default:
 	break;
     }
@@ -6909,6 +7244,10 @@ main (int argc, char *argv[])
 	{
 	    replace = TRUE;
 	}
+	else if (strcmp (argv[i], "--reduced-resources") == 0)
+	{
+	    reduced_resources = TRUE;
+	}
 	else if (strcmp (argv[i], "--blur") == 0)
 	{
 	    if (argc > ++i)
@@ -6957,6 +7296,7 @@ main (int argc, char *argv[])
 	    fprintf (stderr, "%s "
 		     "[--minimal] "
 		     "[--replace] "
+		     "[--reduced-resources] "
 		     "[--blur none|titlebar|all] "
 
 #ifdef USE_METACITY
@@ -6999,8 +7339,12 @@ main (int argc, char *argv[])
     xdisplay   = gdk_x11_display_get_xdisplay (gdkdisplay);
     gdkscreen  = gdk_display_get_default_screen (gdkdisplay);
 
+    win_decor_atom	  = XInternAtom (xdisplay, DECOR_WINDOW_ATOM_NAME,
+					 FALSE);
+    win_decor_active_atom = XInternAtom (xdisplay, DECOR_ACTIVE_ATOM_NAME,
+					 FALSE);
+
     frame_window_atom	= XInternAtom (xdisplay, "_NET_FRAME_WINDOW", FALSE);
-    win_decor_atom	= XInternAtom (xdisplay, DECOR_WINDOW_ATOM_NAME, FALSE);
     win_blur_decor_atom	= XInternAtom (xdisplay, DECOR_BLUR_ATOM_NAME, FALSE);
     wm_move_resize_atom = XInternAtom (xdisplay, "_NET_WM_MOVERESIZE", FALSE);
     restack_window_atom = XInternAtom (xdisplay, "_NET_RESTACK_WINDOW", FALSE);
@@ -7027,6 +7371,23 @@ main (int argc, char *argv[])
     panel_action_run_dialog_atom =
 	XInternAtom (xdisplay, "_GNOME_PANEL_ACTION_RUN_DIALOG", FALSE);
 
+    for (i = 0; i < 3; i++)
+	for (j = 0; j < 3; j++)
+	    wm_action_atom[i][j] = XInternAtom (xdisplay,
+						wm_action_name[i][j],
+						FALSE);
+
+    for (i = 0; i < 3; i++)
+    {
+	char name[256];
+
+	for (j = 0; j < 3; j++)
+	{
+	    sprintf (name, "%s_NOTIFY", wm_action_name[i][j]);
+	    wm_action_notify_atom[i][j] = XInternAtom (xdisplay, name, FALSE);
+	}
+    }
+
     status = decor_acquire_dm_session (xdisplay,
 				       gdk_screen_get_number (gdkscreen),
 				       "gwd", replace, &dm_sn_timestamp);
diff --git a/include/compiz-core.h b/include/compiz-core.h
index 38257e6..e649d19 100644
--- a/include/compiz-core.h
+++ b/include/compiz-core.h
@@ -1,3 +1,4 @@
+
 /*
  * Copyright © 2007 Novell, Inc.
  *
@@ -48,6 +49,9 @@
 #include <GL/gl.h>
 #include <GL/glx.h>
 
+#undef CORE_ABIVERSION
+#define CORE_ABIVERSION 20081121
+
 COMPIZ_BEGIN_DECLS
 
 #if COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR > 2
@@ -80,6 +84,8 @@ typedef struct _CompCursor	  CompCursor;
 typedef struct _CompMatch	  CompMatch;
 typedef struct _CompOutput        CompOutput;
 typedef struct _CompWalker        CompWalker;
+typedef struct _CompPainter       CompPainter;
+typedef struct _CompTransform     CompTransform;
 
 /* virtual modifiers */
 
@@ -219,6 +225,8 @@ extern Bool       useCow;
 extern Bool       noDetection;
 extern Bool	  useDesktopHints;
 extern Bool       onlyCurrentScreen;
+extern Bool       windowManagement;
+extern Bool       manualCompositeManagement;
 
 extern int  defaultRefreshRate;
 extern char *defaultTextureFilter;
@@ -736,6 +744,664 @@ void
 removeFileWatch (CompFileWatchHandle handle);
 
 
+/* window.c */
+
+typedef struct _CompMatrix {
+    float xx; float yx;
+    float xy; float yy;
+    float x0; float y0;
+} CompMatrix;
+
+typedef struct _CompGroup {
+    struct _CompGroup *next;
+    unsigned int      refCnt;
+    Window	      id;
+} CompGroup;
+
+/* XXX: scale and translate fields will be removed */
+typedef struct _WindowPaintAttrib {
+    GLushort opacity;
+    GLushort brightness;
+    GLushort saturation;
+    GLfloat  xScale;
+    GLfloat  yScale;
+    GLfloat  xTranslate;
+    GLfloat  yTranslate;
+} WindowPaintAttrib;
+
+typedef void (*DrawWindowGeometryProc) (CompWindow *window);
+
+typedef Bool (*PaintWindowProc) (CompWindow		 *window,
+				 const WindowPaintAttrib *attrib,
+				 const CompTransform     *transform,
+				 Region			 region,
+				 unsigned int		 mask);
+
+#define WINDOW_INVISIBLE(w)				       \
+    ((w)->attrib.map_state != IsViewable		    || \
+     (!(w)->damaged)					    || \
+     (w)->attrib.x + (w)->width  + (w)->output.right  <= 0  || \
+     (w)->attrib.y + (w)->height + (w)->output.bottom <= 0  || \
+     (w)->attrib.x - (w)->output.left >= (w)->screen->width || \
+     (w)->attrib.y - (w)->output.top >= (w)->screen->height)
+
+typedef enum {
+    CompStackingUpdateModeNone = 0,
+    CompStackingUpdateModeNormal,
+    CompStackingUpdateModeAboveFullscreen,
+    CompStackingUpdateModeInitialMap,
+    CompStackingUpdateModeInitialMapDeniedFocus
+} CompStackingUpdateMode;
+
+struct _CompWindowExtents {
+    int left;
+    int right;
+    int top;
+    int bottom;
+};
+
+typedef struct _CompStruts {
+    XRectangle left;
+    XRectangle right;
+    XRectangle top;
+    XRectangle bottom;
+} CompStruts;
+
+struct _CompWindow {
+    CompObject base;
+
+    CompScreen *screen;
+
+    CompWindow *parent;
+    CompWindow *next;
+    CompWindow *prev;
+
+    CompWindow *windows;
+    CompWindow *reverseWindows;
+
+    Bool substructureRedirect;
+    Bool redirectSubwindows;
+
+    int viewportOffsetX;
+    int viewportOffsetY;
+
+    int		      refcnt;
+    Window	      id;
+    Window	      frame;
+    unsigned int      mapNum;
+    unsigned int      activeNum;
+    XWindowAttributes attrib;
+    int		      serverX;
+    int		      serverY;
+    int		      serverWidth;
+    int		      serverHeight;
+    int		      serverBorderWidth;
+    Window	      transientFor;
+    Window	      clientLeader;
+    XSizeHints	      sizeHints;
+    Pixmap	      pixmap;
+    CompTexture       *texture;
+    CompMatrix        matrix;
+    Damage	      damage;
+    Bool	      inputHint;
+    Bool	      alpha;
+    GLint	      width;
+    GLint	      height;
+    Region	      region;
+    Region	      clip;
+    unsigned int      wmType;
+    unsigned int      type;
+    unsigned int      state;
+    unsigned int      actions;
+    unsigned int      protocols;
+    unsigned int      mwmDecor;
+    unsigned int      mwmFunc;
+    Bool	      invisible;
+    Bool	      destroyed;
+    Bool	      damaged;
+    Bool	      redirected;
+    Bool	      managed;
+    Bool	      bindFailed;
+    Bool	      overlayWindow;
+    int		      destroyRefCnt;
+    int		      unmapRefCnt;
+
+    unsigned int initialViewportX;
+    unsigned int initialViewportY;
+
+    Time initialTimestamp;
+    Bool initialTimestampSet;
+
+    Bool placed;
+    Bool minimized;
+    Bool inShowDesktopMode;
+    Bool shaded;
+    Bool hidden;
+    Bool grabbed;
+
+    unsigned int desktop;
+
+    int pendingUnmaps;
+    int pendingMaps;
+
+    char *startupId;
+    char *resName;
+    char *resClass;
+
+    CompGroup *group;
+
+    unsigned int lastPong;
+    Bool	 alive;
+
+    WindowPaintAttrib paint;
+    WindowPaintAttrib lastPaint;
+
+    unsigned int lastMask;
+
+    CompWindowExtents input;
+    CompWindowExtents output;
+
+    CompStruts *struts;
+
+    CompIcon **icon;
+    int	     nIcon;
+
+    XRectangle iconGeometry;
+    Bool       iconGeometrySet;
+
+    XWindowChanges saveWc;
+    int		   saveMask;
+
+    XSyncCounter  syncCounter;
+    XSyncValue	  syncValue;
+    XSyncAlarm	  syncAlarm;
+    unsigned long syncAlarmConnection;
+    unsigned int  syncWaitHandle;
+
+    Bool syncWait;
+    int	 syncX;
+    int	 syncY;
+    int	 syncWidth;
+    int	 syncHeight;
+    int	 syncBorderWidth;
+
+    Bool   syncStateSupport;
+    Window supportingWmCheckWindow;
+    Window activeChild;
+    Window previousActiveChild;
+
+    Bool closeRequests;
+    Time lastCloseRequestTime;
+
+    XRectangle *damageRects;
+    int	       sizeDamage;
+    int	       nDamage;
+
+    int desktopWindowCount;
+
+    GLfloat  *vertices;
+    int      vertexSize;
+    int      vertexStride;
+    GLushort *indices;
+    int      indexSize;
+    int      vCount;
+    int      texUnits;
+    int      texCoordSize;
+    int      indexCount;
+
+    /* must be set by addWindowGeometry */
+    DrawWindowGeometryProc drawWindowGeometry;
+
+    PaintWindowProc paintWindowStack;
+};
+
+#define GET_CORE_WINDOW(object) ((CompWindow *) (object))
+#define CORE_WINDOW(object) CompWindow *w = GET_CORE_WINDOW (object)
+
+CompBool
+allocWindowObjectPrivates (CompObject *object,
+			   CompObject *parent);
+
+int
+allocWindowObjectPrivateIndex (CompObject *parent);
+
+void
+freeWindowObjectPrivateIndex (CompObject *parent,
+			      int	 index);
+
+CompBool
+forEachWindowObject (CompObject	        *parent,
+		     ObjectCallBackProc proc,
+		     void	        *closure);
+
+char *
+nameWindowObject (CompObject *object);
+
+CompObject *
+findWindowObject (CompObject *parent,
+		  const char *name);
+
+int
+allocateWindowPrivateIndex (CompScreen *screen);
+
+void
+freeWindowPrivateIndex (CompScreen *screen,
+			int	   index);
+
+unsigned int
+windowStateMask (CompDisplay *display,
+		 Atom	     state);
+
+unsigned int
+windowStateFromString (const char *str);
+
+unsigned int
+getWindowState (CompDisplay *display,
+		Window      id);
+
+void
+setWindowState (CompDisplay  *display,
+		unsigned int state,
+		Window       id);
+
+void
+changeWindowState (CompWindow   *w,
+		   unsigned int newState);
+
+void
+recalcWindowActions (CompWindow *w);
+
+unsigned int
+constrainWindowState (unsigned int state,
+		      unsigned int actions);
+
+unsigned int
+windowTypeFromString (const char *str);
+
+unsigned int
+getWindowType (CompDisplay *display,
+	       Window      id);
+
+void
+recalcWindowType (CompWindow *w);
+
+void
+getMwmHints (CompDisplay  *display,
+	     Window	  id,
+	     unsigned int *func,
+	     unsigned int *decor);
+
+unsigned int
+getProtocols (CompDisplay *display,
+	      Window      id);
+
+unsigned int
+getWindowProp (CompDisplay  *display,
+	       Window	    id,
+	       Atom	    property,
+	       unsigned int defaultValue);
+
+void
+setWindowProp (CompDisplay  *display,
+	       Window       id,
+	       Atom	    property,
+	       unsigned int value);
+
+Bool
+readWindowProp32 (CompDisplay    *display,
+		  Window	 id,
+		  Atom		 property,
+		  unsigned short *returnValue);
+
+unsigned short
+getWindowProp32 (CompDisplay	*display,
+		 Window		id,
+		 Atom		property,
+		 unsigned short defaultValue);
+
+void
+setWindowProp32 (CompDisplay    *display,
+		 Window         id,
+		 Atom		property,
+		 unsigned short value);
+
+void
+updateNormalHints (CompWindow *window);
+
+void
+updateWmHints (CompWindow *w);
+
+void
+updateWindowClassHints (CompWindow *window);
+
+void
+updateTransientHint (CompWindow *w);
+
+void
+updateIconGeometry (CompWindow *w);
+
+Window
+getClientLeader (CompWindow *w);
+
+Window
+getFrameWindow (CompWindow *w);
+
+char *
+getStartupId (CompWindow *w);
+
+int
+getWmState (CompDisplay *display,
+	    Window      id);
+
+void
+setWmState (CompDisplay *display,
+	    int		state,
+	    Window      id);
+
+void
+setWindowFrameExtents (CompWindow	 *w,
+		       CompWindowExtents *input);
+
+void
+updateWindowOutputExtents (CompWindow *w);
+
+void
+updateWindowRegion (CompWindow *w);
+
+Bool
+updateWindowStruts (CompWindow *w);
+
+void
+initRootWindow (CompScreen *s,
+		CompWindow *root);
+
+void
+addWindow (CompWindow *parent,
+	   Window     id,
+	   Window     aboveId);
+
+void
+removeWindow (CompWindow *w);
+
+void
+destroyWindow (CompWindow *w);
+
+void
+sendConfigureNotify (CompWindow *w);
+
+void
+mapWindow (CompWindow *w);
+
+void
+unmapWindow (CompWindow *w);
+
+Bool
+bindWindow (CompWindow *w);
+
+void
+releaseWindow (CompWindow *w);
+
+void
+moveWindow (CompWindow *w,
+	    int        dx,
+	    int        dy,
+	    Bool       damage,
+	    Bool       immediate);
+
+void
+configureXWindow (CompWindow	 *w,
+		  unsigned int	 valueMask,
+		  XWindowChanges *xwc);
+
+unsigned int
+adjustConfigureRequestForGravity (CompWindow     *w,
+				  XWindowChanges *xwc,
+				  unsigned int   xwcm,
+				  int            gravity,
+				  int		 direction);
+
+void
+moveResizeWindow (CompWindow     *w,
+		  XWindowChanges *xwc,
+		  unsigned int   xwcm,
+		  int            gravity,
+		  unsigned int   source);
+
+void
+syncWindowPosition (CompWindow *w);
+
+void
+syncWait (CompWindow *w);
+
+void
+sendSyncRequest (CompWindow *w);
+
+Bool
+resizeWindow (CompWindow *w,
+	      int	 x,
+	      int	 y,
+	      int	 width,
+	      int	 height,
+	      int	 borderWidth);
+
+void
+configureWindow (CompWindow	 *w,
+		 XConfigureEvent *ce);
+
+void
+circulateWindow (CompWindow	 *w,
+		 XCirculateEvent *ce);
+
+void
+addWindowDamageRect (CompWindow *w,
+		     BoxPtr     rect);
+
+void
+getOutputExtentsForWindow (CompWindow	     *w,
+			   CompWindowExtents *output);
+
+void
+getAllowedActionsForWindow (CompWindow   *w,
+			    unsigned int *setActions,
+			    unsigned int *clearActions);
+
+void
+addWindowDamage (CompWindow *w);
+
+void
+damageWindowOutputExtents (CompWindow *w);
+
+Bool
+damageWindowRect (CompWindow *w,
+		  Bool       initial,
+		  BoxPtr     rect);
+
+void
+damageTransformedWindowRect (CompWindow *w,
+			     float	xScale,
+			     float	yScale,
+			     float	xTranslate,
+			     float	yTranslate,
+			     BoxPtr     rect);
+
+Bool
+focusWindow (CompWindow *w);
+
+Bool
+placeWindow (CompWindow *w,
+	     int        x,
+	     int        y,
+	     int        *newX,
+	     int        *newY);
+
+void
+validateWindowResizeRequest (CompWindow     *w,
+			     unsigned int   *mask,
+			     XWindowChanges *xwc,
+			     unsigned int   source);
+
+void
+windowResizeNotify (CompWindow *w,
+		    int	       dx,
+		    int	       dy,
+		    int	       dwidth,
+		    int	       dheight);
+
+void
+windowMoveNotify (CompWindow *w,
+		  int	     dx,
+		  int	     dy,
+		  Bool	     immediate);
+
+void
+windowGrabNotify (CompWindow   *w,
+		  int	       x,
+		  int	       y,
+		  unsigned int state,
+		  unsigned int mask);
+
+void
+windowUngrabNotify (CompWindow *w);
+
+void
+windowStateChangeNotify (CompWindow   *w,
+			 unsigned int lastState);
+
+void
+moveInputFocusToWindow (CompWindow *w);
+
+void
+updateWindowSize (CompWindow *w);
+
+void
+raiseWindow (CompWindow *w);
+
+void
+lowerWindow (CompWindow *w);
+
+void
+restackWindowAbove (CompWindow *w,
+		    CompWindow *sibling);
+
+void
+restackWindowBelow (CompWindow *w,
+		    CompWindow *sibling);
+
+void
+updateWindowAttributes (CompWindow             *w,
+			CompStackingUpdateMode stackingMode);
+
+void
+activateWindow (CompWindow *w);
+
+void
+closeWindow (CompWindow *w,
+	     Time	serverTime);
+
+Bool
+constrainNewWindowSize (CompWindow *w,
+			int        width,
+			int        height,
+			int        *newWidth,
+			int        *newHeight);
+
+void
+hideWindow (CompWindow *w);
+
+void
+showWindow (CompWindow *w);
+
+void
+minimizeWindow (CompWindow *w);
+
+void
+unminimizeWindow (CompWindow *w);
+
+void
+maximizeWindow (CompWindow *w,
+		int	   state);
+
+Bool
+getWindowUserTime (CompWindow *w,
+		   Time       *time);
+
+void
+setWindowUserTime (CompWindow *w,
+		   Time       time);
+
+Bool
+allowWindowFocus (CompWindow   *w,
+		  unsigned int noFocusMask,
+		  unsigned int viewportX,
+		  unsigned int viewportY,
+		  Time         timestamp);
+
+void
+unredirectWindow (CompWindow *w);
+
+void
+redirectWindow (CompWindow *w);
+
+void
+defaultViewportForWindow (CompWindow *w,
+			  int	     *vx,
+			  int        *vy);
+
+CompIcon *
+getWindowIcon (CompWindow *w,
+	       int	  width,
+	       int	  height);
+
+void
+freeWindowIcons (CompWindow *w);
+
+int
+outputDeviceForWindow (CompWindow *w);
+
+Bool
+onCurrentDesktop (CompWindow *w);
+
+void
+setDesktopForWindow (CompWindow   *w,
+		     unsigned int desktop);
+
+int
+compareWindowActiveness (CompWindow *w1,
+			 CompWindow *w2);
+
+Bool
+windowOnAllViewports (CompWindow *w);
+
+void
+getWindowMovementForOffset (CompWindow *w,
+			    int        offX,
+			    int        offY,
+			    int        *retX,
+			    int        *retY);
+
+void
+enterSyncWaitState (CompWindow *w);
+
+void
+leaveSyncWaitState (CompWindow *w);
+
+void
+insertWindow (CompWindow *parent,
+	      CompWindow *w,
+	      Window	 aboveId);
+
+void
+unhookWindow (CompWindow *parent,
+	      CompWindow *w);
+
+CompWindow *
+findSibling (CompWindow *w,
+	     Window     id);
+
+CompWindow *
+walkDepthFirst (CompWindow *w);
+
+
 /* display.c */
 
 #define COMP_DISPLAY_OPTION_ABI                              0
@@ -1053,6 +1719,8 @@ struct _CompDisplay {
 
     Atom startupIdAtom;
 
+    Atom syncStateAtom;
+
     unsigned int      lastPing;
     CompTimeoutHandle pingHandle;
 
@@ -1163,6 +1831,12 @@ addDisplay (const char *name);
 void
 removeDisplay (CompDisplay *d);
 
+Bool
+manageDisplay (CompDisplay *d);
+
+void
+updatePlugins (CompDisplay *d);
+
 Time
 getCurrentTimeFromDisplay (CompDisplay *d);
 
@@ -1180,6 +1854,10 @@ findWindowAtDisplay (CompDisplay *display,
 		     Window      id);
 
 CompWindow *
+findClientWindowAtDisplay (CompDisplay *d,
+			   Window      id);
+
+CompWindow *
 findTopLevelWindowAtDisplay (CompDisplay *d,
 			     Window      id);
 
@@ -1190,6 +1868,9 @@ virtualToRealModMask (CompDisplay  *d,
 void
 updateModifierMappings (CompDisplay *d);
 
+void
+handleTimeouts (struct timeval *tv);
+
 unsigned int
 keycodeToModifiers (CompDisplay *d,
 		    int         keycode);
@@ -1305,9 +1986,9 @@ clearTargetOutput (CompDisplay	*display,
 
 #define DEG2RAD (M_PI / 180.0f)
 
-typedef struct _CompTransform {
+struct _CompTransform {
     float m[16];
-} CompTransform;
+};
 
 typedef union _CompVector {
     float v[4];
@@ -1330,26 +2011,9 @@ typedef struct _ScreenPaintAttrib {
     GLfloat zCamera;
 } ScreenPaintAttrib;
 
-/* XXX: scale and translate fields will be removed */
-typedef struct _WindowPaintAttrib {
-    GLushort opacity;
-    GLushort brightness;
-    GLushort saturation;
-    GLfloat  xScale;
-    GLfloat  yScale;
-    GLfloat  xTranslate;
-    GLfloat  yTranslate;
-} WindowPaintAttrib;
-
 extern ScreenPaintAttrib defaultScreenPaintAttrib;
 extern WindowPaintAttrib defaultWindowPaintAttrib;
 
-typedef struct _CompMatrix {
-    float xx; float yx;
-    float xy; float yy;
-    float x0; float y0;
-} CompMatrix;
-
 #define COMP_TEX_COORD_X(m, vx) ((m)->xx * (vx) + (m)->x0)
 #define COMP_TEX_COORD_Y(m, vy) ((m)->yy * (vy) + (m)->y0)
 
@@ -1407,7 +2071,7 @@ typedef void (*DisableOutputClippingProc) (CompScreen *screen);
 typedef void (*WalkerFiniProc) (CompScreen *screen,
 				CompWalker *walker);
 
-typedef CompWindow *(*WalkInitProc) (CompScreen *screen);
+typedef CompWindow *(*WalkInitProc) (CompWindow *parent);
 typedef CompWindow *(*WalkStepProc) (CompWindow *window);
 
 struct _CompWalker {
@@ -1420,6 +2084,16 @@ struct _CompWalker {
     WalkStepProc prev;
 };
 
+typedef void (*PainterFiniProc) (CompScreen  *screen,
+				 CompPainter *painter);
+
+struct _CompPainter {
+    PainterFiniProc fini;
+    CompPrivate	    priv;
+
+    PaintWindowProc paintObject;
+};
+
 /*
   window paint flags
 
@@ -1450,6 +2124,12 @@ struct _CompWalker {
 #define PAINT_WINDOW_WITH_OFFSET_MASK           (1 << 2)
 
 /*
+  this flag is present when occlusion detection has been
+  performed and the window clip region is properly set.
+*/
+#define PAINT_WINDOW_CLIP_MASK                  (1 << 3)
+
+/*
   flag indicate that window is translucent.
 */
 #define PAINT_WINDOW_TRANSLUCENT_MASK           (1 << 16)
@@ -1470,12 +2150,11 @@ struct _CompWalker {
 */
 #define PAINT_WINDOW_BLEND_MASK			(1 << 19)
 
+/*
+  flag indicate that there might be transformed child windows.
+*/
+#define PAINT_WINDOW_WITH_TRANSFORMED_CHILD_MASK (1 << 20)
 
-typedef Bool (*PaintWindowProc) (CompWindow		 *window,
-				 const WindowPaintAttrib *attrib,
-				 const CompTransform     *transform,
-				 Region			 region,
-				 unsigned int		 mask);
 
 typedef Bool (*DrawWindowProc) (CompWindow	     *window,
 				const CompTransform  *transform,
@@ -1494,8 +2173,6 @@ typedef void (*DrawWindowTextureProc) (CompWindow	    *w,
 				       const FragmentAttrib *fragment,
 				       unsigned int	    mask);
 
-typedef void (*DrawWindowGeometryProc) (CompWindow *window);
-
 typedef void (*PaintCursorProc) (CompCursor	     *cursor,
 				 const CompTransform *transform,
 				 Region		     region,
@@ -1594,6 +2271,11 @@ paintWindow (CompWindow		     *w,
 	     unsigned int	     mask);
 
 void
+drawTransformedWindowWithChildren (CompWindow              *w,
+				   const WindowPaintAttrib *attrib,
+				   const CompTransform     *transform);
+
+void
 paintCursor (CompCursor		 *cursor,
 	     const CompTransform *transform,
 	     Region		 region,
@@ -1901,8 +2583,12 @@ typedef void (*WindowStateChangeNotifyProc) (CompWindow   *window,
 typedef void (*OutputChangeNotifyProc) (CompScreen *screen);
 
 typedef void (*InitWindowWalkerProc) (CompScreen *screen,
+				      CompWindow *parent,
 				      CompWalker *walker);
 
+typedef void (*InitObjectPainterProc) (CompScreen  *screen,
+				       CompPainter *painter);
+
 #define COMP_SCREEN_DAMAGE_PENDING_MASK (1 << 0)
 #define COMP_SCREEN_DAMAGE_REGION_MASK  (1 << 1)
 #define COMP_SCREEN_DAMAGE_ALL_MASK     (1 << 2)
@@ -1925,12 +2611,6 @@ typedef struct _CompGrab {
     const char *name;
 } CompGrab;
 
-typedef struct _CompGroup {
-    struct _CompGroup *next;
-    unsigned int      refCnt;
-    Window	      id;
-} CompGroup;
-
 typedef struct _CompStartupSequence {
     struct _CompStartupSequence *next;
     SnStartupSequence		*sequence;
@@ -2019,8 +2699,8 @@ struct _CompScreen {
 
     CompScreen  *next;
     CompDisplay *display;
-    CompWindow	*windows;
-    CompWindow	*reverseWindows;
+
+    CompWindow root;
 
     char *windowPrivateIndices;
     int  windowPrivateLen;
@@ -2038,7 +2718,6 @@ struct _CompScreen {
     REGION	      region;
     Region	      damage;
     unsigned long     damageMask;
-    Window	      root;
     Window	      overlay;
     Window	      output;
     XWindowAttributes attrib;
@@ -2061,7 +2740,6 @@ struct _CompScreen {
     CompTexture       backgroundTexture;
     Bool	      backgroundLoaded;
     unsigned int      pendingDestroys;
-    int		      desktopWindowCount;
     unsigned int      mapNum;
     unsigned int      activeNum;
 
@@ -2071,9 +2749,6 @@ struct _CompScreen {
     CompOutput fullscreenOutput;
     Bool       hasOverlappingOutputs;
 
-    int windowOffsetX;
-    int windowOffsetY;
-
     XRectangle lastViewport;
 
     CompActiveWindowHistory history[ACTIVE_WINDOW_HISTORY_NUM];
@@ -2220,7 +2895,8 @@ struct _CompScreen {
 
     OutputChangeNotifyProc outputChangeNotify;
 
-    InitWindowWalkerProc initWindowWalker;
+    InitWindowWalkerProc  initWindowWalker;
+    InitObjectPainterProc initObjectPainter;
 };
 
 #define GET_CORE_SCREEN(object) ((CompScreen *) (object))
@@ -2283,6 +2959,12 @@ void
 detectRefreshRateOfScreen (CompScreen *s);
 
 void
+getSupportingWmCheck (CompWindow *w);
+
+void
+getDesktopHints (CompScreen *s);
+
+void
 showOutputWindow (CompScreen *s);
 
 void
@@ -2312,15 +2994,6 @@ void
 damagePendingOnScreen (CompScreen *s);
 
 void
-insertWindowIntoScreen (CompScreen *s,
-			CompWindow *w,
-			Window	   aboveId);
-
-void
-unhookWindowFromScreen (CompScreen *s,
-			CompWindow *w);
-
-void
 forEachWindowOnScreen (CompScreen	 *screen,
 		       ForEachWindowProc proc,
 		       void		 *closure);
@@ -2330,6 +3003,10 @@ findWindowAtScreen (CompScreen *s,
 		    Window     id);
 
 CompWindow *
+findClientWindowAtScreen (CompScreen *s,
+			  Window      id);
+
+CompWindow *
 findTopLevelWindowAtScreen (CompScreen *s,
 			    Window      id);
 
@@ -2436,7 +3113,7 @@ disableScreenEdge (CompScreen *s,
 		   int	      edge);
 
 Window
-getTopWindow (CompScreen *s);
+getTopWindow (CompWindow *parent);
 
 void
 makeScreenCurrent (CompScreen *s);
@@ -2523,579 +3200,6 @@ setWindowPaintOffset (CompScreen *s,
 		      int        y);
 
 
-/* window.c */
-
-#define WINDOW_INVISIBLE(w)				       \
-    ((w)->attrib.map_state != IsViewable		    || \
-     (!(w)->damaged)					    || \
-     (w)->attrib.x + (w)->width  + (w)->output.right  <= 0  || \
-     (w)->attrib.y + (w)->height + (w)->output.bottom <= 0  || \
-     (w)->attrib.x - (w)->output.left >= (w)->screen->width || \
-     (w)->attrib.y - (w)->output.top >= (w)->screen->height)
-
-typedef enum {
-    CompStackingUpdateModeNone = 0,
-    CompStackingUpdateModeNormal,
-    CompStackingUpdateModeAboveFullscreen,
-    CompStackingUpdateModeInitialMap,
-    CompStackingUpdateModeInitialMapDeniedFocus
-} CompStackingUpdateMode;
-
-struct _CompWindowExtents {
-    int left;
-    int right;
-    int top;
-    int bottom;
-};
-
-typedef struct _CompStruts {
-    XRectangle left;
-    XRectangle right;
-    XRectangle top;
-    XRectangle bottom;
-} CompStruts;
-
-struct _CompWindow {
-    CompObject base;
-
-    CompScreen *screen;
-    CompWindow *next;
-    CompWindow *prev;
-
-    int		      refcnt;
-    Window	      id;
-    Window	      frame;
-    unsigned int      mapNum;
-    unsigned int      activeNum;
-    XWindowAttributes attrib;
-    int		      serverX;
-    int		      serverY;
-    int		      serverWidth;
-    int		      serverHeight;
-    int		      serverBorderWidth;
-    Window	      transientFor;
-    Window	      clientLeader;
-    XSizeHints	      sizeHints;
-    Pixmap	      pixmap;
-    CompTexture       *texture;
-    CompMatrix        matrix;
-    Damage	      damage;
-    Bool	      inputHint;
-    Bool	      alpha;
-    GLint	      width;
-    GLint	      height;
-    Region	      region;
-    Region	      clip;
-    unsigned int      wmType;
-    unsigned int      type;
-    unsigned int      state;
-    unsigned int      actions;
-    unsigned int      protocols;
-    unsigned int      mwmDecor;
-    unsigned int      mwmFunc;
-    Bool	      invisible;
-    Bool	      destroyed;
-    Bool	      damaged;
-    Bool	      redirected;
-    Bool	      managed;
-    Bool	      bindFailed;
-    Bool	      overlayWindow;
-    int		      destroyRefCnt;
-    int		      unmapRefCnt;
-
-    unsigned int initialViewportX;
-    unsigned int initialViewportY;
-
-    Time initialTimestamp;
-    Bool initialTimestampSet;
-
-    Bool placed;
-    Bool minimized;
-    Bool inShowDesktopMode;
-    Bool shaded;
-    Bool hidden;
-    Bool grabbed;
-
-    unsigned int desktop;
-
-    int pendingUnmaps;
-    int pendingMaps;
-
-    char *startupId;
-    char *resName;
-    char *resClass;
-
-    CompGroup *group;
-
-    unsigned int lastPong;
-    Bool	 alive;
-
-    WindowPaintAttrib paint;
-    WindowPaintAttrib lastPaint;
-
-    unsigned int lastMask;
-
-    CompWindowExtents input;
-    CompWindowExtents output;
-
-    CompStruts *struts;
-
-    CompIcon **icon;
-    int	     nIcon;
-
-    XRectangle iconGeometry;
-    Bool       iconGeometrySet;
-
-    XWindowChanges saveWc;
-    int		   saveMask;
-
-    XSyncCounter  syncCounter;
-    XSyncValue	  syncValue;
-    XSyncAlarm	  syncAlarm;
-    unsigned long syncAlarmConnection;
-    unsigned int  syncWaitHandle;
-
-    Bool syncWait;
-    int	 syncX;
-    int	 syncY;
-    int	 syncWidth;
-    int	 syncHeight;
-    int	 syncBorderWidth;
-
-    Bool closeRequests;
-    Time lastCloseRequestTime;
-
-    XRectangle *damageRects;
-    int	       sizeDamage;
-    int	       nDamage;
-
-    GLfloat  *vertices;
-    int      vertexSize;
-    int      vertexStride;
-    GLushort *indices;
-    int      indexSize;
-    int      vCount;
-    int      texUnits;
-    int      texCoordSize;
-    int      indexCount;
-
-    /* must be set by addWindowGeometry */
-    DrawWindowGeometryProc drawWindowGeometry;
-};
-
-#define GET_CORE_WINDOW(object) ((CompWindow *) (object))
-#define CORE_WINDOW(object) CompWindow *w = GET_CORE_WINDOW (object)
-
-CompBool
-allocWindowObjectPrivates (CompObject *object,
-			   CompObject *parent);
-
-int
-allocWindowObjectPrivateIndex (CompObject *parent);
-
-void
-freeWindowObjectPrivateIndex (CompObject *parent,
-			      int	 index);
-
-CompBool
-forEachWindowObject (CompObject	        *parent,
-		     ObjectCallBackProc proc,
-		     void	        *closure);
-
-char *
-nameWindowObject (CompObject *object);
-
-CompObject *
-findWindowObject (CompObject *parent,
-		  const char *name);
-
-int
-allocateWindowPrivateIndex (CompScreen *screen);
-
-void
-freeWindowPrivateIndex (CompScreen *screen,
-			int	   index);
-
-unsigned int
-windowStateMask (CompDisplay *display,
-		 Atom	     state);
-
-unsigned int
-windowStateFromString (const char *str);
-
-unsigned int
-getWindowState (CompDisplay *display,
-		Window      id);
-
-void
-setWindowState (CompDisplay  *display,
-		unsigned int state,
-		Window       id);
-
-void
-changeWindowState (CompWindow   *w,
-		   unsigned int newState);
-
-void
-recalcWindowActions (CompWindow *w);
-
-unsigned int
-constrainWindowState (unsigned int state,
-		      unsigned int actions);
-
-unsigned int
-windowTypeFromString (const char *str);
-
-unsigned int
-getWindowType (CompDisplay *display,
-	       Window      id);
-
-void
-recalcWindowType (CompWindow *w);
-
-void
-getMwmHints (CompDisplay  *display,
-	     Window	  id,
-	     unsigned int *func,
-	     unsigned int *decor);
-
-unsigned int
-getProtocols (CompDisplay *display,
-	      Window      id);
-
-unsigned int
-getWindowProp (CompDisplay  *display,
-	       Window	    id,
-	       Atom	    property,
-	       unsigned int defaultValue);
-
-void
-setWindowProp (CompDisplay  *display,
-	       Window       id,
-	       Atom	    property,
-	       unsigned int value);
-
-Bool
-readWindowProp32 (CompDisplay    *display,
-		  Window	 id,
-		  Atom		 property,
-		  unsigned short *returnValue);
-
-unsigned short
-getWindowProp32 (CompDisplay	*display,
-		 Window		id,
-		 Atom		property,
-		 unsigned short defaultValue);
-
-void
-setWindowProp32 (CompDisplay    *display,
-		 Window         id,
-		 Atom		property,
-		 unsigned short value);
-
-void
-updateNormalHints (CompWindow *window);
-
-void
-updateWmHints (CompWindow *w);
-
-void
-updateWindowClassHints (CompWindow *window);
-
-void
-updateTransientHint (CompWindow *w);
-
-void
-updateIconGeometry (CompWindow *w);
-
-Window
-getClientLeader (CompWindow *w);
-
-char *
-getStartupId (CompWindow *w);
-
-int
-getWmState (CompDisplay *display,
-	    Window      id);
-
-void
-setWmState (CompDisplay *display,
-	    int		state,
-	    Window      id);
-
-void
-setWindowFrameExtents (CompWindow	 *w,
-		       CompWindowExtents *input);
-
-void
-updateWindowOutputExtents (CompWindow *w);
-
-void
-updateWindowRegion (CompWindow *w);
-
-Bool
-updateWindowStruts (CompWindow *w);
-
-void
-addWindow (CompScreen *screen,
-	   Window     id,
-	   Window     aboveId);
-
-void
-removeWindow (CompWindow *w);
-
-void
-destroyWindow (CompWindow *w);
-
-void
-sendConfigureNotify (CompWindow *w);
-
-void
-mapWindow (CompWindow *w);
-
-void
-unmapWindow (CompWindow *w);
-
-Bool
-bindWindow (CompWindow *w);
-
-void
-releaseWindow (CompWindow *w);
-
-void
-moveWindow (CompWindow *w,
-	    int        dx,
-	    int        dy,
-	    Bool       damage,
-	    Bool       immediate);
-
-void
-configureXWindow (CompWindow	 *w,
-		  unsigned int	 valueMask,
-		  XWindowChanges *xwc);
-
-unsigned int
-adjustConfigureRequestForGravity (CompWindow     *w,
-				  XWindowChanges *xwc,
-				  unsigned int   xwcm,
-				  int            gravity);
-
-void
-moveResizeWindow (CompWindow     *w,
-		  XWindowChanges *xwc,
-		  unsigned int   xwcm,
-		  int            gravity,
-		  unsigned int   source);
-
-void
-syncWindowPosition (CompWindow *w);
-
-void
-sendSyncRequest (CompWindow *w);
-
-Bool
-resizeWindow (CompWindow *w,
-	      int	 x,
-	      int	 y,
-	      int	 width,
-	      int	 height,
-	      int	 borderWidth);
-
-void
-configureWindow (CompWindow	 *w,
-		 XConfigureEvent *ce);
-
-void
-circulateWindow (CompWindow	 *w,
-		 XCirculateEvent *ce);
-
-void
-addWindowDamageRect (CompWindow *w,
-		     BoxPtr     rect);
-
-void
-getOutputExtentsForWindow (CompWindow	     *w,
-			   CompWindowExtents *output);
-
-void
-getAllowedActionsForWindow (CompWindow   *w,
-			    unsigned int *setActions,
-			    unsigned int *clearActions);
-
-void
-addWindowDamage (CompWindow *w);
-
-void
-damageWindowOutputExtents (CompWindow *w);
-
-Bool
-damageWindowRect (CompWindow *w,
-		  Bool       initial,
-		  BoxPtr     rect);
-
-void
-damageTransformedWindowRect (CompWindow *w,
-			     float	xScale,
-			     float	yScale,
-			     float	xTranslate,
-			     float	yTranslate,
-			     BoxPtr     rect);
-
-Bool
-focusWindow (CompWindow *w);
-
-Bool
-placeWindow (CompWindow *w,
-	     int        x,
-	     int        y,
-	     int        *newX,
-	     int        *newY);
-
-void
-validateWindowResizeRequest (CompWindow     *w,
-			     unsigned int   *mask,
-			     XWindowChanges *xwc,
-			     unsigned int   source);
-
-void
-windowResizeNotify (CompWindow *w,
-		    int	       dx,
-		    int	       dy,
-		    int	       dwidth,
-		    int	       dheight);
-
-void
-windowMoveNotify (CompWindow *w,
-		  int	     dx,
-		  int	     dy,
-		  Bool	     immediate);
-
-void
-windowGrabNotify (CompWindow   *w,
-		  int	       x,
-		  int	       y,
-		  unsigned int state,
-		  unsigned int mask);
-
-void
-windowUngrabNotify (CompWindow *w);
-
-void
-windowStateChangeNotify (CompWindow   *w,
-			 unsigned int lastState);
-
-void
-moveInputFocusToWindow (CompWindow *w);
-
-void
-updateWindowSize (CompWindow *w);
-
-void
-raiseWindow (CompWindow *w);
-
-void
-lowerWindow (CompWindow *w);
-
-void
-restackWindowAbove (CompWindow *w,
-		    CompWindow *sibling);
-
-void
-restackWindowBelow (CompWindow *w,
-		    CompWindow *sibling);
-
-void
-updateWindowAttributes (CompWindow             *w,
-			CompStackingUpdateMode stackingMode);
-
-void
-activateWindow (CompWindow *w);
-
-void
-closeWindow (CompWindow *w,
-	     Time	serverTime);
-
-Bool
-constrainNewWindowSize (CompWindow *w,
-			int        width,
-			int        height,
-			int        *newWidth,
-			int        *newHeight);
-
-void
-hideWindow (CompWindow *w);
-
-void
-showWindow (CompWindow *w);
-
-void
-minimizeWindow (CompWindow *w);
-
-void
-unminimizeWindow (CompWindow *w);
-
-void
-maximizeWindow (CompWindow *w,
-		int	   state);
-
-Bool
-getWindowUserTime (CompWindow *w,
-		   Time       *time);
-
-void
-setWindowUserTime (CompWindow *w,
-		   Time       time);
-
-Bool
-allowWindowFocus (CompWindow   *w,
-		  unsigned int noFocusMask,
-		  unsigned int viewportX,
-		  unsigned int viewportY,
-		  Time         timestamp);
-
-void
-unredirectWindow (CompWindow *w);
-
-void
-redirectWindow (CompWindow *w);
-
-void
-defaultViewportForWindow (CompWindow *w,
-			  int	     *vx,
-			  int        *vy);
-
-CompIcon *
-getWindowIcon (CompWindow *w,
-	       int	  width,
-	       int	  height);
-
-void
-freeWindowIcons (CompWindow *w);
-
-int
-outputDeviceForWindow (CompWindow *w);
-
-Bool
-onCurrentDesktop (CompWindow *w);
-
-void
-setDesktopForWindow (CompWindow   *w,
-		     unsigned int desktop);
-
-int
-compareWindowActiveness (CompWindow *w1,
-			 CompWindow *w2);
-
-Bool
-windowOnAllViewports (CompWindow *w);
-
-void
-getWindowMovementForOffset (CompWindow *w,
-			    int        offX,
-			    int        offY,
-			    int        *retX,
-			    int        *retY);
-
 /* plugin.c */
 
 #define HOME_PLUGINDIR ".compiz/plugins"
diff --git a/include/decoration.h b/include/decoration.h
index 5eed043..9bc6552 100644
--- a/include/decoration.h
+++ b/include/decoration.h
@@ -196,19 +196,32 @@ decor_property_to_quads (long		 *data,
 			 decor_quad_t    *quad);
 
 void
+decor_region_to_box_property (long   *data,
+			      int    width,
+			      int    height,
+			      Region topRegion,
+			      int    topOffset,
+			      Region bottomRegion,
+			      int    bottomOffset,
+			      Region leftRegion,
+			      int    leftOffset,
+			      Region rightRegion,
+			      int    rightOffset);
+
+void
 decor_region_to_blur_property (long   *data,
 			       int    threshold,
 			       int    filter,
 			       int    width,
 			       int    height,
-			       Region topRegion,
-			       int    topOffset,
-			       Region bottomRegion,
-			       int    bottomOffset,
-			       Region leftRegion,
-			       int    leftOffset,
-			       Region rightRegion,
-			       int    rightOffset);
+			       Region top_region,
+			       int    top_offset,
+			       Region bottom_region,
+			       int    bottom_offset,
+			       Region left_region,
+			       int    left_offset,
+			       Region right_region,
+			       int    right_offset);
 
 void
 decor_apply_gravity (int gravity,
diff --git a/kde/window-decorator-kde4/decorator.cpp b/kde/window-decorator-kde4/decorator.cpp
index 96b818d..6ca2a39 100644
--- a/kde/window-decorator-kde4/decorator.cpp
+++ b/kde/window-decorator-kde4/decorator.cpp
@@ -403,7 +403,7 @@ KWD::Decorator::updateShadow (void)
 	KWD::trapXError ();
 	XChangeProperty (QX11Info::display(), QX11Info::appRootWindow(),
 			 Atoms::netWindowDecorBare,
-			 XA_INTEGER,
+			 Atoms::netWindowDecor,
 			 32, PropModeReplace, (unsigned char *) data,
 			 BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
 	KWD::popXError ();
diff --git a/kde/window-decorator-kde4/switcher.cpp b/kde/window-decorator-kde4/switcher.cpp
index 2978e69..860b8aa 100644
--- a/kde/window-decorator-kde4/switcher.cpp
+++ b/kde/window-decorator-kde4/switcher.cpp
@@ -261,15 +261,18 @@ KWD::Switcher::updateBlurProperty (int topOffset,
 
     if (size)
     {
-	long data[size * 6 + 2];
-
-	decor_region_to_blur_property (data, 4, 0,
-				       mGeometry.width (),
-				       mGeometry.height (),
-				       topRegion, topOffset,
-				       bottomRegion, bottomOffset,
-				       leftRegion, leftOffset,
-				       rightRegion, rightOffset);
+      	long data[size * 6 + 2];
+
+        data[0] = 4;
+	data[1] = 0;
+
+	decor_region_to_box_property (data + 2,
+                                      mGeometry.width (),
+                                      mGeometry.height (),
+                                      topRegion, topOffset,
+                                      bottomRegion, bottomOffset,
+                                      leftRegion, leftOffset,
+                                      rightRegion, rightOffset);
 
 	KWD::trapXError ();
 	XChangeProperty (QX11Info::display (), mId, atom, XA_INTEGER,
diff --git a/kde/window-decorator-kde4/window.cpp b/kde/window-decorator-kde4/window.cpp
index d2d362b..1e7d8c5 100644
--- a/kde/window-decorator-kde4/window.cpp
+++ b/kde/window-decorator-kde4/window.cpp
@@ -1426,13 +1426,16 @@ KWD::Window::updateBlurProperty (int topOffset,
     {
 	long data[size * 6 + 2];
 
-	decor_region_to_blur_property (data, 4, 0,
-				       mGeometry.width (),
-				       mGeometry.height (),
-				       topRegion, topOffset,
-				       bottomRegion, bottomOffset,
-				       leftRegion, leftOffset,
-				       rightRegion, rightOffset);
+        data[0] = 4;
+	data[1] = 0;
+
+	decor_region_to_box_property (data + 2,
+                                      mGeometry.width (),
+                                      mGeometry.height (),
+                                      topRegion, topOffset,
+                                      bottomRegion, bottomOffset,
+                                      leftRegion, leftOffset,
+                                      rightRegion, rightOffset);
 
 	KWD::trapXError ();
 	XChangeProperty (QX11Info::display(), mClientId, atom,
@@ -1542,7 +1545,7 @@ KWD::Window::updateProperty (void)
 
     KWD::trapXError ();
     XChangeProperty (QX11Info::display(), mClientId, atom,
-		     XA_INTEGER,
+		     Atoms::netWindowDecor,
 		     32, PropModeReplace, (unsigned char *) data,
 		     BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
     KWD::popXError ();
diff --git a/kde/window-decorator/decorator.cpp b/kde/window-decorator/decorator.cpp
index 2d5ada0..03819dc 100644
--- a/kde/window-decorator/decorator.cpp
+++ b/kde/window-decorator/decorator.cpp
@@ -530,7 +530,7 @@ KWD::Decorator::updateShadow (void)
 	KWD::trapXError ();
 	XChangeProperty (qt_xdisplay (), qt_xrootwin (),
 			 Atoms::netWindowDecorBare,
-			 XA_INTEGER,
+			 Atoms::netWindowDecor,
 			 32, PropModeReplace, (unsigned char *) data,
 			 BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
 	KWD::popXError ();
diff --git a/kde/window-decorator/window.cpp b/kde/window-decorator/window.cpp
index 55580e6..9e73e1a 100644
--- a/kde/window-decorator/window.cpp
+++ b/kde/window-decorator/window.cpp
@@ -1323,13 +1323,16 @@ KWD::Window::updateBlurProperty (int topOffset,
     {
 	long data[size * 6 + 2];
 
-	decor_region_to_blur_property (data, 4, 0,
-				       mGeometry.width (),
-				       mGeometry.height (),
-				       topRegion, topOffset,
-				       bottomRegion, bottomOffset,
-				       leftRegion, leftOffset,
-				       rightRegion, rightOffset);
+        data[0] = 4;
+	data[1] = 0;
+
+	decor_region_to_box_property (data + 2,
+                                      mGeometry.width (),
+                                      mGeometry.height (),
+                                      topRegion, topOffset,
+                                      bottomRegion, bottomOffset,
+                                      leftRegion, leftOffset,
+                                      rightRegion, rightOffset);
 
 	KWD::trapXError ();
 	XChangeProperty (qt_xdisplay (), mClientId, atom,
@@ -1442,7 +1445,7 @@ KWD::Window::updateProperty (void)
 
     KWD::trapXError ();
     XChangeProperty (qt_xdisplay (), mClientId, atom,
-		     XA_INTEGER,
+		     Atoms::netWindowDecor,
 		     32, PropModeReplace, (unsigned char *) data,
 		     BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
     KWD::popXError ();
diff --git a/libdecoration/decoration.c b/libdecoration/decoration.c
index 1f3407c..b261045 100644
--- a/libdecoration/decoration.c
+++ b/libdecoration/decoration.c
@@ -205,13 +205,13 @@ decor_property_to_quads (long		 *data,
 }
 
 static int
-add_blur_boxes (long   *data,
-		BoxPtr box,
-		int    n_box,
-		int    width,
-		int    height,
-		int    gravity,
-		int    offset)
+add_boxes (long   *data,
+	   BoxPtr box,
+	   int    n_box,
+	   int    width,
+	   int    height,
+	   int    gravity,
+	   int    offset)
 {
     int x1, y1, x2, y2;
     int more_gravity;
@@ -289,6 +289,52 @@ add_blur_boxes (long   *data,
 }
 
 void
+decor_region_to_box_property (long   *data,
+			      int    width,
+			      int    height,
+			      Region top_region,
+			      int    top_offset,
+			      Region bottom_region,
+			      int    bottom_offset,
+			      Region left_region,
+			      int    left_offset,
+			      Region right_region,
+			      int    right_offset)
+{
+    if (top_region)
+	data += add_boxes (data,
+			   top_region->rects,
+			   top_region->numRects,
+			   width, height,
+			   GRAVITY_NORTH,
+			   top_offset);
+
+    if (bottom_region)
+	data += add_boxes (data,
+			   bottom_region->rects,
+			   bottom_region->numRects,
+			   width, height,
+			   GRAVITY_SOUTH,
+			   bottom_offset);
+
+    if (left_region)
+	data += add_boxes (data,
+			   left_region->rects,
+			   left_region->numRects,
+			   width, height,
+			   GRAVITY_WEST,
+			   left_offset);
+
+    if (right_region)
+	data += add_boxes (data,
+			   right_region->rects,
+			   right_region->numRects,
+			   width, height,
+			   GRAVITY_EAST,
+			   right_offset);
+}
+
+void
 decor_region_to_blur_property (long   *data,
 			       int    threshold,
 			       int    filter,
@@ -303,40 +349,14 @@ decor_region_to_blur_property (long   *data,
 			       Region right_region,
 			       int    right_offset)
 {
-    *data++ = threshold;
-    *data++ = filter;
-
-    if (top_region)
-	data += add_blur_boxes (data,
-				top_region->rects,
-				top_region->numRects,
-				width, height,
-				GRAVITY_NORTH,
-				top_offset);
-
-    if (bottom_region)
-	data += add_blur_boxes (data,
-				bottom_region->rects,
-				bottom_region->numRects,
-				width, height,
-				GRAVITY_SOUTH,
-				bottom_offset);
-
-    if (left_region)
-	data += add_blur_boxes (data,
-				left_region->rects,
-				left_region->numRects,
-				width, height,
-				GRAVITY_WEST,
-				left_offset);
-
-    if (right_region)
-	data += add_blur_boxes (data,
-				right_region->rects,
-				right_region->numRects,
-				width, height,
-				GRAVITY_EAST,
-				right_offset);
+    data[0] = threshold;
+    data[1] = filter;
+
+    decor_region_to_box_property (data + 2, width, height,
+				  top_region, top_offset,
+				  bottom_region, bottom_offset,
+				  left_region, left_offset,
+				  right_region, right_offset);
 }
 
 void
diff --git a/metadata/Makefile.am b/metadata/Makefile.am
index 666d989..eeb208a 100644
--- a/metadata/Makefile.am
+++ b/metadata/Makefile.am
@@ -11,6 +11,7 @@ xml_in_files =		  \
 	fs.xml.in	  \
 	gconf.xml.in	  \
 	glib.xml.in	  \
+	glx.xml.in	  \
 	ini.xml.in	  \
 	inotify.xml.in	  \
 	kconfig.xml.in	  \
@@ -28,6 +29,7 @@ xml_in_files =		  \
 	switcher.xml.in   \
 	video.xml.in      \
 	water.xml.in      \
+	wm.xml.in	  \
 	wobbly.xml.in     \
 	zoom.xml.in
 xml_files    = $(xml_in_files:.xml.in=.xml)
diff --git a/metadata/annotate.xml.in b/metadata/annotate.xml.in
index 46a2b09..486b84a 100644
--- a/metadata/annotate.xml.in
+++ b/metadata/annotate.xml.in
@@ -2,6 +2,14 @@
     <plugin name="annotate">
 	<_short>Annotate</_short>
 	<_long>Annotate plugin</_long>
+	<deps>
+	    <requirement>
+		<plugin>glx</plugin>
+	    </requirement>
+	    <relation type="after">
+		<plugin>glx</plugin>
+	    </relation>
+	</deps>
 	<display>
 	    <option name="initiate_button" type="button">
 		<_short>Initiate</_short>
diff --git a/metadata/blur.xml.in b/metadata/blur.xml.in
index 21be0f0..1fd674f 100644
--- a/metadata/blur.xml.in
+++ b/metadata/blur.xml.in
@@ -4,6 +4,9 @@
 	<_long>Blur windows</_long>
 	<feature>blur</feature>
 	<deps>
+	    <requirement>
+		<plugin>glx</plugin>
+	    </requirement>
 	    <relation type="before">
 		<plugin>video</plugin>
 	    </relation>
diff --git a/metadata/clone.xml.in b/metadata/clone.xml.in
index d7c7ce4..7735f7c 100644
--- a/metadata/clone.xml.in
+++ b/metadata/clone.xml.in
@@ -2,6 +2,11 @@
     <plugin name="clone">
 	<_short>Clone Output</_short>
 	<_long>Output clone handler</_long>
+	<deps>
+	    <requirement>
+		<plugin>glx</plugin>
+	    </requirement>
+	</deps>
 	<display>
 	    <option name="initiate_button" type="button">
 		<_short>Initiate</_short>
diff --git a/metadata/cube.xml.in b/metadata/cube.xml.in
index f07da8b..ff9b114 100644
--- a/metadata/cube.xml.in
+++ b/metadata/cube.xml.in
@@ -4,6 +4,9 @@
 	<_long>Place windows on cube</_long>
 	<feature>largedesktop</feature>
 	<deps>
+	    <requirement>
+		<plugin>glx</plugin>
+	    </requirement>
 	    <relation type="before">
 		<plugin>switcher</plugin>
 		<plugin>scale</plugin>
diff --git a/metadata/fade.xml.in b/metadata/fade.xml.in
index 7e1ddff..a327e1e 100644
--- a/metadata/fade.xml.in
+++ b/metadata/fade.xml.in
@@ -3,6 +3,9 @@
 	<_short>Fading Windows</_short>
 	<_long>Fade in windows when mapped and fade out windows when unmapped</_long>
 	<deps>
+	    <requirement>
+		<plugin>glx</plugin>
+	    </requirement>
 	    <relation type="before">
 		<plugin>cube</plugin>
 		<plugin>scale</plugin>
diff --git a/metadata/glx.xml.in b/metadata/glx.xml.in
new file mode 100644
index 0000000..9f25dcd
--- /dev/null
+++ b/metadata/glx.xml.in
@@ -0,0 +1,9 @@
+<compiz>
+    <plugin name="glx">
+	<_short>GLX</_short>
+	<_long>GLX compositing output</_long>
+	<display>
+	    <option name="abi" type="int" read_only="true"/>
+	</display>
+    </plugin>
+</compiz>
\ No newline at end of file
diff --git a/metadata/minimize.xml.in b/metadata/minimize.xml.in
index 4968549..f9e8077 100644
--- a/metadata/minimize.xml.in
+++ b/metadata/minimize.xml.in
@@ -4,6 +4,9 @@
 	<_long>Transform windows when they are minimized and unminimized</_long>
 	<feature>windowanimations</feature>
 	<deps>
+	    <requirement>
+		<plugin>glx</plugin>
+	    </requirement>
 	    <relation type="before">
 		<plugin>cube</plugin>
 		<plugin>scale</plugin>
diff --git a/metadata/place.xml.in b/metadata/place.xml.in
index 19625ba..fd9b524 100644
--- a/metadata/place.xml.in
+++ b/metadata/place.xml.in
@@ -2,6 +2,11 @@
     <plugin name="place">
 	<_short>Place Windows</_short>
 	<_long>Place windows at appropriate positions when mapped</_long>
+	<deps>
+	    <requirement>
+		<plugin>wm</plugin>
+	    </requirement>
+	</deps>
 	<screen>
 	    <option name="workarounds" type="bool">
 		<_short>Workarounds</_short>
diff --git a/metadata/scale.xml.in b/metadata/scale.xml.in
index c551aa3..f85132c 100644
--- a/metadata/scale.xml.in
+++ b/metadata/scale.xml.in
@@ -2,6 +2,11 @@
     <plugin name="scale">
 	<_short>Scale</_short>
 	<_long>Scale windows</_long>
+	<deps>
+	    <requirement>
+		<plugin>glx</plugin>
+	    </requirement>
+	</deps>
 	<display>
 	    <option name="abi" type="int" read_only="true"/>
 	    <option name="index" type="int" read_only="true"/>
diff --git a/metadata/screenshot.xml.in b/metadata/screenshot.xml.in
index d7b528e..8de85e7 100644
--- a/metadata/screenshot.xml.in
+++ b/metadata/screenshot.xml.in
@@ -2,6 +2,11 @@
     <plugin name="screenshot">
 	<_short>Screenshot</_short>
 	<_long>Screenshot plugin</_long>
+	<deps>
+	    <requirement>
+		<plugin>glx</plugin>
+	    </requirement>
+	</deps>
 	<display>
 	    <option name="initiate_button" type="button">
 		<_short>Initiate</_short>
diff --git a/metadata/svg.xml.in b/metadata/svg.xml.in
index 7eaa8b8..eaa0293 100644
--- a/metadata/svg.xml.in
+++ b/metadata/svg.xml.in
@@ -4,5 +4,10 @@
 	<_long>Svg image loader</_long>
 	<feature>imageext:svg</feature>
 	<feature>imagemime:image/svg+xml</feature>
+	<deps>
+	    <requirement>
+		<plugin>glx</plugin>
+	    </requirement>
+	</deps>
     </plugin>
 </compiz>
diff --git a/metadata/switcher.xml.in b/metadata/switcher.xml.in
index e829cc3..03c01e5 100644
--- a/metadata/switcher.xml.in
+++ b/metadata/switcher.xml.in
@@ -2,6 +2,11 @@
     <plugin name="switcher">
 	<_short>Application Switcher</_short>
 	<_long>Application Switcher</_long>
+	<deps>
+	    <requirement>
+		<plugin>glx</plugin>
+	    </requirement>
+	</deps>
 	<display>
 	    <option name="next_button" type="button">
 		<_short>Next window</_short>
diff --git a/metadata/video.xml.in b/metadata/video.xml.in
index 09c5076..1a7cedc 100644
--- a/metadata/video.xml.in
+++ b/metadata/video.xml.in
@@ -3,6 +3,11 @@
 	<_short>Video Playback</_short>
 	<_long>Video playback</_long>
 	<feature>video</feature>
+	<deps>
+	    <requirement>
+		<plugin>glx</plugin>
+	    </requirement>
+	</deps>
 	<display>
 	    <option name="yv12" type="bool">
 		<_short>YV12 colorspace</_short>
diff --git a/metadata/water.xml.in b/metadata/water.xml.in
index 9d3b9d2..4ea35a1 100644
--- a/metadata/water.xml.in
+++ b/metadata/water.xml.in
@@ -3,6 +3,9 @@
 	<_short>Water Effect</_short>
 	<_long>Adds water effects to different desktop actions</_long>
 	<deps>
+	    <requirement>
+		<plugin>glx</plugin>
+	    </requirement>
 	    <relation type="before">
 		<plugin>blur</plugin>
 		<plugin>video</plugin>
diff --git a/metadata/wm.xml.in b/metadata/wm.xml.in
new file mode 100644
index 0000000..5c5a023
--- /dev/null
+++ b/metadata/wm.xml.in
@@ -0,0 +1,9 @@
+<compiz>
+    <plugin name="wm">
+	<_short>Window Management</_short>
+	<_long>Window management</_long>
+	<display>
+	    <option name="abi" type="int" read_only="true"/>
+	</display>
+    </plugin>
+</compiz>
diff --git a/metadata/wobbly.xml.in b/metadata/wobbly.xml.in
index 005ef3d..c2fb951 100644
--- a/metadata/wobbly.xml.in
+++ b/metadata/wobbly.xml.in
@@ -3,6 +3,9 @@
 	<_short>Wobbly Windows</_short>
 	<_long>Use spring model for wobbly window effect</_long>
 	<deps>
+	    <requirement>
+		<plugin>glx</plugin>
+	    </requirement>
 	    <relation type="before">
 		<plugin>fade</plugin>
 		<plugin>cube</plugin>
diff --git a/metadata/zoom.xml.in b/metadata/zoom.xml.in
index 1a5bd5b..6903c5e 100644
--- a/metadata/zoom.xml.in
+++ b/metadata/zoom.xml.in
@@ -2,6 +2,11 @@
     <plugin name="zoom">
 	<_short>Zoom Desktop</_short>
 	<_long>Zoom and pan desktop cube</_long>
+	<deps>
+	    <requirement>
+		<plugin>glx</plugin>
+	    </requirement>
+	</deps>
 	<display>
 	    <option name="initiate_button" type="button">
 		<_short>Initiate</_short>
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 66e4ed7..7e1129d 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -1,3 +1,9 @@
+libwm_la_LDFLAGS = -module -avoid-version -no-undefined
+libwm_la_SOURCES = wm.c
+
+libglx_la_LDFLAGS = -module -avoid-version -no-undefined
+libglx_la_SOURCES = glx.c
+
 libfade_la_LDFLAGS = -module -avoid-version -no-undefined
 libfade_la_SOURCES = fade.c
 
@@ -19,7 +25,9 @@ libwobbly_la_SOURCES = wobbly.c
 libminimize_la_LDFLAGS = -module -avoid-version -no-undefined
 libminimize_la_SOURCES = minimize.c
 
+libmove_la_DEPENDENCIES = $(top_builddir)/libdecoration/libdecoration.la
 libmove_la_LDFLAGS = -module -avoid-version -no-undefined
+libmove_la_LIBADD = $(top_builddir)/libdecoration/libdecoration.la
 libmove_la_SOURCES = move.c
 
 libresize_la_LDFLAGS = -module -avoid-version -no-undefined
@@ -148,6 +156,8 @@ INCLUDES =					\
 moduledir = $(plugindir)
 
 module_LTLIBRARIES =		\
+	libwm.la		\
+	libglx.la		\
 	$(libglib_module)	\
 	$(libgconf_module)	\
 	$(libkconfig_module)	\
diff --git a/plugins/annotate.c b/plugins/annotate.c
index 6271260..e671468 100644
--- a/plugins/annotate.c
+++ b/plugins/annotate.c
@@ -118,7 +118,7 @@ annoCairoContext (CompScreen *s)
 	format = XRenderFindStandardFormat (s->display->display,
 					    PictStandardARGB32);
 
-	as->pixmap = XCreatePixmap (s->display->display, s->root, w, h, 32);
+	as->pixmap = XCreatePixmap (s->display->display, s->root.id, w, h, 32);
 
 	if (!bindPixmapToTexture (s, &as->texture, as->pixmap, w, h, 32))
 	{
@@ -497,7 +497,7 @@ annoTerminate (CompDisplay     *d,
     {
 	ANNO_SCREEN (s);
 
-	if (xid && s->root != xid)
+	if (xid && s->root.id != xid)
 	    continue;
 
 	if (as->grabIndex)
@@ -758,7 +758,8 @@ annoInitDisplay (CompPlugin  *p,
 {
     AnnoDisplay *ad;
 
-    if (!checkPluginABI ("core", CORE_ABIVERSION))
+    if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+	!checkPluginABI ("glx",  CORE_ABIVERSION))
 	return FALSE;
 
     ad = malloc (sizeof (AnnoDisplay));
diff --git a/plugins/blur.c b/plugins/blur.c
index d7da5da..ecb3a6d 100644
--- a/plugins/blur.c
+++ b/plugins/blur.c
@@ -588,7 +588,7 @@ blurSetScreenOption (CompPlugin      *plugin,
 	{
 	    CompWindow *w;
 
-	    for (w = screen->windows; w; w = w->next)
+	    for (w = screen->root.windows; w; w = w->next)
 		blurUpdateWindowMatch (bs, w);
 
 	    bs->moreBlur = TRUE;
@@ -784,7 +784,7 @@ blurPreparePaintScreen (CompScreen *s,
 
 	bs->moreBlur = FALSE;
 
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = w->next)
 	{
 	    BLUR_WINDOW (w);
 
@@ -843,7 +843,7 @@ blurPreparePaintScreen (CompScreen *s,
 	    int	       x1, y1, x2, y2;
 	    int	       count = 0;
 
-	    for (w = s->windows; w; w = w->next)
+	    for (w = s->root.windows; w; w = w->next)
 	    {
 		BLUR_WINDOW (w);
 
@@ -914,7 +914,7 @@ blurPaintOutput (CompScreen		 *s,
 
 	XSubtractRegion (&emptyRegion, &emptyRegion, bs->occlusion);
 
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = w->next)
 	    XSubtractRegion (&emptyRegion, &emptyRegion,
 			     GET_BLUR_WINDOW (w, bs)->clip);
     }
@@ -944,7 +944,7 @@ blurPaintTransformedOutput (CompScreen		    *s,
 
 	XSubtractRegion (&emptyRegion, &emptyRegion, bs->occlusion);
 
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = w->next)
 	    XSubtractRegion (&emptyRegion, &emptyRegion,
 			     GET_BLUR_WINDOW (w, bs)->clip);
     }
@@ -964,7 +964,7 @@ blurDonePaintScreen (CompScreen *s)
     {
 	CompWindow *w;
 
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = w->next)
 	{
 	    BLUR_WINDOW (w);
 
@@ -2715,7 +2715,7 @@ blurMatchExpHandlerChanged (CompDisplay *d)
     {
 	BLUR_SCREEN (s);
 
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = w->next)
 	    blurUpdateWindowMatch (bs, w);
     }
 }
@@ -2735,10 +2735,10 @@ blurMatchPropertyChanged (CompDisplay *d,
 }
 
 static void
-blurWindowAdd (CompScreen *s,
+blurWindowAdd (CompObject *parent,
 	       CompWindow *w)
 {
-    BLUR_SCREEN (s);
+    BLUR_SCREEN (w->screen);
 
     blurWindowUpdate (w, BLUR_STATE_CLIENT);
     blurWindowUpdate (w, BLUR_STATE_DECOR);
@@ -2772,7 +2772,8 @@ blurInitCore (CompPlugin *p,
 {
     BlurCore *bc;
 
-    if (!checkPluginABI ("core", CORE_ABIVERSION))
+    if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+	!checkPluginABI ("glx",  CORE_ABIVERSION))
 	return FALSE;
 
     bc = malloc (sizeof (BlurCore));
@@ -3112,7 +3113,7 @@ blurInitWindow (CompPlugin *p,
     w->base.privates[bs->windowPrivateIndex].ptr = bw;
 
     if (w->base.parent)
-	blurWindowAdd (w->screen, w);
+	blurWindowAdd (w->base.parent, w);
 
     return TRUE;
 }
diff --git a/plugins/clone.c b/plugins/clone.c
index 31b78a6..4854406 100644
--- a/plugins/clone.c
+++ b/plugins/clone.c
@@ -167,7 +167,7 @@ cloneFinish (CompScreen *s)
 
 		    clone->input =
 			XCreateWindow (s->display->display,
-				       s->root, x, y,
+				       s->root.id, x, y,
 				       s->outputDev[cs->dst].width,
 				       s->outputDev[cs->dst].height,
 				       0, 0, InputOnly, CopyFromParent,
@@ -400,7 +400,7 @@ clonePaintOutput (CompScreen		  *s,
 	if (cs->offset == 0.0f)
 	    s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;
 
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = w->next)
 	{
 	    if (w->destroyed)
 		continue;
@@ -515,7 +515,7 @@ cloneTerminate (CompDisplay     *d,
     {
 	CLONE_SCREEN (s);
 
-	if (xid && s->root != xid)
+	if (xid && s->root.id != xid)
 	    continue;
 
 	if (cs->grabIndex)
@@ -723,7 +723,8 @@ cloneInitDisplay (CompPlugin  *p,
 {
     CloneDisplay *cd;
 
-    if (!checkPluginABI ("core", CORE_ABIVERSION))
+    if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+	!checkPluginABI ("glx",  CORE_ABIVERSION))
 	return FALSE;
 
     cd = malloc (sizeof (CloneDisplay));
diff --git a/plugins/cube.c b/plugins/cube.c
index 91845f8..eaf76ed 100644
--- a/plugins/cube.c
+++ b/plugins/cube.c
@@ -1277,59 +1277,6 @@ cubePaintInside (CompScreen		 *s,
 }
 
 static void
-cubeEnableOutputClipping (CompScreen 	      *s,
-			  const CompTransform *transform,
-			  Region	      region,
-			  CompOutput 	      *output)
-{
-    CUBE_SCREEN (s);
-
-    if (cs->rotationState != RotationNone)
-    {
-	glPushMatrix ();
-	glLoadMatrixf (transform->m);
-	glTranslatef (cs->outputXOffset, -cs->outputYOffset, 0.0f);
-	glScalef (cs->outputXScale, cs->outputYScale, 1.0f);
-
-	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);
-	}
-
-	glEnable (GL_CLIP_PLANE0);
-	glEnable (GL_CLIP_PLANE1);
-	glEnable (GL_CLIP_PLANE2);
-	glEnable (GL_CLIP_PLANE3);
-
-	glPopMatrix ();
-    }
-    else
-    {
-	UNWRAP (cs, s, enableOutputClipping);
-	(*s->enableOutputClipping) (s, transform, region, output);
-	WRAP (cs, s, enableOutputClipping, cubeEnableOutputClipping);
-    }
-}
-
-static void
 cubePaintViewport (CompScreen              *s,
 		   const ScreenPaintAttrib *sAttrib,
 		   const CompTransform     *transform,
@@ -1580,7 +1527,8 @@ cubePaintWindow (CompWindow		  *w,
     CompScreen *s = w->screen;
     CUBE_SCREEN (s);
 
-    if ((w->type & CompWindowTypeDesktopMask) &&
+    if (w->parent == &s->root &&
+	(w->type & CompWindowTypeDesktopMask) &&
 	(attrib->opacity != cs->desktopOpacity))
     {
 	WindowPaintAttrib wAttrib = *attrib;
@@ -1602,12 +1550,12 @@ cubePaintWindow (CompWindow		  *w,
 }
 
 static void
-cubeInitWindowWalker (CompScreen *s, CompWalker* walker)
+cubeInitWindowWalker (CompScreen *s, CompWindow *w, CompWalker* walker)
 {
     CUBE_SCREEN (s);
 
     UNWRAP (cs, s, initWindowWalker);
-    (*s->initWindowWalker) (s, walker);
+    (*s->initWindowWalker) (s, w, walker);
     WRAP (cs, s, initWindowWalker, cubeInitWindowWalker);
 
     if (cs->paintOrder == FTB)
@@ -1701,7 +1649,7 @@ cubeFold (CompDisplay     *d,
     {
 	CUBE_SCREEN (s);
 
-	if (xid && s->root != xid)
+	if (xid && s->root.id != xid)
 	    continue;
 
 	if (cs->grabIndex)
@@ -1806,7 +1754,7 @@ cubeSetOptionForPlugin (CompObject      *o,
     status = (*core.setOptionForPlugin) (o, plugin, name, value);
     WRAP (cc, &core, setOptionForPlugin, cubeSetOptionForPlugin);
 
-    if (status && o->type == COMP_OBJECT_TYPE_SCREEN)
+    if (status && o->parent && o->type == COMP_OBJECT_TYPE_SCREEN)
     {
 	if (strcmp (plugin, "core") == 0 && strcmp (name, "hsize") == 0)
 	{
@@ -1864,7 +1812,8 @@ cubeInitCore (CompPlugin *p,
 {
     CubeCore *cc;
 
-    if (!checkPluginABI ("core", CORE_ABIVERSION))
+    if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+	!checkPluginABI ("glx",  CORE_ABIVERSION))
 	return FALSE;
 
     cc = malloc (sizeof (CubeCore));
@@ -2081,7 +2030,6 @@ cubeInitScreen (CompPlugin *p,
     WRAP (cs, s, paintScreen, cubePaintScreen);
     WRAP (cs, s, paintOutput, cubePaintOutput);
     WRAP (cs, s, paintTransformedOutput, cubePaintTransformedOutput);
-    WRAP (cs, s, enableOutputClipping, cubeEnableOutputClipping);
     WRAP (cs, s, paintWindow, cubePaintWindow);
     WRAP (cs, s, applyScreenTransform, cubeApplyScreenTransform);
     WRAP (cs, s, outputChangeNotify, cubeOutputChangeNotify);
@@ -2107,7 +2055,6 @@ cubeFiniScreen (CompPlugin *p,
     UNWRAP (cs, s, paintScreen);
     UNWRAP (cs, s, paintOutput);
     UNWRAP (cs, s, paintTransformedOutput);
-    UNWRAP (cs, s, enableOutputClipping);
     UNWRAP (cs, s, paintWindow);
     UNWRAP (cs, s, applyScreenTransform);
     UNWRAP (cs, s, outputChangeNotify);
diff --git a/plugins/dbus.c b/plugins/dbus.c
index bcc6f28..01734d5 100644
--- a/plugins/dbus.c
+++ b/plugins/dbus.c
@@ -65,13 +65,17 @@ typedef struct _DbusCore {
 
     CompFileWatchHandle fileWatch[DBUS_FILE_WATCH_NUM];
 
-    InitPluginForObjectProc initPluginForObject;
-    SetOptionForPluginProc  setOptionForPlugin;
+    SetOptionForPluginProc setOptionForPlugin;
+
+    ObjectAddProc    objectAdd;
+    ObjectRemoveProc objectRemove;
 } DbusCore;
 
 typedef struct _DbusDisplay {
     char         **pluginList;
     unsigned int nPlugins;
+
+    CompTimeoutHandle registerPluginsHandle;
 } DbusDisplay;
 
 static DBusHandlerResult dbusHandleMessage (DBusConnection *,
@@ -96,6 +100,19 @@ static DBusObjectPathVTable dbusMessagesVTable = {
     DbusDisplay *dd = GET_DBUS_DISPLAY (d)
 
 static void
+dbusEmptyPluginList (CompDisplay *d)
+{
+    int i;
+
+    DBUS_DISPLAY (d);
+
+    for (i = 0; i < dd->nPlugins; i++)
+	free (dd->pluginList[i]);
+
+    dd->nPlugins = 0;
+}
+
+static void
 dbusUpdatePluginList (CompDisplay *d)
 {
     CompListValue *pl;
@@ -105,20 +122,15 @@ dbusUpdatePluginList (CompDisplay *d)
 
     pl = &d->opt[COMP_DISPLAY_OPTION_ACTIVE_PLUGINS].value.list;
 
-    for (i = 0; i < dd->nPlugins; i++)
-	free (dd->pluginList[i]);
+    dbusEmptyPluginList (d);
 
     dd->pluginList = realloc (dd->pluginList, pl->nValue * sizeof (char *));
     if (!dd->pluginList)
-    {
-	dd->nPlugins = 0;
 	return;
-    }
 
     for (i = 0; i < pl->nValue; i++)
-	dd->pluginList[i] = strdup (pl->value[i].s);
-
-    dd->nPlugins = pl->nValue;
+	if (findActivePlugin (pl->value[i].s))
+	    dd->pluginList[dd->nPlugins++] = strdup (pl->value[i].s);
 }
 
 static CompOption *
@@ -1814,6 +1826,7 @@ dbusHandleMessage (DBusConnection *connection,
 	dbus_free_string_array (path);
 	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
+
     /* option message */
     if (dbus_message_is_method_call (message, DBUS_INTERFACE_INTROSPECTABLE,
 				     "Introspect"))
@@ -2169,59 +2182,26 @@ dbusUnregisterPluginsForScreen (DBusConnection *connection,
 }
 
 static CompBool
-dbusInitPluginForDisplay (CompPlugin  *p,
-			  CompDisplay *d)
-{
-    char objectPath[256];
-
-    DBUS_CORE (&core);
-
-    snprintf (objectPath, 256, "%s/%s/%s", COMPIZ_DBUS_ROOT_PATH,
-	      p->vTable->name, "allscreens");
-    dbusRegisterOptions (dc->connection, objectPath);
-
-    return TRUE;
-}
-
-static Bool
-dbusInitPluginForScreen (CompPlugin *p,
-			 CompScreen *s)
+dbusRegisterPlugins (void *data)
 {
-    char objectPath[256];
+    CompDisplay *d = (CompDisplay *) data;
+    CompScreen  *s;
 
     DBUS_CORE (&core);
+    DBUS_DISPLAY (d);
 
-    snprintf (objectPath, 256, "%s/%s/screen%d", COMPIZ_DBUS_ROOT_PATH,
-	      p->vTable->name, s->screenNum);
-    dbusRegisterOptions (dc->connection, objectPath);
-
-    return TRUE;
-}
-
-static CompBool
-dbusInitPluginForObject (CompPlugin *p,
-			 CompObject *o)
-{
-    CompBool status;
-
-    DBUS_CORE (&core);
+    if (d->dirtyPluginList)
+	return TRUE;
 
-    UNWRAP (dc, &core, initPluginForObject);
-    status = (*core.initPluginForObject) (p, o);
-    WRAP (dc, &core, initPluginForObject, dbusInitPluginForObject);
+    dd->registerPluginsHandle = 0;
 
-    if (status && p->vTable->getObjectOptions)
-    {
-	static InitPluginForObjectProc dispTab[] = {
-	    (InitPluginForObjectProc) 0, /* InitPluginForCore */
-	    (InitPluginForObjectProc) dbusInitPluginForDisplay,
-	    (InitPluginForObjectProc) dbusInitPluginForScreen
-	};
+    dbusUpdatePluginList (d);
 
-	RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
-    }
+    dbusRegisterPluginsForDisplay (dc->connection, d);
+    for (s = d->screens; s; s = s->next)
+	dbusRegisterPluginsForScreen (dc->connection, s);
 
-    return status;
+    return FALSE;
 }
 
 static CompBool
@@ -2262,16 +2242,19 @@ dbusSetOptionForPlugin (CompObject      *object,
 		CompScreen *s;
 
 		CORE_DISPLAY (object);
+		DBUS_DISPLAY (d);
 
 		dbusUnregisterPluginsForDisplay (dc->connection, d);
 		for (s = d->screens; s; s = s->next)
 		    dbusUnregisterPluginsForScreen (dc->connection, s);
 
-		dbusUpdatePluginList (d);
+		dbusEmptyPluginList (d);
 
-		dbusRegisterPluginsForDisplay (dc->connection, d);
-		for (s = d->screens; s; s = s->next)
-		    dbusRegisterPluginsForScreen (dc->connection, s);
+		if (!dd->registerPluginsHandle)
+		    dd->registerPluginsHandle =
+			compAddTimeout (10, -1,
+					dbusRegisterPlugins,
+					d);
 	    }
 	}
     }
@@ -2297,6 +2280,84 @@ dbusSendPluginsChangedSignal (const char *name,
     dbus_message_unref (signal);
 }
 
+static void
+dbusDisplayAdd (CompCore    *c,
+		CompDisplay *d)
+{
+    DBUS_DISPLAY (d);
+
+    if (!dd->registerPluginsHandle)
+	dd->registerPluginsHandle = compAddTimeout (10, -1,
+						    dbusRegisterPlugins,
+						    d);
+}
+
+static void
+dbusDisplayRemove (CompCore    *c,
+		   CompDisplay *d)
+{
+    DBUS_CORE (&core);
+
+    dbusUnregisterPluginsForDisplay (dc->connection, d);
+    dbusEmptyPluginList (d);
+}
+
+static void
+dbusScreenAdd (CompDisplay *d,
+	       CompScreen  *s)
+{
+    DBUS_CORE (&core);
+
+    dbusRegisterPluginsForScreen (dc->connection, s);
+}
+
+static void
+dbusScreenRemove (CompDisplay *d,
+		  CompScreen  *s)
+{
+    DBUS_CORE (&core);
+
+    dbusUnregisterPluginsForScreen (dc->connection, s);
+}
+
+static void
+dbusObjectAdd (CompObject *parent,
+	       CompObject *object)
+{
+    static ObjectAddProc dispTab[] = {
+	(ObjectAddProc) 0, /* CoreAdd */
+	(ObjectAddProc) dbusDisplayAdd,
+	(ObjectAddProc) dbusScreenAdd
+    };
+
+    DBUS_CORE (&core);
+
+    UNWRAP (dc, &core, objectAdd);
+    (*core.objectAdd) (parent, object);
+    WRAP (dc, &core, objectAdd, dbusObjectAdd);
+
+    DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), (parent, object));
+}
+
+static void
+dbusObjectRemove (CompObject *parent,
+		  CompObject *object)
+{
+    static ObjectRemoveProc dispTab[] = {
+	(ObjectRemoveProc) 0, /* CoreRemove */
+	(ObjectRemoveProc) dbusDisplayRemove,
+	(ObjectRemoveProc) dbusScreenRemove
+    };
+
+    DBUS_CORE (&core);
+
+    DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), (parent, object));
+
+    UNWRAP (dc, &core, objectRemove);
+    (*core.objectRemove) (parent, object);
+    WRAP (dc, &core, objectRemove, dbusObjectRemove);
+}
+
 static Bool
 dbusInitCore (CompPlugin *p,
 	      CompCore   *c)
@@ -2415,7 +2476,8 @@ dbusInitCore (CompPlugin *p,
 	}
     }
 
-    WRAP (dc, c, initPluginForObject, dbusInitPluginForObject);
+    WRAP (dc, c, objectAdd, dbusObjectAdd);
+    WRAP (dc, c, objectRemove, dbusObjectRemove);
     WRAP (dc, c, setOptionForPlugin, dbusSetOptionForPlugin);
 
     c->base.privates[corePrivateIndex].ptr = dc;
@@ -2452,7 +2514,8 @@ dbusFiniCore (CompPlugin *p,
       dbus_connection_unref (dc->connection);
     */
 
-    UNWRAP (dc, c, initPluginForObject);
+    UNWRAP (dc, c, objectAdd);
+    UNWRAP (dc, c, objectRemove);
     UNWRAP (dc, c, setOptionForPlugin);
 
     free (dc);
@@ -2464,8 +2527,6 @@ dbusInitDisplay (CompPlugin  *p,
 {
     DbusDisplay *dd;
 
-    DBUS_CORE (&core);
-
     dd = malloc (sizeof (DbusDisplay));
     if (!dd)
 	return FALSE;
@@ -2473,10 +2534,12 @@ dbusInitDisplay (CompPlugin  *p,
     dd->pluginList = NULL;
     dd->nPlugins   = 0;
 
+    dd->registerPluginsHandle = 0;
+
     d->base.privates[displayPrivateIndex].ptr = dd;
     
-    dbusUpdatePluginList (d);
-    dbusRegisterPluginsForDisplay (dc->connection, d);
+    if (d->base.parent)
+	dbusObjectAdd (d->base.parent, &d->base);
 
     return TRUE;
 }
@@ -2485,10 +2548,13 @@ static void
 dbusFiniDisplay (CompPlugin  *p,
 		 CompDisplay *d)
 {
-    DBUS_CORE (&core);
     DBUS_DISPLAY (d);
 
-    dbusUnregisterPluginsForDisplay (dc->connection, d);
+    if (dd->registerPluginsHandle)
+	compRemoveTimeout (dd->registerPluginsHandle);
+
+    if (d->base.parent)
+	dbusObjectRemove (d->base.parent, &d->base);
 
     if (dd->pluginList)
     {
@@ -2506,9 +2572,8 @@ static Bool
 dbusInitScreen (CompPlugin *p,
 		CompScreen *s)
 {
-    DBUS_CORE (&core);
-
-    dbusRegisterPluginsForScreen (dc->connection, s);
+    if (s->base.parent)
+	dbusObjectAdd (s->base.parent, &s->base);
 
     return TRUE;
 }
@@ -2517,9 +2582,8 @@ static void
 dbusFiniScreen (CompPlugin *p,
 		CompScreen *s)
 {
-    DBUS_CORE (&core);
-
-    dbusUnregisterPluginsForScreen (dc->connection, s);
+    if (s->base.parent)
+	dbusObjectRemove (s->base.parent, &s->base);
 }
 
 static CompBool
diff --git a/plugins/decoration.c b/plugins/decoration.c
index 003685f..a7a8d47 100644
--- a/plugins/decoration.c
+++ b/plugins/decoration.c
@@ -121,10 +121,6 @@ typedef struct _DecorDisplay {
 typedef struct _DecorScreen {
     int	windowPrivateIndex;
 
-    Window dmWin;
-
-    Decoration *decor[DECOR_NUM];
-
     DrawWindowProc		  drawWindow;
     DamageWindowRectProc	  damageWindowRect;
     GetOutputExtentsForWindowProc getOutputExtentsForWindow;
@@ -139,7 +135,11 @@ typedef struct _DecorScreen {
 
 typedef struct _DecorWindow {
     WindowDecoration *wd;
-    Decoration	     *decor;
+
+    Window dmWin;
+    Window wmWin;
+
+    Decoration *decor[DECOR_NUM];
 
     CompTimeoutHandle resizeUpdateHandle;
 } DecorWindow;
@@ -188,6 +188,15 @@ decorDrawWindow (CompWindow	      *w,
     status = (*w->screen->drawWindow) (w, transform, attrib, region, mask);
     WRAP (ds, w->screen, drawWindow, decorDrawWindow);
 
+    if (!w->shaded)
+    {
+	if (w->attrib.map_state != IsViewable)
+	    return status;
+
+	if (!w->damaged)
+	    return status;
+    }
+
     if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
 	region = &infiniteRegion;
 
@@ -224,7 +233,7 @@ decorDrawWindow (CompWindow	      *w,
 					     attrib, mask);
     }
 
-    return status;
+    return TRUE;
 }
 
 static DecorTexture *
@@ -261,19 +270,26 @@ decorGetTexture (CompScreen *screen,
 	return NULL;
     }
 
-    if (!bindPixmapToTexture (screen, &texture->texture, pixmap,
-			      width, height, depth))
+    if (manualCompositeManagement)
     {
-	finiTexture (screen, &texture->texture);
-	free (texture);
-	return NULL;
-    }
+	if (!bindPixmapToTexture (screen, &texture->texture, pixmap,
+				  width, height, depth))
+	{
+	    finiTexture (screen, &texture->texture);
+	    free (texture);
+	    return NULL;
+	}
 
-    if (!dd->opt[DECOR_DISPLAY_OPTION_MIPMAP].value.b)
-	texture->texture.mipmap = FALSE;
+	if (!dd->opt[DECOR_DISPLAY_OPTION_MIPMAP].value.b)
+	    texture->texture.mipmap = FALSE;
 
-    texture->damage = XDamageCreate (screen->display->display, pixmap,
-				     XDamageReportRawRectangles);
+	texture->damage = XDamageCreate (screen->display->display, pixmap,
+					 XDamageReportRawRectangles);
+    }
+    else
+    {
+	texture->damage = None;
+    }
 
     texture->refCount = 1;
     texture->pixmap   = pixmap;
@@ -410,7 +426,7 @@ decorCreateDecoration (CompScreen *screen,
 
     result = XGetWindowProperty (screen->display->display, id,
 				 decorAtom, 0L, 1024L, FALSE,
-				 XA_INTEGER, &actual, &format,
+				 0, &actual, &format,
 				 &n, &nleft, &data);
 
     if (result != Success || !n || !data)
@@ -532,19 +548,20 @@ decorReleaseDecoration (CompScreen *screen,
 }
 
 static void
-decorWindowUpdateDecoration (CompWindow *w)
+decorWindowUpdateDecoration (CompWindow *w,
+			     Atom       atom,
+			     int        type)
 {
     Decoration *decoration;
 
-    DECOR_DISPLAY (w->screen->display);
     DECOR_WINDOW (w);
 
-    decoration = decorCreateDecoration (w->screen, w->id, dd->winDecorAtom);
+    decoration = decorCreateDecoration (w->screen, w->id, atom);
 
-    if (dw->decor)
-	decorReleaseDecoration (w->screen, dw->decor);
+    if (dw->decor[type])
+	decorReleaseDecoration (w->screen, dw->decor[type]);
 
-    dw->decor = decoration;
+    dw->decor[type] = decoration;
 }
 
 static WindowDecoration *
@@ -654,6 +671,9 @@ updateWindowDecorationScale (CompWindow *w)
     if (!wd)
 	return;
 
+    if (!manualCompositeManagement)
+	return;
+
     for (i = 0; i < wd->nQuad; i++)
     {
 	computeQuadBox (&wd->decor->quad[i], w->width, w->height,
@@ -712,6 +732,17 @@ decorWindowShiftY (CompWindow *w)
 }
 
 static Bool
+decorIsActiveWindow (CompWindow *w)
+{
+    for (; w->parent; w = w->parent)
+    	if (w->parent->redirectSubwindows || w->parent->substructureRedirect)
+	    if (w->parent->activeChild != w->id)
+		return FALSE;
+
+    return TRUE;
+}
+
+static Bool
 decorWindowUpdate (CompWindow *w,
 		   Bool	      allowDecoration)
 {
@@ -727,6 +758,9 @@ decorWindowUpdate (CompWindow *w,
     DECOR_SCREEN (w->screen);
     DECOR_WINDOW (w);
 
+    if (!w->parent)
+	return FALSE;
+
     wd = dw->wd;
     old = (wd) ? wd->decor : NULL;
 
@@ -742,6 +776,9 @@ decorWindowUpdate (CompWindow *w,
 	break;
     }
 
+    if (!GET_DECOR_WINDOW (w->parent, ds)->wmWin)
+	decorate = FALSE;
+
     if (w->attrib.override_redirect)
 	decorate = FALSE;
 
@@ -754,16 +791,16 @@ decorWindowUpdate (CompWindow *w,
 
     if (decorate)
     {
-	if (dw->decor && decorCheckSize (w, dw->decor))
+	decor = dw->decor[DECOR_NORMAL];
+	if (decorIsActiveWindow (w) && dw->decor[DECOR_ACTIVE])
+	    decor = dw->decor[DECOR_ACTIVE];
+		    
+	if (!decor || !decorCheckSize (w, decor))
 	{
-	    decor = dw->decor;
-	}
-	else
-	{
-	    if (w->id == w->screen->display->activeWindow)
-		decor = ds->decor[DECOR_ACTIVE];
+	    if (decorIsActiveWindow (w))
+		decor = GET_DECOR_WINDOW (w->parent, ds)->decor[DECOR_ACTIVE];
 	    else
-		decor = ds->decor[DECOR_NORMAL];
+		decor = GET_DECOR_WINDOW (w->parent, ds)->decor[DECOR_NORMAL];
 	}
     }
     else
@@ -772,7 +809,7 @@ decorWindowUpdate (CompWindow *w,
 	if (matchEval (match, w))
 	{
 	    if (w->region->numRects == 1)
-		decor = ds->decor[DECOR_BARE];
+		decor = GET_DECOR_WINDOW (w->parent, ds)->decor[DECOR_BARE];
 
 	    if (decor)
 	    {
@@ -782,7 +819,7 @@ decorWindowUpdate (CompWindow *w,
 	}
     }
 
-    if (!ds->dmWin || !allowDecoration)
+    if (!GET_DECOR_WINDOW (w->parent, ds)->dmWin || !allowDecoration)
 	decor = NULL;
 
     if (decor == old)
@@ -829,7 +866,7 @@ decorWindowUpdate (CompWindow *w,
 	moveDy = -oldShiftY;
     }
 
-    if (w->placed && !w->attrib.override_redirect && (moveDx || moveDy))
+    if (w->placed && w->managed && (moveDx || moveDy))
     {
 	XWindowChanges xwc;
 	unsigned int   mask = CWX | CWY;
@@ -860,20 +897,34 @@ decorWindowUpdate (CompWindow *w,
 }
 
 static void
-decorCheckForDmOnScreen (CompScreen *s,
-			 Bool	    updateWindows)
+decorWindowUpdateTree (CompWindow *ancestor,
+		       Bool       allowDecoration)
+{
+    CompWindow *w;
+
+    w = ancestor;
+    do {
+	decorWindowUpdate (w, allowDecoration);
+    } while ((w = walkDepthFirst (w)) && w != ancestor);
+}
+
+static void
+decorCheckForDm (CompWindow *w,
+		 Bool	    updateWindows)
 {
+    CompScreen    *s = w->screen;
     CompDisplay   *d = s->display;
     Atom	  actual;
     int		  result, format;
     unsigned long n, left;
     unsigned char *data;
     Window	  dmWin = None;
+    Window	  wmWin = w->supportingWmCheckWindow;
 
     DECOR_DISPLAY (s->display);
-    DECOR_SCREEN (s);
+    DECOR_WINDOW (w);
 
-    result = XGetWindowProperty (d->display, s->root,
+    result = XGetWindowProperty (d->display, w->id,
 				 dd->supportingDmCheckAtom, 0L, 1L, FALSE,
 				 XA_WINDOW, &actual, &format,
 				 &n, &left, &data);
@@ -893,46 +944,58 @@ decorCheckForDmOnScreen (CompScreen *s,
 	    dmWin = None;
     }
 
-    if (dmWin != ds->dmWin)
+    if (dmWin != dw->dmWin)
     {
-	CompWindow *w;
+	CompWindow *c;
 	int	   i;
 
 	if (dmWin)
 	{
 	    for (i = 0; i < DECOR_NUM; i++)
-		ds->decor[i] =
-		    decorCreateDecoration (s, s->root, dd->decorAtom[i]);
+		dw->decor[i] = decorCreateDecoration (s,
+						      w->id,
+						      dd->decorAtom[i]);
 	}
 	else
 	{
+	    DECOR_SCREEN (w->screen);
+
 	    for (i = 0; i < DECOR_NUM; i++)
 	    {
-		if (ds->decor[i])
+		if (dw->decor[i])
 		{
-		    decorReleaseDecoration (s, ds->decor[i]);
-		    ds->decor[i] = 0;
+		    decorReleaseDecoration (s, dw->decor[i]);
+		    dw->decor[i] = 0;
 		}
 	    }
 
-	    for (w = s->windows; w; w = w->next)
+	    for (c = w->windows; c; c = c->next)
 	    {
-		DECOR_WINDOW (w);
+		DecorWindow *dc = GET_DECOR_WINDOW (c, ds);
 
-		if (dw->decor)
+		for (i = 0; i < DECOR_NUM; i++)
 		{
-		    decorReleaseDecoration (s, dw->decor);
-		    dw->decor = 0;
+		    if (dc->decor[i])
+		    {
+			decorReleaseDecoration (s, dc->decor[i]);
+			dc->decor[i] = 0;
+		    }
 		}
 	    }
 	}
+    }
 
-	ds->dmWin = dmWin;
+    if ((wmWin != dw->wmWin) || (dmWin != dw->dmWin))
+    {
+	dw->wmWin = wmWin;
+	dw->dmWin = dmWin;
 
 	if (updateWindows)
 	{
-	    for (w = s->windows; w; w = w->next)
-		decorWindowUpdate (w, TRUE);
+	    CompWindow *c;
+
+	    for (c = w->windows; c; c = c->next)
+		decorWindowUpdate (c, TRUE);
 	}
     }
 }
@@ -941,7 +1004,6 @@ static void
 decorHandleEvent (CompDisplay *d,
 		  XEvent      *event)
 {
-    Window     activeWindow = d->activeWindow;
     CompWindow *w;
 
     DECOR_DISPLAY (d);
@@ -949,12 +1011,16 @@ decorHandleEvent (CompDisplay *d,
     switch (event->type) {
     case DestroyNotify:
 	w = findWindowAtDisplay (d, event->xdestroywindow.window);
-	if (w)
+	if (w && (w = w->parent))
 	{
-	    DECOR_SCREEN (w->screen);
+	    DECOR_WINDOW (w);
 
-	    if (w->id == ds->dmWin)
-		decorCheckForDmOnScreen (w->screen, TRUE);
+	    if (w->supportingWmCheckWindow == event->xdestroywindow.window)
+		getSupportingWmCheck (w);
+
+	    if (event->xdestroywindow.window == dw->wmWin ||
+		event->xdestroywindow.window == dw->dmWin)
+		decorCheckForDm (w, TRUE);
 	}
 	break;
     case MapRequest:
@@ -982,7 +1048,7 @@ decorHandleEvent (CompDisplay *d,
 		    {
 			ds = GET_DECOR_SCREEN (s, dd);
 
-			for (w = s->windows; w; w = w->next)
+			for (w = s->root.windows; w; w = walkDepthFirst (w))
 			{
 			    if (w->shaded || w->mapNum)
 			    {
@@ -1004,25 +1070,47 @@ decorHandleEvent (CompDisplay *d,
     (*d->handleEvent) (d, event);
     WRAP (dd, d, handleEvent, decorHandleEvent);
 
-    if (d->activeWindow != activeWindow)
-    {
-	w = findWindowAtDisplay (d, activeWindow);
-	if (w)
-	    decorWindowUpdate (w, TRUE);
-
-	w = findWindowAtDisplay (d, d->activeWindow);
-	if (w)
-	    decorWindowUpdate (w, TRUE);
-    }
-
     switch (event->type) {
+    case FocusIn:
+	if (event->xfocus.mode != NotifyGrab)
+	{
+	    w = findTopLevelWindowAtDisplay (d, event->xfocus.window);
+	    if (w && w->managed && (w = w->parent))
+	    {
+		CompWindow *c;
+
+		for (c = w->windows; c; c = c->next)
+		    if (c->id == w->previousActiveChild ||
+			c->id == w->activeChild)
+			decorWindowUpdateTree (c, TRUE);
+	    }
+	}
+	break;
     case PropertyNotify:
-	if (event->xproperty.atom == dd->winDecorAtom)
+	if (event->xproperty.atom == d->winActiveAtom)
+	{
+	    w = findWindowAtDisplay (d, event->xproperty.window);
+	    if (w)
+	    {	
+		if (!w->substructureRedirect)
+		{
+		    CompWindow *c;
+
+		    for (c = w->windows; c; c = c->next)
+			if (c->id == w->previousActiveChild ||
+			    c->id == w->activeChild)
+			    decorWindowUpdateTree (c, TRUE);
+		}
+	    }
+	}
+	else if (event->xproperty.atom == dd->winDecorAtom)
 	{
 	    w = findWindowAtDisplay (d, event->xproperty.window);
 	    if (w)
 	    {
-		decorWindowUpdateDecoration (w);
+		decorWindowUpdateDecoration (w,
+					     dd->winDecorAtom,
+					     DECOR_NORMAL);
 		decorWindowUpdate (w, TRUE);
 	    }
 	}
@@ -1034,14 +1122,13 @@ decorHandleEvent (CompDisplay *d,
 	}
 	else
 	{
-	    CompScreen *s;
-
-	    s = findScreenAtDisplay (d, event->xproperty.window);
-	    if (s)
+	    w = findWindowAtDisplay (d, event->xproperty.window);
+	    if (w)
 	    {
-		if (event->xproperty.atom == dd->supportingDmCheckAtom)
+		if (event->xproperty.atom == d->supportingWmCheckAtom ||
+		    event->xproperty.atom == dd->supportingDmCheckAtom)
 		{
-		    decorCheckForDmOnScreen (s, TRUE);
+		    decorCheckForDm (w, TRUE);
 		}
 		else
 		{
@@ -1051,17 +1138,23 @@ decorHandleEvent (CompDisplay *d,
 		    {
 			if (event->xproperty.atom == dd->decorAtom[i])
 			{
-			    DECOR_SCREEN (s);
+			    DECOR_WINDOW (w);
 
-			    if (ds->decor[i])
-				decorReleaseDecoration (s, ds->decor[i]);
+			    decorWindowUpdateDecoration (w,
+							 dd->decorAtom[i],
+							 i);
 
-			    ds->decor[i] =
-				decorCreateDecoration (s, s->root,
-						       dd->decorAtom[i]);
+			    if (dw->dmWin)
+			    {
+				CompWindow *c;
 
-			    for (w = s->windows; w; w = w->next)
+				for (c = w->windows; c; c = c->next)
+				    decorWindowUpdate (c, TRUE);
+			    }
+			    else
+			    {
 				decorWindowUpdate (w, TRUE);
+			    }
 			}
 		    }
 		}
@@ -1132,10 +1225,11 @@ decorStartDecorator (void *closure)
 
     DECOR_DISPLAY (s->display);
     DECOR_SCREEN (s);
+    DECOR_WINDOW ((&s->root));
 
     ds->decoratorStartHandle = 0;
 
-    if (!ds->dmWin)
+    if (!dw->dmWin)
 	runCommand (s, dd->opt[DECOR_DISPLAY_OPTION_COMMAND].value.s);
 
     return FALSE;
@@ -1175,10 +1269,14 @@ decorSetDisplayOption (CompPlugin      *plugin,
 
 	    for (s = display->screens; s; s = s->next)
 	    {
+		DECOR_WINDOW ((&s->root));
 		DECOR_SCREEN (s);
 
-		if (!ds->dmWin)
-		    runCommand (s, o->value.s);
+		if (!dw->dmWin && !ds->decoratorStartHandle)
+		    ds->decoratorStartHandle =
+			compAddTimeout (0, -1,
+					decorStartDecorator,
+					s);
 	    }
 
 	    return TRUE;
@@ -1221,11 +1319,9 @@ decorSetDisplayOption (CompPlugin      *plugin,
 	if (compSetMatchOption (o, value))
 	{
 	    CompScreen *s;
-	    CompWindow *w;
 
 	    for (s = display->screens; s; s = s->next)
-		for (w = s->windows; w; w = w->next)
-		    decorWindowUpdate (w, TRUE);
+		decorWindowUpdateTree (&s->root, TRUE);
 	}
 	break;
     default:
@@ -1246,7 +1342,7 @@ decorWindowMoveNotify (CompWindow *w,
     DECOR_SCREEN (w->screen);
     DECOR_WINDOW (w);
 
-    if (dw->wd)
+    if (dw->wd && w->parent && w->parent->redirectSubwindows)
     {
 	WindowDecoration *wd = dw->wd;
 	int		 i;
@@ -1291,15 +1387,21 @@ decorWindowResizeNotify (CompWindow *w,
     DECOR_SCREEN (w->screen);
     DECOR_WINDOW (w);
 
-    /* FIXME: we should not need a timer for calling decorWindowUpdate,
-       and only call updateWindowDecorationScale if decorWindowUpdate
-       returns FALSE. Unfortunately, decorWindowUpdate may call
-       updateWindowOutputExtents, which may call WindowResizeNotify. As
-       we never should call a wrapped function that's currently
-       processed, we need the timer for the moment. updateWindowOutputExtents
-       should be fixed so that it does not emit a resize notification. */
-    dw->resizeUpdateHandle = compAddTimeout (0, 0, decorResizeUpdateTimeout, w);
-    updateWindowDecorationScale (w);
+    if (w->parent && w->parent->redirectSubwindows)
+    {
+	/* FIXME: we should not need a timer for calling decorWindowUpdate,
+	   and only call updateWindowDecorationScale if decorWindowUpdate
+	   returns FALSE. Unfortunately, decorWindowUpdate may call
+	   updateWindowOutputExtents, which may call WindowResizeNotify. As
+	   we never should call a wrapped function that's currently
+	   processed, we need the timer for the moment.
+	   updateWindowOutputExtents should be fixed so that it does not
+	   emit a resize notification. */
+	if (!dw->resizeUpdateHandle)
+	    dw->resizeUpdateHandle =
+		compAddTimeout (0, 0, decorResizeUpdateTimeout, w);
+	updateWindowDecorationScale (w);
+    }
 
     UNWRAP (ds, w->screen, windowResizeNotify);
     (*w->screen->windowResizeNotify) (w, dx, dy, dwidth, dheight);
@@ -1343,7 +1445,7 @@ decorMatchPropertyChanged (CompDisplay *d,
 }
 
 static void
-decorWindowAdd (CompScreen *s,
+decorWindowAdd (CompObject *parent,
 		CompWindow *w)
 {
     if (w->shaded || w->attrib.map_state == IsViewable)
@@ -1351,7 +1453,7 @@ decorWindowAdd (CompScreen *s,
 }
 
 static void
-decorWindowRemove (CompScreen *s,
+decorWindowRemove (CompObject *parent,
 		   CompWindow *w)
 {
     if (!w->destroyed)
@@ -1536,9 +1638,6 @@ decorInitScreen (CompPlugin *p,
 	return FALSE;
     }
 
-    memset (ds->decor, 0, sizeof (ds->decor));
-
-    ds->dmWin                = None;
     ds->decoratorStartHandle = 0;
 
     WRAP (ds, s, drawWindow, decorDrawWindow);
@@ -1550,12 +1649,6 @@ decorInitScreen (CompPlugin *p,
 
     s->base.privates[dd->screenPrivateIndex].ptr = ds;
 
-    decorCheckForDmOnScreen (s, FALSE);
-
-    if (!ds->dmWin)
-	ds->decoratorStartHandle = compAddTimeout (0, -1,
-						   decorStartDecorator, s);
-
     return TRUE;
 }
 
@@ -1563,14 +1656,8 @@ static void
 decorFiniScreen (CompPlugin *p,
 		 CompScreen *s)
 {
-    int	i;
-
     DECOR_SCREEN (s);
 
-    for (i = 0; i < DECOR_NUM; i++)
-	if (ds->decor[i])
-	    decorReleaseDecoration (s, ds->decor[i]);
-
     if (ds->decoratorStartHandle)
 	compRemoveTimeout (ds->decoratorStartHandle);
 
@@ -1591,6 +1678,7 @@ decorInitWindow (CompPlugin *p,
 		 CompWindow *w)
 {
     DecorWindow *dw;
+    int         i;
 
     DECOR_SCREEN (w->screen);
 
@@ -1598,18 +1686,46 @@ decorInitWindow (CompPlugin *p,
     if (!dw)
 	return FALSE;
 
-    dw->wd    = NULL;
-    dw->decor = NULL;
+    dw->wmWin = None;
+    dw->dmWin = None;
+    
+    dw->wd = NULL;
+
+    for (i = 0; i < DECOR_NUM; i++)
+	dw->decor[i] = 0;
 
     dw->resizeUpdateHandle = 0;
 
     w->base.privates[ds->windowPrivateIndex].ptr = dw;
 
-    if (!w->attrib.override_redirect)
-	decorWindowUpdateDecoration (w);
+    decorCheckForDm (w, FALSE);
+
+    if (w->parent)
+    {
+	if (!w->attrib.override_redirect)
+	{
+	    DECOR_DISPLAY (w->screen->display);
+
+	    decorWindowUpdateDecoration (w,
+					 dd->winDecorAtom,
+					 DECOR_NORMAL);
+	    decorWindowUpdateDecoration (w,
+					 dd->decorAtom[DECOR_ACTIVE],
+					 DECOR_ACTIVE);
+	}
+    }
+    else
+    {
+	DECOR_SCREEN (w->screen);
+
+	if (!dw->dmWin && !ds->decoratorStartHandle)
+	    ds->decoratorStartHandle = compAddTimeout (0, -1,
+						       decorStartDecorator,
+						       w->screen);
+    }
 
     if (w->base.parent)
-	decorWindowAdd (w->screen, w);
+	decorWindowAdd (w->base.parent, w);
 
     return TRUE;
 }
@@ -1618,19 +1734,22 @@ static void
 decorFiniWindow (CompPlugin *p,
 		 CompWindow *w)
 {
+    int i;
+
     DECOR_WINDOW (w);
 
     if (dw->resizeUpdateHandle)
 	compRemoveTimeout (dw->resizeUpdateHandle);
 
     if (w->base.parent)
-	decorWindowRemove (w->screen, w);
+	decorWindowRemove (w->base.parent, w);
 
     if (dw->wd)
 	destroyWindowDecoration (w->screen, dw->wd);
 
-    if (dw->decor)
-	decorReleaseDecoration (w->screen, dw->decor);
+    for (i = 0; i < DECOR_NUM; i++)
+	if (dw->decor[i])
+	    decorReleaseDecoration (w->screen, dw->decor[i]);
 
     free (dw);
 }
diff --git a/plugins/fade.c b/plugins/fade.c
index a30deef..7526750 100644
--- a/plugins/fade.c
+++ b/plugins/fade.c
@@ -196,16 +196,16 @@ fadePreparePaintScreen (CompScreen *s,
 	if (steps < 12)
 	    steps = 12;
 
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = walkDepthFirst (w))
 	{
 	    FadeWindow *fw = GET_FADE_WINDOW (w, fs);
+
 	    fw->steps    = steps;
 	    fw->fadeTime = 0;
-	}
-
+	}	
 	break;
     case FADE_MODE_CONSTANTTIME:
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = walkDepthFirst (w))
 	{
 	    FadeWindow *fw = GET_FADE_WINDOW (w, fs);
 
@@ -221,7 +221,6 @@ fadePreparePaintScreen (CompScreen *s,
 		fw->steps = 0;
 	    }
 	}
-	
 	break;
     }
 
@@ -569,7 +568,7 @@ fadeHandleEvent (CompDisplay *d,
 			option = FADE_SCREEN_OPTION_FULLSCREEN_VISUAL_BELL;
 			if (fs->opt[option].value.b)
 			{
-			    for (w = s->windows; w; w = w->next)
+			    for (w = s->root.windows; w; w = w->next)
 			    {
 				if (w->destroyed)
 				    continue;
@@ -731,7 +730,8 @@ fadeInitDisplay (CompPlugin  *p,
 {
     FadeDisplay *fd;
 
-    if (!checkPluginABI ("core", CORE_ABIVERSION))
+    if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+	!checkPluginABI ("glx",  CORE_ABIVERSION))
 	return FALSE;
 
     fd = malloc (sizeof (FadeDisplay));
diff --git a/plugins/gconf.c b/plugins/gconf.c
index 8d365e0..98094d8 100644
--- a/plugins/gconf.c
+++ b/plugins/gconf.c
@@ -691,22 +691,23 @@ gconfKeyChanged (GConfClient *client,
 }
 
 static void
-gconfSendGLibNotify (CompDisplay *d)
+gconfSendGLibNotify (CompScreen *s)
 {
-    Display *dpy = d->display;
-    XEvent  xev;
+    CompDisplay *d = s->display;
+    Display     *dpy = d->display;
+    XEvent      xev;
 
     xev.xclient.type    = ClientMessage;
     xev.xclient.display = dpy;
     xev.xclient.format  = 32;
 
     xev.xclient.message_type = XInternAtom (dpy, "_COMPIZ_GLIB_NOTIFY", 0);
-    xev.xclient.window	     = d->screens->root;
+    xev.xclient.window	     = s->root.id;
 
     memset (xev.xclient.data.l, 0, sizeof (xev.xclient.data.l));
 
     XSendEvent (dpy,
-		d->screens->root,
+		s->root.id,
 		FALSE,
 		SubstructureRedirectMask | SubstructureNotifyMask,
 		&xev);
@@ -767,10 +768,10 @@ gconfFiniCore (CompPlugin *p,
 }
 
 static Bool
-gconfInitDisplay (CompPlugin  *p,
-		  CompDisplay *d)
+gconfInitScreen (CompPlugin *p,
+		 CompScreen *s)
 {
-    gconfSendGLibNotify (d);
+    gconfSendGLibNotify (s);
 
     return TRUE;
 }
@@ -781,7 +782,8 @@ gconfInitObject (CompPlugin *p,
 {
     static InitPluginObjectProc dispTab[] = {
 	(InitPluginObjectProc) gconfInitCore,
-	(InitPluginObjectProc) gconfInitDisplay
+	(InitPluginObjectProc) NULL,
+	(InitPluginObjectProc) gconfInitScreen
     };
 
     RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
diff --git a/plugins/glx.c b/plugins/glx.c
new file mode 100644
index 0000000..5bf6274
--- /dev/null
+++ b/plugins/glx.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright © 2008 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <compiz-core.h>
+
+static CompMetadata glxMetadata;
+
+static CompOption *
+glxGetDisplayOptions (CompPlugin  *plugin,
+		      CompDisplay *display,
+		      int	  *count)
+{
+    *count = 1;
+    return &display->opt[COMP_DISPLAY_OPTION_ABI];
+}
+
+static Bool
+glxInitDisplay (CompPlugin  *p,
+		CompDisplay *d)
+{
+    int error, event;
+
+    if (!checkPluginABI ("core", CORE_ABIVERSION))
+	return FALSE;
+
+    if (!glXQueryExtension (d->display, &error, &event))
+    {
+	compLogMessage (p->vTable->name, CompLogLevelError,
+			"GLX extension is not available");
+	return FALSE;
+    }
+
+    if (manualCompositeManagement)
+	return TRUE;
+
+    if (d->screens)
+    {
+	compLogMessage (p->vTable->name, CompLogLevelError,
+			"%s plugin must be loaded before screens are "
+			"initialize", p->vTable->name);
+	return FALSE;
+    }
+
+    manualCompositeManagement = TRUE;
+
+    return TRUE;
+}
+
+static CompBool
+glxInitObject (CompPlugin *p,
+	       CompObject *o)
+{
+    static InitPluginObjectProc dispTab[] = {
+	(InitPluginObjectProc) 0, /* InitCore */
+	(InitPluginObjectProc) glxInitDisplay
+    };
+
+    RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
+}
+
+static CompOption *
+glxGetObjectOptions (CompPlugin *plugin,
+		    CompObject *object,
+		    int	       *count)
+{
+    static GetPluginObjectOptionsProc dispTab[] = {
+	(GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
+	(GetPluginObjectOptionsProc) glxGetDisplayOptions
+    };
+
+    RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
+		     (void *) (*count = 0), (plugin, object, count));
+}
+
+static Bool
+glxInit (CompPlugin *p)
+{
+    if (!compInitPluginMetadataFromInfo (&glxMetadata, p->vTable->name,
+					 0, 0, 0, 0))
+	return FALSE;
+
+    compAddMetadataFromFile (&glxMetadata, p->vTable->name);
+
+    return TRUE;
+}
+
+static void
+glxFini (CompPlugin *p)
+{
+    compFiniMetadata (&glxMetadata);
+}
+
+static CompMetadata *
+glxGetMetadata (CompPlugin *plugin)
+{
+    return &glxMetadata;
+}
+
+CompPluginVTable glxVTable = {
+    "glx",
+    glxGetMetadata,
+    glxInit,
+    glxFini,
+    glxInitObject,
+    0, /* FiniObject */
+    glxGetObjectOptions,
+    0  /* SetObjectOption */
+};
+
+CompPluginVTable *
+getCompPluginInfo20070830 (void)
+{
+    return &glxVTable;
+}
diff --git a/plugins/minimize.c b/plugins/minimize.c
index eb82370..901c29c 100644
--- a/plugins/minimize.c
+++ b/plugins/minimize.c
@@ -312,7 +312,7 @@ minPreparePaintScreen (CompScreen *s,
 	{
 	    ms->moreAdjust = 0;
 
-	    for (w = s->windows; w; w = w->next)
+	    for (w = s->root.windows; w; w = w->next)
 	    {
 		MIN_WINDOW (w);
 
@@ -395,7 +395,7 @@ minPreparePaintScreen (CompScreen *s,
 
 	if (ms->moreAdjust)
 	{
-	    for (w = s->windows; w; w = w->next)
+	    for (w = s->root.windows; w; w = w->next)
 	    {
 		MIN_WINDOW (w);
 
@@ -431,7 +431,7 @@ minDonePaintScreen (CompScreen *s)
 	CompWindow *w;
 	int	   h;
 
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = w->next)
 	{
 	    MIN_WINDOW (w);
 
@@ -762,7 +762,9 @@ minInitDisplay (CompPlugin  *p,
 {
     MinDisplay *md;
 
-    if (!checkPluginABI ("core", CORE_ABIVERSION))
+    if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+	!checkPluginABI ("wm",   CORE_ABIVERSION) ||
+	!checkPluginABI ("glx",  CORE_ABIVERSION))
 	return FALSE;
 
     md = malloc (sizeof (MinDisplay));
diff --git a/plugins/move.c b/plugins/move.c
index 32fb456..d66f17a 100644
--- a/plugins/move.c
+++ b/plugins/move.c
@@ -28,8 +28,10 @@
 #include <string.h>
 
 #include <X11/cursorfont.h>
+#include <X11/Xatom.h>
 
 #include <compiz-core.h>
+#include <decoration.h>
 
 static CompMetadata moveMetadata;
 
@@ -51,6 +53,11 @@ struct _MoveKeys {
 #define SNAP_BACK 20
 #define SNAP_OFF  100
 
+typedef struct _MoveBox {
+    decor_point_t p1;
+    decor_point_t p2;
+} MoveBox;
+
 static int displayPrivateIndex;
 
 #define MOVE_DISPLAY_OPTION_INITIATE_BUTTON   0
@@ -76,12 +83,17 @@ typedef struct _MoveDisplay {
     int        status;
     KeyCode    key[NUM_KEYS];
 
+    Atom moveAtom;
+    Atom moveNotifyAtom;
+
     int releaseButton;
 
     GLushort moveOpacity;
 } MoveDisplay;
 
 typedef struct _MoveScreen {
+    int windowPrivateIndex;
+
     PaintWindowProc paintWindow;
 
     int grabIndex;
@@ -94,6 +106,12 @@ typedef struct _MoveScreen {
     int	snapBackY;
 } MoveScreen;
 
+typedef struct _MoveWindow {
+    int     button;
+    MoveBox *box;
+    int     nBox;
+} MoveWindow;
+
 #define GET_MOVE_DISPLAY(d)					  \
     ((MoveDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
 
@@ -106,8 +124,106 @@ typedef struct _MoveScreen {
 #define MOVE_SCREEN(s)						        \
     MoveScreen *ms = GET_MOVE_SCREEN (s, GET_MOVE_DISPLAY (s->display))
 
+#define GET_MOVE_WINDOW(w, ms)					      \
+    ((MoveWindow *) (w)->base.privates[(ms)->windowPrivateIndex].ptr)
+
+#define MOVE_WINDOW(w)					     \
+    MoveWindow *mw = GET_MOVE_WINDOW  (w,		     \
+		     GET_MOVE_SCREEN  (w->screen,	     \
+		     GET_MOVE_DISPLAY (w->screen->display)))
+
+
 #define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
 
+
+static Bool
+movePointInBoxes (int     x,
+		  int     y,
+		  MoveBox *box,
+		  int	  nBox,
+		  int	  width,
+		  int	  height)
+{
+    int x0, y0, x1, y1;
+
+    while (nBox--)
+    {
+	decor_apply_gravity (box->p1.gravity, box->p1.x, box->p1.y,
+			     width, height,
+			     &x0, &y0);
+
+	decor_apply_gravity (box->p2.gravity, box->p2.x, box->p2.y,
+			     width, height,
+			     &x1, &y1);
+
+	if (x >= x0 && x < x1 && y >= y0 && y < y1)
+	    return TRUE;
+
+	box++;
+    }
+
+    return FALSE;
+}
+
+static void
+moveWindowUpdate (CompWindow *w)
+{
+    Atom	  actual;
+    int		  result, format;
+    unsigned long n, left;
+    unsigned char *propData;
+    MoveBox	  *box = NULL;
+    int		  nBox = 0;
+
+    MOVE_DISPLAY (w->screen->display);
+    MOVE_WINDOW (w);
+
+    result = XGetWindowProperty (w->screen->display->display, w->id,
+				 md->moveAtom, 0L, 8192L, FALSE,
+				 XA_INTEGER, &actual, &format,
+				 &n, &left, &propData);
+
+    if (result == Success && n && propData)
+    {
+	if (n >= 2)
+	{
+	    long *data = (long *) propData;
+
+	    mw->button = data[1];
+
+	    nBox = (n - 2) / 6;
+	    if (nBox)
+	    {
+		box = malloc (sizeof (MoveBox) * nBox);
+		if (box)
+		{
+		    int i;
+
+		    data += 2;
+
+		    for (i = 0; i < nBox; i++)
+		    {
+			box[i].p1.gravity = *data++;
+			box[i].p1.x       = *data++;
+			box[i].p1.y       = *data++;
+			box[i].p2.gravity = *data++;
+			box[i].p2.x       = *data++;
+			box[i].p2.y       = *data++;
+		    }
+		}
+	    }
+	}
+
+	XFree (propData);
+    }
+
+    if (mw->box)
+	free (mw->box);
+
+    mw->box  = box;
+    mw->nBox = nBox;
+}
+
 static Bool
 moveInitiate (CompDisplay     *d,
 	      CompAction      *action,
@@ -125,18 +241,25 @@ moveInitiate (CompDisplay     *d,
     w = findWindowAtDisplay (d, xid);
     if (w && (w->actions & CompWindowActionMoveMask))
     {
+	CompWindow   *p;
 	XRectangle   workArea;
 	unsigned int mods;
 	int          x, y, button;
 
 	MOVE_SCREEN (w->screen);
 
+	x = w->width / 2;
+	y = w->height / 2;
+	for (p = w; p; p = p->parent)
+	{
+	    x += p->attrib.x;
+	    y += p->attrib.y;
+	}
+
 	mods = getIntOptionNamed (option, nOption, "modifiers", 0);
 
-	x = getIntOptionNamed (option, nOption, "x",
-			       w->attrib.x + (w->width / 2));
-	y = getIntOptionNamed (option, nOption, "y",
-			       w->attrib.y + (w->height / 2));
+	x = getIntOptionNamed (option, nOption, "x", x);
+	y = getIntOptionNamed (option, nOption, "y", y);
 
 	button = getIntOptionNamed (option, nOption, "button", -1);
 
@@ -192,6 +315,12 @@ moveInitiate (CompDisplay     *d,
 
 	    md->releaseButton = button;
 
+	    for (p = w->parent; p; p = p->parent)
+	    {
+		x -= p->attrib.x;
+		y -= p->attrib.y;
+	    }
+
 	    (w->screen->windowGrabNotify) (w, x, y, mods,
 					   CompWindowGrabMoveMask |
 					   CompWindowGrabButtonMask);
@@ -208,6 +337,8 @@ moveInitiate (CompDisplay     *d,
 
 	    if (md->moveOpacity != OPAQUE)
 		addWindowDamage (w);
+
+	    return TRUE;
 	}
     }
 
@@ -298,7 +429,7 @@ moveGetYConstrainRegion (CompScreen *s)
 	getWorkareaForOutput (s, i, &workArea);
 	extents = s->outputDev[i].region.extents;
 
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = w->next)
 	{
 	    if (!w->mapNum)
 		continue;
@@ -534,12 +665,18 @@ moveHandleMotionEvent (CompScreen *s,
 
 	if (dx || dy)
 	{
+	    Bool lazy = md->opt[MOVE_DISPLAY_OPTION_LAZY_POSITIONING].value.b;
+
 	    moveWindow (w,
 			wX + dx - w->attrib.x,
 			wY + dy - w->attrib.y,
 			TRUE, FALSE);
 
-	    if (md->opt[MOVE_DISPLAY_OPTION_LAZY_POSITIONING].value.b)
+	    /* lazy positioning cannot be used without manual compositing */
+	    if (!manualCompositeManagement)
+		lazy = FALSE;
+
+	    if (lazy)
 	    {
 		/* FIXME: This form of lazy positioning is broken and should
 		   be replaced asap. Current code exists just to avoid a
@@ -563,11 +700,85 @@ moveHandleEvent (CompDisplay *d,
 		 XEvent      *event)
 {
     CompScreen *s;
+    CompWindow *w;
 
     MOVE_DISPLAY (d);
 
     switch (event->type) {
     case ButtonPress:
+	w = findClientWindowAtDisplay (d, event->xbutton.window);
+	if (w)
+	{
+	    CompWindow *p;
+	    int        option = MOVE_DISPLAY_OPTION_INITIATE_BUTTON;
+	    int        x = event->xbutton.x_root;
+	    int        y = event->xbutton.y_root;
+
+	    MOVE_WINDOW (w);
+
+	    for (p = w; p; p = p->parent)
+	    {
+		x -= p->attrib.x;
+		y -= p->attrib.y;
+	    }
+
+	    if (event->xbutton.button == mw->button &&
+		movePointInBoxes (x, y,
+				  mw->box, mw->nBox,
+				  w->width, w->height))
+	    {
+		CompOption o[5];
+
+		o[0].type    = CompOptionTypeInt;
+		o[0].name    = "window";
+		o[0].value.i = w->id;
+
+		o[1].type    = CompOptionTypeInt;
+		o[1].name    = "modifiers";
+		o[1].value.i = event->xbutton.state;
+
+		o[2].type    = CompOptionTypeInt;
+		o[2].name    = "x";
+		o[2].value.i = event->xbutton.x_root;
+
+		o[3].type    = CompOptionTypeInt;
+		o[3].name    = "y";
+		o[3].value.i = event->xbutton.y_root;
+
+		o[4].type    = CompOptionTypeInt;
+		o[4].name    = "button";
+		o[4].value.i = event->xbutton.button;
+
+		if (moveInitiate (d,
+				  &md->opt[option].value.action,
+				  CompActionStateInitButton,
+				  o, 5))
+		{
+		    XEvent ev;
+		    int    mask = NoEventMask;
+
+		    if (!w->parent->substructureRedirect)
+			activateWindow (w);
+
+		    if (w->parent == &w->screen->root)
+			mask = SubstructureRedirectMask |
+			    SubstructureNotifyMask;
+
+		    ev.type		    = ClientMessage;
+		    ev.xclient.window	    = event->xbutton.subwindow;
+		    ev.xclient.message_type = md->moveNotifyAtom;
+		    ev.xclient.format	    = 32;
+		    ev.xclient.data.l[0]    = event->xbutton.button;
+		    ev.xclient.data.l[1]    = event->xbutton.x;
+		    ev.xclient.data.l[2]    = event->xbutton.y;
+		    ev.xclient.data.l[3]    = event->xbutton.time;
+		    ev.xclient.data.l[4]    = 0;
+
+		    XSendEvent (d->display, w->parent->id, FALSE, mask, &ev);
+		}
+	    }
+	}
+	break;
     case ButtonRelease:
 	s = findScreenAtDisplay (d, event->xbutton.root);
 	if (s)
@@ -626,8 +837,6 @@ moveHandleEvent (CompDisplay *d,
     case ClientMessage:
 	if (event->xclient.message_type == d->wmMoveResizeAtom)
 	{
-	    CompWindow *w;
-
 	    if (event->xclient.data.l[2] == WmMoveResizeMove ||
 		event->xclient.data.l[2] == WmMoveResizeMoveKeyboard)
 	    {
@@ -658,7 +867,7 @@ moveHandleEvent (CompDisplay *d,
 
 			option = MOVE_DISPLAY_OPTION_INITIATE_BUTTON;
 
-			XQueryPointer (d->display, w->screen->root,
+			XQueryPointer (d->display, w->screen->root.id,
 				       &root, &child, &xRoot, &yRoot,
 				       &i, &i, &mods);
 
@@ -709,6 +918,14 @@ moveHandleEvent (CompDisplay *d,
 		}
 	    }
 	}
+	else if (event->xclient.message_type == md->moveNotifyAtom)
+	{
+	    /* forward to owner */
+	    XSendEvent (d->display,
+			event->xclient.window,
+			FALSE, NoEventMask,
+			event);
+	}
 	break;
     case DestroyNotify:
 	if (md->w && md->w->id == event->xdestroywindow.window)
@@ -746,6 +963,18 @@ moveHandleEvent (CompDisplay *d,
     UNWRAP (md, d, handleEvent);
     (*d->handleEvent) (d, event);
     WRAP (md, d, handleEvent, moveHandleEvent);
+
+    if (event->type == PropertyNotify)
+    {
+	if (event->xproperty.atom == md->moveAtom)
+	{
+	    CompWindow *w;
+
+	    w = findWindowAtDisplay (d, event->xproperty.window);
+	    if (w)
+		moveWindowUpdate (w);
+	}
+    }
 }
 
 static Bool
@@ -876,6 +1105,13 @@ moveInitDisplay (CompPlugin  *p,
 	md->key[i] = XKeysymToKeycode (d->display,
 				       XStringToKeysym (mKeys[i].name));
 
+    md->moveAtom       = XInternAtom (d->display,
+				      "_COMPIZ_WM_WINDOW_MOVE_DECOR",
+				      0);
+    md->moveNotifyAtom = XInternAtom (d->display,
+				      "_COMPIZ_WM_WINDOW_MOVE_DECOR_NOTIFY",
+				      0);
+
     WRAP (md, d, handleEvent, moveHandleEvent);
 
     d->base.privates[displayPrivateIndex].ptr = md;
@@ -910,6 +1146,13 @@ moveInitScreen (CompPlugin *p,
     if (!ms)
 	return FALSE;
 
+    ms->windowPrivateIndex = allocateWindowPrivateIndex (s);
+    if (ms->windowPrivateIndex < 0)
+    {
+	free (ms);
+	return FALSE;
+    }
+
     ms->grabIndex = 0;
 
     ms->moveCursor = XCreateFontCursor (s->display->display, XC_fleur);
@@ -932,9 +1175,46 @@ moveFiniScreen (CompPlugin *p,
     if (ms->moveCursor)
 	XFreeCursor (s->display->display, ms->moveCursor);
 
+    freeWindowPrivateIndex (s, ms->windowPrivateIndex);
+
     free (ms);
 }
 
+static Bool
+moveInitWindow (CompPlugin *p,
+		CompWindow *w)
+{
+    MoveWindow *mw;
+
+    MOVE_SCREEN (w->screen);
+
+    mw = malloc (sizeof (MoveWindow));
+    if (!mw)
+	return FALSE;
+
+    mw->button = 0;
+    mw->box    = NULL;
+    mw->nBox   = 0;
+
+    w->base.privates[ms->windowPrivateIndex].ptr = mw;
+
+    moveWindowUpdate (w);
+
+    return TRUE;
+}
+
+static void
+moveFiniWindow (CompPlugin *p,
+		CompWindow *w)
+{
+    MOVE_WINDOW (w);
+
+    if (mw->box)
+	free (mw->box);
+
+    free (mw);
+}
+
 static CompBool
 moveInitObject (CompPlugin *p,
 		CompObject *o)
@@ -942,7 +1222,8 @@ moveInitObject (CompPlugin *p,
     static InitPluginObjectProc dispTab[] = {
 	(InitPluginObjectProc) 0, /* InitCore */
 	(InitPluginObjectProc) moveInitDisplay,
-	(InitPluginObjectProc) moveInitScreen
+	(InitPluginObjectProc) moveInitScreen,
+	(InitPluginObjectProc) moveInitWindow
     };
 
     RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
@@ -955,7 +1236,8 @@ moveFiniObject (CompPlugin *p,
     static FiniPluginObjectProc dispTab[] = {
 	(FiniPluginObjectProc) 0, /* FiniCore */
 	(FiniPluginObjectProc) moveFiniDisplay,
-	(FiniPluginObjectProc) moveFiniScreen
+	(FiniPluginObjectProc) moveFiniScreen,
+	(FiniPluginObjectProc) moveFiniWindow
     };
 
     DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
diff --git a/plugins/obs.c b/plugins/obs.c
index bec8136..d526772 100644
--- a/plugins/obs.c
+++ b/plugins/obs.c
@@ -75,7 +75,6 @@ typedef struct _ObsScreen
     int windowPrivateIndex;
 
     PaintWindowProc paintWindow;
-    DrawWindowProc  drawWindow;
 
     CompOption *stepOptions[MODIFIER_COUNT];
     CompOption *matchOptions[MODIFIER_COUNT];
@@ -210,76 +209,32 @@ obsPaintWindow (CompWindow              *w,
 		Region                  region,
 		unsigned int            mask)
 {
-    CompScreen *s = w->screen;
-    Bool       status;
+    WindowPaintAttrib wAttrib = *attrib;
+    CompScreen        *s = w->screen;
+    int               factor;
+    Bool              status;
 
     OBS_SCREEN (s);
     OBS_WINDOW (w);
 
-    if (ow->customFactor[MODIFIER_OPACITY] != 100)
-	mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
-
-    UNWRAP (os, s, paintWindow);
-    status = (*s->paintWindow) (w, attrib, transform, region, mask);
-    WRAP (os, s, paintWindow, obsPaintWindow);
-
-    return status;
-}
-
-/* Note: Normally plugins should wrap into PaintWindow to modify opacity,
-	 brightness and saturation. As some plugins bypass paintWindow when
-	 they draw windows and our custom values always need to be applied,
-	 we wrap into DrawWindow here */
-
-static Bool
-obsDrawWindow (CompWindow           *w,
-	       const CompTransform  *transform,
-	       const FragmentAttrib *attrib,
-	       Region               region,
-	       unsigned int         mask)
-{
-    CompScreen *s = w->screen;
-    Bool       hasCustomFactor = FALSE;
-    Bool       status;
-    int        i;
-
-    OBS_SCREEN (s);
-    OBS_WINDOW (w);
-
-    for (i = 0; i < MODIFIER_COUNT; i++)
-	if (ow->customFactor[i] != 100)
-	{
-	    hasCustomFactor = TRUE;
-	    break;
-	}
-
-    if (hasCustomFactor)
+    factor = ow->customFactor[MODIFIER_OPACITY];
+    if (factor != 100)
     {
-	FragmentAttrib fragment = *attrib;
-	int            factor;
-
-	factor = ow->customFactor[MODIFIER_OPACITY];
-	if (factor != 100)
-	    fragment.opacity = (int) fragment.opacity * factor / 100;
+	wAttrib.opacity = (int) wAttrib.opacity * factor / 100;
+	mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+    }
 
-	factor = ow->customFactor[MODIFIER_BRIGHTNESS];
-	if (factor != 100)
-	    fragment.brightness = (int) fragment.brightness * factor / 100;
+    factor = ow->customFactor[MODIFIER_BRIGHTNESS];
+    if (factor != 100)
+	wAttrib.brightness = (int) wAttrib.brightness * factor / 100;
 
-	factor = ow->customFactor[MODIFIER_SATURATION];
-	if (factor != 100)
-	    fragment.saturation = (int) fragment.saturation * factor / 100;
+    factor = ow->customFactor[MODIFIER_SATURATION];
+    if (factor != 100)
+	wAttrib.saturation = (int) wAttrib.saturation * factor / 100;
 
-	UNWRAP (os, s, drawWindow);
-	status = (*s->drawWindow) (w, transform, &fragment, region, mask);
-	WRAP (os, s, drawWindow, obsDrawWindow);
-    }
-    else
-    {
-	UNWRAP (os, s, drawWindow);
-	status = (*s->drawWindow) (w, transform, attrib, region, mask);
-	WRAP (os, s, drawWindow, obsDrawWindow);
-    }
+    UNWRAP (os, s, paintWindow);
+    status = (*s->paintWindow) (w, &wAttrib, transform, region, mask);
+    WRAP (os, s, paintWindow, obsPaintWindow);
 
     return status;
 }
@@ -299,7 +254,7 @@ obsMatchExpHandlerChanged (CompDisplay *d)
 
     /* match options are up to date after the call to matchExpHandlerChanged */
     for (s = d->screens; s; s = s->next)
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = w->next)
 	    for (i = 0; i < MODIFIER_COUNT; i++)
 		updatePaintModifier (w, i);
 }
@@ -386,7 +341,7 @@ obsSetScreenOption (CompPlugin      *p,
 		for (j = 0; j < o->value.list.nValue; j++)
 		    matchUpdate (s->display, &o->value.list.value[j].match);
 
-		for (w = s->windows; w; w = w->next)
+		for (w = s->root.windows; w; w = w->next)
 		    updatePaintModifier (w, i);
 
 		return TRUE;
@@ -398,7 +353,7 @@ obsSetScreenOption (CompPlugin      *p,
 	    {
 		CompWindow *w;
 
-		for (w = s->windows; w; w = w->next)
+		for (w = s->root.windows; w; w = w->next)
 		    updatePaintModifier (w, i);
 
 		return TRUE;
@@ -599,7 +554,6 @@ obsInitScreen (CompPlugin *p,
     s->base.privates[od->screenPrivateIndex].ptr = os;
 
     WRAP (os, s, paintWindow, obsPaintWindow);
-    WRAP (os, s, drawWindow, obsDrawWindow);
 
     return TRUE;
 }
@@ -611,7 +565,6 @@ obsFiniScreen (CompPlugin *p,
     OBS_SCREEN (s);
 
     UNWRAP (os, s, paintWindow);
-    UNWRAP (os, s, drawWindow);
 
     damageScreen (s);
     
diff --git a/plugins/place.c b/plugins/place.c
index 596a3a5..6c9a8e4 100644
--- a/plugins/place.c
+++ b/plugins/place.c
@@ -257,7 +257,7 @@ placeSendWindowMaximizationRequest (CompWindow *w)
     xev.xclient.data.l[3] = 0;
     xev.xclient.data.l[4] = 0;
 
-    XSendEvent (d->display, w->screen->root, FALSE,
+    XSendEvent (d->display, w->screen->root.id, FALSE,
 		SubstructureRedirectMask | SubstructureNotifyMask, &xev);
 }
 
@@ -681,7 +681,7 @@ placeCascade (CompWindow *w,
     unsigned int count = 0;
 
     /* get the total window count */
-    for (wi = w->screen->windows; wi; wi = wi->next)
+    for (wi = w->screen->root.windows; wi; wi = wi->next)
 	count++;
 
     windows = malloc (sizeof (CompWindow *) * count);
@@ -692,7 +692,7 @@ placeCascade (CompWindow *w,
      * as placed window, may be shaded - if shaded we pretend it isn't
      * for placement purposes)
      */
-    for (wi = w->screen->windows, count = 0; wi; wi = wi->next)
+    for (wi = w->screen->root.windows, count = 0; wi; wi = wi->next)
     {
 	if (!IS_PLACE_RELEVANT (wi, w))
 	    continue;
@@ -813,7 +813,7 @@ placeSmart (CompWindow *w,
 	    cyt = yTmp;
 	    cyb = yTmp + ch;
 
-	    for (wi = w->screen->windows; wi; wi = wi->next)
+	    for (wi = w->screen->root.windows; wi; wi = wi->next)
 	    {
 		if (!IS_PLACE_RELEVANT (wi, w))
 		    continue;
@@ -871,7 +871,7 @@ placeSmart (CompWindow *w,
 		possible -= cw;
 
 	    /* compare to the position of each client on the same desk */
-	    for (wi = w->screen->windows; wi; wi = wi->next)
+	    for (wi = w->screen->root.windows; wi; wi = wi->next)
 	    {
 		if (!IS_PLACE_RELEVANT (wi, w))
 		    continue;
@@ -906,7 +906,7 @@ placeSmart (CompWindow *w,
 		possible -= ch;
 
 	    /* test the position of each window on the desk */
-	    for (wi = w->screen->windows; wi; wi = wi->next)
+	    for (wi = w->screen->root.windows; wi; wi = wi->next)
 	    {
 		if (!IS_PLACE_RELEVANT (wi, w))
 		    continue;
@@ -1016,7 +1016,7 @@ placeGetPlacementOutput (CompWindow        *w,
 	{
 	    CompWindow *parent;
 
-	    parent = findWindowAtScreen (s, w->transientFor);
+	    parent = findSibling (w, w->transientFor);
 	    if (parent)
 		output = outputDeviceForWindow (parent);
 	}
@@ -1047,7 +1047,7 @@ placeGetPlacementOutput (CompWindow        *w,
 	    /* this means a server roundtrip, which kind of sucks; thus
 	       this code should be replaced as soon as we have software
 	       cursor rendering and thus have a cached pointer coordinate */
-	    if (XQueryPointer (s->display->display, s->root,
+	    if (XQueryPointer (s->display->display, s->root.id,
 			       &wDummy, &wDummy, &xPointer, &yPointer,
 			       &iDummy, &iDummy, &uiDummy))
 	    {
@@ -1085,21 +1085,31 @@ placeConstrainToWorkarea (CompWindow *w,
 			  int        *y)
 {
     CompWindowExtents extents;
+    int               delta;
 
     extents.left   = *x - w->input.left;
     extents.top    = *y - w->input.top;
     extents.right  = *x + w->serverWidth + w->input.right;
     extents.bottom = *y + w->serverHeight + w->input.bottom;
 
-    if (extents.left < workArea->x)
-	*x += workArea->x - extents.left;
-    else if (extents.right > workArea->x + workArea->width)
-	*x += workArea->x + workArea->width - extents.right;
+    delta = workArea->x + workArea->width - extents.right;
+    if (delta < 0)
+	extents.left += delta;
 
-    if (extents.top < workArea->y)
-	*y += workArea->y - extents.top;
-    else if (extents.bottom > workArea->y + workArea->height)
-	*y += workArea->y + workArea->height - extents.bottom;
+    delta = workArea->x - extents.left;
+    if (delta > 0)
+    	extents.left  += delta;
+
+    delta = workArea->y + workArea->height - extents.bottom;
+    if (delta < 0)
+	extents.top += delta;
+
+    delta = workArea->y - extents.top;
+    if (delta > 0)
+    	extents.top += delta;
+
+    *x = extents.left + w->input.left;
+    *y = extents.top  + w->input.top;
 }
 
 static Bool
@@ -1138,7 +1148,7 @@ placeDoWindowPlacement (CompWindow *w,
     {
 	CompWindow *parent;
 
-	parent = findWindowAtScreen (s, w->transientFor);
+	parent = findSibling (w, w->transientFor);
 	if (parent)
 	{
 	    /* center over parent horizontally */
@@ -1443,7 +1453,8 @@ placeInitDisplay (CompPlugin  *p,
 {
     PlaceDisplay *pd;
 
-    if (!checkPluginABI ("core", CORE_ABIVERSION))
+    if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+	!checkPluginABI ("wm",   CORE_ABIVERSION))
 	return FALSE;
 
     pd = malloc (sizeof (PlaceDisplay));
diff --git a/plugins/resize.c b/plugins/resize.c
index 5b8b12b..d2de79b 100644
--- a/plugins/resize.c
+++ b/plugins/resize.c
@@ -269,7 +269,7 @@ resizeSendResizeNotify (CompDisplay *d)
     xev.xclient.data.l[4] = 0;
 
     XSendEvent (d->display,
-		rd->w->screen->root,
+		rd->w->screen->root.id,
 		FALSE,
 		SubstructureRedirectMask | SubstructureNotifyMask,
 		&xev);
@@ -438,6 +438,10 @@ resizeInitiate (CompDisplay     *d,
 	    }
 	}
 
+	/* only normal resize mode can be used without manual compositing */
+	if (!manualCompositeManagement)
+	    rd->mode = RESIZE_MODE_NORMAL;
+
 	if (!rs->grabIndex)
 	{
 	    Cursor cursor;
@@ -900,7 +904,7 @@ resizeHandleEvent (CompDisplay *d,
 
 			option = RESIZE_DISPLAY_OPTION_INITIATE_BUTTON;
 
-			XQueryPointer (d->display, w->screen->root,
+			XQueryPointer (d->display, w->screen->root.id,
 				       &root, &child, &xRoot, &yRoot,
 				       &i, &i, &mods);
 
diff --git a/plugins/rotate.c b/plugins/rotate.c
index 8b76d4d..1369d62 100644
--- a/plugins/rotate.c
+++ b/plugins/rotate.c
@@ -368,7 +368,37 @@ rotatePreparePaintScreen (CompScreen *s,
 		    /* flag end of rotation */
 		    cs->rotationState = RotationNone;
 
-		    moveScreenViewport (s, tx, 0, TRUE);
+		    if (s->root.substructureRedirect)
+		    {
+			moveScreenViewport (s, tx, 0, TRUE);
+		    }
+		    else
+		    {
+			CompDisplay *d = s->display;
+			XEvent      xev;
+
+			xev.xclient.type    = ClientMessage;
+			xev.xclient.display = d->display;
+			xev.xclient.format  = 32;
+
+			xev.xclient.message_type = d->desktopViewportAtom;
+			xev.xclient.window	 = s->root.id;
+
+			xev.xclient.data.l[0] = (s->x - tx) * s->width;
+			xev.xclient.data.l[1] = s->y * s->height;
+			xev.xclient.data.l[2] = 0;
+			xev.xclient.data.l[3] = 0;
+			xev.xclient.data.l[4] = 0;
+
+			XSendEvent (s->display->display,
+				    s->root.id,
+				    FALSE,
+				    SubstructureRedirectMask |
+				    SubstructureNotifyMask,
+				    &xev);
+
+			moveScreenViewport (s, tx, 0, FALSE);
+		    }
 
 		    rs->xrot = 0.0f;
 		    rs->yrot = 0.0f;
@@ -680,7 +710,7 @@ rotateTerminate (CompDisplay     *d,
     {
 	ROTATE_SCREEN (s);
 
-	if (xid && s->root != xid)
+	if (xid && s->root.id != xid)
 	    continue;
 
 	if (rs->grabIndex)
@@ -750,7 +780,7 @@ rotate (CompDisplay     *d,
 
 	    o[2].type	 = CompOptionTypeInt;
 	    o[2].name	 = "root";
-	    o[2].value.i = s->root;
+	    o[2].value.i = s->root.id;
 
 	    rotateInitiate (d, NULL, 0, o, 3);
 	}
@@ -839,7 +869,7 @@ rotateWithWindow (CompDisplay     *d,
 
 	    o[2].type	 = CompOptionTypeInt;
 	    o[2].name	 = "root";
-	    o[2].value.i = s->root;
+	    o[2].value.i = s->root.id;
 
 	    rotateInitiate (d, NULL, 0, o, 3);
 	}
@@ -1014,7 +1044,7 @@ rotateFlipLeft (void *closure)
 
     o[2].type	 = CompOptionTypeInt;
     o[2].name	 = "root";
-    o[2].value.i = s->root;
+    o[2].value.i = s->root.id;
 
     o[3].type	 = CompOptionTypeInt;
     o[3].name	 = "direction";
@@ -1059,7 +1089,7 @@ rotateFlipRight (void *closure)
 
     o[2].type	 = CompOptionTypeInt;
     o[2].name	 = "root";
-    o[2].value.i = s->root;
+    o[2].value.i = s->root.id;
 
     o[3].type	 = CompOptionTypeInt;
     o[3].name	 = "direction";
@@ -1139,7 +1169,7 @@ rotateEdgeFlip (CompScreen      *s,
 
     o[2].type	 = CompOptionTypeInt;
     o[2].name	 = "root";
-    o[2].value.i = s->root;
+    o[2].value.i = s->root.id;
 
     o[3].type	 = CompOptionTypeInt;
     o[3].name	 = "direction";
@@ -1256,7 +1286,7 @@ rotateFlipTerminate (CompDisplay     *d,
     {
 	ROTATE_SCREEN (s);
 
-	if (xid && s->root != xid)
+	if (xid && s->root.id != xid)
 	    continue;
 
 	if (rs->rotateHandle)
@@ -1383,7 +1413,7 @@ rotateTo (CompDisplay     *d,
 
 	o[2].type    = CompOptionTypeInt;
 	o[2].name    = "root";
-	o[2].value.i = s->root;
+	o[2].value.i = s->root.id;
 
 	o[3].type    = CompOptionTypeInt;
 	o[3].name    = "direction";
@@ -1443,7 +1473,7 @@ rotateToWithWindow (CompDisplay     *d,
 
 	o[2].type    = CompOptionTypeInt;
 	o[2].name    = "root";
-	o[2].value.i = s->root;
+	o[2].value.i = s->root.id;
 
 	o[3].type    = CompOptionTypeInt;
 	o[3].name    = "direction";
@@ -1464,6 +1494,7 @@ rotateHandleEvent (CompDisplay *d,
 		   XEvent      *event)
 {
     CompScreen *s;
+    int        dx = 0;
 
     ROTATE_DISPLAY (d);
 
@@ -1512,13 +1543,14 @@ rotateHandleEvent (CompDisplay *d,
 	}
 	break;
     case ClientMessage:
+	if (!windowManagement)
+	    break;
+
 	if (event->xclient.message_type == d->desktopViewportAtom)
 	{
 	    s = findScreenAtDisplay (d, event->xclient.window);
 	    if (s)
 	    {
-		int dx;
-
 		ROTATE_SCREEN (s);
 
 		if (otherScreenGrabExist (s, "rotate", "switcher", "cube", 0))
@@ -1535,7 +1567,7 @@ rotateHandleEvent (CompDisplay *d,
 		    unsigned int ui;
 		    CompOption   o[4];
 
-		    XQueryPointer (d->display, s->root,
+		    XQueryPointer (d->display, s->root.id,
 				   &win, &win, &x, &y, &i, &i, &ui);
 
 		    if (dx * 2 > s->hsize)
@@ -1553,7 +1585,7 @@ rotateHandleEvent (CompDisplay *d,
 
 		    o[2].type	 = CompOptionTypeInt;
 		    o[2].name	 = "root";
-		    o[2].value.i = s->root;
+		    o[2].value.i = s->root.id;
 
 		    o[3].type	 = CompOptionTypeInt;
 		    o[3].name	 = "direction";
@@ -1570,6 +1602,29 @@ rotateHandleEvent (CompDisplay *d,
     UNWRAP (rd, d, handleEvent);
     (*d->handleEvent) (d, event);
     WRAP (rd, d, handleEvent, rotateHandleEvent);
+
+    switch (event->type) {
+    case ClientMessage:
+	if (!dx)
+	    break;
+
+	if (event->xclient.message_type == d->desktopViewportAtom)
+	{
+	    s = findScreenAtDisplay (d, event->xclient.window);
+	    if (s)
+	    {
+		ROTATE_SCREEN (s);
+
+		if (rs->moving)
+		{
+		    rs->moveTo   += (360.0f / s->hsize) * -dx;
+		    rs->baseXrot += (360.0f / s->hsize) * dx;
+		}
+	    }
+	}
+    default:
+	break;
+    }
 }
 
 static void
@@ -1596,7 +1651,7 @@ rotateActivateWindow (CompWindow *w)
 	    unsigned int ui;
 	    CompOption   o[5];
 
-	    XQueryPointer (s->display->display, s->root,
+	    XQueryPointer (s->display->display, s->root.id,
 			   &win, &win, &x, &y, &i, &i, &ui);
 
 	    if (dx * 2 > s->hsize)
@@ -1614,7 +1669,7 @@ rotateActivateWindow (CompWindow *w)
 
 	    o[2].type    = CompOptionTypeInt;
 	    o[2].name    = "root";
-	    o[2].value.i = s->root;
+	    o[2].value.i = s->root.id;
 
 	    o[3].type    = CompOptionTypeInt;
 	    o[3].name    = "direction";
diff --git a/plugins/scale.c b/plugins/scale.c
index 5b4df25..7046b17 100644
--- a/plugins/scale.c
+++ b/plugins/scale.c
@@ -151,7 +151,7 @@ scaleActivateEvent (CompScreen *s,
 
     o[0].type = CompOptionTypeInt;
     o[0].name = "root";
-    o[0].value.i = s->root;
+    o[0].value.i = s->root.id;
 
     o[1].type = CompOptionTypeBool;
     o[1].name = "active";
@@ -313,6 +313,9 @@ setScaledPaintAttributes (CompWindow        *w,
     SCALE_SCREEN (w->screen);
     SCALE_WINDOW (w);
 
+    if (w->parent != &w->screen->root)
+	return FALSE;
+
     if (sw->adjust || sw->slot)
     {
 	SCALE_DISPLAY (w->screen->display);
@@ -379,7 +382,12 @@ scalePaintWindow (CompWindow		  *w,
 	scaled = (*ss->setScaledPaintAttributes) (w, &sAttrib);
 
 	if (sw->adjust || sw->slot)
+	{
+	    if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
+		return FALSE;
+
 	    mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
+	}
 
 	UNWRAP (ss, s, paintWindow);
 	status = (*s->paintWindow) (w, &sAttrib, transform, region, mask);
@@ -387,16 +395,7 @@ scalePaintWindow (CompWindow		  *w,
 
 	if (scaled)
 	{
-	    FragmentAttrib fragment;
-	    CompTransform  wTransform = *transform;
-
-	    if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
-		return FALSE;
-
-	    initFragmentAttrib (&fragment, &w->lastPaint);
-
-	    if (w->alpha || fragment.opacity != OPAQUE)
-		mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+	    CompTransform wTransform = *transform;
 
 	    matrixTranslate (&wTransform, w->attrib.x, w->attrib.y, 0.0f);
 	    matrixScale (&wTransform, sw->scale, sw->scale, 1.0f);
@@ -405,13 +404,7 @@ scalePaintWindow (CompWindow		  *w,
 			     sw->ty / sw->scale - w->attrib.y,
 			     0.0f);
 
-	    glPushMatrix ();
-	    glLoadMatrixf (wTransform.m);
-
-	    (*s->drawWindow) (w, &wTransform, &fragment, region,
-			      mask | PAINT_WINDOW_TRANSFORMED_MASK);
-
-	    glPopMatrix ();
+	    drawTransformedWindowWithChildren (w, NULL, &wTransform);
 
 	    (*ss->scalePaintDecoration) (w, &sAttrib, transform, region, mask);
 	}
@@ -742,7 +735,7 @@ layoutThumbs (CompScreen *s)
     ss->nWindows = 0;
 
     /* add windows scale list, top most window first */
-    for (w = s->reverseWindows; w; w = w->prev)
+    for (w = s->root.reverseWindows; w; w = w->prev)
     {
 	SCALE_WINDOW (w);
 
@@ -897,7 +890,7 @@ scalePreparePaintScreen (CompScreen *s,
 	{
 	    ss->moreAdjust = 0;
 
-	    for (w = s->windows; w; w = w->next)
+	    for (w = s->root.windows; w; w = w->next)
 	    {
 		SCALE_WINDOW (w);
 
@@ -962,7 +955,7 @@ scaleCheckForWindowAt (CompScreen *s,
     int        x1, y1, x2, y2;
     CompWindow *w;
 
-    for (w = s->reverseWindows; w; w = w->prev)
+    for (w = s->root.reverseWindows; w; w = w->prev)
     {
 	SCALE_WINDOW (w);
 
@@ -1028,7 +1021,7 @@ scaleTerminate (CompDisplay     *d,
     {
 	SCALE_SCREEN (s);
 
-	if (xid && s->root != xid)
+	if (xid && s->root.id != xid)
 	    continue;
 
 	if (ss->grab)
@@ -1048,7 +1041,7 @@ scaleTerminate (CompDisplay     *d,
 	    {
 		CompWindow *w;
 
-		for (w = s->windows; w; w = w->next)
+		for (w = s->root.windows; w; w = w->next)
 		{
 		    SCALE_WINDOW (w);
 
@@ -1102,7 +1095,7 @@ scaleEnsureDndRedirectWindow (CompScreen *s)
 	attr.override_redirect = TRUE;
 
 	ss->dndTarget = XCreateWindow (s->display->display,
-				       s->root,
+				       s->root.id,
 				       0, 0, 1, 1, 0,
 				       CopyFromParent,
 				       InputOnly,
@@ -1420,7 +1413,7 @@ scaleMoveFocusWindow (CompScreen *s,
 	    cx = (sw->slot->x1 + sw->slot->x2) / 2;
 	    cy = (sw->slot->y1 + sw->slot->y2) / 2;
 
-	    for (w = s->windows; w; w = w->next)
+	    for (w = s->root.windows; w; w = w->next)
 	    {
 		slot = GET_SCALE_WINDOW (w, ss)->slot;
 		if (!slot)
@@ -1453,7 +1446,7 @@ scaleMoveFocusWindow (CompScreen *s,
 
 	SCALE_SCREEN (s);
 
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = w->next)
 	{
 	    if (!GET_SCALE_WINDOW (w, ss)->slot)
 		continue;
@@ -1548,7 +1541,7 @@ scaleWindowRemove (CompDisplay *d,
 
 			o.type    = CompOptionTypeInt;
 			o.name    = "root";
-			o.value.i = w->screen->root;
+			o.value.i = w->screen->root.id;
 
 			opt = SCALE_DISPLAY_OPTION_INITIATE_EDGE;
 			action = &sd->opt[opt].value.action;
@@ -1592,7 +1585,7 @@ scaleHoverTimeout (void *closure)
 
 	o.type    = CompOptionTypeInt;
 	o.name    = "root";
-	o.value.i = s->root;
+	o.value.i = s->root.id;
 
 	option = SCALE_DISPLAY_OPTION_INITIATE_EDGE;
 	scaleTerminate (s->display, &sd->opt[option].value.action, 0, &o, 1);
@@ -1649,7 +1642,7 @@ scaleHandleEvent (CompDisplay *d,
 
 		    o.type    = CompOptionTypeInt;
 		    o.name    = "root";
-		    o.value.i = s->root;
+		    o.value.i = s->root.id;
 
 		    if (scaleSelectWindowAt (s,
 					     event->xbutton.x_root,
@@ -1788,7 +1781,7 @@ scaleHandleEvent (CompDisplay *d,
 
 		    o.type    = CompOptionTypeInt;
 		    o.name    = "root";
-		    o.value.i = w->screen->root;
+		    o.value.i = w->screen->root.id;
 
 		    option = SCALE_DISPLAY_OPTION_INITIATE_EDGE;
 		    scaleTerminate (d, &sd->opt[option].value.action,
@@ -1926,7 +1919,8 @@ scaleInitDisplay (CompPlugin  *p,
 {
     ScaleDisplay *sd;
 
-    if (!checkPluginABI ("core", CORE_ABIVERSION))
+    if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+	!checkPluginABI ("glx",  CORE_ABIVERSION))
 	return FALSE;
 
     sd = malloc (sizeof (ScaleDisplay));
diff --git a/plugins/screenshot.c b/plugins/screenshot.c
index 74f44ba..899b2f0 100644
--- a/plugins/screenshot.c
+++ b/plugins/screenshot.c
@@ -122,7 +122,7 @@ shotTerminate (CompDisplay     *d,
     {
 	SHOT_SCREEN (s);
 
-	if (xid && s->root != xid)
+	if (xid && s->root.id != xid)
 	    continue;
 
 	if (ss->grabIndex)
@@ -436,7 +436,8 @@ shotInitDisplay (CompPlugin  *p,
 {
     ShotDisplay *sd;
 
-    if (!checkPluginABI ("core", CORE_ABIVERSION))
+    if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+	!checkPluginABI ("glx",  CORE_ABIVERSION))
 	return FALSE;
 
     sd = malloc (sizeof (ShotDisplay));
diff --git a/plugins/svg.c b/plugins/svg.c
index bd39174..0ebebbf 100644
--- a/plugins/svg.c
+++ b/plugins/svg.c
@@ -178,7 +178,7 @@ initSvgTexture (CompWindow *w,
 	XGetWindowAttributes (s->display->display, w->id, &attr);
 
 	depth = attr.depth;
-	texture->pixmap = XCreatePixmap (s->display->display, s->root,
+	texture->pixmap = XCreatePixmap (s->display->display, s->root.id,
 					 width, height, depth);
 
 	if (!bindPixmapToTexture (s,
@@ -795,7 +795,8 @@ svgInitDisplay (CompPlugin  *p,
     SvgDisplay *sd;
     CompScreen *s;
 
-    if (!checkPluginABI ("core", CORE_ABIVERSION))
+    if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+	!checkPluginABI ("glx",  CORE_ABIVERSION))
 	return FALSE;
 
     sd = malloc (sizeof (SvgDisplay));
diff --git a/plugins/switcher.c b/plugins/switcher.c
index 13be8ad..b0acfec 100644
--- a/plugins/switcher.c
+++ b/plugins/switcher.c
@@ -328,7 +328,7 @@ switchActivateEvent (CompScreen *s,
 
     o[0].type = CompOptionTypeInt;
     o[0].name = "root";
-    o[0].value.i = s->root;
+    o[0].value.i = s->root.id;
 
     o[1].type = CompOptionTypeBool;
     o[1].name = "active";
@@ -415,7 +415,7 @@ switchCreateWindowList (CompScreen *s,
 
     ss->nWindows = 0;
 
-    for (w = s->windows; w; w = w->next)
+    for (w = s->root.windows; w; w = w->next)
     {
 	if (isSwitchWin (w))
 	    switchAddWindowToList (s, w);
@@ -475,7 +475,7 @@ switchToWindow (CompScreen *s,
 	    xev.xclient.format = 32;
 
 	    xev.xclient.message_type = s->display->desktopViewportAtom;
-	    xev.xclient.window = s->root;
+	    xev.xclient.window = s->root.id;
 
 	    xev.xclient.data.l[0] = x * s->width;
 	    xev.xclient.data.l[1] = y * s->height;
@@ -483,7 +483,7 @@ switchToWindow (CompScreen *s,
 	    xev.xclient.data.l[3] = 0;
 	    xev.xclient.data.l[4] = 0;
 
-	    XSendEvent (s->display->display, s->root, FALSE,
+	    XSendEvent (s->display->display, s->root.id, FALSE,
 			SubstructureRedirectMask | SubstructureNotifyMask,
 			&xev);
 	}
@@ -532,7 +532,7 @@ switchCountWindows (CompScreen *s)
     CompWindow *w;
     int	       count = 0;
 
-    for (w = s->windows; w && count < 5; w = w->next)
+    for (w = s->root.windows; w && count < 5; w = w->next)
 	if (isSwitchWin (w))
 	    count++;
 
@@ -600,7 +600,7 @@ switchInitiate (CompScreen            *s,
     if (count < 1)
 	return;
 
-    if (!ss->popupWindow && showPopup)
+    if (!ss->popupWindow && showPopup && s->root.substructureRedirect)
     {
 	Display		     *dpy = s->display->display;
 	XSizeHints	     xsh;
@@ -635,11 +635,11 @@ switchInitiate (CompScreen            *s,
 
 	attr.background_pixel = 0;
 	attr.border_pixel     = 0;
-	attr.colormap	      = XCreateColormap (dpy, s->root, visual,
+	attr.colormap	      = XCreateColormap (dpy, s->root.id, visual,
 						 AllocNone);
 
 	ss->popupWindow =
-	    XCreateWindow (dpy, s->root,
+	    XCreateWindow (dpy, s->root.id,
 			   s->width  / 2 - xsh.width / 2,
 			   s->height / 2 - xsh.height / 2,
 			   xsh.width, xsh.height, 0,
@@ -727,7 +727,7 @@ switchTerminate (CompDisplay     *d,
     {
 	SWITCH_SCREEN (s);
 
-	if (xid && s->root != xid)
+	if (xid && s->root.id != xid)
 	    continue;
 
 	if (ss->grabIndex)
@@ -989,7 +989,7 @@ switchWindowRemove (CompDisplay *d,
 
 	    o.type    = CompOptionTypeInt;
 	    o.name    = "root";
-	    o.value.i = w->screen->root;
+	    o.value.i = w->screen->root.id;
 
 	    switchTerminate (d, NULL, 0, &o, 1);
 	    return;
@@ -1322,8 +1322,9 @@ switchPaintOutput (CompScreen		   *s,
 		for (w = zoomed->prev; w && w->id <= 1; w = w->prev);
 		zoomedAbove = (w) ? w->id : None;
 
-		unhookWindowFromScreen (s, zoomed);
-		insertWindowIntoScreen (s, zoomed, s->reverseWindows->id);
+		unhookWindow (zoomed->parent, zoomed);
+		insertWindow (zoomed->parent, zoomed,
+			      zoomed->parent->reverseWindows->id);
 	    }
 	}
 	else
@@ -1356,8 +1357,8 @@ switchPaintOutput (CompScreen		   *s,
 
 	if (zoomed)
 	{
-	    unhookWindowFromScreen (s, zoomed);
-	    insertWindowIntoScreen (s, zoomed, zoomedAbove);
+	    unhookWindow (zoomed->parent, zoomed);
+	    insertWindow (zoomed->parent, zoomed, zoomedAbove);
 	}
 
 	if (switcher)
@@ -1445,7 +1446,6 @@ switchPaintThumb (CompWindow		  *w,
     if (w->texture->pixmap)
     {
 	AddWindowGeometryProc oldAddWindowGeometry;
-	FragmentAttrib	      fragment;
 	CompTransform	      wTransform = *transform;
 	int		      ww, wh;
 
@@ -1481,11 +1481,6 @@ switchPaintThumb (CompWindow		  *w,
 	sAttrib.xTranslate = wx - w->attrib.x + w->input.left * sAttrib.xScale;
 	sAttrib.yTranslate = wy - w->attrib.y + w->input.top  * sAttrib.yScale;
 
-	initFragmentAttrib (&fragment, &sAttrib);
-
-	if (w->alpha || fragment.opacity != OPAQUE)
-	    mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
-
 	matrixTranslate (&wTransform, w->attrib.x, w->attrib.y, 0.0f);
 	matrixScale (&wTransform, sAttrib.xScale, sAttrib.yScale, 1.0f);
 	matrixTranslate (&wTransform,
@@ -1493,20 +1488,14 @@ switchPaintThumb (CompWindow		  *w,
 			 sAttrib.yTranslate / sAttrib.yScale - w->attrib.y,
 			 0.0f);
 
-	glPushMatrix ();
-	glLoadMatrixf (wTransform.m);
-
 	/* XXX: replacing the addWindowGeometry function like this is
 	   very ugly but necessary until the vertex stage has been made
 	   fully pluggable. */
 	oldAddWindowGeometry = w->screen->addWindowGeometry;
 	w->screen->addWindowGeometry = addWindowGeometry;
-	(w->screen->drawWindow) (w, &wTransform, &fragment, &infiniteRegion,
-				 mask);
+	drawTransformedWindowWithChildren (w, &sAttrib, &wTransform);
 	w->screen->addWindowGeometry = oldAddWindowGeometry;
 
-	glPopMatrix ();
-
 	if (ss->opt[SWITCH_SCREEN_OPTION_ICON].value.b)
 	{
 	    icon = getWindowIcon (w, ICON_SIZE, ICON_SIZE);
@@ -1634,6 +1623,12 @@ switchPaintWindow (CompWindow		   *w,
 	status = (*s->paintWindow) (w, attrib, transform, region, mask);
 	WRAP (ss, s, paintWindow, switchPaintWindow);
 
+	if (w->attrib.map_state != IsViewable)
+	    return status;
+
+	if (!w->damaged)
+	    return status;
+
 	if (!(mask & PAINT_WINDOW_TRANSFORMED_MASK) && region->numRects == 0)
 	    return TRUE;
 
@@ -1708,44 +1703,53 @@ switchPaintWindow (CompWindow		   *w,
 	status = (*s->paintWindow) (w, attrib, transform, region, mask);
 	WRAP (ss, s, paintWindow, switchPaintWindow);
     }
-    else if (ss->switching)
+    else if (w->parent == &s->root)
     {
-	WindowPaintAttrib sAttrib = *attrib;
-	GLuint            value;
-
-	value = ss->opt[SWITCH_SCREEN_OPTION_SATURATION].value.i;
-	if (value != 100)
-	    sAttrib.saturation = sAttrib.saturation * value / 100;
+	if (ss->switching)
+	{
+	    WindowPaintAttrib sAttrib = *attrib;
+	    GLuint            value;
 
-	value = ss->opt[SWITCH_SCREEN_OPTION_BRIGHTNESS].value.i;
-	if (value != 100)
-	    sAttrib.brightness = sAttrib.brightness * value / 100;
+	    value = ss->opt[SWITCH_SCREEN_OPTION_SATURATION].value.i;
+	    if (value != 100)
+		sAttrib.saturation = sAttrib.saturation * value / 100;
 
-	if (w->wmType & ~(CompWindowTypeDockMask | CompWindowTypeDesktopMask))
-	{
-	    value = ss->opt[SWITCH_SCREEN_OPTION_OPACITY].value.i;
+	    value = ss->opt[SWITCH_SCREEN_OPTION_BRIGHTNESS].value.i;
 	    if (value != 100)
-		sAttrib.opacity = sAttrib.opacity * value / 100;
-	}
+		sAttrib.brightness = sAttrib.brightness * value / 100;
 
-	if (ss->opt[SWITCH_SCREEN_OPTION_BRINGTOFRONT].value.b &&
-	    w->id == ss->zoomedWindow)
-	    zoomType = ZOOMED_WINDOW_MASK;
+	    if (w->wmType & ~(CompWindowTypeDockMask | CompWindowTypeDesktopMask))
+	    {
+		value = ss->opt[SWITCH_SCREEN_OPTION_OPACITY].value.i;
+		if (value != 100)
+		    sAttrib.opacity = sAttrib.opacity * value / 100;
+	    }
 
-	if (!(ss->zoomMask & zoomType))
-	    return (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) ?
-		FALSE : TRUE;
+	    if (ss->opt[SWITCH_SCREEN_OPTION_BRINGTOFRONT].value.b &&
+		w->id == ss->zoomedWindow)
+		zoomType = ZOOMED_WINDOW_MASK;
 
-	UNWRAP (ss, s, paintWindow);
-	status = (*s->paintWindow) (w, &sAttrib, transform, region, mask);
-	WRAP (ss, s, paintWindow, switchPaintWindow);
+	    if (!(ss->zoomMask & zoomType))
+		return (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) ?
+		    FALSE : TRUE;
+
+	    UNWRAP (ss, s, paintWindow);
+	    status = (*s->paintWindow) (w, &sAttrib, transform, region, mask);
+	    WRAP (ss, s, paintWindow, switchPaintWindow);
+	}
+	else
+	{
+	    if (!(ss->zoomMask & zoomType))
+		return (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) ?
+		    FALSE : TRUE;
+
+	    UNWRAP (ss, s, paintWindow);
+	    status = (*s->paintWindow) (w, attrib, transform, region, mask);
+	    WRAP (ss, s, paintWindow, switchPaintWindow);
+	}
     }
     else
     {
-	if (!(ss->zoomMask & zoomType))
-	    return (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) ?
-		FALSE : TRUE;
-
 	UNWRAP (ss, s, paintWindow);
 	status = (*s->paintWindow) (w, attrib, transform, region, mask);
 	WRAP (ss, s, paintWindow, switchPaintWindow);
@@ -1843,7 +1847,8 @@ switchInitDisplay (CompPlugin  *p,
 {
     SwitchDisplay *sd;
 
-    if (!checkPluginABI ("core", CORE_ABIVERSION))
+    if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+	!checkPluginABI ("glx",  CORE_ABIVERSION))
 	return FALSE;
 
     sd = malloc (sizeof (SwitchDisplay));
diff --git a/plugins/video.c b/plugins/video.c
index b95eb6b..6364e08 100644
--- a/plugins/video.c
+++ b/plugins/video.c
@@ -190,7 +190,7 @@ videoSetSupportedHint (CompScreen *s)
 	    data[n++] = vd->videoImageFormatAtom[i];
     }
 
-    XChangeProperty (s->display->display, s->root,
+    XChangeProperty (s->display->display, s->root.id,
 		     vd->videoSupportedAtom, XA_ATOM, 32,
 		     PropModeReplace, (unsigned char *) data, n);
 }
@@ -939,7 +939,7 @@ videoHandleEvent (CompDisplay *d,
 		    {
 			vs = GET_VIDEO_SCREEN (s, vd);
 
-			for (w = s->windows; w; w = w->next)
+			for (w = s->root.windows; w; w = w->next)
 			{
 			    if (w->shaded || w->mapNum)
 			    {
@@ -1045,7 +1045,8 @@ videoInitDisplay (CompPlugin  *p,
 {
     VideoDisplay *vd;
 
-    if (!checkPluginABI ("core", CORE_ABIVERSION))
+    if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+	!checkPluginABI ("glx",  CORE_ABIVERSION))
 	return FALSE;
 
     vd = malloc (sizeof (VideoDisplay));
@@ -1164,7 +1165,7 @@ videoFiniScreen (CompPlugin *p,
 
     freeWindowPrivateIndex (s, vs->windowPrivateIndex);
 
-    XDeleteProperty (s->display->display, s->root, vd->videoSupportedAtom);
+    XDeleteProperty (s->display->display, s->root.id, vd->videoSupportedAtom);
 
     videoDestroyFragmentFunctions (s, &vs->yv12Functions);
 
diff --git a/plugins/water.c b/plugins/water.c
index ef2f191..485060d 100644
--- a/plugins/water.c
+++ b/plugins/water.c
@@ -1040,6 +1040,7 @@ waterDrawWindowTexture (CompWindow	     *w,
 	Bool	       lighting = w->screen->lighting;
 	int	       param, function, unit;
 	GLfloat	       plane[4];
+	CompWindow     *p;
 
 	WATER_DISPLAY (w->screen->display);
 
@@ -1049,6 +1050,17 @@ waterDrawWindowTexture (CompWindow	     *w,
 	function = getBumpMapFragmentFunction (w->screen, texture, unit, param);
 	if (function)
 	{
+	    float dx = ws->tx / (GLfloat) w->screen->width;
+	    float dy = ws->ty / (GLfloat) w->screen->height;
+	    int   wx = 0;
+	    int   wy = 0;
+
+	    for (p = w->parent; p; p = p->parent)
+	    {
+		wx += p->attrib.x;
+		wy += p->attrib.y;
+	    }
+
 	    addFragmentFunction (&fa, function);
 
 	    screenLighting (w->screen, TRUE);
@@ -1058,16 +1070,16 @@ waterDrawWindowTexture (CompWindow	     *w,
 	    glBindTexture (ws->target, ws->texture[TINDEX (ws, 0)]);
 
 	    plane[1] = plane[2] = 0.0f;
-	    plane[0] = ws->tx / (GLfloat) w->screen->width;
-	    plane[3] = 0.0f;
+	    plane[0] = dx;
+	    plane[3] = dx * wx;
 
 	    glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
 	    glTexGenfv (GL_S, GL_EYE_PLANE, plane);
 	    glEnable (GL_TEXTURE_GEN_S);
 
 	    plane[0] = plane[2] = 0.0f;
-	    plane[1] = ws->ty / (GLfloat) w->screen->height;
-	    plane[3] = 0.0f;
+	    plane[1] = dy;
+	    plane[3] = dy * wy;
 
 	    glTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
 	    glTexGenfv (GL_T, GL_EYE_PLANE, plane);
@@ -1268,7 +1280,8 @@ waterInitiate (CompDisplay     *d,
 	if (!ws->grabIndex)
 	    ws->grabIndex = pushScreenGrab (s, None, "water");
 
-	if (XQueryPointer (d->display, s->root, &root, &child, &xRoot, &yRoot,
+	if (XQueryPointer (d->display, s->root.id, &root, &child,
+			   &xRoot, &yRoot,
 			   &i, &i, &ui))
 	{
 	    XPoint p;
@@ -1594,7 +1607,8 @@ waterInitDisplay (CompPlugin  *p,
 {
     WaterDisplay *wd;
 
-    if (!checkPluginABI ("core", CORE_ABIVERSION))
+    if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+	!checkPluginABI ("glx",  CORE_ABIVERSION))
 	return FALSE;
 
     wd = malloc (sizeof (WaterDisplay));
diff --git a/plugins/wm.c b/plugins/wm.c
new file mode 100644
index 0000000..e797c36
--- /dev/null
+++ b/plugins/wm.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright © 2008 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <compiz-core.h>
+
+static CompMetadata wmMetadata;
+
+static CompOption *
+wmGetDisplayOptions (CompPlugin  *plugin,
+		     CompDisplay *display,
+		     int	 *count)
+{
+    *count = 1;
+    return &display->opt[COMP_DISPLAY_OPTION_ABI];
+}
+
+static Bool
+wmInitDisplay (CompPlugin  *p,
+	       CompDisplay *d)
+{
+    if (!checkPluginABI ("core", CORE_ABIVERSION))
+	return FALSE;
+
+    if (windowManagement)
+	return TRUE;
+
+    if (d->screens)
+    {
+	compLogMessage (p->vTable->name, CompLogLevelError,
+			"%s plugin must be loaded before screens are "
+			"initialize", p->vTable->name);
+	return FALSE;
+    }
+
+    windowManagement = TRUE;
+
+    return TRUE;
+}
+
+static CompBool
+wmInitObject (CompPlugin *p,
+	      CompObject *o)
+{
+    static InitPluginObjectProc dispTab[] = {
+	(InitPluginObjectProc) 0, /* InitCore */
+	(InitPluginObjectProc) wmInitDisplay
+    };
+
+    RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
+}
+
+static CompOption *
+wmGetObjectOptions (CompPlugin *plugin,
+		    CompObject *object,
+		    int	       *count)
+{
+    static GetPluginObjectOptionsProc dispTab[] = {
+	(GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
+	(GetPluginObjectOptionsProc) wmGetDisplayOptions
+    };
+
+    RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
+		     (void *) (*count = 0), (plugin, object, count));
+}
+
+static Bool
+wmInit (CompPlugin *p)
+{
+    if (!compInitPluginMetadataFromInfo (&wmMetadata, p->vTable->name,
+					 0, 0, 0, 0))
+	return FALSE;
+
+    compAddMetadataFromFile (&wmMetadata, p->vTable->name);
+
+    return TRUE;
+}
+
+static void
+wmFini (CompPlugin *p)
+{
+    compFiniMetadata (&wmMetadata);
+}
+
+static CompMetadata *
+wmGetMetadata (CompPlugin *plugin)
+{
+    return &wmMetadata;
+}
+
+CompPluginVTable wmVTable = {
+    "wm",
+    wmGetMetadata,
+    wmInit,
+    wmFini,
+    wmInitObject,
+    0, /* FiniObject */
+    wmGetObjectOptions,
+    0  /* SetObjectOption */
+};
+
+CompPluginVTable *
+getCompPluginInfo20070830 (void)
+{
+    return &wmVTable;
+}
diff --git a/plugins/wobbly.c b/plugins/wobbly.c
index d05c983..1beacb0 100644
--- a/plugins/wobbly.c
+++ b/plugins/wobbly.c
@@ -161,6 +161,12 @@ typedef struct _WobblyScreen {
     unsigned int grabMask;
     CompWindow	 *grabWindow;
     Bool         moveWindow;
+
+    Model *model;
+    int   x;
+    int   y;
+    float width;
+    float height;
 } WobblyScreen;
 
 #define WobblyInitial  (1L << 0)
@@ -270,7 +276,7 @@ findNextWestEdge (CompWindow *w,
 
 	v1 = w->screen->outputDev[output].region.extents.x1;
 
-	for (p = w->screen->windows; p; p = p->next)
+	for (p = w->parent->windows; p; p = p->next)
 	{
 	    if (w == p)
 		continue;
@@ -375,7 +381,7 @@ findNextEastEdge (CompWindow *w,
 
 	v1 = w->screen->outputDev[output].region.extents.x2;
 
-	for (p = w->screen->windows; p; p = p->next)
+	for (p = w->parent->windows; p; p = p->next)
 	{
 	    if (w == p)
 		continue;
@@ -480,7 +486,7 @@ findNextNorthEdge (CompWindow *w,
 
 	v1 = w->screen->outputDev[output].region.extents.y1;
 
-	for (p = w->screen->windows; p; p = p->next)
+	for (p = w->parent->windows; p; p = p->next)
 	{
 	    if (w == p)
 		continue;
@@ -583,7 +589,7 @@ findNextSouthEdge (CompWindow *w,
 
 	v1 = w->screen->outputDev[output].region.extents.y2;
 
-	for (p = w->screen->windows; p; p = p->next)
+	for (p = w->parent->windows; p; p = p->next)
 	{
 	    if (w == p)
 		continue;
@@ -1656,7 +1662,8 @@ wobblyPreparePaintScreen (CompScreen *s,
 	springK  = ws->opt[WOBBLY_SCREEN_OPTION_SPRING_K].value.f;
 
 	ws->wobblyWindows = 0;
-	for (w = s->windows; w; w = w->next)
+
+	for (w = s->root.windows; w; w = walkDepthFirst (w))
 	{
 	    ww = GET_WOBBLY_WINDOW (w, ws);
 
@@ -1806,19 +1813,17 @@ wobblyAddWindowGeometry (CompWindow *w,
 			 Region     region,
 			 Region     clip)
 {
-    WOBBLY_WINDOW (w);
     WOBBLY_SCREEN (w->screen);
 
-    if (ww->wobbly)
+    if (ws->model)
     {
-	BoxPtr   pClip;
-	int      nClip, nVertices, nIndices;
+	BoxPtr   pClip, pBox;
+	int      nClip, nBox, nVertices, nIndices;
 	GLushort *i;
 	GLfloat  *v;
 	int      x1, y1, x2, y2;
-	float    width, height;
 	float    deformedX, deformedY;
-	int      x, y, iw, ih, wx, wy;
+	int      x, y, iw, ih;
 	int      vSize, it;
 	int      gridW, gridH;
 	Bool     rect = TRUE;
@@ -1832,21 +1837,16 @@ wobblyAddWindowGeometry (CompWindow *w,
 	    }
 	}
 
-	wx     = WIN_X (w);
-	wy     = WIN_Y (w);
-	width  = WIN_W (w);
-	height = WIN_H (w);
-
-	gridW = width / ws->opt[WOBBLY_SCREEN_OPTION_GRID_RESOLUTION].value.i;
+	gridW = ws->width / ws->opt[WOBBLY_SCREEN_OPTION_GRID_RESOLUTION].value.i;
 	if (gridW < ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i)
 	    gridW = ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i;
 
-	gridH = height / ws->opt[WOBBLY_SCREEN_OPTION_GRID_RESOLUTION].value.i;
+	gridH = ws->height / ws->opt[WOBBLY_SCREEN_OPTION_GRID_RESOLUTION].value.i;
 	if (gridH < ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i)
 	    gridH = ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i;
 
-	nClip = region->numRects;
-	pClip = region->rects;
+	nBox = region->numRects;
+	pBox = region->rects;
 
 	w->texUnits = nMatrix;
 
@@ -1858,96 +1858,117 @@ wobblyAddWindowGeometry (CompWindow *w,
 	v = w->vertices + (nVertices * vSize);
 	i = w->indices  + nIndices;
 
-	while (nClip--)
+	while (nBox--)
 	{
-	    x1 = pClip->x1;
-	    y1 = pClip->y1;
-	    x2 = pClip->x2;
-	    y2 = pClip->y2;
-
-	    iw = ((x2 - x1 - 1) / gridW) + 1;
-	    ih = ((y2 - y1 - 1) / gridH) + 1;
-
-	    if (nIndices + (iw * ih * 4) > w->indexSize)
-	    {
-		if (!moreWindowIndices (w, nIndices + (iw * ih * 4)))
-		    return;
-
-		i = w->indices + nIndices;
-	    }
-
-	    iw++;
-	    ih++;
+	    nClip = clip->numRects;
+	    pClip = clip->rects;
 
-	    for (y = 0; y < ih - 1; y++)
+	    while (nClip--)
 	    {
-		for (x = 0; x < iw - 1; x++)
+		x1 = pClip->x1;
+		y1 = pClip->y1;
+		x2 = pClip->x2;
+		y2 = pClip->y2;
+
+		if (x1 < pBox->x1)
+		    x1 = pBox->x1;
+		if (y1 < pBox->y1)
+		    y1 = pBox->y1;
+		if (x2 > pBox->x2)
+		    x2 = pBox->x2;
+		if (y2 > pBox->y2)
+		    y2 = pBox->y2;
+
+		if (x1 < x2 && y1 < y2)
 		{
-		    *i++ = nVertices + iw * (y + 1) + x;
-		    *i++ = nVertices + iw * (y + 1) + x + 1;
-		    *i++ = nVertices + iw * y + x + 1;
-		    *i++ = nVertices + iw * y + x;
-
-		    nIndices += 4;
-		}
-	    }
+		    iw = ((x2 - x1 - 1) / gridW) + 1;
+		    ih = ((y2 - y1 - 1) / gridH) + 1;
 
-	    if (((nVertices + iw * ih) * vSize) > w->vertexSize)
-	    {
-		if (!moreWindowVertices (w, (nVertices + iw * ih) * vSize))
-		    return;
-
-		v = w->vertices + (nVertices * vSize);
-	    }
-
-	    for (y = y1;; y += gridH)
-	    {
-		if (y > y2)
-		    y = y2;
+		    if (nIndices + (iw * ih * 4) > w->indexSize)
+		    {
+			if (!moreWindowIndices (w, nIndices + (iw * ih * 4)))
+			    return;
 
-		for (x = x1;; x += gridW)
-		{
-		    if (x > x2)
-			x = x2;
+			i = w->indices + nIndices;
+		    }
 
-		    bezierPatchEvaluate (ww->model,
-					 (x - wx) / width,
-					 (y - wy) / height,
-					 &deformedX,
-					 &deformedY);
+		    iw++;
+		    ih++;
 
-		    if (rect)
+		    for (y = 0; y < ih - 1; y++)
 		    {
-			for (it = 0; it < nMatrix; it++)
+			for (x = 0; x < iw - 1; x++)
 			{
-			    *v++ = COMP_TEX_COORD_X (&matrix[it], x);
-			    *v++ = COMP_TEX_COORD_Y (&matrix[it], y);
+			    *i++ = nVertices + iw * (y + 1) + x;
+			    *i++ = nVertices + iw * (y + 1) + x + 1;
+			    *i++ = nVertices + iw * y + x + 1;
+			    *i++ = nVertices + iw * y + x;
+
+			    nIndices += 4;
 			}
 		    }
-		    else
+
+		    if (((nVertices + iw * ih) * vSize) > w->vertexSize)
 		    {
-			for (it = 0; it < nMatrix; it++)
-			{
-			    *v++ = COMP_TEX_COORD_XY (&matrix[it], x, y);
-			    *v++ = COMP_TEX_COORD_YX (&matrix[it], x, y);
-			}
+			if (!moreWindowVertices (w,
+						 (nVertices + iw * ih) * vSize))
+			    return;
+
+			v = w->vertices + (nVertices * vSize);
 		    }
 
-		    *v++ = deformedX;
-		    *v++ = deformedY;
-		    *v++ = 0.0;
+		    for (y = y1;; y += gridH)
+		    {
+			if (y > y2)
+			    y = y2;
 
-		    nVertices++;
+			for (x = x1;; x += gridW)
+			{
+			    if (x > x2)
+				x = x2;
+
+			    bezierPatchEvaluate (ws->model,
+						 (x - ws->x) / ws->width,
+						 (y - ws->y) / ws->height,
+						 &deformedX,
+						 &deformedY);
+
+			    if (rect)
+			    {
+				for (it = 0; it < nMatrix; it++)
+				{
+				    *v++ = COMP_TEX_COORD_X (&matrix[it], x);
+				    *v++ = COMP_TEX_COORD_Y (&matrix[it], y);
+				}
+			    }
+			    else
+			    {
+				for (it = 0; it < nMatrix; it++)
+				{
+				    *v++ = COMP_TEX_COORD_XY (&matrix[it], x, y);
+				    *v++ = COMP_TEX_COORD_YX (&matrix[it], x, y);
+				}
+			    }
+
+			    *v++ = deformedX;
+			    *v++ = deformedY;
+			    *v++ = 0.0;
+
+			    nVertices++;
+
+			    if (x == x2)
+				break;
+			}
 
-		    if (x == x2)
-			break;
+			if (y == y2)
+			    break;
+		    }
 		}
-
-		if (y == y2)
-		    break;
+		
+		pClip++;
 	    }
 
-	    pClip++;
+	    pBox++;
 	}
 
 	w->vCount	      = nVertices;
@@ -1964,6 +1985,53 @@ wobblyAddWindowGeometry (CompWindow *w,
     }
 }
 
+static void
+wobblyDrawSubWindows (CompWindow          *w,
+		      const CompTransform *transform,
+		      Region              region,
+		      int                 mask)
+{
+    CompWindow *c;
+
+    for (c = w->windows; c; c = c->next)
+    {
+	FragmentAttrib fragment;
+	unsigned int   wMask = mask;
+
+	initFragmentAttrib (&fragment, &c->lastPaint);
+
+	if (c->alpha || fragment.opacity != OPAQUE)
+	    wMask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+
+	(*w->screen->drawWindow) (c, transform, &fragment, region, wMask);
+
+	if (c->windows)
+	{
+	    Region r;
+
+	    r = XCreateRegion ();
+	    if (r)
+	    {
+		WOBBLY_SCREEN (w->screen);
+
+		XSubtractRegion (region, &emptyRegion, r);
+		XIntersectRegion (r, c->region, r);
+		XOffsetRegion (r, -c->attrib.x, -c->attrib.y);
+
+		ws->x -= c->attrib.x;
+		ws->y -= c->attrib.y;
+
+		wobblyDrawSubWindows (c, transform, r, mask);
+
+		ws->x += c->attrib.x;
+		ws->y += c->attrib.y;
+
+		XDestroyRegion (r);
+	    }
+	}
+    }
+}
+
 static Bool
 wobblyPaintWindow (CompWindow		   *w,
 		   const WindowPaintAttrib *attrib,
@@ -1971,17 +2039,69 @@ wobblyPaintWindow (CompWindow		   *w,
 		   Region		   region,
 		   unsigned int		   mask)
 {
-    Bool status;
+    CompScreen *s = w->screen;
+    Bool       status;
 
-    WOBBLY_SCREEN (w->screen);
+    WOBBLY_SCREEN (s);
     WOBBLY_WINDOW (w);
 
     if (ww->wobbly)
-	mask |= PAINT_WINDOW_TRANSFORMED_MASK;
+    {
+	FragmentAttrib fragment;
 
-    UNWRAP (ws, w->screen, paintWindow);
-    status = (*w->screen->paintWindow) (w, attrib, transform, region, mask);
-    WRAP (ws, w->screen, paintWindow, wobblyPaintWindow);
+	if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
+	    return FALSE;
+
+	UNWRAP (ws, s, paintWindow);
+	status = (*s->paintWindow) (w, attrib, transform, region,
+				    mask | PAINT_WINDOW_NO_CORE_INSTANCE_MASK);
+	WRAP (ws, s, paintWindow, wobblyPaintWindow);
+
+	glPushMatrix ();
+	glLoadMatrixf (transform->m);
+
+	ws->model  = ww->model;
+	ws->x      = WIN_X (w);
+	ws->y      = WIN_Y (w);
+	ws->width  = WIN_W (w);
+	ws->height = WIN_H (w);
+
+	initFragmentAttrib (&fragment, &w->lastPaint);
+
+	if (w->alpha || fragment.opacity != OPAQUE)
+	    mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+
+	(*s->drawWindow) (w,
+			  transform,
+			  &fragment,
+			  region,
+			  mask | PAINT_WINDOW_TRANSFORMED_MASK);
+
+	if (w->windows)
+	{
+	    XOffsetRegion (w->region, -w->attrib.x, -w->attrib.y);
+
+	    ws->x -= w->attrib.x;
+	    ws->y -= w->attrib.y;
+	    
+	    wobblyDrawSubWindows (w,
+				  transform,
+				  w->region,
+				  PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK);
+
+	    XOffsetRegion (w->region, w->attrib.x, w->attrib.y);
+	}
+
+	ws->model = NULL;
+
+	glPopMatrix ();
+    }
+    else
+    {
+	UNWRAP (ws, s, paintWindow);
+	status = (*s->paintWindow) (w, attrib, transform, region, mask);
+	WRAP (ws, s, paintWindow, wobblyPaintWindow);
+    }
 
     return status;
 }
@@ -2000,7 +2120,7 @@ wobblyEnableSnapping (CompDisplay     *d,
 
     for (s = d->screens; s; s = s->next)
     {
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = walkDepthFirst (w))
 	{
 	    WOBBLY_WINDOW (w);
 
@@ -2031,7 +2151,7 @@ wobblyDisableSnapping (CompDisplay     *d,
 
     for (s = d->screens; s; s = s->next)
     {
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = walkDepthFirst (w))
 	{
 	    WOBBLY_WINDOW (w);
 
@@ -2678,7 +2798,8 @@ wobblyInitDisplay (CompPlugin  *p,
 {
     WobblyDisplay *wd;
 
-    if (!checkPluginABI ("core", CORE_ABIVERSION))
+    if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+	!checkPluginABI ("glx",  CORE_ABIVERSION))
 	return FALSE;
 
     wd = malloc (sizeof (WobblyDisplay));
@@ -2763,6 +2884,8 @@ wobblyInitScreen (CompPlugin *p,
     ws->grabWindow = NULL;
     ws->moveWindow = FALSE;
 
+    ws->model = NULL;
+
     WRAP (ws, s, preparePaintScreen, wobblyPreparePaintScreen);
     WRAP (ws, s, donePaintScreen, wobblyDonePaintScreen);
     WRAP (ws, s, paintOutput, wobblyPaintOutput);
diff --git a/plugins/zoom.c b/plugins/zoom.c
index 8996c1c..4c3b881 100644
--- a/plugins/zoom.c
+++ b/plugins/zoom.c
@@ -163,7 +163,7 @@ zoomInEvent (CompScreen *s)
 
     o[0].type    = CompOptionTypeInt;
     o[0].name    = "root";
-    o[0].value.i = s->root;
+    o[0].value.i = s->root.id;
 
     o[1].type    = CompOptionTypeInt;
     o[1].name    = "output";
@@ -197,7 +197,7 @@ zoomOutEvent (CompScreen *s)
 
     o[0].type    = CompOptionTypeInt;
     o[0].name    = "root";
-    o[0].value.i = s->root;
+    o[0].value.i = s->root.id;
 
     o[1].type    = CompOptionTypeInt;
     o[1].name    = "output";
@@ -694,7 +694,7 @@ zoomTerminate (CompDisplay     *d,
     {
 	ZOOM_SCREEN (s);
 
-	if (xid && s->root != xid)
+	if (xid && s->root.id != xid)
 	    continue;
 
 	if (zs->grab)
@@ -719,7 +719,7 @@ zoomTerminate (CompDisplay     *d,
 
 	    o.type    = CompOptionTypeInt;
 	    o.name    = "root";
-	    o.value.i = s->root;
+	    o.value.i = s->root.id;
 
 	    zoomOut (d, action, state, &o, 1);
 	}
@@ -787,7 +787,7 @@ zoomTerminatePan (CompDisplay     *d,
     {
 	ZOOM_SCREEN (s);
 
-	if (xid && s->root != xid)
+	if (xid && s->root.id != xid)
 	    continue;
 
 	if (zs->panGrabIndex)
@@ -970,7 +970,8 @@ zoomInitDisplay (CompPlugin  *p,
 {
     ZoomDisplay *zd;
 
-    if (!checkPluginABI ("core", CORE_ABIVERSION))
+    if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+	!checkPluginABI ("glx",  CORE_ABIVERSION))
 	return FALSE;
 
     zd = malloc (sizeof (ZoomDisplay));
diff --git a/src/display.c b/src/display.c
index 23b0ba1..72515b6 100644
--- a/src/display.c
+++ b/src/display.c
@@ -195,8 +195,8 @@ mainMenu (CompDisplay     *d,
 
     s = findScreenAtDisplay (d, xid);
     if (s && !s->maxGrab)
-	toolkitAction (s, s->display->toolkitActionMainMenuAtom, time, s->root,
-		       0, 0, 0);
+	toolkitAction (s, s->display->toolkitActionMainMenuAtom, time,
+		       s->root.id, 0, 0, 0);
 
     return TRUE;
 }
@@ -217,8 +217,8 @@ runDialog (CompDisplay     *d,
 
     s = findScreenAtDisplay (d, xid);
     if (s && !s->maxGrab)
-	toolkitAction (s, s->display->toolkitActionRunDialogAtom, time, s->root,
-		       0, 0, 0);
+	toolkitAction (s, s->display->toolkitActionRunDialogAtom, time,
+		       s->root.id, 0, 0, 0);
 
     return TRUE;
 }
@@ -725,7 +725,7 @@ pingTimeout (void *closure)
 
     for (s = d->screens; s; s = s->next)
     {
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = w->next)
 	{
 	    if (w->attrib.map_state != IsViewable)
 		continue;
@@ -841,7 +841,7 @@ setDisplayOption (CompPlugin	  *plugin,
     return FALSE;
 }
 
-static void
+void
 updatePlugins (CompDisplay *d)
 {
     CompOption *o;
@@ -1349,7 +1349,7 @@ doPoll (int timeout)
     return rv;
 }
 
-static void
+void
 handleTimeouts (struct timeval *tv)
 {
     CompTimeout *t;
@@ -1545,13 +1545,20 @@ eventLoop (void)
 	{
 	    for (s = d->screens; s; s = s->next)
 	    {
-		if (s->damageMask)
+		if (manualCompositeManagement)
 		{
-		    finishScreenDrawing (s);
+		    if (s->damageMask)
+		    {
+			finishScreenDrawing (s);
+		    }
+		    else
+		    {
+			s->idle = TRUE;
+		    }
 		}
 		else
 		{
-		    s->idle = TRUE;
+		    s->damageMask = 0;
 		}
 	    }
 	}
@@ -1624,7 +1631,7 @@ eventLoop (void)
 			/* substract top most overlay window region */
 			if (s->overlayWindowCount)
 			{
-			    for (w = s->reverseWindows; w; w = w->prev)
+			    for (w = s->root.reverseWindows; w; w = w->prev)
 			    {
 				if (w->destroyed || w->invisible)
 				    continue;
@@ -1748,24 +1755,6 @@ eventLoop (void)
 
 			(*s->donePaintScreen) (s);
 
-			/* remove destroyed windows */
-			while (s->pendingDestroys)
-			{
-			    CompWindow *w;
-
-			    for (w = s->windows; w; w = w->next)
-			    {
-				if (w->destroyed)
-				{
-				    addWindowDamage (w);
-				    removeWindow (w);
-				    break;
-				}
-			    }
-
-			    s->pendingDestroys--;
-			}
-
 			s->idle = FALSE;
 		    }
 		}
@@ -1797,6 +1786,38 @@ eventLoop (void)
 		doPoll (-1);
 	    }
 	}
+
+	for (d = core.displays; d; d = d->next)
+	{
+	    for (s = d->screens; s; s = s->next)
+	    {
+		/* remove destroyed windows */
+		while (s->pendingDestroys)
+		{
+		    CompWindow *w, *c;
+
+		    for (w = s->root.windows; w; w = walkDepthFirst (w))
+		    {
+			if (w->destroyed)
+			{
+                            for (c = w->windows;
+                                 c && c != w;
+                                 c = walkDepthFirst (c))
+                            {
+                                if (c->destroyed)
+                                    s->pendingDestroys--;
+                            }
+
+			    addWindowDamage (w);
+			    removeWindow (w);
+			    break;
+			}
+		    }
+
+		    s->pendingDestroys--;
+		}
+	    }
+	}
     }
 
     for (d = core.displays; d; d = d->next)
@@ -1864,7 +1885,8 @@ compCheckForError (Display *dpy)
 static void
 addScreenActions (CompScreen *s)
 {
-    int i;
+    CompPlugin *p;
+    int        i;
 
     for (i = 0; i < COMP_DISPLAY_OPTION_NUM; i++)
     {
@@ -1874,6 +1896,27 @@ addScreenActions (CompScreen *s)
 	if (s->display->opt[i].value.action.state & CompActionStateAutoGrab)
 	    addScreenAction (s, &s->display->opt[i].value.action);
     }
+
+    for (p = getPlugins (); p; p = p->next)
+    {
+	CompOption *option;
+	int	   nOption;
+
+	if (!p->vTable->getObjectOptions)
+	    continue;
+
+	option = (*p->vTable->getObjectOptions) (p,
+						 &s->display->base,
+						 &nOption);
+	for (i = 0; i < nOption; i++)
+	{
+	    if (!isActionOption (&option[i]))
+		continue;
+
+	    if (option[i].value.action.state & CompActionStateAutoGrab)
+		addScreenAction (s, &option[i].value.action);
+	}
+    }
 }
 
 void
@@ -1920,12 +1963,10 @@ addDisplay (const char *name)
     CompDisplay *d;
     CompPrivate	*privates;
     Display     *dpy;
-    Window	focus;
-    int		revertTo, i;
     int		compositeMajor, compositeMinor;
     int		fixesMinor;
     int		xkbOpcode;
-    int		firstScreen, lastScreen;
+    int		i;
 
     d = malloc (sizeof (CompDisplay));
     if (!d)
@@ -2198,6 +2239,8 @@ addDisplay (const char *name)
 
     d->startupIdAtom = XInternAtom (dpy, "_NET_STARTUP_ID", 0);
 
+    d->syncStateAtom = XInternAtom (dpy, "_COMPIZ_SYNC_STATE", 0);
+
     d->snDisplay = sn_display_new (dpy, NULL, NULL);
     if (!d->snDisplay)
 	return FALSE;
@@ -2288,7 +2331,7 @@ addDisplay (const char *name)
 						   &d->xineramaEvent,
 						   &d->xineramaError);
 
-    if (d->xineramaExtension)
+    if (d->xineramaExtension && XineramaIsActive (dpy))
 	d->screenInfo = XineramaQueryScreens (dpy, &d->nScreenInfo);
 
     d->escapeKeyCode = XKeysymToKeycode (dpy, XStringToKeysym ("Escape"));
@@ -2301,6 +2344,49 @@ addDisplay (const char *name)
 
     (*core.objectAdd) (&core.base, &d->base);
 
+    return TRUE;
+}
+
+void
+removeDisplay (CompDisplay *d)
+{
+    CompDisplay *p;
+
+    for (p = core.displays; p; p = p->next)
+	if (p->next == d)
+	    break;
+
+    if (p)
+	p->next = d->next;
+    else
+	core.displays = NULL;
+
+    while (d->screens)
+	removeScreen (d->screens);
+
+    (*core.objectRemove) (&core.base, &d->base);
+
+    objectFiniPlugins (&d->base);
+
+    compRemoveTimeout (d->pingHandle);
+
+    if (d->snDisplay)
+	sn_display_unref (d->snDisplay);
+
+    XSync (d->display, False);
+    XCloseDisplay (d->display);
+
+    freeDisplay (d);
+}
+
+Bool
+manageDisplay (CompDisplay *d)
+{
+    Display *dpy = d->display;
+    Window  focus;
+    int     revertTo, i;
+    int     firstScreen, lastScreen;
+
     if (onlyCurrentScreen)
     {
 	firstScreen = DefaultScreen (dpy);
@@ -2319,7 +2405,7 @@ addDisplay (const char *name)
 	Time		     wmSnTimestamp = 0;
 	XEvent		     event;
 	XSetWindowAttributes attr;
-	Window		     currentWmSnOwner, currentCmSnOwner;
+	Window		     currentWmSnOwner = None, currentCmSnOwner;
 	char		     buf[128];
 	Window		     rootDummy, childDummy;
 	unsigned int	     uDummy;
@@ -2328,7 +2414,8 @@ addDisplay (const char *name)
 	sprintf (buf, "WM_S%d", i);
 	wmSnAtom = XInternAtom (dpy, buf, 0);
 
-	currentWmSnOwner = XGetSelectionOwner (dpy, wmSnAtom);
+	if (windowManagement)
+	    currentWmSnOwner = XGetSelectionOwner (dpy, wmSnAtom);
 
 	if (currentWmSnOwner != None)
 	{
@@ -2366,6 +2453,9 @@ addDisplay (const char *name)
 
 		continue;
 	    }
+
+	    XSelectInput (dpy, currentCmSnOwner,
+			  StructureNotifyMask);
 	}
 
 	attr.override_redirect = TRUE;
@@ -2394,36 +2484,60 @@ addDisplay (const char *name)
 
 	wmSnTimestamp = event.xproperty.time;
 
-	XSetSelectionOwner (dpy, wmSnAtom, newWmSnOwner, wmSnTimestamp);
+	XSetSelectionOwner (dpy, cmSnAtom, newCmSnOwner, wmSnTimestamp);
 
-	if (XGetSelectionOwner (dpy, wmSnAtom) != newWmSnOwner)
+	if (XGetSelectionOwner (dpy, cmSnAtom) != newCmSnOwner)
 	{
 	    compLogMessage ("core", CompLogLevelError,
-			    "Could not acquire window manager "
+			    "Could not acquire compositing manager "
 			    "selection on screen %d display \"%s\"",
 			    i, DisplayString (dpy));
 
-	    XDestroyWindow (dpy, newWmSnOwner);
-
 	    continue;
 	}
 
-	/* Send client message indicating that we are now the WM */
-	event.xclient.type	   = ClientMessage;
-	event.xclient.window       = XRootWindow (dpy, i);
-	event.xclient.message_type = d->managerAtom;
-	event.xclient.format       = 32;
-	event.xclient.data.l[0]    = wmSnTimestamp;
-	event.xclient.data.l[1]    = wmSnAtom;
-	event.xclient.data.l[2]    = 0;
-	event.xclient.data.l[3]    = 0;
-	event.xclient.data.l[4]    = 0;
+	if (windowManagement)
+	{
+	    XSetSelectionOwner (dpy, wmSnAtom, newWmSnOwner, wmSnTimestamp);
+
+	    if (XGetSelectionOwner (dpy, wmSnAtom) != newWmSnOwner)
+	    {
+		compLogMessage ("core", CompLogLevelError,
+				"Could not acquire window manager "
+				"selection on screen %d display \"%s\"",
+				i, DisplayString (dpy));
+
+		XDestroyWindow (dpy, newWmSnOwner);
+
+		continue;
+	    }
 
-	XSendEvent (dpy, XRootWindow (dpy, i), FALSE,
-		    StructureNotifyMask, &event);
+	    /* Send client message indicating that we are now the WM */
+	    event.xclient.type	       = ClientMessage;
+	    event.xclient.window       = XRootWindow (dpy, i);
+	    event.xclient.message_type = d->managerAtom;
+	    event.xclient.format       = 32;
+	    event.xclient.data.l[0]    = wmSnTimestamp;
+	    event.xclient.data.l[1]    = wmSnAtom;
+	    event.xclient.data.l[2]    = 0;
+	    event.xclient.data.l[3]    = 0;
+	    event.xclient.data.l[4]    = 0;
+
+	    XSendEvent (dpy, XRootWindow (dpy, i), FALSE,
+			StructureNotifyMask, &event);
+	}
+
+	/* Wait for old compositing manager to go away */
+	if (currentCmSnOwner != None)
+	{
+	    do {
+		XWindowEvent (dpy, currentCmSnOwner,
+			      StructureNotifyMask, &event);
+	    } while (event.type != DestroyNotify);
+	}
 
 	/* Wait for old window manager to go away */
-	if (currentWmSnOwner != None)
+	if (currentWmSnOwner != None && currentCmSnOwner != currentWmSnOwner)
 	{
 	    do {
 		XWindowEvent (dpy, currentWmSnOwner,
@@ -2433,54 +2547,59 @@ addDisplay (const char *name)
 
 	compCheckForError (dpy);
 
-	XCompositeRedirectSubwindows (dpy, XRootWindow (dpy, i),
-				      CompositeRedirectManual);
-
-	if (compCheckForError (dpy))
+	if (manualCompositeManagement)
 	{
-	    compLogMessage ("core", CompLogLevelError,
-			    "Another composite manager is already "
-			    "running on screen: %d", i);
-
-	    continue;
-	}
+	    XCompositeRedirectSubwindows (dpy, XRootWindow (dpy, i),
+					  CompositeRedirectManual);
 
-	XSetSelectionOwner (dpy, cmSnAtom, newCmSnOwner, wmSnTimestamp);
+	    if (compCheckForError (dpy))
+	    {
+		compLogMessage ("core", CompLogLevelError,
+				"Another composite manager is already "
+				"running on screen: %d", i);
 
-	if (XGetSelectionOwner (dpy, cmSnAtom) != newCmSnOwner)
+		continue;
+	    }
+	}
+	else
 	{
-	    compLogMessage ("core", CompLogLevelError,
-			    "Could not acquire compositing manager "
-			    "selection on screen %d display \"%s\"",
-			    i, DisplayString (dpy));
-
-	    continue;
+	    XCompositeRedirectSubwindows (dpy, XRootWindow (dpy, i),
+					  CompositeRedirectAutomatic);
 	}
 
 	XGrabServer (dpy);
 
-	XSelectInput (dpy, XRootWindow (dpy, i),
-		      SubstructureRedirectMask |
-		      SubstructureNotifyMask   |
-		      StructureNotifyMask      |
-		      PropertyChangeMask       |
-		      LeaveWindowMask	       |
-		      EnterWindowMask	       |
-		      KeyPressMask	       |
-		      KeyReleaseMask	       |
-		      ButtonPressMask	       |
-		      ButtonReleaseMask	       |
-		      FocusChangeMask	       |
-		      ExposureMask);
-
-	if (compCheckForError (dpy))
+	if (windowManagement)
 	{
-	    compLogMessage ("core", CompLogLevelError,
-			    "Another window manager is "
-			    "already running on screen: %d", i);
+	    XSelectInput (dpy, XRootWindow (dpy, i),
+			  SubstructureRedirectMask |
+			  StructureNotifyMask      |
+			  PropertyChangeMask       |
+			  LeaveWindowMask          |
+			  EnterWindowMask          |
+			  KeyPressMask             |
+			  KeyReleaseMask           |
+			  ButtonPressMask          |
+			  ButtonReleaseMask        |
+			  FocusChangeMask          |
+			  ExposureMask);
+   
+	    if (compCheckForError (dpy))
+	    {
+		compLogMessage ("core", CompLogLevelError,
+				"Another window manager is "
+				"already running on screen: %d", i);
 
-	    XUngrabServer (dpy);
-	    continue;
+		XUngrabServer (dpy);
+		continue;
+	    }
+	}
+	else
+	{
+	    XSelectInput (dpy, XRootWindow (dpy, i),
+			  StructureNotifyMask      |
+			  PropertyChangeMask       |
+			  ExposureMask);
 	}
 
 	if (!addScreen (d, i, newWmSnOwner, wmSnAtom, wmSnTimestamp))
@@ -2503,74 +2622,50 @@ addDisplay (const char *name)
     if (!d->screens)
     {
 	compLogMessage ("core", CompLogLevelFatal,
-			"No manageable screens found on display %s",
-			XDisplayName (name));
+			"No manageable screens found on display");
 	return FALSE;
     }
 
     setAudibleBell (d, d->opt[COMP_DISPLAY_OPTION_AUDIBLE_BELL].value.b);
 
-    XGetInputFocus (dpy, &focus, &revertTo);
-
-    /* move input focus to root window so that we get a FocusIn event when
-       moving it to the default window */
-    XSetInputFocus (dpy, d->screens->root, RevertToPointerRoot, CurrentTime);
-
-    if (focus == None || focus == PointerRoot)
+    if (windowManagement)
     {
-	focusDefaultWindow (d->screens);
-    }
-    else
-    {
-	CompWindow *w;
+	XGetInputFocus (dpy, &focus, &revertTo);
 
-	w = findWindowAtDisplay (d, focus);
-	if (w)
+	/* move input focus to root window so that we get a FocusIn event when
+	   moving it to the default window */
+	XSetInputFocus (dpy, d->screens->root.id, RevertToPointerRoot,
+			CurrentTime);
+
+	if (focus == None || focus == PointerRoot)
 	{
-	    moveInputFocusToWindow (w);
+	    focusDefaultWindow (d->screens);
 	}
 	else
-	    focusDefaultWindow (d->screens);
-    }
-
-    d->pingHandle =
-	compAddTimeout (d->opt[COMP_DISPLAY_OPTION_PING_DELAY].value.i,
-			d->opt[COMP_DISPLAY_OPTION_PING_DELAY].value.i + 500,
-			pingTimeout, d);
-
-    return TRUE;
-}
-
-void
-removeDisplay (CompDisplay *d)
-{
-    CompDisplay *p;
+	{
+	    CompWindow *w;
 
-    for (p = core.displays; p; p = p->next)
-	if (p->next == d)
-	    break;
+	    w = findWindowAtDisplay (d, focus);
+	    if (w)
+	    {
+		moveInputFocusToWindow (w);
+	    }
+	    else
+		focusDefaultWindow (d->screens);
+	}
 
-    if (p)
-	p->next = d->next;
+	d->pingHandle =
+	    compAddTimeout (d->opt[COMP_DISPLAY_OPTION_PING_DELAY].value.i,
+			    d->opt[COMP_DISPLAY_OPTION_PING_DELAY].value.i +
+			    500, pingTimeout, d);
+    }
     else
-	core.displays = NULL;
-
-    while (d->screens)
-	removeScreen (d->screens);
-
-    (*core.objectRemove) (&core.base, &d->base);
-
-    objectFiniPlugins (&d->base);
-
-    compRemoveTimeout (d->pingHandle);
-
-    if (d->snDisplay)
-	sn_display_unref (d->snDisplay);
-
-    XSync (d->display, False);
-    XCloseDisplay (d->display);
+    {
+	d->activeWindow = d->screens->root.activeChild =
+	    getActiveWindow (d, d->screens->root.id);
+    }
 
-    freeDisplay (d);
+    return TRUE;
 }
 
 Time
@@ -2596,7 +2691,7 @@ findScreenAtDisplay (CompDisplay *d,
 
     for (s = d->screens; s; s = s->next)
     {
-	if (s->root == root)
+	if (s->root.id == root)
 	    return s;
     }
 
@@ -2632,6 +2727,23 @@ findWindowAtDisplay (CompDisplay *d,
 }
 
 CompWindow *
+findClientWindowAtDisplay (CompDisplay *d,
+			   Window      id)
+{
+    CompScreen *s;
+    CompWindow *w;
+
+    for (s = d->screens; s; s = s->next)
+    {
+	w = findClientWindowAtScreen (s, id);
+	if (w)
+	    return w;
+    }
+
+    return 0;
+}
+
+CompWindow *
 findTopLevelWindowAtDisplay (CompDisplay *d,
 			     Window      id)
 {
@@ -2823,7 +2935,7 @@ warpPointer (CompScreen *s,
 	pointerY = 0;
 
     XWarpPointer (display->display,
-		  None, s->root,
+		  None, s->root.id,
 		  0, 0, 0, 0,
 		  pointerX, pointerY);
 
diff --git a/src/event.c b/src/event.c
index ac61749..f9edcfc 100644
--- a/src/event.c
+++ b/src/event.c
@@ -45,37 +45,46 @@ handleWindowDamageRect (CompWindow *w,
 			int	   height)
 {
     REGION region;
-    Bool   initial = FALSE;
+    Bool   status = TRUE;
 
     if (!w->redirected || w->bindFailed)
 	return;
 
-    if (!w->damaged)
-    {
-	w->damaged = initial = TRUE;
-	w->invisible = WINDOW_INVISIBLE (w);
-    }
-
     region.extents.x1 = x;
     region.extents.y1 = y;
     region.extents.x2 = region.extents.x1 + width;
     region.extents.y2 = region.extents.y1 + height;
 
-    if (!(*w->screen->damageWindowRect) (w, initial, &region.extents))
+    while (w != &w->screen->root)
     {
+	Bool initial = FALSE;
+
+	if (!w->damaged)
+	{
+	    w->damaged = initial = TRUE;
+	    w->invisible = WINDOW_INVISIBLE (w);
+	}
+
+	status &= (*w->screen->damageWindowRect) (w, initial, &region.extents);
+
+	if (initial)
+	    damageWindowOutputExtents (w);
+
 	region.extents.x1 += w->attrib.x + w->attrib.border_width;
 	region.extents.y1 += w->attrib.y + w->attrib.border_width;
 	region.extents.x2 += w->attrib.x + w->attrib.border_width;
 	region.extents.y2 += w->attrib.y + w->attrib.border_width;
 
+	w = w->parent;
+    }
+
+    if (!status)
+    {
 	region.rects = &region.extents;
 	region.numRects = region.size = 1;
 
 	damageScreenRegion (w->screen, &region);
     }
-
-    if (initial)
-	damageWindowOutputExtents (w);
 }
 
 void
@@ -99,6 +108,9 @@ handleSyncAlarm (CompWindow *w)
 	    XRectangle *rects;
 	    int	       nDamage;
 
+	    if (w->parent->substructureRedirect)
+		leaveSyncWaitState (w);
+
 	    nDamage = w->nDamage;
 	    rects   = w->damageRects;
 	    while (nDamage--)
@@ -130,9 +142,9 @@ moveInputFocusToOtherWindow (CompWindow *w)
     {
 	CompWindow *ancestor;
 
-	if (w->transientFor && w->transientFor != w->screen->root)
+	if (w->transientFor && w->transientFor != w->screen->root.id)
 	{
-	    ancestor = findWindowAtDisplay (display, w->transientFor);
+	    ancestor = findSibling (w, w->transientFor);
 	    if (ancestor && !(ancestor->type & (CompWindowTypeDesktopMask |
 						CompWindowTypeDockMask)))
 	    {
@@ -146,7 +158,7 @@ moveInputFocusToOtherWindow (CompWindow *w)
 	{
 	    CompWindow *a, *focus = NULL;
 
-	    for (a = w->screen->reverseWindows; a; a = a->prev)
+	    for (a = w->screen->root.reverseWindows; a; a = a->prev)
 	    {
 		if (a->clientLeader == w->clientLeader)
 		{
@@ -277,7 +289,7 @@ triggerButtonPressBindings (CompDisplay  *d,
 
 	if (event->window != edgeWindow)
 	{
-	    if (!s->maxGrab || event->window != s->root)
+	    if (!s->maxGrab || event->window != s->root.id)
 		return FALSE;
 	}
 
@@ -1064,7 +1076,7 @@ handleActionEvent (CompDisplay *d,
 			if (event->xclient.window == s->screenEdge[i].id)
 			{
 			    edge = 1 << i;
-			    root = s->root;
+			    root = s->root.id;
 			    break;
 			}
 		    }
@@ -1115,7 +1127,7 @@ handleActionEvent (CompDisplay *d,
 			if (xdndWindow == s->screenEdge[i].id)
 			{
 			    edge = 1 << i;
-			    root = s->root;
+			    root = s->root.id;
 			    break;
 			}
 		    }
@@ -1307,32 +1319,29 @@ handleEvent (CompDisplay *d,
     case ConfigureNotify:
 	w = findWindowAtDisplay (d, event->xconfigure.window);
 	if (w)
-	{
 	    configureWindow (w, &event->xconfigure);
-	}
-	else
-	{
-	    s = findScreenAtDisplay (d, event->xconfigure.window);
-	    if (s)
-		configureScreen (s, &event->xconfigure);
-	}
 	break;
     case CreateNotify:
-	s = findScreenAtDisplay (d, event->xcreatewindow.parent);
-	if (s)
+	w = findWindowAtDisplay (d, event->xcreatewindow.parent);
+	if (w)
 	{
 	    /* The first time some client asks for the composite
 	     * overlay window, the X server creates it, which causes
 	     * an errorneous CreateNotify event.  We catch it and
 	     * ignore it. */
-	    if (s->overlay != event->xcreatewindow.window)
-		addWindow (s, event->xcreatewindow.window, getTopWindow (s));
+	    if (w->screen->overlay != event->xcreatewindow.window)
+		addWindow (w,
+			   event->xcreatewindow.window,
+			   getTopWindow (w));
 	}
 	break;
     case DestroyNotify:
 	w = findWindowAtDisplay (d, event->xdestroywindow.window);
 	if (w)
 	{
+	    if (w->parent->supportingWmCheckWindow == w->id)
+		getSupportingWmCheck (w->parent);
+
 	    moveInputFocusToOtherWindow (w);
 	    destroyWindow (w);
 	}
@@ -1341,11 +1350,8 @@ handleEvent (CompDisplay *d,
 	w = findWindowAtDisplay (d, event->xmap.window);
 	if (w)
 	{
-	    if (w->pendingMaps)
-		w->managed = TRUE;
-
 	    /* been shaded */
-	    if (w->height == 0)
+	    if (w->managed && w->height == 0)
 	    {
 		if (w->id == d->activeWindow)
 		    moveInputFocusToWindow (w);
@@ -1356,7 +1362,7 @@ handleEvent (CompDisplay *d,
 	break;
     case UnmapNotify:
 	w = findWindowAtDisplay (d, event->xunmap.window);
-	if (w)
+	if (w && w->parent)
 	{
 	    /* Normal -> Iconic */
 	    if (w->pendingUnmaps)
@@ -1364,7 +1370,7 @@ handleEvent (CompDisplay *d,
 		setWmState (d, IconicState, w->id);
 		w->pendingUnmaps--;
 	    }
-	    else /* X -> Withdrawn */
+	    else if (w->managed) /* X -> Withdrawn */
 	    {
 		/* Iconic -> Withdrawn */
 		if (w->state & CompWindowStateHiddenMask)
@@ -1392,12 +1398,7 @@ handleEvent (CompDisplay *d,
 	break;
     case ReparentNotify:
 	w = findWindowAtDisplay (d, event->xreparent.window);
-	s = findScreenAtDisplay (d, event->xreparent.parent);
-	if (s && !w)
-	{
-	    addWindow (s, event->xreparent.window, getTopWindow (s));
-	}
-	else if (w)
+	if (w)
 	{
 	    /* This is the only case where a window is removed but not
 	       destroyed. We must remove our event mask and all passive
@@ -1410,6 +1411,11 @@ handleEvent (CompDisplay *d,
 
 	    destroyWindow (w);
 	}
+
+	w = findWindowAtDisplay (d, event->xreparent.parent);
+	if (w && (w->redirectSubwindows || w->substructureRedirect))
+	    addWindow (w, event->xreparent.window, getTopWindow (w));
+
 	break;
     case CirculateNotify:
 	w = findWindowAtDisplay (d, event->xcirculate.window);
@@ -1456,9 +1462,9 @@ handleEvent (CompDisplay *d,
 		    if (w->attrib.map_state == IsViewable)
 		    {
 			if (w->type == CompWindowTypeDesktopMask)
-			    w->screen->desktopWindowCount--;
+			    w->parent->desktopWindowCount--;
 			else if (type == CompWindowTypeDesktopMask)
-			    w->screen->desktopWindowCount++;
+			    w->parent->desktopWindowCount++;
 		    }
 
 		    w->wmType = type;
@@ -1533,6 +1539,12 @@ handleEvent (CompDisplay *d,
 	    if (w)
 		w->clientLeader = getClientLeader (w);
 	}
+	else if (event->xproperty.atom == d->frameWindowAtom)
+	{
+	    w = findWindowAtDisplay (d, event->xproperty.window);
+	    if (w && w->parent && !w->parent->substructureRedirect)
+		w->frame = getFrameWindow (w);
+	}
 	else if (event->xproperty.atom == d->wmIconGeometryAtom)
 	{
 	    w = findWindowAtDisplay (d, event->xproperty.window);
@@ -1681,10 +1693,67 @@ handleEvent (CompDisplay *d,
 	    if (w)
 		updateWindowClassHints (w);
 	}
+	else if (event->xproperty.atom == d->supportingWmCheckAtom ||
+		 event->xproperty.atom == d->supportedAtom)
+	{
+	    w = findWindowAtDisplay (d, event->xproperty.window);
+	    if (w && !w->substructureRedirect)
+		getSupportingWmCheck (w);
+	}
+	else if (event->xproperty.atom == d->syncStateAtom)
+	{
+	    w = findWindowAtDisplay (d, event->xproperty.window);
+	    if (w && w->parent)
+	    {	
+		if (!w->parent->substructureRedirect)
+		{
+		    if (event->xproperty.state == PropertyDelete)
+		    {
+			if (w->parent->syncStateSupport)
+			    syncWait (w);
+		    }
+		    else
+			handleSyncAlarm (w);
+		}
+	    }
+	}
+	else if (event->xproperty.atom == d->winActiveAtom)
+	{
+	    w = findWindowAtDisplay (d, event->xproperty.window);
+	    if (w)
+	    {	
+		if (!w->substructureRedirect)
+		{
+		    Window activeChild;
+		    
+		    activeChild = getActiveWindow (d, w->id);
+		    if (activeChild != w->activeChild)
+		    {
+			w->previousActiveChild = w->activeChild;
+			w->activeChild = activeChild;
+		    }
+
+		    if (!w->parent)
+			d->activeWindow = activeChild;
+		}
+	    }
+	}
+	else if (event->xproperty.atom == d->desktopViewportAtom)
+	{
+	    w = findWindowAtDisplay (d, event->xproperty.window);
+	    if (w && !w->parent)
+	    {
+		if (!w->substructureRedirect)
+		    getDesktopHints (w->screen);
+	    }
+	}
 	break;
     case MotionNotify:
 	break;
     case ClientMessage:
+	if (!windowManagement)
+	    break;
+
 	if (event->xclient.message_type == d->winActiveAtom)
 	{
 	    w = findWindowAtDisplay (d, event->xclient.window);
@@ -1932,7 +2001,7 @@ handleEvent (CompDisplay *d,
 	{
 	    for (s = d->screens; s; s = s->next)
 	    {
-		if (event->xclient.window == s->root ||
+		if (event->xclient.window == s->root.id ||
 		    event->xclient.window == None)
 		{
 		    if (event->xclient.data.l[0])
@@ -1968,6 +2037,17 @@ handleEvent (CompDisplay *d,
 	    if (w)
 		setDesktopForWindow (w, event->xclient.data.l[0]);
 	}
+	else if (event->xclient.message_type == d->desktopViewportAtom)
+	{
+	    s = findScreenAtDisplay (d, event->xclient.window);
+	    if (s)
+		moveScreenViewport (s,
+				    s->x -
+				    (event->xclient.data.l[0] / s->width),
+				    s->y -
+				    (event->xclient.data.l[1] / s->height),
+				    TRUE);
+	}
 	break;
     case MappingNotify:
 	updateModifierMappings (d);
@@ -2026,7 +2106,7 @@ handleEvent (CompDisplay *d,
 
 		    xwcm = adjustConfigureRequestForGravity (w, &xwc,
 							     CWX | CWY,
-							     gravity);
+							     gravity, 1);
 
 		    if ((*w->screen->placeWindow) (w, xwc.x, xwc.y,
 						   &newX, &newY))
@@ -2061,6 +2141,15 @@ handleEvent (CompDisplay *d,
 
 		if (!(w->state & CompWindowStateHiddenMask))
 		{
+		    /* predict that input will be moved to window. this
+		       makes it look like the window became active just
+		       before it got mapped to external applications */
+		    if (w->inputHint && allowFocus)
+			XChangeProperty (d->display, w->screen->root.id,
+					 d->winActiveAtom,
+					 XA_WINDOW, 32, PropModeReplace,
+					 (unsigned char *) &w->id, 1);
+			
 		    w->pendingMaps++;
 		    XMapWindow (d->display, w->id);
 		}
@@ -2165,14 +2254,19 @@ handleEvent (CompDisplay *d,
 	    {
 		unsigned int state = w->state;
 
-		if (w->id != d->activeWindow)
+		if (w->id != w->parent->activeChild)
 		{
-		    d->activeWindow = w->id;
+		    w->parent->previousActiveChild = w->parent->activeChild; 
+		    w->parent->activeChild = w->id;
+
+		    if (w->parent == &w->screen->root)
+			d->activeWindow = w->id;
+
 		    w->activeNum = w->screen->activeNum++;
 
 		    addToCurrentActiveWindowHistory (w->screen, w->id);
 
-		    XChangeProperty (d->display, w->screen->root,
+		    XChangeProperty (d->display, w->screen->root.id,
 				     d->winActiveAtom,
 				     XA_WINDOW, 32, PropModeReplace,
 				     (unsigned char *) &w->id, 1);
@@ -2324,7 +2418,7 @@ handleEvent (CompDisplay *d,
 
 	    for (s = d->screens; s; s = s->next)
 	    {
-		for (w = s->windows; w; w = w->next)
+		for (w = s->root.windows; w; w = w->next)
 		{
 		    if (w->syncAlarm == sa->alarm)
 			break;
diff --git a/src/main.c b/src/main.c
index ff8328d..ec76311 100644
--- a/src/main.c
+++ b/src/main.c
@@ -68,6 +68,9 @@ Bool onlyCurrentScreen = FALSE;
 Bool useCow = TRUE;
 #endif
 
+Bool windowManagement = FALSE;
+Bool manualCompositeManagement = FALSE;
+
 CompMetadata coreMetadata;
 
 static void
@@ -435,6 +438,15 @@ main (int argc, char **argv)
     if (!addDisplay (displayName))
 	return 1;
 
+    while (core.displays->dirtyPluginList)
+    {
+	updatePlugins (core.displays);
+	handleTimeouts (&core.lastTimeout);
+    }
+
+    if (!manageDisplay (core.displays))
+	return 1;
+
     eventLoop ();
 
     if (!disableSm)
diff --git a/src/paint.c b/src/paint.c
index a2051fa..529fdc6 100644
--- a/src/paint.c
+++ b/src/paint.c
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#include <assert.h>
 
 #include <compiz-core.h>
 
@@ -157,7 +158,7 @@ paintBackground (CompScreen   *s,
     if (!nBox)
 	return;
 
-    if (s->desktopWindowCount)
+    if (s->root.desktopWindowCount)
     {
 	if (bg->name)
 	{
@@ -251,167 +252,54 @@ paintOutputRegion (CompScreen	       *screen,
 		   CompOutput	       *output,
 		   unsigned int	       mask)
 {
-    static Region tmpRegion = NULL;
-    CompWindow    *w;
-    CompCursor	  *c;
-    int		  count, windowMask, odMask, i;
-    CompWindow	  *fullscreenWindow = NULL;
-    CompWalker    walk;
-    Bool          status;
-    Bool          withOffset = FALSE;
-    CompTransform vTransform;
-    int           offX, offY;
-    Region        clip = region;
-
-    if (!tmpRegion)
-    {
-	tmpRegion = XCreateRegion ();
-	if (!tmpRegion)
-	    return;
-    }
+    Region      r = XCreateRegion ();
+    CompPainter painter;
+    CompCursor	*c;
+    int		windowMask = 0;
+
+    assert (r);
+
+    (*screen->initObjectPainter) (screen, &painter);
 
     if (mask & PAINT_SCREEN_TRANSFORMED_MASK)
-    {
-	windowMask     = PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
-	count	       = 1;
-    }
-    else
-    {
-	windowMask     = 0;
-	count	       = 0;
-    }
+    	windowMask = PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
 
-    XSubtractRegion (region, &emptyRegion, tmpRegion);
+    if (mask & PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK)
+    	windowMask |= PAINT_WINDOW_WITH_TRANSFORMED_CHILD_MASK;
 
-    (*screen->initWindowWalker) (screen, &walk);
+    XSubtractRegion (region, &emptyRegion, r);
 
     if (!(mask & PAINT_SCREEN_NO_OCCLUSION_DETECTION_MASK))
     {
-	/* detect occlusions */
-	for (w = (*walk.last) (screen); w; w = (*walk.prev) (w))
-	{
-	    if (w->destroyed)
-		continue;
-
-	    if (!w->shaded)
-	    {
-		if (w->attrib.map_state != IsViewable || !w->damaged)
-		    continue;
-	    }
+	XSubtractRegion (r, &emptyRegion, screen->root.clip);
 
-	    /* copy region */
-	    XSubtractRegion (tmpRegion, &emptyRegion, w->clip);
+	if ((*painter.paintObject) (&screen->root,
+				    &screen->root.paint,
+				    transform,
+				    r,
+				    PAINT_WINDOW_OCCLUSION_DETECTION_MASK))
+	    XSubtractRegion (r, screen->root.region, r);
 
-	    odMask = PAINT_WINDOW_OCCLUSION_DETECTION_MASK;
-		
-	    if ((screen->windowOffsetX != 0 || screen->windowOffsetY != 0) &&
-		!windowOnAllViewports (w))
-	    {
-		withOffset = TRUE;
-
-		getWindowMovementForOffset (w, screen->windowOffsetX,
-					    screen->windowOffsetY,
-					    &offX, &offY);
-
-		vTransform = *transform;
-		matrixTranslate (&vTransform, offX, offY, 0);
-	 
-		XOffsetRegion (w->clip, -offX, -offY);
-
-		odMask |= PAINT_WINDOW_WITH_OFFSET_MASK;
-		status = (*screen->paintWindow) (w, &w->paint, &vTransform,
-						 tmpRegion, odMask);
-	    }
-	    else
-	    {
-		withOffset = FALSE;
-		status = (*screen->paintWindow) (w, &w->paint, transform, tmpRegion,
-						 odMask);
-	    }
-
-	    if (status)
-	    {
-		if (withOffset)
-		{
-		    XOffsetRegion (w->region, offX, offY);
-		    XSubtractRegion (tmpRegion, w->region, tmpRegion);
-		    XOffsetRegion (w->region, -offX, -offY);
-		}
-		else
-		    XSubtractRegion (tmpRegion, w->region, tmpRegion);
-
-		/* unredirect top most fullscreen windows. */
-		if (count == 0 &&
-		    screen->opt[COMP_SCREEN_OPTION_UNREDIRECT_FS].value.b)
-		{
-		    if (XEqualRegion (w->region, &screen->region) &&
-			!REGION_NOT_EMPTY (tmpRegion))
-		    {
-			fullscreenWindow = w;
-		    }
-		    else
-		    {
-			for (i = 0; i < screen->nOutputDev; i++)
-			    if (XEqualRegion (w->region,
-					      &screen->outputDev[i].region))
-				fullscreenWindow = w;
-		    }
-		}
-	    }
-
-	    count++;
-	}
+	windowMask |= PAINT_WINDOW_CLIP_MASK;
     }
 
-    if (fullscreenWindow)
-	unredirectWindow (fullscreenWindow);
-
     if (!(mask & PAINT_SCREEN_NO_BACKGROUND_MASK))
-	paintBackground (screen, tmpRegion,
-			 (mask & PAINT_SCREEN_TRANSFORMED_MASK));
-
-    /* paint all windows from bottom to top */
-    for (w = (*walk.first) (screen); w; w = (*walk.next) (w))
-    {
-	if (w->destroyed)
-	    continue;
-
-	if (w == fullscreenWindow)
-	    continue;
-
-	if (!w->shaded)
-	{
-	    if (w->attrib.map_state != IsViewable || !w->damaged)
-		continue;
-	}
+	paintBackground (screen, r, (mask & PAINT_SCREEN_TRANSFORMED_MASK));
 
-	if (!(mask & PAINT_SCREEN_NO_OCCLUSION_DETECTION_MASK))
-	    clip = w->clip;
+    (*painter.paintObject) (&screen->root,
+			    &screen->root.paint,
+			    transform,
+			    r,
+			    windowMask);
 
-	if ((screen->windowOffsetX != 0 || screen->windowOffsetY != 0) &&
-	    !windowOnAllViewports (w))
-	{
-	    getWindowMovementForOffset (w, screen->windowOffsetX,
-					screen->windowOffsetY, &offX, &offY);
-
-	    vTransform = *transform;
-	    matrixTranslate (&vTransform, offX, offY, 0);
-	    (*screen->paintWindow) (w, &w->paint, &vTransform, clip,
-				    windowMask | PAINT_WINDOW_WITH_OFFSET_MASK);
-	}
-	else
-	{
-	    (*screen->paintWindow) (w, &w->paint, transform, clip,
-				    windowMask);
-	}
-    }
-
-    if (walk.fini)
-	(*walk.fini) (screen, &walk);
+    if (painter.fini)
+	(*painter.fini) (screen, &painter);
 
     /* paint cursors */
     for (c = screen->cursors; c; c = c->next)
-	(*screen->paintCursor) (c, transform, tmpRegion, 0);
+	(*screen->paintCursor) (c, transform, r, 0);
+
+    XDestroyRegion (r);
 }
 
 void
@@ -420,21 +308,15 @@ enableOutputClipping (CompScreen 	  *screen,
 		      Region		  region,
 		      CompOutput 	  *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 = output->width / 2.0;
-    GLdouble halfH = output->height / 2.0;
-
-    GLdouble cx = output->region.extents.x1 + halfW;
-    GLdouble cy = (h - output->region.extents.y2) + halfH;
+    GLdouble x1 = region->extents.x1 > 0 ? 1.0 / region->extents.x1 : MAXSHORT;
+    GLdouble y1 = region->extents.y1 > 0 ? 1.0 / region->extents.y1 : MAXSHORT;
+    GLdouble x2 = region->extents.x2 > 0 ? 1.0 / region->extents.x2 : MAXSHORT;
+    GLdouble y2 = region->extents.y2 > 0 ? 1.0 / region->extents.y2 : MAXSHORT;
 
-    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 };
+    GLdouble top[4]    = { 0.0,  y1, 0.0, -1.0 };
+    GLdouble bottom[4] = { 0.0, -y2, 0.0,  1.0 };
+    GLdouble left[4]   = {  x1, 0.0, 0.0, -1.0 };
+    GLdouble right[4]  = { -x2, 0.0, 0.0,  1.0 };
 
     glPushMatrix ();
     glLoadMatrixf (transform->m);
@@ -461,9 +343,6 @@ disableOutputClipping (CompScreen *screen)
     glDisable (GL_CLIP_PLANE3);
 }
 
-#define CLIP_PLANE_MASK (PAINT_SCREEN_TRANSFORMED_MASK | \
-			 PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK)
-
 void
 paintTransformedOutput (CompScreen		*screen,
 			const ScreenPaintAttrib *sAttrib,
@@ -481,34 +360,14 @@ paintTransformedOutput (CompScreen		*screen,
 
     (*screen->applyScreenTransform) (screen, sAttrib, output, &sTransform);
 
-    if ((mask & CLIP_PLANE_MASK) == CLIP_PLANE_MASK)
-    {
-	screen->enableOutputClipping (screen, &sTransform, region, output);
-
-	transformToScreenSpace (screen, output, -sAttrib->zTranslate,
-				&sTransform);
-
-	glPushMatrix ();
-	glLoadMatrixf (sTransform.m);
+    transformToScreenSpace (screen, output, -sAttrib->zTranslate, &sTransform);
 
-	paintOutputRegion (screen, &sTransform, region, output, mask);
-
-	glPopMatrix ();
-
-	screen->disableOutputClipping (screen);
-    }
-    else
-    {
-	transformToScreenSpace (screen, output, -sAttrib->zTranslate,
-				&sTransform);
-
-	glPushMatrix ();
-	glLoadMatrixf (sTransform.m);
+    glPushMatrix ();
+    glLoadMatrixf (sTransform.m);
 
-	paintOutputRegion (screen, &sTransform, region, output, mask);
+    paintOutputRegion (screen, &sTransform, region, output, mask);
 
-	glPopMatrix ();
-    }
+    glPopMatrix ();
 }
 
 Bool
@@ -1194,7 +1053,13 @@ drawWindow (CompWindow		 *w,
 	return TRUE;
 
     if (w->attrib.map_state != IsViewable)
-	return TRUE;
+	return FALSE;
+
+    if (!w->damaged)
+	return FALSE;
+
+    if (!w->parent || !w->parent->redirectSubwindows)
+	return FALSE;
 
     if (!w->texture->pixmap && !bindWindow (w))
 	return FALSE;
@@ -1210,6 +1075,44 @@ drawWindow (CompWindow		 *w,
     return TRUE;
 }
 
+static int
+paintOffsetX (CompWindow *w,
+	      int        x)
+{
+    int vWidth = w->screen->width * (w->screen->hsize - 1);
+
+    if (vWidth)
+    {
+	int wx = w->attrib.x + x;
+
+	if (wx - w->input.left < -vWidth)
+	    return x + vWidth + w->screen->width;
+	else if (wx + w->width + w->input.right > vWidth)
+	    return x - vWidth - w->screen->width;
+    }
+
+    return x;
+}
+
+static int
+paintOffsetY (CompWindow *w,
+	      int        y)
+{
+    int vHeight = w->screen->height * (w->screen->vsize - 1);
+
+    if (vHeight)
+    {
+	int wy = w->attrib.y + y;
+    
+	if (wy - w->input.top < -vHeight)
+	    return y + vHeight + w->screen->height;
+	else if (wy + w->height + w->input.bottom > vHeight)
+	    return y - vHeight - w->screen->height;
+    }
+
+    return y;
+}
+
 Bool
 paintWindow (CompWindow		     *w,
 	     const WindowPaintAttrib *attrib,
@@ -1217,8 +1120,10 @@ paintWindow (CompWindow		     *w,
 	     Region		     region,
 	     unsigned int	     mask)
 {
-    FragmentAttrib fragment;
-    Bool	   status;
+    CompWindow  *c;
+    CompWalker  walk;
+    CompPainter painter;
+    Bool	status;
 
     w->lastPaint = *attrib;
 
@@ -1229,38 +1134,395 @@ paintWindow (CompWindow		     *w,
 
     if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
     {
-	if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
-	    return FALSE;
+	Bool occlude = TRUE;
 
 	if (mask & PAINT_WINDOW_NO_CORE_INSTANCE_MASK)
-	    return FALSE;
+	    occlude = FALSE;
+
+	if (w->shaded)
+	    occlude = FALSE;
+
+	if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
+	    occlude = FALSE;
 
 	if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
-	    return FALSE;
+	    occlude = FALSE;
 
-	if (w->shaded)
-	    return FALSE;
+	if (w->attrib.map_state != IsViewable)
+	    occlude = FALSE;
 
-	return TRUE;
+	if (!w->redirected || !w->damaged)
+	    occlude = FALSE;
+
+	(*w->screen->initWindowWalker) (w->screen, w, &walk);
+	(*w->screen->initObjectPainter) (w->screen, &painter);
+
+	c = (*walk.last) (w);
+	if (c)
+	{
+	    Region        r = XCreateRegion ();
+	    CompTransform wTransform = *transform;
+	    int		  count = 0;
+	    CompWindow	  *fullscreenWindow = NULL;
+
+	    assert (r);
+
+	    XIntersectRegion (region, w->region, r);
+
+	    if (w->attrib.x || w->attrib.y)
+	    {
+		matrixTranslate (&wTransform, w->attrib.x, w->attrib.y, 0);
+		XOffsetRegion (r, -w->attrib.x, -w->attrib.y);
+		mask |= PAINT_WINDOW_WITH_OFFSET_MASK;
+	    }
+	
+	    for (; c; c = (*walk.prev) (c))
+	    {
+		CompTransform     cTransform = wTransform;
+		WindowPaintAttrib cPaint = c->paint;
+		int               viewportOffsetX = 0;
+		int               viewportOffsetY = 0;
+		int               offsetMask = 0;
+		
+		if (c->destroyed)
+		    continue;
+
+		cPaint.opacity = MULTIPLY_USHORT (cPaint.opacity,
+						  attrib->opacity);
+		cPaint.brightness = MULTIPLY_USHORT (cPaint.brightness,
+						     attrib->brightness);
+		cPaint.saturation = MULTIPLY_USHORT (cPaint.saturation,
+						     attrib->saturation);
+
+		if (!windowOnAllViewports (c))
+		{
+		    if (w->viewportOffsetX || w->viewportOffsetY)
+		    {
+			viewportOffsetX = paintOffsetX (c, w->viewportOffsetX);
+			viewportOffsetY = paintOffsetY (c, w->viewportOffsetY);
+
+			matrixTranslate (&cTransform,
+					 viewportOffsetX,
+					 viewportOffsetY,
+					 0);
+
+			XOffsetRegion (r,
+				       -viewportOffsetX,
+				       -viewportOffsetY);
+
+			offsetMask = PAINT_WINDOW_WITH_OFFSET_MASK;
+		    }
+		}
+
+		/* copy region */
+		XSubtractRegion (r, &emptyRegion, c->clip);
+
+		if ((*painter.paintObject) (c,
+					    &cPaint,
+					    &cTransform,
+					    r,
+					    mask | offsetMask) && !occlude)
+		    XSubtractRegion (r, c->region, r);
+
+		if (viewportOffsetX || viewportOffsetY)
+		    XOffsetRegion (r,
+				   viewportOffsetX,
+				   viewportOffsetY);
+
+		/* unredirect top most top-level fullscreen windows. */
+		if (!w->parent &&
+		    count == 0 &&
+		    w->screen->opt[COMP_SCREEN_OPTION_UNREDIRECT_FS].value.b)
+		{
+		    if (XEqualRegion (c->region, &w->screen->region) &&
+			!REGION_NOT_EMPTY (r))
+		    {
+			fullscreenWindow = c;
+		    }
+		    else
+		    {
+			int i;
+
+			for (i = 0; i < w->screen->nOutputDev; i++)
+			    if (XEqualRegion (c->region,
+					      &w->screen->outputDev[i].region))
+				fullscreenWindow = c;
+		    }
+		}
+
+		count++;
+	    }
+
+	    if (fullscreenWindow)
+		unredirectWindow (fullscreenWindow);
+
+	    if (!occlude)
+	    {
+		if (w->attrib.x || w->attrib.y)
+		    XOffsetRegion (r, w->attrib.x, w->attrib.y);
+
+		XSubtractRegion (region, w->region, region);
+		XUnionRegion (region, r, region);
+	    }
+
+	    XDestroyRegion (r);
+	}
+
+	if (painter.fini)
+	    (*painter.fini) (w->screen, &painter);
+	if (walk.fini)
+	    (*walk.fini) (w->screen, &walk);
+
+	return occlude;
     }
 
     if (mask & PAINT_WINDOW_NO_CORE_INSTANCE_MASK)
-	return TRUE;
+    {
+	status = TRUE;
+    }
+    else
+    {
+	FragmentAttrib fragment;
 
-    initFragmentAttrib (&fragment, attrib);
+	initFragmentAttrib (&fragment, attrib);
 
-    if (mask & PAINT_WINDOW_TRANSFORMED_MASK ||
-        mask & PAINT_WINDOW_WITH_OFFSET_MASK)
-    {
-	glPushMatrix ();
-	glLoadMatrixf (transform->m);
+	if (mask & (PAINT_WINDOW_TRANSFORMED_MASK |
+		    PAINT_WINDOW_WITH_OFFSET_MASK))
+	{
+	    glPushMatrix ();
+	    glLoadMatrixf (transform->m);
+	}
+
+	status = (*w->screen->drawWindow) (w, transform, &fragment, region, mask);
+
+	if (mask & (PAINT_WINDOW_TRANSFORMED_MASK |
+		    PAINT_WINDOW_WITH_OFFSET_MASK))
+	    glPopMatrix ();
     }
 
-    status = (*w->screen->drawWindow) (w, transform, &fragment, region, mask);
+    (*w->screen->initWindowWalker) (w->screen, w, &walk);
+    (*w->screen->initObjectPainter) (w->screen, &painter);
+
+    c = (*walk.first) (w);
+    if (c)
+    {
+	Region        clip = NULL;
+	CompTransform wTransform = *transform;
+	unsigned int  clipMask = PAINT_WINDOW_WITH_TRANSFORMED_CHILD_MASK;
+
+	if (!(mask & PAINT_WINDOW_CLIP_MASK))
+	{
+	    clip = XCreateRegion ();
+	    assert (clip);
+	    XIntersectRegion (region, w->region, clip);
+	}
+
+	if (w->attrib.x || w->attrib.y)
+	{
+	    matrixTranslate (&wTransform, w->attrib.x, w->attrib.y, 0);
+
+	    mask |= PAINT_WINDOW_WITH_OFFSET_MASK;
 
-    if (mask & PAINT_WINDOW_TRANSFORMED_MASK ||
-        mask & PAINT_WINDOW_WITH_OFFSET_MASK)
-	glPopMatrix ();
+	    if (clip)
+		XOffsetRegion (clip, -w->attrib.x, -w->attrib.y);
+	}
+
+	if (w->redirectSubwindows)
+	{
+	    /* root only need clip planes when transformed */
+	    if (!w->parent)
+		clipMask |= PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
+
+	    if ((mask & clipMask) == clipMask)
+	    {
+		glPushAttrib (GL_TRANSFORM_BIT);
+
+		if (mask & PAINT_WINDOW_CLIP_MASK)
+		{
+		    REGION reg;
+
+		    reg.rects    = &reg.extents;
+		    reg.numRects = reg.size = 1;
+		    reg.extents  = w->clip->extents;
+
+		    if (reg.extents.x1 < w->region->extents.x1)
+			reg.extents.x1 = w->region->extents.x1;
+		    if (reg.extents.y1 < w->region->extents.y1)
+			reg.extents.y1 = w->region->extents.y1;
+		    if (reg.extents.x2 > w->region->extents.x2)
+			reg.extents.x2 = w->region->extents.x2;
+		    if (reg.extents.y2 > w->region->extents.y2)
+			reg.extents.y2 = w->region->extents.y2;
+
+		    reg.extents.x1 -= w->attrib.x;
+		    reg.extents.y1 -= w->attrib.y;
+		    reg.extents.x2 -= w->attrib.x;
+		    reg.extents.y2 -= w->attrib.y;
+
+		    (*w->screen->enableOutputClipping) (w->screen,
+							&wTransform,
+							&reg,
+							0);
+		}
+		else
+		    (*w->screen->enableOutputClipping) (w->screen,
+							&wTransform,
+							clip,
+							0);
+	    }
+	}
+
+	/* paint all sub-windows from bottom to top */
+	for (; c; c = (*walk.next) (c))
+	{
+	    CompTransform     cTransform = wTransform;
+	    WindowPaintAttrib cPaint = c->paint;
+	    int               viewportOffsetX = 0;
+	    int               viewportOffsetY = 0;
+	    int               offsetMask = 0;
+
+	    if (c->destroyed)
+		continue;
+
+	    cPaint.opacity = MULTIPLY_USHORT (cPaint.opacity,
+					      attrib->opacity);
+	    cPaint.brightness = MULTIPLY_USHORT (cPaint.brightness,
+						 attrib->brightness);
+	    cPaint.saturation = MULTIPLY_USHORT (cPaint.saturation,
+						 attrib->saturation);
+
+	    if (mask & PAINT_WINDOW_CLIP_MASK)
+		clip = c->clip;
+
+	    if (!windowOnAllViewports (c))
+	    {
+		if (w->viewportOffsetX || w->viewportOffsetY)
+		{
+		    viewportOffsetX = paintOffsetX (c, w->viewportOffsetX);
+		    viewportOffsetY = paintOffsetY (c, w->viewportOffsetY);
+
+		    matrixTranslate (&cTransform,
+				     viewportOffsetX,
+				     viewportOffsetY,
+				     0);
+
+		    if (clip != c->clip)
+			XOffsetRegion (clip,
+				       -viewportOffsetX,
+				       -viewportOffsetY);
+
+		    offsetMask = PAINT_WINDOW_WITH_OFFSET_MASK;
+		}
+	    }
+
+	    (*painter.paintObject) (c,
+				    &cPaint,
+				    &cTransform,
+				    clip,
+				    mask | offsetMask);
+
+	    if (clip != c->clip && (viewportOffsetX || viewportOffsetY))
+		XOffsetRegion (clip,
+			       viewportOffsetX,
+			       viewportOffsetY);
+	}
+
+	if (w->redirectSubwindows)
+	{
+	    if ((mask & clipMask) == clipMask)
+		glPopAttrib ();
+	}
+
+	if (!(mask & PAINT_WINDOW_CLIP_MASK))
+	    XDestroyRegion (clip);
+    }
+
+    if (painter.fini)
+	(*painter.fini) (w->screen, &painter);
+    if (walk.fini)
+	(*walk.fini) (w->screen, &walk);
 
     return status;
 }
+
+static void
+drawWindowAndChildren (CompWindow              *w,
+		       const WindowPaintAttrib *attrib,
+		       const CompTransform     *transform,
+		       Region                  region)
+{
+    FragmentAttrib fragment;
+    unsigned int   wMask = PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
+
+    if (attrib)
+	initFragmentAttrib (&fragment, attrib);
+    else
+	initFragmentAttrib (&fragment, &w->lastPaint);
+
+    if (w->alpha || fragment.opacity != OPAQUE)
+	wMask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+
+    (*w->screen->drawWindow) (w, transform, &fragment, region, wMask);
+
+    if (w->windows)
+    {
+	Region r;
+
+	r = XCreateRegion ();
+	if (r)
+	{
+	    CompWindow *c;
+
+	    XSubtractRegion (region, &emptyRegion, r);
+	    XIntersectRegion (r, w->region, r);
+	    XOffsetRegion (r, -w->attrib.x, -w->attrib.y);
+
+	    glTranslatef (w->attrib.x, w->attrib.y, 0);
+
+	    for (c = w->windows; c; c = c->next)
+		drawWindowAndChildren (c, attrib, transform, r);
+
+	    glTranslatef (-w->attrib.x, -w->attrib.y, 0);
+
+	    XDestroyRegion (r);
+	}
+    }
+}
+
+void
+drawTransformedWindowWithChildren (CompWindow              *w,
+				   const WindowPaintAttrib *attrib,
+				   const CompTransform     *transform)
+{
+    FragmentAttrib fragment;
+    unsigned int   wMask = PAINT_WINDOW_TRANSFORMED_MASK;
+
+    if (attrib)
+	initFragmentAttrib (&fragment, attrib);
+    else
+	initFragmentAttrib (&fragment, &w->lastPaint);
+
+    if (w->alpha || fragment.opacity != OPAQUE)
+	wMask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+
+    glPushMatrix ();
+    glLoadMatrixf (transform->m);
+
+    (*w->screen->drawWindow) (w, transform, &fragment, &infiniteRegion, wMask);
+
+    if (w->windows)
+    {
+	CompWindow *c;
+
+	XOffsetRegion (w->region, -w->attrib.x, -w->attrib.y);
+	glTranslatef (w->attrib.x, w->attrib.y, 0);
+
+	for (c = w->windows; c; c = c->next)
+	    drawWindowAndChildren (c, attrib, transform, w->region);
+
+	glTranslatef (-w->attrib.x, -w->attrib.y, 0);
+	XOffsetRegion (w->region, w->attrib.x, w->attrib.y);
+    }
+
+    glPopMatrix ();
+}
diff --git a/src/screen.c b/src/screen.c
index 33cb3cc..12ac091 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -184,6 +184,9 @@ setDesktopHints (CompScreen *s)
     unsigned long *data;
     int		  size, offset, hintSize, i;
 
+    if (!s->root.substructureRedirect)
+	return;
+
     size = s->nDesktop * 2 + s->nDesktop * 2 + s->nDesktop * 4 + 1;
 
     data = malloc (sizeof (unsigned long) * size);
@@ -200,7 +203,7 @@ setDesktopHints (CompScreen *s)
     }
 
     if (!desktopHintEqual (s, data, size, offset, hintSize))
-	XChangeProperty (d->display, s->root, d->desktopViewportAtom,
+	XChangeProperty (d->display, s->root.id, d->desktopViewportAtom,
 			 XA_CARDINAL, 32, PropModeReplace,
 			 (unsigned char *) &data[offset], hintSize);
 
@@ -213,7 +216,7 @@ setDesktopHints (CompScreen *s)
     }
 
     if (!desktopHintEqual (s, data, size, offset, hintSize))
-	XChangeProperty (d->display, s->root, d->desktopGeometryAtom,
+	XChangeProperty (d->display, s->root.id, d->desktopGeometryAtom,
 			 XA_CARDINAL, 32, PropModeReplace,
 			 (unsigned char *) &data[offset], hintSize);
 
@@ -229,7 +232,7 @@ setDesktopHints (CompScreen *s)
     }
 
     if (!desktopHintEqual (s, data, size, offset, hintSize))
-	XChangeProperty (d->display, s->root, d->workareaAtom,
+	XChangeProperty (d->display, s->root.id, d->workareaAtom,
 			 XA_CARDINAL, 32, PropModeReplace,
 			 (unsigned char *) &data[offset], hintSize);
 
@@ -239,7 +242,7 @@ setDesktopHints (CompScreen *s)
     hintSize = 1;
 
     if (!desktopHintEqual (s, data, size, offset, hintSize))
-	XChangeProperty (d->display, s->root, d->numberOfDesktopsAtom,
+	XChangeProperty (d->display, s->root.id, d->numberOfDesktopsAtom,
 			 XA_CARDINAL, 32, PropModeReplace,
 			 (unsigned char *) &data[offset], hintSize);
 
@@ -375,8 +378,11 @@ updateOutputDevices (CompScreen	*s)
 
     updateWorkareaForScreen (s);
 
-    setDefaultViewport (s);
-    damageScreen (s);
+    if (manualCompositeManagement)
+    {
+	setDefaultViewport (s);
+	damageScreen (s);
+    }
 
     region = XCreateRegion ();
     if (region)
@@ -644,9 +650,9 @@ static void
 updateStartupFeedback (CompScreen *s)
 {
     if (s->startupSequences)
-	XDefineCursor (s->display->display, s->root, s->busyCursor);
+	XDefineCursor (s->display->display, s->root.id, s->busyCursor);
     else
-	XDefineCursor (s->display->display, s->root, s->normalCursor);
+	XDefineCursor (s->display->display, s->root.id, s->normalCursor);
 }
 
 #define STARTUP_TIMEOUT_DELAY 15000
@@ -853,11 +859,12 @@ reshape (CompScreen *s,
 {
 
 #ifdef USE_COW
-    if (useCow)
+    if (useCow && manualCompositeManagement)
 	XMoveResizeWindow (s->display->display, s->overlay, 0, 0, w, h);
 #endif
 
-    if (s->display->xineramaExtension)
+    if (s->display->xineramaExtension &&
+	XineramaIsActive (s->display->display))
     {
 	CompDisplay *d = s->display;
 
@@ -971,7 +978,7 @@ updateScreenBackground (CompScreen  *screen,
 
     for (i = 0; pixmap == 0 && i < 2; i++)
     {
-	status = XGetWindowProperty (dpy, screen->root,
+	status = XGetWindowProperty (dpy, screen->root.id,
 				     screen->display->xBackgroundAtom[i],
 				     0, 4, FALSE, AnyPropertyType,
 				     &actualType, &actualFormat, &nItems,
@@ -1054,7 +1061,7 @@ detectRefreshRateOfScreen (CompScreen *s)
 	{
 	    XRRScreenConfiguration *config;
 
-	    config  = XRRGetScreenInfo (s->display->display, s->root);
+	    config  = XRRGetScreenInfo (s->display->display, s->root.id);
 	    value.i = (int) XRRConfigCurrentRate (config);
 
 	    XRRFreeScreenConfigInfo (config);
@@ -1081,6 +1088,8 @@ setSupportingWmCheck (CompScreen *s)
 {
     CompDisplay *d = s->display;
 
+    s->root.supportingWmCheckWindow = s->grabWindow;
+
     XChangeProperty (d->display, s->grabWindow, d->supportingWmCheckAtom,
 		     XA_WINDOW, 32, PropModeReplace,
 		     (unsigned char *) &s->grabWindow, 1);
@@ -1098,7 +1107,7 @@ setSupportingWmCheck (CompScreen *s)
 		     XA_ATOM, 32, PropModeAppend,
 		     (unsigned char *) &d->winStateHiddenAtom, 1);
 
-    XChangeProperty (d->display, s->root, d->supportingWmCheckAtom,
+    XChangeProperty (d->display, s->root.id, d->supportingWmCheckAtom,
 		     XA_WINDOW, 32, PropModeReplace,
 		     (unsigned char *) &s->grabWindow, 1);
 }
@@ -1199,11 +1208,66 @@ setSupported (CompScreen *s)
     data[i++] = d->moveResizeWindowAtom;
     data[i++] = d->restackWindowAtom;
 
-    XChangeProperty (d->display, s->root, d->supportedAtom, XA_ATOM, 32,
+    data[i++] = d->syncStateAtom;
+
+    XChangeProperty (d->display, s->root.id, d->supportedAtom, XA_ATOM, 32,
 		     PropModeReplace, (unsigned char *) data, i);
 }
 
-static void
+void
+getSupportingWmCheck (CompWindow *w)
+{
+    CompDisplay   *d = w->screen->display;
+    Atom	  actual;
+    int		  result, format;
+    unsigned long n, left;
+    unsigned char *propData;
+
+    w->supportingWmCheckWindow = None;
+    w->syncStateSupport        = FALSE;
+
+    result = XGetWindowProperty (d->display, w->id,
+				 d->supportingWmCheckAtom, 0L, 1L, FALSE,
+				 XA_WINDOW, &actual, &format,
+				 &n, &left, &propData);
+    if (result == Success && n && propData)
+    {
+	Window wmCheckWindow = *((unsigned long *) propData);
+
+	XFree (propData);
+
+	result = XGetWindowProperty (d->display,
+				     wmCheckWindow,
+				     d->supportingWmCheckAtom, 0L, 1L, FALSE,
+				     XA_WINDOW, &actual, &format,
+				     &n, &left, &propData);
+	if (result == Success && n && propData)
+	{
+	    XFree (propData);
+
+	    w->supportingWmCheckWindow = wmCheckWindow;
+
+	    result = XGetWindowProperty (d->display,
+					 w->id,
+					 d->supportedAtom, 0L, 4096L,
+					 FALSE, XA_ATOM, &actual, &format,
+					 &n, &left, &propData);
+	    if (result == Success && n && propData)
+	    {
+		unsigned long *data = (unsigned long *) propData;
+		int           i;
+
+		for (i = 0; i < n; i++)
+		    if ((Atom) data[i] == d->syncStateAtom)
+			w->syncStateSupport = TRUE;
+
+		XFree (propData);
+	    }
+	}
+    }
+}
+
+void
 getDesktopHints (CompScreen *s)
 {
     CompDisplay   *d = s->display;
@@ -1215,7 +1279,7 @@ getDesktopHints (CompScreen *s)
 
     if (useDesktopHints)
     {
-	result = XGetWindowProperty (s->display->display, s->root,
+	result = XGetWindowProperty (s->display->display, s->root.id,
 				     d->numberOfDesktopsAtom, 0L, 1L, FALSE,
 				     XA_CARDINAL, &actual, &format,
 				     &n, &left, &propData);
@@ -1229,7 +1293,7 @@ getDesktopHints (CompScreen *s)
 		s->nDesktop = data[0];
 	}
 
-	result = XGetWindowProperty (s->display->display, s->root,
+	result = XGetWindowProperty (s->display->display, s->root.id,
 				     d->currentDesktopAtom, 0L, 1L, FALSE,
 				     XA_CARDINAL, &actual, &format,
 				     &n, &left, &propData);
@@ -1244,7 +1308,7 @@ getDesktopHints (CompScreen *s)
 	}
     }
 
-    result = XGetWindowProperty (s->display->display, s->root,
+    result = XGetWindowProperty (s->display->display, s->root.id,
 				 d->desktopViewportAtom, 0L, 2L,
 				 FALSE, XA_CARDINAL, &actual, &format,
 				 &n, &left, &propData);
@@ -1265,7 +1329,7 @@ getDesktopHints (CompScreen *s)
 	XFree (propData);
     }
 
-    result = XGetWindowProperty (s->display->display, s->root,
+    result = XGetWindowProperty (s->display->display, s->root.id,
 				 d->showingDesktopAtom, 0L, 1L, FALSE,
 				 XA_CARDINAL, &actual, &format,
 				 &n, &left, &propData);
@@ -1279,17 +1343,20 @@ getDesktopHints (CompScreen *s)
 	    (*s->enterShowDesktopMode) (s);
     }
 
-    data[0] = s->currentDesktop;
+    if (s->root.substructureRedirect)
+    {
+	data[0] = s->currentDesktop;
 
-    XChangeProperty (d->display, s->root, d->currentDesktopAtom,
-		     XA_CARDINAL, 32, PropModeReplace,
-		     (unsigned char *) data, 1);
+	XChangeProperty (d->display, s->root.id, d->currentDesktopAtom,
+			 XA_CARDINAL, 32, PropModeReplace,
+			 (unsigned char *) data, 1);
 
-    data[0] = s->showingDesktopMask ? TRUE : FALSE;
+	data[0] = s->showingDesktopMask ? TRUE : FALSE;
 
-    XChangeProperty (d->display, s->root, d->showingDesktopAtom,
-		     XA_CARDINAL, 32, PropModeReplace,
-		     (unsigned char *) data, 1);
+	XChangeProperty (d->display, s->root.id, d->showingDesktopAtom,
+			 XA_CARDINAL, 32, PropModeReplace,
+			 (unsigned char *) data, 1);
+    }
 }
 
 void
@@ -1297,7 +1364,7 @@ showOutputWindow (CompScreen *s)
 {
 
 #ifdef USE_COW
-    if (useCow)
+    if (useCow && manualCompositeManagement)
     {
 	Display       *dpy = s->display->display;
 	XserverRegion region;
@@ -1326,7 +1393,7 @@ hideOutputWindow (CompScreen *s)
 {
 
 #ifdef USE_COW
-    if (useCow)
+    if (useCow && manualCompositeManagement)
     {
 	Display       *dpy = s->display->display;
 	XserverRegion region;
@@ -1349,7 +1416,7 @@ updateOutputWindow (CompScreen *s)
 {
 
 #ifdef USE_COW
-    if (useCow)
+    if (useCow && manualCompositeManagement)
     {
 	Display       *dpy = s->display->display;
 	XserverRegion region;
@@ -1365,7 +1432,7 @@ updateOutputWindow (CompScreen *s)
 
 	XSubtractRegion (&s->region, &emptyRegion, tmpRegion);
 
-	for (w = s->reverseWindows; w; w = w->prev)
+	for (w = s->root.reverseWindows; w; w = w->prev)
 	    if (w->overlayWindow)
 	    {
 		XSubtractRegion (tmpRegion, w->region, tmpRegion);
@@ -1393,9 +1460,10 @@ makeOutputWindow (CompScreen *s)
 {
 
 #ifdef USE_COW
-    if (useCow)
+    if (useCow && manualCompositeManagement)
     {
-	s->overlay = XCompositeGetOverlayWindow (s->display->display, s->root);
+	s->overlay = XCompositeGetOverlayWindow (s->display->display,
+						 s->root.id);
 	s->output  = s->overlay;
 
 	XSelectInput (s->display->display, s->output, ExposureMask);
@@ -1403,7 +1471,7 @@ makeOutputWindow (CompScreen *s)
     else
 #endif
 
-	s->output = s->overlay = s->root;
+	s->output = s->overlay = s->root.id;
 
     showOutputWindow (s);
 }
@@ -1417,10 +1485,13 @@ enterShowDesktopMode (CompScreen *s)
     int		  count = 0;
     CompOption    *st = &d->opt[COMP_DISPLAY_OPTION_HIDE_SKIP_TASKBAR_WINDOWS];
 
+    if (!s->root.substructureRedirect)
+	return;
+
     s->showingDesktopMask = ~(CompWindowTypeDesktopMask |
 			      CompWindowTypeDockMask);
 
-    for (w = s->windows; w; w = w->next)
+    for (w = s->root.windows; w; w = w->next)
     {
 	if ((s->showingDesktopMask & w->wmType) &&
 	    (!(w->state & CompWindowStateSkipTaskbarMask) || st->value.b))
@@ -1443,7 +1514,7 @@ enterShowDesktopMode (CompScreen *s)
 	data = 0;
     }
 
-    XChangeProperty (s->display->display, s->root,
+    XChangeProperty (s->display->display, s->root.id,
 		     s->display->showingDesktopAtom,
 		     XA_CARDINAL, 32, PropModeReplace,
 		     (unsigned char *) &data, 1);
@@ -1456,6 +1527,9 @@ leaveShowDesktopMode (CompScreen *s,
     CompWindow    *w;
     unsigned long data = 0;
 
+    if (!s->root.substructureRedirect)
+	return;
+
     if (window)
     {
 	if (!window->inShowDesktopMode)
@@ -1465,7 +1539,7 @@ leaveShowDesktopMode (CompScreen *s,
 	showWindow (window);
 
 	/* return if some other window is still in show desktop mode */
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = w->next)
 	    if (w->inShowDesktopMode)
 		return;
 
@@ -1475,7 +1549,7 @@ leaveShowDesktopMode (CompScreen *s,
     {
 	s->showingDesktopMask = 0;
 
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = w->next)
 	{
 	    if (!w->inShowDesktopMode)
 		continue;
@@ -1489,22 +1563,22 @@ leaveShowDesktopMode (CompScreen *s,
 	focusDefaultWindow (s);
     }
 
-    XChangeProperty (s->display->display, s->root,
+    XChangeProperty (s->display->display, s->root.id,
 		     s->display->showingDesktopAtom,
 		     XA_CARDINAL, 32, PropModeReplace,
 		     (unsigned char *) &data, 1);
 }
 
 static CompWindow *
-walkFirst (CompScreen *s)
+walkFirst (CompWindow *parent)
 {
-    return s->windows;
+    return parent->windows;
 }
 
 static CompWindow *
-walkLast (CompScreen *s)
+walkLast (CompWindow *parent)
 {
-    return s->reverseWindows;
+    return parent->reverseWindows;
 }
 
 static CompWindow *
@@ -1521,6 +1595,7 @@ walkPrev (CompWindow *w)
 
 static void
 initWindowWalker (CompScreen *screen,
+		  CompWindow *window,
 		  CompWalker *walker)
 {
     walker->fini  = NULL;
@@ -1530,6 +1605,42 @@ initWindowWalker (CompScreen *screen,
     walker->prev  = walkPrev;
 }
 
+static Bool
+paintObject (CompWindow		     *w,
+	     const WindowPaintAttrib *attrib,
+	     const CompTransform     *transform,
+	     Region		     region,
+	     unsigned int	     mask)
+{
+    PaintWindowProc paint = w->screen->paintWindow;
+    Bool            status;
+
+    if (w->parent)
+	w->paintWindowStack = w->parent->paintWindowStack;
+    else
+	w->paintWindowStack = paint;
+
+    status = (*w->paintWindowStack) (w, attrib, transform, region, mask);
+
+    w->screen->paintWindow = paint;
+
+    return status;
+}
+
+static void
+initObjectPainter (CompScreen  *screen,
+		   CompPainter *painter)
+{
+    painter->fini        = NULL;
+    painter->paintObject = paintObject;
+}
+
+static FuncPtr
+dummyGetProcAddress (const GLubyte *procName)
+{
+    return NULL;
+}
+
 static void
 freeScreen (CompScreen *s)
 {
@@ -1611,7 +1722,7 @@ addScreen (CompDisplay *display,
     GLfloat		 light0Position[] = { -0.5f, 0.5f, -9.0f, 1.0f };
     CompWindow		 *w;
 
-    s = malloc (sizeof (CompScreen));
+    s = calloc (1, sizeof (CompScreen));
     if (!s)
 	return FALSE;
 
@@ -1652,9 +1763,6 @@ addScreen (CompDisplay *display,
     s->hsize = s->opt[COMP_SCREEN_OPTION_HSIZE].value.i;
     s->vsize = s->opt[COMP_SCREEN_OPTION_VSIZE].value.i;
 
-    s->windowOffsetX = 0;
-    s->windowOffsetY = 0;
-
     s->nDesktop	      = 1;
     s->currentDesktop = 0;
 
@@ -1680,11 +1788,12 @@ addScreen (CompDisplay *display,
 
     s->screenNum = screenNum;
     s->colormap  = DefaultColormap (dpy, screenNum);
-    s->root	 = XRootWindow (dpy, screenNum);
 
     s->mapNum    = 1;
     s->activeNum = 1;
 
+    initRootWindow (s, &s->root);
+
     s->groups = NULL;
 
     s->snContext = sn_monitor_context_new (display->snDisplay,
@@ -1712,9 +1821,6 @@ addScreen (CompDisplay *display,
     s->nOutputDev	= 0;
     s->currentOutputDev = 0;
 
-    s->windows = 0;
-    s->reverseWindows = 0;
-
     s->nextRedraw  = 0;
     s->frameStatus = 0;
     s->timeMult    = 1;
@@ -1781,11 +1887,12 @@ addScreen (CompDisplay *display,
 
     s->outputChangeNotify = outputChangeNotify;
 
-    s->initWindowWalker = initWindowWalker;
+    s->initWindowWalker  = initWindowWalker;
+    s->initObjectPainter = initObjectPainter;
 
-    s->getProcAddress = 0;
+    s->getProcAddress = dummyGetProcAddress;
 
-    if (!XGetWindowAttributes (dpy, s->root, &s->attrib))
+    if (!XGetWindowAttributes (dpy, s->root.id, &s->attrib))
 	return FALSE;
 
     s->workArea.x      = 0;
@@ -1818,7 +1925,7 @@ addScreen (CompDisplay *display,
 	return FALSE;
     }
 
-    bitmap = XCreateBitmapFromData (dpy, s->root, &data, 1, 1);
+    bitmap = XCreateBitmapFromData (dpy, s->root.id, &data, 1, 1);
     if (!bitmap)
     {
 	compLogMessage ("core", CompLogLevelFatal, "Couldn't create bitmap");
@@ -1839,383 +1946,423 @@ addScreen (CompDisplay *display,
     XFreePixmap (dpy, bitmap);
     XFreeColors (dpy, s->colormap, &black.pixel, 1, 0);
 
-    glXGetConfig (dpy, visinfo, GLX_USE_GL, &value);
-    if (!value)
-    {
-	compLogMessage ("core", CompLogLevelFatal,
-			"Root visual is not a GL visual");
-	XFree (visinfo);
-	return FALSE;
-    }
-
-    glXGetConfig (dpy, visinfo, GLX_DOUBLEBUFFER, &value);
-    if (!value)
+    if (s->root.redirectSubwindows)
     {
-	compLogMessage ("core", CompLogLevelFatal,
-			"Root visual is not a double buffered GL visual");
-	XFree (visinfo);
-	return FALSE;
-    }
+	glXGetConfig (dpy, visinfo, GLX_USE_GL, &value);
+	if (!value)
+	{
+	    compLogMessage ("core", CompLogLevelFatal,
+			    "Root visual is not a GL visual");
+	    XFree (visinfo);
+	    return FALSE;
+	}
 
-    s->ctx = glXCreateContext (dpy, visinfo, NULL, !indirectRendering);
-    if (!s->ctx)
-    {
-	compLogMessage ("core", CompLogLevelFatal, "glXCreateContext failed");
-	XFree (visinfo);
+	glXGetConfig (dpy, visinfo, GLX_DOUBLEBUFFER, &value);
+	if (!value)
+	{
+	    compLogMessage ("core", CompLogLevelFatal,
+			    "Root visual is not a double buffered GL visual");
+	    XFree (visinfo);
+	    return FALSE;
+	}
 
-	return FALSE;
-    }
+	s->ctx = glXCreateContext (dpy, visinfo, NULL, !indirectRendering);
+	if (!s->ctx)
+	{
+	    compLogMessage ("core", CompLogLevelFatal,
+			    "glXCreateContext failed");
+	    XFree (visinfo);
 
-    glxExtensions = glXQueryExtensionsString (dpy, screenNum);
-    if (!strstr (glxExtensions, "GLX_EXT_texture_from_pixmap"))
-    {
-	compLogMessage ("core", CompLogLevelFatal,
-			"GLX_EXT_texture_from_pixmap is missing");
-	XFree (visinfo);
+	    return FALSE;
+	}
 
-	return FALSE;
-    }
+	glxExtensions = glXQueryExtensionsString (dpy, screenNum);
+	if (!strstr (glxExtensions, "GLX_EXT_texture_from_pixmap"))
+	{
+	    compLogMessage ("core", CompLogLevelFatal,
+			    "GLX_EXT_texture_from_pixmap is missing");
+	    XFree (visinfo);
 
-    XFree (visinfo);
+	    return FALSE;
+	}
 
-    if (!strstr (glxExtensions, "GLX_SGIX_fbconfig"))
-    {
-	compLogMessage ("core", CompLogLevelFatal,
-			"GLX_SGIX_fbconfig is missing");
-	return FALSE;
-    }
+	XFree (visinfo);
 
-    s->getProcAddress = (GLXGetProcAddressProc)
-	getProcAddress (s, "glXGetProcAddressARB");
-    s->bindTexImage = (GLXBindTexImageProc)
-	getProcAddress (s, "glXBindTexImageEXT");
-    s->releaseTexImage = (GLXReleaseTexImageProc)
-	getProcAddress (s, "glXReleaseTexImageEXT");
-    s->queryDrawable = (GLXQueryDrawableProc)
-	getProcAddress (s, "glXQueryDrawable");
-    s->getFBConfigs = (GLXGetFBConfigsProc)
-	getProcAddress (s, "glXGetFBConfigs");
-    s->getFBConfigAttrib = (GLXGetFBConfigAttribProc)
-	getProcAddress (s, "glXGetFBConfigAttrib");
-    s->createPixmap = (GLXCreatePixmapProc)
-	getProcAddress (s, "glXCreatePixmap");
-
-    if (!s->bindTexImage)
-    {
-	compLogMessage ("core", CompLogLevelFatal,
-			"glXBindTexImageEXT is missing");
-	return FALSE;
-    }
+	if (!strstr (glxExtensions, "GLX_SGIX_fbconfig"))
+	{
+	    compLogMessage ("core", CompLogLevelFatal,
+			    "GLX_SGIX_fbconfig is missing");
+	    return FALSE;
+	}
 
-    if (!s->releaseTexImage)
-    {
-	compLogMessage ("core", CompLogLevelFatal,
-			"glXReleaseTexImageEXT is missing");
-	return FALSE;
-    }
+	s->getProcAddress = (GLXGetProcAddressProc)
+	    getProcAddress (s, "glXGetProcAddressARB");
+	s->bindTexImage = (GLXBindTexImageProc)
+	    getProcAddress (s, "glXBindTexImageEXT");
+	s->releaseTexImage = (GLXReleaseTexImageProc)
+	    getProcAddress (s, "glXReleaseTexImageEXT");
+	s->queryDrawable = (GLXQueryDrawableProc)
+	    getProcAddress (s, "glXQueryDrawable");
+	s->getFBConfigs = (GLXGetFBConfigsProc)
+	    getProcAddress (s, "glXGetFBConfigs");
+	s->getFBConfigAttrib = (GLXGetFBConfigAttribProc)
+	    getProcAddress (s, "glXGetFBConfigAttrib");
+	s->createPixmap = (GLXCreatePixmapProc)
+	    getProcAddress (s, "glXCreatePixmap");
+
+	if (!s->bindTexImage)
+	{
+	    compLogMessage ("core", CompLogLevelFatal,
+			    "glXBindTexImageEXT is missing");
+	    return FALSE;
+	}
 
-    if (!s->queryDrawable     ||
-	!s->getFBConfigs      ||
-	!s->getFBConfigAttrib ||
-	!s->createPixmap)
-    {
-	compLogMessage ("core", CompLogLevelFatal,
-			"fbconfig functions missing");
-	return FALSE;
-    }
+	if (!s->releaseTexImage)
+	{
+	    compLogMessage ("core", CompLogLevelFatal,
+			    "glXReleaseTexImageEXT is missing");
+	    return FALSE;
+	}
 
-    s->copySubBuffer = NULL;
-    if (strstr (glxExtensions, "GLX_MESA_copy_sub_buffer"))
-	s->copySubBuffer = (GLXCopySubBufferProc)
-	    getProcAddress (s, "glXCopySubBufferMESA");
+	if (!s->queryDrawable     ||
+	    !s->getFBConfigs      ||
+	    !s->getFBConfigAttrib ||
+	    !s->createPixmap)
+	{
+	    compLogMessage ("core", CompLogLevelFatal,
+			    "fbconfig functions missing");
+	    return FALSE;
+	}
 
-    s->getVideoSync = NULL;
-    s->waitVideoSync = NULL;
-    if (strstr (glxExtensions, "GLX_SGI_video_sync"))
-    {
-	s->getVideoSync = (GLXGetVideoSyncProc)
-	    getProcAddress (s, "glXGetVideoSyncSGI");
+	s->copySubBuffer = NULL;
+	if (strstr (glxExtensions, "GLX_MESA_copy_sub_buffer"))
+	    s->copySubBuffer = (GLXCopySubBufferProc)
+		getProcAddress (s, "glXCopySubBufferMESA");
 
-	s->waitVideoSync = (GLXWaitVideoSyncProc)
-	    getProcAddress (s, "glXWaitVideoSyncSGI");
-    }
+	s->getVideoSync = NULL;
+	s->waitVideoSync = NULL;
+	if (strstr (glxExtensions, "GLX_SGI_video_sync"))
+	{
+	    s->getVideoSync = (GLXGetVideoSyncProc)
+		getProcAddress (s, "glXGetVideoSyncSGI");
 
-    glXMakeCurrent (dpy, s->output, s->ctx);
-    currentRoot = s->root;
+	    s->waitVideoSync = (GLXWaitVideoSyncProc)
+		getProcAddress (s, "glXWaitVideoSyncSGI");
+	}
 
-    glExtensions = (const char *) glGetString (GL_EXTENSIONS);
-    if (!glExtensions)
-    {
-	compLogMessage ("core", CompLogLevelFatal,
-			"No valid GL extensions string found.");
-	return FALSE;
-    }
+	glXMakeCurrent (dpy, s->output, s->ctx);
+	currentRoot = s->root.id;
 
-    s->textureNonPowerOfTwo = 0;
-    if (strstr (glExtensions, "GL_ARB_texture_non_power_of_two"))
-	s->textureNonPowerOfTwo = 1;
+	glExtensions = (const char *) glGetString (GL_EXTENSIONS);
+	if (!glExtensions)
+	{
+	    compLogMessage ("core", CompLogLevelFatal,
+			    "No valid GL extensions string found.");
+	    return FALSE;
+	}
 
-    glGetIntegerv (GL_MAX_TEXTURE_SIZE, &s->maxTextureSize);
+	s->textureNonPowerOfTwo = 0;
+	if (strstr (glExtensions, "GL_ARB_texture_non_power_of_two"))
+	    s->textureNonPowerOfTwo = 1;
 
-    s->textureRectangle = 0;
-    if (strstr (glExtensions, "GL_NV_texture_rectangle")  ||
-	strstr (glExtensions, "GL_EXT_texture_rectangle") ||
-	strstr (glExtensions, "GL_ARB_texture_rectangle"))
-    {
-	s->textureRectangle = 1;
+	glGetIntegerv (GL_MAX_TEXTURE_SIZE, &s->maxTextureSize);
 
-	if (!s->textureNonPowerOfTwo)
+	s->textureRectangle = 0;
+	if (strstr (glExtensions, "GL_NV_texture_rectangle")  ||
+	    strstr (glExtensions, "GL_EXT_texture_rectangle") ||
+	    strstr (glExtensions, "GL_ARB_texture_rectangle"))
 	{
-	    GLint maxTextureSize;
+	    s->textureRectangle = 1;
 
-	    glGetIntegerv (GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, &maxTextureSize);
-	    if (maxTextureSize > s->maxTextureSize)
-		s->maxTextureSize = maxTextureSize;
-	}
-    }
+	    if (!s->textureNonPowerOfTwo)
+	    {
+		GLint maxTextureSize;
 
-    if (!(s->textureRectangle || s->textureNonPowerOfTwo))
-    {
-	compLogMessage ("core", CompLogLevelFatal,
-			"Support for non power of two textures missing");
-	return FALSE;
-    }
+		glGetIntegerv (GL_MAX_RECTANGLE_TEXTURE_SIZE_NV,
+			       &maxTextureSize);
+		if (maxTextureSize > s->maxTextureSize)
+		    s->maxTextureSize = maxTextureSize;
+	    }
+	}
 
-    s->textureEnvCombine = s->textureEnvCrossbar = 0;
-    if (strstr (glExtensions, "GL_ARB_texture_env_combine"))
-    {
-	s->textureEnvCombine = 1;
+	if (!(s->textureRectangle || s->textureNonPowerOfTwo))
+	{
+	    compLogMessage ("core", CompLogLevelFatal,
+			    "Support for non power of two textures missing");
+	    return FALSE;
+	}
 
-	/* XXX: GL_NV_texture_env_combine4 need special code but it seams to
-	   be working anyway for now... */
-	if (strstr (glExtensions, "GL_ARB_texture_env_crossbar") ||
-	    strstr (glExtensions, "GL_NV_texture_env_combine4"))
-	    s->textureEnvCrossbar = 1;
-    }
+	s->textureEnvCombine = s->textureEnvCrossbar = 0;
+	if (strstr (glExtensions, "GL_ARB_texture_env_combine"))
+	{
+	    s->textureEnvCombine = 1;
 
-    s->textureBorderClamp = 0;
-    if (strstr (glExtensions, "GL_ARB_texture_border_clamp") ||
-	strstr (glExtensions, "GL_SGIS_texture_border_clamp"))
-	s->textureBorderClamp = 1;
+	    /* XXX: GL_NV_texture_env_combine4 need special code but it
+	       seems to be working anyway for now... */
+	    if (strstr (glExtensions, "GL_ARB_texture_env_crossbar") ||
+		strstr (glExtensions, "GL_NV_texture_env_combine4"))
+		s->textureEnvCrossbar = 1;
+	}
 
-    s->maxTextureUnits = 1;
-    if (strstr (glExtensions, "GL_ARB_multitexture"))
-    {
-	s->activeTexture = (GLActiveTextureProc)
-	    getProcAddress (s, "glActiveTexture");
-	s->clientActiveTexture = (GLClientActiveTextureProc)
-	    getProcAddress (s, "glClientActiveTexture");
-	s->multiTexCoord2f = (GLMultiTexCoord2fProc)
-	    getProcAddress (s, "glMultiTexCoord2f");
-
-	if (s->activeTexture && s->clientActiveTexture && s->multiTexCoord2f)
-	    glGetIntegerv (GL_MAX_TEXTURE_UNITS_ARB, &s->maxTextureUnits);
-    }
+	s->textureBorderClamp = 0;
+	if (strstr (glExtensions, "GL_ARB_texture_border_clamp") ||
+	    strstr (glExtensions, "GL_SGIS_texture_border_clamp"))
+	    s->textureBorderClamp = 1;
 
-    s->fragmentProgram = 0;
-    if (strstr (glExtensions, "GL_ARB_fragment_program"))
-    {
-	s->genPrograms = (GLGenProgramsProc)
-	    getProcAddress (s, "glGenProgramsARB");
-	s->deletePrograms = (GLDeleteProgramsProc)
-	    getProcAddress (s, "glDeleteProgramsARB");
-	s->bindProgram = (GLBindProgramProc)
-	    getProcAddress (s, "glBindProgramARB");
-	s->programString = (GLProgramStringProc)
-	    getProcAddress (s, "glProgramStringARB");
-	s->programEnvParameter4f = (GLProgramParameter4fProc)
-	    getProcAddress (s, "glProgramEnvParameter4fARB");
-	s->programLocalParameter4f = (GLProgramParameter4fProc)
-	    getProcAddress (s, "glProgramLocalParameter4fARB");
-	s->getProgramiv = (GLGetProgramivProc)
-	    getProcAddress (s, "glGetProgramivARB");
-
-	if (s->genPrograms	       &&
-	    s->deletePrograms	       &&
-	    s->bindProgram	       &&
-	    s->programString	       &&
-	    s->programEnvParameter4f   &&
-	    s->programLocalParameter4f &&
-	    s->getProgramiv)
-	    s->fragmentProgram = 1;
-    }
+	s->maxTextureUnits = 1;
+	if (strstr (glExtensions, "GL_ARB_multitexture"))
+	{
+	    s->activeTexture = (GLActiveTextureProc)
+		getProcAddress (s, "glActiveTexture");
+	    s->clientActiveTexture = (GLClientActiveTextureProc)
+		getProcAddress (s, "glClientActiveTexture");
+	    s->multiTexCoord2f = (GLMultiTexCoord2fProc)
+		getProcAddress (s, "glMultiTexCoord2f");
+
+	    if (s->activeTexture       &&
+		s->clientActiveTexture &&
+		s->multiTexCoord2f)
+		glGetIntegerv (GL_MAX_TEXTURE_UNITS_ARB, &s->maxTextureUnits);
+	}
 
-    s->fbo = 0;
-    if (strstr (glExtensions, "GL_EXT_framebuffer_object"))
-    {
-	s->genFramebuffers = (GLGenFramebuffersProc)
-	    getProcAddress (s, "glGenFramebuffersEXT");
-	s->deleteFramebuffers = (GLDeleteFramebuffersProc)
-	    getProcAddress (s, "glDeleteFramebuffersEXT");
-	s->bindFramebuffer = (GLBindFramebufferProc)
-	    getProcAddress (s, "glBindFramebufferEXT");
-	s->checkFramebufferStatus = (GLCheckFramebufferStatusProc)
-	    getProcAddress (s, "glCheckFramebufferStatusEXT");
-	s->framebufferTexture2D = (GLFramebufferTexture2DProc)
-	    getProcAddress (s, "glFramebufferTexture2DEXT");
-	s->generateMipmap = (GLGenerateMipmapProc)
-	    getProcAddress (s, "glGenerateMipmapEXT");
-
-	if (s->genFramebuffers	      &&
-	    s->deleteFramebuffers     &&
-	    s->bindFramebuffer	      &&
-	    s->checkFramebufferStatus &&
-	    s->framebufferTexture2D   &&
-	    s->generateMipmap)
-	    s->fbo = 1;
-    }
+	s->fragmentProgram = 0;
+	if (strstr (glExtensions, "GL_ARB_fragment_program"))
+	{
+	    s->genPrograms = (GLGenProgramsProc)
+		getProcAddress (s, "glGenProgramsARB");
+	    s->deletePrograms = (GLDeleteProgramsProc)
+		getProcAddress (s, "glDeleteProgramsARB");
+	    s->bindProgram = (GLBindProgramProc)
+		getProcAddress (s, "glBindProgramARB");
+	    s->programString = (GLProgramStringProc)
+		getProcAddress (s, "glProgramStringARB");
+	    s->programEnvParameter4f = (GLProgramParameter4fProc)
+		getProcAddress (s, "glProgramEnvParameter4fARB");
+	    s->programLocalParameter4f = (GLProgramParameter4fProc)
+		getProcAddress (s, "glProgramLocalParameter4fARB");
+	    s->getProgramiv = (GLGetProgramivProc)
+		getProcAddress (s, "glGetProgramivARB");
+
+	    if (s->genPrograms	           &&
+		s->deletePrograms	   &&
+		s->bindProgram	           &&
+		s->programString	   &&
+		s->programEnvParameter4f   &&
+		s->programLocalParameter4f &&
+		s->getProgramiv)
+		s->fragmentProgram = 1;
+	}
 
-    s->textureCompression = 0;
-    if (strstr (glExtensions, "GL_ARB_texture_compression"))
-	s->textureCompression = 1;
+	s->fbo = 0;
+	if (strstr (glExtensions, "GL_EXT_framebuffer_object"))
+	{
+	    s->genFramebuffers = (GLGenFramebuffersProc)
+		getProcAddress (s, "glGenFramebuffersEXT");
+	    s->deleteFramebuffers = (GLDeleteFramebuffersProc)
+		getProcAddress (s, "glDeleteFramebuffersEXT");
+	    s->bindFramebuffer = (GLBindFramebufferProc)
+		getProcAddress (s, "glBindFramebufferEXT");
+	    s->checkFramebufferStatus = (GLCheckFramebufferStatusProc)
+		getProcAddress (s, "glCheckFramebufferStatusEXT");
+	    s->framebufferTexture2D = (GLFramebufferTexture2DProc)
+		getProcAddress (s, "glFramebufferTexture2DEXT");
+	    s->generateMipmap = (GLGenerateMipmapProc)
+		getProcAddress (s, "glGenerateMipmapEXT");
+
+	    if (s->genFramebuffers	  &&
+		s->deleteFramebuffers     &&
+		s->bindFramebuffer	  &&
+		s->checkFramebufferStatus &&
+		s->framebufferTexture2D   &&
+		s->generateMipmap)
+		s->fbo = 1;
+	}
 
-    fbConfigs = (*s->getFBConfigs) (dpy,
-				    screenNum,
-				    &nElements);
+	s->textureCompression = 0;
+	if (strstr (glExtensions, "GL_ARB_texture_compression"))
+	    s->textureCompression = 1;
 
-    for (i = 0; i <= MAX_DEPTH; i++)
-    {
-	int j, db, stencil, depth, alpha, mipmap, rgba;
+	fbConfigs = (*s->getFBConfigs) (dpy,
+					screenNum,
+					&nElements);
 
-	s->glxPixmapFBConfigs[i].fbConfig       = NULL;
-	s->glxPixmapFBConfigs[i].mipmap         = 0;
-	s->glxPixmapFBConfigs[i].yInverted      = 0;
-	s->glxPixmapFBConfigs[i].textureFormat  = 0;
-	s->glxPixmapFBConfigs[i].textureTargets = 0;
+	for (i = 0; i <= MAX_DEPTH; i++)
+	{
+	    int j, db, stencil, depth, alpha, mipmap, rgba;
 
-	db      = MAXSHORT;
-	stencil = MAXSHORT;
-	depth   = MAXSHORT;
-	mipmap  = 0;
-	rgba    = 0;
+	    s->glxPixmapFBConfigs[i].fbConfig       = NULL;
+	    s->glxPixmapFBConfigs[i].mipmap         = 0;
+	    s->glxPixmapFBConfigs[i].yInverted      = 0;
+	    s->glxPixmapFBConfigs[i].textureFormat  = 0;
+	    s->glxPixmapFBConfigs[i].textureTargets = 0;
 
-	for (j = 0; j < nElements; j++)
-	{
-	    XVisualInfo *vi;
-	    int		visualDepth;
+	    db      = MAXSHORT;
+	    stencil = MAXSHORT;
+	    depth   = MAXSHORT;
+	    mipmap  = 0;
+	    rgba    = 0;
 
-	    vi = glXGetVisualFromFBConfig (dpy, fbConfigs[j]);
-	    if (vi == NULL)
-		continue;
+	    for (j = 0; j < nElements; j++)
+	    {
+		XVisualInfo *vi;
+		int		visualDepth;
 
-	    visualDepth = vi->depth;
+		vi = glXGetVisualFromFBConfig (dpy, fbConfigs[j]);
+		if (vi == NULL)
+		    continue;
 
-	    XFree (vi);
+		visualDepth = vi->depth;
 
-	    if (visualDepth != i)
-		continue;
+		XFree (vi);
 
-	    (*s->getFBConfigAttrib) (dpy,
-				     fbConfigs[j],
-				     GLX_ALPHA_SIZE,
-				     &alpha);
-	    (*s->getFBConfigAttrib) (dpy,
-				     fbConfigs[j],
-				     GLX_BUFFER_SIZE,
-				     &value);
-	    if (value != i && (value - alpha) != i)
-		continue;
+		if (visualDepth != i)
+		    continue;
 
-	    value = 0;
-	    if (i == 32)
-	    {
 		(*s->getFBConfigAttrib) (dpy,
 					 fbConfigs[j],
-					 GLX_BIND_TO_TEXTURE_RGBA_EXT,
+					 GLX_ALPHA_SIZE,
+					 &alpha);
+		(*s->getFBConfigAttrib) (dpy,
+					 fbConfigs[j],
+					 GLX_BUFFER_SIZE,
 					 &value);
+		if (value != i && (value - alpha) != i)
+		    continue;
+
+		value = 0;
+		if (i == 32)
+		{
+		    (*s->getFBConfigAttrib) (dpy,
+					     fbConfigs[j],
+					     GLX_BIND_TO_TEXTURE_RGBA_EXT,
+					     &value);
+
+		    if (value)
+		    {
+			rgba = 1;
+
+			s->glxPixmapFBConfigs[i].textureFormat =
+			    GLX_TEXTURE_FORMAT_RGBA_EXT;
+		    }
+		}
 
-		if (value)
+		if (!value)
 		{
-		    rgba = 1;
+		    if (rgba)
+			continue;
+
+		    (*s->getFBConfigAttrib) (dpy,
+					     fbConfigs[j],
+					     GLX_BIND_TO_TEXTURE_RGB_EXT,
+					     &value);
+		    if (!value)
+			continue;
 
 		    s->glxPixmapFBConfigs[i].textureFormat =
-			GLX_TEXTURE_FORMAT_RGBA_EXT;
+			GLX_TEXTURE_FORMAT_RGB_EXT;
 		}
-	    }
 
-	    if (!value)
-	    {
-		if (rgba)
+		(*s->getFBConfigAttrib) (dpy,
+					 fbConfigs[j],
+					 GLX_DOUBLEBUFFER,
+					 &value);
+		if (value > db)
 		    continue;
 
+		db = value;
+
 		(*s->getFBConfigAttrib) (dpy,
 					 fbConfigs[j],
-					 GLX_BIND_TO_TEXTURE_RGB_EXT,
+					 GLX_STENCIL_SIZE,
 					 &value);
-		if (!value)
+		if (value > stencil)
 		    continue;
 
-		s->glxPixmapFBConfigs[i].textureFormat =
-		    GLX_TEXTURE_FORMAT_RGB_EXT;
-	    }
-
-	    (*s->getFBConfigAttrib) (dpy,
-				     fbConfigs[j],
-				     GLX_DOUBLEBUFFER,
-				     &value);
-	    if (value > db)
-		continue;
+		stencil = value;
 
-	    db = value;
+		(*s->getFBConfigAttrib) (dpy,
+					 fbConfigs[j],
+					 GLX_DEPTH_SIZE,
+					 &value);
+		if (value > depth)
+		    continue;
 
-	    (*s->getFBConfigAttrib) (dpy,
-				     fbConfigs[j],
-				     GLX_STENCIL_SIZE,
-				     &value);
-	    if (value > stencil)
-		continue;
+		depth = value;
 
-	    stencil = value;
+		if (s->fbo)
+		{
+		    (*s->getFBConfigAttrib) (dpy,
+					     fbConfigs[j],
+					     GLX_BIND_TO_MIPMAP_TEXTURE_EXT,
+					     &value);
+		    if (value < mipmap)
+			continue;
+
+		    mipmap = value;
+		}
 
-	    (*s->getFBConfigAttrib) (dpy,
-				     fbConfigs[j],
-				     GLX_DEPTH_SIZE,
-				     &value);
-	    if (value > depth)
-		continue;
+		(*s->getFBConfigAttrib) (dpy,
+					 fbConfigs[j],
+					 GLX_Y_INVERTED_EXT,
+					 &value);
 
-	    depth = value;
+		s->glxPixmapFBConfigs[i].yInverted = value;
 
-	    if (s->fbo)
-	    {
 		(*s->getFBConfigAttrib) (dpy,
 					 fbConfigs[j],
-					 GLX_BIND_TO_MIPMAP_TEXTURE_EXT,
+					 GLX_BIND_TO_TEXTURE_TARGETS_EXT,
 					 &value);
-		if (value < mipmap)
-		    continue;
 
-		mipmap = value;
+		s->glxPixmapFBConfigs[i].textureTargets = value;
+
+		s->glxPixmapFBConfigs[i].fbConfig = fbConfigs[j];
+		s->glxPixmapFBConfigs[i].mipmap   = mipmap;
 	    }
+	}
 
-	    (*s->getFBConfigAttrib) (dpy,
-				     fbConfigs[j],
-				     GLX_Y_INVERTED_EXT,
-				     &value);
+	if (nElements)
+	    XFree (fbConfigs);
 
-	    s->glxPixmapFBConfigs[i].yInverted = value;
+	if (!s->glxPixmapFBConfigs[defaultDepth].fbConfig)
+	{
+	    compLogMessage ("core", CompLogLevelFatal,
+			    "No GLXFBConfig for default depth, "
+			    "this isn't going to work.");
+	    return FALSE;
+	}
 
-	    (*s->getFBConfigAttrib) (dpy,
-				     fbConfigs[j],
-				     GLX_BIND_TO_TEXTURE_TARGETS_EXT,
-				     &value);
+	glClearColor (0.0, 0.0, 0.0, 1.0);
+	glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+	glEnable (GL_CULL_FACE);
+	glDisable (GL_BLEND);
+	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+	glColor4usv (defaultColor);
+	glEnableClientState (GL_VERTEX_ARRAY);
+	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+
+	s->canDoSaturated = s->canDoSlightlySaturated = FALSE;
+	if (s->textureEnvCombine && s->maxTextureUnits >= 2)
+	{
+	    s->canDoSaturated = TRUE;
+	    if (s->textureEnvCrossbar && s->maxTextureUnits >= 4)
+		s->canDoSlightlySaturated = TRUE;
+	}
 
-	    s->glxPixmapFBConfigs[i].textureTargets = value;
+	glLightModelfv (GL_LIGHT_MODEL_AMBIENT, globalAmbient);
 
-	    s->glxPixmapFBConfigs[i].fbConfig = fbConfigs[j];
-	    s->glxPixmapFBConfigs[i].mipmap   = mipmap;
-	}
-    }
+	glEnable (GL_LIGHT0);
+	glLightfv (GL_LIGHT0, GL_AMBIENT, ambientLight);
+	glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuseLight);
+	glLightfv (GL_LIGHT0, GL_POSITION, light0Position);
 
-    if (nElements)
-	XFree (fbConfigs);
+	glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
 
-    if (!s->glxPixmapFBConfigs[defaultDepth].fbConfig)
+	glNormal3f (0.0f, 0.0f, -1.0f);
+    }
+    else
     {
-	compLogMessage ("core", CompLogLevelFatal,
-			"No GLXFBConfig for default depth, "
-			"this isn't going to work.");
-	return FALSE;
+	s->maxTextureSize = SHRT_MAX;
+	s->canDoSaturated = s->canDoSlightlySaturated = FALSE;
     }
 
     initTexture (s, &s->backgroundTexture);
@@ -2223,80 +2370,13 @@ addScreen (CompDisplay *display,
 
     s->defaultIcon = NULL;
 
-    s->desktopWindowCount = 0;
-
-    glClearColor (0.0, 0.0, 0.0, 1.0);
-    glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-    glEnable (GL_CULL_FACE);
-    glDisable (GL_BLEND);
-    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-    glColor4usv (defaultColor);
-    glEnableClientState (GL_VERTEX_ARRAY);
-    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
-
-    s->canDoSaturated = s->canDoSlightlySaturated = FALSE;
-    if (s->textureEnvCombine && s->maxTextureUnits >= 2)
-    {
-	s->canDoSaturated = TRUE;
-	if (s->textureEnvCrossbar && s->maxTextureUnits >= 4)
-	    s->canDoSlightlySaturated = TRUE;
-    }
-
     s->redrawTime = 1000 / defaultRefreshRate;
     s->optimalRedrawTime = s->redrawTime;
 
-    reshape (s, s->attrib.width, s->attrib.height);
-
-    detectRefreshRateOfScreen (s);
-    detectOutputDevices (s);
-    updateOutputDevices (s);
-
-    glLightModelfv (GL_LIGHT_MODEL_AMBIENT, globalAmbient);
-
-    glEnable (GL_LIGHT0);
-    glLightfv (GL_LIGHT0, GL_AMBIENT, ambientLight);
-    glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuseLight);
-    glLightfv (GL_LIGHT0, GL_POSITION, light0Position);
-
-    glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
-
-    glNormal3f (0.0f, 0.0f, -1.0f);
-
-    s->lighting	      = FALSE;
-    s->slowAnimations = FALSE;
-
-    addScreenToDisplay (display, s);
-
-    getDesktopHints (s);
-
-    /* TODO: bailout properly when objectInitPlugins fails */
-    assert (objectInitPlugins (&s->base));
-
-    (*core.objectAdd) (&display->base, &s->base);
-
-    XQueryTree (dpy, s->root,
-		&rootReturn, &parentReturn,
-		&children, &nchildren);
-
-    for (i = 0; i < nchildren; i++)
-	addWindow (s, children[i], i ? children[i - 1] : 0);
-
-    for (w = s->windows; w; w = w->next)
-    {
-	if (w->attrib.map_state == IsViewable)
-	{
-	    w->activeNum = s->activeNum++;
-	    w->damaged   = TRUE;
-	    w->invisible = WINDOW_INVISIBLE (w);
-	}
-    }
-
-    XFree (children);
-
     attrib.override_redirect = 1;
     attrib.event_mask	     = PropertyChangeMask;
 
-    s->grabWindow = XCreateWindow (dpy, s->root, -100, -100, 1, 1, 0,
+    s->grabWindow = XCreateWindow (dpy, s->root.id, -100, -100, 1, 1, 0,
 				   CopyFromParent, InputOnly, CopyFromParent,
 				   CWOverrideRedirect | CWEventMask,
 				   &attrib);
@@ -2306,9 +2386,13 @@ addScreen (CompDisplay *display,
     {
 	long xdndVersion = 3;
 
-	s->screenEdge[i].id = XCreateWindow (dpy, s->root, -100, -100, 1, 1, 0,
-					     CopyFromParent, InputOnly,
-					     CopyFromParent, CWOverrideRedirect,
+	s->screenEdge[i].id = XCreateWindow (dpy,
+					     s->root.id,
+					     -100, -100, 1, 1, 0,
+					     CopyFromParent,
+					     InputOnly,
+					     CopyFromParent,
+					     CWOverrideRedirect,
 					     &attrib);
 
 	XChangeProperty (dpy, s->screenEdge[i].id, display->xdndAwareAtom,
@@ -2325,19 +2409,90 @@ addScreen (CompDisplay *display,
 
     updateScreenEdges (s);
 
-    setDesktopHints (s);
-    setSupportingWmCheck (s);
-    setSupported (s);
+    reshape (s, s->attrib.width, s->attrib.height);
+
+    detectRefreshRateOfScreen (s);
+    detectOutputDevices (s);
+    updateOutputDevices (s);
+
+    s->lighting	      = FALSE;
+    s->slowAnimations = FALSE;
+
+    addScreenToDisplay (display, s);
+
+    getDesktopHints (s);
 
     s->normalCursor = XCreateFontCursor (dpy, XC_left_ptr);
     s->busyCursor   = XCreateFontCursor (dpy, XC_watch);
 
-    XDefineCursor (dpy, s->root, s->normalCursor);
+    if (s->root.substructureRedirect)
+    {
+	setDesktopHints (s);
+	setSupportingWmCheck (s);
+	setSupported (s);
+
+	XDefineCursor (dpy, s->root.id, s->normalCursor);
+    }
+    else
+    {
+	getSupportingWmCheck (&s->root);
+    }
 
     s->filter[NOTHING_TRANS_FILTER] = COMP_TEXTURE_FILTER_FAST;
     s->filter[SCREEN_TRANS_FILTER]  = COMP_TEXTURE_FILTER_GOOD;
     s->filter[WINDOW_TRANS_FILTER]  = COMP_TEXTURE_FILTER_GOOD;
 
+    /* TODO: bailout properly when objectInitPlugins fails */
+    assert (objectInitPlugins (&s->base));
+    (*core.objectAdd) (&display->base, &s->base);
+
+    assert (objectInitPlugins (&s->root.base));
+    (*core.objectAdd) (&s->base, &s->root.base);
+
+    XQueryTree (dpy, s->root.id,
+		&rootReturn, &parentReturn,
+		&children, &nchildren);
+
+    if (windowManagement)
+    {
+	XSelectInput (dpy, s->root.id,
+		      SubstructureRedirectMask |
+		      SubstructureNotifyMask   |
+		      StructureNotifyMask      |
+		      PropertyChangeMask       |
+		      LeaveWindowMask          |
+		      EnterWindowMask          |
+		      KeyPressMask             |
+		      KeyReleaseMask           |
+		      ButtonPressMask          |
+		      ButtonReleaseMask        |
+		      FocusChangeMask          |
+		      ExposureMask);
+    }
+    else
+    {
+	XSelectInput (dpy, s->root.id,
+		      SubstructureNotifyMask |
+		      StructureNotifyMask    |
+		      PropertyChangeMask     |
+		      ExposureMask);
+    }
+
+    for (i = 0; i < nchildren; i++)
+	addWindow (&s->root, children[i], i ? children[i - 1] : 0);
+
+    for (w = s->root.windows; w; w = w->next)
+    {
+	if (w->attrib.map_state == IsViewable)
+	{
+	    w->activeNum = s->activeNum++;
+	    w->damaged   = TRUE;
+	    w->invisible = WINDOW_INVISIBLE (w);
+	}
+    }
+
+    XFree (children);
+
     return TRUE;
 }
 
@@ -2357,14 +2512,14 @@ removeScreen (CompScreen *s)
     else
 	d->screens = NULL;
 
-    while (s->windows)
-	removeWindow (s->windows);
+    while (s->root.windows)
+	removeWindow (s->root.windows);
 
     (*core.objectRemove) (&d->base, &s->base);
 
     objectFiniPlugins (&s->base);
 
-    XUngrabKey (d->display, AnyKey, AnyModifier, s->root);
+    XUngrabKey (d->display, AnyKey, AnyModifier, s->root.id);
 
     for (i = 0; i < SCREEN_EDGE_NUM; i++)
 	XDestroyWindow (d->display, s->screenEdge[i].id);
@@ -2379,13 +2534,14 @@ removeScreen (CompScreen *s)
 	free (s->defaultIcon);
     }
 
-    glXDestroyContext (d->display, s->ctx);
+    if (manualCompositeManagement)
+	glXDestroyContext (d->display, s->ctx);
 
     XFreeCursor (d->display, s->invisibleCursor);
 
 #ifdef USE_COW
-    if (useCow)
-	XCompositeReleaseOverlayWindow (s->display->display, s->root);
+    if (useCow && manualCompositeManagement)
+	XCompositeReleaseOverlayWindow (s->display->display, s->root.id);
 #endif
 
     freeScreen (s);
@@ -2430,7 +2586,7 @@ forEachWindowOnScreen (CompScreen	 *screen,
 {
     CompWindow *w;
 
-    for (w = screen->windows; w; w = w->next)
+    for (w = screen->root.windows; w; w = w->next)
 	(*proc) (w, closure);
 }
 
@@ -2441,6 +2597,9 @@ focusDefaultWindow (CompScreen *s)
     CompWindow  *w;
     CompWindow  *focus = NULL;
 
+    if (!s->root.substructureRedirect)
+	return;
+
     if (!d->opt[COMP_DISPLAY_OPTION_CLICK_TO_FOCUS].value.b)
     {
 	w = findTopLevelWindowAtDisplay (d, d->below);
@@ -2461,11 +2620,11 @@ focusDefaultWindow (CompScreen *s)
 	    /* huh, we didn't find d->below ... perhaps it's out of date;
 	       try grabbing it through the server */
 
-	    status = XQueryPointer (d->display, s->root, &rootReturn,
+	    status = XQueryPointer (d->display, s->root.id, &rootReturn,
 				    &childReturn, &dummyInt, &dummyInt,
 				    &dummyInt, &dummyInt, &dummyUInt);
 
-	    if (status && rootReturn == s->root)
+	    if (status && rootReturn == s->root.id)
 	    {
 		w = findTopLevelWindowAtDisplay (d, childReturn);
 
@@ -2481,7 +2640,7 @@ focusDefaultWindow (CompScreen *s)
 
     if (!focus)
     {
-	for (w = s->reverseWindows; w; w = w->prev)
+	for (w = s->root.reverseWindows; w; w = w->prev)
 	{
 	    if (w->type & CompWindowTypeDockMask)
 		continue;
@@ -2511,7 +2670,7 @@ focusDefaultWindow (CompScreen *s)
     }
     else
     {
-	XSetInputFocus (d->display, s->root, RevertToPointerRoot,
+	XSetInputFocus (d->display, s->root.id, RevertToPointerRoot,
 			CurrentTime);
     }
 }
@@ -2528,17 +2687,17 @@ findWindowAtScreen (CompScreen *s,
     {
 	CompWindow *w;
 
-	for (w = s->windows; w; w = w->next)
+	for (w = &s->root; w; w = walkDepthFirst (w))
 	    if (w->id == id)
 		return (lastFoundWindow = w);
     }
 
-    return 0;
+    return NULL;
 }
 
 CompWindow *
-findTopLevelWindowAtScreen (CompScreen *s,
-			    Window     id)
+findClientWindowAtScreen (CompScreen *s,
+			  Window     id)
 {
     CompWindow *w;
 
@@ -2548,120 +2707,29 @@ findTopLevelWindowAtScreen (CompScreen *s,
 
     if (w->attrib.override_redirect)
     {
-	/* likely a frame window */
-	if (w->attrib.class == InputOnly)
-	{
-	    for (w = s->windows; w; w = w->next)
-		if (w->frame == id)
-		    return w;
-	}
+	if (!w->parent || w->attrib.class != InputOnly)
+	    return NULL;
 
-	return NULL;
+	/* likely a frame window */
+	for (w = w->parent->windows; w; w = w->next)
+	    if (w->frame == id)
+		break;
     }
 
     return w;
 }
 
-void
-insertWindowIntoScreen (CompScreen *s,
-			CompWindow *w,
-			Window	   aboveId)
-{
-    CompWindow *p;
-
-    if (s->windows)
-    {
-	if (!aboveId)
-	{
-	    w->next = s->windows;
-	    w->prev = NULL;
-	    s->windows->prev = w;
-	    s->windows = w;
-	}
-	else
-	{
-	    for (p = s->windows; p; p = p->next)
-	    {
-		if (p->id == aboveId)
-		{
-		    if (p->next)
-		    {
-			w->next = p->next;
-			w->prev = p;
-			p->next->prev = w;
-			p->next = w;
-		    }
-		    else
-		    {
-			p->next = w;
-			w->next = NULL;
-			w->prev = p;
-			s->reverseWindows = w;
-		    }
-		    break;
-		}
-	    }
-
-#ifdef DEBUG
-	    if (!p)
-		abort ();
-#endif
-
-	}
-    }
-    else
-    {
-	s->reverseWindows = s->windows = w;
-	w->prev = w->next = NULL;
-    }
-}
-
-void
-unhookWindowFromScreen (CompScreen *s,
-			CompWindow *w)
+CompWindow *
+findTopLevelWindowAtScreen (CompScreen *s,
+			    Window     id)
 {
-    CompWindow *next, *prev;
-
-    next = w->next;
-    prev = w->prev;
+    CompWindow *w;
 
-    if (next || prev)
-    {
-	if (next)
-	{
-	    if (prev)
-	    {
-		next->prev = prev;
-	    }
-	    else
-	    {
-		s->windows = next;
-		next->prev = NULL;
-	    }
-	}
+    w = findClientWindowAtScreen (s, id);
+    if (w && w->managed)
+	return w;
 
-	if (prev)
-	{
-	    if (next)
-	    {
-		prev->next = next;
-	    }
-	    else
-	    {
-		s->reverseWindows = prev;
-		prev->next = NULL;
-	    }
-	}
-    }
-    else
-    {
-	s->windows = s->reverseWindows = NULL;
-    }
-
-    if (w == lastFoundWindow)
-	lastFoundWindow = NULL;
-    if (w == lastDamagedWindow)
-	lastDamagedWindow = NULL;
+    return NULL;
 }
 
 #define POINTER_GRAB_MASK (ButtonReleaseMask | \
@@ -2679,7 +2747,7 @@ pushScreenGrab (CompScreen *s,
 	status = XGrabPointer (s->display->display, s->grabWindow, TRUE,
 			       POINTER_GRAB_MASK,
 			       GrabModeAsync, GrabModeAsync,
-			       s->root, cursor,
+			       s->root.id, cursor,
 			       CurrentTime);
 
 	if (status == GrabSuccess)
@@ -2831,7 +2899,7 @@ grabUngrabOneKey (CompScreen   *s,
 	XGrabKey (s->display->display,
 		  keycode,
 		  modifiers,
-		  s->root,
+		  s->root.id,
 		  TRUE,
 		  GrabModeAsync,
 		  GrabModeAsync);
@@ -2841,7 +2909,7 @@ grabUngrabOneKey (CompScreen   *s,
 	XUngrabKey (s->display->display,
 		    keycode,
 		    modifiers,
-		    s->root);
+		    s->root.id);
     }
 }
 
@@ -2971,7 +3039,7 @@ updatePassiveKeyGrabs (CompScreen *s)
 {
     int i;
 
-    XUngrabKey (s->display->display, AnyKey, AnyModifier, s->root);
+    XUngrabKey (s->display->display, AnyKey, AnyModifier, s->root.id);
 
     for (i = 0; i < s->nKeyGrab; i++)
     {
@@ -3127,7 +3195,7 @@ computeWorkareaForBox (CompScreen *s,
 
     XUnionRegion (&r, region, region);
 
-    for (w = s->windows; w; w = w->next)
+    for (w = s->root.windows; w; w = w->next)
     {
 	if (!w->mapNum)
 	    continue;
@@ -3241,7 +3309,7 @@ updateWorkareaForScreen (CompScreen *s)
 
 	/* as work area changed, update all maximized windows on this
 	   screen to snap to the new work area */
-	for (w = s->windows; w; w = w->next)
+	for (w = s->root.windows; w; w = w->next)
 	    updateWindowSize (w);
     }
 }
@@ -3308,6 +3376,9 @@ updateClientListForScreen (CompScreen *s)
     Bool   updateClientListStacking = FALSE;
     int	   i, n = 0;
 
+    if (!s->root.substructureRedirect)
+	return;
+
     forEachWindowOnScreen (s, countClientListWindow, (void *) &n);
 
     if (n == 0)
@@ -3319,11 +3390,11 @@ updateClientListForScreen (CompScreen *s)
 	    s->clientList  = NULL;
 	    s->nClientList = 0;
 
-	    XChangeProperty (s->display->display, s->root,
+	    XChangeProperty (s->display->display, s->root.id,
 			     s->display->clientListAtom,
 			     XA_WINDOW, 32, PropModeReplace,
 			     (unsigned char *) &s->grabWindow, 1);
-	    XChangeProperty (s->display->display, s->root,
+	    XChangeProperty (s->display->display, s->root.id,
 			     s->display->clientListStackingAtom,
 			     XA_WINDOW, 32, PropModeReplace,
 			     (unsigned char *) &s->grabWindow, 1);
@@ -3379,13 +3450,13 @@ updateClientListForScreen (CompScreen *s)
     }
 
     if (updateClientList)
-	XChangeProperty (s->display->display, s->root,
+	XChangeProperty (s->display->display, s->root.id,
 			 s->display->clientListAtom,
 			 XA_WINDOW, 32, PropModeReplace,
 			 (unsigned char *) clientList, s->nClientList);
 
     if (updateClientListStacking)
-	XChangeProperty (s->display->display, s->root,
+	XChangeProperty (s->display->display, s->root.id,
 			 s->display->clientListStackingAtom,
 			 XA_WINDOW, 32, PropModeReplace,
 			 (unsigned char *) clientListStacking, s->nClientList);
@@ -3439,7 +3510,8 @@ toolkitAction (CompScreen *s,
     XUngrabPointer (s->display->display, CurrentTime);
     XUngrabKeyboard (s->display->display, CurrentTime);
 
-    XSendEvent (s->display->display, s->root, FALSE, StructureNotifyMask, &ev);
+    XSendEvent (s->display->display, s->root.id, FALSE, StructureNotifyMask,
+		&ev);
 }
 
 void
@@ -3510,7 +3582,7 @@ moveScreenViewport (CompScreen *s,
     tx *= -s->width;
     ty *= -s->height;
 
-    for (w = s->windows; w; w = w->next)
+    for (w = s->root.windows; w; w = w->next)
     {
 	if (windowOnAllViewports (w))
 	    continue;
@@ -3581,7 +3653,7 @@ moveWindowToViewportPosition (CompWindow *w,
     {
 	int m, wx, wy;
 
-	if (!w->managed)
+	if (w->attrib.override_redirect)
 	    return;
 
 	if (w->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
@@ -3698,7 +3770,7 @@ applyStartupProperties (CompScreen *screen,
     {
 	CompWindow *leader;
 
-	leader = findWindowAtScreen (screen, window->clientLeader);
+	leader = findSibling (window, window->clientLeader);
 	if (leader)
 	    startupId = leader->startupId;
 
@@ -3752,7 +3824,7 @@ sendWindowActivationRequest (CompScreen *s,
     xev.xclient.data.l[4] = 0;
 
     XSendEvent (s->display->display,
-		s->root,
+		s->root.id,
 		FALSE,
 		SubstructureRedirectMask | SubstructureNotifyMask,
 		&xev);
@@ -3813,12 +3885,12 @@ disableScreenEdge (CompScreen *s,
 }
 
 Window
-getTopWindow (CompScreen *s)
+getTopWindow (CompWindow *parent)
 {
     CompWindow *w;
 
     /* return first window that has not been destroyed */
-    for (w = s->reverseWindows; w; w = w->prev)
+    for (w = parent->reverseWindows; w; w = w->prev)
     {
 	if (w->id > 1)
 	    return w->id;
@@ -3830,24 +3902,30 @@ getTopWindow (CompScreen *s)
 void
 makeScreenCurrent (CompScreen *s)
 {
-    if (currentRoot != s->root)
+    if (manualCompositeManagement)
     {
-	glXMakeCurrent (s->display->display, s->output, s->ctx);
-	currentRoot = s->root;
-    }
+	if (currentRoot != s->root.id)
+	{
+	    glXMakeCurrent (s->display->display, s->output, s->ctx);
+	    currentRoot = s->root.id;
+	}
 
-    s->pendingCommands = TRUE;
+	s->pendingCommands = TRUE;
+    }
 }
 
 void
 finishScreenDrawing (CompScreen *s)
 {
-    if (s->pendingCommands)
+    if (manualCompositeManagement)
     {
-	makeScreenCurrent (s);
-	glFinish ();
+	if (s->pendingCommands)
+	{
+	    makeScreenCurrent (s);
+	    glFinish ();
 
-	s->pendingCommands = FALSE;
+	    s->pendingCommands = FALSE;
+	}
     }
 }
 
@@ -3894,7 +3972,7 @@ setNumberOfDesktops (CompScreen   *s,
     if (s->currentDesktop >= nDesktop)
 	s->currentDesktop = nDesktop - 1;
 
-    for (w = s->windows; w; w = w->next)
+    for (w = s->root.windows; w; w = w->next)
     {
 	if (w->desktop == 0xffffffff)
 	    continue;
@@ -3915,6 +3993,9 @@ setCurrentDesktop (CompScreen   *s,
     unsigned long data;
     CompWindow    *w;
 
+    if (!s->root.substructureRedirect)
+	return;
+
     if (desktop >= s->nDesktop)
 	return;
 
@@ -3923,7 +4004,7 @@ setCurrentDesktop (CompScreen   *s,
 
     s->currentDesktop = desktop;
 
-    for (w = s->windows; w; w = w->next)
+    for (w = s->root.windows; w; w = w->next)
     {
 	if (w->desktop == 0xffffffff)
 	    continue;
@@ -3936,7 +4017,7 @@ setCurrentDesktop (CompScreen   *s,
 
     data = desktop;
 
-    XChangeProperty (s->display->display, s->root,
+    XChangeProperty (s->display->display, s->root.id,
 		     s->display->currentDesktopAtom,
 		     XA_CARDINAL, 32, PropModeReplace,
 		     (unsigned char *) &data, 1);
@@ -4292,6 +4373,14 @@ setWindowPaintOffset (CompScreen *s,
 		      int        x,
 		      int        y)
 {
-    s->windowOffsetX = x;
-    s->windowOffsetY = y;
+    x = (s->x * s->width) - x;
+    x = MOD (x, s->hsize * s->width);
+    x -= (s->x * s->width);
+
+    y = (s->y * s->height) - y;
+    y = MOD (y, s->vsize * s->height);
+    y -= (s->y * s->height);
+
+    s->root.viewportOffsetX = -x;
+    s->root.viewportOffsetY = -y;
 }
diff --git a/src/window.c b/src/window.c
index 881bbd5..f252a36 100644
--- a/src/window.c
+++ b/src/window.c
@@ -53,18 +53,18 @@ static int
 reallocWindowPrivates (int  size,
 		       void *closure)
 {
-    CompScreen *s = (CompScreen *) closure;
-    CompWindow *w;
+    CompWindow *c, *w = (CompWindow *) closure;
     void       *privates;
 
-    for (w = s->windows; w; w = w->next)
-    {
-	privates = realloc (w->base.privates, size * sizeof (CompPrivate));
-	if (!privates)
-	    return FALSE;
+    privates = realloc (w->base.privates, size * sizeof (CompPrivate));
+    if (!privates)
+	return FALSE;
 
-	w->base.privates = (CompPrivate *) privates;
-    }
+    w->base.privates = (CompPrivate *) privates;
+
+    for (c = w->windows; c; c = c->next)
+	if (!reallocWindowPrivates (size, (void *) c))
+	    return FALSE;
 
     return TRUE;
 }
@@ -77,7 +77,7 @@ allocWindowObjectPrivateIndex (CompObject *parent)
     return allocatePrivateIndex (&screen->windowPrivateLen,
 				 &screen->windowPrivateIndices,
 				 reallocWindowPrivates,
-				 (void *) screen);
+				 (void *) &screen->root);
 }
 
 void
@@ -98,15 +98,16 @@ forEachWindowObject (CompObject	        *parent,
 {
     if (parent->type == COMP_OBJECT_TYPE_SCREEN)
     {
-	CompWindow *w;
-
-	CORE_SCREEN (parent);
+	if (!(*proc) (&GET_CORE_SCREEN (parent)->root.base, closure))
+	    return FALSE;
+    }
+    else if (parent->type == COMP_OBJECT_TYPE_WINDOW)
+    {
+	CompWindow *c;
 
-	for (w = s->windows; w; w = w->next)
-	{
-	    if (!(*proc) (&w->base, closure))
+	for (c = GET_CORE_WINDOW (parent)->windows; c; c = c->next)
+	    if (!(*proc) (&c->base, closure))
 		return FALSE;
-	}
     }
 
     return TRUE;
@@ -130,14 +131,23 @@ findWindowObject (CompObject *parent,
 {
     if (parent->type == COMP_OBJECT_TYPE_SCREEN)
     {
-	CompWindow *w;
-	Window	   id = atoi (name);
+	Window id = atoi (name);
 
 	CORE_SCREEN (parent);
 
-	for (w = s->windows; w; w = w->next)
-	    if (w->id == id)
-		return &w->base;
+	if (s->root.id == id)
+	    return &s->root.base;
+    }
+    else if (parent->type == COMP_OBJECT_TYPE_WINDOW)
+    {
+	CompWindow *c;
+	Window	   id = atoi (name);
+
+	CORE_WINDOW (parent);
+
+	for (c = w->windows; c; c = c->next)
+	    if (c->id == id)
+		return &c->base;
     }
 
     return NULL;
@@ -168,8 +178,7 @@ isAncestorTo (CompWindow *transient,
 	if (transient->transientFor == ancestor->id)
 	    return TRUE;
 
-	transient = findWindowAtScreen (transient->screen,
-					transient->transientFor);
+	transient = findSibling (transient, transient->transientFor);
 	if (transient)
 	    return isAncestorTo (transient, ancestor);
     }
@@ -376,7 +385,7 @@ updateTransientHint (CompWindow *w)
     {
 	CompWindow *ancestor;
 
-	ancestor = findWindowAtScreen (w->screen, transientFor);
+	ancestor = findSibling (w, transientFor);
 	if (!ancestor)
 	    return;
 
@@ -426,7 +435,7 @@ getClientLeaderOfAncestor (CompWindow *w)
 {
     if (w->transientFor)
     {
-	w = findWindowAtScreen (w->screen, w->transientFor);
+	w = findSibling (w, w->transientFor);
 	if (w)
 	{
 	    if (w->clientLeader)
@@ -1153,6 +1162,33 @@ setWindowProp32 (CompDisplay    *display,
 		     (unsigned char *) &value32, 1);
 }
 
+Window
+getFrameWindow (CompWindow *w)
+{
+    Atom	  actual;
+    int		  result, format;
+    unsigned long n, left;
+    unsigned char *data;
+
+    result = XGetWindowProperty (w->screen->display->display, w->id,
+				 w->screen->display->frameWindowAtom,
+				 0L, 1L, False, XA_WINDOW, &actual, &format,
+				 &n, &left, &data);
+
+    if (result == Success && n && data)
+    {
+	Window win;
+
+	memcpy (&win, data, sizeof (Window));
+	XFree ((void *) data);
+
+	if (win)
+	    return win;
+    }
+
+    return None;
+}
+
 static void
 updateFrameWindow (CompWindow *w)
 {
@@ -1181,7 +1217,7 @@ updateFrameWindow (CompWindow *w)
 	    attr.event_mask	   = 0;
 	    attr.override_redirect = TRUE;
 
-	    w->frame = XCreateWindow (d->display, w->screen->root,
+	    w->frame = XCreateWindow (d->display, w->parent->id,
 				      x, y, width, height, 0,
 				      CopyFromParent,
 				      InputOnly,
@@ -1281,14 +1317,17 @@ setWindowFrameExtents (CompWindow	 *w,
 	data[2] = input->top;
 	data[3] = input->bottom;
 
-	updateWindowSize (w);
-	updateFrameWindow (w);
-	recalcWindowActions (w);
-
-	XChangeProperty (w->screen->display->display, w->id,
-			 w->screen->display->frameExtentsAtom,
-			 XA_CARDINAL, 32, PropModeReplace,
-			 (unsigned char *) data, 4);
+	if (w->parent->substructureRedirect)
+	{
+	    updateWindowSize (w);
+	    updateFrameWindow (w);
+	    recalcWindowActions (w);
+
+	    XChangeProperty (w->screen->display->display, w->id,
+			     w->screen->display->frameExtentsAtom,
+			     XA_CARDINAL, 32, PropModeReplace,
+			     (unsigned char *) data, 4);
+	}
     }
 }
 
@@ -1397,7 +1436,7 @@ freeWindow (CompWindow *w)
 
     destroyTexture (w->screen, w->texture);
 
-    if (w->frame)
+    if (w->frame && w->parent->substructureRedirect)
 	XDestroyWindow (w->screen->display->display, w->frame);
 
     if (w->clip)
@@ -1446,9 +1485,6 @@ damageTransformedWindowRect (CompWindow *w,
 {
     REGION reg;
 
-    reg.rects    = &reg.extents;
-    reg.numRects = 1;
-
     reg.extents.x1 = (rect->x1 * xScale) - 1;
     reg.extents.y1 = (rect->y1 * yScale) - 1;
     reg.extents.x2 = (rect->x2 * xScale + 0.5f) + 1;
@@ -1461,10 +1497,17 @@ damageTransformedWindowRect (CompWindow *w,
 
     if (reg.extents.x2 > reg.extents.x1 && reg.extents.y2 > reg.extents.y1)
     {
-	reg.extents.x1 += w->attrib.x + w->attrib.border_width;
-	reg.extents.y1 += w->attrib.y + w->attrib.border_width;
-	reg.extents.x2 += w->attrib.x + w->attrib.border_width;
-	reg.extents.y2 += w->attrib.y + w->attrib.border_width;
+	CompWindow *p = w;
+
+	do {
+	    reg.extents.x1 += p->attrib.x + p->attrib.border_width;
+	    reg.extents.y1 += p->attrib.y + p->attrib.border_width;
+	    reg.extents.x2 += p->attrib.x + p->attrib.border_width;
+	    reg.extents.y2 += p->attrib.y + p->attrib.border_width;
+	} while ((p = p->parent));
+
+	reg.rects    = &reg.extents;
+	reg.numRects = reg.size = 1;
 
 	damageScreenRegion (w->screen, &reg);
     }
@@ -1527,19 +1570,27 @@ addWindowDamageRect (CompWindow *w,
 		     BoxPtr     rect)
 {
     REGION region;
+    Bool   status = TRUE;
 
     if (w->screen->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK)
 	return;
 
     region.extents = *rect;
 
-    if (!(*w->screen->damageWindowRect) (w, FALSE, &region.extents))
+    while (w != &w->screen->root)
     {
+	status &= (*w->screen->damageWindowRect) (w, FALSE, &region.extents);
+
 	region.extents.x1 += w->attrib.x + w->attrib.border_width;
 	region.extents.y1 += w->attrib.y + w->attrib.border_width;
 	region.extents.x2 += w->attrib.x + w->attrib.border_width;
 	region.extents.y2 += w->attrib.y + w->attrib.border_width;
 
+	w = w->parent;
+    }
+
+    if (!status)
+    {
 	region.rects = &region.extents;
 	region.numRects = region.size = 1;
 
@@ -1882,21 +1933,123 @@ setDefaultWindowAttributes (XWindowAttributes *wa)
 }
 
 void
-addWindow (CompScreen *screen,
+initRootWindow (CompScreen *s,
+		CompWindow *root)
+{
+    CompWindow  *w = root;
+    CompPrivate	*privates;
+    CompDisplay *d = s->display;
+    REGION      rect;
+
+    memset (w, 0, sizeof (*w));
+
+    w->id     = XRootWindow (d->display, s->screenNum);
+    w->screen = s;
+
+    w->bindFailed = TRUE;
+    w->alive      = TRUE;
+
+    w->mapNum = s->mapNum++;
+
+    w->paint.opacity    = OPAQUE;
+    w->paint.brightness = BRIGHT;
+    w->paint.saturation = COLOR;
+    w->paint.xScale	= 1.0f;
+    w->paint.yScale	= 1.0f;
+    w->paint.xTranslate	= 0.0f;
+    w->paint.yTranslate	= 0.0f;
+
+    w->lastPaint = w->paint;
+
+    if (s->windowPrivateLen)
+    {
+	privates = malloc (s->windowPrivateLen * sizeof (CompPrivate));
+	assert (privates);
+    }
+    else
+	privates = 0;
+
+    compObjectInit (&w->base, privates, COMP_OBJECT_TYPE_WINDOW);
+
+    w->clip   = XCreateRegion ();
+    w->region = XCreateRegion ();
+
+    assert (w->clip && w->region);
+
+    if (!XGetWindowAttributes (d->display, w->id, &w->attrib))
+	setDefaultWindowAttributes (&w->attrib);
+
+    w->attrib.override_redirect = TRUE;
+
+    w->serverWidth	 = w->attrib.width;
+    w->serverHeight	 = w->attrib.height;
+    w->serverBorderWidth = w->attrib.border_width;
+
+    w->width  = w->attrib.width  + w->attrib.border_width * 2;
+    w->height = w->attrib.height + w->attrib.border_width * 2;
+
+    w->serverX = w->attrib.x;
+    w->serverY = w->attrib.y;
+
+    w->syncWait	       = FALSE;
+    w->syncX	       = w->attrib.x;
+    w->syncY	       = w->attrib.y;
+    w->syncWidth       = w->attrib.width;
+    w->syncHeight      = w->attrib.height;
+    w->syncBorderWidth = w->attrib.border_width;
+
+    w->alpha = (w->attrib.depth == 32);
+    w->type  = CompWindowTypeUnknownMask;
+
+    w->invisible = TRUE;
+
+    rect.rects = &rect.extents;
+    rect.numRects = rect.size = 1;
+
+    rect.extents.x1 = w->attrib.x;
+    rect.extents.y1 = w->attrib.y;
+    rect.extents.x2 = w->attrib.x + w->width;
+    rect.extents.y2 = w->attrib.y + w->height;
+
+    XUnionRegion (&rect, w->region, w->region);
+
+    w->substructureRedirect = windowManagement;
+    w->redirectSubwindows   = manualCompositeManagement;
+}
+
+void
+addWindow (CompWindow *parent,
 	   Window     id,
 	   Window     aboveId)
 {
     CompWindow  *w;
     CompPrivate	*privates;
+    CompScreen  *screen = parent->screen;
     CompDisplay *d = screen->display;
 
     w = (CompWindow *) malloc (sizeof (CompWindow));
     if (!w)
 	return;
 
+    w->parent = parent;
+
+    w->windows        = 0;
+    w->reverseWindows = 0;
+
     w->next = NULL;
     w->prev = NULL;
 
+    w->substructureRedirect = FALSE;
+    w->redirectSubwindows   = FALSE;
+
+    w->supportingWmCheckWindow = None;
+    w->syncStateSupport        = FALSE;
+    w->activeChild             = None;
+    w->previousActiveChild     = None;
+
+    w->viewportOffsetX = 0;
+    w->viewportOffsetY = 0;
+    
     w->mapNum	 = 0;
     w->activeNum = 0;
 
@@ -1935,9 +2088,18 @@ addWindow (CompScreen *screen,
     w->pixmap     = None;
     w->destroyed  = FALSE;
     w->damaged    = FALSE;
-    w->redirected = TRUE;
     w->managed    = FALSE;
-    w->bindFailed = FALSE;
+
+    if (parent->redirectSubwindows)
+    {
+	w->redirected = TRUE;
+	w->bindFailed = FALSE;
+    }
+    else
+    {
+	w->redirected = FALSE;
+	w->bindFailed = TRUE;
+    }
 
     w->destroyRefCnt = 1;
     w->unmapRefCnt   = 1;
@@ -1996,11 +2158,15 @@ addWindow (CompScreen *screen,
     w->syncCounter    = 0;
     w->syncWaitHandle = 0;
 
+    XSyncIntToValue (&w->syncValue, 0);
+
     w->closeRequests	    = 0;
     w->lastCloseRequestTime = 0;
 
     w->overlayWindow = FALSE;
 
+    w->desktopWindowCount = 0;
+
     if (screen->windowPrivateLen)
     {
 	privates = malloc (screen->windowPrivateLen * sizeof (CompPrivate));
@@ -2063,10 +2229,23 @@ addWindow (CompScreen *screen,
 
     w->saveMask = 0;
 
-    XSelectInput (d->display, id,
-		  PropertyChangeMask |
-		  EnterWindowMask    |
-		  FocusChangeMask);
+    if (w->parent->substructureRedirect)
+    {
+	XSelectInput (d->display, id,
+		      PropertyChangeMask |
+		      EnterWindowMask    |
+		      FocusChangeMask);
+    }
+    else if (w->parent->redirectSubwindows)
+    {
+	XSelectInput (d->display, id, PropertyChangeMask);
+
+	if (w->parent->syncStateSupport)
+	{
+	    if (!getWindowProp (d, w->id, d->syncStateAtom, 0))
+		syncWait (w);
+	}
+    }
 
     w->id = id;
 
@@ -2083,10 +2262,10 @@ addWindow (CompScreen *screen,
     w->type      = CompWindowTypeUnknownMask;
     w->lastPong  = d->lastPing;
 
-    if (d->shapeExtension)
+    if (d->shapeExtension && parent->redirectSubwindows)
 	XShapeSelectInput (d->display, id, ShapeNotifyMask);
 
-    insertWindowIntoScreen (screen, w, aboveId);
+    insertWindow (parent, w, aboveId);
 
     EMPTY_REGION (w->region);
 
@@ -2104,8 +2283,9 @@ addWindow (CompScreen *screen,
 
 	XUnionRegion (&rect, w->region, w->region);
 
-	w->damage = XDamageCreate (d->display, id,
-				   XDamageReportRawRectangles);
+	if (parent->redirectSubwindows)
+	    w->damage = XDamageCreate (d->display, id,
+				       XDamageReportRawRectangles);
 
 	/* need to check for DisplayModal state on all windows */
 	w->state = getWindowState (d, w->id);
@@ -2115,7 +2295,6 @@ addWindow (CompScreen *screen,
     else
     {
 	w->damage = None;
-	w->attrib.map_state = IsUnmapped;
     }
 
     w->invisible = TRUE;
@@ -2134,6 +2313,9 @@ addWindow (CompScreen *screen,
 	if (!w->clientLeader)
 	    w->startupId = getStartupId (w);
 
+	if (w->parent && !w->parent->substructureRedirect)
+	    w->frame = getFrameWindow (w);
+
 	recalcWindowType (w);
 
 	getMwmHints (d, w->id, &w->mwmFunc, &w->mwmDecor);
@@ -2168,35 +2350,41 @@ addWindow (CompScreen *screen,
     else
 	w->paint.saturation = getWindowProp32 (d, w->id,
 					       d->winSaturationAtom, COLOR);
-	
+
+    getSupportingWmCheck (w);
+
     if (w->attrib.map_state == IsViewable)
     {
 	w->placed = TRUE;
 
 	if (!w->attrib.override_redirect)
 	{
-	    w->managed = TRUE;
-
-	    if (getWmState (d, w->id) == IconicState)
-	    {
-		if (w->state & CompWindowStateShadedMask)
-		    w->shaded = TRUE;
-		else
-		    w->minimized = TRUE;
-	    }
-	    else
+	    if (w->parent->substructureRedirect)
 	    {
-		if (w->wmType & (CompWindowTypeDockMask |
-				 CompWindowTypeDesktopMask))
+		w->managed = TRUE;
+
+		if (getWmState (d, w->id) == IconicState)
 		{
-		    setDesktopForWindow (w, 0xffffffff);
+		    if (w->state & CompWindowStateShadedMask)
+			w->shaded = TRUE;
+		    else
+			w->minimized = TRUE;
 		}
 		else
 		{
-		    if (w->desktop != 0xffffffff)
-			w->desktop = screen->currentDesktop;
+		    if (w->wmType & (CompWindowTypeDockMask |
+				     CompWindowTypeDesktopMask))
+		    {
+			setDesktopForWindow (w, 0xffffffff);
+		    }
+		    else
+		    {
+			if (w->desktop != 0xffffffff)
+			    w->desktop = screen->currentDesktop;
 
-		    setWindowProp (d, w->id, d->winDesktopAtom, w->desktop);
+			setWindowProp (d, w->id, d->winDesktopAtom,
+				       w->desktop);
+		    }
 		}
 	    }
 	}
@@ -2239,7 +2427,7 @@ addWindow (CompScreen *screen,
     /* TODO: bailout properly when objectInitPlugins fails */
     assert (objectInitPlugins (&w->base));
 
-    (*core.objectAdd) (&screen->base, &w->base);
+    (*core.objectAdd) (&parent->base, &w->base);
 
     recalcWindowActions (w);
     updateIconGeometry (w);
@@ -2254,7 +2442,10 @@ addWindow (CompScreen *screen,
 void
 removeWindow (CompWindow *w)
 {
-    unhookWindowFromScreen (w->screen, w);
+    while (w->windows)
+	removeWindow (w->windows);
+
+    unhookWindow (w->parent, w);
 
     if (!w->destroyed)
     {
@@ -2276,7 +2467,7 @@ removeWindow (CompWindow *w)
 	if (w->damage)
 	    XDamageDestroy (d->display, w->damage);
 
-	if (d->shapeExtension)
+	if (d->shapeExtension && w->parent->redirectSubwindows)
 	    XShapeSelectInput (d->display, w->id, NoEventMask);
 
 	XSelectInput (d->display, w->id, NoEventMask);
@@ -2287,7 +2478,7 @@ removeWindow (CompWindow *w)
     if (w->attrib.map_state == IsViewable && w->damaged)
     {
 	if (w->type == CompWindowTypeDesktopMask)
-	    w->screen->desktopWindowCount--;
+	    w->parent->desktopWindowCount--;
 
 	if (w->destroyed && w->struts)
 	    updateWorkareaForScreen (w->screen);
@@ -2296,7 +2487,7 @@ removeWindow (CompWindow *w)
     if (w->destroyed)
 	updateClientListForScreen (w->screen);
 
-    if (!w->redirected)
+    if (w->parent->redirectSubwindows && !w->redirected)
     {
 	w->screen->overlayWindowCount--;
 
@@ -2304,7 +2495,7 @@ removeWindow (CompWindow *w)
 	    showOutputWindow (w->screen);
     }
 
-    (*core.objectRemove) (&w->screen->base, &w->base);
+    (*core.objectRemove) (&w->parent->base, &w->base);
 
     objectFiniPlugins (&w->base);
 
@@ -2384,9 +2575,17 @@ sendConfigureNotify (CompWindow *w)
 void
 mapWindow (CompWindow *w)
 {
+    CompWindow *c;
+
     if (w->attrib.map_state == IsViewable)
 	return;
 
+    if (w->parent->attrib.map_state != IsViewable)
+    {
+	w->attrib.map_state = IsUnviewable;
+	return;
+    }
+
     if (w->pendingMaps > 0)
 	w->pendingMaps--;
 
@@ -2402,7 +2601,7 @@ mapWindow (CompWindow *w)
 
     w->attrib.map_state = IsViewable;
 
-    if (!w->attrib.override_redirect)
+    if (w->managed)
 	setWmState (w->screen->display, NormalState, w->id);
 
     w->invisible  = TRUE;
@@ -2415,21 +2614,28 @@ mapWindow (CompWindow *w)
     updateWindowRegion (w);
     updateWindowSize (w);
 
-    if (w->frame)
+    if (w->frame && w->parent->substructureRedirect)
 	XMapWindow (w->screen->display->display, w->frame);
 
     updateClientListForScreen (w->screen);
 
     if (w->type & CompWindowTypeDesktopMask)
-	w->screen->desktopWindowCount++;
+	w->parent->desktopWindowCount++;
 
-    if (w->protocols & CompWindowProtocolSyncRequestMask)
+    if (w->parent->substructureRedirect)
     {
-	sendSyncRequest (w);
-	sendConfigureNotify (w);
+	if (w->protocols & CompWindowProtocolSyncRequestMask)
+	{
+	    sendSyncRequest (w);
+	    sendConfigureNotify (w);
+	}
+	else
+	{
+	    leaveSyncWaitState (w);
+	}
     }
 
-    if (!w->attrib.override_redirect)
+    if (w->managed)
     {
 	/* been shaded */
 	if (!w->height)
@@ -2438,35 +2644,31 @@ mapWindow (CompWindow *w)
 			  w->attrib.width, ++w->attrib.height - 1,
 			  w->attrib.border_width);
     }
+
+    for (c = w->windows; c; c = c->next)
+	if (c->attrib.map_state == IsUnviewable)
+	    mapWindow (c);
 }
 
-void
-unmapWindow (CompWindow *w)
+static void
+withdrawWindowToState (CompWindow *w,
+		       int        state)
 {
-    if (w->mapNum)
-    {
-	if (w->frame && !w->shaded)
-	    XUnmapWindow (w->screen->display->display, w->frame);
-
-	w->mapNum = 0;
-    }
-
-    w->unmapRefCnt--;
-    if (w->unmapRefCnt > 0)
-	return;
+    CompWindow *c;
 
     if (w->struts)
 	updateWorkareaForScreen (w->screen);
 
-    if (w->attrib.map_state != IsViewable)
+    if (w->attrib.map_state == state)
 	return;
 
     if (w->type == CompWindowTypeDesktopMask)
-	w->screen->desktopWindowCount--;
+	w->parent->desktopWindowCount--;
 
-    addWindowDamage (w);
+    if (w->attrib.map_state == IsViewable)
+	addWindowDamage (w);
 
-    w->attrib.map_state = IsUnmapped;
+    w->attrib.map_state = state;
 
     w->invisible = TRUE;
 
@@ -2482,6 +2684,31 @@ unmapWindow (CompWindow *w)
 
     if (!w->redirected)
 	redirectWindow (w);
+
+    for (c = w->windows; c; c = c->next)
+	if (c->attrib.map_state == IsViewable)
+	    withdrawWindowToState (c, IsUnviewable);
+}
+
+void
+unmapWindow (CompWindow *w)
+{
+    if (w->mapNum)
+    {
+	if (w->frame && w->parent->substructureRedirect && !w->shaded)
+	    XUnmapWindow (w->screen->display->display, w->frame);
+
+	if (w->parent->substructureRedirect)
+	    enterSyncWaitState (w);
+
+	w->mapNum = 0;
+    }
+
+    w->unmapRefCnt--;
+    if (w->unmapRefCnt > 0)
+	return;
+
+    withdrawWindowToState (w, IsUnmapped);
 }
 
 static int
@@ -2496,8 +2723,8 @@ restackWindow (CompWindow *w,
     else if (aboveId == None && !w->next)
 	return 0;
 
-    unhookWindowFromScreen (w->screen, w);
-    insertWindowIntoScreen (w->screen, w, aboveId);
+    unhookWindow (w->parent, w);
+    insertWindow (w->parent, w, aboveId);
 
     updateClientListForScreen (w->screen);
 
@@ -2575,7 +2802,8 @@ resizeWindow (CompWindow *w,
 
 	w->invisible = WINDOW_INVISIBLE (w);
 
-	updateFrameWindow (w);
+	if (w->parent && w->parent->substructureRedirect)
+	    updateFrameWindow (w);
     }
     else if (w->attrib.x != x || w->attrib.y != y)
     {
@@ -2586,7 +2814,7 @@ resizeWindow (CompWindow *w,
 
 	moveWindow (w, dx, dy, TRUE, TRUE);
 
-	if (w->frame)
+	if (w->frame && w->parent->substructureRedirect)
 	    XMoveWindow (w->screen->display->display, w->frame,
 			 w->attrib.x - w->input.left,
 			 w->attrib.y - w->input.top);
@@ -2614,6 +2842,9 @@ initializeSyncCounter (CompWindow *w)
     unsigned long	 n, left;
     unsigned char	 *data;
 
+    if (!w->parent->substructureRedirect)
+	return FALSE;
+
     if (w->syncCounter)
 	return w->syncAlarm != None;
 
@@ -2633,7 +2864,6 @@ initializeSyncCounter (CompWindow *w)
 
 	XFree (data);
 
-	XSyncIntsToValue (&w->syncValue, (unsigned int) rand (), 0);
 	XSyncSetCounter (w->screen->display->display,
 			 w->syncCounter,
 			 w->syncValue);
@@ -2689,6 +2919,20 @@ syncWaitTimeout (void *closure)
 }
 
 void
+syncWait (CompWindow *w)
+{
+    w->syncWait	       = TRUE;
+    w->syncX	       = w->serverX;
+    w->syncY	       = w->serverY;
+    w->syncWidth       = w->serverWidth;
+    w->syncHeight      = w->serverHeight;
+    w->syncBorderWidth = w->serverBorderWidth;
+
+    if (!w->syncWaitHandle)
+	w->syncWaitHandle = compAddTimeout (1000, 1200, syncWaitTimeout, w);
+}
+
+void
 sendSyncRequest (CompWindow *w)
 {
     XClientMessageEvent xev;
@@ -2697,7 +2941,10 @@ sendSyncRequest (CompWindow *w)
 	return;
 
     if (!initializeSyncCounter (w))
+    {
+	leaveSyncWaitState (w);
 	return;
+    }
 
     xev.type	     = ClientMessage;
     xev.window	     = w->id;
@@ -2711,23 +2958,26 @@ sendSyncRequest (CompWindow *w)
 
     syncValueIncrement (&w->syncValue);
 
-    XSendEvent (w->screen->display->display, w->id, FALSE, 0, (XEvent *) &xev);
+    enterSyncWaitState (w);
 
-    w->syncWait	       = TRUE;
-    w->syncX	       = w->serverX;
-    w->syncY	       = w->serverY;
-    w->syncWidth       = w->serverWidth;
-    w->syncHeight      = w->serverHeight;
-    w->syncBorderWidth = w->serverBorderWidth;
+    XSendEvent (w->screen->display->display, w->id, FALSE, 0, (XEvent *) &xev);
 
-    if (!w->syncWaitHandle)
-	w->syncWaitHandle = compAddTimeout (1000, 1200, syncWaitTimeout, w);
+    syncWait (w);
 }
 
 void
 configureWindow (CompWindow	 *w,
 		 XConfigureEvent *ce)
 {
+    if (!w->managed)
+    {
+	w->serverX	     = ce->x;
+	w->serverY	     = ce->y;
+	w->serverWidth       = ce->width;
+	w->serverHeight      = ce->height;
+	w->serverBorderWidth = ce->border_width;
+    }
+
     if (w->syncWait)
     {
 	w->syncX	   = ce->x;
@@ -2738,15 +2988,6 @@ configureWindow (CompWindow	 *w,
     }
     else
     {
-	if (ce->override_redirect)
-	{
-	    w->serverX		 = ce->x;
-	    w->serverY		 = ce->y;
-	    w->serverWidth       = ce->width;
-	    w->serverHeight      = ce->height;
-	    w->serverBorderWidth = ce->border_width;
-	}
-
 	resizeWindow (w, ce->x, ce->y, ce->width, ce->height,
 		      ce->border_width);
     }
@@ -2755,6 +2996,9 @@ configureWindow (CompWindow	 *w,
 
     if (restackWindow (w, ce->above))
 	addWindowDamage (w);
+
+    if (!w->parent)
+	configureScreen (w->screen, ce);
 }
 
 void
@@ -2764,7 +3008,7 @@ circulateWindow (CompWindow	 *w,
     Window newAboveId;
 
     if (ce->place == PlaceOnTop)
-	newAboveId = getTopWindow (w->screen);
+	newAboveId = getTopWindow (w->parent);
     else
 	newAboveId = 0;
 
@@ -2800,29 +3044,12 @@ moveWindow (CompWindow *w,
     }
 }
 
-void
-syncWindowPosition (CompWindow *w)
-{
-    w->serverX = w->attrib.x;
-    w->serverY = w->attrib.y;
-
-    XMoveWindow (w->screen->display->display, w->id, w->attrib.x, w->attrib.y);
-
-    if (w->frame)
-	XMoveWindow (w->screen->display->display, w->frame,
-		     w->serverX - w->input.left,
-		     w->serverY - w->input.top);
-}
-
 Bool
 focusWindow (CompWindow *w)
 {
     if (w->attrib.override_redirect)
 	return FALSE;
 
-    if (!w->managed)
-	return FALSE;
-
     if (!onCurrentDesktop (w))
 	return FALSE;
 
@@ -2902,7 +3129,8 @@ isGroupTransient (CompWindow *w,
     if (!clientLeader)
 	return FALSE;
 
-    if (w->transientFor == None || w->transientFor == w->screen->root)
+    if (w->transientFor == None ||
+	(w->parent && w->transientFor == w->parent->id))
     {
 	if (w->type & (CompWindowTypeDialogMask |
 		       CompWindowTypeModalDialogMask))
@@ -2922,7 +3150,7 @@ getModalTransient (CompWindow *window)
 
     modalTransient = window;
 
-    for (w = window->screen->reverseWindows; w; w = w->prev)
+    for (w = window->parent->reverseWindows; w; w = w->prev)
     {
 	if (w == modalTransient || w->mapNum == 0)
 	    continue;
@@ -2932,7 +3160,7 @@ getModalTransient (CompWindow *window)
 	    if (w->state & CompWindowStateModalMask)
 	    {
 		modalTransient = w;
-		w = window->screen->reverseWindows;
+		w = window->parent->reverseWindows;
 	    }
 	}
     }
@@ -2944,7 +3172,7 @@ getModalTransient (CompWindow *window)
 	if (window->state & CompWindowStateModalMask)
 	    return NULL;
 
-	for (w = window->screen->reverseWindows; w; w = w->prev)
+	for (w = window->parent->reverseWindows; w; w = w->prev)
 	{
 	    if (w == modalTransient || w->mapNum == 0)
 		continue;
@@ -2980,14 +3208,18 @@ moveInputFocusToWindow (CompWindow *w)
     CompDisplay *d = s->display;
     CompWindow  *modalTransient;
 
+    if (!w->managed)
+	return;
+
     modalTransient = getModalTransient (w);
     if (modalTransient)
 	w = modalTransient;
 
     if (w->state & CompWindowStateHiddenMask)
     {
-	XSetInputFocus (d->display, w->frame, RevertToPointerRoot, CurrentTime);
-	XChangeProperty (d->display, s->root, d->winActiveAtom,
+	XSetInputFocus (d->display, w->frame, RevertToPointerRoot,
+			CurrentTime);
+	XChangeProperty (d->display, w->parent->id, d->winActiveAtom,
 			 XA_WINDOW, 32, PropModeReplace,
 			 (unsigned char *) &w->id, 1);
     }
@@ -3027,7 +3259,9 @@ moveInputFocusToWindow (CompWindow *w)
 	    CompWindow *ancestor;
 
 	    /* move input to closest ancestor */
-	    for (ancestor = s->windows; ancestor; ancestor = ancestor->next)
+	    for (ancestor = w->parent->windows;
+		 ancestor;
+		 ancestor = ancestor->next)
 	    {
 		if (isAncestorTo (w, ancestor))
 		{
@@ -3111,7 +3345,7 @@ findSiblingBelow (CompWindow *w,
     if (w->transientFor || isGroupTransient (w, clientLeader))
 	clientLeader = None;
 
-    for (below = w->screen->reverseWindows; below; below = below->prev)
+    for (below = w->parent->reverseWindows; below; below = below->prev)
     {
 	if (below == w || avoidStackingRelativeTo (below))
 	    continue;
@@ -3157,7 +3391,7 @@ findSiblingBelow (CompWindow *w,
 static CompWindow *
 findLowestSiblingBelow (CompWindow *w)
 {
-    CompWindow   *below, *lowest = w->screen->reverseWindows;
+    CompWindow   *below, *lowest = w->parent->reverseWindows;
     Window	 clientLeader = w->clientLeader;
     unsigned int type = w->type;
 
@@ -3169,7 +3403,7 @@ findLowestSiblingBelow (CompWindow *w)
     if (w->transientFor || isGroupTransient (w, clientLeader))
 	clientLeader = None;
 
-    for (below = w->screen->reverseWindows; below; below = below->prev)
+    for (below = w->parent->reverseWindows; below; below = below->prev)
     {
 	if (below == w || avoidStackingRelativeTo (below))
 	    continue;
@@ -3351,6 +3585,55 @@ reconfigureXWindow (CompWindow	   *w,
 		    unsigned int   valueMask,
 		    XWindowChanges *xwc)
 {
+    if (!w->parent->substructureRedirect)
+    {
+	XEvent xev;
+        int    mask = 0;
+
+	valueMask |=
+	    adjustConfigureRequestForGravity (w,
+					      xwc, valueMask,
+					      w->sizeHints.win_gravity,
+					      -1);
+
+	xev.xclient.type    = ClientMessage;
+	xev.xclient.display = w->screen->display->display;
+	xev.xclient.format  = 32;
+
+	xev.xclient.message_type = w->screen->display->moveResizeWindowAtom;
+	xev.xclient.window	 = w->id;
+
+	xev.xclient.data.l[0] = (ClientTypePager << 12);
+
+	if (valueMask & CWX)
+	    xev.xclient.data.l[0] |= (1 << 8);
+
+	if (valueMask & CWY)
+	    xev.xclient.data.l[0] |= (1 << 9);
+
+	if (valueMask & CWWidth)
+	    xev.xclient.data.l[0] |= (1 << 9);
+
+	if (valueMask & CWHeight)
+	    xev.xclient.data.l[0] |= (1 << 9);
+
+	xev.xclient.data.l[1] = xwc->x;
+	xev.xclient.data.l[2] = xwc->y;
+	xev.xclient.data.l[3] = xwc->width;
+	xev.xclient.data.l[4] = xwc->height;
+
+        if (w->parent == &w->screen->root)
+            mask = SubstructureRedirectMask | SubstructureNotifyMask;
+
+	XSendEvent (w->screen->display->display,
+		    w->parent->id,
+		    FALSE,
+		    mask,
+		    &xev);
+
+	return;
+    }
+	
     if (valueMask & CWX)
 	w->serverX = xwc->x;
 
@@ -3368,9 +3651,31 @@ reconfigureXWindow (CompWindow	   *w,
 
     XConfigureWindow (w->screen->display->display, w->id, valueMask, xwc);
 
-    if (w->frame && (valueMask & (CWSibling | CWStackMode)))
+    if (w->frame && (valueMask & (CWSibling | CWStackMode | CWX | CWY)))
+    {
+	XWindowChanges wc = *xwc;
+
+	wc.x -= w->input.left;
+	wc.y -= w->input.top;
+	    
 	XConfigureWindow (w->screen->display->display, w->frame,
-			  valueMask & (CWSibling | CWStackMode), xwc);
+			  valueMask & (CWSibling | CWStackMode | CWX | CWY),
+			  &wc);
+
+    }
+}
+
+void
+syncWindowPosition (CompWindow *w)
+{
+    XWindowChanges xwc;
+
+    xwc.x      = w->attrib.x;
+    xwc.y      = w->attrib.y;
+    xwc.width  = w->serverWidth;
+    xwc.height = w->serverHeight;
+
+    reconfigureXWindow (w, CWX | CWY, &xwc);
 }
 
 static Bool
@@ -3384,7 +3689,7 @@ stackTransients (CompWindow	*w,
     if (w->transientFor || isGroupTransient (w, clientLeader))
 	clientLeader = None;
 
-    for (t = w->screen->reverseWindows; t; t = t->prev)
+    for (t = w->parent->reverseWindows; t; t = t->prev)
     {
 	if (t == w || t == avoid)
 	    continue;
@@ -3417,7 +3722,7 @@ stackAncestors (CompWindow     *w,
     {
 	CompWindow *ancestor;
 
-	ancestor = findWindowAtScreen (w->screen, w->transientFor);
+	ancestor = findSibling (w, w->transientFor);
 	if (ancestor)
 	{
 	    if (!stackTransients (ancestor, w, xwc))
@@ -3442,7 +3747,7 @@ stackAncestors (CompWindow     *w,
     {
 	CompWindow *a;
 
-	for (a = w->screen->reverseWindows; a; a = a->prev)
+	for (a = w->parent->reverseWindows; a; a = a->prev)
 	{
 	    if (a->clientLeader == w->clientLeader &&
 		a->transientFor == None		   &&
@@ -3709,7 +4014,8 @@ unsigned int
 adjustConfigureRequestForGravity (CompWindow     *w,
 				  XWindowChanges *xwc,
 				  unsigned int   xwcm,
-				  int            gravity)
+				  int            gravity,
+				  int		 direction)
 {
     int          newX, newY;
     unsigned int mask = 0;
@@ -3724,23 +4030,23 @@ adjustConfigureRequestForGravity (CompWindow     *w,
 	case WestGravity:
 	case SouthWestGravity:
 	    if (xwcm & CWX)
-		newX += w->input.left;
+		newX += w->input.left * direction;
 	    break;
 
 	case NorthGravity:
 	case CenterGravity:
 	case SouthGravity:
 	    if (!(xwcm & CWX))
-		newX += (w->serverWidth - xwc->width) / 2;
+		newX += ((w->serverWidth - xwc->width) / 2) * direction;
 	    break;
 
 	case NorthEastGravity:
 	case EastGravity:
 	case SouthEastGravity:
 	    if (xwcm & CWX)
-		newX -= w->input.right;
+		newX -= w->input.right * direction;
 	    else
-		newX += w->serverWidth - xwc->width;
+		newX += (w->serverWidth - xwc->width) * direction;
 	    break;
 
 	case StaticGravity:
@@ -3756,23 +4062,23 @@ adjustConfigureRequestForGravity (CompWindow     *w,
 	case NorthGravity:
 	case NorthEastGravity:
 	    if (xwcm & CWY)
-		newY += w->input.top;
+		newY += w->input.top * direction;
 	    break;
 
 	case WestGravity:
 	case CenterGravity:
 	case EastGravity:
 	    if (!(xwcm & CWY))
-		newY += (w->serverHeight - xwc->height) / 2;
+		newY += ((w->serverHeight - xwc->height) / 2) * direction;
 	    break;
 
 	case SouthWestGravity:
 	case SouthGravity:
 	case SouthEastGravity:
 	    if (xwcm & CWY)
-		newY -= w->input.bottom;
+		newY -= w->input.bottom * direction;
 	    else
-		newY += w->serverHeight - xwc->height;
+		newY += (w->serverHeight - xwc->height) * direction;
 	    break;
 
 	case StaticGravity:
@@ -3838,7 +4144,7 @@ moveResizeWindow (CompWindow     *w,
 	}
     }
 
-    xwcm |= adjustConfigureRequestForGravity (w, xwc, xwcm, gravity);
+    xwcm |= adjustConfigureRequestForGravity (w, xwc, xwcm, gravity, 1);
 
     if (!(w->type & (CompWindowTypeDockMask       |
 		     CompWindowTypeFullscreenMask |
@@ -3864,7 +4170,7 @@ moveResizeWindow (CompWindow     *w,
 	{
 	    int min, max;
 
-	    min = w->screen->workArea.x + w->input.left;
+	    min = w->screen->workArea.x - w->serverWidth;
 	    max = w->screen->workArea.x + w->screen->workArea.width;
 
 	    min -= w->screen->x * w->screen->width;
@@ -3975,7 +4281,7 @@ addWindowStackChanges (CompWindow     *w,
 	    if (!sibling)
 	    {
 		XLowerWindow (w->screen->display->display, w->id);
-		if (w->frame)
+		if (w->frame && w->parent->substructureRedirect)
 		    XLowerWindow (w->screen->display->display, w->frame);
 	    }
 	    else if (sibling->id != w->prev->id)
@@ -4008,7 +4314,7 @@ addWindowStackChanges (CompWindow     *w,
 	{
 	    CompWindow *dw;
 
-	    for (dw = w->screen->reverseWindows; dw; dw = dw->prev)
+	    for (dw = w->parent->reverseWindows; dw; dw = dw->prev)
 		if (dw == sibling)
 		    break;
 
@@ -4073,7 +4379,7 @@ findValidStackSiblingBelow (CompWindow *w,
     lowest = last = findLowestSiblingBelow (w);
 
     /* walk from bottom up */
-    for (p = w->screen->windows; p; p = p->next)
+    for (p = w->parent->windows; p; p = p->next)
     {
 	/* stop walking when we reach the sibling we should try to stack
 	   below */
@@ -4122,7 +4428,7 @@ updateWindowAttributes (CompWindow             *w,
     XWindowChanges xwc;
     int		   mask = 0;
 
-    if (w->attrib.override_redirect || !w->managed)
+    if (!w->managed)
 	return;
 
     if (w->state & CompWindowStateShadedMask)
@@ -4200,7 +4506,7 @@ ensureWindowVisibility (CompWindow *w)
     int dx = 0;
     int dy = 0;
 
-    if (w->struts || w->attrib.override_redirect)
+    if (w->struts || !w->managed)
 	return;
 
     if (w->type & (CompWindowTypeDockMask	|
@@ -4259,6 +4565,34 @@ revealAncestors (CompWindow *w,
 void
 activateWindow (CompWindow *w)
 {
+    if (!w->parent->substructureRedirect)
+    {
+	XEvent xev;
+	int    mask = 0;
+
+	xev.xclient.type    = ClientMessage;
+	xev.xclient.display = w->screen->display->display;
+	xev.xclient.format  = 32;
+
+	xev.xclient.message_type = w->screen->display->winActiveAtom;
+	xev.xclient.window	 = w->id;
+
+	xev.xclient.data.l[0] = 2; /* pretend to be a pager */
+	xev.xclient.data.l[1] = 0;
+	xev.xclient.data.l[2] = 0;
+	xev.xclient.data.l[3] = 0;
+	xev.xclient.data.l[4] = 0;
+
+	if (w->parent == &w->screen->root)
+	    mask = SubstructureRedirectMask | SubstructureNotifyMask;
+
+	XSendEvent (w->screen->display->display, w->parent->id, FALSE,
+		    mask,
+		    &xev);
+
+	return;
+    }
+
     setCurrentDesktop (w->screen, w->desktop);
 
     forEachWindowOnScreen (w->screen, revealAncestors, (void *) w);
@@ -4511,7 +4845,8 @@ hideWindow (CompWindow *w)
 
 	w->shaded = FALSE;
 
-	if ((w->state & CompWindowStateShadedMask) && w->frame)
+	if ((w->state & CompWindowStateShadedMask) &&
+	    w->frame && w->parent->substructureRedirect)
 	    XUnmapWindow (w->screen->display->display, w->frame);
     }
 
@@ -4551,7 +4886,7 @@ showWindow (CompWindow *w)
     {
 	w->shaded = TRUE;
 
-	if (w->frame)
+	if (w->frame && w->parent->substructureRedirect)
 	    XMapWindow (w->screen->display->display, w->frame);
 
 	if (w->height)
@@ -4633,7 +4968,7 @@ void
 maximizeWindow (CompWindow *w,
 		int	   state)
 {
-    if (w->attrib.override_redirect)
+    if (!w->managed)
 	return;
 
     state = constrainWindowState (state, w->actions);
@@ -4770,7 +5105,7 @@ isWindowFocusAllowed (CompWindow   *w,
     {
 	CompWindow *parent;
 
-	parent = findWindowAtScreen (w->screen, w->transientFor);
+	parent = findSibling (w, w->transientFor);
 	if (parent)
 	    gotTimestamp = getUsageTimestampForWindow (parent, &wUserTime);
     }
@@ -4880,7 +5215,7 @@ unredirectWindow (CompWindow *w)
 void
 redirectWindow (CompWindow *w)
 {
-    if (w->redirected)
+    if (!w->parent || !w->parent->redirectSubwindows || w->redirected)
 	return;
 
     XCompositeRedirectWindow (w->screen->display->display, w->id,
@@ -5199,3 +5534,151 @@ getWindowMovementForOffset (CompWindow *w,
     }
 
 }
+
+void
+enterSyncWaitState (CompWindow *w)
+{
+    XDeleteProperty (w->screen->display->display,
+		     w->id,
+		     w->screen->display->syncStateAtom);
+}
+
+void
+leaveSyncWaitState (CompWindow *w)
+{
+    unsigned long data = XSyncValueLow32 (w->syncValue);
+
+    XChangeProperty (w->screen->display->display,
+		     w->id,
+		     w->screen->display->syncStateAtom,
+		     XA_CARDINAL,
+		     32,
+		     PropModeReplace,
+		     (unsigned char *) &data, 1);
+}
+
+void
+insertWindow (CompWindow *parent,
+	      CompWindow *w,
+	      Window	 aboveId)
+{
+    CompWindow *p;
+
+    if (parent->windows)
+    {
+	if (!aboveId)
+	{
+	    w->next = parent->windows;
+	    w->prev = NULL;
+	    parent->windows->prev = w;
+	    parent->windows = w;
+	}
+	else
+	{
+	    for (p = parent->windows; p; p = p->next)
+	    {
+		if (p->id == aboveId)
+		{
+		    if (p->next)
+		    {
+			w->next = p->next;
+			w->prev = p;
+			p->next->prev = w;
+			p->next = w;
+		    }
+		    else
+		    {
+			p->next = w;
+			w->next = NULL;
+			w->prev = p;
+			parent->reverseWindows = w;
+		    }
+		    break;
+		}
+	    }
+
+#ifdef DEBUG
+	    if (!p)
+		abort ();
+#endif
+
+	}
+    }
+    else
+    {
+	parent->reverseWindows = parent->windows = w;
+	w->prev = w->next = NULL;
+    }
+}
+
+void
+unhookWindow (CompWindow *parent,
+	      CompWindow *w)
+{
+    CompWindow *next, *prev;
+
+    next = w->next;
+    prev = w->prev;
+
+    if (next || prev)
+    {
+	if (next)
+	{
+	    if (prev)
+	    {
+		next->prev = prev;
+	    }
+	    else
+	    {
+		parent->windows = next;
+		next->prev = NULL;
+	    }
+	}
+
+	if (prev)
+	{
+	    if (next)
+	    {
+		prev->next = next;
+	    }
+	    else
+	    {
+		parent->reverseWindows = prev;
+		prev->next = NULL;
+	    }
+	}
+    }
+    else
+    {
+	parent->windows = parent->reverseWindows = NULL;
+    }
+
+    if (w == lastFoundWindow)
+	lastFoundWindow = NULL;
+    if (w == lastDamagedWindow)
+	lastDamagedWindow = NULL;
+}
+
+CompWindow *
+findSibling (CompWindow *w,
+	     Window     id)
+{
+    if (w->parent)
+	for (w = w->parent->windows; w; w = w->next)
+	    if (w->id == id)
+		return w;
+
+    return NULL;
+}
+
+CompWindow *
+walkDepthFirst (CompWindow *w)
+{
+    if (w->windows)
+        return w->windows;
+
+    while (!w->next && w->parent)
+        w = w->parent;
+
+    return w->next;
+}
