[Spice-commits] 26 commits - client/canvas.cpp client/canvas.h client/cursor_channel.cpp client/display_channel.cpp client/display_channel.h client/gui client/red_cairo_canvas.cpp client/red_cairo_canvas.h client/red_drawable.h client/red_gdi_canvas.cpp client/red_gdi_canvas.h client/red_gl_canvas.cpp client/red_gl_canvas.h client/red_pixmap_cairo.h client/red_pixmap_gdi.h client/red_pixmap_gl.h client/red_pixmap.h client/red_window.h client/screen.cpp client/windows client/x11 common/cairo_canvas.c common/cairo_canvas.h common/canvas_base.c common/canvas_base.h common/canvas_utils.c common/canvas_utils.h common/gdi_canvas.c common/gdi_canvas.h common/gl_canvas.c common/gl_canvas.h common/pixman_utils.c common/pixman_utils.h common/region.c common/rop3.c configure.ac server/red_worker.c server/vd_interface.h

Alexander Larsson alexl at kemper.freedesktop.org
Fri Apr 23 07:54:57 PDT 2010


 client/canvas.cpp                   |    1 
 client/canvas.h                     |   10 
 client/cursor_channel.cpp           |   14 
 client/display_channel.cpp          |   72 +--
 client/display_channel.h            |   15 
 client/gui/gui.cpp                  |    3 
 client/red_cairo_canvas.cpp         |   76 +--
 client/red_cairo_canvas.h           |   11 
 client/red_drawable.h               |   57 ++
 client/red_gdi_canvas.cpp           |   48 --
 client/red_gdi_canvas.h             |    9 
 client/red_gl_canvas.cpp            |   55 --
 client/red_gl_canvas.h              |    7 
 client/red_pixmap.h                 |   12 
 client/red_pixmap_cairo.h           |    3 
 client/red_pixmap_gdi.h             |    4 
 client/red_pixmap_gl.h              |    2 
 client/red_window.h                 |    1 
 client/screen.cpp                   |    4 
 client/windows/red_pixmap.cpp       |    8 
 client/windows/red_pixmap_cairo.cpp |   29 -
 client/windows/red_pixmap_gdi.cpp   |   28 -
 client/windows/red_window.cpp       |    9 
 client/x11/pixels_source.cpp        |   70 +--
 client/x11/pixels_source_p.h        |    8 
 client/x11/platform.cpp             |  181 +++++++-
 client/x11/red_drawable.cpp         |  145 ++++--
 client/x11/red_pixmap.cpp           |    4 
 client/x11/red_pixmap_cairo.cpp     |  203 ++-------
 client/x11/red_pixmap_gl.cpp        |    8 
 client/x11/red_window.cpp           |   71 ++-
 client/x11/x_platform.h             |   14 
 common/cairo_canvas.c               |  207 ++++++---
 common/cairo_canvas.h               |   17 
 common/canvas_base.c                |  617 +++++++++++++--------------
 common/canvas_base.h                |    6 
 common/canvas_utils.c               |   57 ++
 common/canvas_utils.h               |    9 
 common/gdi_canvas.c                 |   22 
 common/gdi_canvas.h                 |    2 
 common/gl_canvas.c                  |   20 
 common/gl_canvas.h                  |    2 
 common/pixman_utils.c               |  810 +++++++++++++++++++++++++++++++++---
 common/pixman_utils.h               |   23 +
 common/region.c                     |    6 
 common/rop3.c                       |  107 +++-
 configure.ac                        |    1 
 server/red_worker.c                 |  140 ++++--
 server/vd_interface.h               |    2 
 49 files changed, 2144 insertions(+), 1086 deletions(-)

New commits:
commit a1ec6e065a1d39426949a322eeb67f8fb9f854e5
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Apr 23 16:35:31 2010 +0200

    Fix up win32 client with recent changes

diff --git a/client/red_gdi_canvas.cpp b/client/red_gdi_canvas.cpp
index 0ea53ed..391883b 100644
--- a/client/red_gdi_canvas.cpp
+++ b/client/red_gdi_canvas.cpp
@@ -31,12 +31,12 @@ GDICanvas::GDICanvas(int width, int height, uint32_t format,
 {
     _pixmap = new RedPixmapGdi(width, height,
                                RedDrawable::format_from_surface(format),
-                               true, NULL);
+                               true);
     if (!(_canvas = gdi_canvas_create(width, height, _pixmap->get_dc(),
                                       &_pixmap->get_mutex(),
-                                      depth, &pixmap_cache().base,
-                                      &palette_cache().base,
-                                      &csurfaces().base,
+                                      format, &pixmap_cache.base,
+                                      &palette_cache.base,
+                                      &csurfaces.base,
                                       &glz_decoder()))) {
         THROW("create canvas failed");
     }
@@ -44,8 +44,8 @@ GDICanvas::GDICanvas(int width, int height, uint32_t format,
 
 GDICanvas::~GDICanvas()
 {
-  _canvas->ops->destroy(_canvas);
-  _canvas = NULL;
+    _canvas->ops->destroy(_canvas);
+    _canvas = NULL;
     delete _pixmap;
     _pixmap = NULL;
 }
@@ -72,10 +72,6 @@ void GDICanvas::copy_pixels(const QRegion& region, RedDrawable* dest_dc, const P
     copy_pixels(region, *dest_dc);
 }
 
-void GDICanvas::set_mode(int width, int height, int depth)
-{
-    destroy();
-}
 
 CanvasType GDICanvas::get_pixmap_type()
 {
diff --git a/client/windows/red_pixmap_gdi.cpp b/client/windows/red_pixmap_gdi.cpp
index 322d020..b6449b9 100644
--- a/client/windows/red_pixmap_gdi.cpp
+++ b/client/windows/red_pixmap_gdi.cpp
@@ -30,7 +30,7 @@ struct RedPixmap_p {
 };
 
 RedPixmapGdi::RedPixmapGdi(int width, int height, RedDrawable::Format format, bool top_bottom)
-    : RedPixmap(width, height, format, top_bottom, pallet)
+    : RedPixmap(width, height, format, top_bottom	)
 {
     ASSERT(format == RedDrawable::ARGB32 || format == RedDrawable::RGB32 || format == RedDrawable::A1);
     ASSERT(sizeof(RedPixmap_p) <= PIXELES_SOURCE_OPAQUE_SIZE);
diff --git a/client/windows/red_window.cpp b/client/windows/red_window.cpp
index def2587..80a282a 100644
--- a/client/windows/red_window.cpp
+++ b/client/windows/red_window.cpp
@@ -364,6 +364,15 @@ void RedWindow_p::destroy(PixelsSource_p& pixels_source)
     DestroyWindow(_win);
 }
 
+RedDrawable::Format RedWindow::get_format()
+{
+  /* TODO: Windows will convert types when
+     blitting, so this works (and is what we did before).
+     but it would be better to return the right format here */
+    return RedDrawable::RGB32;
+}
+
+
 void RedWindow_p::on_pos_changing(RedWindow& red_window)
 {
     if (_minimized || IsIconic(_win)) {
commit b2165b4d04435db32eec01e9389fce6d20bcd040
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Apr 23 16:33:36 2010 +0200

    Win32 canvas fixes

diff --git a/common/gdi_canvas.c b/common/gdi_canvas.c
index c600419..f74a6c3 100644
--- a/common/gdi_canvas.c
+++ b/common/gdi_canvas.c
@@ -664,7 +664,7 @@ static HBRUSH get_brush(GdiCanvas *canvas, SpiceBrush *brush, RecurciveMutex **b
             }
             *brush_lock = gdi_surface->lock;
         } else {
-            surface = canvas_get_image(&canvas->base, brush->u.pattern.pat);
+            surface = canvas_get_image(&canvas->base, brush->u.pattern.pat, FALSE);
             surface_to_image(surface, &image);
     
             if (!create_bitmap(&bitmap, &prev_bitmap, &dc, image.pixels, image.width,
@@ -1076,7 +1076,7 @@ static void gdi_canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spi
         gdi_draw_bitmap_redrop(canvas->dc, &copy->src_area, bbox, gdi_surface->dc,
                                &bitmapmask, copy->rop_decriptor, 0);
     } else {
-        surface = canvas_get_image(&canvas->base, copy->src_bitmap);
+        surface = canvas_get_image(&canvas->base, copy->src_bitmap, FALSE);
         pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface);
     
         RecurciveLock lock(*canvas->lock);
@@ -1217,7 +1217,7 @@ static void gdi_canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bb
         gdi_draw_bitmap_transparent(canvas, canvas->dc, &transparent->src_area, bbox,
                                     gdi_surface->dc, transparent->true_color);
     } else {
-        surface = canvas_get_image(&canvas->base, transparent->src_bitmap);
+        surface = canvas_get_image(&canvas->base, transparent->src_bitmap, FALSE);
         pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface);
         RecurciveLock lock(*canvas->lock);
         set_clip(canvas, clip);
@@ -1297,11 +1297,11 @@ static void gdi_canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bb
         RecurciveLock lock(*canvas->lock);
         RecurciveLock s_lock(*gdi_surface->lock);
         set_clip(canvas, clip);
-        use_bitmap_alpha = 0;
+        use_bitmap_alpha = alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_SRC_SURFACE_HAS_ALPHA;
         gdi_draw_bitmap_alpha(canvas->dc, &alpha_blend->src_area, bbox, gdi_surface->dc,
                               alpha_blend->alpha, use_bitmap_alpha);
     } else {
-        surface = canvas_get_image(&canvas->base, alpha_blend->src_bitmap);
+        surface = canvas_get_image(&canvas->base, alpha_blend->src_bitmap, TRUE);
         use_bitmap_alpha = pixman_image_get_depth(surface) == 32;
         pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface);
     
@@ -1361,7 +1361,7 @@ static void gdi_canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, S
         }
         unset_brush(canvas->dc, prev_hbrush);
     } else {
-        surface = canvas_get_image(&canvas->base, opaque->src_bitmap);
+        surface = canvas_get_image(&canvas->base, opaque->src_bitmap, FALSE);
         pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface);
     
         RecurciveLock lock(*canvas->lock);
@@ -1423,7 +1423,7 @@ static void gdi_canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, Sp
         gdi_draw_bitmap_redrop(canvas->dc, &blend->src_area, bbox, gdi_surface->dc,
                                &bitmapmask, blend->rop_decriptor, 0);
     }  else {
-        surface = canvas_get_image(&canvas->base, blend->src_bitmap);
+        surface = canvas_get_image(&canvas->base, blend->src_bitmap, FALSE);
         pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface);
     
         RecurciveLock lock(*canvas->lock);
@@ -1524,7 +1524,7 @@ static void gdi_canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spi
         }
         unset_brush(canvas->dc, prev_hbrush);
     } else {
-        surface = canvas_get_image(&canvas->base, rop3->src_bitmap);
+        surface = canvas_get_image(&canvas->base, rop3->src_bitmap, FALSE);
         pixman_data = (PixmanData *)pixman_image_get_destroy_data(surface);
         RecurciveLock lock(*canvas->lock);
         hbrush = get_brush(canvas, &rop3->brush, &brush_lock);
@@ -1706,7 +1706,7 @@ static void gdi_canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, S
     pixman_image_t *surface = NULL;
 
     if (stroke->brush.type == SPICE_BRUSH_TYPE_PATTERN) {
-        surface = canvas_get_image(&canvas->base, stroke->brush.u.pattern.pat);
+        surface = canvas_get_image(&canvas->base, stroke->brush.u.pattern.pat, FALSE);
     }
 
     RecurciveLock lock(*canvas->lock);
commit c2f38a68ba4004cdf6eb9eba875d6f8f53fa1fb8
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Apr 23 15:24:03 2010 +0200

    If we have alpha in a 32bit rgb surface, ensure we send that
    
    If we don't then alpha is lost which is problematic if the surface
    is later used as with alpha_blend and SRC_SURFACE_HAS_ALPHA.

diff --git a/server/red_worker.c b/server/red_worker.c
index 98ead52..042f59e 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -3581,6 +3581,25 @@ static int surface_format_to_image_type(uint32_t surface_format)
     return 0;
 }
 
+static int rgb32_data_has_alpha(int width, int height, size_t stride,
+                                uint8_t *data)
+{
+    uint32_t *line, *end;
+
+    while (height-- > 0) {
+        line = (uint32_t *)data;
+        end = line + width;
+        data += stride;
+        while (line != end) {
+            if ((*line & 0xff000000) != 0) {
+                return 1;
+            }
+            line++;
+        }
+    }
+    return 0;
+}
+
 static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
 {
     QXLImage *image;
@@ -3623,6 +3642,11 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
     red_get_area(worker, drawable->surface_id,
                  &drawable->qxl_drawable->self_bitmap_area, dest, dest_stride, TRUE);
 
+    if (image->bitmap.format == SPICE_BITMAP_FMT_32BIT &&
+        rgb32_data_has_alpha(width, height, dest_stride, dest)) {
+        image->bitmap.format = SPICE_BITMAP_FMT_RGBA;
+    }
+
     drawable->self_bitmap = (uint8_t *)image;
     return TRUE;
 }
@@ -4941,6 +4965,12 @@ static void red_add_surface_image(RedWorker *worker, int surface_id)
     area.right = surface->context.width;
     area.bottom = surface->context.height;
     canvas->ops->read_bits(canvas, item->data, stride, &area);
+
+    if (item->image_format == SPICE_BITMAP_FMT_32BIT &&
+        rgb32_data_has_alpha(item->width, item->height, item->stride, item->data)) {
+        item->image_format = SPICE_BITMAP_FMT_RGBA;
+    }
+
     red_pipe_add_image_item(worker, item);
     release_image_item(item);
     display_channel_push(worker);
commit 810caf0e779bf280370221018bee6a0d4d63160b
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Apr 23 15:15:40 2010 +0200

    Support alpha surface sources and destinations

diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c
index 931fd36..a324c44 100644
--- a/common/cairo_canvas.c
+++ b/common/cairo_canvas.c
@@ -555,8 +555,28 @@ static void scale_image_rop_from_surface(SpiceCanvas *spice_canvas,
                       src_height, dest_x, dest_y, dest_width, dest_height, scale_mode, rop);
 }
 
+static pixman_image_t *canvas_get_as_surface(CairoCanvas *canvas,
+                                          int with_alpha)
+{
+    pixman_image_t *target;
+
+    if (with_alpha &&
+        canvas->base.format == SPICE_SURFACE_FMT_32_xRGB) {
+        target = pixman_image_create_bits(PIXMAN_a8r8g8b8,
+                                          pixman_image_get_width(canvas->image),
+                                          pixman_image_get_height(canvas->image),
+                                          pixman_image_get_data(canvas->image),
+                                          pixman_image_get_stride(canvas->image));
+    } else {
+        target = pixman_image_ref(canvas->image);
+    }
+
+    return target;
+}
+
 static void __blend_image(SpiceCanvas *spice_canvas,
                           pixman_region32_t *region,
+                          int dest_has_alpha,
                           pixman_image_t *src,
                           int src_x, int src_y,
                           int dest_x, int dest_y,
@@ -564,9 +584,11 @@ static void __blend_image(SpiceCanvas *spice_canvas,
                           int overall_alpha)
 {
     CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
-    pixman_image_t *mask;
+    pixman_image_t *mask, *dest;
 
-    pixman_image_set_clip_region32(canvas->image, region);
+    dest = canvas_get_as_surface(canvas, dest_has_alpha);
+
+    pixman_image_set_clip_region32(dest, region);
 
     mask = NULL;
     if (overall_alpha != 0xff) {
@@ -578,7 +600,7 @@ static void __blend_image(SpiceCanvas *spice_canvas,
     pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
 
     pixman_image_composite32(PIXMAN_OP_OVER,
-                             src, mask, canvas->image,
+                             src, mask, dest,
                              src_x, src_y, /* src */
                              0, 0, /* mask */
                              dest_x, dest_y, /* dst */
@@ -589,36 +611,48 @@ static void __blend_image(SpiceCanvas *spice_canvas,
         pixman_image_unref(mask);
     }
 
-    pixman_image_set_clip_region32(canvas->image, NULL);
+    pixman_image_set_clip_region32(dest, NULL);
+    pixman_image_unref(dest);
 }
 
 static void blend_image(SpiceCanvas *spice_canvas,
                         pixman_region32_t *region,
+                        int dest_has_alpha,
                         pixman_image_t *src,
                         int src_x, int src_y,
                         int dest_x, int dest_y,
                         int width, int height,
                         int overall_alpha)
 {
-    __blend_image(spice_canvas, region, src, src_x, src_y, dest_x, dest_y, width, height,
+    __blend_image(spice_canvas, region, dest_has_alpha, src, src_x, src_y,
+                  dest_x, dest_y, width, height,
                   overall_alpha);
 }
 
 static void blend_image_from_surface(SpiceCanvas *spice_canvas,
                                      pixman_region32_t *region,
+                                     int dest_has_alpha,
                                      SpiceCanvas *surface_canvas,
+                                     int src_has_alpha,
                                      int src_x, int src_y,
                                      int dest_x, int dest_y,
                                      int width, int height,
                                      int overall_alpha)
 {
     CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas;
-    __blend_image(spice_canvas, region, cairo_surface_canvas->image, src_x, src_y, dest_x, dest_y,
+    pixman_image_t *src;
+
+    src = canvas_get_as_surface(cairo_surface_canvas, src_has_alpha);
+    __blend_image(spice_canvas, region, dest_has_alpha,
+                  src, src_x, src_y,
+                  dest_x, dest_y,
                   width, height, overall_alpha);
+    pixman_image_unref(src);
 }
 
 static void __blend_scale_image(SpiceCanvas *spice_canvas,
                                 pixman_region32_t *region,
+                                int dest_has_alpha,
                                 pixman_image_t *src,
                                 int src_x, int src_y,
                                 int src_width, int src_height,
@@ -629,13 +663,15 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas,
 {
     CairoCanvas *canvas = (CairoCanvas *)spice_canvas;
     pixman_transform_t transform;
-    pixman_image_t *mask;
+    pixman_image_t *mask, *dest;
     double sx, sy;
 
     sx = (double)(src_width) / (dest_width);
     sy = (double)(src_height) / (dest_height);
 
-    pixman_image_set_clip_region32(canvas->image, region);
+    dest = canvas_get_as_surface(canvas, dest_has_alpha);
+
+    pixman_image_set_clip_region32(dest, region);
 
     pixman_transform_init_scale(&transform,
                                 pixman_double_to_fixed(sx),
@@ -658,7 +694,7 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas,
                             NULL, 0);
 
     pixman_image_composite32(PIXMAN_OP_OVER,
-                             src, mask, canvas->image,
+                             src, mask, dest,
                              ROUND(src_x / sx), ROUND(src_y / sy), /* src */
                              0, 0, /* mask */
                              dest_x, dest_y, /* dst */
@@ -671,11 +707,13 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas,
         pixman_image_unref(mask);
     }
 
-    pixman_image_set_clip_region32(canvas->image, NULL);
+    pixman_image_set_clip_region32(dest, NULL);
+    pixman_image_unref(dest);
 }
 
 static void blend_scale_image(SpiceCanvas *spice_canvas,
                               pixman_region32_t *region,
+                              int dest_has_alpha,
                               pixman_image_t *src,
                               int src_x, int src_y,
                               int src_width, int src_height,
@@ -684,13 +722,17 @@ static void blend_scale_image(SpiceCanvas *spice_canvas,
                               int scale_mode,
                               int overall_alpha)
 {
-    __blend_scale_image(spice_canvas, region, src, src_x, src_y, src_width, src_height, dest_x,
-                        dest_y, dest_width, dest_height, scale_mode, overall_alpha);
+    __blend_scale_image(spice_canvas, region, dest_has_alpha,
+                        src, src_x, src_y, src_width, src_height,
+                        dest_x, dest_y, dest_width, dest_height,
+                        scale_mode, overall_alpha);
 }
 
 static void blend_scale_image_from_surface(SpiceCanvas *spice_canvas,
                                            pixman_region32_t *region,
+                                           int dest_has_alpha,
                                            SpiceCanvas *surface_canvas,
+                                           int src_has_alpha,
                                            int src_x, int src_y,
                                            int src_width, int src_height,
                                            int dest_x, int dest_y,
@@ -699,9 +741,13 @@ static void blend_scale_image_from_surface(SpiceCanvas *spice_canvas,
                                            int overall_alpha)
 {
     CairoCanvas *cairo_surface_canvas = (CairoCanvas *)surface_canvas;
-    __blend_scale_image(spice_canvas, region, cairo_surface_canvas->image, src_x, src_y, src_width,
+    pixman_image_t *src;
+
+    src = canvas_get_as_surface(cairo_surface_canvas, src_has_alpha);
+    __blend_scale_image(spice_canvas, region, dest_has_alpha, src, src_x, src_y, src_width,
                         src_height, dest_x, dest_y, dest_width, dest_height, scale_mode,
                         overall_alpha);
+    pixman_image_unref(src);
 }
 
 static void __colorkey_image(SpiceCanvas *spice_canvas,
@@ -1116,6 +1162,9 @@ SpiceCanvas *canvas_create(int width, int height, uint32_t format
 {
     pixman_image_t *image;
 
+    if (format == SPICE_SURFACE_FMT_32_ARGB) {
+        format = SPICE_SURFACE_FMT_32_xRGB;
+    }
     image = pixman_image_create_bits(spice_surface_format_to_pixman (format),
                                      width, height, NULL, 0);
 
@@ -1151,6 +1200,10 @@ SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format,
 {
     pixman_image_t *image;
 
+    if (format == SPICE_SURFACE_FMT_32_ARGB) {
+        format = SPICE_SURFACE_FMT_32_xRGB;
+    }
+
     image = pixman_image_create_bits(spice_surface_format_to_pixman (format),
                                      width, height, (uint32_t *)data, stride);
 
diff --git a/common/canvas_base.c b/common/canvas_base.c
index e1201af..c305f4d 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -414,10 +414,26 @@ static pixman_format_code_t canvas_get_target_format(CanvasBase *canvas,
     /* Convert to target surface format */
     format = spice_surface_format_to_pixman (canvas->format);
 
-    if (!source_has_alpha) {
+    if (source_has_alpha) {
+        /* Even though the destination has no alpha, we make the source
+         * remember there are alpha bits instead of throwing away this
+         * information. The results are the same if alpha is not
+         * interpreted, and if need to interpret alpha, don't use
+         * conversion to target format.
+         * This is needed for instance when doing the final
+         * canvas_get_target_format() in canvas_get_image_internal
+         * as otherwise we wouldn't know if the bitmap source
+         * really had alpha.
+         */
+        if (format == PIXMAN_x8r8g8b8) {
+            format = PIXMAN_a8r8g8b8;
+        }
+    } else { /* !source_has_alpha */
         /* If the source doesn't have alpha, but the destination has,
-           don't convert to alpha, since that would fill the alpha bytes
-           with 0xff which is not expected if we just use the raw bits */
+           don't convert to alpha, since that would just do an unnecessary
+           copy to fill the alpha bytes with 0xff which is not expected if
+           we just use the raw bits, (and handled implicitly by pixman if
+           we're interpreting data) */
         if (format == PIXMAN_a8r8g8b8) {
             format = PIXMAN_x8r8g8b8;
         }
@@ -914,7 +930,7 @@ static SpiceCanvas *canvas_get_surface_internal(CanvasBase *canvas, SPICE_ADDRES
 static SpiceCanvas *canvas_get_surface_mask_internal(CanvasBase *canvas, SPICE_ADDRESS addr)
 {
     SpiceImageDescriptor *descriptor;
- 
+
     descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
     access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
 
@@ -2222,7 +2238,9 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox,
     if (surface_canvas) {
         if (rect_is_same_size(bbox, &alpha_blend->src_area)) {
             spice_canvas->ops->blend_image_from_surface(spice_canvas, &dest_region,
+                                                        alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_DEST_HAS_ALPHA,
                                                         surface_canvas,
+                                                        alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_SRC_SURFACE_HAS_ALPHA,
                                                         alpha_blend->src_area.left,
                                                         alpha_blend->src_area.top,
                                                         bbox->left,
@@ -2232,7 +2250,9 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox,
                                                         alpha_blend->alpha);
         } else {
             spice_canvas->ops->blend_scale_image_from_surface(spice_canvas, &dest_region,
+                                                              alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_DEST_HAS_ALPHA,
                                                               surface_canvas,
+                                                              alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_SRC_SURFACE_HAS_ALPHA,
                                                               alpha_blend->src_area.left,
                                                               alpha_blend->src_area.top,
                                                               alpha_blend->src_area.right - alpha_blend->src_area.left,
@@ -2248,6 +2268,7 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox,
         src_image = canvas_get_image(canvas, alpha_blend->src_bitmap, TRUE);
         if (rect_is_same_size(bbox, &alpha_blend->src_area)) {
             spice_canvas->ops->blend_image(spice_canvas, &dest_region,
+                                           alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_DEST_HAS_ALPHA,
                                            src_image,
                                            alpha_blend->src_area.left,
                                            alpha_blend->src_area.top,
@@ -2258,6 +2279,7 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox,
                                            alpha_blend->alpha);
         } else {
             spice_canvas->ops->blend_scale_image(spice_canvas, &dest_region,
+                                                 alpha_blend->alpha_flags & SPICE_ALPHA_FLAGS_DEST_HAS_ALPHA,
                                                  src_image,
                                                  alpha_blend->src_area.left,
                                                  alpha_blend->src_area.top,
@@ -2270,7 +2292,7 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox,
                                                  SPICE_IMAGE_SCALE_MODE_NEAREST,
                                                  alpha_blend->alpha);
         }
- 
+
         pixman_image_unref(src_image);
     }
 
diff --git a/common/canvas_base.h b/common/canvas_base.h
index f2b0d5b..f78b0b8 100644
--- a/common/canvas_base.h
+++ b/common/canvas_base.h
@@ -206,6 +206,7 @@ typedef struct {
 					 int scale_mode, SpiceROP rop);
     void (*blend_image)(SpiceCanvas *canvas,
                         pixman_region32_t *region,
+                        int dest_has_alpha,
                         pixman_image_t *src_image,
                         int src_x, int src_y,
                         int dest_x, int dest_y,
@@ -213,13 +214,16 @@ typedef struct {
                         int overall_alpha);
     void (*blend_image_from_surface)(SpiceCanvas *canvas,
 				     pixman_region32_t *region,
+                                     int dest_has_alpha,
 				     SpiceCanvas *src_image,
+                                     int src_has_alpha,
 				     int src_x, int src_y,
 				     int dest_x, int dest_y,
 				     int width, int height,
 				     int overall_alpha);
     void (*blend_scale_image)(SpiceCanvas *canvas,
                               pixman_region32_t *region,
+                              int dest_has_alpha,
                               pixman_image_t *src_image,
                               int src_x, int src_y,
                               int src_width, int src_height,
@@ -229,7 +233,9 @@ typedef struct {
                               int overall_alpha);
     void (*blend_scale_image_from_surface)(SpiceCanvas *canvas,
 					   pixman_region32_t *region,
+                                           int dest_has_alpha,
 					   SpiceCanvas *src_image,
+                                           int src_has_alpha,
 					   int src_x, int src_y,
 					   int src_width, int src_height,
 					   int dest_x, int dest_y,
commit 1a590c50c03c5d752af8d8c3b3c0ff28d35ee147
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu Apr 22 17:48:21 2010 +0200

    Localize palettes for LZ PLT format
    
    This is needed since they always decode to 32bit mode.

diff --git a/common/canvas_base.c b/common/canvas_base.c
index 799722c..e1201af 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -572,7 +572,7 @@ static pixman_image_t *canvas_bitmap_to_surface(CanvasBase *canvas, SpiceBitmap*
 
 #ifdef CAIRO_CANVAS_CACHE
 
-static inline SpicePalette *canvas_get_palett(CanvasBase *canvas, SPICE_ADDRESS base_palette, uint8_t flags)
+static inline SpicePalette *canvas_get_palette(CanvasBase *canvas, SPICE_ADDRESS base_palette, uint8_t flags)
 {
     SpicePalette *palette;
     if (!base_palette) {
@@ -592,6 +592,42 @@ static inline SpicePalette *canvas_get_palett(CanvasBase *canvas, SPICE_ADDRESS
     return palette;
 }
 
+static inline SpicePalette *canvas_get_localized_palette(CanvasBase *canvas, SPICE_ADDRESS base_palette, uint8_t flags, int *free_palette)
+{
+    SpicePalette *palette = canvas_get_palette(canvas, base_palette, flags);
+    SpicePalette *copy;
+    uint32_t *now, *end;
+    size_t size;
+
+    if (canvas->format == SPICE_SURFACE_FMT_32_xRGB ||
+        canvas->format == SPICE_SURFACE_FMT_32_ARGB) {
+        return palette;
+    }
+
+    size = sizeof(SpicePalette) + palette->num_ents * 4;
+    copy = (SpicePalette *)spice_malloc(size);
+    memcpy(copy, palette, size);
+
+    switch (canvas->format) {
+    case SPICE_SURFACE_FMT_32_xRGB:
+    case SPICE_SURFACE_FMT_32_ARGB:
+        /* Won't happen */
+        break;
+    case SPICE_SURFACE_FMT_16_555:
+        now = copy->ents;
+        end = now + copy->num_ents;
+        for (; now < end; now++) {
+            *now = canvas_16bpp_to_32bpp(*now);
+        }
+        break;
+    case SPICE_SURFACE_FMT_16_565:
+    default:
+        PANIC("Unsupported palette depth");
+    }
+    *free_palette = TRUE;
+    return copy;
+}
+
 static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int invers,
                                      int want_original)
 {
@@ -608,6 +644,7 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int inv
     int height;
     int top_down;
     int stride;
+    int free_palette;
 
     if (setjmp(lz_data->jmp_env)) {
         if (decomp_buf) {
@@ -616,6 +653,7 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int inv
         CANVAS_ERROR("lz error, %s", lz_data->message_buf);
     }
 
+    free_palette = FALSE;
     if (image->descriptor.type == SPICE_IMAGE_TYPE_LZ_RGB) {
         comp_buf = image->lz_rgb.data;
         comp_size = image->lz_rgb.data_size;
@@ -623,7 +661,7 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int inv
     } else if (image->descriptor.type == SPICE_IMAGE_TYPE_LZ_PLT) {
         comp_buf = image->lz_plt.data;
         comp_size = image->lz_plt.data_size;
-        palette = canvas_get_palett(canvas, image->lz_plt.palette, image->lz_plt.flags);
+        palette = canvas_get_localized_palette(canvas, image->lz_plt.palette, image->lz_plt.flags, &free_palette);
     } else {
         CANVAS_ERROR("unexpected image type");
     }
@@ -700,6 +738,10 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int inv
         }
     }
 
+    if (free_palette)  {
+        free(palette);
+    }
+
     return lz_data->decode_data.out_surface;
 }
 
@@ -770,7 +812,7 @@ static pixman_image_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap,
     pixman_image_t* surface;
     SpicePalette *palette;
 
-    palette = canvas_get_palett(canvas, bitmap->palette, bitmap->flags);
+    palette = canvas_get_palette(canvas, bitmap->palette, bitmap->flags);
 #ifdef DEBUG_DUMP_BITMAP
     if (palette) {
         dump_bitmap(bitmap, palette);
commit 395b5a5626bfb2c113f9cc865cb0ce9c7c937d2c
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu Apr 22 15:57:41 2010 +0200

    Server: Use the right image format when updating from a surface

diff --git a/server/red_worker.c b/server/red_worker.c
index 7d6df88..98ead52 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -399,6 +399,7 @@ typedef struct ImageItem {
     int stride;
     int top_down;
     int surface_id;
+    int image_format;
     uint8_t data[0];
 } ImageItem;
 
@@ -3565,6 +3566,21 @@ static void red_get_area(RedWorker *worker, int surface_id, const SpiceRect *are
     canvas->ops->read_bits(canvas, dest, dest_stride, area);
 }
 
+static int surface_format_to_image_type(uint32_t surface_format)
+{
+    switch (surface_format) {
+    case SPICE_SURFACE_FMT_16_555:
+        return SPICE_BITMAP_FMT_16BIT;
+    case SPICE_SURFACE_FMT_32_xRGB:
+        return SPICE_BITMAP_FMT_32BIT;
+    case SPICE_SURFACE_FMT_32_ARGB:
+        return SPICE_BITMAP_FMT_RGBA;
+    default:
+        PANIC("Unsupported surface format");
+    }
+    return 0;
+}
+
 static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
 {
     QXLImage *image;
@@ -3597,19 +3613,7 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
     QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_RED, ++worker->bits_unique);
     image->bitmap.flags = QXL_BITMAP_DIRECT | (surface->context.top_down ?
                                                QXL_BITMAP_TOP_DOWN : 0);
-    switch (surface->context.format) {
-    case SPICE_SURFACE_FMT_32_xRGB:
-        image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
-        break;
-    case SPICE_SURFACE_FMT_32_ARGB:
-        image->bitmap.format = SPICE_BITMAP_FMT_RGBA;
-        break;
-    case SPICE_SURFACE_FMT_16_555:
-        image->bitmap.format = SPICE_BITMAP_FMT_16BIT;
-        break;
-    default:
-        ASSERT(0); /* not supported yet */
-    }
+    image->bitmap.format = surface_format_to_image_type(surface->context.format);
     image->bitmap.stride = dest_stride;
     image->descriptor.width = image->bitmap.x = width;
     image->descriptor.height = image->bitmap.y = height;
@@ -4908,29 +4912,34 @@ static void red_add_surface_image(RedWorker *worker, int surface_id)
     int stride;
     SpiceRect area;
     SpiceCanvas *canvas = worker->surfaces[surface_id].context.canvas;
+    RedSurface *surface;
+
+    surface = &worker->surfaces[surface_id];
 
-    if (!worker->display_channel || !worker->surfaces[surface_id].context.canvas) {
+    if (!worker->display_channel || !surface->context.canvas) {
         return;
     }
 
-    stride = abs(worker->surfaces[surface_id].context.stride);
+    stride = abs(surface->context.stride);
 
-    item = (ImageItem *)spice_malloc_n_m(worker->surfaces[surface_id].context.height, stride,
+    item = (ImageItem *)spice_malloc_n_m(surface->context.height, stride,
                                          sizeof(ImageItem));
 
     red_pipe_item_init(&item->link, PIPE_ITEM_TYPE_IMAGE);
 
     item->refs = 1;
     item->surface_id = surface_id;
+    item->image_format =
+        surface_format_to_image_type(surface->context.format);
     item->pos.x = item->pos.y = 0;
-    item->width = worker->surfaces[surface_id].context.width;
-    item->height = worker->surfaces[surface_id].context.height;
+    item->width = surface->context.width;
+    item->height = surface->context.height;
     item->stride = stride;
-    item->top_down = worker->surfaces[surface_id].context.top_down;
+    item->top_down = surface->context.top_down;
 
     area.top = area.left = 0;
-    area.right = worker->surfaces[surface_id].context.width;
-    area.bottom = worker->surfaces[surface_id].context.height;
+    area.right = surface->context.width;
+    area.bottom = surface->context.height;
     canvas->ops->read_bits(canvas, item->data, stride, &area);
     red_pipe_add_image_item(worker, item);
     release_image_item(item);
@@ -7239,7 +7248,7 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item)
     red_image->descriptor.width = item->width;
     red_image->descriptor.height = item->height;
 
-    bitmap.format = SPICE_BITMAP_FMT_32BIT;
+    bitmap.format = item->image_format;
     bitmap.flags = QXL_BITMAP_DIRECT;
     bitmap.flags |= item->top_down ? QXL_BITMAP_TOP_DOWN : 0;
     bitmap.x = item->width;
commit 4f5a09a73d4659e6aaf6537bf9c582df7fe39f00
Author: Alexander Larsson <alexl at redhat.com>
Date:   Mon Apr 19 16:31:45 2010 +0200

    Make each surface its own depth/format
    
    Surface creation now specifies the exact format, not only the bit depth
    of each surface which is used for rendering.
    
    Additionally we now actually store the surfaces in that format, instead
    of converting everything to 32bpp when drawing or e.g. handling palettes.

diff --git a/client/canvas.h b/client/canvas.h
index 1dc2acb..82badc4 100644
--- a/client/canvas.h
+++ b/client/canvas.h
@@ -342,9 +342,12 @@ public:
                                          int width, int height, int gross_pixels,
                                          int n_bytes_per_pixel, bool top_down)
     {
-        pixman_image_t *surface = alloc_lz_image_surface((LzDecodeUsrData *)opaque_usr_info,
-                                                         type, width, height, gross_pixels,
-                                                         top_down);
+        ASSERT(type == LZ_IMAGE_TYPE_RGB32 || type == LZ_IMAGE_TYPE_RGBA);
+
+        pixman_image_t *surface =
+            alloc_lz_image_surface((LzDecodeUsrData *)opaque_usr_info,
+                                   type == LZ_IMAGE_TYPE_RGBA ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
+                                   width, height, gross_pixels, top_down);
         uint8_t *data = (uint8_t *)pixman_image_get_data(surface);
         if (!top_down) {
             data = data - (gross_pixels / height) * n_bytes_per_pixel * (height - 1);
diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index acbf5da..1a326cf 100644
--- a/client/display_channel.cpp
+++ b/client/display_channel.cpp
@@ -45,11 +45,11 @@
 
 class CreatePrimarySurfaceEvent: public SyncEvent {
 public:
-   CreatePrimarySurfaceEvent(DisplayChannel& channel, int width, int height, int depth)
+   CreatePrimarySurfaceEvent(DisplayChannel& channel, int width, int height, uint32_t format)
         : _channel (channel)
         , _width (width)
         , _height (height)
-        , _depth (depth)
+        , _format (format)
     {
     }
 
@@ -58,14 +58,14 @@ public:
         Application* app = (Application*)events_loop.get_owner();
         _channel.screen()->lock_size();
         _channel.screen()->resize(_width, _height);
-        _channel.create_canvas(0, app->get_canvas_types(), _width, _height, _depth);
+        _channel.create_canvas(0, app->get_canvas_types(), _width, _height, _format);
     }
 
 private:
     DisplayChannel& _channel;
     int _width;
     int _height;
-    int _depth;
+    uint32_t _format;
 };
 
 class DestroyPrimarySurfaceEvent: public SyncEvent {
@@ -86,19 +86,20 @@ private:
 
 class CreateSurfaceEvent: public SyncEvent {
 public:
-   CreateSurfaceEvent(DisplayChannel& channel, int surface_id, int width, int height, int depth)
+   CreateSurfaceEvent(DisplayChannel& channel, int surface_id, int width, int height,
+                      uint32_t format)
         : _channel (channel)
         , _surface_id (surface_id)
         , _width (width)
         , _height (height)
-        , _depth (depth)
+        , _format (format)
     {
     }
 
     virtual void do_response(AbstractProcessLoop& events_loop)
     {
         Application* app = (Application*)events_loop.get_owner();
-        _channel.create_canvas(_surface_id, app->get_canvas_types(), _width, _height, _depth);
+        _channel.create_canvas(_surface_id, app->get_canvas_types(), _width, _height, _format);
     }
 
 private:
@@ -106,7 +107,7 @@ private:
     int _surface_id;
     int _width;
     int _height;
-    int _depth;
+    uint32_t _format;
 };
 
 class DestroySurfaceEvent: public SyncEvent {
@@ -562,7 +563,7 @@ void DisplaySurfacesManger::del_canvas(int surface_id)
 }
 
 CSurfaces& DisplaySurfacesManger::get_surfaces()
-{ 
+{
     return surfaces;
 }
 
@@ -753,7 +754,7 @@ void DisplayChannel::recreate_ogl_context_interrupt()
         delete canvas;
     }
 
-    if (!create_ogl_canvas(0, _x_res, _y_res, _depth, 0, _rendertype)) {
+    if (!create_ogl_canvas(0, _x_res, _y_res, _format, 0, _rendertype)) {
         THROW("create_ogl_canvas failed");
     }
 
@@ -1187,23 +1188,23 @@ void DisplayChannel::create_canvas(int surface_id, const std::vector<int>& canva
 
     for (i = 0; i < canvas_types.size(); i++) {
 
-        if (canvas_types[i] == CANVAS_OPTION_CAIRO && create_cairo_canvas(surface_id, width, height, depth)) {
+        if (canvas_types[i] == CANVAS_OPTION_CAIRO && create_cairo_canvas(surface_id, width, height, format)) {
             break;
         }
 #ifdef USE_OGL
-        if (canvas_types[i] == CANVAS_OPTION_OGL_FBO && create_ogl_canvas(surface_id, width, height, depth,
+        if (canvas_types[i] == CANVAS_OPTION_OGL_FBO && create_ogl_canvas(surface_id, width, height, format,
                                                                           recreate,
                                                                           RENDER_TYPE_FBO)) {
             break;
         }
-        if (canvas_types[i] == CANVAS_OPTION_OGL_PBUFF && create_ogl_canvas(surface_id, width, height, depth,
+        if (canvas_types[i] == CANVAS_OPTION_OGL_PBUFF && create_ogl_canvas(surface_id, width, height, format,
                                                                             recreate,
                                                                             RENDER_TYPE_PBUFF)) {
             break;
         }
 #endif
 #ifdef WIN32
-        if (canvas_types[i] == CANVAS_OPTION_GDI && create_gdi_canvas(surface_id, width, height, depth)) {
+        if (canvas_types[i] == CANVAS_OPTION_GDI && create_gdi_canvas(surface_id, width, height, format)) {
             break;
         }
 #endif
@@ -1424,7 +1425,7 @@ void DisplayChannel::create_primary_surface(int width, int height, uint32_t form
     clear_area();
 
     AutoRef<CreatePrimarySurfaceEvent> event(new CreatePrimarySurfaceEvent(*this, width, height,
-                                                                           depth));
+                                                                           format));
     get_client().push_event(*event);
     (*event)->wait();
     if (!(*event)->success()) {
@@ -1433,7 +1434,7 @@ void DisplayChannel::create_primary_surface(int width, int height, uint32_t form
 
     _x_res = width;
     _y_res = height;
-    _depth = depth;
+    _format = format;
 
     canvas = surfaces_mngr.get_canvas(0);
 
@@ -1446,12 +1447,12 @@ void DisplayChannel::create_primary_surface(int width, int height, uint32_t form
 #endif
 }
 
-void DisplayChannel::create_surface(int surface_id, int width, int height, int depth)
+void DisplayChannel::create_surface(int surface_id, int width, int height, uint32_t format)
 {
    Canvas *canvas;
 
     AutoRef<CreateSurfaceEvent> event(new CreateSurfaceEvent(*this, surface_id, width, height,
-                                                             depth));
+                                                             format));
     get_client().push_event(*event);
     (*event)->wait();
     if (!(*event)->success()) {
@@ -1508,10 +1509,11 @@ void DisplayChannel::handle_surface_create(RedPeer::InMessage* message)
 {
     SpiceMsgSurfaceCreate* surface_create = (SpiceMsgSurfaceCreate*)message->data();
     if (surface_create->flags == SPICE_SURFACE_FLAGS_PRIMARY) {
-        create_primary_surface(surface_create->width, surface_create->height, surface_create->depth);
+        create_primary_surface(surface_create->width, surface_create->height,
+                               surface_create->format);
     } else {
         create_surface(surface_create->surface_id, surface_create->width, surface_create->height,
-                       surface_create->depth);
+                       surface_create->format);
     }
 }
 
diff --git a/client/display_channel.h b/client/display_channel.h
index a5761b3..e864bfc 100644
--- a/client/display_channel.h
+++ b/client/display_channel.h
@@ -143,12 +143,12 @@ private:
 #endif
     void destroy_canvas(int surface_id);
     void create_canvas(int surface_id, const std::vector<int>& canvas_type, int width, int height,
-                       int depth);
+                       uint32_t format);
     void destroy_strams();
     void update_cursor();
 
-    void create_primary_surface(int width, int height, int depth);
-    void create_surface(int surface_id, int width, int height, int depth);
+    void create_primary_surface(int width, int height, uint32_t format);
+    void create_surface(int surface_id, int width, int height, uint32_t format);
     void destroy_primary_surface();
     void destroy_surface(int surface_id);
 
@@ -199,7 +199,7 @@ private:
     bool _mark;
     int _x_res;
     int _y_res;
-    int _depth;
+    uint32_t _format;
 #ifdef USE_OGL
     RenderType _rendertype;
 #endif
diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c
index fde43d7..931fd36 100644
--- a/common/cairo_canvas.c
+++ b/common/cairo_canvas.c
@@ -51,7 +51,7 @@ static pixman_image_t *canvas_get_pixman_brush(CairoCanvas *canvas,
 
         return pixman_image_create_solid_fill(&c);
     }
-    case SPICE_BRUSH_TYPE_PATTERN: { 
+    case SPICE_BRUSH_TYPE_PATTERN: {
         CairoCanvas *surface_canvas;
         pixman_image_t* surface;
         pixman_transform_t t;
@@ -61,7 +61,7 @@ static pixman_image_t *canvas_get_pixman_brush(CairoCanvas *canvas,
             surface = surface_canvas->image;
             surface = pixman_image_ref(surface);
         } else {
-            surface = canvas_get_image(&canvas->base, brush->u.pattern.pat);
+            surface = canvas_get_image(&canvas->base, brush->u.pattern.pat, FALSE);
         }
         pixman_transform_init_translate(&t,
                                         pixman_int_to_fixed(-brush->u.pattern.pos.x),
@@ -156,33 +156,6 @@ static void copy_region(SpiceCanvas *spice_canvas,
     }
 }
 
-static inline uint8_t get_converted_color(uint8_t color)
-{
-    uint8_t msb;
-
-    msb = color & 0xE0;
-    msb = msb >> 5;
-    color |= msb;
-    return color;
-}
-
-static inline uint32_t get_color(CairoCanvas *canvas, uint32_t color)
-{
-    int shift = canvas->base.color_shift == 8 ? 0 : 3;
-    uint32_t ret;
-
-    if (!shift) {
-        return color;
-    }
-
-    ret = ((color & 0x001f) << 3) | ((color & 0x001c) >> 2);
-    ret |= ((color & 0x03e0) << 6) | ((color & 0x0380) << 1);
-    ret |= ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
-
-    return ret;
-}
-
-
 static void fill_solid_spans(SpiceCanvas *spice_canvas,
                              SpicePoint *points,
                              int *widths,
@@ -197,7 +170,7 @@ static void fill_solid_spans(SpiceCanvas *spice_canvas,
                                points[i].x, points[i].y,
                                widths[i],
                                1,
-                               get_color(canvas, color));
+                               color);
     }
 }
 
@@ -214,7 +187,7 @@ static void fill_solid_rects(SpiceCanvas *spice_canvas,
                                rects[i].x1, rects[i].y1,
                                rects[i].x2 - rects[i].x1,
                                rects[i].y2 - rects[i].y1,
-                               get_color(canvas, color));
+                               color);
     }
 }
 
@@ -232,7 +205,7 @@ static void fill_solid_rects_rop(SpiceCanvas *spice_canvas,
                                    rects[i].x1, rects[i].y1,
                                    rects[i].x2 - rects[i].x1,
                                    rects[i].y2 - rects[i].y1,
-                                   get_color(canvas, color), rop);
+                                   color, rop);
     }
 }
 
@@ -504,7 +477,7 @@ static void __scale_image_rop(SpiceCanvas *spice_canvas,
     sx = (double)(src_width) / (dest_width);
     sy = (double)(src_height) / (dest_height);
 
-    scaled = pixman_image_create_bits(PIXMAN_x8r8g8b8,
+    scaled = pixman_image_create_bits(spice_pixman_image_get_format(src),
                                       dest_width,
                                       dest_height,
                                       NULL, 0);
@@ -802,7 +775,7 @@ static void __colorkey_scale_image(SpiceCanvas *spice_canvas,
     sx = (double)(src_width) / (dest_width);
     sy = (double)(src_height) / (dest_height);
 
-    scaled = pixman_image_create_bits(PIXMAN_x8r8g8b8,
+    scaled = pixman_image_create_bits(spice_pixman_image_get_format (src),
                                       dest_width,
                                       dest_height,
                                       NULL, 0);
@@ -1026,16 +999,20 @@ static void canvas_read_bits(SpiceCanvas *spice_canvas, uint8_t *dest, int dest_
     uint8_t *src;
     int src_stride;
     uint8_t *dest_end;
+    int bpp;
 
     ASSERT(canvas && area);
 
     surface = canvas->image;
+
+    bpp = spice_pixman_image_get_bpp(surface) / 8;
+
     src_stride = pixman_image_get_stride(surface);
     src = (uint8_t *)pixman_image_get_data(surface) +
-        area->top * src_stride + area->left * sizeof(uint32_t);
+        area->top * src_stride + area->left * bpp;
     dest_end = dest + (area->bottom - area->top) * dest_stride;
     for (; dest != dest_end; dest += dest_stride, src += src_stride) {
-        memcpy(dest, src, dest_stride);
+        memcpy(dest, src, (area->right - area->left) * bpp);
     }
 }
 
@@ -1095,6 +1072,9 @@ static SpiceCanvas *canvas_create_common(pixman_image_t *image,
     if (need_init) {
         return NULL;
     }
+    spice_pixman_image_set_format(image,
+                                  spice_surface_format_to_pixman (format));
+
     canvas = spice_new0(CairoCanvas, 1);
     init_ok = canvas_base_init(&canvas->base, &cairo_canvas_ops,
                                pixman_image_get_width (image),
diff --git a/common/canvas_base.c b/common/canvas_base.c
index fb101fd..799722c 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -109,6 +109,21 @@ static inline double fix_to_double(SPICE_FIXED28_4 fixed)
     return (double)(fixed & 0x0f) / 0x0f + (fixed >> 4);
 }
 
+static inline uint16_t rgb_32_to_16_555(uint32_t color)
+{
+    return
+        (((color) >> 3) & 0x001f) |
+        (((color) >> 6) & 0x03e0) |
+        (((color) >> 9) & 0x7c00);
+}
+static inline uint16_t rgb_32_to_16_565(uint32_t color)
+{
+    return
+        (((color) >> 3) & 0x001f) |
+        (((color) >> 5) & 0x07e0) |
+        (((color) >> 8) & 0xf800);
+}
+
 static inline uint32_t canvas_16bpp_to_32bpp(uint32_t color)
 {
     uint32_t ret;
@@ -119,17 +134,6 @@ static inline uint32_t canvas_16bpp_to_32bpp(uint32_t color)
 
     return ret;
 }
-
-static inline int test_bit(void* addr, int bit)
-{
-    return !!(((uint32_t*)addr)[bit >> 5] & (1 << (bit & 0x1f)));
-}
-
-static inline int test_bit_be(void* addr, int bit)
-{
-    return !!(((uint8_t*)addr)[bit >> 3] & (0x80 >> (bit & 0x07)));
-}
-
 #ifdef WIN32
 static HDC create_compatible_dc()
 {
@@ -396,31 +400,43 @@ static SpiceROP ropd_descriptor_to_rop(int desc,
     return SPICE_ROP_COPY;
 }
 
-static inline void canvas_localize_palette(CanvasBase *canvas, SpicePalette *palette)
+//#define DEBUG_DUMP_COMPRESS
+#ifdef DEBUG_DUMP_COMPRESS
+static void dump_surface(pixman_image_t *surface, int cache);
+#endif
+
+
+static pixman_format_code_t canvas_get_target_format(CanvasBase *canvas,
+                                                     int source_has_alpha)
 {
-    if (canvas->color_shift == 5) {
-        uint32_t *now = palette->ents;
-        uint32_t *end = now + palette->num_ents;
-        for (; now < end; now++) {
-            *now = canvas_16bpp_to_32bpp(*now);
+    pixman_format_code_t format;
+
+    /* Convert to target surface format */
+    format = spice_surface_format_to_pixman (canvas->format);
+
+    if (!source_has_alpha) {
+        /* If the source doesn't have alpha, but the destination has,
+           don't convert to alpha, since that would fill the alpha bytes
+           with 0xff which is not expected if we just use the raw bits */
+        if (format == PIXMAN_a8r8g8b8) {
+            format = PIXMAN_x8r8g8b8;
         }
     }
+
+    return format;
 }
 
-//#define DEBUG_DUMP_COMPRESS
-#ifdef DEBUG_DUMP_COMPRESS
-static void dump_surface(pixman_image_t *surface, int cache);
-#endif
-static pixman_image_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image, int invers)
+static pixman_image_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image,
+                                       int invers, int want_original)
 {
     pixman_image_t *surface = NULL;
     QuicData *quic_data = &canvas->quic_data;
-    QuicImageType type;
+    QuicImageType type, as_type;
+    pixman_format_code_t pixman_format;
     uint8_t *dest;
     int stride;
     int width;
     int height;
-    int alpha;
 #ifndef CAIRO_CANVAS_NO_CHUNKS
     DataChunk **tmp;
     DataChunk *chunk;
@@ -446,14 +462,26 @@ static pixman_image_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image
     }
 #endif
 
-    switch (type) {
+   switch (type) {
     case QUIC_IMAGE_TYPE_RGBA:
-        alpha = 1;
+        as_type = QUIC_IMAGE_TYPE_RGBA;
+        pixman_format = PIXMAN_a8r8g8b8;
         break;
     case QUIC_IMAGE_TYPE_RGB32:
     case QUIC_IMAGE_TYPE_RGB24:
+        as_type = QUIC_IMAGE_TYPE_RGB32;
+        pixman_format = PIXMAN_x8r8g8b8;
+        break;
     case QUIC_IMAGE_TYPE_RGB16:
-        alpha = 0;
+        if (!want_original &&
+            (canvas->format == SPICE_SURFACE_FMT_32_xRGB ||
+             canvas->format == SPICE_SURFACE_FMT_32_ARGB)) {
+            as_type = QUIC_IMAGE_TYPE_RGB32;
+            pixman_format = PIXMAN_x8r8g8b8;
+        } else {
+            as_type = QUIC_IMAGE_TYPE_RGB16;
+            pixman_format = PIXMAN_x1r5g5b5;
+        }
         break;
     case QUIC_IMAGE_TYPE_INVALID:
     case QUIC_IMAGE_TYPE_GRAY:
@@ -468,7 +496,7 @@ static pixman_image_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image
 #ifdef WIN32
                              canvas->dc,
 #endif
-                             alpha ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
+                             pixman_format,
                              width, height, FALSE);
 
     if (surface == NULL) {
@@ -477,7 +505,7 @@ static pixman_image_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image
 
     dest = (uint8_t *)pixman_image_get_data(surface);
     stride = pixman_image_get_stride(surface);
-    if (quic_decode(quic_data->quic, alpha ? QUIC_IMAGE_TYPE_RGBA : QUIC_IMAGE_TYPE_RGB32,
+    if (quic_decode(quic_data->quic, as_type,
                     dest, stride) == QUIC_ERROR) {
         pixman_image_unref(surface);
         CANVAS_ERROR("quic decode failed");
@@ -492,7 +520,7 @@ static pixman_image_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image
             pix = (uint32_t *)dest;
             end_pix = pix + width;
             for (; pix < end_pix; pix++) {
-                *pix ^= 0x00ffffff;
+                *pix ^= 0xffffffff;
             }
         }
     }
@@ -503,170 +531,45 @@ static pixman_image_t *canvas_get_quic(CanvasBase *canvas, SpiceQUICImage *image
     return surface;
 }
 
-static inline void canvas_copy_32bpp(uint8_t* dest, int dest_stride, uint8_t* src, int src_stride,
-                                     int width, uint8_t* end)
-{
-    for (; src != end; src += src_stride, dest += dest_stride) {
-        memcpy(dest, src, width << 2);
-    }
-}
-
-static inline void canvas_copy_24bpp(uint8_t* dest, int dest_stride, uint8_t* src, int src_stride,
-                                     int width, uint8_t* end)
-{
-    for (; src != end; src += src_stride, dest += dest_stride) {
-        uint8_t* src_line = src;
-        uint8_t* src_line_end = src_line + width * 3;
-        uint8_t* dest_line = dest;
-
-        for (; src_line < src_line_end; ++dest_line) {
-            *(dest_line++) = *(src_line++);
-            *(dest_line++) = *(src_line++);
-            *(dest_line++) = *(src_line++);
-        }
-    }
-}
-
-static inline void canvas_copy_16bpp(uint8_t* dest, int dest_stride, uint8_t* src, int src_stride,
-                                     int width, uint8_t* end)
-{
-    for (; src != end; src += src_stride, dest += dest_stride) {
-        uint16_t* src_line = (uint16_t*)src;
-        uint16_t* src_line_end = src_line + width;
-        uint32_t* dest_line = (uint32_t*)dest;
-
-        for (; src_line < src_line_end; ++dest_line, src_line++) {
-            *dest_line = canvas_16bpp_to_32bpp(*src_line);
-        }
-    }
-}
-
-static inline void canvas_copy_8bpp(uint8_t *dest, int dest_stride, uint8_t *src, int src_stride,
-                                    int width, uint8_t *end, SpicePalette *palette)
-{
-    if (!palette) {
-        CANVAS_ERROR("no palette");
-    }
-
-    for (; src != end; src += src_stride, dest += dest_stride) {
-        uint32_t *dest_line = (uint32_t*)dest;
-        uint8_t *src_line = src;
-        uint8_t *src_line_end = src_line + width;
-
-        while (src_line < src_line_end) {
-            ASSERT(*src_line < palette->num_ents);
-            *(dest_line++) = palette->ents[*(src_line++)];
-        }
-    }
-}
-
-static inline void canvas_copy_4bpp_be(uint8_t* dest, int dest_stride, uint8_t* src, int src_stride,
-                                       int width, uint8_t* end, SpicePalette *palette)
-{
-    if (!palette) {
-        CANVAS_ERROR("no palette");
-    }
-
-    for (; src != end; src += src_stride, dest += dest_stride) {
-        uint32_t *dest_line = (uint32_t *)dest;
-        uint8_t *now = src;
-        int i;
-
-        for (i = 0; i < (width >> 1); i++) {
-            ASSERT((*now & 0x0f) < palette->num_ents);
-            ASSERT(((*now >> 4) & 0x0f) < palette->num_ents);
-            *(dest_line++) = palette->ents[(*now >> 4) & 0x0f];
-            *(dest_line++) = palette->ents[*(now++) & 0x0f];
-        }
-        if (width & 1) {
-            *(dest_line) = palette->ents[(*src >> 4) & 0x0f];
-        }
-    }
-}
-
-static inline void canvas_copy_1bpp_be(uint8_t* dest, int dest_stride, uint8_t* src, int src_stride,
-                                       int width, uint8_t* end, SpicePalette *palette)
-{
-    uint32_t fore_color;
-    uint32_t back_color;
-
-    if (!palette) {
-        CANVAS_ERROR("no palette");
-    }
-
-    fore_color = palette->ents[1];
-    back_color = palette->ents[0];
-
-    for (; src != end; src += src_stride, dest += dest_stride) {
-        uint32_t* dest_line = (uint32_t*)dest;
-        int i;
-
-        for (i = 0; i < width; i++) {
-            if (test_bit_be(src, i)) {
-                *(dest_line++) = fore_color;
-            } else {
-                *(dest_line++) = back_color;
-            }
-        }
-    }
-}
-
 static pixman_image_t *canvas_bitmap_to_surface(CanvasBase *canvas, SpiceBitmap* bitmap,
-                                                SpicePalette *palette)
+                                                SpicePalette *palette, int want_original)
 {
-    uint8_t* src = (uint8_t *)SPICE_GET_ADDRESS(bitmap->data);
+    uint8_t* src;
     int src_stride;
-    uint8_t* end;
-    uint8_t* dest;
-    int dest_stride;
-    pixman_image_t* image;
+    pixman_image_t *image;
+    pixman_format_code_t format;
 
+    src = (uint8_t *)SPICE_GET_ADDRESS(bitmap->data);
     src_stride = bitmap->stride;
-    end = src + (bitmap->y * src_stride);
     access_test(canvas, src, bitmap->y * src_stride);
 
+    if (want_original) {
+        format = spice_bitmap_format_to_pixman(bitmap->format, canvas->format);
+    } else {
+        format = canvas_get_target_format(canvas,
+                                          bitmap->format == SPICE_BITMAP_FMT_RGBA);
+    }
+
     image = surface_create(
 #ifdef WIN32
-                                   canvas->dc,
+                           canvas->dc,
 #endif
-                                   (bitmap->format == SPICE_BITMAP_FMT_RGBA) ? PIXMAN_a8r8g8b8 :
-                                                                         PIXMAN_x8r8g8b8,
-                                   bitmap->x, bitmap->y, FALSE);
+                           format,
+                           bitmap->x, bitmap->y, FALSE);
     if (image == NULL) {
         CANVAS_ERROR("create surface failed");
     }
-    dest = (uint8_t *)pixman_image_get_data(image);
-    dest_stride = pixman_image_get_stride(image);
-    if (!(bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
-        ASSERT(bitmap->y > 0);
-        dest += dest_stride * ((int)bitmap->y - 1);
-        dest_stride = -dest_stride;
-    }
 
-    switch (bitmap->format) {
-    case SPICE_BITMAP_FMT_32BIT:
-    case SPICE_BITMAP_FMT_RGBA:
-        canvas_copy_32bpp(dest, dest_stride, src, src_stride, bitmap->x, end);
-        break;
-    case SPICE_BITMAP_FMT_24BIT:
-        canvas_copy_24bpp(dest, dest_stride, src, src_stride, bitmap->x, end);
-        break;
-    case SPICE_BITMAP_FMT_16BIT:
-        canvas_copy_16bpp(dest, dest_stride, src, src_stride, bitmap->x, end);
-        break;
-    case SPICE_BITMAP_FMT_8BIT:
-        canvas_copy_8bpp(dest, dest_stride, src, src_stride, bitmap->x, end, palette);
-        break;
-    case SPICE_BITMAP_FMT_4BIT_BE:
-        canvas_copy_4bpp_be(dest, dest_stride, src, src_stride, bitmap->x, end, palette);
-        break;
-    case SPICE_BITMAP_FMT_1BIT_BE:
-        canvas_copy_1bpp_be(dest, dest_stride, src, src_stride, bitmap->x, end, palette);
-        break;
-    }
+    spice_bitmap_convert_to_pixman(format, image,
+                                   bitmap->format,
+                                   bitmap->flags,
+                                   bitmap->x, bitmap->y,
+                                   src, bitmap->stride,
+                                   canvas->format, palette);
     return image;
 }
 
+
 #ifdef CAIRO_CANVAS_CACHE
 
 static inline SpicePalette *canvas_get_palett(CanvasBase *canvas, SPICE_ADDRESS base_palette, uint8_t flags)
@@ -682,25 +585,24 @@ static inline SpicePalette *canvas_get_palett(CanvasBase *canvas, SPICE_ADDRESS
         palette = (SpicePalette *)SPICE_GET_ADDRESS(base_palette);
         access_test(canvas, palette, sizeof(SpicePalette));
         access_test(canvas, palette, sizeof(SpicePalette) + palette->num_ents * sizeof(uint32_t));
-        canvas_localize_palette(canvas, palette);
         canvas->palette_cache->ops->put(canvas->palette_cache, palette);
     } else {
         palette = (SpicePalette *)SPICE_GET_ADDRESS(base_palette);
-        canvas_localize_palette(canvas, palette);
     }
     return palette;
 }
 
-static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int invers)
+static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int invers,
+                                     int want_original)
 {
     LzData *lz_data = &canvas->lz_data;
     uint8_t *comp_buf = NULL;
     int comp_size;
     uint8_t    *decomp_buf = NULL;
     uint8_t    *src;
-    LzImageType type;
+    pixman_format_code_t pixman_format;
+    LzImageType type, as_type;
     SpicePalette *palette;
-    int alpha;
     int n_comp_pixels;
     int width;
     int height;
@@ -731,17 +633,29 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int inv
 
     switch (type) {
     case LZ_IMAGE_TYPE_RGBA:
-        alpha = 1;
+        as_type = LZ_IMAGE_TYPE_RGBA;
+        pixman_format = PIXMAN_a8r8g8b8;
         break;
     case LZ_IMAGE_TYPE_RGB32:
     case LZ_IMAGE_TYPE_RGB24:
-    case LZ_IMAGE_TYPE_RGB16:
     case LZ_IMAGE_TYPE_PLT1_LE:
     case LZ_IMAGE_TYPE_PLT1_BE:
     case LZ_IMAGE_TYPE_PLT4_LE:
     case LZ_IMAGE_TYPE_PLT4_BE:
     case LZ_IMAGE_TYPE_PLT8:
-        alpha = 0;
+        as_type = LZ_IMAGE_TYPE_RGB32;
+        pixman_format = PIXMAN_x8r8g8b8;
+        break;
+    case LZ_IMAGE_TYPE_RGB16:
+        if (!want_original &&
+            (canvas->format == SPICE_SURFACE_FMT_32_xRGB ||
+             canvas->format == SPICE_SURFACE_FMT_32_ARGB)) {
+            as_type = LZ_IMAGE_TYPE_RGB32;
+            pixman_format = PIXMAN_x8r8g8b8;
+        } else {
+            as_type = LZ_IMAGE_TYPE_RGB16;
+            pixman_format = PIXMAN_x1r5g5b5;
+        }
         break;
     default:
         CANVAS_ERROR("unexpected LZ image type");
@@ -756,7 +670,7 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int inv
 #endif
 
 
-    alloc_lz_image_surface(&lz_data->decode_data, alpha ? LZ_IMAGE_TYPE_RGBA : LZ_IMAGE_TYPE_RGB32,
+    alloc_lz_image_surface(&lz_data->decode_data, pixman_format,
                            width, height, n_comp_pixels, top_down);
 
     src = (uint8_t *)pixman_image_get_data(lz_data->decode_data.out_surface);
@@ -769,7 +683,7 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int inv
         decomp_buf = src;
     }
 
-    lz_decode(lz_data->lz, alpha ? LZ_IMAGE_TYPE_RGBA : LZ_IMAGE_TYPE_RGB32, decomp_buf);
+    lz_decode(lz_data->lz, as_type, decomp_buf);
 
     if (invers) {
         uint8_t *line = src;
@@ -781,7 +695,7 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int inv
             pix = (uint32_t *)line;
             end_pix = pix + width;
             for (; pix < end_pix; pix++) {
-                *pix ^= 0x00ffffff;
+                *pix ^= 0xffffffff;
             }
         }
     }
@@ -791,7 +705,8 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, LZImage *image, int inv
 
 // don't handle plts since bitmaps with plt can be decoded globaly to RGB32 (because
 // same byte sequence can be transformed to different RGB pixels by different plts)
-static pixman_image_t *canvas_get_glz(CanvasBase *canvas, LZImage *image)
+static pixman_image_t *canvas_get_glz(CanvasBase *canvas, LZImage *image,
+                                      int want_original)
 {
     ASSERT(image->descriptor.type == SPICE_IMAGE_TYPE_GLZ_RGB);
 #ifdef WIN32
@@ -849,7 +764,8 @@ static void dump_bitmap(SpiceBitmap *bitmap, SpicePalette *palette)
 
 #endif
 
-static pixman_image_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap)
+static pixman_image_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap,
+                                       int want_original)
 {
     pixman_image_t* surface;
     SpicePalette *palette;
@@ -861,7 +777,7 @@ static pixman_image_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap)
     }
 #endif
 
-    surface = canvas_bitmap_to_surface(canvas, bitmap, palette);
+    surface = canvas_bitmap_to_surface(canvas, bitmap, palette, want_original);
 
     if (palette && (bitmap->flags & SPICE_BITMAP_FLAGS_PAL_FROM_CACHE)) {
         canvas->palette_cache->ops->release(canvas->palette_cache, palette);
@@ -873,27 +789,16 @@ static pixman_image_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap)
 #else
 
 
-static pixman_image_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap)
+static pixman_image_t *canvas_get_bits(CanvasBase *canvas, SpiceBitmap *bitmap,
+                                       int want_original)
 {
     SpicePalette *palette;
 
     if (!bitmap->palette) {
-        return canvas_bitmap_to_surface(canvas, bitmap, NULL);
+        return canvas_bitmap_to_surface(canvas, bitmap, NULL, want_original);
     }
     palette = (SpicePalette *)SPICE_GET_ADDRESS(bitmap->palette);
-    if (canvas->color_shift == 5) {
-        int size = sizeof(SpicePalette) + (palette->num_ents << 2);
-        SpicePalette *local_palette = spice_malloc(size);
-        pixman_image_t* surface;
-
-        memcpy(local_palette, palette, size);
-        canvas_localize_palette(canvas, local_palette);
-        surface = canvas_bitmap_to_surface(canvas, bitmap, local_palette);
-        free(local_palette);
-        return surface;
-    } else {
-        return canvas_bitmap_to_surface(canvas, bitmap, palette);
-    }
+    return canvas_bitmap_to_surface(canvas, bitmap, palette, want_original);
 }
 
 #endif
@@ -984,11 +889,20 @@ static SpiceCanvas *canvas_get_surface_mask_internal(CanvasBase *canvas, SPICE_A
 //#define DEBUG_LZ
 
 /* If real get is FALSE, then only do whatever is needed but don't return an image. For instance,
-   if we need to read it to cache it we do. */
-static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRESS addr, int real_get)
+ *  if we need to read it to cache it we do.
+ *
+ * This generally converts the image to the right type for the canvas.
+ * However, if want_original is set the real source format is returned, and
+ * you have to be able to handle any image format. This is useful to avoid
+ * e.g. losing alpha when blending a argb32 image on a rgb16 surface.
+ */
+static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRESS addr,
+                                                 int want_original, int real_get)
 {
     SpiceImageDescriptor *descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
-    pixman_image_t *surface;
+    pixman_image_t *surface, *converted;
+    pixman_format_code_t wanted_format, surface_format;
+    int saved_want_original;
     access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
 #ifdef DEBUG_LZ
     LOG_DEBUG("canvas_get_image image type: " << (int)descriptor->type);
@@ -1003,24 +917,29 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
         return NULL;
     }
 
+    saved_want_original = want_original;
+    if (descriptor->flags & SPICE_IMAGE_FLAGS_CACHE_ME) {
+        want_original = TRUE;
+    }
+
     switch (descriptor->type) {
     case SPICE_IMAGE_TYPE_QUIC: {
         SpiceQUICImage *image = (SpiceQUICImage *)descriptor;
         access_test(canvas, descriptor, sizeof(SpiceQUICImage));
-        surface = canvas_get_quic(canvas, image, 0);
+        surface = canvas_get_quic(canvas, image, 0, want_original);
         break;
     }
 #ifdef CAIRO_CANVAS_NO_CHUNKS
     case SPICE_IMAGE_TYPE_LZ_PLT: {
         access_test(canvas, descriptor, sizeof(SpiceLZPLTImage));
         LZImage *image = (LZImage *)descriptor;
-        surface = canvas_get_lz(canvas, image, 0);
+        surface = canvas_get_lz(canvas, image, 0, want_original);
         break;
     }
     case SPICE_IMAGE_TYPE_LZ_RGB: {
         access_test(canvas, descriptor, sizeof(SpiceLZRGBImage));
         LZImage *image = (LZImage *)descriptor;
-        surface = canvas_get_lz(canvas, image, 0);
+        surface = canvas_get_lz(canvas, image, 0, want_original);
         break;
     }
 #endif
@@ -1029,24 +948,27 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
     case SPICE_IMAGE_TYPE_GLZ_RGB: {
         access_test(canvas, descriptor, sizeof(SpiceLZRGBImage));
         LZImage *image = (LZImage *)descriptor;
-        surface = canvas_get_glz(canvas, image);
+        surface = canvas_get_glz(canvas, image, want_original);
         break;
     }
 #endif
 
     case SPICE_IMAGE_TYPE_FROM_CACHE:
-        return canvas->bits_cache->ops->get(canvas->bits_cache, descriptor->id);
+        surface = canvas->bits_cache->ops->get(canvas->bits_cache, descriptor->id);
+        break;
+
     case SPICE_IMAGE_TYPE_BITMAP: {
         SpiceBitmapImage *bitmap = (SpiceBitmapImage *)descriptor;
         access_test(canvas, descriptor, sizeof(SpiceBitmapImage));
-        surface = canvas_get_bits(canvas, &bitmap->bitmap);
+        surface = canvas_get_bits(canvas, &bitmap->bitmap, want_original);
         break;
     }
     default:
         CANVAS_ERROR("invalid image type");
     }
 
-    if (descriptor->flags & SPICE_IMAGE_FLAGS_CACHE_ME) {
+    if (descriptor->flags & SPICE_IMAGE_FLAGS_CACHE_ME &&
+        descriptor->type != SPICE_IMAGE_TYPE_FROM_CACHE) {
         canvas->bits_cache->ops->put(canvas->bits_cache, descriptor->id, surface);
 #ifdef DEBUG_DUMP_SURFACE
         dump_surface(surface, 1);
@@ -1062,14 +984,48 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
         return NULL;
     }
 
+    surface_format = spice_pixman_image_get_format(surface);
+
+    if (!saved_want_original) {
+        /* Conversion to canvas format was requested, but maybe it didn't
+           happen above (due to save/load to cache for instance, or
+           maybe the reader didn't support conversion).
+           If so we convert here. */
+
+        wanted_format = canvas_get_target_format(canvas,
+                                                 surface_format == PIXMAN_a8r8g8b8);
+
+        if (surface_format != wanted_format) {
+            converted = surface_create(
+#ifdef WIN32
+                                       canvas->dc,
+#endif
+                                       wanted_format,
+                                       pixman_image_get_width(surface),
+                                       pixman_image_get_height(surface),
+                                       TRUE);
+            pixman_image_composite32 (PIXMAN_OP_SRC,
+                                      surface, NULL, converted,
+                                      0, 0,
+                                      0, 0,
+                                      0, 0,
+                                      pixman_image_get_width(surface),
+                                      pixman_image_get_height(surface));
+            pixman_image_unref (surface);
+            surface = converted;
+        }
+    }
+
     return surface;
 }
 
 #else
 
-static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRESS addr, int real_get)
+static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRESS addr,
+                                                 int want_original, int real_get)
 {
     SpiceImageDescriptor *descriptor = (SpiceImageDescriptor *)SPICE_GET_ADDRESS(addr);
+    pixman_format_code_t format;
 
     access_test(canvas, descriptor, sizeof(SpiceImageDescriptor));
 
@@ -1087,7 +1043,7 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE
     case SPICE_IMAGE_TYPE_BITMAP: {
         SpiceBitmapImage *bitmap = (SpiceBitmapImage *)descriptor;
         access_test(canvas, descriptor, sizeof(SpiceBitmapImage));
-        return canvas_get_bits(canvas, &bitmap->bitmap);
+        return canvas_get_bits(canvas, &bitmap->bitmap, want_original, &format);
     }
     default:
         CANVAS_ERROR("invalid image type");
@@ -1106,26 +1062,29 @@ static SpiceCanvas *canvas_get_surface(CanvasBase *canvas, SPICE_ADDRESS addr)
     return canvas_get_surface_internal(canvas, addr);
 }
 
-static pixman_image_t *canvas_get_image(CanvasBase *canvas, SPICE_ADDRESS addr)
+static pixman_image_t *canvas_get_image(CanvasBase *canvas, SPICE_ADDRESS addr,
+                                        int want_original)
 {
-    return canvas_get_image_internal(canvas, addr, TRUE);
+    return canvas_get_image_internal(canvas, addr, want_original, TRUE);
 }
 
 static void canvas_touch_image(CanvasBase *canvas, SPICE_ADDRESS addr)
 {
-    canvas_get_image_internal(canvas, addr, FALSE);
+    canvas_get_image_internal(canvas, addr, TRUE, FALSE);
 }
 
 static pixman_image_t* canvas_get_image_from_self(SpiceCanvas *canvas,
                                                   int x, int y,
                                                   int32_t width, int32_t height)
 {
+    CanvasBase *canvas_base = (CanvasBase *)canvas;
     pixman_image_t *surface;
     uint8_t *dest;
     int dest_stride;
     SpiceRect area;
 
-    surface = pixman_image_create_bits(PIXMAN_x8r8g8b8, width, height, NULL, 0);
+    surface = pixman_image_create_bits(spice_surface_format_to_pixman (canvas_base->format),
+                                       width, height, NULL, 0);
     if (surface == NULL) {
         CANVAS_ERROR("create surface failed");
     }
@@ -1569,7 +1528,8 @@ static pixman_image_t *canvas_scale_surface(pixman_image_t *src, const SpiceRect
     pixman_transform_t transform;
     double sx, sy;
 
-    surface = pixman_image_create_bits(PIXMAN_x8r8g8b8, width, height, NULL, 0);
+    surface = pixman_image_create_bits(spice_pixman_image_get_format (src),
+                                       width, height, NULL, 0);
     if (surface == NULL) {
         CANVAS_ERROR("create surface failed");
     }
@@ -1933,7 +1893,7 @@ static void draw_brush(SpiceCanvas *canvas,
                                                                rop);
             }
         } else {
-            tile = canvas_get_image(canvas_base, pattern->pat);
+            tile = canvas_get_image(canvas_base, pattern->pat, FALSE);
             if (rop == SPICE_ROP_COPY) {
                 canvas->ops->fill_tiled_rects(canvas, rects, n_rects, tile, offset_x, offset_y);
             } else {
@@ -2067,7 +2027,7 @@ static void canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceCl
             }
         }
     } else {
-        src_image = canvas_get_image(canvas, copy->src_bitmap);
+        src_image = canvas_get_image(canvas, copy->src_bitmap, FALSE);
         if (rect_is_same_size(bbox, &copy->src_area)) {
             if (rop == SPICE_ROP_COPY) {
                 spice_canvas->ops->blit_image(spice_canvas, &dest_region,
@@ -2120,6 +2080,7 @@ static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox,
     SpiceCanvas *surface_canvas;
     pixman_image_t *src_image;
     pixman_region32_t dest_region;
+    uint32_t transparent_color;
 
     pixman_region32_init_rect(&dest_region,
                               bbox->left, bbox->top,
@@ -2134,6 +2095,19 @@ static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox,
         return;
     }
 
+    switch (canvas->format) {
+    case SPICE_SURFACE_FMT_32_xRGB:
+    case SPICE_SURFACE_FMT_32_ARGB:
+        transparent_color = transparent->true_color;
+        break;
+    case SPICE_SURFACE_FMT_16_555:
+        transparent_color = rgb_32_to_16_555(transparent->true_color);
+        break;
+    case SPICE_SURFACE_FMT_16_565:
+        transparent_color = rgb_32_to_16_565(transparent->true_color);
+        break;
+    }
+
     surface_canvas = canvas_get_surface(canvas, transparent->src_bitmap);
     if (surface_canvas) {
         if (rect_is_same_size(bbox, &transparent->src_area)) {
@@ -2141,7 +2115,7 @@ static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox,
                                                            surface_canvas,
                                                            bbox->left - transparent->src_area.left,
                                                            bbox->top - transparent->src_area.top,
-                                                           transparent->true_color);
+                                                           transparent_color);
         } else {
             spice_canvas->ops->colorkey_scale_image_from_surface(spice_canvas, &dest_region,
                                                                  surface_canvas,
@@ -2153,16 +2127,16 @@ static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox,
                                                                  bbox->top,
                                                                  bbox->right - bbox->left,
                                                                  bbox->bottom - bbox->top,
-                                                                 transparent->true_color);
+                                                                 transparent_color);
         }
     } else {
-        src_image = canvas_get_image(canvas, transparent->src_bitmap);
+        src_image = canvas_get_image(canvas, transparent->src_bitmap, FALSE);
         if (rect_is_same_size(bbox, &transparent->src_area)) {
             spice_canvas->ops->colorkey_image(spice_canvas, &dest_region,
                                               src_image,
                                               bbox->left - transparent->src_area.left,
                                               bbox->top - transparent->src_area.top,
-                                              transparent->true_color);
+                                              transparent_color);
         } else {
             spice_canvas->ops->colorkey_scale_image(spice_canvas, &dest_region,
                                                     src_image,
@@ -2174,7 +2148,7 @@ static void canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox,
                                                     bbox->top,
                                                     bbox->right - bbox->left,
                                                     bbox->bottom - bbox->top,
-                                                    transparent->true_color);
+                                                    transparent_color);
         }
         pixman_image_unref(src_image);
     }
@@ -2229,7 +2203,7 @@ static void canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox,
                                                               alpha_blend->alpha);
         }
      } else {
-        src_image = canvas_get_image(canvas, alpha_blend->src_bitmap);
+        src_image = canvas_get_image(canvas, alpha_blend->src_bitmap, TRUE);
         if (rect_is_same_size(bbox, &alpha_blend->src_area)) {
             spice_canvas->ops->blend_image(spice_canvas, &dest_region,
                                            src_image,
@@ -2288,7 +2262,7 @@ static void canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spice
         return;
     }
 
-    src_image = canvas_get_image(canvas, opaque->src_bitmap);
+    src_image = canvas_get_image(canvas, opaque->src_bitmap, FALSE);
 
     if (rect_is_same_size(bbox, &opaque->src_area)) {
         spice_canvas->ops->blit_image(spice_canvas, &dest_region,
@@ -2389,7 +2363,7 @@ static void canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceC
             }
         }
     } else {
-        src_image = canvas_get_image(canvas, blend->src_bitmap);
+        src_image = canvas_get_image(canvas, blend->src_bitmap, FALSE);
         if (rect_is_same_size(bbox, &blend->src_area)) {
             if (rop == SPICE_ROP_COPY)
                 spice_canvas->ops->blit_image(spice_canvas, &dest_region,
@@ -2933,7 +2907,8 @@ static void canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox,
         } else {
             gc.use_surface_canvas = FALSE;
             gc.tile = canvas_get_image(canvas,
-                                       stroke->brush.u.pattern.pat);
+                                       stroke->brush.u.pattern.pat,
+                                       FALSE);
         }
         gc.tile_offset_x = stroke->brush.u.pattern.pos.x;
         gc.tile_offset_y = stroke->brush.u.pattern.pos.y;
@@ -3034,7 +3009,7 @@ static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox,
     if (surface_canvas) {
         s = surface_canvas->ops->get_image(surface_canvas);
     } else {
-        s = canvas_get_image(canvas, rop3->src_bitmap);
+        s = canvas_get_image(canvas, rop3->src_bitmap, FALSE);
     }
 
     if (!rect_is_same_size(bbox, &rop3->src_area)) {
@@ -3060,7 +3035,7 @@ static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox,
         if (_surface_canvas) {
             p = _surface_canvas->ops->get_image(_surface_canvas);
         } else {
-            p = canvas_get_image(canvas, rop3->brush.u.pattern.pat);
+            p = canvas_get_image(canvas, rop3->brush.u.pattern.pat, FALSE);
         }
         SpicePoint pat_pos;
 
@@ -3069,9 +3044,7 @@ static void canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox,
         do_rop3_with_pattern(rop3->rop3, d, s, &src_pos, p, &pat_pos);
         pixman_image_unref(p);
     } else {
-        uint32_t color = (canvas->color_shift) == 8 ? rop3->brush.u.color :
-                                                         canvas_16bpp_to_32bpp(rop3->brush.u.color);
-        do_rop3_with_color(rop3->rop3, d, s, &src_pos, color);
+        do_rop3_with_color(rop3->rop3, d, s, &src_pos, rop3->brush.u.color);
     }
     pixman_image_unref(s);
 
diff --git a/common/canvas_utils.c b/common/canvas_utils.c
index 4f2456d..1f6eca6 100644
--- a/common/canvas_utils.c
+++ b/common/canvas_utils.c
@@ -283,11 +283,11 @@ pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, in
     return __surface_create_stride(format, width, height, stride);
 }
 
-pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data, LzImageType type, int width,
+pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
+                                       pixman_format_code_t pixman_format, int width,
                                        int height, int gross_pixels, int top_down)
 {
     int stride;
-    int alpha;
     pixman_image_t *surface = NULL;
 
     stride = (gross_pixels / height) * 4;
@@ -296,18 +296,11 @@ pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data, LzImageType
         stride = -stride;
     }
 
-    if (type == LZ_IMAGE_TYPE_RGB32) {
-        alpha = 0;
-    } else if (type == LZ_IMAGE_TYPE_RGBA) {
-        alpha = 1;
-    } else {
-        CANVAS_ERROR("unexpected image type");
-    }
-    surface = surface_create_stride(
+   surface = surface_create_stride(
 #ifdef WIN32
             canvas_data->dc,
 #endif
-            alpha ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8, width, height, stride);
+            pixman_format, width, height, stride);
     canvas_data->out_surface = surface;
     return surface;
 }
diff --git a/common/canvas_utils.h b/common/canvas_utils.h
index b81a6f9..b87b816 100644
--- a/common/canvas_utils.h
+++ b/common/canvas_utils.h
@@ -62,6 +62,7 @@ typedef struct LzDecodeUsrData {
 } LzDecodeUsrData;
 
 
-pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data, LzImageType type, int width,
+pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
+                                       pixman_format_code_t pixman_format, int width,
                                        int height, int gross_pixels, int top_down);
 #endif
diff --git a/common/gl_canvas.c b/common/gl_canvas.c
index 9b017fa..63d6977 100644
--- a/common/gl_canvas.c
+++ b/common/gl_canvas.c
@@ -275,7 +275,7 @@ static void set_brush(GLCanvas *canvas, SpiceBrush *brush)
         GLCPattern pattern;
         pixman_image_t *surface;
 
-        surface = canvas_get_image(&canvas->base, brush->u.pattern.pat);
+        surface = canvas_get_image(&canvas->base, brush->u.pattern.pat, FALSE);
         surface_to_image(canvas, surface, &image, 0);
 
         pattern = glc_pattern_create(canvas->glc, -brush->u.pattern.pos.x,
@@ -379,7 +379,7 @@ static void gl_canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spic
     set_op(canvas, copy->rop_decriptor);
 
     //todo: optimize get_imag (use ogl conversion + remove unnecessary copy of 32bpp)
-    surface = canvas_get_image(&canvas->base, copy->src_bitmap);
+    surface = canvas_get_image(&canvas->base, copy->src_bitmap, FALSE);
     surface_to_image(canvas, surface, &image, 0);
     SET_GLC_RECT(&dest, bbox);
     SET_GLC_RECT(&src, &copy->src_area);
@@ -403,7 +403,7 @@ static void gl_canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, Sp
 
     glc_set_op(canvas->glc, (opaque->rop_decriptor & SPICE_ROPD_INVERS_SRC) ? GLC_OP_COPY_INVERTED :
                GLC_OP_COPY);
-    surface = canvas_get_image(&canvas->base, opaque->src_bitmap);
+    surface = canvas_get_image(&canvas->base, opaque->src_bitmap, FALSE);
     surface_to_image(canvas, surface, &image, 0);
     SET_GLC_RECT(&dest, bbox);
     SET_GLC_RECT(&src, &opaque->src_area);
@@ -430,7 +430,7 @@ static void gl_canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbo
     glc_clear_mask(canvas->glc, GLC_MASK_A);
     glc_set_op(canvas->glc, GLC_OP_COPY);
 
-    surface = canvas_get_image(&canvas->base, alpha_blend->src_bitmap);
+    surface = canvas_get_image(&canvas->base, alpha_blend->src_bitmap, FALSE);
     surface_to_image(canvas, surface, &image, 0);
     SET_GLC_RECT(&dest, bbox);
     SET_GLC_RECT(&src, &alpha_blend->src_area);
@@ -452,7 +452,7 @@ static void gl_canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spi
     set_mask(canvas, &blend->mask, bbox->left, bbox->top);
     set_op(canvas, blend->rop_decriptor);
 
-    surface = canvas_get_image(&canvas->base, blend->src_bitmap);
+    surface = canvas_get_image(&canvas->base, blend->src_bitmap, FALSE);
     SET_GLC_RECT(&dest, bbox);
     SET_GLC_RECT(&src, &blend->src_area);
     surface_to_image(canvas, surface, &image, 0);
@@ -475,7 +475,7 @@ static void gl_canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbo
     glc_clear_mask(canvas->glc, GLC_MASK_A);
     glc_set_op(canvas->glc, GLC_OP_COPY);
 
-    surface = canvas_get_image(&canvas->base, transparent->src_bitmap);
+    surface = canvas_get_image(&canvas->base, transparent->src_bitmap, FALSE);
     surface_to_image(canvas, surface, &image, 0);
 
     trans_surf = canvas_surf_to_trans_surf(&image, transparent->true_color);
@@ -554,7 +554,7 @@ static void gl_canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spic
     memcpy(image.pixels, data_opp,
            image.stride * pixman_image_get_height(d));
 
-    s = canvas_get_image(&canvas->base, rop3->src_bitmap);
+    s = canvas_get_image(&canvas->base, rop3->src_bitmap, FALSE);
     src_stride = pixman_image_get_stride(s);
     if (src_stride > 0) {
         data_opp = copy_opposite_image(canvas, (uint8_t *)pixman_image_get_data(s),
@@ -581,7 +581,7 @@ static void gl_canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, Spic
     }
 
     if (rop3->brush.type == SPICE_BRUSH_TYPE_PATTERN) {
-        pixman_image_t *p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat);
+        pixman_image_t *p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat, FALSE);
         SpicePoint pat_pos;
 
         pat_pos.x = (bbox->left - rop3->brush.u.pattern.pos.x) % pixman_image_get_width(p);
diff --git a/server/red_worker.c b/server/red_worker.c
index af3a888..7d6df88 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -872,7 +872,7 @@ typedef struct DrawContext {
     uint32_t width;
     uint32_t height;
     int32_t stride;
-    uint8_t depth;
+    uint32_t format;
     void *line_0;
 } DrawContext;
 
@@ -3573,6 +3573,7 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
     uint8_t *dest;
     int dest_stride;
     RedSurface *surface;
+    int bpp;
 
     if (!drawable->qxl_drawable->self_bitmap) {
         return TRUE;
@@ -3581,9 +3582,11 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
 
     surface = &worker->surfaces[drawable->surface_id];
 
+    bpp = SPICE_SURFACE_FMT_DEPTH(surface->context.format) / 8;
+
     width = drawable->qxl_drawable->bbox.right - drawable->qxl_drawable->bbox.left;
     height = drawable->qxl_drawable->bbox.bottom - drawable->qxl_drawable->bbox.top;
-    dest_stride = width * sizeof(uint32_t);
+    dest_stride = SPICE_ALIGN(width * bpp, 4);
 
     image = spice_malloc_n_m(height, dest_stride, sizeof(QXLImage));
     dest = (uint8_t *)(image + 1);
@@ -3594,7 +3597,19 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
     QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_RED, ++worker->bits_unique);
     image->bitmap.flags = QXL_BITMAP_DIRECT | (surface->context.top_down ?
                                                QXL_BITMAP_TOP_DOWN : 0);
-    image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
+    switch (surface->context.format) {
+    case SPICE_SURFACE_FMT_32_xRGB:
+        image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
+        break;
+    case SPICE_SURFACE_FMT_32_ARGB:
+        image->bitmap.format = SPICE_BITMAP_FMT_RGBA;
+        break;
+    case SPICE_SURFACE_FMT_16_555:
+        image->bitmap.format = SPICE_BITMAP_FMT_16BIT;
+        break;
+    default:
+        ASSERT(0); /* not supported yet */
+    }
     image->bitmap.stride = dest_stride;
     image->descriptor.width = image->bitmap.x = width;
     image->descriptor.height = image->bitmap.y = height;
@@ -3801,7 +3816,8 @@ static inline void red_process_drawable(RedWorker *worker, QXLDrawable *drawable
 }
 
 static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uint32_t width,
-                                      uint32_t height, int32_t stride, uint8_t depth, void *line_0);
+                                      uint32_t height, int32_t stride, uint32_t format,
+                                      void *line_0);
 
 static inline void red_process_surface(RedWorker *worker, QXLSurfaceCmd *surface, uint32_t group_id)
 {
@@ -3820,13 +3836,13 @@ static inline void red_process_surface(RedWorker *worker, QXLSurfaceCmd *surface
         uint32_t height = surface->u.surface_create.height;
         int32_t stride = surface->u.surface_create.stride;
         QXLReleaseInfoExt release_info_ext;
-        
+
         data = (uint8_t *)get_virt(&worker->mem_slots, saved_data, height * abs(stride), group_id);
         if (stride < 0) {
             data -= (int32_t)(stride * (height - 1));
         }
         red_create_surface(worker, surface_id, surface->u.surface_create.width,
-                           height, stride, surface->u.surface_create.depth, data);
+                           height, stride, surface->u.surface_create.format, data);
         release_info_ext.group_id = group_id;
         release_info_ext.info = &surface->release_info;
         worker->qxl->release_resource(worker->qxl, release_info_ext);
@@ -7881,7 +7897,7 @@ static inline void *create_canvas_for_surface(RedWorker *worker, RedSurface *sur
 }
 
 static SurfaceCreateItem *get_surface_create_item(uint32_t surface_id, uint32_t width,
-                                                  uint32_t height, uint8_t depth, uint32_t flags)
+                                                  uint32_t height, uint32_t format, uint32_t flags)
 {
     SurfaceCreateItem *create;
 
@@ -7892,7 +7908,7 @@ static SurfaceCreateItem *get_surface_create_item(uint32_t surface_id, uint32_t
     create->surface_create.width = width;
     create->surface_create.height = height;
     create->surface_create.flags = flags;
-    create->surface_create.depth = depth;
+    create->surface_create.format = format;
 
     red_pipe_item_init(&create->pipe_item, PIPE_ITEM_TYPE_CREATE_SURFACE);
 
@@ -7911,7 +7927,7 @@ static inline void __red_create_surface_item(RedWorker *worker, int surface_id,
     surface = &worker->surfaces[surface_id];
 
     create = get_surface_create_item(surface_id, surface->context.width, surface->context.height,
-                                     surface->context.depth, flags);
+                                     surface->context.format, flags);
 
     worker->display_channel->surface_client_created[surface_id] = TRUE;
 
@@ -7924,26 +7940,24 @@ static inline void red_create_surface_item(RedWorker *worker, int surface_id)
         __red_create_surface_item(worker, surface_id, SPICE_SURFACE_FLAGS_PRIMARY);
     } else {
         __red_create_surface_item(worker, surface_id, 0);
-    } 
+    }
 }
 
 static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, uint32_t width,
-                                      uint32_t height, int32_t stride, uint8_t depth, void *line_0)
+                                      uint32_t height, int32_t stride, uint32_t format,
+                                      void *line_0)
 {
     uint32_t i;
     RedSurface *surface = &worker->surfaces[surface_id];
     if (stride >= 0) {
         PANIC("Untested path stride >= 0");
     }
-    if (depth != 16 && depth != 32) {
-        PANIC("As for now support just 32/16 depth surfaces");
-    }
     PANIC_ON(surface->context.canvas);
 
     surface->context.canvas_draws_on_surface = FALSE;
     surface->context.width = width;
     surface->context.height = height;
-    surface->context.depth = depth;
+    surface->context.format = format;
     surface->context.stride = stride;
     surface->context.line_0 = line_0;
     memset(line_0 + (int32_t)(stride * (height - 1)), 0, height*abs(stride));
@@ -7957,7 +7971,7 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
     if (worker->renderer != RED_RENDERER_INVALID) {
         surface->context.canvas = create_canvas_for_surface(worker, surface, worker->renderer,
                                                             width, height, stride,
-                                                            surface->context.depth, line_0);
+                                                            surface->context.format, line_0);
         if (!surface->context.canvas) {
             PANIC("drawing canvas creating failed - can`t create same type canvas");
         }
@@ -7969,7 +7983,7 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
     for (i = 0; i < worker->num_renderers; i++) {
         surface->context.canvas = create_canvas_for_surface(worker, surface, worker->renderers[i],
                                                             width, height, stride,
-                                                            surface->context.depth, line_0);
+                                                            surface->context.format, line_0);
         if (surface->context.canvas) { //no need canvas check
             worker->renderer = worker->renderers[i];
             red_create_surface_item(worker, surface_id);
@@ -9043,7 +9057,7 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
         line_0 -= (int32_t)(surface.stride * (surface.height -1));
     }
 
-    red_create_surface(worker, 0, surface.width, surface.height, surface.stride, surface.depth,
+    red_create_surface(worker, 0, surface.width, surface.height, surface.stride, surface.format,
                        line_0);
 
     if (worker->display_channel) {
diff --git a/server/vd_interface.h b/server/vd_interface.h
index 25ff007..e91539f 100644
--- a/server/vd_interface.h
+++ b/server/vd_interface.h
@@ -173,7 +173,7 @@ struct QXLDevSurfaceCreate {
     uint32_t width;
     uint32_t height;
     int32_t stride;
-    uint32_t depth;
+    uint32_t format;
     uint32_t position;
     uint32_t mouse_mode;
     uint32_t flags;
commit 774e5bd36f4fc156dd744a455ff7ddda27441568
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Apr 21 13:08:52 2010 +0200

    Client: Support pixmap format conversion in copy_pixels
    
    In order to be able to support 16bit canvases on 32bit screens and 32bit
    canvases on 16bit screens we need to handle format conversion when drawing
    RedPixmaps.
    
    The way this works now for X11 is that we only have one PIXELS_SOURCE_TYPE
    for pixmaps, which always has a pixman_image_t for the data, but additionally
    it has an XImage (shared mem or not) if the screen the pixmap was created
    for (i.e. an explicit one or the default screen) has the same format as
    the pixmap.
    
    When we draw a pixmap on a drawable we have two variants. If the pixmap
    has a XImage and it matches the format of the target drawable then we
    just X(Shm)PutImage it to the drawable. If the formats differ, then we
    create a temporary XImage and convert into that before drawing it to
    the screen.
    
    Right now this is a bit inefficient, because we always allocate a new
    temporary image when converting. We want to add some caching here, but
    at least this lets things work again.

diff --git a/client/cursor_channel.cpp b/client/cursor_channel.cpp
index 289c059..db020a0 100644
--- a/client/cursor_channel.cpp
+++ b/client/cursor_channel.cpp
@@ -112,7 +112,7 @@ void UnsupportedCursor::draw(RedDrawable& dest, int x, int y, const SpiceRect& a
 
 AlphaCursor::AlphaCursor(const SpiceCursorHeader& header, const uint8_t* data)
     : _pixmap (new RedPixmapCairo(header.width, header.height,
-                                  RedPixmap::ARGB32, true, NULL))
+                                  RedDrawable::ARGB32, true, NULL))
 {
     int stride = _pixmap->get_stride();
     uint8_t* dest = _pixmap->get_data();
@@ -131,7 +131,7 @@ MonoCursor::MonoCursor(const SpiceCursorHeader& header, const uint8_t* data)
     : _pixmap (NULL)
     , _height (header.height)
 {
-    _pixmap.reset(new RedPixmapCairo(header.width, _height * 2, RedPixmap::A1,
+    _pixmap.reset(new RedPixmapCairo(header.width, _height * 2, RedDrawable::A1,
                                      true, NULL));
 
     int dest_stride = _pixmap->get_stride();
@@ -176,10 +176,10 @@ private:
 
 ColorCursor::ColorCursor(const SpiceCursorHeader& header)
     : _pixmap (new RedPixmapCairo(header.width, header.height,
-                                  RedPixmap::ARGB32, true, NULL))
+                                  RedDrawable::ARGB32, true, NULL))
     , _invers (NULL)
 {
-    _invers.reset(new RedPixmapCairo(header.width, header.height, RedPixmap::A1,
+    _invers.reset(new RedPixmapCairo(header.width, header.height, RedDrawable::A1,
                                      true, NULL));
 }
 
diff --git a/client/gui/gui.cpp b/client/gui/gui.cpp
index 30b864d..3e0f257 100644
--- a/client/gui/gui.cpp
+++ b/client/gui/gui.cpp
@@ -888,7 +888,7 @@ GUI::GUI(Application& app, Application::State state)
     : ScreenLayer (SCREEN_LAYER_GUI, false)
     , _app (app)
     , _state (state)
-    , _pixmap (new RedPixmapCairo(MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT, RedDrawable::RGB32, true, NULL))
+    , _pixmap (new RedPixmapCairo(MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT, RedDrawable::RGB32, true, 0))
     , _renderer (new CEGUI::SoftRenderer(_pixmap->get_data(), MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT,
                                          _pixmap->get_stride()))
     , _gui_system (new CEGUI::System(_renderer, new CEGUIResourceProvider()))
diff --git a/client/red_cairo_canvas.cpp b/client/red_cairo_canvas.cpp
index 9338d9f..b795acf 100644
--- a/client/red_cairo_canvas.cpp
+++ b/client/red_cairo_canvas.cpp
@@ -34,7 +34,7 @@ CCanvas::CCanvas(bool onscreen,
 {
     if (onscreen) {
         _pixmap = new RedPixmapCairo(width, height,
-                                     RedPixmap::format_from_surface(format),
+                                     RedDrawable::format_from_surface(format),
                                      true, win);
         _canvas = canvas_create_for_data(width, height, format,
                                          _pixmap->get_data(),
diff --git a/client/red_pixmap_cairo.h b/client/red_pixmap_cairo.h
index 7f9523e..7f28532 100644
--- a/client/red_pixmap_cairo.h
+++ b/client/red_pixmap_cairo.h
@@ -23,7 +23,7 @@
 
 class RedPixmapCairo: public RedPixmap {
 public:
-    RedPixmapCairo(int width, int height, Format format, bool top_bottom, RedWindow *win);
+    RedPixmapCairo(int width, int height, Format format, bool top_bottom, RedWindow *window);
     ~RedPixmapCairo();
 };
 
diff --git a/client/screen.cpp b/client/screen.cpp
index a1ce888..c2bd4e7 100644
--- a/client/screen.cpp
+++ b/client/screen.cpp
@@ -172,7 +172,7 @@ void RedScreen::create_composit_area()
 {
     destroy_composit_area();
     _composit_area = new RedPixmapCairo(_size.x, _size.y, _window.get_format(),
-                                        false, -1);
+                                        false, &_window);
 }
 
 void RedScreen::adjust_window_rect(int x, int y)
diff --git a/client/windows/red_pixmap_cairo.cpp b/client/windows/red_pixmap_cairo.cpp
index 35fe89b..aa4e5cb 100644
--- a/client/windows/red_pixmap_cairo.cpp
+++ b/client/windows/red_pixmap_cairo.cpp
@@ -29,7 +29,7 @@ struct RedPixmap_p {
     HBITMAP prev_bitmap;
 };
 
-RedPixmapCairo::RedPixmapCairo(int width, int height, RedPixmap::Format format,
+RedPixmapCairo::RedPixmapCairo(int width, int height, RedDrawable::Format format,
                                bool top_bottom, RedWindow *win)
     : RedPixmap(width, height, format, top_bottom)
 {
diff --git a/client/x11/pixels_source.cpp b/client/x11/pixels_source.cpp
index 0ec39bd..a2d49f3 100644
--- a/client/x11/pixels_source.cpp
+++ b/client/x11/pixels_source.cpp
@@ -24,50 +24,28 @@
 #include "res.h"
 
 
-static void create_image(const PixmapHeader* pixmap, PixelsSource_p& pixels_source,
+static void create_pixmap(const PixmapHeader* pixmap, PixelsSource_p& pixels_source,
                          pixman_format_code_t format)
 {
     pixman_image_t *pixman_image;
-    XImage *image = new XImage;
-
-    memset(image, 0, sizeof(*image));
-    image->width = pixmap->width;
-    image->height = pixmap->height;
-
-    image->data = (char*)pixmap->data;
-    image->byte_order = LSBFirst;
-    image->bitmap_unit = 32;
-    image->bitmap_bit_order = LSBFirst;
-    image->bitmap_pad = 32;
-    image->bytes_per_line = pixmap->stride;
-
-    image->depth = XPlatform::get_vinfo()[0]->depth;
-    image->format = ZPixmap;
-    image->bits_per_pixel = 32;
-    image->red_mask = 0x00ff0000;
-    image->green_mask = 0x0000ff00;
-    image->blue_mask = 0x000000ff;
-
-    try {
-        if (!XInitImage(image)) {
-            THROW("init image failed");
-        }
-
-        pixman_image = pixman_image_create_bits(format,
-                                                pixmap->width, pixmap->height,
-                                                (uint32_t *)pixmap->data,
-                                                pixmap->stride);
-        if (pixman_image == NULL) {
-            THROW("surf create failed");
-        }
-    } catch (...) {
-        delete image;
-        throw;
+
+    pixman_image = pixman_image_create_bits(format,
+					    pixmap->width, pixmap->height,
+					    (uint32_t *)pixmap->data,
+					    pixmap->stride);
+    if (pixman_image == NULL) {
+      THROW("surf create failed");
     }
 
     pixels_source.type = PIXELS_SOURCE_TYPE_PIXMAP;
-    pixels_source.pixmap.x_image = image;
     pixels_source.pixmap.pixman_image = pixman_image;
+    pixels_source.pixmap.x_image = NULL;
+    pixels_source.pixmap.shminfo = NULL;
+    if (format == PIXMAN_a8r8g8b8) {
+        pixels_source.pixmap.format = RedDrawable::ARGB32;
+    } else {
+        pixels_source.pixmap.format = RedDrawable::RGB32;
+    }
 }
 
 PixelsSource::PixelsSource()
@@ -86,21 +64,20 @@ ImageFromRes::ImageFromRes(int res_id)
     if (!pixmap) {
         THROW("no image %d", res_id);
     }
-    create_image(pixmap, *(PixelsSource_p*)get_opaque(), PIXMAN_x8r8g8b8);
+    create_pixmap(pixmap, *(PixelsSource_p*)get_opaque(), PIXMAN_x8r8g8b8);
 }
 
 ImageFromRes::~ImageFromRes()
 {
     pixman_image_unref(((PixelsSource_p*)get_opaque())->pixmap.pixman_image);
-    delete ((PixelsSource_p*)get_opaque())->pixmap.x_image;
 }
 
 SpicePoint ImageFromRes::get_size()
 {
-    XImage *image = ((PixelsSource_p*)get_opaque())->pixmap.x_image;
+    pixman_image_t *image = ((PixelsSource_p*)get_opaque())->pixmap.pixman_image;
     SpicePoint pt;
-    pt.x = image->width;
-    pt.y = image->height;
+    pt.x = pixman_image_get_width(image);
+    pt.y = pixman_image_get_height(image);
     return pt;
 }
 
@@ -110,21 +87,20 @@ AlphaImageFromRes::AlphaImageFromRes(int res_id)
     if (!pixmap) {
         THROW("no image %d", res_id);
     }
-    create_image(pixmap, *(PixelsSource_p*)get_opaque(), PIXMAN_a8r8g8b8);
+    create_pixmap(pixmap, *(PixelsSource_p*)get_opaque(), PIXMAN_a8r8g8b8);
 }
 
 AlphaImageFromRes::~AlphaImageFromRes()
 {
     pixman_image_unref(((PixelsSource_p*)get_opaque())->pixmap.pixman_image);
-    delete ((PixelsSource_p*)get_opaque())->pixmap.x_image;
 }
 
 SpicePoint AlphaImageFromRes::get_size()
 {
-    XImage *image = ((PixelsSource_p*)get_opaque())->pixmap.x_image;
+    pixman_image_t *image = ((PixelsSource_p*)get_opaque())->pixmap.pixman_image;
     SpicePoint pt;
-    pt.x = image->width;
-    pt.y = image->height;
+    pt.x = pixman_image_get_width(image);
+    pt.y = pixman_image_get_height(image);
     return pt;
 }
 
diff --git a/client/x11/pixels_source_p.h b/client/x11/pixels_source_p.h
index 050c19a..a3e4cfb 100644
--- a/client/x11/pixels_source_p.h
+++ b/client/x11/pixels_source_p.h
@@ -28,7 +28,6 @@
 enum {
     PIXELS_SOURCE_TYPE_INVALID,
     PIXELS_SOURCE_TYPE_X_DRAWABLE,
-    PIXELS_SOURCE_TYPE_XSHM_DRAWABLE,
     PIXELS_SOURCE_TYPE_PIXMAP,
     PIXELS_SOURCE_TYPE_GL_TEXTURE,
     PIXELS_SOURCE_TYPE_GL_DRAWABLE,
@@ -39,6 +38,7 @@ struct PixelsSource_p {
     union {
         struct {
             Drawable drawable;
+            int screen;
             GC gc;
             int width, height;
             RenderType rendertype;
@@ -53,11 +53,7 @@ struct PixelsSource_p {
             XImage* x_image;
             XShmSegmentInfo *shminfo;
             pixman_image_t* pixman_image;
-        } x_shm_drawable;
-
-        struct {
-            XImage* x_image;
-            pixman_image_t* pixman_image;
+            RedDrawable::Format format;
         } pixmap;
 
         struct {
diff --git a/client/x11/red_drawable.cpp b/client/x11/red_drawable.cpp
index 94ae523..32754da 100644
--- a/client/x11/red_drawable.cpp
+++ b/client/x11/red_drawable.cpp
@@ -111,11 +111,11 @@ static inline void copy_to_gldrawable_from_pixmap(const RedDrawable_p* dest,
         glDisable(GL_TEXTURE_2D);
     }
 
-    glPixelStorei(GL_UNPACK_ROW_LENGTH, source->pixmap.x_image->bytes_per_line / 4);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, pixman_image_get_stride(source->pixmap.pixman_image) / 4);
 
     glPixelZoom(1, -1);
-    addr = (uint8_t *)source->pixmap.x_image->data;
-    addr += (src_x * 4 + src_y * source->pixmap.x_image->bytes_per_line);
+    addr = (uint8_t *)pixman_image_get_data(source->pixmap.pixman_image);
+    addr += (src_x * 4 + src_y * pixman_image_get_stride(source->pixmap.pixman_image));
     glWindowPos2i(area.left + offset.x, dest->source.x_drawable.height -
                   (area.top + offset.y));  //+ (area.bottom - area.top)));
     glDrawPixels(area.right - area.left, area.bottom - area.top,
@@ -149,37 +149,106 @@ static inline void copy_to_drawable_from_drawable(const RedDrawable_p* dest,
               area.left + offset.x, area.top + offset.y);
 }
 
+static XImage *create_temp_image(int screen, int width, int height,
+                                 pixman_image_t **pixman_image_out,
+                                 XShmSegmentInfo **shminfo_out)
+{
+    XImage *image;
+    XShmSegmentInfo *shminfo;
+    RedDrawable::Format format;
+    pixman_image_t *pixman_image;
+    XVisualInfo *vinfo;
+
+    image = NULL;
+    shminfo = NULL;
+
+    vinfo = XPlatform::get_vinfo()[screen];
+    format = XPlatform::get_screen_format(screen);
+
+    image = XPlatform::create_x_image(format, width, height, vinfo->depth,
+					  vinfo->visual, &shminfo);
+
+    pixman_image = pixman_image_create_bits(RedDrawable::format_to_pixman(format),
+                                            width, height,
+                                            (uint32_t *)image->data, image->bytes_per_line);
+    if (pixman_image == NULL) {
+        THROW("surf create failed");
+    }
+    *pixman_image_out = pixman_image;
+    *shminfo_out = shminfo;
+    return image;
+}
+
+static void free_temp_image(XImage *image, XShmSegmentInfo *shminfo, pixman_image_t *pixman_image)
+{
+    XPlatform::free_x_image(image, shminfo);
+    pixman_image_unref(pixman_image);
+}
+
+
 static inline void copy_to_drawable_from_pixmap(const RedDrawable_p* dest,
                                                 const SpiceRect& area,
                                                 const SpicePoint& offset,
                                                 const PixelsSource_p* source,
                                                 int src_x, int src_y)
 {
+    pixman_image_t *src_surface = source->pixmap.pixman_image;
     XGCValues gc_vals;
     gc_vals.function = GXcopy;
+    RedDrawable::Format screen_format;
+    XImage *image;
+    XShmSegmentInfo *shminfo;
+    pixman_image_t *pixman_image;
+    int screen;
+
+    screen = dest->source.x_drawable.screen;
+    screen_format = XPlatform::get_screen_format(screen);
 
     XChangeGC(XPlatform::get_display(), dest->source.x_drawable.gc, GCFunction, &gc_vals);
-    XPutImage(XPlatform::get_display(), dest->source.x_drawable.drawable,
-              dest->source.x_drawable.gc, source->pixmap.x_image, src_x,
-              src_y, area.left + offset.x, area.top + offset.y,
-              area.right - area.left, area.bottom - area.top);
-}
 
-static inline void copy_to_drawable_from_shmdrawable(const RedDrawable_p* dest,
-                                                     const SpiceRect& area,
-                                                     const SpicePoint& offset,
-                                                     const PixelsSource_p* source,
-                                                     int src_x, int src_y)
-{
-    XGCValues gc_vals;
-    gc_vals.function = GXcopy;
+    if (source->pixmap.x_image != NULL &&
+        RedDrawable::format_copy_compatible(source->pixmap.format, screen_format)) {
+        if (source->pixmap.shminfo) {
+            XShmPutImage(XPlatform::get_display(), dest->source.x_drawable.drawable,
+                         dest->source.x_drawable.gc, source->pixmap.x_image,
+                         src_x, src_y, area.left + offset.x, area.top + offset.y,
+                         area.right - area.left, area.bottom - area.top, false);
+            XSync(XPlatform::get_display(), 0);
+        } else {
+            XPutImage(XPlatform::get_display(), dest->source.x_drawable.drawable,
+                      dest->source.x_drawable.gc, source->pixmap.x_image, src_x,
+                      src_y, area.left + offset.x, area.top + offset.y,
+                      area.right - area.left, area.bottom - area.top);
+        }
+    } else {
+        image = create_temp_image(screen,
+                                  area.right - area.left, area.bottom - area.top,
+                                  &pixman_image, &shminfo);
 
-    XChangeGC(XPlatform::get_display(), dest->source.x_drawable.gc, GCFunction, &gc_vals);
-    XShmPutImage(XPlatform::get_display(), dest->source.x_drawable.drawable,
-                 dest->source.x_drawable.gc, source->x_shm_drawable.x_image,
-                 src_x, src_y, area.left + offset.x, area.top + offset.y,
-                 area.right - area.left, area.bottom - area.top, false);
-    XSync(XPlatform::get_display(), 0);
+        pixman_image_composite32(PIXMAN_OP_SRC,
+                                 src_surface, NULL, pixman_image,
+                                 src_x + offset.x,
+                                 src_y + offset.y,
+                                 0, 0,
+                                 0, 0,
+                                 area.right - area.left,
+                                 area.bottom - area.top);
+
+        if (shminfo) {
+            XShmPutImage(XPlatform::get_display(), dest->source.x_drawable.drawable,
+                         dest->source.x_drawable.gc, image,
+                         0, 0, area.left + offset.x, area.top + offset.y,
+                         area.right - area.left, area.bottom - area.top, false);
+            XSync(XPlatform::get_display(), 0);
+        } else {
+            XPutImage(XPlatform::get_display(), dest->source.x_drawable.drawable,
+                      dest->source.x_drawable.gc, image,
+                      0, 0, area.left + offset.x, area.top + offset.y,
+                      area.right - area.left, area.bottom - area.top);
+        }
+
+        free_temp_image(image, shminfo, pixman_image);
+    }
 }
 
 static inline void copy_to_x_drawable(const RedDrawable_p* dest,
@@ -195,9 +264,6 @@ static inline void copy_to_x_drawable(const RedDrawable_p* dest,
     case PIXELS_SOURCE_TYPE_PIXMAP:
         copy_to_drawable_from_pixmap(dest, area, offset, source, src_x, src_y);
         break;
-    case PIXELS_SOURCE_TYPE_XSHM_DRAWABLE:
-        copy_to_drawable_from_shmdrawable(dest, area, offset, source, src_x, src_y);
-        break;
     default:
         THROW("invalid source type %d", source->type);
     }
@@ -230,26 +296,6 @@ static inline void copy_to_pixmap_from_drawable(const RedDrawable_p* dest,
     LOG_WARN("not implemented");
 }
 
-static inline void copy_to_pixmap_from_shmdrawable(const RedDrawable_p* dest,
-                                                   const SpiceRect& area,
-                                                   const SpicePoint& offset,
-                                                   const PixelsSource_p* source,
-                                                   int src_x, int src_y)
-{
-    pixman_image_t *dest_surface =  dest->source.pixmap.pixman_image;
-    pixman_image_t *src_surface = source->x_shm_drawable.pixman_image;
-
-    pixman_image_composite32(PIXMAN_OP_SRC,
-                             src_surface, NULL, dest_surface,
-                             src_x + offset.x,
-                             src_y + offset.y,
-                             0, 0,
-                             area.left + offset.x,
-                             area.top + offset.y,
-                             area.right - area.left,
-                             area.bottom - area.top);
-}
-
 static inline void copy_to_pixmap_from_pixmap(const RedDrawable_p* dest,
                                               const SpiceRect& area,
                                               const SpicePoint& offset,
@@ -297,15 +343,15 @@ static inline void copy_to_pixmap_from_gltexture(const RedDrawable_p* dest,
     }
     glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
     glPixelStorei(GL_PACK_ROW_LENGTH,
-                  dest->source.pixmap.x_image->bytes_per_line / 4);
+                  pixman_image_get_stride(dest->source.pixmap.pixman_image) / 4);
 
     while (height > 0) {
         glReadPixels(src_x, y - height, area.right - area.left, 1,
                      GL_BGRA, GL_UNSIGNED_BYTE,
-                     dest->source.pixmap.x_image->data +
+                     (uint8_t *)pixman_image_get_stride(dest->source.pixmap.pixman_image) +
                      (area.left + offset.x) * 4 +
                      (area.top + offset.y + height - 1) *
-                     dest->source.pixmap.x_image->bytes_per_line);
+                     pixman_image_get_stride(dest->source.pixmap.pixman_image));
         height--;
     }
     if (rendertype != RENDER_TYPE_FBO) {
@@ -330,9 +376,6 @@ static inline void copy_to_pixmap(const RedDrawable_p* dest,
     case PIXELS_SOURCE_TYPE_PIXMAP:
         copy_to_pixmap_from_pixmap(dest, area, offset, source, src_x, src_y);
         break;
-    case PIXELS_SOURCE_TYPE_XSHM_DRAWABLE:
-        copy_to_pixmap_from_shmdrawable(dest, area, offset, source, src_x, src_y);
-        break;
     default:
         THROW("invalid source type %d", source->type);
     }
diff --git a/client/x11/red_pixmap_cairo.cpp b/client/x11/red_pixmap_cairo.cpp
index 1974ebc..863ed39 100644
--- a/client/x11/red_pixmap_cairo.cpp
+++ b/client/x11/red_pixmap_cairo.cpp
@@ -22,156 +22,70 @@
 #include "utils.h"
 #include "pixels_source_p.h"
 #include "x_platform.h"
-#include <sys/shm.h>
 
-
-RedPixmapCairo::RedPixmapCairo(int width, int height, RedPixmap::Format format,
+RedPixmapCairo::RedPixmapCairo(int width, int height, RedDrawable::Format format,
                                bool top_bottom, RedWindow *win)
     : RedPixmap(width, height, format, top_bottom)
 {
-    ASSERT(format == RedPixmap::ARGB32 || format == RedPixmap::RGB32 ||
-	   format == RedPixmap::RGB16_555 || format == RedPixmap::RGB16_565 ||
-	   format == RedPixmap::A1);
+    ASSERT(format == RedDrawable::ARGB32 || format == RedDrawable::RGB32 ||
+	   format == RedDrawable::RGB16_555 || format == RedDrawable::RGB16_565 ||
+	   format == RedDrawable::A1);
     ASSERT(sizeof(RedDrawable_p) <= PIXELES_SOURCE_OPAQUE_SIZE);
     pixman_image_t *pixman_image;
-    XImage *image = NULL;
-    XShmSegmentInfo *shminfo = NULL;
+    XImage *image;
+    XShmSegmentInfo *shminfo;
     _data = NULL;
-    XVisualInfo *vinfo = NULL;
-    bool using_shm = false;
-
-
-    try {
-        pixman_format_code_t pixman_format;
-
-        if (win) {
-            vinfo = XPlatform::get_vinfo()[win->get_screen_num()];
-        }
-
-        using_shm = vinfo && XPlatform::is_x_shm_avail();
-
-        if (using_shm) {
-            int depth = RedPixmap::format_to_bpp(format);
-            pixman_format = RedPixmap::format_to_pixman(format);
-
-            shminfo = new XShmSegmentInfo;
-            shminfo->shmid = -1;
-            shminfo->shmaddr = 0;
-            ((PixelsSource_p*)get_opaque())->type = PIXELS_SOURCE_TYPE_XSHM_DRAWABLE;
-            memset(shminfo, 0, sizeof(XShmSegmentInfo));
-            image = XShmCreateImage(XPlatform::get_display(), vinfo->visual,
-                                    depth, ZPixmap, NULL, shminfo, width, height);
-            if (!image) {
-                THROW("XShmCreateImage failed");
-            }
-
-            shminfo->shmid = shmget(IPC_PRIVATE, height * _stride, IPC_CREAT | 0777);
-            if (shminfo->shmid < 0) {
-                THROW("shmget failed");
-            }
-            shminfo->shmaddr = (char *)shmat(shminfo->shmid, 0, 0);
-            if (shmctl(shminfo->shmid, IPC_RMID, NULL) == -1) {
-                LOG_WARN("shmctl IPC_RMID failed %s (%d)", strerror(errno), errno);
-            }
-            if (!shminfo->shmaddr) {
-                THROW("shmat failed");
-            }
-            shminfo->readOnly = False;
-            if (!XShmAttach(XPlatform::get_display(), shminfo)) {
-                THROW("XShmAttach failed");
-            }
-
-            ((PixelsSource_p*)get_opaque())->x_shm_drawable.x_image = image;
-            ((PixelsSource_p*)get_opaque())->x_shm_drawable.shminfo = shminfo;
-            _data = (uint8_t *)shminfo->shmaddr;
-            image->data = (char *)_data;
-        } else {
-            image = new XImage;
-            _data = new uint8_t[height * _stride];
-            ((PixelsSource_p*)get_opaque())->type = PIXELS_SOURCE_TYPE_PIXMAP;
-            ((PixelsSource_p*)get_opaque())->pixmap.x_image = image;
-            memset(image, 0, sizeof(*image));
-            image->width = _width;
-            image->height = _height;
-
-            image->data = (char*)_data;
-            image->byte_order = LSBFirst;
-            image->bitmap_unit = 32;
-            image->bitmap_bit_order = LSBFirst;
-            image->bitmap_pad = 32;
-
-            image->bytes_per_line = _stride;
-            switch (format) {
-            case RedPixmap::ARGB32:
-            case RedPixmap::RGB32:
-                image->depth = XPlatform::get_vinfo()[0]->depth;
-                image->format = ZPixmap;
-                image->bits_per_pixel = 32;
-                image->red_mask = 0x00ff0000;
-                image->green_mask = 0x0000ff00;
-                image->blue_mask = 0x000000ff;
-                pixman_format = format == RedPixmap::ARGB32 ? PIXMAN_a8r8g8b8 :
-                                                             PIXMAN_x8r8g8b8;
-                break;
-            case RedPixmap::A1:
-                image->depth = 1;
-                image->format = XYBitmap;
-                pixman_format = PIXMAN_a1;
-                break;
-            default:
-                THROW("unsupported format %d", format);
-            }
-
-            if (!XInitImage(image)) {
-                THROW("init image failed");
-            }
-        }
-        pixman_image = pixman_image_create_bits(pixman_format, _width, _height,
-                                                (uint32_t *)_data, _stride);
-        if (pixman_image == NULL) {
-            THROW("surf create failed");
-        }
+    XVisualInfo *vinfo;
+    int screen_num;
+    RedDrawable::Format screen_format;
+
+    screen_num = win ? win->get_screen_num() : 0;
+    vinfo = XPlatform::get_vinfo()[screen_num];
+    screen_format = XPlatform::get_screen_format(screen_num);
+
+    image = NULL;
+    shminfo = NULL;
+
+    /* Only create XImage if same format as screen (needs re-verifying at
+       draw time!)  */
+    if (RedDrawable::format_copy_compatible(format, screen_format) ||
+        format == A1) {
+        image = XPlatform::create_x_image(format, width, height,
+                                          vinfo->depth, vinfo->visual,
+                                          &shminfo);
+        _stride = image->bytes_per_line;
+        _data = (uint8_t *)image->data;
+    } else {
+        _data = new uint8_t[height * _stride];
+    }
 
-        if (!using_shm) {
-            ((PixelsSource_p*)get_opaque())->pixmap.pixman_image = pixman_image;
-        } else {
-            ((PixelsSource_p*)get_opaque())->x_shm_drawable.pixman_image = pixman_image;
-        }
-    } catch (...) {
-        if (using_shm) {
-            if (image) {
-                XDestroyImage(image);
-            }
-            if (shminfo) {
-                if (shminfo->shmid >= 0) {
-                    shmctl(shminfo->shmid, IPC_RMID, NULL);
-                }
-                if (shminfo->shmaddr) {
-                    shmdt(shminfo->shmaddr);
-                }
-            }
-        } else {
-            delete image;
-            delete _data;
-        }
-        throw;
+    pixman_image = pixman_image_create_bits(RedDrawable::format_to_pixman(format),
+                                            _width, _height,
+                                            (uint32_t *)_data, _stride);
+    if (pixman_image == NULL) {
+        THROW("surf create failed");
     }
+
+    ((PixelsSource_p*)get_opaque())->type = PIXELS_SOURCE_TYPE_PIXMAP;
+    ((PixelsSource_p*)get_opaque())->pixmap.shminfo = shminfo;
+    ((PixelsSource_p*)get_opaque())->pixmap.x_image = image;
+    ((PixelsSource_p*)get_opaque())->pixmap.pixman_image = pixman_image;
+    ((PixelsSource_p*)get_opaque())->pixmap.format = format;
 }
 
 RedPixmapCairo::~RedPixmapCairo()
 {
-    if (((PixelsSource_p*)get_opaque())->type == PIXELS_SOURCE_TYPE_PIXMAP) {
-        pixman_image_unref(((PixelsSource_p*)get_opaque())->pixmap.pixman_image);
-        delete ((PixelsSource_p*)get_opaque())->pixmap.x_image;
-        delete[] _data;
+    ASSERT(((PixelsSource_p*)get_opaque())->type == PIXELS_SOURCE_TYPE_PIXMAP);
+
+    XShmSegmentInfo *shminfo = ((PixelsSource_p*)get_opaque())->pixmap.shminfo;
+    XImage *image = ((PixelsSource_p*)get_opaque())->pixmap.x_image;
+
+    pixman_image_unref(((PixelsSource_p*)get_opaque())->pixmap.pixman_image);
+
+    if (image) {
+        XPlatform::free_x_image(image, shminfo);
     } else {
-        pixman_image_unref(((PixelsSource_p*)get_opaque())->x_shm_drawable.pixman_image);
-        XShmSegmentInfo *shminfo = ((PixelsSource_p*)get_opaque())->x_shm_drawable.shminfo;
-        XShmDetach(XPlatform::get_display(), shminfo);
-        XDestroyImage(((PixelsSource_p*)get_opaque())->x_shm_drawable.x_image);
-        XSync(XPlatform::get_display(), False);
-        shmdt(shminfo->shmaddr);
-        delete shminfo;
+        delete[] _data;
     }
 }
 
diff --git a/client/x11/red_window.cpp b/client/x11/red_window.cpp
index 2156727..c9a16ec 100644
--- a/client/x11/red_window.cpp
+++ b/client/x11/red_window.cpp
@@ -1164,6 +1164,7 @@ void RedWindow_p::create(RedWindow& red_window, PixelsSource_p& pix_source, int
     _expect_parent = false;
     pix_source.type = PIXELS_SOURCE_TYPE_X_DRAWABLE;
     pix_source.x_drawable.drawable = window;
+    pix_source.x_drawable.screen = _screen;
     pix_source.x_drawable.gc = gc;
     set_minmax(pix_source, width, height);
     sync();
commit d2a2f18b6e1b77bb6a04121455385d7e23e77168
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Apr 21 13:06:07 2010 +0200

    X11 client: Add helper for XImage construction

diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp
index bda5e87..33817e2 100644
--- a/client/x11/platform.cpp
+++ b/client/x11/platform.cpp
@@ -255,10 +255,51 @@ err1:
     return NULL;
 }
 
+XImage *XPlatform::create_x_image(RedDrawable::Format format,
+                                  int width, int height, int depth,
+                                  Visual *visual,
+                                  XShmSegmentInfo **shminfo_out)
+{
+    XImage *image;
+    uint8_t *data;
+    size_t stride;
+
+    *shminfo_out = NULL;
+
+    if (XPlatform::is_x_shm_avail()) {
+        image = XPlatform::create_x_shm_image(format, width, height,
+                                              depth, visual,
+                                              shminfo_out);
+    }
+
+    if (image != NULL) {
+        return image;
+    }
+
+    stride = SPICE_ALIGN(width * RedDrawable::format_to_bpp (format), 32) / 8;
+    /* Must use malloc here, not new, because XDestroyImage will free() it */
+    data = (uint8_t *)malloc(height * stride);
+    if (data == NULL) {
+        THROW("Out of memory");
+    }
+
+    if (format == RedDrawable::A1) {
+        image = XCreateImage(XPlatform::get_display(),
+                             NULL, 1, XYBitmap,
+                             0, (char *)data, width, height, 32, stride);
+    } else {
+        image = XCreateImage(XPlatform::get_display(),
+                             visual, depth, ZPixmap,
+                             0, (char *)data, width, height, 32, stride);
+    }
+
+    return image;
+}
+
+
 void XPlatform::free_x_image(XImage *image,
-			     XShmSegmentInfo *shminfo)
+                             XShmSegmentInfo *shminfo)
 {
-    char *data = image->data;
     if (shminfo) {
         XShmDetach(XPlatform::get_display(), shminfo);
     }
@@ -269,8 +310,6 @@ void XPlatform::free_x_image(XImage *image,
         XSync(XPlatform::get_display(), False);
         shmdt(shminfo->shmaddr);
         delete shminfo;
-    } else {
-        delete[] data;
     }
 }
 
diff --git a/client/x11/x_platform.h b/client/x11/x_platform.h
index c4f2425..57c2f26 100644
--- a/client/x11/x_platform.h
+++ b/client/x11/x_platform.h
@@ -41,6 +41,10 @@ public:
 				      int width, int height, int depth,
 				      Visual *visual,
 				      XShmSegmentInfo **shminfo_out);
+    static XImage *create_x_image(RedDrawable::Format format,
+				  int width, int height, int depth,
+				  Visual *visual,
+				  XShmSegmentInfo **shminfo_out);
     static void free_x_image(XImage *image,
 			     XShmSegmentInfo *shminfo);
 };
commit 4200c66cd7012287f03f1f5314cafae6e2a46027
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Apr 21 12:37:38 2010 +0200

    Add utility functions to create XShm images

diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp
index 5f6c1fe..bda5e87 100644
--- a/client/x11/platform.cpp
+++ b/client/x11/platform.cpp
@@ -39,6 +39,7 @@
 #include <values.h>
 #include <signal.h>
 #include <config.h>
+#include <sys/shm.h>
 
 #include "platform.h"
 #include "application.h"
@@ -198,6 +199,82 @@ bool XPlatform::is_x_shm_avail()
     return x_shm_avail;
 }
 
+XImage *XPlatform::create_x_shm_image(RedDrawable::Format format,
+                                      int width, int height, int depth,
+                                      Visual *visual,
+                                      XShmSegmentInfo **shminfo_out)
+{
+    XImage *image;
+    XShmSegmentInfo *shminfo;
+
+    shminfo = new XShmSegmentInfo;
+    shminfo->shmid = -1;
+    shminfo->shmaddr = NULL;
+
+    image = XShmCreateImage(XPlatform::get_display(),
+                            format == RedDrawable::A1 ? NULL : visual,
+                            format == RedDrawable::A1 ? 1 : depth,
+                            format == RedDrawable::A1 ? XYBitmap : ZPixmap,
+                            NULL, shminfo, width, height);
+    if (image == NULL) {
+        goto err1;
+    }
+
+    shminfo->shmid = shmget(IPC_PRIVATE, height * image->bytes_per_line,
+                            IPC_CREAT | 0777);
+    if (shminfo->shmid < 0) {
+        goto err2;
+    }
+
+    shminfo->shmaddr = (char *)shmat(shminfo->shmid, 0, 0);
+    if (!shminfo->shmaddr) {
+        goto err2;
+    }
+
+    shminfo->readOnly = False;
+    if (!XShmAttach(XPlatform::get_display(), shminfo)) {
+        goto err2;
+    }
+
+    image->data = (char *)shminfo->shmaddr;
+
+    *shminfo_out = shminfo;
+    return image;
+
+err2:
+    XDestroyImage(image);
+    if (shminfo->shmaddr != NULL) {
+        shmdt(shminfo->shmaddr);
+    }
+    if (shminfo->shmid != -1) {
+        shmctl(shminfo->shmid, IPC_RMID, 0);
+    }
+
+err1:
+    delete shminfo;
+    return NULL;
+}
+
+void XPlatform::free_x_image(XImage *image,
+			     XShmSegmentInfo *shminfo)
+{
+    char *data = image->data;
+    if (shminfo) {
+        XShmDetach(XPlatform::get_display(), shminfo);
+    }
+    if (image) {
+        XDestroyImage(image);
+    }
+    if (shminfo) {
+        XSync(XPlatform::get_display(), False);
+        shmdt(shminfo->shmaddr);
+        delete shminfo;
+    } else {
+        delete[] data;
+    }
+}
+
+
 XVisualInfo** XPlatform::get_vinfo()
 {
     return vinfo;
diff --git a/client/x11/x_platform.h b/client/x11/x_platform.h
index 575ee2d..c4f2425 100644
--- a/client/x11/x_platform.h
+++ b/client/x11/x_platform.h
@@ -37,6 +37,12 @@ public:
     static void on_focus_out();
 
     static bool is_x_shm_avail();
+    static XImage *create_x_shm_image(RedDrawable::Format format,
+				      int width, int height, int depth,
+				      Visual *visual,
+				      XShmSegmentInfo **shminfo_out);
+    static void free_x_image(XImage *image,
+			     XShmSegmentInfo *shminfo);
 };
 
 #endif
commit ecc51c6478f7bd379598021c2507f5cf13b21366
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Apr 21 12:34:08 2010 +0200

    Create screen composit area in same format as window
    
    This way we don't have to convert when drawing to it, or drawing it to
    the dc.

diff --git a/client/screen.cpp b/client/screen.cpp
index 7edca12..a1ce888 100644
--- a/client/screen.cpp
+++ b/client/screen.cpp
@@ -171,8 +171,8 @@ void RedScreen::destroy_composit_area()
 void RedScreen::create_composit_area()
 {
     destroy_composit_area();
-    _composit_area = new RedPixmapCairo(_size.x, _size.y, RedPixmap::RGB32,
-                                        false, NULL);
+    _composit_area = new RedPixmapCairo(_size.x, _size.y, _window.get_format(),
+                                        false, -1);
 }
 
 void RedScreen::adjust_window_rect(int x, int y)
commit 1efe358a05661054eac79dfdb88a55982de10760
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Apr 21 12:46:22 2010 +0200

    Add helper to compare RedDrawable::Formats for copy compabible
    
    Being copy compatible means the format are identical except
    that some bits in the source may be ignored in the destination.

diff --git a/client/red_drawable.h b/client/red_drawable.h
index 64929e8..3fac164 100644
--- a/client/red_drawable.h
+++ b/client/red_drawable.h
@@ -57,6 +57,10 @@ public:
         A1,
     };
 
+    static int format_copy_compatible(Format src, Format dest) {
+        return src == dest || (src == ARGB32 && dest == RGB32);
+    }
+
     static int format_to_bpp(Format format) {
         if (format == RedDrawable::A1) {
             return 1;
commit 5c2d9a3e321eca7f93f69a5cfc8ff240c8992e13
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Apr 21 12:31:23 2010 +0200

    Add RedDrawable::Format get_format()
    
    This is useful because we can e.g. create pixmaps in the same format as
    a window.

diff --git a/client/red_drawable.h b/client/red_drawable.h
index 5cea85e..64929e8 100644
--- a/client/red_drawable.h
+++ b/client/red_drawable.h
@@ -105,6 +105,7 @@ public:
         OP_XOR,
     };
 
+    virtual RedDrawable::Format get_format() = 0;
     void copy_pixels(const PixelsSource& src, int src_x, int src_y, const SpiceRect& dest);
     void blend_pixels(const PixelsSource& src, int src_x, int src_y, const SpiceRect& dest);
     void combine_pixels(const PixelsSource& src, int src_x, int src_y, const SpiceRect& dest,
diff --git a/client/red_pixmap.h b/client/red_pixmap.h
index a07c59c..46e3657 100644
--- a/client/red_pixmap.h
+++ b/client/red_pixmap.h
@@ -34,6 +34,7 @@ public:
     int get_stride() { return _stride;}
     uint8_t* get_data() { return _data;}
     bool is_big_endian_bits();
+    virtual RedDrawable::Format get_format() { return _format; }
 
 protected:
     Format _format;
diff --git a/client/red_window.h b/client/red_window.h
index 7da7e4c..a5eeb53 100644
--- a/client/red_window.h
+++ b/client/red_window.h
@@ -50,6 +50,7 @@ public:
     void activate();
     void set_title(std::wstring& title);
     void set_icon(Icon *icon);
+    virtual RedDrawable::Format get_format();
 
     enum Type {
         TYPE_INVALID,
diff --git a/client/x11/red_window.cpp b/client/x11/red_window.cpp
index 6de86bf..2156727 100644
--- a/client/x11/red_window.cpp
+++ b/client/x11/red_window.cpp
@@ -1930,6 +1930,11 @@ int RedWindow::get_screen_num()
     return _screen;
 }
 
+RedDrawable::Format RedWindow::get_format()
+{
+  return XPlatform::get_screen_format(_screen);
+}
+
 void RedWindow::set_type_gl()
 {
     PixelsSource_p *pix_source = (PixelsSource_p*)get_opaque();
commit cfa250caa24593b24e13290bf7c6216b871b8c7a
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Apr 21 12:20:33 2010 +0200

    Add XPlatform::get_screen_format for X11

diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp
index dba276d..5f6c1fe 100644
--- a/client/x11/platform.cpp
+++ b/client/x11/platform.cpp
@@ -67,6 +67,7 @@
 static Display* x_display = NULL;
 static bool x_shm_avail = false;
 static XVisualInfo **vinfo = NULL;
+static RedDrawable::Format *screen_format = NULL;
 static GLXFBConfig **fb_config = NULL;
 static XIM x_input_method = NULL;
 static XIC x_input_context = NULL;
@@ -202,6 +203,11 @@ XVisualInfo** XPlatform::get_vinfo()
     return vinfo;
 }
 
+RedDrawable::Format XPlatform::get_screen_format(int screen)
+{
+    return screen_format[screen];
+}
+
 GLXFBConfig** XPlatform::get_fbconfig()
 {
     return fb_config;
@@ -2194,6 +2200,8 @@ void Platform::init()
     memset(vinfo, 0, sizeof(XVisualInfo *) * ScreenCount(x_display));
     fb_config = new GLXFBConfig *[ScreenCount(x_display)];
     memset(fb_config, 0, sizeof(GLXFBConfig *) * ScreenCount(x_display));
+    screen_format = new RedDrawable::Format[ScreenCount(x_display)];
+    memset(screen_format, 0, sizeof(RedDrawable::Format) * ScreenCount(x_display));
 
     if (threads_enable && glXQueryExtension(x_display, &err, &ev)) {
         int num_configs;
@@ -2235,6 +2243,24 @@ void Platform::init()
         if (vinfo[i] == NULL) {
             THROW("Unable to find a visual for screen");
         }
+        if ((vinfo[i]->depth == 32  || vinfo[i]->depth == 24) &&
+            vinfo[i]->red_mask == 0xff0000 &&
+            vinfo[i]->green_mask == 0x00ff00 &&
+            vinfo[i]->blue_mask == 0x0000ff) {
+            screen_format[i] = RedDrawable::RGB32;
+        } else if (vinfo[i]->depth == 16 &&
+                   vinfo[i]->red_mask == 0xf800 &&
+                   vinfo[i]->green_mask == 0x7e0 &&
+                   vinfo[i]->blue_mask == 0x1f) {
+            screen_format[i] = RedDrawable::RGB16_565;
+        } else if (vinfo[i]->depth == 15 &&
+                   vinfo[i]->red_mask == 0x7c00 &&
+                   vinfo[i]->green_mask == 0x3e0 &&
+                   vinfo[i]->blue_mask == 0x1f) {
+            screen_format[i] = RedDrawable::RGB16_555;
+        } else {
+            THROW("Unsupported visual for screen");
+        }
     }
 
     XSetErrorHandler(x_error_handler);
diff --git a/client/x11/x_platform.h b/client/x11/x_platform.h
index 12d20f1..575ee2d 100644
--- a/client/x11/x_platform.h
+++ b/client/x11/x_platform.h
@@ -18,10 +18,14 @@
 #ifndef _H_XPLATFORM
 #define _H_XPLATFORM
 
+#include "red_drawable.h"
+#include <X11/extensions/XShm.h>
+
 class XPlatform {
 public:
     static Display* get_display();
     static XVisualInfo** get_vinfo();
+    static RedDrawable::Format get_screen_format(int screen);
     static GLXFBConfig** get_fbconfig();
     static XIC get_input_context();
 
commit 2d6fbde89b08b7dd4a2050c71fe6663ea8e9c2d9
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Apr 21 12:03:06 2010 +0200

    Move RedPixmap::Format to RedDrawable::Format
    
    We need to know the format for other drawables too (like for instance
    the native format of a window), so we're pushing this down.
    
    This changes a bunch of references to be RedDrawable::, but not all.
    The the old RedPixmap:: references still work, but will be phased out.

diff --git a/client/gui/gui.cpp b/client/gui/gui.cpp
index 6debdd1..30b864d 100644
--- a/client/gui/gui.cpp
+++ b/client/gui/gui.cpp
@@ -888,7 +888,7 @@ GUI::GUI(Application& app, Application::State state)
     : ScreenLayer (SCREEN_LAYER_GUI, false)
     , _app (app)
     , _state (state)
-    , _pixmap (new RedPixmapCairo(MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT, RedPixmap::RGB32, true, NULL))
+    , _pixmap (new RedPixmapCairo(MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT, RedDrawable::RGB32, true, NULL))
     , _renderer (new CEGUI::SoftRenderer(_pixmap->get_data(), MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT,
                                          _pixmap->get_stride()))
     , _gui_system (new CEGUI::System(_renderer, new CEGUIResourceProvider()))
diff --git a/client/red_drawable.h b/client/red_drawable.h
index b6538f1..5cea85e 100644
--- a/client/red_drawable.h
+++ b/client/red_drawable.h
@@ -18,7 +18,9 @@
 #ifndef _H_RED_DRAWABLE
 #define _H_RED_DRAWABLE
 
+#include <pixman_utils.h>
 #include "pixels_source.h"
+#include "utils.h"
 
 typedef uint32_t rgb32_t;
 
@@ -47,6 +49,56 @@ public:
     RedDrawable() {}
     virtual ~RedDrawable() {}
 
+    enum Format {
+        ARGB32,
+        RGB32,
+        RGB16_555,
+        RGB16_565,
+        A1,
+    };
+
+    static int format_to_bpp(Format format) {
+        if (format == RedDrawable::A1) {
+            return 1;
+        } else if (format == RGB16_555 || format == RGB16_565) {
+            return 16;
+        } else {
+            return 32;
+        }
+    }
+
+    static pixman_format_code_t format_to_pixman(Format format) {
+            switch (format) {
+            case RedDrawable::ARGB32:
+                return PIXMAN_a8r8g8b8;
+            case RedDrawable::RGB32:
+                return PIXMAN_x8r8g8b8;
+            case RedDrawable::RGB16_555:
+                return PIXMAN_x1r5g5b5;
+            case RedDrawable::RGB16_565:
+                return PIXMAN_r5g6b5;
+            case RedDrawable::A1:
+                return PIXMAN_a1;
+            default:
+                THROW("unsupported format %d", format);
+            }
+    }
+
+    static Format format_from_surface(uint32_t format) {
+        switch (format) {
+        case SPICE_SURFACE_FMT_16_555:
+            return RedDrawable::RGB16_555;
+        case SPICE_SURFACE_FMT_16_565:
+            return RedDrawable::RGB16_565;
+        case SPICE_SURFACE_FMT_32_xRGB:
+            return RedDrawable::RGB32;
+        case SPICE_SURFACE_FMT_32_ARGB:
+            return RedDrawable::ARGB32;
+        default:
+            THROW("Unsupported RedPixman format");
+        }
+    }
+
     enum CombineOP {
         OP_COPY,
         OP_AND,
diff --git a/client/red_gdi_canvas.cpp b/client/red_gdi_canvas.cpp
index ae73ea2..0ea53ed 100644
--- a/client/red_gdi_canvas.cpp
+++ b/client/red_gdi_canvas.cpp
@@ -30,7 +30,7 @@ GDICanvas::GDICanvas(int width, int height, uint32_t format,
     , _pixmap (0)
 {
     _pixmap = new RedPixmapGdi(width, height,
-                               RedPixmap::format_from_surface(format),
+                               RedDrawable::format_from_surface(format),
                                true, NULL);
     if (!(_canvas = gdi_canvas_create(width, height, _pixmap->get_dc(),
                                       &_pixmap->get_mutex(),
diff --git a/client/red_gl_canvas.cpp b/client/red_gl_canvas.cpp
index dc743cf..13e4723 100644
--- a/client/red_gl_canvas.cpp
+++ b/client/red_gl_canvas.cpp
@@ -33,7 +33,7 @@ GCanvas::GCanvas(int width, int height, uint32_t format, RedWindow *win,
     , _textures_lost (false)
 {
     _pixmap = new RedPixmapGL(width, height,
-                              RedPixmap::format_from_surface(format),
+                              RedDrawable::format_from_surface(format),
                               true, win, rendertype);
     if (!(_canvas = gl_canvas_create(width, height,
                                      SPICE_SURFACE_FMT_DEPTH(format),
diff --git a/client/red_pixmap.h b/client/red_pixmap.h
index c81c2f7..a07c59c 100644
--- a/client/red_pixmap.h
+++ b/client/red_pixmap.h
@@ -21,60 +21,9 @@
 
 #include "red_drawable.h"
 #include "utils.h"
-#include <pixman_utils.h>
 
 class RedPixmap: public RedDrawable {
 public:
-    enum Format {
-        ARGB32,
-        RGB32,
-        RGB16_555,
-        RGB16_565,
-        A1,
-    };
-
-    static int format_to_bpp(Format format) {
-        if (format == RedPixmap::A1) {
-            return 1;
-        } else if (format == RGB16_555 || format == RGB16_565) {
-            return 16;
-        } else {
-            return 32;
-        }
-    }
-
-    static pixman_format_code_t format_to_pixman(Format format) {
-            switch (format) {
-            case RedPixmap::ARGB32:
-                return PIXMAN_a8r8g8b8;
-            case RedPixmap::RGB32:
-                return PIXMAN_x8r8g8b8;
-            case RedPixmap::RGB16_555:
-                return PIXMAN_x1r5g5b5;
-            case RedPixmap::RGB16_565:
-                return PIXMAN_r5g6b5;
-            case RedPixmap::A1:
-                return PIXMAN_a1;
-            default:
-                THROW("unsupported format %d", format);
-            }
-    }
-
-    static Format format_from_surface(uint32_t format) {
-        switch (format) {
-        case SPICE_SURFACE_FMT_16_555:
-            return RedPixmap::RGB16_555;
-        case SPICE_SURFACE_FMT_16_565:
-            return RedPixmap::RGB16_565;
-        case SPICE_SURFACE_FMT_32_xRGB:
-            return RedPixmap::RGB32;
-        case SPICE_SURFACE_FMT_32_ARGB:
-            return RedPixmap::ARGB32;
-        default:
-            THROW("Unsupported RedPixman format");
-        }
-    }
-
     RedPixmap(int width, int height, Format format, bool top_bottom);
     virtual ~RedPixmap();
 
diff --git a/client/windows/red_pixmap.cpp b/client/windows/red_pixmap.cpp
index 574d285..2f8655c 100644
--- a/client/windows/red_pixmap.cpp
+++ b/client/windows/red_pixmap.cpp
@@ -20,7 +20,7 @@
 #include "debug.h"
 #include "utils.h"
 
-RedPixmap::RedPixmap(int width, int height, RedPixmap::Format format,
+RedPixmap::RedPixmap(int width, int height, RedDrawable::Format format,
                      bool top_bottom)
     : _format (format)
     , _width (width)
@@ -37,6 +37,6 @@ RedPixmap::~RedPixmap()
 
 bool RedPixmap::is_big_endian_bits()
 {
-    return _format == RedPixmap::A1;
+    return _format == RedDrawable::A1;
 }
 
diff --git a/client/windows/red_pixmap_cairo.cpp b/client/windows/red_pixmap_cairo.cpp
index 793d21e..35fe89b 100644
--- a/client/windows/red_pixmap_cairo.cpp
+++ b/client/windows/red_pixmap_cairo.cpp
@@ -33,7 +33,7 @@ RedPixmapCairo::RedPixmapCairo(int width, int height, RedPixmap::Format format,
                                bool top_bottom, RedWindow *win)
     : RedPixmap(width, height, format, top_bottom)
 {
-    ASSERT(format == RedPixmap::ARGB32 || format == RedPixmap::RGB32 || format == RedPixmap::A1);
+    ASSERT(format == RedDrawable::ARGB32 || format == RedDrawable::RGB32 || format == RedDrawable::A1);
     ASSERT(sizeof(RedPixmap_p) <= PIXELES_SOURCE_OPAQUE_SIZE);
 
     struct {
@@ -60,10 +60,10 @@ RedPixmapCairo::RedPixmapCairo(int width, int height, RedPixmap::Format format,
 #endif*/
 
     bitmap_info.inf.bmiHeader.biPlanes = 1;
-    bitmap_info.inf.bmiHeader.biBitCount = RedPixmap::format_to_bpp(format);
+    bitmap_info.inf.bmiHeader.biBitCount = RedDrawable::format_to_bpp(format);
     bitmap_info.inf.bmiHeader.biCompression = BI_RGB;
     switch (format) {
-    case RedPixmap::A1:
+    case RedDrawable::A1:
         bitmap_info.inf.bmiColors[0].rgbRed = 0;
         bitmap_info.inf.bmiColors[0].rgbGreen = 0;
         bitmap_info.inf.bmiColors[0].rgbBlue = 0;
diff --git a/client/windows/red_pixmap_gdi.cpp b/client/windows/red_pixmap_gdi.cpp
index 1c90f3d..322d020 100644
--- a/client/windows/red_pixmap_gdi.cpp
+++ b/client/windows/red_pixmap_gdi.cpp
@@ -29,10 +29,10 @@ struct RedPixmap_p {
     HBITMAP prev_bitmap;
 };
 
-RedPixmapGdi::RedPixmapGdi(int width, int height, RedPixmap::Format format, bool top_bottom)
+RedPixmapGdi::RedPixmapGdi(int width, int height, RedDrawable::Format format, bool top_bottom)
     : RedPixmap(width, height, format, top_bottom, pallet)
 {
-    ASSERT(format == RedPixmap::ARGB32 || format == RedPixmap::RGB32 || format == RedPixmap::A1);
+    ASSERT(format == RedDrawable::ARGB32 || format == RedDrawable::RGB32 || format == RedDrawable::A1);
     ASSERT(sizeof(RedPixmap_p) <= PIXELES_SOURCE_OPAQUE_SIZE);
 
     struct {
@@ -46,10 +46,10 @@ RedPixmapGdi::RedPixmapGdi(int width, int height, RedPixmap::Format format, bool
     bitmap_info.inf.bmiHeader.biHeight = top_bottom ? -_height : _height;
 
     bitmap_info.inf.bmiHeader.biPlanes = 1;
-    bitmap_info.inf.bmiHeader.biBitCount = RedPixmap::format_to_bpp(format);
+    bitmap_info.inf.bmiHeader.biBitCount = RedDrawable::format_to_bpp(format);
     bitmap_info.inf.bmiHeader.biCompression = BI_RGB;
     switch (format) {
-    case RedPixmap::A1:
+    case RedDrawable::A1:
         bitmap_info.inf.bmiColors[0].rgbRed = 0;
         bitmap_info.inf.bmiColors[0].rgbGreen = 0;
         bitmap_info.inf.bmiColors[0].rgbBlue = 0;
diff --git a/client/x11/red_pixmap_gl.cpp b/client/x11/red_pixmap_gl.cpp
index a309651..7c85966 100644
--- a/client/x11/red_pixmap_gl.cpp
+++ b/client/x11/red_pixmap_gl.cpp
@@ -30,7 +30,7 @@
 #include "red_window_p.h"
 
 
-RedPixmapGL::RedPixmapGL(int width, int height, RedPixmap::Format format,
+RedPixmapGL::RedPixmapGL(int width, int height, RedDrawable::Format format,
                          bool top_bottom, RedWindow *win,
                          RenderType rendertype)
     : RedPixmap(width, height, format, top_bottom)
@@ -41,7 +41,7 @@ RedPixmapGL::RedPixmapGL(int width, int height, RedPixmap::Format format,
     Win xwin;
     //GLint max_texture_size;
 
-    ASSERT(format == RedPixmap::ARGB32 || format == RedPixmap::RGB32 || format == RedPixmap::A1);
+    ASSERT(format == RedDrawable::ARGB32 || format == RedDrawable::RGB32 || format == RedDrawable::A1);
     ASSERT(sizeof(RedDrawable_p) <= PIXELES_SOURCE_OPAQUE_SIZE);
 
     ((PixelsSource_p*)get_opaque())->type = PIXELS_SOURCE_TYPE_GL_TEXTURE;
commit 98d91203c5d2f6f7249f38941466857b6a566f5d
Author: Alexander Larsson <alexl at redhat.com>
Date:   Mon Apr 19 16:19:43 2010 +0200

    Make client canvas and pixmaps handle more formats and simplify
    
    We now support 16bit format pixmaps as well as the old ones. Including
    both 555 and 565 modes.
    
    We drop the palette argument for pixmap construction as it was only
    used for black/white anyway.
    
    Canvas creation is simplified so that there is no separate set_mode
    state. Canvases are already created in the right mode and never change.

diff --git a/client/cursor_channel.cpp b/client/cursor_channel.cpp
index 0dd9dcb..289c059 100644
--- a/client/cursor_channel.cpp
+++ b/client/cursor_channel.cpp
@@ -112,7 +112,7 @@ void UnsupportedCursor::draw(RedDrawable& dest, int x, int y, const SpiceRect& a
 
 AlphaCursor::AlphaCursor(const SpiceCursorHeader& header, const uint8_t* data)
     : _pixmap (new RedPixmapCairo(header.width, header.height,
-                                  RedPixmap::ARGB32, true, NULL, NULL))
+                                  RedPixmap::ARGB32, true, NULL))
 {
     int stride = _pixmap->get_stride();
     uint8_t* dest = _pixmap->get_data();
@@ -131,9 +131,8 @@ MonoCursor::MonoCursor(const SpiceCursorHeader& header, const uint8_t* data)
     : _pixmap (NULL)
     , _height (header.height)
 {
-    rgb32_t pallete[2] = { rgb32_make(0x00, 0x00, 0x00), rgb32_make(0xff, 0xff, 0xff)};
     _pixmap.reset(new RedPixmapCairo(header.width, _height * 2, RedPixmap::A1,
-                                     true, pallete, NULL));
+                                     true, NULL));
 
     int dest_stride = _pixmap->get_stride();
     uint8_t *dest_line = _pixmap->get_data();
@@ -177,12 +176,11 @@ private:
 
 ColorCursor::ColorCursor(const SpiceCursorHeader& header)
     : _pixmap (new RedPixmapCairo(header.width, header.height,
-                                  RedPixmap::ARGB32, true, NULL, NULL))
+                                  RedPixmap::ARGB32, true, NULL))
     , _invers (NULL)
 {
-    rgb32_t pallete[2] = { rgb32_make(0x00, 0x00, 0x00), rgb32_make(0xff, 0xff, 0xff)};
     _invers.reset(new RedPixmapCairo(header.width, header.height, RedPixmap::A1,
-                                     true, pallete, NULL));
+                                     true, NULL));
 }
 
 void ColorCursor::init_pixels(const SpiceCursorHeader& header, const uint8_t* pixels,
diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index 719e7df..acbf5da 100644
--- a/client/display_channel.cpp
+++ b/client/display_channel.cpp
@@ -1079,12 +1079,13 @@ void DisplayChannel::on_disconnect()
     (*sync_event)->wait();
 }
 
-bool DisplayChannel::create_cairo_canvas(int surface_id, int width, int height, int depth)
+bool DisplayChannel::create_cairo_canvas(int surface_id, int width, int height, uint32_t format)
 {
     try {
-        CCanvas *canvas = new CCanvas(_pixmap_cache, _palette_cache, _glz_window,
+        CCanvas *canvas = new CCanvas(surface_id == 0, width, height, format,
+                                      screen()->get_window(),
+                                      _pixmap_cache, _palette_cache, _glz_window,
                                       surfaces_mngr.get_surfaces());
-        canvas->set_mode(width, height, depth, screen()->get_window());
         surfaces_mngr.add_canvas(surface_id, canvas);
         surfaces_mngr.add_surface(surface_id, canvas->get_internal_canvas());
         if (surface_id == 0) {
@@ -1097,21 +1098,19 @@ bool DisplayChannel::create_cairo_canvas(int surface_id, int width, int height,
 }
 
 #ifdef USE_OGL
-bool DisplayChannel::create_ogl_canvas(int surface_id, int width, int height, int depth,
+bool DisplayChannel::create_ogl_canvas(int surface_id, int width, int height, uint32_t format,
                                        bool recreate, RenderType rendertype)
 {
     try {
         RedWindow *win;
 
-        GCanvas *canvas = new GCanvas(_pixmap_cache,
+        win = screen()->get_window();
+        GCanvas *canvas = new GCanvas(width, height, format, win, rendertype,
+                                      _pixmap_cache,
                                       _palette_cache,
                                       _glz_window,
                                       surfaces_mngr.get_surfaces());
 
-        win = screen()->get_window();
-
-        canvas->set_mode(width, height, depth, win, rendertype);
-
         screen()->untouch_context();
 
         surfaces_mngr.add_canvas(surface_id, canvas);
@@ -1129,12 +1128,12 @@ bool DisplayChannel::create_ogl_canvas(int surface_id, int width, int height, in
 #endif
 
 #ifdef WIN32
-bool DisplayChannel::create_gdi_canvas(int surface_id, int width, int height, int depth)
+bool DisplayChannel::create_gdi_canvas(int surface_id, int width, int height, uint32_t format)
 {
     try {
-        GDICanvas *canvas = new GDICanvas(_pixmap_cache, _palette_cache, _glz_window,
+        GDICanvas *canvas = new GDICanvas(width, height, format,
+                                          _pixmap_cache, _palette_cache, _glz_window,
                                           surfaces_mngr.get_surfaces());
-        canvas->set_mode(width, height, depth);
         surfaces_mngr.add_canvas(surface_id, canvas);
         surfaces_mngr.add_surface(surface_id, canvas->get_internal_canvas());
         if (surface_id == 0) {
@@ -1155,7 +1154,7 @@ void DisplayChannel::destroy_canvas(int surface_id)
     if (!surfaces_mngr.is_present_canvas(surface_id)) {
         return;
     }
-    
+
     canvas = surfaces_mngr.get_canvas(surface_id);
 
 #ifdef USE_OGL
@@ -1171,7 +1170,7 @@ void DisplayChannel::destroy_canvas(int surface_id)
 }
 
 void DisplayChannel::create_canvas(int surface_id, const std::vector<int>& canvas_types, int width,
-                                   int height, int depth)
+                                   int height, uint32_t format)
 {
 #ifdef USE_OGL
     bool recreate = true;
@@ -1417,7 +1416,7 @@ void DisplayChannel::handle_stream_destroy_all(RedPeer::InMessage* message)
     destroy_strams();
 }
 
-void DisplayChannel::create_primary_surface(int width, int height, int depth)
+void DisplayChannel::create_primary_surface(int width, int height, uint32_t format)
 {
    Canvas *canvas;
    _mark = false;
diff --git a/client/display_channel.h b/client/display_channel.h
index 2bb697c..a5761b3 100644
--- a/client/display_channel.h
+++ b/client/display_channel.h
@@ -133,13 +133,13 @@ protected:
 private:
     void set_draw_handlers();
     void clear_draw_handlers();
-    bool create_cairo_canvas(int surface_id, int width, int height, int depth);
+    bool create_cairo_canvas(int surface_id, int width, int height, uint32_t format);
 #ifdef USE_OGL
-    bool create_ogl_canvas(int surface_id, int width, int height, int depth, bool recreate,
+    bool create_ogl_canvas(int surface_id, int width, int height, uint32_t format, bool recreate,
                            RenderType rendertype);
 #endif
 #ifdef WIN32
-    bool create_gdi_canvas(int surface_id, int width, int height, int depth);
+    bool create_gdi_canvas(int surface_id, int width, int height, uint32_t format);
 #endif
     void destroy_canvas(int surface_id);
     void create_canvas(int surface_id, const std::vector<int>& canvas_type, int width, int height,
diff --git a/client/gui/gui.cpp b/client/gui/gui.cpp
index 0ff442e..6debdd1 100644
--- a/client/gui/gui.cpp
+++ b/client/gui/gui.cpp
@@ -888,8 +888,7 @@ GUI::GUI(Application& app, Application::State state)
     : ScreenLayer (SCREEN_LAYER_GUI, false)
     , _app (app)
     , _state (state)
-    , _pixmap (new RedPixmapCairo(MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT, RedPixmap::RGB32, true, NULL,
-                                  NULL))
+    , _pixmap (new RedPixmapCairo(MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT, RedPixmap::RGB32, true, NULL))
     , _renderer (new CEGUI::SoftRenderer(_pixmap->get_data(), MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT,
                                          _pixmap->get_stride()))
     , _gui_system (new CEGUI::System(_renderer, new CEGUIResourceProvider()))
diff --git a/client/red_cairo_canvas.cpp b/client/red_cairo_canvas.cpp
index 96f7637..9338d9f 100644
--- a/client/red_cairo_canvas.cpp
+++ b/client/red_cairo_canvas.cpp
@@ -25,36 +25,44 @@
 #include "region.h"
 #include "red_pixmap_cairo.h"
 
-CCanvas::CCanvas(PixmapCache& pixmap_cache, PaletteCache& palette_cache,
+CCanvas::CCanvas(bool onscreen,
+                 int width, int height, uint32_t format, RedWindow *win,
+                 PixmapCache& pixmap_cache, PaletteCache& palette_cache,
                  GlzDecoderWindow &glz_decoder_window, CSurfaces& csurfaces)
     : Canvas (pixmap_cache, palette_cache, glz_decoder_window, csurfaces)
     , _pixmap (0)
 {
+    if (onscreen) {
+        _pixmap = new RedPixmapCairo(width, height,
+                                     RedPixmap::format_from_surface(format),
+                                     true, win);
+        _canvas = canvas_create_for_data(width, height, format,
+                                         _pixmap->get_data(),
+                                         _pixmap->get_stride(),
+                                         &pixmap_cache.base,
+                                         &palette_cache.base,
+                                         &csurfaces.base,
+                                         &glz_decoder());
+    } else {
+        _canvas = canvas_create(width, height, format,
+                                &pixmap_cache.base,
+                                &palette_cache.base,
+                                &csurfaces.base,
+                                &glz_decoder());
+    }
+    if (_canvas == NULL) {
+        THROW("create canvas failed");
+    }
 }
 
 CCanvas::~CCanvas()
 {
-    destroy();
-}
-
-void CCanvas::destroy()
-{
-    if (_canvas) {
-        _canvas->ops->destroy(_canvas);
-        _canvas = NULL;
+    _canvas->ops->destroy(_canvas);
+    _canvas = NULL;
+    if (_pixmap) {
+        delete _pixmap;
+        _pixmap = NULL;
     }
-    destroy_pixmap();
-}
-
-void CCanvas::destroy_pixmap()
-{
-    delete _pixmap;
-    _pixmap = NULL;
-}
-
-void CCanvas::create_pixmap(int width, int height, RedWindow *win)
-{
-    _pixmap = new RedPixmapCairo(width, height, RedPixmap::RGB32, true, NULL, win);
 }
 
 void CCanvas::copy_pixels(const QRegion& region, RedDrawable& dest_dc)
@@ -62,6 +70,8 @@ void CCanvas::copy_pixels(const QRegion& region, RedDrawable& dest_dc)
     pixman_box32_t *rects;
     int num_rects;
 
+    ASSERT(_pixmap != NULL);
+
     rects = pixman_region32_rectangles((pixman_region32_t *)&region, &num_rects);
     for (int i = 0; i < num_rects; i++) {
         SpiceRect r;
@@ -79,29 +89,6 @@ void CCanvas::copy_pixels(const QRegion& region, RedDrawable* dest_dc, const Pix
     copy_pixels(region, *dest_dc);
 }
 
-void CCanvas::set_mode(int width, int height, int depth, RedWindow *win)
-{
-    pixman_image_t *surface;
-
-    destroy();
-    create_pixmap(width, height, win);
-    surface = pixman_image_create_bits(PIXMAN_x8r8g8b8, width, height,
-                                       (uint32_t *)_pixmap->get_data(),
-                                       _pixmap->get_stride());
-    if (surface == NULL) {
-        THROW("create surface failed, out of memory");
-    }
-
-    if (!(_canvas = canvas_create(surface, depth,
-                                  &pixmap_cache().base,
-                                  &palette_cache().base,
-                                  &csurfaces().base,
-                                  &glz_decoder()))) {
-        THROW("create canvas failed");
-    }
-    pixman_image_unref (surface);
-}
-
 CanvasType CCanvas::get_pixmap_type()
 {
     return CANVAS_TYPE_CAIRO;
diff --git a/client/red_cairo_canvas.h b/client/red_cairo_canvas.h
index 8d039bf..9f4911b 100644
--- a/client/red_cairo_canvas.h
+++ b/client/red_cairo_canvas.h
@@ -26,11 +26,12 @@ class RedPixmap;
 
 class CCanvas: public Canvas {
 public:
-    CCanvas(PixmapCache& pixmap_cache, PaletteCache& palette_cache,
+    CCanvas(bool onscreen,
+            int width, int height, uint32_t format, RedWindow *win,
+            PixmapCache& pixmap_cache, PaletteCache& palette_cache,
             GlzDecoderWindow &glz_decoder_window, CSurfaces &csurfaces);
     virtual ~CCanvas();
 
-    virtual void set_mode(int x, int y, int bits, RedWindow *win);
     virtual void thread_touch() {}
     virtual void copy_pixels(const QRegion& region, RedDrawable* dc,
                              const PixmapHeader* pixmap);
@@ -39,11 +40,6 @@ public:
     virtual CanvasType get_pixmap_type();
 
 private:
-    void create_pixmap(int width, int height, RedWindow *win);
-    void destroy_pixmap();
-    void destroy();
-
-private:
     RedPixmap *_pixmap;
     unsigned long _base;
     unsigned long _max;
diff --git a/client/red_gdi_canvas.cpp b/client/red_gdi_canvas.cpp
index be7992c..ae73ea2 100644
--- a/client/red_gdi_canvas.cpp
+++ b/client/red_gdi_canvas.cpp
@@ -23,38 +23,33 @@
 #include "region.h"
 #include "red_pixmap_gdi.h"
 
-GDICanvas::GDICanvas(PixmapCache& pixmap_cache, PaletteCache& palette_cache,
+GDICanvas::GDICanvas(int width, int height, uint32_t format,
+		     PixmapCache& pixmap_cache, PaletteCache& palette_cache,
                      GlzDecoderWindow &glz_decoder_window, CSurfaces &csurfaces)
     : Canvas (pixmap_cache, palette_cache, glz_decoder_window, csurfaces)
     , _pixmap (0)
 {
-}
-
-GDICanvas::~GDICanvas()
-{
-    destroy();
-}
-
-void GDICanvas::destroy()
-{
-    if (_canvas) {
-        _canvas->ops->destroy(_canvas);
-        _canvas = NULL;
+    _pixmap = new RedPixmapGdi(width, height,
+                               RedPixmap::format_from_surface(format),
+                               true, NULL);
+    if (!(_canvas = gdi_canvas_create(width, height, _pixmap->get_dc(),
+                                      &_pixmap->get_mutex(),
+                                      depth, &pixmap_cache().base,
+                                      &palette_cache().base,
+                                      &csurfaces().base,
+                                      &glz_decoder()))) {
+        THROW("create canvas failed");
     }
-    destroy_pixmap();
 }
 
-void GDICanvas::destroy_pixmap()
+GDICanvas::~GDICanvas()
 {
+  _canvas->ops->destroy(_canvas);
+  _canvas = NULL;
     delete _pixmap;
     _pixmap = NULL;
 }
 
-void GDICanvas::create_pixmap(int width, int height)
-{
-    _pixmap = new RedPixmapGdi(width, height, RedPixmap::RGB32, true, NULL);
-}
-
 void GDICanvas::copy_pixels(const QRegion& region, RedDrawable& dest_dc)
 {
     pixman_box32_t *rects;
@@ -80,15 +75,6 @@ void GDICanvas::copy_pixels(const QRegion& region, RedDrawable* dest_dc, const P
 void GDICanvas::set_mode(int width, int height, int depth)
 {
     destroy();
-    create_pixmap(width, height);
-    if (!(_canvas = gdi_canvas_create(width, height, _pixmap->get_dc(),
-                                      &_pixmap->get_mutex(),
-                                      depth, &pixmap_cache().base,
-                                      &palette_cache().base,
-                                      &csurfaces().base,
-                                      &glz_decoder()))) {
-        THROW("create canvas failed");
-    }
 }
 
 CanvasType GDICanvas::get_pixmap_type()
diff --git a/client/red_gdi_canvas.h b/client/red_gdi_canvas.h
index d117282..643f3c6 100644
--- a/client/red_gdi_canvas.h
+++ b/client/red_gdi_canvas.h
@@ -27,11 +27,11 @@ class RedPixmap;
 
 class GDICanvas: public Canvas {
 public:
-    GDICanvas(PixmapCache& pixmap_cache, PaletteCache& palette_cache,
+    GDICanvas(int width, int height, uint32_t format,
+	      PixmapCache& pixmap_cache, PaletteCache& palette_cache,
               GlzDecoderWindow &glz_decoder_window, CSurfaces &csurfaces);
     virtual ~GDICanvas();
 
-    virtual void set_mode(int x, int y, int bits);
     virtual void thread_touch() {}
     virtual void copy_pixels(const QRegion& region, RedDrawable* dc,
                              const PixmapHeader* pixmap);
@@ -40,11 +40,6 @@ public:
     virtual CanvasType get_pixmap_type();
 
 private:
-    void create_pixmap(int width, int height);
-    void destroy_pixmap();
-    void destroy();
-
-private:
     RedPixmapGdi *_pixmap;
     RedPixmapGdi *_helper_pixmap;
     HDC _dc;
diff --git a/client/red_gl_canvas.cpp b/client/red_gl_canvas.cpp
index 2d285a5..dc743cf 100644
--- a/client/red_gl_canvas.cpp
+++ b/client/red_gl_canvas.cpp
@@ -24,42 +24,36 @@
 #include "red_pixmap_gl.h"
 #include <GL/glx.h>
 
-GCanvas::GCanvas(PixmapCache& pixmap_cache, PaletteCache& palette_cache,
+GCanvas::GCanvas(int width, int height, uint32_t format, RedWindow *win,
+                 RenderType rendertype,
+                 PixmapCache& pixmap_cache, PaletteCache& palette_cache,
                  GlzDecoderWindow &glz_decoder_window, CSurfaces &csurfaces)
     : Canvas(pixmap_cache, palette_cache, glz_decoder_window, csurfaces)
     , _pixmap (0)
     , _textures_lost (false)
 {
-}
-
-GCanvas::~GCanvas()
-{
-    destroy();
-}
-
-void GCanvas::destroy()
-{
-    if (_canvas) {
-        gl_canvas_set_textures_lost (_canvas, (int)_textures_lost);
-        _canvas->ops->destroy(_canvas);
-        _canvas = NULL;
+    _pixmap = new RedPixmapGL(width, height,
+                              RedPixmap::format_from_surface(format),
+                              true, win, rendertype);
+    if (!(_canvas = gl_canvas_create(width, height,
+                                     SPICE_SURFACE_FMT_DEPTH(format),
+                                     &pixmap_cache.base,
+                                     &palette_cache.base,
+                                     &csurfaces.base,
+                                     &glz_decoder()))) {
+        THROW("create canvas failed");
     }
-    destroy_pixmap();
 }
 
-void GCanvas::destroy_pixmap()
+GCanvas::~GCanvas()
 {
+    gl_canvas_set_textures_lost (_canvas, (int)_textures_lost);
+    _canvas->ops->destroy(_canvas);
+    _canvas = NULL;
     delete _pixmap;
     _pixmap = NULL;
 }
 
-void GCanvas::create_pixmap(int width, int height, RedWindow *win,
-                            RenderType rendertype)
-{
-    _pixmap = new RedPixmapGL(width, height, RedPixmap::RGB32, true, NULL,
-                              win, rendertype);
-}
-
 void GCanvas::copy_pixels(const QRegion& region, RedDrawable& dest_dc)
 {
     pixman_box32_t *rects;
@@ -83,21 +77,6 @@ void GCanvas::copy_pixels(const QRegion& region, RedDrawable* dest_dc, const Pix
     copy_pixels(region, *dest_dc);
 }
 
-void GCanvas::set_mode(int width, int height, int depth, RedWindow *win,
-                       RenderType rendertype)
-{
-    destroy();
-
-    create_pixmap(width, height, win, rendertype);
-    if (!(_canvas = gl_canvas_create(width, height, depth,
-                                     &pixmap_cache().base,
-                                     &palette_cache().base,
-                                     &csurfaces().base,
-                                     &glz_decoder()))) {
-        THROW("create canvas failed");
-    }
-}
-
 void GCanvas::touched_bbox(const SpiceRect *bbox)
 {
     _pixmap->update_texture(bbox);
diff --git a/client/red_gl_canvas.h b/client/red_gl_canvas.h
index 22491c4..dfe53d6 100644
--- a/client/red_gl_canvas.h
+++ b/client/red_gl_canvas.h
@@ -28,12 +28,13 @@ class RedPixmapGL;
 
 class GCanvas: public Canvas {
 public:
-    GCanvas(PixmapCache& pixmap_cache, PaletteCache& palette_cache,
+    GCanvas(int width, int height, uint32_t format, RedWindow *win,
+            RenderType rendertype,
+            PixmapCache& pixmap_cache, PaletteCache& palette_cache,
             GlzDecoderWindow &glz_decoder_window, CSurfaces &csurfaces);
     virtual ~GCanvas();
 
-    void set_mode(int width, int height, int depth, RedWindow *win,
-                  RenderType rendertype);
+    void set_mode();
     void clear();
     void thread_touch() {}
     void copy_pixels(const QRegion& region, RedDrawable* dc,
diff --git a/client/red_pixmap.h b/client/red_pixmap.h
index 1b469bd..c81c2f7 100644
--- a/client/red_pixmap.h
+++ b/client/red_pixmap.h
@@ -20,17 +20,62 @@
 #define _H_RED_PIXMAP
 
 #include "red_drawable.h"
+#include "utils.h"
+#include <pixman_utils.h>
 
 class RedPixmap: public RedDrawable {
 public:
     enum Format {
         ARGB32,
         RGB32,
+        RGB16_555,
+        RGB16_565,
         A1,
     };
 
-    RedPixmap(int width, int height, Format format, bool top_bottom,
-              rgb32_t* pallete);
+    static int format_to_bpp(Format format) {
+        if (format == RedPixmap::A1) {
+            return 1;
+        } else if (format == RGB16_555 || format == RGB16_565) {
+            return 16;
+        } else {
+            return 32;
+        }
+    }
+
+    static pixman_format_code_t format_to_pixman(Format format) {
+            switch (format) {
+            case RedPixmap::ARGB32:
+                return PIXMAN_a8r8g8b8;
+            case RedPixmap::RGB32:
+                return PIXMAN_x8r8g8b8;
+            case RedPixmap::RGB16_555:
+                return PIXMAN_x1r5g5b5;
+            case RedPixmap::RGB16_565:
+                return PIXMAN_r5g6b5;
+            case RedPixmap::A1:
+                return PIXMAN_a1;
+            default:
+                THROW("unsupported format %d", format);
+            }
+    }
+
+    static Format format_from_surface(uint32_t format) {
+        switch (format) {
+        case SPICE_SURFACE_FMT_16_555:
+            return RedPixmap::RGB16_555;
+        case SPICE_SURFACE_FMT_16_565:
+            return RedPixmap::RGB16_565;
+        case SPICE_SURFACE_FMT_32_xRGB:
+            return RedPixmap::RGB32;
+        case SPICE_SURFACE_FMT_32_ARGB:
+            return RedPixmap::ARGB32;
+        default:
+            THROW("Unsupported RedPixman format");
+        }
+    }
+
+    RedPixmap(int width, int height, Format format, bool top_bottom);
     virtual ~RedPixmap();
 
     virtual SpicePoint get_size() { SpicePoint pt = {_width, _height}; return pt;}
diff --git a/client/red_pixmap_cairo.h b/client/red_pixmap_cairo.h
index 3f89db8..7f9523e 100644
--- a/client/red_pixmap_cairo.h
+++ b/client/red_pixmap_cairo.h
@@ -23,8 +23,7 @@
 
 class RedPixmapCairo: public RedPixmap {
 public:
-    RedPixmapCairo(int width, int height, Format format, bool top_bottom,
-                   rgb32_t *pallete, RedWindow *win);
+    RedPixmapCairo(int width, int height, Format format, bool top_bottom, RedWindow *win);
     ~RedPixmapCairo();
 };
 
diff --git a/client/red_pixmap_gdi.h b/client/red_pixmap_gdi.h
index 9e10adc..524e6f3 100644
--- a/client/red_pixmap_gdi.h
+++ b/client/red_pixmap_gdi.h
@@ -25,8 +25,7 @@ class RecurciveMutex;
 
 class RedPixmapGdi: public RedPixmap {
 public:
-    RedPixmapGdi(int width, int height, Format format, bool top_bottom,
-                 rgb32_t *pallete);
+    RedPixmapGdi(int width, int height, Format format, bool top_bottom);
     HDC get_dc();
     void *get_memptr();
     ~RedPixmapGdi();
diff --git a/client/red_pixmap_gl.h b/client/red_pixmap_gl.h
index f322d52..f7a14af 100644
--- a/client/red_pixmap_gl.h
+++ b/client/red_pixmap_gl.h
@@ -29,7 +29,7 @@ enum RenderType {
 class RedPixmapGL: public RedPixmap {
 public:
     RedPixmapGL(int width, int height, Format format, bool top_bottom,
-                rgb32_t *pallete, RedWindow *win, RenderType rendertype);
+                RedWindow *win, RenderType rendertype);
 
     void textures_lost();
     void touch_context();
diff --git a/client/screen.cpp b/client/screen.cpp
index f31a9a6..7edca12 100644
--- a/client/screen.cpp
+++ b/client/screen.cpp
@@ -172,7 +172,7 @@ void RedScreen::create_composit_area()
 {
     destroy_composit_area();
     _composit_area = new RedPixmapCairo(_size.x, _size.y, RedPixmap::RGB32,
-                                        false, NULL, NULL);
+                                        false, NULL);
 }
 
 void RedScreen::adjust_window_rect(int x, int y)
diff --git a/client/windows/red_pixmap.cpp b/client/windows/red_pixmap.cpp
index 1ec41fa..574d285 100644
--- a/client/windows/red_pixmap.cpp
+++ b/client/windows/red_pixmap.cpp
@@ -21,11 +21,11 @@
 #include "utils.h"
 
 RedPixmap::RedPixmap(int width, int height, RedPixmap::Format format,
-                     bool top_bottom, rgb32_t* pallet)
+                     bool top_bottom)
     : _format (format)
     , _width (width)
     , _height (height)
-    , _stride (SPICE_ALIGN(width * (_format == RedPixmap::A1 ? 1: 32), 32) / 8)
+    , _stride (SPICE_ALIGN(width * format_to_bpp(format), 32) / 8)
     , _top_bottom (top_bottom)
     , _data (NULL)
 {
diff --git a/client/windows/red_pixmap_cairo.cpp b/client/windows/red_pixmap_cairo.cpp
index 6ed5806..793d21e 100644
--- a/client/windows/red_pixmap_cairo.cpp
+++ b/client/windows/red_pixmap_cairo.cpp
@@ -29,14 +29,9 @@ struct RedPixmap_p {
     HBITMAP prev_bitmap;
 };
 
-static inline int format_to_bpp(RedPixmap::Format format)
-{
-    return ((format == RedPixmap::A1) ? 1 : 32);
-}
-
-RedPixmapCairo::RedPixmapCairo(int width, int height, RedPixmap::Format format, bool top_bottom,
-                               rgb32_t* pallet, RedWindow *win)
-    : RedPixmap(width, height, format, top_bottom, pallet)
+RedPixmapCairo::RedPixmapCairo(int width, int height, RedPixmap::Format format,
+                               bool top_bottom, RedWindow *win)
+    : RedPixmap(width, height, format, top_bottom)
 {
     ASSERT(format == RedPixmap::ARGB32 || format == RedPixmap::RGB32 || format == RedPixmap::A1);
     ASSERT(sizeof(RedPixmap_p) <= PIXELES_SOURCE_OPAQUE_SIZE);
@@ -65,15 +60,16 @@ RedPixmapCairo::RedPixmapCairo(int width, int height, RedPixmap::Format format,
 #endif*/
 
     bitmap_info.inf.bmiHeader.biPlanes = 1;
-    bitmap_info.inf.bmiHeader.biBitCount = format_to_bpp(format);
+    bitmap_info.inf.bmiHeader.biBitCount = RedPixmap::format_to_bpp(format);
     bitmap_info.inf.bmiHeader.biCompression = BI_RGB;
     switch (format) {
     case RedPixmap::A1:
-        for (int i = 0; i < (1 << format_to_bpp(format)); i++) {
-            bitmap_info.inf.bmiColors[i].rgbRed = rgb32_get_red(pallet[i]);
-            bitmap_info.inf.bmiColors[i].rgbGreen = rgb32_get_green(pallet[i]);
-            bitmap_info.inf.bmiColors[i].rgbBlue = rgb32_get_blue(pallet[i]);
-        }
+        bitmap_info.inf.bmiColors[0].rgbRed = 0;
+        bitmap_info.inf.bmiColors[0].rgbGreen = 0;
+        bitmap_info.inf.bmiColors[0].rgbBlue = 0;
+        bitmap_info.inf.bmiColors[1].rgbRed = 0xff;
+        bitmap_info.inf.bmiColors[1].rgbGreen = 0xff;
+        bitmap_info.inf.bmiColors[1].rgbBlue = 0xff;
         break;
     }
     AutoDC dc(create_compatible_dc());
diff --git a/client/windows/red_pixmap_gdi.cpp b/client/windows/red_pixmap_gdi.cpp
index d4913c4..1c90f3d 100644
--- a/client/windows/red_pixmap_gdi.cpp
+++ b/client/windows/red_pixmap_gdi.cpp
@@ -29,13 +29,7 @@ struct RedPixmap_p {
     HBITMAP prev_bitmap;
 };
 
-static inline int format_to_bpp(RedPixmap::Format format)
-{
-    return ((format == RedPixmap::A1) ? 1 : 32);
-}
-
-RedPixmapGdi::RedPixmapGdi(int width, int height, RedPixmap::Format format, bool top_bottom,
-                           rgb32_t* pallet)
+RedPixmapGdi::RedPixmapGdi(int width, int height, RedPixmap::Format format, bool top_bottom)
     : RedPixmap(width, height, format, top_bottom, pallet)
 {
     ASSERT(format == RedPixmap::ARGB32 || format == RedPixmap::RGB32 || format == RedPixmap::A1);
@@ -52,15 +46,16 @@ RedPixmapGdi::RedPixmapGdi(int width, int height, RedPixmap::Format format, bool
     bitmap_info.inf.bmiHeader.biHeight = top_bottom ? -_height : _height;
 
     bitmap_info.inf.bmiHeader.biPlanes = 1;
-    bitmap_info.inf.bmiHeader.biBitCount = format_to_bpp(format);
+    bitmap_info.inf.bmiHeader.biBitCount = RedPixmap::format_to_bpp(format);
     bitmap_info.inf.bmiHeader.biCompression = BI_RGB;
     switch (format) {
     case RedPixmap::A1:
-        for (int i = 0; i < (1 << format_to_bpp(format)); i++) {
-            bitmap_info.inf.bmiColors[i].rgbRed = rgb32_get_red(pallet[i]);
-            bitmap_info.inf.bmiColors[i].rgbGreen = rgb32_get_green(pallet[i]);
-            bitmap_info.inf.bmiColors[i].rgbBlue = rgb32_get_blue(pallet[i]);
-        }
+        bitmap_info.inf.bmiColors[0].rgbRed = 0;
+        bitmap_info.inf.bmiColors[0].rgbGreen = 0;
+        bitmap_info.inf.bmiColors[0].rgbBlue = 0;
+        bitmap_info.inf.bmiColors[1].rgbRed = 0xff;
+        bitmap_info.inf.bmiColors[1].rgbGreen = 0xff;
+        bitmap_info.inf.bmiColors[1].rgbBlue = 0xff;
         break;
     }
     AutoDC dc(create_compatible_dc());
diff --git a/client/x11/red_pixmap.cpp b/client/x11/red_pixmap.cpp
index 09455dd..2a0eb99 100644
--- a/client/x11/red_pixmap.cpp
+++ b/client/x11/red_pixmap.cpp
@@ -21,11 +21,11 @@
 #include "utils.h"
 
 RedPixmap::RedPixmap(int width, int height, RedPixmap::Format format,
-                     bool top_bottom, rgb32_t* pallet)
+                     bool top_bottom)
     : _format (format)
     , _width (width)
     , _height (height)
-    , _stride (SPICE_ALIGN(width * (_format == RedPixmap::A1 ? 1 : 32), 32) / 8)
+    , _stride (SPICE_ALIGN(width * format_to_bpp(format), 32) / 8)
     , _top_bottom (top_bottom)
     , _data (NULL)
 {
diff --git a/client/x11/red_pixmap_cairo.cpp b/client/x11/red_pixmap_cairo.cpp
index e73b8b4..1974ebc 100644
--- a/client/x11/red_pixmap_cairo.cpp
+++ b/client/x11/red_pixmap_cairo.cpp
@@ -26,10 +26,12 @@
 
 
 RedPixmapCairo::RedPixmapCairo(int width, int height, RedPixmap::Format format,
-                               bool top_bottom, rgb32_t* pallet, RedWindow *win)
-    : RedPixmap(width, height, format, top_bottom, pallet)
+                               bool top_bottom, RedWindow *win)
+    : RedPixmap(width, height, format, top_bottom)
 {
-    ASSERT(format == RedPixmap::ARGB32 || format == RedPixmap::RGB32 || format == RedPixmap::A1);
+    ASSERT(format == RedPixmap::ARGB32 || format == RedPixmap::RGB32 ||
+	   format == RedPixmap::RGB16_555 || format == RedPixmap::RGB16_565 ||
+	   format == RedPixmap::A1);
     ASSERT(sizeof(RedDrawable_p) <= PIXELES_SOURCE_OPAQUE_SIZE);
     pixman_image_t *pixman_image;
     XImage *image = NULL;
@@ -49,22 +51,8 @@ RedPixmapCairo::RedPixmapCairo(int width, int height, RedPixmap::Format format,
         using_shm = vinfo && XPlatform::is_x_shm_avail();
 
         if (using_shm) {
-            int depth;
-
-            switch (format) {
-            case RedPixmap::ARGB32:
-            case RedPixmap::RGB32:
-                depth = XPlatform::get_vinfo()[0]->depth;
-                pixman_format = format == RedPixmap::ARGB32 ? PIXMAN_a8r8g8b8 :
-                                                             PIXMAN_x8r8g8b8;
-                break;
-            case RedPixmap::A1:
-                depth = 1;
-                pixman_format = PIXMAN_a1;
-                break;
-            default:
-                THROW("unsupported format %d", format);
-            }
+            int depth = RedPixmap::format_to_bpp(format);
+            pixman_format = RedPixmap::format_to_pixman(format);
 
             shminfo = new XShmSegmentInfo;
             shminfo->shmid = -1;
diff --git a/client/x11/red_pixmap_gl.cpp b/client/x11/red_pixmap_gl.cpp
index 2722476..a309651 100644
--- a/client/x11/red_pixmap_gl.cpp
+++ b/client/x11/red_pixmap_gl.cpp
@@ -31,9 +31,9 @@
 
 
 RedPixmapGL::RedPixmapGL(int width, int height, RedPixmap::Format format,
-                         bool top_bottom, rgb32_t* pallet, RedWindow *win,
+                         bool top_bottom, RedWindow *win,
                          RenderType rendertype)
-    : RedPixmap(width, height, format, top_bottom, pallet)
+    : RedPixmap(width, height, format, top_bottom)
 {
     GLuint fbo;
     GLuint tex;
diff --git a/common/cairo_canvas.c b/common/cairo_canvas.c
index 38a7081..fde43d7 100644
--- a/common/cairo_canvas.c
+++ b/common/cairo_canvas.c
@@ -1074,7 +1074,8 @@ static void canvas_destroy(SpiceCanvas *spice_canvas)
 static int need_init = 1;
 static SpiceCanvasOps cairo_canvas_ops;
 
-SpiceCanvas *canvas_create(pixman_image_t *image, int bits
+static SpiceCanvas *canvas_create_common(pixman_image_t *image,
+                                         uint32_t format
 #ifdef CAIRO_CANVAS_CACHE
                            , SpiceImageCache *bits_cache
                            , SpicePaletteCache *palette_cache
@@ -1098,7 +1099,7 @@ SpiceCanvas *canvas_create(pixman_image_t *image, int bits
     init_ok = canvas_base_init(&canvas->base, &cairo_canvas_ops,
                                pixman_image_get_width (image),
                                pixman_image_get_height (image),
-                               bits
+                               format
 #ifdef CAIRO_CANVAS_CACHE
                                , bits_cache
                                , palette_cache
@@ -1114,11 +1115,80 @@ SpiceCanvas *canvas_create(pixman_image_t *image, int bits
     canvas->private_data = NULL;
     canvas->private_data_size = 0;
 
-    canvas->image = pixman_image_ref(image);
+    canvas->image = image;
 
     return (SpiceCanvas *)canvas;
 }
 
+SpiceCanvas *canvas_create(int width, int height, uint32_t format
+#ifdef CAIRO_CANVAS_CACHE
+                           , SpiceImageCache *bits_cache
+                           , SpicePaletteCache *palette_cache
+#elif defined(CAIRO_CANVAS_IMAGE_CACHE)
+                           , SpiceImageCache *bits_cache
+#endif
+                           , SpiceImageSurfaces *surfaces
+                           , SpiceGlzDecoder *glz_decoder
+#ifndef CAIRO_CANVAS_NO_CHUNKS
+                           , SpiceVirtMapping *virt_mapping
+#endif
+                           )
+{
+    pixman_image_t *image;
+
+    image = pixman_image_create_bits(spice_surface_format_to_pixman (format),
+                                     width, height, NULL, 0);
+
+    return canvas_create_common(image, format
+#ifdef CAIRO_CANVAS_CACHE
+                                , bits_cache
+                                , palette_cache
+#elif defined(CAIRO_CANVAS_IMAGE_CACHE)
+                                , bits_cache
+#endif
+                                , surfaces
+                                , glz_decoder
+#ifndef CAIRO_CANVAS_NO_CHUNKS
+                                , virt_mapping
+#endif
+                                );
+}
+
+SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format,
+                                    uint8_t *data, size_t stride
+#ifdef CAIRO_CANVAS_CACHE
+                           , SpiceImageCache *bits_cache
+                           , SpicePaletteCache *palette_cache
+#elif defined(CAIRO_CANVAS_IMAGE_CACHE)
+                           , SpiceImageCache *bits_cache
+#endif
+			   , SpiceImageSurfaces *surfaces
+                           , SpiceGlzDecoder *glz_decoder
+#ifndef CAIRO_CANVAS_NO_CHUNKS
+                           , SpiceVirtMapping *virt_mapping
+#endif
+                           )
+{
+    pixman_image_t *image;
+
+    image = pixman_image_create_bits(spice_surface_format_to_pixman (format),
+                                     width, height, (uint32_t *)data, stride);
+
+    return canvas_create_common(image, format
+#ifdef CAIRO_CANVAS_CACHE
+                                , bits_cache
+                                , palette_cache
+#elif defined(CAIRO_CANVAS_IMAGE_CACHE)
+                                , bits_cache
+#endif
+                                , surfaces
+                                , glz_decoder
+#ifndef CAIRO_CANVAS_NO_CHUNKS
+                                , virt_mapping
+#endif
+                                );
+}
+
 void cairo_canvas_init() //unsafe global function
 {
     if (!need_init) {
diff --git a/common/cairo_canvas.h b/common/cairo_canvas.h
index 7f882b2..c97380e 100644
--- a/common/cairo_canvas.h
+++ b/common/cairo_canvas.h
@@ -26,7 +26,7 @@
 #include "canvas_base.h"
 #include "region.h"
 
-SpiceCanvas *canvas_create(pixman_image_t *image, int bits
+SpiceCanvas *canvas_create(int width, int height, uint32_t format
 #ifdef CAIRO_CANVAS_CACHE
                            , SpiceImageCache *bits_cache
                            , SpicePaletteCache *palette_cache
@@ -40,6 +40,21 @@ SpiceCanvas *canvas_create(pixman_image_t *image, int bits
 #endif
                            );
 
+SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint8_t *data, size_t stride
+#ifdef CAIRO_CANVAS_CACHE
+                           , SpiceImageCache *bits_cache
+                           , SpicePaletteCache *palette_cache
+#elif defined(CAIRO_CANVAS_IMAGE_CACHE)
+                           , SpiceImageCache *bits_cache
+#endif
+			   , SpiceImageSurfaces *surfaces
+                           , SpiceGlzDecoder *glz_decoder
+#ifndef CAIRO_CANVAS_NO_CHUNKS
+                           , SpiceVirtMapping *virt_mapping
+#endif
+                           );
+
+
 void cairo_canvas_init();
 
 #endif
diff --git a/common/canvas_base.c b/common/canvas_base.c
index 9852da9..fb101fd 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -176,6 +176,7 @@ typedef struct CanvasBase {
     unsigned long max;
 #endif
 
+    uint32_t format;
     int width;
     int height;
     pixman_region32_t canvas_region;
@@ -3175,7 +3176,7 @@ inline static void canvas_base_init_ops(SpiceCanvasOps *ops)
 }
 
 static int canvas_base_init(CanvasBase *canvas, SpiceCanvasOps *ops,
-                            int width, int height, int depth
+                            int width, int height, uint32_t format
 #ifdef CAIRO_CANVAS_CACHE
                             , SpiceImageCache *bits_cache
                             , SpicePaletteCache *palette_cache
@@ -3218,7 +3219,10 @@ static int canvas_base_init(CanvasBase *canvas, SpiceCanvasOps *ops,
     canvas->surfaces = surfaces;
     canvas->glz_data.decoder = glz_decoder;
 
-    if (depth == 16) {
+    canvas->format = format;
+
+    /* TODO: This is all wrong now */
+    if (SPICE_SURFACE_FMT_DEPTH(format) == 16) {
         canvas->color_shift = 5;
         canvas->color_mask = 0x1f;
     } else {
diff --git a/common/canvas_utils.c b/common/canvas_utils.c
index 1e97e87..4f2456d 100644
--- a/common/canvas_utils.c
+++ b/common/canvas_utils.c
@@ -175,6 +175,11 @@ pixman_image_t * surface_create(pixman_format_code_t format, int width, int heig
             bitmap_info.inf.bmiHeader.biBitCount = 32;
             nstride = width * 4;
             break;
+        case PIXMAN_x1r5g5b5:
+        case PIXMAN_r5g6b5:
+            bitmap_info.inf.bmiHeader.biBitCount = 16;
+            nstride = SPICE_ALIGN(width * 2, 4);
+            break;
         case PIXMAN_a8:
             bitmap_info.inf.bmiHeader.biBitCount = 8;
             nstride = SPICE_ALIGN(width, 4);
@@ -237,6 +242,10 @@ pixman_image_t * surface_create(pixman_format_code_t format, int width, int heig
         case PIXMAN_x8r8g8b8:
             stride = width * 4;
             break;
+        case PIXMAN_x1r5g5b5:
+        case PIXMAN_r5g6b5:
+            stride = SPICE_ALIGN(width * 2, 4);
+            break;
         case PIXMAN_a8:
             stride = SPICE_ALIGN(width, 4);
             break;
diff --git a/common/gdi_canvas.c b/common/gdi_canvas.c
index ead94af..c600419 100644
--- a/common/gdi_canvas.c
+++ b/common/gdi_canvas.c
@@ -1884,7 +1884,7 @@ static int need_init = 1;
 static SpiceCanvasOps gdi_canvas_ops;
 
 SpiceCanvas *gdi_canvas_create(int width, int height,
-                               HDC dc, RecurciveMutex* lock, int bits
+                               HDC dc, RecurciveMutex* lock, uint32_t format
 #ifdef CAIRO_CANVAS_CACHE
                              , SpiceImageCache *bits_cache
                              , SpicePaletteCache *palette_cache
@@ -1903,7 +1903,7 @@ SpiceCanvas *gdi_canvas_create(int width, int height,
     }
     canvas = spice_new0(GdiCanvas, 1);
     init_ok = canvas_base_init(&canvas->base, &gdi_canvas_ops,
-                               width, height, bits
+                               width, height, format
 #ifdef CAIRO_CANVAS_CACHE
                                ,bits_cache
                                ,palette_cache
diff --git a/common/gdi_canvas.h b/common/gdi_canvas.h
index 43da189..13d82ef 100644
--- a/common/gdi_canvas.h
+++ b/common/gdi_canvas.h
@@ -34,7 +34,7 @@ typedef struct {
 } GdiImage;
 
 SpiceCanvas *gdi_canvas_create(int width, int height,
-                               HDC dc, class RecurciveMutex *lock, int bits,
+                               HDC dc, class RecurciveMutex *lock, uint32_t format,
                                SpiceImageCache *bits_cache,
                                SpicePaletteCache *palette_cache,
 			       SpiceImageSurfaces *surfaces,
diff --git a/common/gl_canvas.c b/common/gl_canvas.c
index dd470bc..9b017fa 100644
--- a/common/gl_canvas.c
+++ b/common/gl_canvas.c
@@ -821,7 +821,7 @@ static void gl_canvas_set_access_params(SpiceCanvas *spice_canvas, unsigned long
 static int need_init = 1;
 static SpiceCanvasOps gl_canvas_ops;
 
-SpiceCanvas *gl_canvas_create(int width, int height, int depth
+SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
 #ifdef CAIRO_CANVAS_CACHE
                               , SpiceImageCache *bits_cache
                               , SpicePaletteCache *palette_cache
@@ -848,7 +848,7 @@ SpiceCanvas *gl_canvas_create(int width, int height, int depth
     }
     canvas->private_data = NULL;
     init_ok = canvas_base_init(&canvas->base, &gl_canvas_ops,
-                               width, height, depth
+                               width, height, format
 #ifdef CAIRO_CANVAS_CACHE
                                , bits_cache
                                , palette_cache
diff --git a/common/gl_canvas.h b/common/gl_canvas.h
index 7c54cbf..615ca89 100644
--- a/common/gl_canvas.h
+++ b/common/gl_canvas.h
@@ -21,7 +21,7 @@
 #include "canvas_base.h"
 #include "region.h"
 
-SpiceCanvas *gl_canvas_create(int width, int height, int depth
+SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
 #ifdef CAIRO_CANVAS_CACHE
                            , SpiceImageCache *bits_cache
                            , SpicePaletteCache *palette_cache
diff --git a/server/red_worker.c b/server/red_worker.c
index 2892728..af3a888 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -7795,25 +7795,6 @@ static void red_migrate_display(RedWorker *worker)
     }
 }
 
-static SpiceCanvas *create_cairo_context(RedWorker *worker, uint32_t width, uint32_t height,
-                                         int32_t stride, uint8_t depth, void *line_0)
-{
-    SpiceCanvas *canvas;
-    pixman_image_t *surface;
-
-    surface = pixman_image_create_bits(PIXMAN_x8r8g8b8, width, height,
-                                       (uint32_t *)line_0,
-                                       stride);
-    if (surface == NULL) {
-        red_error("create cairo surface failed");
-    }
-    canvas = canvas_create(surface, depth, &worker->image_cache.base,
-                           &worker->image_surfaces, NULL,
-                           &worker->preload_group_virt_mapping);
-    pixman_image_unref (surface);
-    return canvas;
-}
-
 static SpiceCanvas *create_ogl_context_common(RedWorker *worker, OGLCtx *ctx, uint32_t width,
                                               uint32_t height, int32_t stride, uint8_t depth)
 {
@@ -7870,22 +7851,28 @@ static SpiceCanvas *create_ogl_pixmap_context(RedWorker *worker, uint32_t width,
 
 static inline void *create_canvas_for_surface(RedWorker *worker, RedSurface *surface,
                                               uint32_t renderer, uint32_t width, uint32_t height,
-                                              int32_t stride, uint8_t depth, void *line_0)
+                                              int32_t stride, uint32_t format, void *line_0)
 {
     SpiceCanvas *canvas;
 
     switch (renderer) {
     case RED_RENDERER_CAIRO:
-        canvas = create_cairo_context(worker, width, height, stride, depth, line_0);
+        canvas = canvas_create_for_data(width, height, format,
+                                        line_0, stride,
+                                        &worker->image_cache.base,
+                                        &worker->image_surfaces, NULL,
+                                        &worker->preload_group_virt_mapping);
         surface->context.top_down = TRUE;
         surface->context.canvas_draws_on_surface = TRUE;
         return canvas;
     case RED_RENDERER_OGL_PBUF:
-        canvas = create_ogl_pbuf_context(worker, width, height, stride, depth);
+        canvas = create_ogl_pbuf_context(worker, width, height, stride,
+                                         SPICE_SURFACE_FMT_DEPTH(format));
         surface->context.top_down = FALSE;
         return canvas;
     case RED_RENDERER_OGL_PIXMAP:
-        canvas = create_ogl_pixmap_context(worker, width, height, stride, depth);
+        canvas = create_ogl_pixmap_context(worker, width, height, stride,
+                                           SPICE_SURFACE_FMT_DEPTH(format));
         surface->context.top_down = FALSE;
         return canvas;
     default:
commit 619c37af17406f77c7cb76f3b72bbfc268383d91
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Apr 21 17:45:07 2010 +0200

    common: Add lookaside storage for pixman image format
    
    Ideally we should just read this from the pixman image, but
    there is no API to do so in stable pixman, so we store it.

diff --git a/common/canvas_utils.c b/common/canvas_utils.c
index 6ffd856..1e97e87 100644
--- a/common/canvas_utils.c
+++ b/common/canvas_utils.c
@@ -82,6 +82,29 @@ pixman_image_add_data(pixman_image_t *image)
     return data;
 }
 
+void
+spice_pixman_image_set_format(pixman_image_t *image,
+                              pixman_format_code_t format)
+{
+    PixmanData *data;
+
+    data = pixman_image_add_data(image);
+    data->format = format;
+}
+
+pixman_format_code_t
+spice_pixman_image_get_format(pixman_image_t *image)
+{
+    PixmanData *data;
+
+    data = (PixmanData *)pixman_image_get_destroy_data(image);
+    if (data != NULL &&
+        data->format != 0)
+        return data->format;
+
+    CANVAS_ERROR("Unknown pixman image type");
+}
+
 static inline pixman_image_t *__surface_create_stride(pixman_format_code_t format, int width, int height,
                                                       int stride)
 {
@@ -106,6 +129,7 @@ static inline pixman_image_t *__surface_create_stride(pixman_format_code_t forma
 
     pixman_data = pixman_image_add_data(surface);
     pixman_data->data = data;
+    pixman_data->format = format;
 
     return surface;
 }
@@ -190,6 +214,7 @@ pixman_image_t * surface_create(pixman_format_code_t format, int width, int heig
             CANVAS_ERROR("create surface failed, out of memory");
         }
         pixman_data = pixman_image_add_data(surface);
+        pixman_data->format = format;
         pixman_data->bitmap = bitmap;
         pixman_data->mutex = mutex;
         gdi_handlers++;
@@ -197,7 +222,13 @@ pixman_image_t * surface_create(pixman_format_code_t format, int width, int heig
     } else {
 #endif
     if (top_down) {
-        return pixman_image_create_bits(format, width, height, NULL, 0);
+        pixman_image_t *surface;
+        PixmanData *data;
+
+        surface = pixman_image_create_bits(format, width, height, NULL, 0);
+        data = pixman_image_add_data(surface);
+        data->format = format;
+        return surface;
     } else {
         // NOTE: we assume here that the lz decoders always decode to RGB32.
         int stride = 0;
diff --git a/common/canvas_utils.h b/common/canvas_utils.h
index 1c78ffa..b81a6f9 100644
--- a/common/canvas_utils.h
+++ b/common/canvas_utils.h
@@ -30,8 +30,14 @@ typedef struct PixmanData {
     HANDLE mutex;
 #endif
     uint8_t *data;
+    pixman_format_code_t format;
 } PixmanData;
 
+void spice_pixman_image_set_format(pixman_image_t *image,
+                                   pixman_format_code_t format);
+pixman_format_code_t spice_pixman_image_get_format(pixman_image_t *image);
+
+
 #ifdef WIN32
 pixman_image_t *surface_create(HDC dc, pixman_format_code_t format,
                                int width, int height, int top_down);
commit 6dc52f1389b6b1c6ce2589ff183982d65c8c1581
Author: Alexander Larsson <alexl at redhat.com>
Date:   Mon Apr 19 15:49:20 2010 +0200

    Add pixman utilities for bitmap to pixman_image_t conversion

diff --git a/common/pixman_utils.c b/common/pixman_utils.c
index cbd226a..4ba0c17 100644
--- a/common/pixman_utils.c
+++ b/common/pixman_utils.c
@@ -16,6 +16,7 @@
    License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <config.h>
 #include "pixman_utils.h"
 #include <spice/macros.h>
 
@@ -31,6 +32,13 @@
 }
 #endif
 
+#ifndef PANIC
+#define PANIC(str) {                                \
+    printf("%s: panic: %s", __FUNCTION__, str);     \
+    abort();                                        \
+}
+#endif
+
 #define SOLID_RASTER_OP(_name, _size, _type, _equation)  \
 static void                                        \
 solid_rop_ ## _name ## _ ## _size (_type *ptr, int len, _type src)  \
@@ -176,6 +184,24 @@ ROP_TABLE(uint8_t, 8)
 ROP_TABLE(uint16_t, 16)
 ROP_TABLE(uint32_t, 32)
 
+/* We can't get the real bits per pixel info from pixman_image_t,
+   only the DEPTH which is the sum of all a+r+g+b bits, which
+   is e.g. 24 for 32bit xRGB. We really want the bpp, so
+   we have this ugly conversion thing */
+int spice_pixman_image_get_bpp(pixman_image_t *image)
+{
+    int depth;
+
+    depth = pixman_image_get_depth(image);
+    if (depth == 24) {
+        return 32;
+    }
+    if (depth == 15) {
+        return 16;
+    }
+    return depth;
+}
+
 void spice_pixman_fill_rect(pixman_image_t *dest,
                             int x, int y,
                             int width, int height,
@@ -188,7 +214,7 @@ void spice_pixman_fill_rect(pixman_image_t *dest,
 
     bits = pixman_image_get_data(dest);
     stride = pixman_image_get_stride(dest);
-    depth = pixman_image_get_depth(dest);
+    depth = spice_pixman_image_get_bpp(dest);
     /* stride is in bytes, depth in bits */
 
     ASSERT(x >= 0);
@@ -198,10 +224,6 @@ void spice_pixman_fill_rect(pixman_image_t *dest,
     ASSERT(x + width <= pixman_image_get_width(dest));
     ASSERT(y + height <= pixman_image_get_height(dest));
 
-    if (depth == 24) {
-        depth = 32; /* Needed for pixman_fill */
-    }
-
     if (pixman_fill(bits,
                     stride / 4,
                     depth,
@@ -220,7 +242,7 @@ void spice_pixman_fill_rect(pixman_image_t *dest,
         byte_width = 2 * width;
         value = (value & 0xffff) * 0x00010001;
     } else {
-        ASSERT (depth == 32 || depth == 24)
+        ASSERT (depth == 32)
         byte_line = ((uint8_t *)bits) + stride * y + x * 4;
         byte_width = 4 * width;
     }
@@ -284,7 +306,7 @@ void spice_pixman_fill_rect_rop(pixman_image_t *dest,
 
     bits = pixman_image_get_data(dest);
     stride = pixman_image_get_stride(dest);
-    depth = pixman_image_get_depth(dest);
+    depth = spice_pixman_image_get_bpp(dest);
     /* stride is in bytes, depth in bits */
 
     ASSERT(x >= 0);
@@ -315,8 +337,6 @@ void spice_pixman_fill_rect_rop(pixman_image_t *dest,
     }  else {
         solid_rop_32_func_t rop_func = solid_rops_32[rop];
 
-        ASSERT (depth == 32 || depth == 24);
-
         byte_line = ((uint8_t *)bits) + stride * y + x * 4;
         while (height--) {
             rop_func((uint32_t *)byte_line, width, (uint32_t)value);
@@ -341,7 +361,7 @@ void spice_pixman_tile_rect(pixman_image_t *dest,
 
     bits = pixman_image_get_data(dest);
     stride = pixman_image_get_stride(dest);
-    depth = pixman_image_get_depth(dest);
+    depth = spice_pixman_image_get_bpp(dest);
     /* stride is in bytes, depth in bits */
 
     tile_bits = pixman_image_get_data(tile);
@@ -355,7 +375,7 @@ void spice_pixman_tile_rect(pixman_image_t *dest,
     ASSERT(height > 0);
     ASSERT(x + width <= pixman_image_get_width(dest));
     ASSERT(y + height <= pixman_image_get_height(dest));
-    ASSERT(depth == pixman_image_get_depth(tile));
+    ASSERT(depth == spice_pixman_image_get_bpp(tile));
 
     tile_start_x = (x - offset_x) % tile_width;
     if (tile_start_x < 0) {
@@ -397,7 +417,7 @@ void spice_pixman_tile_rect(pixman_image_t *dest,
             }
         }
     }  else {
-        ASSERT (depth == 32 || depth == 24);
+        ASSERT (depth == 32);
 
         byte_line = ((uint8_t *)bits) + stride * y + x * 4;
         tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 4;
@@ -432,7 +452,7 @@ void spice_pixman_tile_rect_rop(pixman_image_t *dest,
 
     bits = pixman_image_get_data(dest);
     stride = pixman_image_get_stride(dest);
-    depth = pixman_image_get_depth(dest);
+    depth = spice_pixman_image_get_bpp(dest);
     /* stride is in bytes, depth in bits */
 
     tile_bits = pixman_image_get_data(tile);
@@ -447,7 +467,7 @@ void spice_pixman_tile_rect_rop(pixman_image_t *dest,
     ASSERT(x + width <= pixman_image_get_width(dest));
     ASSERT(y + height <= pixman_image_get_height(dest));
     ASSERT(rop >= 0 && rop < 16);
-    ASSERT(depth == pixman_image_get_depth(tile));
+    ASSERT(depth == spice_pixman_image_get_bpp(tile));
 
     tile_start_x = (x - offset_x) % tile_width;
     if (tile_start_x < 0) {
@@ -495,7 +515,7 @@ void spice_pixman_tile_rect_rop(pixman_image_t *dest,
     }  else {
         tiled_rop_32_func_t rop_func = tiled_rops_32[rop];
 
-        ASSERT (depth == 32 || depth == 24);
+        ASSERT (depth == 32);
 
         byte_line = ((uint8_t *)bits) + stride * y + x * 4;
         tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 4;
@@ -529,22 +549,14 @@ void spice_pixman_blit(pixman_image_t *dest,
 
     bits = pixman_image_get_data(dest);
     stride = pixman_image_get_stride(dest);
-    depth = pixman_image_get_depth(dest);
+    depth = spice_pixman_image_get_bpp(dest);
     /* stride is in bytes, depth in bits */
 
-    if (depth == 24) {
-        depth = 32; /* Needed for pixman_blt */
-    }
-
     src_bits = pixman_image_get_data(src);
     src_stride = pixman_image_get_stride(src);
     src_width = pixman_image_get_width(src);
     src_height = pixman_image_get_height(src);
-    src_depth = pixman_image_get_depth(src);
-
-    if (src_depth == 24) {
-        src_depth = 32; /* Needed for pixman_blt */
-    }
+    src_depth = spice_pixman_image_get_bpp(src);
 
     /* Clip source */
     if (src_x < 0) {
@@ -600,7 +612,7 @@ void spice_pixman_blit(pixman_image_t *dest,
         byte_width = width * 2;
         src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 2;
     }  else {
-        ASSERT (depth == 32 || depth == 24);
+        ASSERT (depth == 32);
         byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
         byte_width = width * 4;
         src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
@@ -628,22 +640,14 @@ void spice_pixman_blit_rop (pixman_image_t *dest,
 
     bits = pixman_image_get_data(dest);
     stride = pixman_image_get_stride(dest);
-    depth = pixman_image_get_depth(dest);
+    depth = spice_pixman_image_get_bpp(dest);
     /* stride is in bytes, depth in bits */
 
-    if (depth == 24) {
-        depth = 32; /* Needed for pixman_blt */
-    }
-
     src_bits = pixman_image_get_data(src);
     src_stride = pixman_image_get_stride(src);
     src_width = pixman_image_get_width(src);
     src_height = pixman_image_get_height(src);
-    src_depth = pixman_image_get_depth(src);
-
-    if (src_depth == 24) {
-        src_depth = 32; /* Needed for pixman_blt */
-    }
+    src_depth = spice_pixman_image_get_bpp(src);
 
     /* Clip source */
     if (src_x < 0) {
@@ -704,7 +708,7 @@ void spice_pixman_blit_rop (pixman_image_t *dest,
     }  else {
         copy_rop_32_func_t rop_func = copy_rops_32[rop];
 
-        ASSERT (depth == 32 || depth == 24);
+        ASSERT (depth == 32);
         byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
         src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
 
@@ -733,7 +737,7 @@ void spice_pixman_blit_colorkey (pixman_image_t *dest,
 
     bits = pixman_image_get_data(dest);
     stride = pixman_image_get_stride(dest);
-    depth = pixman_image_get_depth(dest);
+    depth = spice_pixman_image_get_bpp(dest);
     /* stride is in bytes, depth in bits */
 
     src_bits = pixman_image_get_data(src);
@@ -773,7 +777,7 @@ void spice_pixman_blit_colorkey (pixman_image_t *dest,
     ASSERT(dest_y + height <= pixman_image_get_height(dest));
     ASSERT(src_x + width <= pixman_image_get_width(src));
     ASSERT(src_y + height <= pixman_image_get_height(src));
-    ASSERT(depth == pixman_image_get_depth(src));
+    ASSERT(depth == spice_pixman_image_get_bpp(src));
 
     if (depth == 8) {
         byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x;
@@ -816,7 +820,7 @@ void spice_pixman_blit_colorkey (pixman_image_t *dest,
             src_line += src_stride;
         }
     }  else {
-        ASSERT (depth == 32 || depth == 24);
+        ASSERT (depth == 32);
         byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
         src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
 
@@ -840,43 +844,43 @@ void spice_pixman_blit_colorkey (pixman_image_t *dest,
     }
 }
 
-static void copy_bits_up(uint8_t *data, const int stride,
+static void copy_bits_up(uint8_t *data, const int stride, int bpp,
                          const int src_x, const int src_y,
                          const int width, const int height,
                          const int dest_x, const int dest_y)
 {
-    uint8_t *src = data + src_y * stride + src_x * sizeof(uint32_t);
-    uint8_t *dest = data + dest_y * stride + dest_x * sizeof(uint32_t);
+    uint8_t *src = data + src_y * stride + src_x * bpp;
+    uint8_t *dest = data + dest_y * stride + dest_x * bpp;
     uint8_t *end = dest + height * stride;
     for (; dest != end; dest += stride, src += stride) {
-        memcpy(dest, src, width * sizeof(uint32_t));
+        memcpy(dest, src, width * bpp);
     }
 }
 
-static void copy_bits_down(uint8_t *data, const int stride,
+static void copy_bits_down(uint8_t *data, const int stride, int bpp,
                            const int src_x, const int src_y,
                            const int width, const int height,
                            const int dest_x, const int dest_y)
 {
-    uint8_t *src = data + (src_y + height - 1) * stride + src_x * sizeof(uint32_t);
-    uint8_t *end = data + (dest_y - 1) * stride + dest_x * sizeof(uint32_t);
+    uint8_t *src = data + (src_y + height - 1) * stride + src_x * bpp;
+    uint8_t *end = data + (dest_y - 1) * stride + dest_x * bpp;
     uint8_t *dest = end + height * stride;
 
     for (; dest != end; dest -= stride, src -= stride) {
-        memcpy(dest, src, width * sizeof(uint32_t));
+        memcpy(dest, src, width * bpp);
     }
 }
 
-static void copy_bits_same_line(uint8_t *data, const int stride,
+static void copy_bits_same_line(uint8_t *data, const int stride, int bpp,
                                 const int src_x, const int src_y,
                                 const int width, const int height,
                                 const int dest_x, const int dest_y)
 {
-    uint8_t *src = data + src_y * stride + src_x * sizeof(uint32_t);
-    uint8_t *dest = data + dest_y * stride + dest_x * sizeof(uint32_t);
+    uint8_t *src = data + src_y * stride + src_x * bpp;
+    uint8_t *dest = data + dest_y * stride + dest_x * bpp;
     uint8_t *end = dest + height * stride;
     for (; dest != end; dest += stride, src += stride) {
-        memmove(dest, src, width * sizeof(uint32_t));
+        memmove(dest, src, width * bpp);
     }
 }
 
@@ -887,25 +891,24 @@ void spice_pixman_copy_rect (pixman_image_t *image,
 {
     uint8_t *data;
     int stride;
+    int bpp;
 
     data = (uint8_t *)pixman_image_get_data(image);
     stride = pixman_image_get_stride(image);
-
-    ASSERT(pixman_image_get_depth(image) == 24 ||
-           pixman_image_get_depth(image) == 32);
+    bpp = spice_pixman_image_get_bpp(image) / 8;
 
     if (dest_y > src_y) {
-        copy_bits_down(data, stride,
+        copy_bits_down(data, stride, bpp,
                        src_x, src_y,
                        width, height,
                        dest_x, dest_y);
     } else if (dest_y < src_y) {
-        copy_bits_up(data, stride,
+        copy_bits_up(data, stride, bpp,
                      src_x, src_y,
                      width, height,
                      dest_x, dest_y);
     } else {
-        copy_bits_same_line(data, stride,
+        copy_bits_same_line(data, stride, bpp,
                             src_x, src_y,
                             width, height,
                             dest_x, dest_y);
@@ -945,3 +948,694 @@ pixman_bool_t spice_pixman_region32_init_rects (pixman_region32_t *region,
 
     return res;
 }
+
+pixman_format_code_t spice_surface_format_to_pixman(uint32_t surface_format)
+{
+    switch (surface_format) {
+    case SPICE_SURFACE_FMT_1_A:
+        return PIXMAN_a1;
+    case SPICE_SURFACE_FMT_8_A:
+        return PIXMAN_a8;
+    case SPICE_SURFACE_FMT_16_555:
+        return PIXMAN_x1r5g5b5;
+    case SPICE_SURFACE_FMT_16_565:
+        return PIXMAN_r5g6b5;
+    case SPICE_SURFACE_FMT_32_xRGB:
+        return PIXMAN_x8r8g8b8;
+    case SPICE_SURFACE_FMT_32_ARGB:
+        return PIXMAN_a8r8g8b8;
+    default:
+        printf("Unknown surface format %d\n", surface_format);
+        abort();
+        break;
+    }
+	return (pixman_format_code_t)0; /* Not reached */
+}
+
+/* Returns the "spice native" pixman version of a specific bitmap format.
+ * This isn't bitwise the same as the bitmap format, for instance we
+ * typically convert indexed to real color modes and use the standard
+ * surface modes rather than weird things like 24bit
+ */
+pixman_format_code_t spice_bitmap_format_to_pixman(int bitmap_format,
+                                                   uint32_t palette_surface_format)
+{
+    switch (bitmap_format) {
+    case SPICE_BITMAP_FMT_1BIT_LE:
+    case SPICE_BITMAP_FMT_1BIT_BE:
+    case SPICE_BITMAP_FMT_4BIT_LE:
+    case SPICE_BITMAP_FMT_4BIT_BE:
+    case SPICE_BITMAP_FMT_8BIT:
+        /* Indexed mode palettes are the same as their destination canvas format */
+        return spice_surface_format_to_pixman(palette_surface_format);
+
+    case SPICE_BITMAP_FMT_16BIT:
+        return PIXMAN_x1r5g5b5;
+
+    case SPICE_BITMAP_FMT_24BIT:
+    case SPICE_BITMAP_FMT_32BIT:
+        return PIXMAN_x8r8g8b8;
+
+    case SPICE_BITMAP_FMT_RGBA:
+        return PIXMAN_a8r8g8b8;
+
+    case SPICE_BITMAP_FMT_INVALID:
+    default:
+        printf("Unknown bitmap format %d\n", bitmap_format);
+        abort();
+        return PIXMAN_a8r8g8b8;
+    }
+}
+
+/* Tries to view a spice bitmap as a pixman_image_t without copying,
+ * will often fail due to unhandled formats or strides.
+ */
+pixman_image_t *spice_bitmap_try_as_pixman(int src_format,
+                                           int flags,
+                                           int width,
+                                           int height,
+                                           uint8_t *data,
+                                           int stride)
+{
+    pixman_format_code_t pixman_format;
+
+    /* Pixman stride must be multiple of 4 */
+    if (stride % 4 != 0) {
+        return NULL;
+    }
+
+    switch (src_format) {
+    case SPICE_BITMAP_FMT_32BIT:
+#ifdef WORDS_BIGENDIAN
+        pixman_format = PIXMAN_b8g8r8x8;
+#else
+        pixman_format = PIXMAN_x8r8g8b8;
+#endif
+        break;
+    case SPICE_BITMAP_FMT_RGBA:
+#ifdef WORDS_BIGENDIAN
+        pixman_format = PIXMAN_b8g8r8a8;
+#else
+        pixman_format = PIXMAN_a8r8g8b8;
+#endif
+        break;
+    case SPICE_BITMAP_FMT_24BIT:
+#ifdef WORDS_BIGENDIAN
+        pixman_format = PIXMAN_b8g8r8;
+#else
+        pixman_format = PIXMAN_r8g8b8;
+#endif
+        break;
+    case SPICE_BITMAP_FMT_16BIT:
+#ifdef WORDS_BIGENDIAN
+        return NULL;
+#else
+        pixman_format = PIXMAN_x1r5g5b5;
+#endif
+        break;
+
+    default:
+        return NULL;
+    }
+
+    if (!(flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
+        data += stride * (height - 1);
+        stride = -stride;
+    }
+
+    return pixman_image_create_bits (pixman_format,
+                                     width,
+                                     height,
+                                     (uint32_t *)data,
+                                     stride);
+}
+
+#ifdef WORDS_BIGENDIAN
+#define UINT16_FROM_LE(x)  ((uint16_t) ( \
+    (uint16_t) ((uint16_t) (x) >> 8) |   \
+    (uint16_t) ((uint16_t) (x) << 8)))
+#define UINT32_FROM_LE(x) (x) ((uint32_t) ( \
+    (((uint32_t) (val) & (uint32_t) 0x000000ffU) << 24) | \
+    (((uint32_t) (val) & (uint32_t) 0x0000ff00U) <<  8) | \
+    (((uint32_t) (val) & (uint32_t) 0x00ff0000U) >>  8) | \
+    (((uint32_t) (val) & (uint32_t) 0xff000000U) >> 24)))
+#else
+#define UINT16_FROM_LE(x) (x)
+#define UINT32_FROM_LE(x) (x)
+#endif
+
+static inline uint32_t rgb_16_555_to_32(uint16_t color)
+{
+    uint32_t ret;
+
+    ret = ((color & 0x001f) << 3) | ((color & 0x001c) >> 2);
+    ret |= ((color & 0x03e0) << 6) | ((color & 0x0380) << 1);
+    ret |= ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
+
+    return ret;
+}
+
+static inline uint16_t rgb_32_to_16_555(uint32_t color)
+{
+    return
+        (((color) >> 3) & 0x001f) |
+        (((color) >> 6) & 0x03e0) |
+        (((color) >> 9) & 0x7c00);
+}
+
+
+static void bitmap_32_to_32(uint8_t* dest, int dest_stride,
+                            uint8_t* src, int src_stride,
+                            int width, uint8_t* end)
+{
+#ifdef WORDS_BIGENDIAN
+    for (; src != end; src += src_stride, dest += dest_stride) {
+        uint32_t* src_line = (uint32_t *)src;
+        uint32_t* src_line_end = src_line + width;
+        uint32_t* dest_line = (uint32_t *)dest;
+
+        for (; src_line < src_line_end; ++dest_line, ++src_line) {
+            *dest_line = UINT32_FROM_LE(*src_line);
+        }
+    }
+#else
+    for (; src != end; src += src_stride, dest += dest_stride) {
+        memcpy(dest, src, width * 4);
+    }
+#endif
+}
+
+static void bitmap_24_to_32(uint8_t* dest, int dest_stride,
+                            uint8_t* src, int src_stride,
+                            int width, uint8_t* end)
+{
+    for (; src != end; src += src_stride, dest += dest_stride) {
+        uint8_t* src_line = src;
+        uint8_t* src_line_end = src_line + width * 3;
+        uint32_t* dest_line = (uint32_t *)dest;
+
+        for (; src_line < src_line_end; ++dest_line) {
+            uint32_t r, g, b;
+            b = *(src_line++);
+            g = *(src_line++);
+            r = *(src_line++);
+            *dest_line = (r << 16) | (g << 8) | (b);
+        }
+    }
+}
+
+static void bitmap_16_to_16_555(uint8_t* dest, int dest_stride,
+                                uint8_t* src, int src_stride,
+                                int width, uint8_t* end)
+{
+#ifdef WORDS_BIGENDIAN
+    for (; src != end; src += src_stride, dest += dest_stride) {
+        uint16_t* src_line = (uint16_t *)src;
+        uint16_t* src_line_end = src_line + width;
+        uint16_t* dest_line = (uint16_t *)dest;
+
+        for (; src_line < src_line_end; ++dest_line, ++src_line) {
+            *dest_line = UINT16_FROM_LE(*src_line);
+        }
+    }
+#else
+    for (; src != end; src += src_stride, dest += dest_stride) {
+        memcpy(dest, src, width * 2);
+    }
+#endif
+}
+
+static void bitmap_8_32_to_32(uint8_t *dest, int dest_stride,
+                              uint8_t *src, int src_stride,
+                              int width, uint8_t *end,
+                              SpicePalette *palette)
+{
+    uint32_t local_ents[256];
+    uint32_t *ents;
+    int n_ents;
+#ifdef WORDS_BIGENDIAN
+    int i;
+#endif
+
+    if (!palette) {
+        PANIC("No palette");
+        return;
+    }
+
+    n_ents = MIN(palette->num_ents, 256);
+    ents = palette->ents;
+
+    if (n_ents < 255
+#ifdef WORDS_BIGENDIAN
+        || TRUE
+#endif
+        ) {
+        memcpy(local_ents, ents, n_ents*4);
+        ents = local_ents;
+
+#ifdef WORDS_BIGENDIAN
+        for (i = 0; i < n_ents; i++) {
+            ents[i] = UINT32_FROM_LE(ents[i]);
+        }
+#endif
+    }
+
+    for (; src != end; src += src_stride, dest += dest_stride) {
+        uint32_t *dest_line = (uint32_t*)dest;
+        uint8_t *src_line = src;
+        uint8_t *src_line_end = src_line + width;
+
+        while (src_line < src_line_end) {
+            *(dest_line++) = ents[*(src_line++)];
+        }
+    }
+}
+
+static void bitmap_8_16_to_16_555(uint8_t *dest, int dest_stride,
+                                  uint8_t *src, int src_stride,
+                                  int width, uint8_t *end,
+                                  SpicePalette *palette)
+{
+    uint32_t local_ents[256];
+    uint32_t *ents;
+    int n_ents;
+#ifdef WORDS_BIGENDIAN
+    int i;
+#endif
+
+    if (!palette) {
+        PANIC("No palette");
+        return;
+    }
+
+    n_ents = MIN(palette->num_ents, 256);
+    ents = palette->ents;
+
+    if (n_ents < 255
+#ifdef WORDS_BIGENDIAN
+        || TRUE
+#endif
+        ) {
+        memcpy(local_ents, ents, n_ents*4);
+        ents = local_ents;
+
+#ifdef WORDS_BIGENDIAN
+        for (i = 0; i < n_ents; i++) {
+            ents[i] = UINT32_FROM_LE(ents[i]);
+        }
+#endif
+    }
+
+    for (; src != end; src += src_stride, dest += dest_stride) {
+        uint16_t *dest_line = (uint16_t*)dest;
+        uint8_t *src_line = src;
+        uint8_t *src_line_end = src_line + width;
+
+        while (src_line < src_line_end) {
+            *(dest_line++) = ents[*(src_line++)];
+        }
+    }
+}
+
+static void bitmap_4be_32_to_32(uint8_t* dest, int dest_stride,
+                                uint8_t* src, int src_stride,
+                                int width, uint8_t* end,
+                                SpicePalette *palette)
+{
+    uint32_t local_ents[16];
+    uint32_t *ents;
+    int n_ents;
+#ifdef WORDS_BIGENDIAN
+    int i;
+#endif
+
+    if (!palette) {
+        PANIC("No palette");
+        return;
+    }
+
+    n_ents = MIN(palette->num_ents, 16);
+    ents = palette->ents;
+
+    if (n_ents < 16
+#ifdef WORDS_BIGENDIAN
+        || TRUE
+#endif
+        ) {
+        memcpy(local_ents, ents, n_ents*4);
+        ents = local_ents;
+
+#ifdef WORDS_BIGENDIAN
+        for (i = 0; i < n_ents; i++) {
+            ents[i] = UINT32_FROM_LE(ents[i]);
+        }
+#endif
+    }
+
+    for (; src != end; src += src_stride, dest += dest_stride) {
+        uint32_t *dest_line = (uint32_t *)dest;
+        uint8_t *row = src;
+        int i;
+
+        for (i = 0; i < (width >> 1); i++) {
+            *(dest_line++) = ents[(*row >> 4) & 0x0f];
+            *(dest_line++) = ents[*(row++) & 0x0f];
+        }
+        if (width & 1) {
+            *(dest_line) = ents[(*row >> 4) & 0x0f];
+        }
+    }
+}
+
+static void bitmap_4be_16_to_16_555(uint8_t* dest, int dest_stride,
+                                    uint8_t* src, int src_stride,
+                                    int width, uint8_t* end,
+                                    SpicePalette *palette)
+{
+    uint32_t local_ents[16];
+    uint32_t *ents;
+    int n_ents;
+#ifdef WORDS_BIGENDIAN
+    int i;
+#endif
+
+    if (!palette) {
+        PANIC("No palette");
+        return;
+    }
+
+    n_ents = MIN(palette->num_ents, 16);
+    ents = palette->ents;
+
+    if (n_ents < 16
+#ifdef WORDS_BIGENDIAN
+        || TRUE
+#endif
+        ) {
+        memcpy(local_ents, ents, n_ents*4);
+        ents = local_ents;
+
+#ifdef WORDS_BIGENDIAN
+        for (i = 0; i < n_ents; i++) {
+            ents[i] = UINT32_FROM_LE(ents[i]);
+        }
+#endif
+    }
+
+    for (; src != end; src += src_stride, dest += dest_stride) {
+        uint16_t *dest_line = (uint16_t *)dest;
+        uint8_t *row = src;
+        int i;
+
+        for (i = 0; i < (width >> 1); i++) {
+            *(dest_line++) = ents[(*row >> 4) & 0x0f];
+            *(dest_line++) = ents[*(row++) & 0x0f];
+        }
+        if (width & 1) {
+            *(dest_line) = ents[(*row >> 4) & 0x0f];
+        }
+    }
+}
+
+static inline int test_bit_be(void* addr, int bit)
+{
+    return !!(((uint8_t*)addr)[bit >> 3] & (0x80 >> (bit & 0x07)));
+}
+
+static void bitmap_1be_32_to_32(uint8_t* dest, int dest_stride,
+                                uint8_t* src, int src_stride,
+                                int width, uint8_t* end,
+                                SpicePalette *palette)
+{
+    uint32_t fore_color;
+    uint32_t back_color;
+
+    ASSERT(palette != NULL);
+
+    if (!palette) {
+        return;
+    }
+
+    fore_color = UINT32_FROM_LE(palette->ents[1]);
+    back_color = UINT32_FROM_LE(palette->ents[0]);
+
+    for (; src != end; src += src_stride, dest += dest_stride) {
+        uint32_t* dest_line = (uint32_t*)dest;
+        int i;
+
+        for (i = 0; i < width; i++) {
+            if (test_bit_be(src, i)) {
+                *(dest_line++) = fore_color;
+            } else {
+                *(dest_line++) = back_color;
+            }
+        }
+    }
+}
+
+
+static void bitmap_1be_16_to_16_555(uint8_t* dest, int dest_stride,
+                                    uint8_t* src, int src_stride,
+                                    int width, uint8_t* end,
+                                    SpicePalette *palette)
+{
+    uint16_t fore_color;
+    uint16_t back_color;
+
+    ASSERT(palette != NULL);
+
+    if (!palette) {
+        return;
+    }
+
+    fore_color = (uint16_t) UINT32_FROM_LE(palette->ents[1]);
+    back_color = (uint16_t) UINT32_FROM_LE(palette->ents[0]);
+
+    for (; src != end; src += src_stride, dest += dest_stride) {
+        uint16_t* dest_line = (uint16_t*)dest;
+        int i;
+
+        for (i = 0; i < width; i++) {
+            if (test_bit_be(src, i)) {
+                *(dest_line++) = fore_color;
+            } else {
+                *(dest_line++) = back_color;
+            }
+        }
+    }
+}
+
+#ifdef NOT_USED_ATM
+
+static void bitmap_16_to_32(uint8_t* dest, int dest_stride,
+                            uint8_t* src, int src_stride,
+                            int width, uint8_t* end)
+{
+    for (; src != end; src += src_stride, dest += dest_stride) {
+        uint16_t* src_line = (uint16_t*)src;
+        uint16_t* src_line_end = src_line + width;
+        uint32_t* dest_line = (uint32_t*)dest;
+
+        for (; src_line < src_line_end; ++dest_line, src_line++) {
+            *dest_line = rgb_16_555_to_32(UINT16_FROM_LE(*src_line));
+        }
+    }
+}
+
+static void bitmap_32_to_16_555(uint8_t* dest, int dest_stride,
+                                uint8_t* src, int src_stride,
+                                int width, uint8_t* end)
+{
+    for (; src != end; src += src_stride, dest += dest_stride) {
+        uint32_t* src_line = (uint32_t *)src;
+        uint32_t* src_line_end = src_line + width;
+        uint16_t* dest_line = (uint16_t *)dest;
+
+        for (; src_line < src_line_end; ++dest_line, ++src_line) {
+            *dest_line = rgb_32_to_16_555(UINT16_FROM_LE(*src_line));
+        }
+    }
+}
+
+
+static void bitmap_24_to_16_555(uint8_t* dest, int dest_stride,
+                                uint8_t* src, int src_stride,
+                                int width, uint8_t* end)
+{
+    for (; src != end; src += src_stride, dest += dest_stride) {
+        uint8_t* src_line = src;
+        uint8_t* src_line_end = src_line + width * 3;
+        uint16_t* dest_line = (uint16_t *)dest;
+
+        for (; src_line < src_line_end; ++dest_line) {
+            uint8_t r, g, b;
+            b = *(src_line++);
+            g = *(src_line++);
+            r = *(src_line++);
+            *dest_line = rgb_32_to_16_555(r << 24 | g << 16 | b);
+        }
+    }
+}
+
+#endif
+
+/* This assumes that the dest, if set is the same format as
+   spice_bitmap_format_to_pixman would have picked */
+pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
+                                       int src_format,
+                                       int flags,
+                                       int width,
+                                       int height,
+                                       uint8_t *src,
+                                       int src_stride,
+                                       uint32_t palette_surface_format,
+                                       SpicePalette *palette)
+{
+    uint8_t* dest;
+    int dest_stride;
+    uint8_t* end;
+
+    if (dest_image == NULL) {
+        pixman_format_code_t dest_format;
+
+        dest_format = spice_bitmap_format_to_pixman(src_format,
+                                                    palette_surface_format);
+        dest_image = pixman_image_create_bits (dest_format,
+                                               width, height,
+                                               NULL, 0);
+    }
+
+    dest = (uint8_t *)pixman_image_get_data(dest_image);
+    dest_stride = pixman_image_get_stride(dest_image);
+    if (!(flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
+        ASSERT(height > 0);
+        dest += dest_stride * (height - 1);
+        dest_stride = -dest_stride;
+    }
+    end = src + (height * src_stride);
+
+    switch (src_format) {
+    case SPICE_BITMAP_FMT_32BIT:
+    case SPICE_BITMAP_FMT_RGBA:
+        bitmap_32_to_32(dest, dest_stride, src, src_stride, width, end);
+        break;
+    case SPICE_BITMAP_FMT_24BIT:
+        bitmap_24_to_32(dest, dest_stride, src, src_stride, width, end);
+        break;
+    case SPICE_BITMAP_FMT_16BIT:
+        bitmap_16_to_16_555(dest, dest_stride, src, src_stride, width, end);
+        break;
+    case SPICE_BITMAP_FMT_8BIT:
+        if (palette_surface_format == SPICE_SURFACE_FMT_32_ARGB ||
+            palette_surface_format == SPICE_SURFACE_FMT_32_xRGB) {
+            bitmap_8_32_to_32(dest, dest_stride, src, src_stride, width, end, palette);
+        } else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
+            bitmap_8_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
+        } else {
+            PANIC("Unsupported palette format");
+        }
+        break;
+    case SPICE_BITMAP_FMT_4BIT_BE:
+        if (palette_surface_format == SPICE_SURFACE_FMT_32_ARGB ||
+            palette_surface_format == SPICE_SURFACE_FMT_32_xRGB) {
+            bitmap_4be_32_to_32(dest, dest_stride, src, src_stride, width, end, palette);
+        } else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
+            bitmap_4be_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
+        } else {
+            PANIC("Unsupported palette format");
+        }
+        break;
+    case SPICE_BITMAP_FMT_1BIT_BE:
+        if (palette_surface_format == SPICE_SURFACE_FMT_32_ARGB ||
+            palette_surface_format == SPICE_SURFACE_FMT_32_xRGB) {
+            bitmap_1be_32_to_32(dest, dest_stride, src, src_stride, width, end, palette);
+        } else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
+            bitmap_1be_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
+        } else {
+            PANIC("Unsupported palette format");
+        }
+        break;
+    default:
+        PANIC("Unsupported bitmap format");
+        break;
+    }
+
+    return dest_image;
+}
+
+static int pixman_format_compatible (pixman_format_code_t dest_format,
+                              pixman_format_code_t src_format)
+{
+    if (dest_format == src_format) {
+        return TRUE;
+    }
+
+    if (src_format == PIXMAN_a8r8g8b8 &&
+        dest_format == PIXMAN_x8r8g8b8) {
+        /* This is the same, we just ignore the alphas */
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+pixman_image_t *spice_bitmap_convert_to_pixman(pixman_format_code_t dest_format,
+                                               pixman_image_t *dest_image,
+                                               int src_format,
+                                               int flags,
+                                               int width,
+                                               int height,
+                                               uint8_t *src,
+                                               int src_stride,
+                                               uint32_t palette_surface_format,
+                                               SpicePalette *palette)
+{
+    pixman_image_t *src_image;
+    pixman_format_code_t native_format;
+
+    if (dest_image == NULL) {
+        dest_image = pixman_image_create_bits (dest_format,
+                                               width, height,
+                                               NULL, 0);
+    }
+
+    native_format =
+        spice_bitmap_format_to_pixman(src_format, palette_surface_format);
+
+    if (pixman_format_compatible (dest_format, native_format)) {
+        return spice_bitmap_to_pixman(dest_image,
+                                      src_format,
+                                      flags, width,height,
+                                      src, src_stride,
+                                      palette_surface_format, palette);
+    }
+
+    src_image = spice_bitmap_try_as_pixman(src_format,
+                                           flags, width,height,
+                                           src, src_stride);
+
+    /* Can't convert directly, need a temporary copy
+     * Hopefully most bitmap reads should not need conversion (i.e.
+     * hit the spice_bitmap_to_pixmap case above) or work with the
+     * try_as_pixmap case, but in case some specific combination
+     * shows up here commonly we might want to add non-temporary
+     * conversion special casing here */
+    if (src_image == NULL) {
+        src_image = spice_bitmap_to_pixman(NULL,
+                                           src_format,
+                                           flags, width,height,
+                                           src, src_stride,
+                                           palette_surface_format, palette);
+    }
+
+    pixman_image_composite32 (PIXMAN_OP_SRC,
+                              src_image, NULL, dest_image,
+                              0, 0,
+                              0, 0,
+                              0, 0,
+                              width, height);
+
+    pixman_image_unref (src_image);
+
+    return dest_image;
+}
diff --git a/common/pixman_utils.h b/common/pixman_utils.h
index 743bd06..24ecee3 100644
--- a/common/pixman_utils.h
+++ b/common/pixman_utils.h
@@ -20,6 +20,7 @@
 #define _H__PIXMAN_UTILS
 
 #include <spice/types.h>
+#include <stdlib.h>
 #define PIXMAN_DONT_DEFINE_STDINT
 #include <pixman.h>
 
@@ -51,6 +52,28 @@ typedef enum {
 } SpiceROP;
 
 
+int spice_pixman_image_get_bpp(pixman_image_t *image);
+
+pixman_format_code_t spice_surface_format_to_pixman(uint32_t surface_format);
+pixman_format_code_t spice_bitmap_format_to_pixman(int bitmap_format,
+                                                   uint32_t palette_surface_format);
+pixman_image_t *spice_bitmap_try_as_pixman(int src_format, int flags,
+                                           int width, int height,
+                                           uint8_t *data, int stride);
+pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
+                                       int src_format, int flags,
+                                       int width, int height,
+                                       uint8_t *src, int src_stride,
+                                       uint32_t palette_surface_format,
+                                       SpicePalette *palette);
+pixman_image_t *spice_bitmap_convert_to_pixman(pixman_format_code_t dest_format,
+                                               pixman_image_t *dest_image,
+                                               int src_format, int flags,
+                                               int width, int height,
+                                               uint8_t *src, int src_stride,
+                                               uint32_t palette_surface_format,
+                                               SpicePalette *palette);
+
 void spice_pixman_region32_init_from_bitmap(pixman_region32_t *region,
                                             uint32_t *data,
                                             int width, int height,
commit 8bd1a873704dbaa3a65c1335cb710537080acccd
Author: Alexander Larsson <alexl at redhat.com>
Date:   Mon Apr 19 15:43:54 2010 +0200

    Add support for 16bit rop3

diff --git a/common/rop3.c b/common/rop3.c
index d647de5..77f0a71 100644
--- a/common/rop3.c
+++ b/common/rop3.c
@@ -20,6 +20,13 @@
 
 #include "rop3.h"
 
+#ifndef ASSERT
+#define ASSERT(x) if (!(x)) {                               \
+    printf("%s: ASSERT %s failed\n", __FUNCTION__, #x);     \
+    abort();                                                \
+}
+#endif
+
 #ifndef WARN
 #define WARN(x) printf("warning: %s\n", x)
 #endif
@@ -35,9 +42,12 @@ typedef void (*rop3_test_handler_t)();
 
 #define ROP3_NUM_OPS 256
 
-static rop3_with_pattern_handler_t rop3_with_pattern_handlers[ROP3_NUM_OPS];
-static rop3_with_color_handler_t rop3_with_color_handlers[ROP3_NUM_OPS];
-static rop3_test_handler_t rop3_test_handlers[ROP3_NUM_OPS];
+static rop3_with_pattern_handler_t rop3_with_pattern_handlers_32[ROP3_NUM_OPS];
+static rop3_with_pattern_handler_t rop3_with_pattern_handlers_16[ROP3_NUM_OPS];
+static rop3_with_color_handler_t rop3_with_color_handlers_32[ROP3_NUM_OPS];
+static rop3_with_color_handler_t rop3_with_color_handlers_16[ROP3_NUM_OPS];
+static rop3_test_handler_t rop3_test_handlers_32[ROP3_NUM_OPS];
+static rop3_test_handler_t rop3_test_handlers_16[ROP3_NUM_OPS];
 
 
 static void default_rop3_with_pattern_handler(pixman_image_t *d, pixman_image_t *s,
@@ -57,13 +67,14 @@ static void default_rop3_test_handler()
 {
 }
 
-#define ROP3_HANDLERS(name, formula, index)                                                     \
-static void rop3_handle_p_##name(pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,     \
-                                      pixman_image_t *p, SpicePoint *pat_pos)                   \
+#define ROP3_HANDLERS_DEPTH(name, formula, index, depth)                            \
+static void rop3_handle_p##depth##_##name(pixman_image_t *d, pixman_image_t *s,                 \
+                                          SpicePoint *src_pos,                                  \
+                                          pixman_image_t *p, SpicePoint *pat_pos)               \
 {                                                                                               \
     int width = pixman_image_get_width(d);                                                      \
     int height = pixman_image_get_height(d);                                                    \
-    uint8_t *dest_line = (uint8_t *)pixman_image_get_data(d);		                        \
+    uint8_t *dest_line = (uint8_t *)pixman_image_get_data(d);                                   \
     int dest_stride = pixman_image_get_stride(d);                                               \
     uint8_t *end_line = dest_line + height * dest_stride;                                       \
                                                                                                 \
@@ -75,18 +86,19 @@ static void rop3_handle_p_##name(pixman_image_t *d, pixman_image_t *s, SpicePoin
                                                                                                 \
     int src_stride = pixman_image_get_stride(s);                                                \
     uint8_t *src_line;                                                                          \
-    src_line = (uint8_t *)pixman_image_get_data(s) + src_pos->y * src_stride + (src_pos->x << 2); \
+    src_line = (uint8_t *)pixman_image_get_data(s) + src_pos->y * src_stride + (src_pos->x * depth / 8); \
                                                                                                 \
     for (; dest_line < end_line; dest_line += dest_stride, src_line += src_stride) {            \
-        uint32_t *dest = (uint32_t *)dest_line;                                                 \
-        uint32_t *end = dest + width;                                                           \
-        uint32_t *src = (uint32_t *)src_line;                                                   \
+        uint##depth##_t *dest = (uint##depth##_t *)dest_line;                                   \
+        uint##depth##_t *end = dest + width;                                                    \
+        uint##depth##_t *src = (uint##depth##_t *)src_line;                                     \
                                                                                                 \
         int pat_h_offset = pat_pos->x;                                                          \
                                                                                                 \
         for (; dest < end; dest++, src++) {                                                     \
-            uint32_t *pat;                                                                      \
-            pat  = (uint32_t *)(pat_base + pat_v_offset * pat_stride + (pat_h_offset << 2));    \
+            uint##depth##_t *pat;                                                               \
+            pat  = (uint##depth##_t *)                                                          \
+                        (pat_base + pat_v_offset * pat_stride + (pat_h_offset * depth / 8));    \
             *dest = formula;                                                                    \
             pat_h_offset = (pat_h_offset + 1) % pat_width;                                      \
         }                                                                                       \
@@ -95,31 +107,34 @@ static void rop3_handle_p_##name(pixman_image_t *d, pixman_image_t *s, SpicePoin
     }                                                                                           \
 }                                                                                               \
                                                                                                 \
-static void rop3_handle_c_##name(pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,     \
-                                   uint32_t rgb)                                                \
+static void rop3_handle_c##depth##_##name(pixman_image_t *d, pixman_image_t *s,                 \
+                                          SpicePoint *src_pos,                                  \
+                                          uint32_t rgb)                                         \
 {                                                                                               \
     int width = pixman_image_get_width(d);                                                      \
     int height = pixman_image_get_height(d);                                                    \
     uint8_t *dest_line = (uint8_t *)pixman_image_get_data(d);                                   \
     int dest_stride = pixman_image_get_stride(d);                                               \
     uint8_t *end_line = dest_line + height * dest_stride;                                       \
-    uint32_t *pat = &rgb;                                                                       \
+    uint##depth##_t _pat = rgb;                                                                \
+    uint##depth##_t *pat = &_pat;                                                               \
                                                                                                 \
     int src_stride = pixman_image_get_stride(s);                                                \
     uint8_t *src_line;                                                                          \
-    src_line = (uint8_t *)pixman_image_get_data(s) + src_pos->y * src_stride + (src_pos->x << 2); \
+    src_line = (uint8_t *)                                                                      \
+        pixman_image_get_data(s) + src_pos->y * src_stride + (src_pos->x * depth / 8);          \
                                                                                                 \
     for (; dest_line < end_line; dest_line += dest_stride, src_line += src_stride) {            \
-        uint32_t *dest = (uint32_t *)dest_line;                                                 \
-        uint32_t *end = dest + width;                                                           \
-        uint32_t *src = (uint32_t *)src_line;                                                   \
+        uint##depth##_t *dest = (uint##depth##_t *)dest_line;                                   \
+        uint##depth##_t *end = dest + width;                                                    \
+        uint##depth##_t *src = (uint##depth##_t *)src_line;                                     \
         for (; dest < end; dest++, src++) {                                                     \
             *dest = formula;                                                                    \
         }                                                                                       \
     }                                                                                           \
 }                                                                                               \
                                                                                                 \
-static void rop3_test_##name()                                                                  \
+static void rop3_test##depth##_##name()                                                         \
 {                                                                                               \
     uint8_t d = 0xaa;                                                                           \
     uint8_t s = 0xcc;                                                                           \
@@ -134,6 +149,10 @@ static void rop3_test_##name()
     }                                                                                           \
 }
 
+#define ROP3_HANDLERS(name, formula, index) \
+    ROP3_HANDLERS_DEPTH(name, formula, index, 32)  \
+    ROP3_HANDLERS_DEPTH(name, formula, index, 16)
+
 ROP3_HANDLERS(DPSoon, ~(*pat | *src | *dest), 0x01);
 ROP3_HANDLERS(DPSona, ~(*pat | *src) & *dest, 0x02);
 ROP3_HANDLERS(SDPona, ~(*pat | *dest) & *src, 0x04);
@@ -354,11 +373,13 @@ ROP3_HANDLERS(PSDnoo, ~*dest | *src | *pat, 0xfd);
 ROP3_HANDLERS(DPSoo, *src | *pat | *dest, 0xfe);
 
 
-
 #define ROP3_FILL_HANDLERS(op, index)                       \
-    rop3_with_pattern_handlers[index] = rop3_handle_p_##op; \
-    rop3_with_color_handlers[index] = rop3_handle_c_##op;   \
-    rop3_test_handlers[index] = rop3_test_##op;
+    rop3_with_pattern_handlers_32[index] = rop3_handle_p32_##op; \
+    rop3_with_pattern_handlers_16[index] = rop3_handle_p16_##op; \
+    rop3_with_color_handlers_32[index] = rop3_handle_c32_##op;   \
+    rop3_with_color_handlers_16[index] = rop3_handle_c16_##op;   \
+    rop3_test_handlers_32[index] = rop3_test32_##op;             \
+    rop3_test_handlers_16[index] = rop3_test16_##op;
 
 void rop3_init()
 {
@@ -371,9 +392,12 @@ void rop3_init()
     need_init = 0;
 
     for (i = 0; i < ROP3_NUM_OPS; i++) {
-        rop3_with_pattern_handlers[i] = default_rop3_with_pattern_handler;
-        rop3_with_color_handlers[i] = default_rop3_withe_color_handler;
-        rop3_test_handlers[i] = default_rop3_test_handler;
+        rop3_with_pattern_handlers_32[i] = default_rop3_with_pattern_handler;
+        rop3_with_pattern_handlers_16[i] = default_rop3_with_pattern_handler;
+        rop3_with_color_handlers_32[i] = default_rop3_withe_color_handler;
+        rop3_with_color_handlers_16[i] = default_rop3_withe_color_handler;
+        rop3_test_handlers_32[i] = default_rop3_test_handler;
+        rop3_test_handlers_16[i] = default_rop3_test_handler;
     }
 
     ROP3_FILL_HANDLERS(DPSoon, 0x01);
@@ -596,19 +620,38 @@ void rop3_init()
     ROP3_FILL_HANDLERS(DPSoo, 0xfe);
 
     for (i = 0; i < ROP3_NUM_OPS; i++) {
-        rop3_test_handlers[i]();
+        rop3_test_handlers_32[i]();
+        rop3_test_handlers_16[i]();
     }
 }
 
 void do_rop3_with_pattern(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
                           pixman_image_t *p, SpicePoint *pat_pos)
 {
-    rop3_with_pattern_handlers[rop3](d, s, src_pos, p, pat_pos);
+    int bpp;
+
+    bpp = spice_pixman_image_get_bpp(d);
+    ASSERT (bpp == spice_pixman_image_get_bpp(s));
+    ASSERT (bpp == spice_pixman_image_get_bpp(p));
+
+    if (bpp == 32) {
+        rop3_with_pattern_handlers_32[rop3](d, s, src_pos, p, pat_pos);
+    } else {
+        rop3_with_pattern_handlers_16[rop3](d, s, src_pos, p, pat_pos);
+    }
 }
 
 void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
                         uint32_t rgb)
 {
-    rop3_with_color_handlers[rop3](d, s, src_pos, rgb);
-}
+    int bpp;
 
+    bpp = spice_pixman_image_get_bpp(d);
+    ASSERT (bpp == spice_pixman_image_get_bpp(s));
+
+    if (bpp == 32) {
+        rop3_with_color_handlers_32[rop3](d, s, src_pos, rgb);
+    } else {
+        rop3_with_color_handlers_16[rop3](d, s, src_pos, rgb);
+    }
+}
commit ee04978272511412e0fadfbb22a7f6516c4d6323
Author: Alexander Larsson <alexl at redhat.com>
Date:   Mon Apr 19 15:51:29 2010 +0200

    Add emacs modelines to more files

diff --git a/client/canvas.cpp b/client/canvas.cpp
index 2400c45..419bfc9 100644
--- a/client/canvas.cpp
+++ b/client/canvas.cpp
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
diff --git a/client/canvas.h b/client/canvas.h
index 9e9d39f..1dc2acb 100644
--- a/client/canvas.h
+++ b/client/canvas.h
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index 54e8dd0..719e7df 100644
--- a/client/display_channel.cpp
+++ b/client/display_channel.cpp
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
diff --git a/client/display_channel.h b/client/display_channel.h
index 4c421e1..2bb697c 100644
--- a/client/display_channel.h
+++ b/client/display_channel.h
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
diff --git a/client/red_cairo_canvas.cpp b/client/red_cairo_canvas.cpp
index f50e45b..96f7637 100644
--- a/client/red_cairo_canvas.cpp
+++ b/client/red_cairo_canvas.cpp
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
diff --git a/client/red_cairo_canvas.h b/client/red_cairo_canvas.h
index 1f8aef1..8d039bf 100644
--- a/client/red_cairo_canvas.h
+++ b/client/red_cairo_canvas.h
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
diff --git a/client/red_pixmap.h b/client/red_pixmap.h
index 03e18fe..1b469bd 100644
--- a/client/red_pixmap.h
+++ b/client/red_pixmap.h
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
diff --git a/client/red_pixmap_gdi.h b/client/red_pixmap_gdi.h
index ba6c15b..9e10adc 100644
--- a/client/red_pixmap_gdi.h
+++ b/client/red_pixmap_gdi.h
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
diff --git a/client/windows/red_pixmap_cairo.cpp b/client/windows/red_pixmap_cairo.cpp
index 994ba1e..6ed5806 100644
--- a/client/windows/red_pixmap_cairo.cpp
+++ b/client/windows/red_pixmap_cairo.cpp
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
diff --git a/client/windows/red_pixmap_gdi.cpp b/client/windows/red_pixmap_gdi.cpp
index ddbd068..d4913c4 100644
--- a/client/windows/red_pixmap_gdi.cpp
+++ b/client/windows/red_pixmap_gdi.cpp
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
diff --git a/client/x11/red_pixmap_cairo.cpp b/client/x11/red_pixmap_cairo.cpp
index 7dc9087..e73b8b4 100644
--- a/client/x11/red_pixmap_cairo.cpp
+++ b/client/x11/red_pixmap_cairo.cpp
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
commit f5b00cdd6c52312c120458a7889882e6e932d009
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Apr 21 18:42:58 2010 +0200

    Remove unused method canvas_surf_to_invers

diff --git a/common/canvas_base.c b/common/canvas_base.c
index 9f1f536..9852da9 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -1267,85 +1267,35 @@ static inline pixman_image_t *canvas_A1_invers(pixman_image_t *src_surf)
 {
     int width = pixman_image_get_width(src_surf);
     int height = pixman_image_get_height(src_surf);
+    pixman_image_t * invers;
+    uint8_t *src_line, *end_line,  *dest_line;
+    int src_stride, line_size, dest_stride;
 
-    pixman_image_t * invers = pixman_image_create_bits(PIXMAN_a1, width, height, NULL, 0);
-    if (invers != NULL) {
-        uint8_t *src_line = (uint8_t *)pixman_image_get_data(src_surf);
-        int src_stride = pixman_image_get_stride(src_surf);
-        uint8_t *end_line = src_line + (height * src_stride);
-        int line_size = SPICE_ALIGN(width, 8) >> 3;
-        uint8_t *dest_line = (uint8_t *)pixman_image_get_data(invers);
-        int dest_stride = pixman_image_get_stride(invers);
-
-        for (; src_line != end_line; src_line += src_stride, dest_line += dest_stride) {
-            uint8_t *dest = dest_line;
-            uint8_t *now = src_line;
-            uint8_t *end = now + line_size;
-            while (now < end) {
-                *(dest++) = ~*(now++);
-            }
-        }
-    }
-    return invers;
-}
-
-static pixman_image_t *canvas_surf_to_invers(pixman_image_t *surf)
-{
-    int width = pixman_image_get_width(surf);
-    int height = pixman_image_get_height(surf);
-    uint8_t *dest_line;
-    uint8_t *dest_line_end;
-    uint8_t *src_line;
-    int dest_stride;
-    int src_stride;
-
-    ASSERT(pixman_image_get_depth(surf) == 24);
-    pixman_image_t *invers = pixman_image_create_bits (PIXMAN_x8r8g8b8, width, height, NULL, 0);
+    ASSERT(pixman_image_get_depth(src_surf) == 1);
 
+    invers = pixman_image_create_bits(PIXMAN_a1, width, height, NULL, 0);
     if (invers == NULL) {
         CANVAS_ERROR("create surface failed");
     }
 
+    src_line = (uint8_t *)pixman_image_get_data(src_surf);
+    src_stride = pixman_image_get_stride(src_surf);
+    end_line = src_line + (height * src_stride);
+    line_size = SPICE_ALIGN(width, 8) >> 3;
     dest_line = (uint8_t *)pixman_image_get_data(invers);
     dest_stride = pixman_image_get_stride(invers);
-    dest_line_end = dest_line + dest_stride * height;
-    src_line = (uint8_t *)pixman_image_get_data(surf);
-    src_stride = pixman_image_get_stride(surf);
-
-    for (; dest_line != dest_line_end; dest_line += dest_stride, src_line += src_stride) {
-        uint32_t *src = (uint32_t *)src_line;
-        uint32_t *dest = (uint32_t *)dest_line;
-        uint32_t *end = dest + width;
-        while (dest < end) {
-            *(dest++) = ~*(src++) & 0x00ffffff;
+
+    for (; src_line != end_line; src_line += src_stride, dest_line += dest_stride) {
+        uint8_t *dest = dest_line;
+        uint8_t *now = src_line;
+        uint8_t *end = now + line_size;
+        while (now < end) {
+            *(dest++) = ~*(now++);
         }
     }
     return invers;
 }
 
-/*
-* Return the inversed surface and assigns it to the user data of the given surface.
-* The routine also handles the reference count of the inversed surface. It you don't use
-* the returned reference, you must call cairo_surface_destroy.
-* Thread safe with respect to the user data.
-*/
-static inline pixman_image_t* canvas_handle_inverse_user_data(pixman_image_t* surface)
-{
-    pixman_image_t *inv_surf = NULL;
-
-    if (pixman_image_get_depth(surface) == 1) {
-        inv_surf = canvas_A1_invers(surface);
-    } else {
-        inv_surf = canvas_surf_to_invers(surface);
-    }
-
-    if (inv_surf == NULL) {
-        CANVAS_ERROR("create surface failed");
-    }
-
-    return inv_surf;
-}
-
 static pixman_image_t *canvas_get_mask(CanvasBase *canvas, SpiceQMask *mask, int *needs_invert_out)
 {
     SpiceImageDescriptor *descriptor;
@@ -1396,7 +1346,7 @@ static pixman_image_t *canvas_get_mask(CanvasBase *canvas, SpiceQMask *mask, int
             *needs_invert_out = TRUE;
         } else {
             pixman_image_t *inv_surf;
-            inv_surf = canvas_handle_inverse_user_data(surface);
+            inv_surf = canvas_A1_invers(surface);
             pixman_image_unref(surface);
             surface = inv_surf;
         }
commit aeab661c5df12e6f3d225597643530f08792c4b6
Author: Alexander Larsson <alexl at redhat.com>
Date:   Mon Apr 19 16:55:36 2010 +0200

    Make client start if screen is 16bpp
    
    The current glx code is looking for a rgb32 visual and always failing
    if there is none. This means not even software rendering starts up
    on e.g. 16bit visuals. This commit makes it pick software fallbacks
    on 16bit visuals.
    
    Long term we need to fix the gl implementation to do 16bpp too.

diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp
index 228069f..dba276d 100644
--- a/client/x11/platform.cpp
+++ b/client/x11/platform.cpp
@@ -2016,7 +2016,9 @@ static void cleanup(void)
     }
     if (fb_config) {
         for (i = 0; i < ScreenCount(x_display); ++i) {
-            XFree(fb_config[i]);
+            if (fb_config[i]) {
+                XFree(fb_config[i]);
+            }
         }
         delete fb_config;
         fb_config = NULL;
@@ -2209,22 +2211,29 @@ void Platform::init()
         };
 
         for (int i = 0; i < ScreenCount(x_display); ++i) {
-            if (!(fb_config[i] = glXChooseFBConfig(x_display, i, attrlist, &num_configs))) {
-                vinfo[i] = get_x_vis_info(i);
-            } else {
+            fb_config[i] = glXChooseFBConfig(x_display, i, attrlist, &num_configs);
+            if (fb_config[i] != NULL) {
                 ASSERT(num_configs > 0);
                 vinfo[i] = glXGetVisualFromFBConfig(x_display, fb_config[i][0]);
             }
 
-            if (!vinfo[i]) {
-                THROW("XGetVisualInfo failed");
+            if (vinfo[i] == NULL) {
+                if (fb_config[i]) {
+                    XFree(fb_config[i]);
+                    fb_config[i] = NULL;
+                }
+                vinfo[i] = get_x_vis_info(i);
             }
         }
     } else {
         for (int i = 0; i < ScreenCount(x_display); ++i) {
-            if (!(vinfo[i] = get_x_vis_info(i))) {
-                THROW("XGetVisualInfo failed");
-            }
+            vinfo[i] = get_x_vis_info(i);
+        }
+    }
+
+    for (int i = 0; i < ScreenCount(x_display); ++i) {
+        if (vinfo[i] == NULL) {
+            THROW("Unable to find a visual for screen");
         }
     }
 
commit 9c02d1539624403506b93fc6b5cb425978fcfd92
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Apr 21 13:40:13 2010 +0200

    Client: Don't die if XIM not availible

diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp
index 2c3604a..228069f 100644
--- a/client/x11/platform.cpp
+++ b/client/x11/platform.cpp
@@ -2111,7 +2111,7 @@ static void init_XIM()
     x_input_method = XOpenIM(x_display, NULL, app_name, app_name);
 
     if (!x_input_method) {
-        THROW("open IM failed");
+        return;
     }
 
     x_input_context = XCreateIC(x_input_method, XNInputStyle, XIMPreeditNone | XIMStatusNone, NULL);
diff --git a/client/x11/red_window.cpp b/client/x11/red_window.cpp
index b3b9cac..6de86bf 100644
--- a/client/x11/red_window.cpp
+++ b/client/x11/red_window.cpp
@@ -714,7 +714,6 @@ static inline SpiceMouseButton to_red_button(unsigned int botton, unsigned int&
 void RedWindow_p::handle_key_press_event(RedWindow& window, XKeyEvent* event)
 {
     static int buf_size = 0;
-    static char* utf8_buf = NULL;
     static wchar_t* utf32_buf = NULL;
 
     KeySym key_sym;
@@ -722,35 +721,47 @@ void RedWindow_p::handle_key_press_event(RedWindow& window, XKeyEvent* event)
     int len;
 
     window.get_listener().on_key_press(to_red_key_code(event->keycode));
-    for (;;) {
-        len = XwcLookupString(x_input_context, event, utf32_buf, buf_size, &key_sym, &status);
-        if (status != XBufferOverflow) {
-            break;
+
+    if (x_input_context != NULL) {
+        for (;;) {
+            len = XwcLookupString(x_input_context, event, utf32_buf, buf_size, &key_sym, &status);
+            if (status != XBufferOverflow) {
+                break;
+            }
+
+            if (utf32_buf) {
+                delete [] utf32_buf;
+            }
+            utf32_buf = new wchar_t[len];
+            buf_size = len;
         }
 
-        free(utf32_buf);
-        free(utf32_buf);
-        utf8_buf = new char[len];
-        utf32_buf = new wchar_t[len];
-        buf_size = len;
-    }
+        switch (status) {
+        case XLookupChars:
+        case XLookupBoth: {
+            uint32_t* now = (uint32_t*)utf32_buf;
+            uint32_t* end = now + len;
+
+            for (; now < end; now++) {
+                window.get_listener().on_char(*now);
+            }
+            break;
+        }
 
-    switch (status) {
-    case XLookupChars:
-    case XLookupBoth: {
-        uint32_t* now = (uint32_t*)utf32_buf;
-        uint32_t* end = now + len;
+        case XLookupNone:
+        case XLookupKeySym:
+            break;
+        default:
+            THROW("unexpected status %d", status);
+        }
+    } else { /* no XIM */
+        unsigned char buffer[16];
+        int i;
 
-        for (; now < end; now++) {
-            window.get_listener().on_char(*now);
+        len = XLookupString(event, (char *)buffer, sizeof(buffer), NULL, NULL);
+        for (i = 0; i < len; i++) {
+            window.get_listener().on_char((uint32_t)buffer[i]);
         }
-        break;
-    }
-    case XLookupNone:
-    case XLookupKeySym:
-        break;
-    default:
-        THROW("unexpected status %d", status);
     }
 }
 
@@ -1962,7 +1973,9 @@ void RedWindow::on_focus_in()
         return;
     }
     _focused = true;
-    XwcResetIC(x_input_context);
+    if (x_input_context) {
+        XwcResetIC(x_input_context);
+    }
     XPlatform::on_focus_in();
     get_listener().on_activate();
     if (_trace_key_interception && _pointer_in_window) {
commit 43a61bb6fe1e9741e686fc57b51e782432c384de
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Apr 21 11:46:42 2010 +0200

    Detect XShm extension sanely
    
    The previous way XShm detection worked failed at least for me, and is
    not the standard way. We now just use XShmQueryExtension and
    XShmQueryVersion.

diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp
index 0151b41..2c3604a 100644
--- a/client/x11/platform.cpp
+++ b/client/x11/platform.cpp
@@ -2169,9 +2169,8 @@ void Platform::init()
 {
     int err, ev;
     int threads_enable;
-    int connection_fd;
-    socklen_t sock_len;
-    struct sockaddr sock_addr;
+    int major, minor;
+    Bool pixmaps;
 
     DBG(0, "");
 
@@ -2184,9 +2183,8 @@ void Platform::init()
         THROW("open X display failed");
     }
 
-    connection_fd = ConnectionNumber(x_display);
-    if (!getsockname(connection_fd, &sock_addr, &sock_len) &&
-        XShmQueryExtension(x_display) && sock_addr.sa_family == AF_UNIX ) {
+    if (XShmQueryExtension (x_display) &&
+        XShmQueryVersion (x_display, &major, &minor, &pixmaps)) {
         x_shm_avail = true;
     }
 
commit c39f9e4a5baa7208a791f41531e87f05c43ceb71
Author: Alexander Larsson <alexl at redhat.com>
Date:   Mon Apr 19 15:51:45 2010 +0200

    Detect big endian systems

diff --git a/configure.ac b/configure.ac
index e1f0c8e..94cd65f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -24,6 +24,7 @@ AC_PROG_INSTALL
 AC_CANONICAL_HOST
 AC_PROG_LIBTOOL
 AM_PROG_CC_C_O
+AC_C_BIGENDIAN
 
 SPICE_LT_VERSION=m4_format("%d:%d:%d", SPICE_MAJOR, SPICE_MINOR, SPICE_MICRO)
 AC_SUBST(SPICE_LT_VERSION)
commit 36f7c3b1e33e0c90f3ec454f808edc354f574fe4
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri Apr 23 16:33:19 2010 +0200

    Fix warnings breaking win32 build

diff --git a/common/region.c b/common/region.c
index f3cf0b2..3f51f7b 100644
--- a/common/region.c
+++ b/common/region.c
@@ -366,9 +366,9 @@ SpiceRect *region_dup_rects(const QRegion *rgn, uint32_t *num_rects)
 void region_ret_rects(const QRegion *rgn, SpiceRect *rects, uint32_t num_rects)
 {
     pixman_box32_t *boxes;
-    int n, i;
+    unsigned int n, i;
 
-    boxes = pixman_region32_rectangles((pixman_region32_t *)rgn, &n);
+    boxes = pixman_region32_rectangles((pixman_region32_t *)rgn, (int *)&n);
     for (i = 0; i < n && i < num_rects; i++) {
         rects[i].left = boxes[i].x1;
         rects[i].top = boxes[i].y1;
@@ -377,7 +377,7 @@ void region_ret_rects(const QRegion *rgn, SpiceRect *rects, uint32_t num_rects)
     }
 
     if (i && i != n) {
-        int x;
+        unsigned int x;
 
         for (x = 0; x < (n - num_rects); ++x) {
             rects[i - 1].left = MIN(rects[i - 1].left, boxes[i + x].x1);


More information about the Spice-commits mailing list