[gtk-vnc] Convert VncConnection over to use VncFramebuffer object



commit 37fc69f2da557669b14728e2b4af5147f98a3b3c
Author: Daniel P. Berrange <berrange redhat com>
Date:   Thu Nov 19 19:06:00 2009 +0000

    Convert VncConnection over to use VncFramebuffer object
    
    Remove the vnc_framebuffer struct, and make VncConnection use the
    new VncFramebuffer object.
    
    VncDisplay is changed to use the VncImageFramebuffer object
    type as its implementation of VncFramebuffer

 src/blt.h                |  334 ------------------------------------
 src/blt1.h               |   31 ----
 src/vncbaseframebuffer.c |   10 +
 src/vncconnection.c      |  423 ++++++++++++++++++----------------------------
 src/vncconnection.h      |   29 +---
 src/vncconnectionblt.h   |  163 ++++++++++++++++++
 src/vncdisplay.c         |  195 +++++++++++-----------
 7 files changed, 440 insertions(+), 745 deletions(-)
---
diff --git a/src/vncbaseframebuffer.c b/src/vncbaseframebuffer.c
index f7dab3b..1651870 100644
--- a/src/vncbaseframebuffer.c
+++ b/src/vncbaseframebuffer.c
@@ -351,6 +351,15 @@ static const VncPixelFormat *vnc_base_framebuffer_get_remote_format(VncFramebuff
 }
 
 
+static gboolean vnc_base_framebuffer_perfect_format_match(VncFramebuffer *iface)
+{
+	VncBaseFramebuffer *fb = VNC_BASE_FRAMEBUFFER(iface);
+	VncBaseFramebufferPrivate *priv = fb->priv;
+
+	return priv->perfect_match;
+}
+
+
 static guint8 vnc_base_framebuffer_swap_img_8(VncBaseFramebufferPrivate *priv G_GNUC_UNUSED, guint8 pixel)
 {
 	return pixel;
@@ -710,6 +719,7 @@ static void vnc_base_framebuffer_interface_init(gpointer g_iface,
     iface->get_buffer = vnc_base_framebuffer_get_buffer;
     iface->get_local_format = vnc_base_framebuffer_get_local_format;
     iface->get_remote_format = vnc_base_framebuffer_get_remote_format;
+    iface->perfect_format_match = vnc_base_framebuffer_perfect_format_match;
 
     iface->set_pixel_at = vnc_base_framebuffer_set_pixel_at;
     iface->fill = vnc_base_framebuffer_fill;
diff --git a/src/vncconnection.c b/src/vncconnection.c
index dabe2d4..65bd576 100644
--- a/src/vncconnection.c
+++ b/src/vncconnection.c
@@ -71,23 +71,9 @@ struct wait_queue
 };
 
 
-typedef void vnc_connection_blt_func(VncConnection *conn, guint8 *, int, int, int, int, int);
-
-typedef void vnc_connection_fill_func(VncConnection *conn, guint8 *, int, int, int, int);
-
-typedef void vnc_connection_set_pixel_at_func(VncConnection *conn, int, int, guint8 *);
-
-typedef void vnc_connection_hextile_func(VncConnection *conn, guint8 flags,
-					  guint16 x, guint16 y,
-					  guint16 width, guint16 height,
-					  guint8 *fg, guint8 *bg);
-
 typedef void vnc_connection_rich_cursor_blt_func(VncConnection *conn, guint8 *, guint8 *,
 						  guint8 *, int, guint16, guint16);
 
-typedef void vnc_connection_rgb24_blt_func(VncConnection *conn, int, int, int, int,
-					    guint8 *, int);
-
 typedef void vnc_connection_tight_compute_predicted_func(VncConnection *conn, guint8 *,
 							  guint8 *, guint8 *,
 							  guint8 *);
@@ -156,19 +142,10 @@ struct _VncConnection
 	char write_buffer[4096];
 	size_t write_offset;
 
-	gboolean perfect_match;
-	struct vnc_framebuffer local;
-
-	int rm, gm, bm;
-	int rrs, grs, brs;
-	int rls, gls, bls;
+	VncFramebuffer *fb;
+	gboolean fbSwapRemote;
 
-	vnc_connection_blt_func *blt;
-	vnc_connection_fill_func *fill;
-	vnc_connection_set_pixel_at_func *set_pixel_at;
-	vnc_connection_hextile_func *hextile;
 	vnc_connection_rich_cursor_blt_func *rich_cursor_blt;
-	vnc_connection_rgb24_blt_func *rgb24_blt;
 	vnc_connection_tight_compute_predicted_func *tight_compute_predicted;
 	vnc_connection_tight_sum_pixel_func *tight_sum_pixel;
 
@@ -1070,6 +1047,11 @@ gboolean vnc_connection_set_pixel_format(VncConnection *conn,
 }
 
 
+const VncPixelFormat *vnc_connection_get_pixel_format(VncConnection *conn)
+{
+	return &conn->fmt;
+}
+
 gboolean vnc_connection_set_encodings(VncConnection *conn, int n_encoding, gint32 *encoding)
 {
 	guint8 pad[1] = {0};
@@ -1215,59 +1197,37 @@ gboolean vnc_connection_client_cut_text(VncConnection *conn,
 	return !vnc_connection_has_error(conn);
 }
 
+
 static inline guint8 *vnc_connection_get_local(VncConnection *conn, int x, int y)
 {
-	return conn->local.data +
-		(y * conn->local.linesize) +
-		(x * conn->local.bpp);
-}
+	const VncPixelFormat *local = vnc_framebuffer_get_local_format(conn->fb);
+	int rowstride = vnc_framebuffer_get_rowstride(conn->fb);
 
-static guint8 vnc_connection_swap_img_8(VncConnection *conn G_GNUC_UNUSED, guint8 pixel)
-{
-	return pixel;
+	return vnc_framebuffer_get_buffer(conn->fb) +
+		(y * rowstride) +
+		(x * (local->bits_per_pixel / 8));
 }
 
+
 static guint8 vnc_connection_swap_rfb_8(VncConnection *conn G_GNUC_UNUSED, guint8 pixel)
 {
 	return pixel;
 }
 
-/* local host native format -> X server image format */
-static guint16 vnc_connection_swap_img_16(VncConnection *conn, guint16 pixel)
-{
-	if (G_BYTE_ORDER != conn->local.byte_order)
-		return  (((pixel >> 8) & 0xFF) << 0) |
-			(((pixel >> 0) & 0xFF) << 8);
-	else
-		return pixel;
-}
-
 /* VNC server RFB  format ->  local host native format */
 static guint16 vnc_connection_swap_rfb_16(VncConnection *conn, guint16 pixel)
 {
-	if (conn->fmt.byte_order != G_BYTE_ORDER)
+	if (conn->fbSwapRemote)
 		return  (((pixel >> 8) & 0xFF) << 0) |
 			(((pixel >> 0) & 0xFF) << 8);
 	else
 		return pixel;
 }
 
-/* local host native format -> X server image format */
-static guint32 vnc_connection_swap_img_32(VncConnection *conn, guint32 pixel)
-{
-	if (G_BYTE_ORDER != conn->local.byte_order)
-		return  (((pixel >> 24) & 0xFF) <<  0) |
-			(((pixel >> 16) & 0xFF) <<  8) |
-			(((pixel >>  8) & 0xFF) << 16) |
-			(((pixel >>  0) & 0xFF) << 24);
-	else
-		return pixel;
-}
-
 /* VNC server RFB  format ->  local host native format */
 static guint32 vnc_connection_swap_rfb_32(VncConnection *conn, guint32 pixel)
 {
-	if (conn->fmt.byte_order != G_BYTE_ORDER)
+	if (conn->fbSwapRemote)
 		return  (((pixel >> 24) & 0xFF) <<  0) |
 			(((pixel >> 16) & 0xFF) <<  8) |
 			(((pixel >>  8) & 0xFF) << 16) |
@@ -1276,62 +1236,61 @@ static guint32 vnc_connection_swap_rfb_32(VncConnection *conn, guint32 pixel)
 		return pixel;
 }
 
-#define SPLICE_I(a, b) a ## b
-#define SPLICE(a, b) SPLICE_I(a, b)
+#define SRC 8
+#define DST 8
+#include "vncconnectionblt.h"
+#undef SRC
+#undef DST
+
+#define SRC 8
+#define DST 16
+#include "vncconnectionblt.h"
+#undef SRC
+#undef DST
 
 #define SRC 8
-#include "blt1.h"
+#define DST 32
+#include "vncconnectionblt.h"
 #undef SRC
+#undef DST
+
 
 #define SRC 16
-#include "blt1.h"
+#define DST 8
+#include "vncconnectionblt.h"
 #undef SRC
+#undef DST
 
-#define SRC 32
-#include "blt1.h"
+#define SRC 16
+#define DST 16
+#include "vncconnectionblt.h"
 #undef SRC
+#undef DST
 
-static vnc_connection_blt_func *vnc_connection_blt_table[3][3] = {
-	{  vnc_connection_blt_8x8,  vnc_connection_blt_8x16,  vnc_connection_blt_8x32 },
-	{ vnc_connection_blt_16x8, vnc_connection_blt_16x16, vnc_connection_blt_16x32 },
-	{ vnc_connection_blt_32x8, vnc_connection_blt_32x16, vnc_connection_blt_32x32 },
-};
+#define SRC 16
+#define DST 32
+#include "vncconnectionblt.h"
+#undef SRC
+#undef DST
 
-static vnc_connection_hextile_func *vnc_connection_hextile_table[3][3] = {
-	{ (vnc_connection_hextile_func *)vnc_connection_hextile_8x8,
-	  (vnc_connection_hextile_func *)vnc_connection_hextile_8x16,
-	  (vnc_connection_hextile_func *)vnc_connection_hextile_8x32 },
-	{ (vnc_connection_hextile_func *)vnc_connection_hextile_16x8,
-	  (vnc_connection_hextile_func *)vnc_connection_hextile_16x16,
-	  (vnc_connection_hextile_func *)vnc_connection_hextile_16x32 },
-	{ (vnc_connection_hextile_func *)vnc_connection_hextile_32x8,
-	  (vnc_connection_hextile_func *)vnc_connection_hextile_32x16,
-	  (vnc_connection_hextile_func *)vnc_connection_hextile_32x32 },
-};
 
-static vnc_connection_set_pixel_at_func *vnc_connection_set_pixel_at_table[3][3] = {
-	{ (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_8x8,
-	  (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_8x16,
-	  (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_8x32 },
-	{ (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_16x8,
-	  (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_16x16,
-	  (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_16x32 },
-	{ (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_32x8,
-	  (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_32x16,
-	  (vnc_connection_set_pixel_at_func *)vnc_connection_set_pixel_at_32x32 },
-};
+#define SRC 32
+#define DST 8
+#include "vncconnectionblt.h"
+#undef SRC
+#undef DST
 
-static vnc_connection_fill_func *vnc_connection_fill_table[3][3] = {
-	{ (vnc_connection_fill_func *)vnc_connection_fill_8x8,
-	  (vnc_connection_fill_func *)vnc_connection_fill_8x16,
-	  (vnc_connection_fill_func *)vnc_connection_fill_8x32 },
-	{ (vnc_connection_fill_func *)vnc_connection_fill_16x8,
-	  (vnc_connection_fill_func *)vnc_connection_fill_16x16,
-	  (vnc_connection_fill_func *)vnc_connection_fill_16x32 },
-	{ (vnc_connection_fill_func *)vnc_connection_fill_32x8,
-	  (vnc_connection_fill_func *)vnc_connection_fill_32x16,
-	  (vnc_connection_fill_func *)vnc_connection_fill_32x32 },
-};
+#define SRC 32
+#define DST 16
+#include "vncconnectionblt.h"
+#undef SRC
+#undef DST
+
+#define SRC 32
+#define DST 32
+#include "vncconnectionblt.h"
+#undef SRC
+#undef DST
 
 static vnc_connection_rich_cursor_blt_func *vnc_connection_rich_cursor_blt_table[3] = {
 	vnc_connection_rich_cursor_blt_8x32,
@@ -1339,12 +1298,6 @@ static vnc_connection_rich_cursor_blt_func *vnc_connection_rich_cursor_blt_table
 	vnc_connection_rich_cursor_blt_32x32,
 };
 
-static vnc_connection_rgb24_blt_func *vnc_connection_rgb24_blt_table[3] = {
-	(vnc_connection_rgb24_blt_func *)vnc_connection_rgb24_blt_32x8,
-	(vnc_connection_rgb24_blt_func *)vnc_connection_rgb24_blt_32x16,
-	(vnc_connection_rgb24_blt_func *)vnc_connection_rgb24_blt_32x32,
-};
-
 static vnc_connection_tight_compute_predicted_func *vnc_connection_tight_compute_predicted_table[3] = {
 	(vnc_connection_tight_compute_predicted_func *)vnc_connection_tight_compute_predicted_8x8,
 	(vnc_connection_tight_compute_predicted_func *)vnc_connection_tight_compute_predicted_16x16,
@@ -1357,52 +1310,39 @@ static vnc_connection_tight_sum_pixel_func *vnc_connection_tight_sum_pixel_table
 	(vnc_connection_tight_sum_pixel_func *)vnc_connection_tight_sum_pixel_32x32,
 };
 
-/* a fast blit for the perfect match scenario */
-static void vnc_connection_blt_fast(VncConnection *conn, guint8 *src, int pitch,
-				    int x, int y, int width, int height)
-{
-	guint8 *dst = vnc_connection_get_local(conn, x, y);
-	int i;
-	for (i = 0; i < height; i++) {
-		memcpy(dst, src, width * conn->local.bpp);
-		dst += conn->local.linesize;
-		src += pitch;
-	}
-}
-
-static void vnc_connection_blt(VncConnection *conn, guint8 *src, int pitch,
-			       int x, int y, int width, int height)
-{
-	conn->blt(conn, src, pitch, x, y, width, height);
-}
 
 static void vnc_connection_raw_update(VncConnection *conn,
 				      guint16 x, guint16 y,
 				      guint16 width, guint16 height)
 {
-	guint8 *dst;
-	int i;
-
 	/* optimize for perfect match between server/client
 	   FWIW, in the local case, we ought to be doing a write
 	   directly from the source framebuffer and a read directly
 	   into the client framebuffer
 	*/
-	if (conn->perfect_match) {
-		dst = vnc_connection_get_local(conn, x, y);
+	if (vnc_framebuffer_perfect_format_match(conn->fb)) {
+		int i;
+		int rowstride = vnc_framebuffer_get_rowstride(conn->fb);
+		guint8 *dst = vnc_framebuffer_get_buffer(conn->fb);
+
+		dst += (y * rowstride) + (x * (conn->fmt.bits_per_pixel/8));
+
 		for (i = 0; i < height; i++) {
-			vnc_connection_read(conn, dst, width * conn->local.bpp);
-			dst += conn->local.linesize;
+			vnc_connection_read(conn, dst,
+					    width * (conn->fmt.bits_per_pixel/8));
+			dst += rowstride;
 		}
-		return;
-	}
+	} else {
+		guint8 *dst;
+		int i;
 
-	dst = g_malloc(width * (conn->fmt.bits_per_pixel / 8));
-	for (i = 0; i < height; i++) {
-		vnc_connection_read(conn, dst, width * (conn->fmt.bits_per_pixel / 8));
-		vnc_connection_blt(conn, dst, 0, x, y + i, width, 1);
+		dst = g_malloc(width * (conn->fmt.bits_per_pixel / 8));
+		for (i = 0; i < height; i++) {
+			vnc_connection_read(conn, dst, width * (conn->fmt.bits_per_pixel / 8));
+			vnc_framebuffer_blt(conn->fb, dst, 0, x, y + i, width, 1);
+		}
+		g_free(dst);
 	}
-	g_free(dst);
 }
 
 static void vnc_connection_copyrect_update(VncConnection *conn,
@@ -1410,28 +1350,60 @@ static void vnc_connection_copyrect_update(VncConnection *conn,
 					   guint16 width, guint16 height)
 {
 	int src_x, src_y;
-	guint8 *dst, *src;
-	int pitch = conn->local.linesize;
-	int i;
 
 	src_x = vnc_connection_read_u16(conn);
 	src_y = vnc_connection_read_u16(conn);
 
-	if (src_y < dst_y) {
-		pitch = -pitch;
-		src_y += (height - 1);
-		dst_y += (height - 1);
-	}
+	vnc_framebuffer_copyrect(conn->fb,
+				 src_x, src_y,
+				 dst_x, dst_y,
+				 width, height);
+}
+
+static void vnc_connection_hextile_rect(VncConnection *conn,
+					guint8 flags,
+					guint16 x, guint16 y,
+					guint16 width, guint16 height,
+					guint8 *fg, guint8 *bg)
+{
+	int i;
+
+	if (flags & 0x01) {
+		vnc_connection_raw_update(conn, x, y, width, height);
+	} else {
+		/* Background Specified */
+		if (flags & 0x02)
+			vnc_connection_read_pixel(conn, bg);
+
+		/* Foreground Specified */
+		if (flags & 0x04)
+			vnc_connection_read_pixel(conn, fg);
+
+		vnc_framebuffer_fill(conn->fb, bg, x, y, width, height);
+
+		/* AnySubrects */
+		if (flags & 0x08) {
+			guint8 n_rects = vnc_connection_read_u8(conn);
+
+			for (i = 0; i < n_rects; i++) {
+				guint8 xy, wh;
+
+				/* SubrectsColored */
+				if (flags & 0x10)
+					vnc_connection_read_pixel(conn, fg);
+
+				xy = vnc_connection_read_u8(conn);
+				wh = vnc_connection_read_u8(conn);
 
-	dst = vnc_connection_get_local(conn, dst_x, dst_y);
-	src = vnc_connection_get_local(conn, src_x, src_y);
-	for (i = 0; i < height; i++) {
-		memmove(dst, src, width * conn->local.bpp);
-		dst += pitch;
-		src += pitch;
+				vnc_framebuffer_fill(conn->fb, fg,
+						     x + nibhi(xy), y + niblo(xy),
+						     nibhi(wh) + 1, niblo(wh) + 1);
+			}
+		}
 	}
 }
 
+
 static void vnc_connection_hextile_update(VncConnection *conn,
 					  guint16 x, guint16 y,
 					  guint16 width, guint16 height)
@@ -1448,22 +1420,14 @@ static void vnc_connection_hextile_update(VncConnection *conn,
 			int h = MIN(16, height - j);
 
 			flags = vnc_connection_read_u8(conn);
-			conn->hextile(conn, flags, x + i, y + j, w, h, fg, bg);
+			vnc_connection_hextile_rect(conn, flags,
+						    x + i, y + j,
+						    w, h,
+						    fg, bg);
 		}
 	}
 }
 
-static void vnc_connection_fill(VncConnection *conn, guint8 *color,
-				guint16 x, guint16 y, guint16 width, guint16 height)
-{
-	conn->fill(conn, color, x, y, width, height);
-}
-
-static void vnc_connection_set_pixel_at(VncConnection *conn, int x, int y, guint8 *pixel)
-{
-	conn->set_pixel_at(conn, x, y, pixel);
-}
-
 static void vnc_connection_rre_update(VncConnection *conn,
 				      guint16 x, guint16 y,
 				      guint16 width, guint16 height)
@@ -1474,7 +1438,7 @@ static void vnc_connection_rre_update(VncConnection *conn,
 
 	num = vnc_connection_read_u32(conn);
 	vnc_connection_read_pixel(conn, bg);
-	vnc_connection_fill(conn, bg, x, y, width, height);
+	vnc_framebuffer_fill(conn->fb, bg, x, y, width, height);
 
 	for (i = 0; i < num; i++) {
 		guint8 fg[4];
@@ -1486,8 +1450,8 @@ static void vnc_connection_rre_update(VncConnection *conn,
 		sub_w = vnc_connection_read_u16(conn);
 		sub_h = vnc_connection_read_u16(conn);
 
-		vnc_connection_fill(conn, fg,
-				    x + sub_x, y + sub_y, sub_w, sub_h);
+		vnc_framebuffer_fill(conn->fb, fg,
+				     x + sub_x, y + sub_y, sub_w, sub_h);
 	}
 }
 
@@ -1536,7 +1500,7 @@ static void vnc_connection_zrle_update_tile_blit(VncConnection *conn,
 	for (i = 0; i < width * height; i++)
 		vnc_connection_read_cpixel(conn, blit_data + (i * bpp));
 
-	vnc_connection_blt(conn, blit_data, width * bpp, x, y, width, height);
+	vnc_framebuffer_blt(conn->fb, blit_data, width * bpp, x, y, width, height);
 }
 
 static guint8 vnc_connection_read_zrle_pi(VncConnection *conn, int palette_size)
@@ -1579,8 +1543,8 @@ static void vnc_connection_zrle_update_tile_palette(VncConnection *conn,
 		for (i = 0; i < width; i++) {
 			int ind = vnc_connection_read_zrle_pi(conn, palette_size);
 
-			vnc_connection_set_pixel_at(conn, x + i, y + j,
-						    palette[ind & 0x7F]);
+			vnc_framebuffer_set_pixel_at(conn->fb, palette[ind & 0x7F],
+						     x + i, y + j);
 		}
 	}
 }
@@ -1611,7 +1575,7 @@ static void vnc_connection_zrle_update_tile_rle(VncConnection *conn,
 				vnc_connection_read_cpixel(conn, pixel);
 				rl = vnc_connection_read_zrle_rl(conn);
 			}
-			vnc_connection_set_pixel_at(conn, x + i, y + j, pixel);
+			vnc_framebuffer_set_pixel_at(conn->fb, pixel, x + i, y + j);
 			rl -= 1;
 		}
 	}
@@ -1640,7 +1604,7 @@ static void vnc_connection_zrle_update_tile_prle(VncConnection *conn,
 					rl = 1;
 			}
 
-			vnc_connection_set_pixel_at(conn, x + i, y + j, palette[pi]);
+			vnc_framebuffer_set_pixel_at(conn->fb, palette[pi], x + i, y + j);
 			rl -= 1;
 		}
 	}
@@ -1658,7 +1622,7 @@ static void vnc_connection_zrle_update_tile(VncConnection *conn, guint16 x, guin
 	} else if (subencoding == 1) {
 		/* Solid tile of a single color */
 		vnc_connection_read_cpixel(conn, pixel);
-		vnc_connection_fill(conn, pixel, x, y, width, height);
+		vnc_framebuffer_fill(conn->fb, pixel, x, y, width, height);
 	} else if ((subencoding >= 2) && (subencoding <= 16)) {
 		/* Packed palette types */
 		vnc_connection_zrle_update_tile_palette(conn, subencoding,
@@ -1715,12 +1679,6 @@ static void vnc_connection_zrle_update(VncConnection *conn,
 	g_free(zlib_data);
 }
 
-static void vnc_connection_rgb24_blt(VncConnection *conn, int x, int y,
-				     int width, int height, guint8 *data, int pitch)
-{
-	conn->rgb24_blt(conn, x, y, width, height, data, pitch);
-}
-
 static guint32 vnc_connection_read_cint(VncConnection *conn)
 {
 	guint32 value = 0;
@@ -1779,7 +1737,7 @@ static void vnc_connection_tight_update_copy(VncConnection *conn,
 	for (j = 0; j < height; j++) {
 		for (i = 0; i < width; i++) {
 			vnc_connection_read_tpixel(conn, pixel);
-			vnc_connection_set_pixel_at(conn, x + i, y + j, pixel);
+			vnc_framebuffer_set_pixel_at(conn->fb, pixel, x + i, y + j);
 		}
 	}
 }
@@ -1810,8 +1768,7 @@ static void vnc_connection_tight_update_palette(VncConnection *conn,
 			guint8 ind;
 
 			ind = vnc_connection_tight_get_pi(conn, &ra, i, palette_size);
-			vnc_connection_set_pixel_at(conn, x + i, y + j,
-						    &palette[ind * 4]);
+			vnc_framebuffer_set_pixel_at(conn->fb, &palette[ind * 4], x + i, y + j);
 		}
 	}
 }
@@ -1874,7 +1831,7 @@ static void vnc_connection_tight_update_gradient(VncConnection *conn,
 		}
 
 		/* write out row of pixel data */
-		vnc_connection_blt(conn, row, width * bpp, x, y + j, width, 1);
+		vnc_framebuffer_blt(conn->fb, row, width * bpp, x, y + j, width, 1);
 
 		/* swap last row and current row */
 		tmp_row = last_row;
@@ -1891,7 +1848,7 @@ static void jpeg_draw(void *opaque, int x, int y, int w, int h,
 {
 	VncConnection *conn = opaque;
 
-	vnc_connection_rgb24_blt(conn, x, y, w, h, data, stride);
+	vnc_framebuffer_rgb24_blt(conn->fb, data, stride, x, y, w, h);
 }
 
 static void vnc_connection_tight_update_jpeg(VncConnection *conn, guint16 x, guint16 y,
@@ -1995,7 +1952,7 @@ static void vnc_connection_tight_update(VncConnection *conn,
 		/* fill */
 		/* FIXME check each width; endianness */
 		vnc_connection_read_tpixel(conn, pixel);
-		vnc_connection_fill(conn, pixel, x, y, width, height);
+		vnc_framebuffer_fill(conn->fb, pixel, x, y, width, height);
 	} else if (ccontrol == 9) {
 		/* jpeg */
 		guint32 length;
@@ -2018,6 +1975,7 @@ static void vnc_connection_update(VncConnection *conn, int x, int y, int width,
 {
 	if (conn->has_error || !conn->ops.update)
 		return;
+	GVNC_DEBUG("Notify update area (%dx%d) at location %d,%d", width, height, x, y);
 	if (!conn->ops.update(conn->ops_data, x, y, width, height)) {
 		GVNC_DEBUG("Closing the connection: vnc_connection_update");
 		conn->has_error = TRUE;
@@ -2198,8 +2156,8 @@ static void vnc_connection_framebuffer_update(VncConnection *conn, gint32 etype,
 					      guint16 x, guint16 y,
 					      guint16 width, guint16 height)
 {
-	GVNC_DEBUG("FramebufferUpdate(%d, %d, %d, %d, %d)",
-		   etype, x, y, width, height);
+	GVNC_DEBUG("FramebufferUpdate type=%d area (%dx%d) at location %d,%d",
+		   etype, width, height, x, y);
 
 	switch (etype) {
 	case GVNC_ENCODING_RAW:
@@ -3448,6 +3406,9 @@ void vnc_connection_free(VncConnection *conn)
 	if (vnc_connection_is_open(conn))
 		vnc_connection_close(conn);
 
+	if (conn->fb)
+		g_object_unref(G_OBJECT(conn->fb));
+
 	g_free(conn);
 	conn = NULL;
 }
@@ -3898,86 +3859,28 @@ gboolean vnc_connection_set_credential_x509_cert(VncConnection *conn, const char
 }
 
 
-gboolean vnc_connection_set_local(VncConnection *conn, struct vnc_framebuffer *fb)
+gboolean vnc_connection_set_framebuffer(VncConnection *conn, VncFramebuffer *fb)
 {
-	int i, j, n;
-	int depth;
+	const VncPixelFormat *remote;
+	int i;
 
-	memcpy(&conn->local, fb, sizeof(*fb));
+	if (conn->fb)
+		g_object_unref(G_OBJECT(conn->fb));
+	conn->fb = fb;
+	g_object_ref(G_OBJECT(conn->fb));
+
+	remote = vnc_framebuffer_get_remote_format(conn->fb);
+
+	conn->fbSwapRemote = remote->byte_order != G_BYTE_ORDER;
+
+        i = conn->fmt.bits_per_pixel / 8;
+
+        if (i == 4) i = 3;
 
-	if (fb->bpp == (conn->fmt.bits_per_pixel / 8) &&
-	    fb->red_mask == conn->fmt.red_max &&
-	    fb->green_mask == conn->fmt.green_max &&
-	    fb->blue_mask == conn->fmt.blue_max &&
-	    fb->red_shift == conn->fmt.red_shift &&
-	    fb->green_shift == conn->fmt.green_shift &&
-	    fb->blue_shift == conn->fmt.blue_shift &&
-	    fb->byte_order == G_BYTE_ORDER &&
-	    conn->fmt.byte_order == G_BYTE_ORDER)
-		conn->perfect_match = TRUE;
-	else
-		conn->perfect_match = FALSE;
-
-	depth = conn->fmt.depth;
-	if (depth == 32)
-		depth = 24;
-
-	conn->rm = conn->local.red_mask & conn->fmt.red_max;
-	conn->gm = conn->local.green_mask & conn->fmt.green_max;
-	conn->bm = conn->local.blue_mask & conn->fmt.blue_max;
-	GVNC_DEBUG("Mask local: %3d %3d %3d\n"
-		   "    remote: %3d %3d %3d\n"
-		   "    merged: %3d %3d %3d",
-		   conn->local.red_mask, conn->local.green_mask, conn->local.blue_mask,
-		   conn->fmt.red_max, conn->fmt.green_max, conn->fmt.blue_max,
-		   conn->rm, conn->gm, conn->bm);
-
-	/* Setup shifts assuming matched bpp (but not necessarily match rgb order)*/
-	conn->rrs = conn->fmt.red_shift;
-	conn->grs = conn->fmt.green_shift;
-	conn->brs = conn->fmt.blue_shift;
-
-	conn->rls = conn->local.red_shift;
-	conn->gls = conn->local.green_shift;
-	conn->bls = conn->local.blue_shift;
-
-	/* This adjusts for remote having more bpp than local */
-	for (n = conn->fmt.red_max; n > conn->local.red_mask ; n>>= 1)
-		conn->rrs++;
-	for (n = conn->fmt.green_max; n > conn->local.green_mask ; n>>= 1)
-		conn->grs++;
-	for (n = conn->fmt.blue_max; n > conn->local.blue_mask ; n>>= 1)
-		conn->brs++;
-
-	/* This adjusts for remote having less bpp than remote */
-	for (n = conn->local.red_mask ; n > conn->fmt.red_max ; n>>= 1)
-		conn->rls++;
-	for (n = conn->local.green_mask ; n > conn->fmt.green_max ; n>>= 1)
-		conn->gls++;
-	for (n = conn->local.blue_mask ; n > conn->fmt.blue_max ; n>>= 1)
-		conn->bls++;
-	GVNC_DEBUG("Pixel shifts\n   right: %3d %3d %3d\n    left: %3d %3d %3d",
-		   conn->rrs, conn->grs, conn->brs,
-		   conn->rls, conn->gls, conn->bls);
-
-	i = conn->fmt.bits_per_pixel / 8;
-	j = conn->local.bpp;
-
-	if (i == 4) i = 3;
-	if (j == 4) j = 3;
-
-	conn->blt = vnc_connection_blt_table[i - 1][j - 1];
-	conn->fill = vnc_connection_fill_table[i - 1][j - 1];
-	conn->set_pixel_at = vnc_connection_set_pixel_at_table[i - 1][j - 1];
-	conn->hextile = vnc_connection_hextile_table[i - 1][j - 1];
 	conn->rich_cursor_blt = vnc_connection_rich_cursor_blt_table[i - 1];
-	conn->rgb24_blt = vnc_connection_rgb24_blt_table[i - 1];
 	conn->tight_compute_predicted = vnc_connection_tight_compute_predicted_table[i - 1];
 	conn->tight_sum_pixel = vnc_connection_tight_sum_pixel_table[i - 1];
 
-	if (conn->perfect_match)
-		conn->blt = vnc_connection_blt_fast;
-
 	return !vnc_connection_has_error(conn);
 }
 
diff --git a/src/vncconnection.h b/src/vncconnection.h
index 1c8ef27..9c3de73 100644
--- a/src/vncconnection.h
+++ b/src/vncconnection.h
@@ -23,7 +23,7 @@
 
 #include <glib.h>
 
-#include "vncpixelformat.h"
+#include "vncframebuffer.h"
 
 typedef struct _VncConnection VncConnection;
 
@@ -50,28 +50,6 @@ struct vnc_connection_ops
 };
 
 
-struct vnc_framebuffer
-{
-	guint8 *data;
-
-	int width;
-	int height;
-
-	int linesize;
-
-	guint16 byte_order;
-	int depth;
-	int bpp;
-
-	int red_mask;
-	int green_mask;
-	int blue_mask;
-
-	int red_shift;
-	int blue_shift;
-	int green_shift;
-};
-
 typedef enum {
 	GVNC_ENCODING_RAW = 0,
 	GVNC_ENCODING_COPY_RECT = 1,
@@ -180,9 +158,12 @@ gboolean vnc_connection_set_encodings(VncConnection *conn, int n_encoding, gint3
 gboolean vnc_connection_set_pixel_format(VncConnection *conn,
 					 const VncPixelFormat *fmt);
 
+const VncPixelFormat *vnc_connection_get_pixel_format(VncConnection *conn);
+
 gboolean vnc_connection_has_error(VncConnection *conn);
 
-gboolean vnc_connection_set_local(VncConnection *conn, struct vnc_framebuffer *fb);
+gboolean vnc_connection_set_framebuffer(VncConnection *conn,
+					VncFramebuffer *fb);
 
 const char *vnc_connection_get_name(VncConnection *conn);
 int vnc_connection_get_width(VncConnection *conn);
diff --git a/src/vncconnectionblt.h b/src/vncconnectionblt.h
new file mode 100644
index 0000000..031fcf2
--- /dev/null
+++ b/src/vncconnectionblt.h
@@ -0,0 +1,163 @@
+/*
+ * GTK VNC Widget
+ *
+ * Copyright (C) 2006  Anthony Liguori <anthony codemonkey ws>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/* Ordering of the SPLICE calls here is important to avoid
+ * a Solaris compiler/cpp  whitespace bug
+ */
+#define SPLICE_I(a, b) a ## b
+#define SPLICE(a, b) SPLICE_I(a, b)
+#define src_pixel_t SPLICE(SPLICE(uint, SRC), _t)
+#define ssrc_pixel_t SPLICE(SPLICE(int, SRC), _t)
+#define dst_pixel_t SPLICE(SPLICE(uint, DST), _t)
+#define SUFFIX() SPLICE(SRC,SPLICE(x,DST))
+#define RICH_CURSOR_BLIT SPLICE(vnc_connection_rich_cursor_blt_, SUFFIX())
+#define TIGHT_COMPUTE_PREDICTED SPLICE(vnc_connection_tight_compute_predicted_, SUFFIX())
+#define TIGHT_SUM_PIXEL SPLICE(vnc_connection_tight_sum_pixel_, SUFFIX())
+#define SWAP_RFB(conn, pixel) SPLICE(vnc_connection_swap_rfb_, SRC)(conn, pixel)
+#define SWAP_IMG(conn, pixel) SPLICE(vnc_connection_swap_img_, DST)(conn, pixel)
+#define COMPONENT(color, pixel) ((SWAP_RFB(conn, pixel) >> conn->fmt.SPLICE(color, _shift) & conn->fmt.SPLICE(color, _max)))
+
+
+/* We need to convert to a GdkPixbuf which is always 32-bit */
+#if DST == 32
+static void RICH_CURSOR_BLIT(VncConnection *conn, guint8 *pixbuf,
+			     guint8 *image, guint8 *mask, int pitch,
+			     guint16 width, guint16 height)
+{
+	int x1, y1;
+	guint32 *dst = (guint32 *)pixbuf;
+	guint8 *src = image;
+	guint8 *alpha = mask;
+	int as, rs, gs, bs, n;
+
+	/*
+	 * GdkPixbuf is always 32-bit RGB, so we can't use the precomputed
+	 * left / right shift data from conn->{r,g,b}{r,l}s. The latter
+	 * is set for the local display depth, which may be different
+	 * to GdkPixbuf's fixed 32-bit RGBA
+	 *
+	 * This function isn't called often, so just re-compute them now
+	 */
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+	as = 0;
+	rs = 8;
+	gs = 16;
+	bs = 24;
+#else
+	as = 24;
+	rs = 16;
+	gs = 8;
+	bs = 0;
+#endif
+
+	/* Then this adjusts for remote having less bpp than 32 */
+	for (n = 255 ; n > conn->fmt.red_max ; n>>= 1)
+		rs++;
+	for (n = 255 ; n > conn->fmt.green_max ; n>>= 1)
+		gs++;
+	for (n = 255 ; n > conn->fmt.blue_max ; n>>= 1)
+		bs++;
+
+	for (y1 = 0; y1 < height; y1++) {
+		src_pixel_t *sp = (src_pixel_t *)src;
+		guint8 *mp = alpha;
+		for (x1 = 0; x1 < width; x1++) {
+			*dst = (COMPONENT(red, *sp) << rs)
+				| (COMPONENT(green, *sp) << gs)
+				| (COMPONENT(blue, *sp) << bs);
+
+			if ((mp[x1 / 8] >> (7 - (x1 % 8))) & 1)
+				*dst |= (0xFF << as);
+
+			dst++;
+			sp++;
+		}
+		src += pitch;
+		alpha += ((width + 7) / 8);
+	}
+}
+#endif
+
+
+#if SRC == DST
+
+static void TIGHT_COMPUTE_PREDICTED(VncConnection *conn, src_pixel_t *ppixel,
+				    src_pixel_t *lp, src_pixel_t *cp,
+				    src_pixel_t *llp)
+{
+	ssrc_pixel_t red, green, blue;
+
+	red = COMPONENT(red, *lp) + COMPONENT(red, *cp) - COMPONENT(red, *llp);
+	red = MAX(red, 0);
+	red = MIN(red, conn->fmt.red_max);
+
+	green = COMPONENT(green, *lp) + COMPONENT(green, *cp) - COMPONENT(green, *llp);
+	green = MAX(green, 0);
+	green = MIN(green, conn->fmt.green_max);
+
+	blue = COMPONENT(blue, *lp) + COMPONENT(blue, *cp) - COMPONENT(blue, *llp);
+	blue = MAX(blue, 0);
+	blue = MIN(blue, conn->fmt.blue_max);
+
+	*ppixel = SWAP_RFB(conn,
+		       (red << conn->fmt.red_shift) |
+		       (green << conn->fmt.green_shift) |
+		       (blue << conn->fmt.blue_shift));
+}
+
+static void TIGHT_SUM_PIXEL(VncConnection *conn,
+			    src_pixel_t *lhs, src_pixel_t *rhs)
+{
+	src_pixel_t red, green, blue;
+
+	red = COMPONENT(red, *lhs) + COMPONENT(red, *rhs);
+	green = COMPONENT(green, *lhs) + COMPONENT(green, *rhs);
+	blue = COMPONENT(blue, *lhs) + COMPONENT(blue, *rhs);
+
+	*lhs = SWAP_RFB(conn,
+		    ((red & conn->fmt.red_max) << conn->fmt.red_shift) |
+		    ((green & conn->fmt.green_max) << conn->fmt.green_shift) |
+		    ((blue & conn->fmt.blue_max) << conn->fmt.blue_shift));
+}
+
+#endif
+
+#undef SPLICE
+#undef SPLICE_T
+#undef SUFFIX
+#undef RICH_CURSOR_BLIT
+#undef TIGHT_SUM_PIXEL
+#undef TIGHT_COMPUTE_PREDICTED
+#undef SWAP_RFB
+#undef SWAP_IMG
+#undef COMPONENT
+#undef dst_pixel_t
+#undef src_pixel_t
+#undef ssrc_pixel_t
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index 1af3e23..33c310f 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -24,6 +24,7 @@
 #include "vncdisplay.h"
 #include "coroutine.h"
 #include "vncconnection.h"
+#include "vncimageframebuffer.h"
 #include "utils.h"
 #include "vncmarshal.h"
 #include "config.h"
@@ -59,14 +60,13 @@ struct _VncDisplayPrivate
 	char *host;
 	char *port;
 	GdkGC *gc;
-	GdkImage *image;
 	GdkPixmap *pixmap;
 	GdkCursor *null_cursor;
 	GdkCursor *remote_cursor;
 
-	struct vnc_framebuffer fb;
 	struct coroutine coroutine;
 	VncConnection *conn;
+	VncImageFramebuffer *fb;
 
 	guint open_id;
 	VncDisplayDepthColor depth;
@@ -304,19 +304,23 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *expose)
 	GdkRectangle drawn;
 	GdkRegion *clear, *copy;
 #endif
+	int fbw, fbh;
 
-	GVNC_DEBUG("Expose %dx%d @ %d,%d",
-		   expose->area.x,
-		   expose->area.y,
+	fbw = vnc_framebuffer_get_width(VNC_FRAMEBUFFER(priv->fb));
+	fbh = vnc_framebuffer_get_height(VNC_FRAMEBUFFER(priv->fb));
+
+	GVNC_DEBUG("Expose area %dx%d at location %d,%d",
 		   expose->area.width,
-		   expose->area.height);
+		   expose->area.height,
+		   expose->area.x,
+		   expose->area.y);
 
 	gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
 
-	if (ww > priv->fb.width)
-		mx = (ww - priv->fb.width) / 2;
-	if (wh > priv->fb.height)
-		my = (wh - priv->fb.height) / 2;
+	if (ww > fbw)
+		mx = (ww - fbw) / 2;
+	if (wh > fbh)
+		my = (wh - fbh) / 2;
 
 #if WITH_GTK_CAIRO
 	cr = gdk_cairo_create(gtk_widget_get_window(GTK_WIDGET(obj)));
@@ -338,8 +342,8 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *expose)
 		   behaviour of drawing the rectangle from right to left
 		   to cut out the whole */
 		if (priv->pixmap)
-			cairo_rectangle(cr, mx + priv->fb.width, my,
-					-1 * priv->fb.width, priv->fb.height);
+			cairo_rectangle(cr, mx + fbw, my,
+					-1 * fbw, fbh);
 		cairo_fill(cr);
 	}
 
@@ -348,8 +352,8 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *expose)
 		if (priv->allow_scaling) {
 			double sx, sy;
 			/* Scale to fill window */
-			sx = (double)ww / (double)priv->fb.width;
-			sy = (double)wh / (double)priv->fb.height;
+			sx = (double)ww / (double)fbw;
+			sy = (double)wh / (double)fbh;
 			cairo_scale(cr, sx, sy);
 			gdk_cairo_set_source_pixmap(cr,
 						    priv->pixmap,
@@ -364,10 +368,10 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *expose)
 
 	cairo_destroy(cr);
 #else
-	x = MIN(expose->area.x - mx, priv->fb.width);
-	y = MIN(expose->area.y - my, priv->fb.height);
-	w = MIN(expose->area.x + expose->area.width - mx, priv->fb.width);
-	h = MIN(expose->area.y + expose->area.height - my, priv->fb.height);
+	x = MIN(expose->area.x - mx, fbw);
+	y = MIN(expose->area.y - my, fbh);
+	w = MIN(expose->area.x + expose->area.width - mx, fbw);
+	h = MIN(expose->area.y + expose->area.height - my, fbh);
 	x = MAX(0, x);
 	y = MAX(0, y);
 	w = MAX(0, w);
@@ -590,6 +594,10 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
 {
 	VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv;
 	int ww, wh;
+	int fbw, fbh;
+
+	fbw = vnc_framebuffer_get_width(VNC_FRAMEBUFFER(priv->fb));
+	fbh = vnc_framebuffer_get_height(VNC_FRAMEBUFFER(priv->fb));
 
 	if (priv->conn == NULL || !vnc_connection_is_initialized(priv->conn))
 		return FALSE;
@@ -607,8 +615,8 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
 	/* First apply adjustments to the coords in the motion event */
 	if (priv->allow_scaling) {
 		double sx, sy;
-		sx = (double)priv->fb.width / (double)ww;
-		sy = (double)priv->fb.height / (double)wh;
+		sx = (double)fbw / (double)ww;
+		sy = (double)fbh / (double)wh;
 
 		/* Scaling the desktop, so scale the mouse coords
 		 * by same ratio */
@@ -617,10 +625,10 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
 	} else {
 		int mw = 0, mh = 0;
 
-		if (ww > priv->fb.width)
-			mw = (ww - priv->fb.width) / 2;
-		if (wh > priv->fb.height)
-			mh = (wh - priv->fb.height) / 2;
+		if (ww > fbw)
+			mw = (ww - fbw) / 2;
+		if (wh > fbh)
+			mh = (wh - fbh) / 2;
 
 		/* Not scaling, drawing the desktop centered
 		 * in the larger window, so offset the mouse
@@ -666,8 +674,8 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
 
 			/* Drop out of bounds motion to avoid upsetting
 			 * the server */
-			if (dx < 0 || dx >= priv->fb.width ||
-			    dy < 0 || dy >= priv->fb.height)
+			if (dx < 0 || dx >= fbw ||
+			    dy < 0 || dy >= fbh)
 				return FALSE;
 		} else {
 			/* Just send the delta since last motion event */
@@ -833,10 +841,15 @@ static gboolean on_update(void *opaque, int x, int y, int w, int h)
 	VncDisplayPrivate *priv = obj->priv;
 	int ww, wh;
 	GdkRectangle r = { x, y, w, h };
+	int fbw, fbh;
+
+	fbw = vnc_framebuffer_get_width(VNC_FRAMEBUFFER(priv->fb));
+	fbh = vnc_framebuffer_get_height(VNC_FRAMEBUFFER(priv->fb));
 
 	/* Copy pixbuf to pixmap */
 	gdk_gc_set_clip_rectangle(priv->gc, &r);
-	gdk_draw_image(priv->pixmap, priv->gc, priv->image,
+	gdk_draw_image(priv->pixmap, priv->gc,
+		       vnc_image_framebuffer_get_image(priv->fb),
 		       x, y, x, y, w, h);
 
 	gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
@@ -846,8 +859,8 @@ static gboolean on_update(void *opaque, int x, int y, int w, int h)
 
 		/* Scale the VNC region to produce expose region */
 
-		sx = (double)ww / (double)priv->fb.width;
-		sy = (double)wh / (double)priv->fb.height;
+		sx = (double)ww / (double)fbw;
+		sy = (double)wh / (double)fbh;
 		x *= sx;
 		y *= sy;
 		w *= sx;
@@ -857,10 +870,10 @@ static gboolean on_update(void *opaque, int x, int y, int w, int h)
 
 		/* Offset the VNC region to produce expose region */
 
-		if (ww > priv->fb.width)
-			mw = (ww - priv->fb.width) / 2;
-		if (wh > priv->fb.height)
-			mh = (wh - priv->fb.height) / 2;
+		if (ww > fbw)
+			mw = (ww - fbw) / 2;
+		if (wh > fbh)
+			mh = (wh - fbh) / 2;
 
 		x += mw;
 		y += mh;
@@ -871,42 +884,6 @@ static gboolean on_update(void *opaque, int x, int y, int w, int h)
 	return TRUE;
 }
 
-static void setup_gdk_image(VncDisplay *obj, gint width, gint height)
-{
-	VncDisplayPrivate *priv = obj->priv;
-	GdkVisual *visual;
-
-	visual = gdk_drawable_get_visual(gtk_widget_get_window(GTK_WIDGET(obj)));
-
-	priv->image = gdk_image_new(GDK_IMAGE_FASTEST, visual, width, height);
-	priv->pixmap = gdk_pixmap_new(gtk_widget_get_window(GTK_WIDGET(obj)), width, height, -1);
-
-	GVNC_DEBUG("Visual mask: %3d %3d %3d\n      shift: %3d %3d %3d",
-		   visual->red_mask,
-		   visual->green_mask,
-		   visual->blue_mask,
-		   visual->red_shift,
-		   visual->green_shift,
-		   visual->blue_shift);
-
-	priv->fb.red_mask = visual->red_mask >> visual->red_shift;
-	priv->fb.green_mask = visual->green_mask >> visual->green_shift;
-	priv->fb.blue_mask = visual->blue_mask >> visual->blue_shift;
-	priv->fb.red_shift = visual->red_shift;
-	priv->fb.green_shift = visual->green_shift;
-	priv->fb.blue_shift = visual->blue_shift;
-	priv->fb.depth = priv->image->depth;
-	priv->fb.bpp = priv->image->bpp;
-	priv->fb.width = priv->image->width;
-	priv->fb.height = priv->image->height;
-	priv->fb.linesize = priv->image->bpl;
-	priv->fb.data = (guint8 *)priv->image->mem;
-	priv->fb.byte_order = priv->image->byte_order == GDK_LSB_FIRST ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
-
-	if (priv->force_size)
-		gtk_widget_set_size_request(GTK_WIDGET(obj), width, height);
-}
-
 
 static gboolean emit_signal_auth_cred(gpointer opaque)
 {
@@ -969,18 +946,21 @@ static void emit_signal_delayed(VncDisplay *obj, int signum,
 	coroutine_yield(NULL);
 }
 
-static gboolean do_resize(void *opaque, int width, int height, gboolean quiet)
+static gboolean do_framebuffer_init(VncDisplay *obj,
+				    const VncPixelFormat *remoteFormat,
+				    int width, int height, gboolean quiet)
 {
-	VncDisplay *obj = VNC_DISPLAY(opaque);
 	VncDisplayPrivate *priv = obj->priv;
 	struct signal_data s;
+	GdkVisual *visual;
+	GdkImage *image;
 
 	if (priv->conn == NULL || !vnc_connection_is_initialized(priv->conn))
 		return TRUE;
 
-	if (priv->image) {
-		g_object_unref(priv->image);
-		priv->image = NULL;
+	if (priv->fb) {
+		g_object_unref(priv->fb);
+		priv->fb = NULL;
 	}
 	if (priv->pixmap) {
 		g_object_unref(priv->pixmap);
@@ -997,9 +977,18 @@ static gboolean do_resize(void *opaque, int width, int height, gboolean quiet)
 		priv->gc = gdk_gc_new(gtk_widget_get_window(GTK_WIDGET(obj)));
 	}
 
-	setup_gdk_image(obj, width, height);
+	visual = gdk_drawable_get_visual(gtk_widget_get_window(GTK_WIDGET(obj)));
+	image = gdk_image_new(GDK_IMAGE_FASTEST, visual, width, height);
 
-	vnc_connection_set_local(priv->conn, &priv->fb);
+	priv->fb = vnc_image_framebuffer_new(image, remoteFormat);
+	priv->pixmap = gdk_pixmap_new(gtk_widget_get_window(GTK_WIDGET(obj)), width, height, -1);
+
+	g_object_unref(G_OBJECT(image));
+
+	vnc_connection_set_framebuffer(priv->conn, VNC_FRAMEBUFFER(priv->fb));
+
+	if (priv->force_size)
+		gtk_widget_set_size_request(GTK_WIDGET(obj), width, height);
 
 	if (!quiet) {
 		s.width = width;
@@ -1012,16 +1001,24 @@ static gboolean do_resize(void *opaque, int width, int height, gboolean quiet)
 
 static gboolean on_resize(void *opaque, int width, int height)
 {
-	return do_resize(opaque, width, height, FALSE);
+        VncDisplay *obj = VNC_DISPLAY(opaque);
+	VncDisplayPrivate *priv = obj->priv;
+	const VncPixelFormat *remoteFormat;
+
+	remoteFormat = vnc_connection_get_pixel_format(priv->conn);
+
+	return do_framebuffer_init(opaque, remoteFormat, width, height, FALSE);
 }
 
 static gboolean on_pixel_format(void *opaque,
-				VncPixelFormat *fmt G_GNUC_UNUSED)
+				VncPixelFormat *remoteFormat)
 {
         VncDisplay *obj = VNC_DISPLAY(opaque);
         VncDisplayPrivate *priv = obj->priv;
+	gint16 width = vnc_connection_get_width(priv->conn);
+	gint16 height = vnc_connection_get_height(priv->conn);
 
-        return do_resize(opaque, priv->fb.width, priv->fb.height, TRUE);
+        return do_framebuffer_init(opaque, remoteFormat, width, height, TRUE);
 }
 
 static gboolean on_get_preferred_pixel_format(void *opaque,
@@ -1351,9 +1348,9 @@ static gboolean delayed_unref_object(gpointer data)
 
 	g_assert(obj->priv->coroutine.exited == TRUE);
 
-	if (obj->priv->image) {
-		g_object_unref(obj->priv->image);
-		obj->priv->image = NULL;
+	if (obj->priv->fb) {
+		g_object_unref(obj->priv->fb);
+		obj->priv->fb = NULL;
 	}
 	if (obj->priv->pixmap) {
 		g_object_unref(obj->priv->pixmap);
@@ -1431,13 +1428,16 @@ static void *vnc_coroutine(void *opaque)
 	if (!vnc_connection_set_encodings(priv->conn, n_encodings, encodingsp))
 			goto cleanup;
 
-	if (!vnc_connection_framebuffer_update_request(priv->conn, 0, 0, 0, priv->fb.width, priv->fb.height))
+	if (!vnc_connection_framebuffer_update_request(priv->conn, 0, 0, 0,
+						       vnc_connection_get_width(priv->conn),
+						       vnc_connection_get_height(priv->conn)))
 		goto cleanup;
 
 	GVNC_DEBUG("Running main loop");
 	while ((ret = vnc_connection_server_message(priv->conn))) {
 		if (!vnc_connection_framebuffer_update_request(priv->conn, 1, 0, 0,
-						     priv->fb.width, priv->fb.height))
+							       vnc_connection_get_width(priv->conn),
+							       vnc_connection_get_height(priv->conn)))
 			goto cleanup;
 	}
 
@@ -1625,9 +1625,9 @@ static void vnc_display_finalize (GObject *obj)
 	vnc_connection_free(priv->conn);
 	display->priv->conn = NULL;
 
-	if (priv->image) {
-		g_object_unref(priv->image);
-		priv->image = NULL;
+	if (priv->fb) {
+		g_object_unref(priv->fb);
+		priv->fb = NULL;
 	}
 
 	if (priv->null_cursor) {
@@ -2144,20 +2144,23 @@ GdkPixbuf *vnc_display_get_pixbuf(VncDisplay *obj)
 {
 	VncDisplayPrivate *priv = obj->priv;
 	GdkPixbuf *pixbuf;
+	GdkImage *image;
 
 	if (!priv->conn ||
 	    !vnc_connection_is_initialized(priv->conn))
 		return NULL;
 
+	image = vnc_image_framebuffer_get_image(priv->fb);
+
 	pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
-				priv->image->width, priv->image->height);
+				image->width, image->height);
 
 	if (!gdk_pixbuf_get_from_image(pixbuf,
-				       priv->image,
+				       image,
 				       gdk_colormap_get_system(),
 				       0, 0, 0, 0,
-				       priv->image->width,
-				       priv->image->height))
+				       image->width,
+				       image->height))
 		return NULL;
 
 	return pixbuf;
@@ -2346,11 +2349,11 @@ vnc_display_request_update(VncDisplay *obj)
 
 	GVNC_DEBUG ("Requesting a full update");
 	return vnc_connection_framebuffer_update_request(obj->priv->conn,
-					       0,
-					       0,
-					       0,
-					       obj->priv->fb.width,
-					       obj->priv->fb.height);
+							 0,
+							 0,
+							 0,
+							 vnc_connection_get_width(obj->priv->conn),
+							 vnc_connection_get_width(obj->priv->conn));
 }
 
 #ifdef WIN32



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]