diff --git a/lib/modules/Protocols.pmod/X.pmod/Extensions.pmod b/lib/modules/Protocols.pmod/X.pmod/Extensions.pmod
index 1ab7c0c32d9910e54944673745192d1930e35564..274759bec62defbbbd6a50357d25a18a739b72f5 100644
--- a/lib/modules/Protocols.pmod/X.pmod/Extensions.pmod
+++ b/lib/modules/Protocols.pmod/X.pmod/Extensions.pmod
@@ -51,11 +51,13 @@ class Shape
 
   void ShapeRectangles( object window, int xo, int yo,
 			string kind, string operation,
-			array (object) rectangles )
+			object(Types.Rectangle)|
+			array(object(Types.Rectangle)) rectangles )
   {
     int k = shape_kind[kind];
     int o = shape_op[operation];
-    string rects = (rectangles->to_string())*"";
+    string rects = (objectp(rectangles)?rectangles->to_string():
+		    (rectangles->to_string())*"");
 
     object req = Requests.ExtensionRequest( major, 0, 0 );
     req->code = 1;
diff --git a/lib/modules/Protocols.pmod/X.pmod/Requests.pmod b/lib/modules/Protocols.pmod/X.pmod/Requests.pmod
index 24f80a3649ec780ee70f5225f38f8b8018ce6808..74051dac804e00791ac56df6d9aa307a1897f7ce 100644
--- a/lib/modules/Protocols.pmod/X.pmod/Requests.pmod
+++ b/lib/modules/Protocols.pmod/X.pmod/Requests.pmod
@@ -501,8 +501,8 @@ class PolyFillRectangle
 
   string to_string()
   {
-    return build_request(sprintf("%4c%4c%@s", drawable, gc,
-				 rectangles->to_string()));
+    return build_request(sprintf("%4c%4c%s", drawable, gc,
+				 rectangles->to_string()*""));
   }
 }
 
@@ -525,13 +525,13 @@ class PutImage
 
   string to_string()
   {
-  string pad="";
+    string pad="";
     while(((strlen(data)+strlen(pad))%4)) pad += "\0";
     pad =  build_request(sprintf("%4c" "%4c"
-				 "%2c" "%2c"
-				 "%2c" "%2c"
-				 "%c" "%c" "\0\0"
-				 "%s%s",
+			       "%2c" "%2c"
+			       "%2c" "%2c"
+			       "%c" "%c" "\0\0"
+			       "%s%s",
 				 drawable, gc,
 				 width, height,
 				 dst_x, dst_y, left_pad, depth,
diff --git a/lib/modules/Protocols.pmod/X.pmod/Types.pmod b/lib/modules/Protocols.pmod/X.pmod/Types.pmod
index 3d1a68f66ed6e26cfe60360313155965f8ac9f9b..c9cd2f33cd4a84ab3e71a023f98802c601915f7a 100644
--- a/lib/modules/Protocols.pmod/X.pmod/Types.pmod
+++ b/lib/modules/Protocols.pmod/X.pmod/Types.pmod
@@ -22,6 +22,8 @@ class Visual
 {
   inherit XResource;
 
+  int depth;
+
   int c_class;
   int bitsPerRGB;
   int colorMapEntries;
@@ -121,10 +123,10 @@ class Colormap
     req->blue = b;
 
     array a = display->blocking_request( req );
-    return a[0] && (alloced[sprintf("%2c%2c%2c", r, g, b)]=
-		    a[1]);
+    return a[0] && (alloced[sprintf("%2c%2c%2c", r, g, b)]=a[1]);
   }
 
+
   void create(object disp, int i, object vis)
   {
     display = disp;
@@ -583,6 +585,12 @@ class Window
   void ShapeMask( string kind, int xo, int yo, string operation,
 		  object (Pixmap) mask )
   {
+    if(kind == "both")
+    {
+      ShapeMask( "clip", xo, yo, operation, mask);
+      ShapeMask( "bounding", xo, yo, operation, mask);
+      return;
+    }
     if(!display->extensions["SHAPE"])
       error("No shape extension available.\n");
     display->extensions["SHAPE"]->
@@ -591,6 +599,12 @@ class Window
 
   void ShapeOffset( string kind, int xo, int yo )
   {
+    if(kind == "both")
+    {
+      ShapeOffset( "clip", xo, yo );
+      ShapeOffset( "bounding", xo, yo );
+      return;
+    }
     if(!display->extensions["SHAPE"])
       error("No shape extension available.\n");
     display->extensions["SHAPE"]->ShapeOffset( this_object(), kind, xo, yo );
diff --git a/lib/modules/Protocols.pmod/X.pmod/XImage.pmod b/lib/modules/Protocols.pmod/X.pmod/XImage.pmod
new file mode 100644
index 0000000000000000000000000000000000000000..00bccca4ac49c26b475bbf87588759053846a6fe
--- /dev/null
+++ b/lib/modules/Protocols.pmod/X.pmod/XImage.pmod
@@ -0,0 +1,289 @@
+#include "error.h"
+
+// Image --> X module.
+// Needs: Pike 0.6
+
+
+// Base class.
+class XImage
+{
+  class funcall
+  {
+    function f;
+    object parent;
+    
+    void `()( mixed ... args )
+    {
+      mixed q = f( @args );
+      if(objectp(q)) parent->set_image( q );
+      return q;
+    }
+    
+    void create(function q, object p) { f = q;parent=p; }
+  }
+  
+  object image; // The real image.
+
+
+
+  void clear_caches(int x, int y, int width, int height)
+  {
+    // Changed by the inheriting class.
+  }
+
+  void redraw(int x, int y, int width, int height)
+  {
+    // Changed by the inheriting class.
+  }
+
+  void copy(mixed ... args)
+  {
+    return image->copy( @args );
+  }
+
+  varargs object paste(object what, int x, int y)
+  {
+    image->paste(what, x, y);
+    clear_caches(x,y,what->xsize(),what->ysize());
+    redraw(x,y,what->xsize(),what->ysize());
+  }
+
+  varargs object paste_mask(object what, object mask, int x, int y)
+  {
+    image->paste_mask(what, mask, x, y);
+    clear_caches(x,y,what->xsize(),what->ysize());
+    redraw(x,y,what->xsize(),what->ysize());
+  }
+
+  void set_image(object to)
+  {
+    image = to;
+    clear_caches(0,0,image->xsize(),image->ysize());
+    redraw(0,0,image->xsize(),image->ysize());
+  }
+
+  mixed `->( string ind )
+  {
+    mixed x;
+    if((x = `[](this_object(),ind)))
+      return x;
+    x = funcall(image[ind], this_object() );
+  }
+  
+}
+
+
+// Steels a few callbacks from the window.
+
+class WindowImage
+{
+  inherit XImage;
+  object (Types.Window) window;
+  object (Types.RootWindow) root; // extends window
+  object (Types.Visual) visual;
+  object (Types.Colormap) colormap;
+  object (Image.colortable) ccol;
+  object (Types.GC) dgc;
+
+  int best;
+
+  int depth, bpp;
+  function converter;
+  int linepad;
+  int rmask, gmask, bmask;
+
+  void set_render(string type)
+  {
+    if(type == "best") best=1;
+  }
+
+
+  object allocate_colortable()
+  {
+    array wanted;
+    if(best)
+      wanted = image->select_colors( 100 );
+    else
+      wanted = image->select_colors( 32 );
+
+    if(sizeof(wanted) < 10) 
+    {
+      object i = Image.image(100,100);
+      i->tuned_box(0,0, 100, 50,
+		   ({ ({0,255,255 }),({255,255,255 }),
+		      ({0,0,255 }),({255,0,255 }) }));
+      i->tuned_box(0,0, 100, 50,
+		   ({ ({0,0,255 }),({255,0,255 }),
+		      ({0,255,255 }),({255,255,0 }) }));
+      i = i->hsv_to_rgb();
+      wanted += i->select_colors(100);
+    }
+
+    int max_pixel;
+
+    Array.map((array)wanted,
+	    lambda(array o){
+	      return colormap->AllocColor(o[0]*257,o[1]*257,o[2]*257);
+	    });
+
+    foreach(values(colormap->alloced), mapping m)
+      if(m && m->pixel > max_pixel)
+	max_pixel = m->pixel;
+
+    array res = allocate( max_pixel+1 );
+
+    foreach(values(colormap->alloced), mapping m)
+      if(m) res[ m->pixel ] = ({ m->red/257, m->green/257, m->blue/257 });
+// What to do with unallocated colors?
+    res = replace( res, 0, ({ 255,0,255 }) );
+
+    object ct = Image.colortable( res );
+    ct->cubicles(12, 12, 12);
+    if(best)
+      ct->floyd_steinberg();
+    else
+      ct->ordered();
+//  werror(sprintf("colortable: %O\n", res));
+    return ct;
+  }
+
+  void clear_caches(int x, int y, int width, int height)
+  {
+    // no inteligence yet...
+  }
+
+  void redraw(int x, int y, int width, int height)
+  {
+    int lheight = height;
+    int slice = (window->display->maxRequestSize/depth)*32 / width;
+    if(x+width > image->xsize())
+      width = image->xsize()-x;
+    if(width<=0) return;
+
+    if(y+lheight > image->ysize())
+    {
+      height = image->ysize()-y;
+      lheight = image->ysize()-y;
+    }
+    if(lheight<=0) return;
+
+    while(lheight>0)
+    {
+      lheight -= slice;
+      if(lheight < 0) slice += lheight;
+      object mimg = image->copy(x,y,x+width-1,y+slice-1);
+
+      if(rmask)
+	window->PutImage( dgc, depth, x, y, width, slice,
+			  converter( mimg, bpp, linepad, rmask, gmask, bmask,
+				     @(ccol?({ccol}):({}))));
+      else
+      {
+	if(!ccol) ccol = allocate_colortable();
+	string data = converter( mimg, bpp, linepad, depth, ccol );
+	window->PutImage( dgc, bpp, x, y, width, slice, data );
+      }
+      y += slice;
+    }
+  }
+
+  void exposed(mixed event)
+  {
+    redraw(event->x, event->y, event->width, event->height);
+  }
+
+
+  void create(object (Types.Window) w)
+  {
+    window = w;
+    if(!w->visual)
+    {
+      object q = w->parent;
+      if(q)
+	do {
+	  if(q->visual)
+	  {
+	    visual = q->visual;
+	    break;
+	  } else {
+	    q = q->parent;
+	  }
+	} while(q);
+      q = w;
+      while(q) { root = q; q = q->parent; }
+
+      if(!visual)
+	visual = root->visual;
+    } else
+      visual = w->visual;
+
+
+
+    if(root->visual == visual)
+    {
+      werror("using default visual\n");
+      colormap = root->defaultColorMap;
+    }
+    else
+      colormap = w->CreateColormap( visual, 0 );
+    rmask = visual->redMask;
+    gmask = visual->greenMask;
+    bmask = visual->blueMask;
+    depth = visual->depth;
+    bpp = visual->bitsPerRGB;
+    linepad = 32; // FIXME!
+    
+    switch(_Xlib.visual_classes[visual->c_class])
+    {
+     case "StaticGray":  
+       ccol = Image.colortable(0,0,0, ({0,0,0}), ({255,255,255}), 1<<depth);
+       converter = Image.X.encode_pseudocolor;
+       break;
+     case "GrayScale":   
+       ccol = Image.colortable(0,0,0, ({0,0,0}), ({255,255,255}), 1<<depth);
+       converter = Image.X.encode_pseudocolor;
+       break;
+     case "PseudoColor": 
+       ccol = 0;
+       converter = Image.X.encode_pseudocolor;
+       break;
+     case "StaticColor": 
+     case "TrueColor":
+       if(depth < 16)
+       {
+	 ccol = Image.colortable(1<<depth, 1<<rmask, 1<<gmask, 1<<bmask);
+	 ccol->ordered();
+       }
+       converter = Image.X.encode_truecolor_masks;
+       break;
+     case "DirectColor":
+       error("Cannot handle Direct Color visual yet."); 
+       break;
+    }
+    dgc = window->CreateGC();
+
+    w->set_event_callback("_Expose", exposed); // internal callback...
+    w->SelectInput("Exposure");
+  }
+}
+
+class PixmapImage
+{
+  inherit XImage;
+  object pixmap;
+  object (Types.Window) window, root;
+  object (Types.Visual) visual;
+  object (Types.Colormap) colormap;
+
+  int depth;
+  function converter;
+  int linepad;
+  int rmask, gmask, bmask;
+
+
+  void create(object (Types.Pixmap) p, object (Types.Window) w)
+  {
+    pixmap = p;
+    window = w;
+  }
+}
diff --git a/lib/modules/Protocols.pmod/X.pmod/Xlib.pmod b/lib/modules/Protocols.pmod/X.pmod/Xlib.pmod
index 9641739b5da0bfb016e5f9a9ec8a0b94c0746817..5c7d567b8a37096125b7e55e719391e9b453813f 100644
--- a/lib/modules/Protocols.pmod/X.pmod/Xlib.pmod
+++ b/lib/modules/Protocols.pmod/X.pmod/Xlib.pmod
@@ -113,6 +113,11 @@ class Display
   inherit id_manager;
   inherit Atom.atom_manager;
   
+
+  
+  void close_callback(mixed id);
+  void read_callback(mixed id, string data);
+
   // FIXME! Should use some sort of (global) db.
   mapping compose_patterns = decode_value(Stdio.read_bytes("db/compose.db"));
   
@@ -211,9 +216,7 @@ class Display
   /* This function leaves the socket in blocking mode */
   int flush()
   { /* FIXME: Not thread-safe */
-    //     trace(5);
     set_blocking();
-
     int written = write(buffer);
     if (written < strlen(buffer))
       return 0;
@@ -234,7 +237,7 @@ class Display
     int wid;
     object w;
 
-    werror(sprintf("Event: %s\n", event->type));
+//     werror(sprintf("Event: %s\n", event->type));
     if (event->wid && (w = lookup_id(event->wid))
 	&& ((w->event_callbacks["_"+event->type])
 	    ||(w->event_callbacks[event->type])))
@@ -359,6 +362,7 @@ class Display
 		      {
 			int visualID = struct->get_uint(4);
 			object v = Types.Visual(this_object(), visualID);
+			v->depth = depth;
 			v->c_class = struct->get_uint(1);
 			v->bitsPerRGB = struct->get_uint(1);
 			v->colorMapEntries = struct->get_uint(2);
@@ -620,7 +624,6 @@ class Display
 	break;
       }
   }
-  
   void read_callback(mixed id, string data)
   {
     // werror(sprintf("Xlib: received '%s'\n", data));
@@ -650,7 +653,7 @@ class Display
       handle_action(a);
     set_nonblocking(read_callback, write_callback, close_callback);
   }
-
+	  
   int open(string|void display)
   {
     int async = !!connect_handler;
@@ -712,6 +715,7 @@ class Display
 	if (!connect(host, port))
 	  return 0;
       }
+
     set_buffer( 65536 );
 
     screen_number = (int) fields[2];
@@ -756,7 +760,6 @@ class Display
 	      get_keyboard_mapping();
 	      set_nonblocking(read_callback, write_callback, close_callback);
 	      return 1;
-	      break;
 	    case ACTION_CONNECT_FAILED:
 	      werror("Connection failed: "+a[1]+"\n");
 	      return 0;
@@ -813,10 +816,12 @@ class Display
 	    pending_actions->put(a);
 	  }
       }
+
     if (!pending_actions->is_empty())
       call_out(process_pending_actions, 0);
     else
       set_nonblocking(read_callback,write_callback,close_callback);
+
     return ({ success, result });
   }
   
diff --git a/lib/modules/Protocols.pmod/X.pmod/_Xlib.pmod b/lib/modules/Protocols.pmod/X.pmod/_Xlib.pmod
index 0b39a561c02d278af340cd49601039b60a1b96f0..c0cce15cfb5ac782200db45388bcfcdc2dfa4cf8 100644
--- a/lib/modules/Protocols.pmod/X.pmod/_Xlib.pmod
+++ b/lib/modules/Protocols.pmod/X.pmod/_Xlib.pmod
@@ -162,3 +162,13 @@ array(string) error_codes =
   "Length",		/* Request length incorrect */
   "Implementation"	/* server is defective */
 });
+
+array(string) visual_classes =
+({
+  "StaticGray",
+  "GrayScale",
+  "StaticColor",
+  "PseudoColor",
+  "TrueColor",
+  "DirectColor",
+});