summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--console.c171
-rw-r--r--console.h135
-rw-r--r--curses.c38
-rw-r--r--hw/cirrus_vga.c19
-rw-r--r--hw/nseries.c3
-rw-r--r--hw/palm.c3
-rw-r--r--hw/vga.c101
-rw-r--r--hw/vga_int.h2
-rw-r--r--qemu-common.h3
-rw-r--r--sdl.c88
-rw-r--r--vl.c87
-rw-r--r--vnc.c107
12 files changed, 498 insertions, 259 deletions
diff --git a/console.c b/console.c
index 4e088d7a6f..efd07ce31d 100644
--- a/console.c
+++ b/console.c
@@ -1044,12 +1044,15 @@ void console_select(unsigned int index)
 
     if (index >= MAX_CONSOLES)
         return;
+    active_console->g_width = ds_get_width(active_console->ds);
+    active_console->g_height = ds_get_height(active_console->ds);
     s = consoles[index];
     if (s) {
+        DisplayState *ds = s->ds;
         active_console = s;
-        if (s->console_type != TEXT_CONSOLE && s->g_width && s->g_height
-            && (s->g_width != ds_get_width(s->ds) || s->g_height != ds_get_height(s->ds)))
-            dpy_resize(s->ds, s->g_width, s->g_height);
+        ds->surface = qemu_resize_displaysurface(ds->surface, s->g_width,
+                                                s->g_height, 32, 4 * s->g_width);
+        dpy_resize(s->ds);
         vga_hw_invalidate();
     }
 }
@@ -1157,16 +1160,6 @@ void kbd_put_keysym(int keysym)
 static void text_console_invalidate(void *opaque)
 {
     TextConsole *s = (TextConsole *) opaque;
-
-    if (s->g_width != ds_get_width(s->ds) || s->g_height != ds_get_height(s->ds)) {
-        if (s->console_type == TEXT_CONSOLE_FIXED_SIZE)
-            dpy_resize(s->ds, s->g_width, s->g_height);
-        else {
-            s->g_width = ds_get_width(s->ds);
-            s->g_height = ds_get_height(s->ds);
-            text_console_resize(s);
-        }
-    }
     console_refresh(s);
 }
 
@@ -1346,13 +1339,12 @@ CharDriverState *text_console_init(DisplayState *ds, const char *p)
 
 void qemu_console_resize(QEMUConsole *console, int width, int height)
 {
-    if (console->g_width != width || console->g_height != height
-        || !ds_get_data(console->ds)) {
-        console->g_width = width;
-        console->g_height = height;
-        if (active_console == console) {
-            dpy_resize(console->ds, width, height);
-        }
+    console->g_width = width;
+    console->g_height = height;
+    if (active_console == console) {
+        DisplayState *ds = console->ds;
+        ds->surface = qemu_resize_displaysurface(ds->surface, width, height, 32, 4 * width);
+        dpy_resize(console->ds);
     }
 }
 
@@ -1360,12 +1352,137 @@ void qemu_console_copy(QEMUConsole *console, int src_x, int src_y,
                 int dst_x, int dst_y, int w, int h)
 {
     if (active_console == console) {
-        if (console->ds->dpy_copy)
-            console->ds->dpy_copy(console->ds,
-                            src_x, src_y, dst_x, dst_y, w, h);
-        else {
-            /* TODO */
-            console->ds->dpy_update(console->ds, dst_x, dst_y, w, h);
-        }
+            dpy_copy(console->ds, src_x, src_y, dst_x, dst_y, w, h);
     }
 }
+
+static PixelFormat qemu_default_pixelformat(int bpp)
+{
+    PixelFormat pf;
+
+    memset(&pf, 0x00, sizeof(PixelFormat));
+
+    pf.bits_per_pixel = bpp;
+    pf.bytes_per_pixel = bpp / 8;
+    pf.depth = bpp == 32 ? 24 : bpp;
+
+    switch (bpp) {
+        case 8:
+            pf.rmask = 0x000000E0;
+            pf.gmask = 0x0000001C;
+            pf.bmask = 0x00000003;
+            pf.rmax = 7;
+            pf.gmax = 7;
+            pf.bmax = 3;
+            pf.rshift = 5;
+            pf.gshift = 2;
+            pf.bshift = 0;
+            break;
+        case 16:
+            pf.rmask = 0x0000F800;
+            pf.gmask = 0x000007E0;
+            pf.bmask = 0x0000001F;
+            pf.rmax = 31;
+            pf.gmax = 63;
+            pf.bmax = 31;
+            pf.rshift = 11;
+            pf.gshift = 5;
+            pf.bshift = 0;
+            break;
+        case 24:
+        case 32:
+            pf.rmask = 0x00FF0000;
+            pf.gmask = 0x0000FF00;
+            pf.bmask = 0x000000FF;
+            pf.rmax = 255;
+            pf.gmax = 255;
+            pf.bmax = 255;
+            pf.rshift = 16;
+            pf.gshift = 8;
+            pf.bshift = 0;
+            break;
+        default:
+            break;
+    }
+    return pf;
+}
+
+DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int linesize)
+{
+    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
+    if (surface == NULL) {
+        fprintf(stderr, "qemu_create_displaysurface: malloc failed\n");
+        exit(1);
+    }
+
+    surface->width = width;
+    surface->height = height;
+    surface->linesize = linesize;
+    surface->pf = qemu_default_pixelformat(bpp);
+#ifdef WORDS_BIGENDIAN
+    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
+#else
+    surface->flags = QEMU_ALLOCATED_FLAG;
+#endif
+    surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
+    if (surface->data == NULL) {
+        fprintf(stderr, "qemu_create_displaysurface: malloc failed\n");
+        exit(1);
+    }
+
+    return surface;
+}
+
+DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface,
+                                          int width, int height, int bpp, int linesize)
+{
+    surface->width = width;
+    surface->height = height;
+    surface->linesize = linesize;
+    surface->pf = qemu_default_pixelformat(bpp);
+    if (surface->flags & QEMU_ALLOCATED_FLAG)
+        surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
+    else
+        surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
+    if (surface->data == NULL) {
+        fprintf(stderr, "qemu_resize_displaysurface: malloc failed\n");
+        exit(1);
+    }
+#ifdef WORDS_BIGENDIAN
+    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
+#else
+    surface->flags = QEMU_ALLOCATED_FLAG;
+#endif
+
+    return surface;
+}
+
+DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
+                                              int linesize, uint8_t *data)
+{
+    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
+    if (surface == NULL) {
+        fprintf(stderr, "qemu_create_displaysurface_from: malloc failed\n");
+        exit(1);
+    }
+
+    surface->width = width;
+    surface->height = height;
+    surface->linesize = linesize;
+    surface->pf = qemu_default_pixelformat(bpp);
+#ifdef WORDS_BIGENDIAN
+    surface->flags = QEMU_BIG_ENDIAN_FLAG;
+#endif
+    surface->data = data;
+
+    return surface;
+}
+
+void qemu_free_displaysurface(DisplaySurface *surface)
+{
+    if (surface == NULL)
+        return;
+    if (surface->flags & QEMU_ALLOCATED_FLAG)
+        qemu_free(surface->data);
+    qemu_free(surface);
+}
diff --git a/console.h b/console.h
index 9d4edee5c1..06c9326fd0 100644
--- a/console.h
+++ b/console.h
@@ -73,75 +73,168 @@ void kbd_put_keysym(int keysym);
 
 /* consoles */
 
-struct DisplayState {
-    uint8_t *data;
-    int linesize;
-    int depth;
-    int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */
+#define QEMU_BIG_ENDIAN_FLAG    0x01
+#define QEMU_ALLOCATED_FLAG     0x02
+
+struct PixelFormat {
+    uint8_t bits_per_pixel;
+    uint8_t bytes_per_pixel;
+    uint8_t depth; /* color depth in bits */
+    uint32_t rmask, gmask, bmask, amask;
+    uint8_t rshift, gshift, bshift, ashift;
+    uint8_t rmax, gmax, bmax, amax;
+};
+
+struct DisplaySurface {
+    uint8_t flags;
     int width;
     int height;
-    void *opaque;
-    struct QEMUTimer *gui_timer;
+    int linesize;        /* bytes per line */
+    uint8_t *data;
+
+    struct PixelFormat pf;
+};
+
+struct DisplayChangeListener {
+    int idle;
     uint64_t gui_timer_interval;
-    int idle; /* there is nothing to update (window invisible), set by vnc/sdl */
 
     void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h);
-    void (*dpy_resize)(struct DisplayState *s, int w, int h);
+    void (*dpy_resize)(struct DisplayState *s);
+    void (*dpy_setdata)(struct DisplayState *s);
     void (*dpy_refresh)(struct DisplayState *s);
     void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y,
                      int dst_x, int dst_y, int w, int h);
     void (*dpy_fill)(struct DisplayState *s, int x, int y,
                      int w, int h, uint32_t c);
     void (*dpy_text_cursor)(struct DisplayState *s, int x, int y);
+
+    struct DisplayChangeListener *next;
+};
+
+struct DisplayState {
+    struct DisplaySurface *surface;
+    void *opaque;
+    struct QEMUTimer *gui_timer;
+
+    struct DisplayChangeListener* listeners;
+
     void (*mouse_set)(int x, int y, int on);
     void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y,
                           uint8_t *image, uint8_t *mask);
 };
 
+DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int linesize);
+DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface,
+                                           int width, int height, int bpp, int linesize);
+DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
+                                                int linesize, uint8_t *data);
+void qemu_free_displaysurface(DisplaySurface *surface);
+
+static inline int is_buffer_shared(DisplaySurface *surface)
+{
+    return (!(surface->flags & QEMU_ALLOCATED_FLAG));
+}
+
+static inline void register_displaychangelistener(DisplayState *ds, DisplayChangeListener *dcl)
+{
+    dcl->next = ds->listeners;
+    ds->listeners = dcl;
+}
+
 static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
 {
-    s->dpy_update(s, x, y, w, h);
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        dcl->dpy_update(s, x, y, w, h);
+        dcl = dcl->next;
+    }
 }
 
-static inline void dpy_resize(DisplayState *s, int w, int h)
+static inline void dpy_resize(DisplayState *s)
 {
-    s->dpy_resize(s, w, h);
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        dcl->dpy_resize(s);
+        dcl = dcl->next;
+    }
 }
 
-static inline void dpy_cursor(DisplayState *s, int x, int y)
+static inline void dpy_setdata(DisplayState *s)
 {
-    if (s->dpy_text_cursor)
-        s->dpy_text_cursor(s, x, y);
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_setdata) dcl->dpy_setdata(s);
+        dcl = dcl->next;
+    }
+}
+
+static inline void dpy_refresh(DisplayState *s)
+{
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_refresh) dcl->dpy_refresh(s);
+        dcl = dcl->next;
+    }
+}
+
+static inline void dpy_copy(struct DisplayState *s, int src_x, int src_y,
+                             int dst_x, int dst_y, int w, int h) {
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_copy)
+            dcl->dpy_copy(s, src_x, src_y, dst_x, dst_y, w, h);
+        else /* TODO */
+            dcl->dpy_update(s, dst_x, dst_y, w, h);
+        dcl = dcl->next;
+    }
+}
+
+static inline void dpy_fill(struct DisplayState *s, int x, int y,
+                             int w, int h, uint32_t c) {
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_fill) dcl->dpy_fill(s, x, y, w, h, c);
+        dcl = dcl->next;
+    }
+}
+
+static inline void dpy_cursor(struct DisplayState *s, int x, int y) {
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_text_cursor) dcl->dpy_text_cursor(s, x, y);
+        dcl = dcl->next;
+    }
 }
 
 static inline int ds_get_linesize(DisplayState *ds)
 {
-    return ds->linesize;
+    return ds->surface->linesize;
 }
 
 static inline uint8_t* ds_get_data(DisplayState *ds)
 {
-    return ds->data;
+    return ds->surface->data;
 }
 
 static inline int ds_get_width(DisplayState *ds)
 {
-    return ds->width;
+    return ds->surface->width;
 }
 
 static inline int ds_get_height(DisplayState *ds)
 {
-    return ds->height;
+    return ds->surface->height;
 }
 
 static inline int ds_get_bits_per_pixel(DisplayState *ds)
 {
-    return ds->depth;
+    return ds->surface->pf.bits_per_pixel;
 }
 
 static inline int ds_get_bytes_per_pixel(DisplayState *ds)
 {
-    return (ds->depth / 8);
+    return ds->surface->pf.bytes_per_pixel;
 }
 
 typedef unsigned long console_ch_t;
diff --git a/curses.c b/curses.c
index 7c82377eff..b3aa01192c 100644
--- a/curses.c
+++ b/curses.c
@@ -97,13 +97,13 @@ static void curses_calc_pad(void)
     }
 }
 
-static void curses_resize(DisplayState *ds, int w, int h)
+static void curses_resize(DisplayState *ds)
 {
-    if (w == gwidth && h == gheight)
+    if (ds_get_width(ds) == gwidth && ds_get_height(ds) == gheight)
         return;
 
-    gwidth = w;
-    gheight = h;
+    gwidth = ds_get_width(ds);
+    gheight = ds_get_height(ds);
 
     curses_calc_pad();
 }
@@ -169,8 +169,8 @@ static void curses_refresh(DisplayState *ds)
         clear();
         refresh();
         curses_calc_pad();
-        ds->width = FONT_WIDTH * width;
-        ds->height = FONT_HEIGHT * height;
+        ds->surface->width = FONT_WIDTH * width;
+        ds->surface->height = FONT_HEIGHT * height;
         vga_hw_invalidate();
         invalidate = 0;
     }
@@ -197,8 +197,8 @@ static void curses_refresh(DisplayState *ds)
             refresh();
             curses_calc_pad();
             curses_update(ds, 0, 0, width, height);
-            ds->width = FONT_WIDTH * width;
-            ds->height = FONT_HEIGHT * height;
+            ds->surface->width = FONT_WIDTH * width;
+            ds->surface->height = FONT_HEIGHT * height;
             continue;
         }
 #endif
@@ -338,6 +338,7 @@ static void curses_keyboard_setup(void)
 
 void curses_display_init(DisplayState *ds, int full_screen)
 {
+    DisplayChangeListener *dcl;
 #ifndef _WIN32
     if (!isatty(1)) {
         fprintf(stderr, "We need a terminal output\n");
@@ -357,18 +358,19 @@ void curses_display_init(DisplayState *ds, int full_screen)
 #endif
 #endif
 
-    ds->data = (void *) screen;
-    ds->linesize = 0;
-    ds->depth = 0;
-    ds->width = 640;
-    ds->height = 400;
-    ds->dpy_update = curses_update;
-    ds->dpy_resize = curses_resize;
-    ds->dpy_refresh = curses_refresh;
-    ds->dpy_text_cursor = curses_cursor_position;
+    dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener));
+    if (!dcl)
+        exit(1);
+    dcl->dpy_update = curses_update;
+    dcl->dpy_resize = curses_resize;
+    dcl->dpy_refresh = curses_refresh;
+    dcl->dpy_text_cursor = curses_cursor_position;
+    register_displaychangelistener(ds, dcl);
+    qemu_free_displaysurface(ds->surface);
+    ds->surface = qemu_create_displaysurface_from(80, 25, 0, 0, (uint8_t*) screen);
 
     invalidate = 1;
 
     /* Standard VGA initial text mode dimensions */
-    curses_resize(ds, 80, 25);
+    curses_resize(ds);
 }
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index f9ad479573..55c2cc18a1 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -793,22 +793,9 @@ static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
     if (BLTUNSAFE(s))
         return 0;
 
-    if (s->ds->dpy_copy) {
-	cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr,
-		       s->cirrus_blt_srcaddr - s->start_addr,
-		       s->cirrus_blt_width, s->cirrus_blt_height);
-    } else {
-	(*s->cirrus_rop) (s, s->vram_ptr +
-                (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
-			  s->vram_ptr +
-                (s->cirrus_blt_srcaddr & s->cirrus_addr_mask),
-			  s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
-			  s->cirrus_blt_width, s->cirrus_blt_height);
-
-	cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
-				 s->cirrus_blt_dstpitch, s->cirrus_blt_width,
-				 s->cirrus_blt_height);
-    }
+    cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr,
+            s->cirrus_blt_srcaddr - s->start_addr,
+            s->cirrus_blt_width, s->cirrus_blt_height);
 
     return 1;
 }
diff --git a/hw/nseries.c b/hw/nseries.c
index d52a5e9efd..9559fd0245 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -1360,7 +1360,8 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
     /* FIXME: We shouldn't really be doing this here.  The LCD controller
        will set the size once configured, so this just sets an initial
        size until the guest activates the display.  */
-    dpy_resize(ds, 800, 480);
+    ds->surface = qemu_resize_displaysurface(ds->surface, 800, 480, 32, 4 * 800);
+    dpy_resize(ds);
 }
 
 static struct arm_boot_info n800_binfo = {
diff --git a/hw/palm.c b/hw/palm.c
index 9a0eb385f1..739d3f8128 100644
--- a/hw/palm.c
+++ b/hw/palm.c
@@ -277,7 +277,8 @@ static void palmte_init(ram_addr_t ram_size, int vga_ram_size,
     /* FIXME: We shouldn't really be doing this here.  The LCD controller
        will set the size once configured, so this just sets an initial
        size until the guest activates the display.  */
-    dpy_resize(ds, 320, 320);
+    ds->surface = qemu_resize_displaysurface(ds->surface, 320, 320, 32, 4 * 320);
+    dpy_resize(ds);
 }
 
 QEMUMachine palmte_machine = {
diff --git a/hw/vga.c b/hw/vga.c
index ce8ca45956..f2d98b098d 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1243,6 +1243,10 @@ static void vga_get_text_resolution(VGAState *s, int *pwidth, int *pheight,
     *pcheight = cheight;
 }
 
+typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
+
+static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS];
+
 /*
  * Text mode update
  * Missing:
@@ -1266,9 +1270,6 @@ static void vga_draw_text(VGAState *s, int full_update)
 
     vga_dirty_log_stop(s);
 
-    full_update |= update_palette16(s);
-    palette = s->last_palette;
-
     /* compute font data address (in plane 2) */
     v = s->sr[3];
     offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
@@ -1303,16 +1304,23 @@ static void vga_draw_text(VGAState *s, int full_update)
     }
 
     if (width != s->last_width || height != s->last_height ||
-        cw != s->last_cw || cheight != s->last_ch) {
+        cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
         s->last_scr_width = width * cw;
         s->last_scr_height = height * cheight;
         qemu_console_resize(s->console, s->last_scr_width, s->last_scr_height);
+        s->last_depth = 0;
         s->last_width = width;
         s->last_height = height;
         s->last_ch = cheight;
         s->last_cw = cw;
         full_update = 1;
     }
+    s->rgb_to_pixel =
+        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
+    full_update |= update_palette16(s);
+    palette = s->last_palette;
+    x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
+
     cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
     if (cursor_offset != s->cursor_offset ||
         s->cr[0xa] != s->cursor_start ||
@@ -1504,8 +1512,6 @@ static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
     vga_draw_line32_16bgr,
 };
 
-typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
-
 static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
     rgb_to_pixel8_dup,
     rgb_to_pixel15_dup,
@@ -1580,7 +1586,7 @@ static void vga_sync_dirty_bitmap(VGAState *s)
  */
 static void vga_draw_graphic(VGAState *s, int full_update)
 {
-    int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
+    int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask, depth;
     int width, height, shift_control, line_offset, page0, page1, bwidth, bits;
     int disp_width, multi_scan, multi_run;
     uint8_t *d;
@@ -1663,16 +1669,41 @@ static void vga_draw_graphic(VGAState *s, int full_update)
     }
     vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
 
-    if (disp_width != s->last_width ||
-        height != s->last_height) {
-        qemu_console_resize(s->console, disp_width, height);
+    depth = s->get_bpp(s);
+    if (s->line_offset != s->last_line_offset ||
+        disp_width != s->last_width ||
+        height != s->last_height ||
+        s->last_depth != depth) {
+        if (depth == 16 || depth == 32) {
+            if (is_graphic_console()) {
+                qemu_free_displaysurface(s->ds->surface);
+                s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
+                                                               s->line_offset,
+                                                               s->vram_ptr + (s->start_addr * 4));
+                dpy_resize(s->ds);
+            } else {
+                qemu_console_resize(s->console, disp_width, height);
+            }
+        } else {
+            qemu_console_resize(s->console, disp_width, height);
+        }
         s->last_scr_width = disp_width;
         s->last_scr_height = height;
         s->last_width = disp_width;
         s->last_height = height;
+        s->last_line_offset = s->line_offset;
+        s->last_depth = depth;
         full_update = 1;
+    } else if (is_graphic_console() && is_buffer_shared(s->ds->surface) &&
+               (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
+        s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
+        dpy_setdata(s->ds);
     }
-    if (s->cursor_invalidate)
+
+    s->rgb_to_pixel =
+        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
+
+    if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
         s->cursor_invalidate(s);
 
     line_offset = s->line_offset;
@@ -1718,9 +1749,11 @@ static void vga_draw_graphic(VGAState *s, int full_update)
                 page_min = page0;
             if (page1 > page_max)
                 page_max = page1;
-            vga_draw_line(s, d, s->vram_ptr + addr, width);
-            if (s->cursor_draw_line)
-                s->cursor_draw_line(s, d, y);
+            if (!(is_buffer_shared(s->ds->surface))) {
+                vga_draw_line(s, d, s->vram_ptr + addr, width);
+                if (s->cursor_draw_line)
+                    s->cursor_draw_line(s, d, y);
+            }
         } else {
             if (y_start >= 0) {
                 /* flush to display */
@@ -1767,6 +1800,8 @@ static void vga_draw_blank(VGAState *s, int full_update)
         return;
     vga_dirty_log_stop(s);
 
+    s->rgb_to_pixel =
+        rgb_to_pixel_dup_table[get_depth_index(s->ds)];
     if (ds_get_bits_per_pixel(s->ds) == 8)
         val = s->rgb_to_pixel(0, 0, 0);
     else
@@ -1793,9 +1828,6 @@ static void vga_update_display(void *opaque)
     if (ds_get_bits_per_pixel(s->ds) == 0) {
         /* nothing to do */
     } else {
-        s->rgb_to_pixel =
-            rgb_to_pixel_dup_table[get_depth_index(s->ds)];
-
         full_update = 0;
         if (!(s->ar_index & 0x20)) {
             graphic_mode = GMODE_BLANK;
@@ -1966,7 +1998,9 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
             cw != s->last_cw || cheight != s->last_ch) {
             s->last_scr_width = width * cw;
             s->last_scr_height = height * cheight;
-            qemu_console_resize(s->console, width, height);
+            s->ds->surface->width = width;
+            s->ds->surface->height = height;
+            dpy_resize(s->ds);
             s->last_width = width;
             s->last_height = height;
             s->last_ch = cheight;
@@ -2047,7 +2081,9 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
     s->last_width = 60;
     s->last_height = height = 3;
     dpy_cursor(s->ds, -1, -1);
-    qemu_console_resize(s->console, s->last_width, height);
+    s->ds->surface->width = s->last_width;
+    s->ds->surface->height = height;
+    dpy_resize(s->ds);
 
     for (dst = chardata, i = 0; i < s->last_width * height; i ++)
         console_write_ch(dst ++, ' ');
@@ -2505,12 +2541,8 @@ static void vga_save_dpy_update(DisplayState *s,
 {
 }
 
-static void vga_save_dpy_resize(DisplayState *s, int w, int h)
+static void vga_save_dpy_resize(DisplayState *s)
 {
-    s->linesize = w * 4;
-    s->data = qemu_mallocz(h * s->linesize);
-    vga_save_w = w;
-    vga_save_h = h;
 }
 
 static void vga_save_dpy_refresh(DisplayState *s)
@@ -2570,24 +2602,29 @@ static void vga_screen_dump_common(VGAState *s, const char *filename,
                                    int w, int h)
 {
     DisplayState *saved_ds, ds1, *ds = &ds1;
+    DisplayChangeListener dcl;
 
     /* XXX: this is a little hackish */
     vga_invalidate_display(s);
     saved_ds = s->ds;
 
     memset(ds, 0, sizeof(DisplayState));
-    ds->dpy_update = vga_save_dpy_update;
-    ds->dpy_resize = vga_save_dpy_resize;
-    ds->dpy_refresh = vga_save_dpy_refresh;
-    ds->depth = 32;
+    memset(&dcl, 0, sizeof(DisplayChangeListener));
+    dcl.dpy_update = vga_save_dpy_update;
+    dcl.dpy_resize = vga_save_dpy_resize;
+    dcl.dpy_refresh = vga_save_dpy_refresh;
+    register_displaychangelistener(ds, &dcl);
+    ds->surface = qemu_create_displaysurface(ds_get_width(saved_ds),
+            ds_get_height(saved_ds), 32, 4 * ds_get_width(saved_ds));
 
-    ds->linesize = w * sizeof(uint32_t);
-    ds->data = qemu_mallocz(h * ds->linesize);
     s->ds = ds;
     s->graphic_mode = -1;
     vga_update_display(s);
-    ppm_save(filename, ds->data, w, h, ds->linesize);
-    qemu_free(ds->data);
+
+    ppm_save(filename, ds_get_data(ds), vga_save_w, vga_save_h,
+            ds_get_linesize(ds));
+
+    qemu_free_displaysurface(ds->surface);
     s->ds = saved_ds;
 }
 
diff --git a/hw/vga_int.h b/hw/vga_int.h
index 39b7367dff..319678a9a9 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -154,9 +154,11 @@ typedef void (* vga_update_retrace_info_fn)(struct VGAState *s);
     uint32_t line_compare;                                              \
     uint32_t start_addr;                                                \
     uint32_t plane_updated;                                             \
+    uint32_t last_line_offset;                                          \
     uint8_t last_cw, last_ch;                                           \
     uint32_t last_width, last_height; /* in chars or pixels */          \
     uint32_t last_scr_width, last_scr_height; /* in pixels */           \
+    uint32_t last_depth; /* in bits */                                  \
     uint8_t cursor_start, cursor_end;                                   \
     uint32_t cursor_offset;                                             \
     unsigned int (*rgb_to_pixel)(unsigned int r,                        \
diff --git a/qemu-common.h b/qemu-common.h
index db6c1a612c..d83e61be35 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -166,6 +166,9 @@ typedef struct HCIInfo HCIInfo;
 typedef struct AudioState AudioState;
 typedef struct BlockDriverState BlockDriverState;
 typedef struct DisplayState DisplayState;
+typedef struct DisplayChangeListener DisplayChangeListener;
+typedef struct DisplaySurface DisplaySurface;
+typedef struct PixelFormat PixelFormat;
 typedef struct TextConsole TextConsole;
 typedef TextConsole QEMUConsole;
 typedef struct CharDriverState CharDriverState;
diff --git a/sdl.c b/sdl.c
index 67aba76bd7..73396e86ad 100644
--- a/sdl.c
+++ b/sdl.c
@@ -31,7 +31,9 @@
 #include <signal.h>
 #endif
 
-static SDL_Surface *screen;
+static DisplayChangeListener *dcl;
+static SDL_Surface *real_screen;
+static SDL_Surface *guest_screen = NULL;
 static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
 static int last_vm_running;
 static int gui_saved_grab;
@@ -52,11 +54,34 @@ static SDL_Cursor *guest_sprite = 0;
 
 static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
 {
+    SDL_Rect rec;
+    rec.x = x;
+    rec.y = y;
+    rec.w = w;
+    rec.h = h;
     //    printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
-    SDL_UpdateRect(screen, x, y, w, h);
+
+    SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
+    SDL_Flip(real_screen);
+}
+
+static void sdl_setdata(DisplayState *ds)
+{
+    SDL_Rect rec;
+    rec.x = 0;
+    rec.y = 0;
+    rec.w = real_screen->w;
+    rec.h = real_screen->h;
+
+    if (guest_screen != NULL) SDL_FreeSurface(guest_screen);
+
+    guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds),
+                                            ds_get_bits_per_pixel(ds), ds_get_linesize(ds),
+                                            ds->surface->pf.rmask, ds->surface->pf.gmask,
+                                            ds->surface->pf.bmask, ds->surface->pf.amask);
 }
 
-static void sdl_resize(DisplayState *ds, int w, int h)
+static void sdl_resize(DisplayState *ds)
 {
     int flags;
 
@@ -68,40 +93,23 @@ static void sdl_resize(DisplayState *ds, int w, int h)
     if (gui_noframe)
         flags |= SDL_NOFRAME;
 
-    width = w;
-    height = h;
-
  again:
-    screen = SDL_SetVideoMode(w, h, 0, flags);
-    if (!screen) {
+    real_screen = SDL_SetVideoMode(ds_get_width(ds), ds_get_height(ds), 0, flags);
+    if (!real_screen) {
         fprintf(stderr, "Could not open SDL display\n");
         exit(1);
     }
-    if (!screen->pixels && (flags & SDL_HWSURFACE) && (flags & SDL_FULLSCREEN)) {
+    if (!real_screen->pixels && (flags & SDL_HWSURFACE) && (flags & SDL_FULLSCREEN)) {
         flags &= ~SDL_HWSURFACE;
         goto again;
     }
 
-    if (!screen->pixels) {
+    if (!real_screen->pixels) {
         fprintf(stderr, "Could not open SDL display\n");
         exit(1);
     }
-    ds->data = screen->pixels;
-    ds->linesize = screen->pitch;
-    ds->depth = screen->format->BitsPerPixel;
-    /* SDL BitsPerPixel never indicates any values other than
-       multiples of 8, so we need to check for strange depths. */
-    if (ds->depth == 16) {
-        uint32_t mask;
-
-        mask = screen->format->Rmask;
-        mask |= screen->format->Gmask;
-        mask |= screen->format->Bmask;
-        if ((mask & 0x8000) == 0)
-            ds->depth = 15;
-    }
-    ds->width = w;
-    ds->height = h;
+
+    sdl_setdata(ds);
 }
 
 /* generic keyboard conversion */
@@ -337,7 +345,7 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state
 static void toggle_full_screen(DisplayState *ds)
 {
     gui_fullscreen = !gui_fullscreen;
-    sdl_resize(ds, screen->w, screen->h);
+    sdl_resize(ds);
     if (gui_fullscreen) {
         gui_saved_grab = gui_grab;
         sdl_grab_start();
@@ -366,7 +374,7 @@ static void sdl_refresh(DisplayState *ds)
     while (SDL_PollEvent(ev)) {
         switch (ev->type) {
         case SDL_VIDEOEXPOSE:
-            sdl_update(ds, 0, 0, screen->w, screen->h);
+            sdl_update(ds, 0, 0, real_screen->w, real_screen->h);
             break;
         case SDL_KEYDOWN:
         case SDL_KEYUP:
@@ -521,12 +529,12 @@ static void sdl_refresh(DisplayState *ds)
             if (ev->active.state & SDL_APPACTIVE) {
                 if (ev->active.gain) {
                     /* Back to default interval */
-                    ds->gui_timer_interval = 0;
-                    ds->idle = 0;
+                    dcl->gui_timer_interval = 0;
+                    dcl->idle = 0;
                 } else {
                     /* Sleeping interval */
-                    ds->gui_timer_interval = 500;
-                    ds->idle = 1;
+                    dcl->gui_timer_interval = 500;
+                    dcl->idle = 1;
                 }
             }
             break;
@@ -539,7 +547,7 @@ static void sdl_refresh(DisplayState *ds)
 static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c)
 {
     SDL_Rect dst = { x, y, w, h };
-    SDL_FillRect(screen, &dst, c);
+    SDL_FillRect(real_screen, &dst, c);
 }
 
 static void sdl_mouse_warp(int x, int y, int on)
@@ -635,14 +643,18 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
         exit(1);
     }
 
-    ds->dpy_update = sdl_update;
-    ds->dpy_resize = sdl_resize;
-    ds->dpy_refresh = sdl_refresh;
-    ds->dpy_fill = sdl_fill;
+    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+    if (!dcl)
+        exit(1);
+    dcl->dpy_update = sdl_update;
+    dcl->dpy_resize = sdl_resize;
+    dcl->dpy_refresh = sdl_refresh;
+    dcl->dpy_setdata = sdl_setdata;
+    dcl->dpy_fill = sdl_fill;
     ds->mouse_set = sdl_mouse_warp;
     ds->cursor_define = sdl_mouse_define;
+    register_displaychangelistener(ds, dcl);
 
-    sdl_resize(ds, 640, 400);
     sdl_update_caption();
     SDL_EnableKeyRepeat(250, 50);
     gui_grab = 0;
diff --git a/vl.c b/vl.c
index 2452d0f7d9..d099658830 100644
--- a/vl.c
+++ b/vl.c
@@ -193,6 +193,7 @@ enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
 DisplayState display_state;
 int nographic;
 static int curses;
+static int sdl;
 const char* keyboard_layout = NULL;
 int64_t ticks_per_sec;
 ram_addr_t ram_size;
@@ -2764,20 +2765,21 @@ static void dumb_update(DisplayState *ds, int x, int y, int w, int h)
 {
 }
 
-static void dumb_resize(DisplayState *ds, int w, int h)
+static void dumb_resize(DisplayState *ds)
 {
 }
 
 static void dumb_display_init(DisplayState *ds)
 {
-    ds->data = NULL;
-    ds->linesize = 0;
-    ds->depth = 0;
-    ds->dpy_update = dumb_update;
-    ds->dpy_resize = dumb_resize;
-    ds->dpy_refresh = NULL;
-    ds->gui_timer_interval = 0;
-    ds->idle = 1;
+    DisplayChangeListener *dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+    if (!dcl)
+        exit(1);
+    dcl->dpy_update = dumb_update;
+    dcl->dpy_resize = dumb_resize;
+    dcl->dpy_refresh = NULL;
+    dcl->idle = 1;
+    dcl->gui_timer_interval = 500;
+    register_displaychangelistener(ds, dcl);
 }
 
 /***********************************************************/
@@ -3360,13 +3362,19 @@ static QEMUMachine *find_machine(const char *name)
 
 static void gui_update(void *opaque)
 {
+    uint64_t interval = GUI_REFRESH_INTERVAL;
     DisplayState *ds = opaque;
-    ds->dpy_refresh(ds);
-    qemu_mod_timer(ds->gui_timer,
-        (ds->gui_timer_interval ?
-	    ds->gui_timer_interval :
-	    GUI_REFRESH_INTERVAL)
-	+ qemu_get_clock(rt_clock));
+    DisplayChangeListener *dcl = ds->listeners;
+
+    dpy_refresh(ds);
+
+    while (dcl != NULL) {
+        if (dcl->gui_timer_interval &&
+            dcl->gui_timer_interval < interval)
+            interval = dcl->gui_timer_interval;
+        dcl = dcl->next;
+    }
+    qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock(rt_clock));
 }
 
 struct vm_change_state_entry {
@@ -3848,6 +3856,7 @@ static void help(int exitcode)
            "-no-frame       open SDL window without a frame and window decorations\n"
            "-alt-grab       use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt)\n"
            "-no-quit        disable SDL window close capability\n"
+           "-sdl            enable SDL\n"
 #endif
 #ifdef TARGET_I386
            "-no-fd-bootchk  disable boot signature checking for floppy disks\n"
@@ -4064,6 +4073,7 @@ enum {
     QEMU_OPTION_no_frame,
     QEMU_OPTION_alt_grab,
     QEMU_OPTION_no_quit,
+    QEMU_OPTION_sdl,
     QEMU_OPTION_pidfile,
     QEMU_OPTION_no_kqemu,
     QEMU_OPTION_kernel_kqemu,
@@ -4176,6 +4186,7 @@ static const QEMUOption qemu_options[] = {
     { "no-frame", 0, QEMU_OPTION_no_frame },
     { "alt-grab", 0, QEMU_OPTION_alt_grab },
     { "no-quit", 0, QEMU_OPTION_no_quit },
+    { "sdl", 0, QEMU_OPTION_sdl },
 #endif
     { "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
     { "win2k-hack", 0, QEMU_OPTION_win2k_hack },
@@ -4495,6 +4506,7 @@ int main(int argc, char **argv, char **envp)
     const char *kernel_filename, *kernel_cmdline;
     const char *boot_devices = "";
     DisplayState *ds = &display_state;
+    DisplayChangeListener *dcl;
     int cyls, heads, secs, translation;
     const char *net_clients[MAX_NET_CLIENTS];
     int nb_net_clients;
@@ -5007,6 +5019,9 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_no_quit:
                 no_quit = 1;
                 break;
+            case QEMU_OPTION_sdl:
+                sdl = 1;
+                break;
 #endif
             case QEMU_OPTION_pidfile:
                 pid_file = optarg;
@@ -5404,6 +5419,7 @@ int main(int argc, char **argv, char **envp)
 
     /* terminal init */
     memset(&display_state, 0, sizeof(display_state));
+    ds->surface = qemu_create_displaysurface(640, 480, 32, 640 * 4);
     if (nographic) {
         if (curses) {
             fprintf(stderr, "fatal: -nographic can't be used with -curses\n");
@@ -5411,26 +5427,30 @@ int main(int argc, char **argv, char **envp)
         }
         /* nearly nothing to do */
         dumb_display_init(ds);
-    } else if (vnc_display != NULL) {
-        vnc_display_init(ds);
-        if (vnc_display_open(ds, vnc_display) < 0)
-            exit(1);
-    } else
+    } else { 
 #if defined(CONFIG_CURSES)
-    if (curses) {
-        curses_display_init(ds, full_screen);
-    } else
+            if (curses) {
+                /* At the moment curses cannot be used with other displays */
+                curses_display_init(ds, full_screen);
+            } else
 #endif
-    {
+            {
+                if (vnc_display != NULL) {
+                    vnc_display_init(ds);
+                    if (vnc_display_open(ds, vnc_display) < 0)
+                        exit(1);
+                }
+                if (sdl || !vnc_display)
 #if defined(CONFIG_SDL)
-        sdl_display_init(ds, full_screen, no_frame);
+                    sdl_display_init(ds, full_screen, no_frame);
 #elif defined(CONFIG_COCOA)
-        cocoa_display_init(ds, full_screen);
+                    cocoa_display_init(ds, full_screen);
 #else
-        dumb_display_init(ds);
+                    dumb_display_init(ds);
 #endif
+            }
     }
-
+    dpy_resize(ds);
 #ifndef _WIN32
     /* must be after terminal init, SDL library changes signal handlers */
     termsig_setup();
@@ -5541,11 +5561,14 @@ int main(int argc, char **argv, char **envp)
         }
     }
 
-    if (display_state.dpy_refresh) {
-        display_state.gui_timer = qemu_new_timer(rt_clock, gui_update, &display_state);
-        qemu_mod_timer(display_state.gui_timer, qemu_get_clock(rt_clock));
+    dcl = ds->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_refresh != NULL) {
+            display_state.gui_timer = qemu_new_timer(rt_clock, gui_update, &display_state);
+            qemu_mod_timer(display_state.gui_timer, qemu_get_clock(rt_clock));
+        }
+        dcl = dcl->next;
     }
-
 #ifdef CONFIG_GDBSTUB
     if (use_gdbstub) {
         /* XXX: use standard host:port notation and modify options
diff --git a/vnc.c b/vnc.c
index e1ff4edd75..357ff648f9 100644
--- a/vnc.c
+++ b/vnc.c
@@ -180,6 +180,7 @@ struct VncState
 };
 
 static VncState *vnc_state; /* needed for info vnc */
+static DisplayChangeListener *dcl;
 
 void do_info_vnc(void)
 {
@@ -213,7 +214,7 @@ static void vnc_flush(VncState *vs);
 static void vnc_update_client(void *opaque);
 static void vnc_client_read(void *opaque);
 
-static void vnc_colordepth(DisplayState *ds, int depth);
+static void vnc_colordepth(DisplayState *ds);
 
 static inline void vnc_set_bit(uint32_t *d, int k)
 {
@@ -291,35 +292,30 @@ static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
     vnc_write_s32(vs, encoding);
 }
 
-static void vnc_dpy_resize(DisplayState *ds, int w, int h)
+static void vnc_dpy_resize(DisplayState *ds)
 {
     int size_changed;
     VncState *vs = ds->opaque;
 
-    ds->data = qemu_realloc(ds->data, w * h * vs->depth);
-    vs->old_data = qemu_realloc(vs->old_data, w * h * vs->depth);
+    vs->old_data = qemu_realloc(vs->old_data, ds_get_linesize(ds) * ds_get_height(ds));
 
-    if (ds->data == NULL || vs->old_data == NULL) {
+    if (vs->old_data == NULL) {
 	fprintf(stderr, "vnc: memory allocation failed\n");
 	exit(1);
     }
 
-    if (ds->depth != vs->depth * 8) {
-        ds->depth = vs->depth * 8;
+    if (ds_get_bytes_per_pixel(ds) != vs->depth)
         console_color_init(ds);
-    }
-    size_changed = ds->width != w || ds->height != h;
-    ds->width = w;
-    ds->height = h;
-    ds->linesize = w * vs->depth;
+    vnc_colordepth(ds);
+    size_changed = ds_get_width(ds) != vs->width || ds_get_height(ds) != vs->height;
     if (size_changed) {
-        vs->width = ds->width;
-        vs->height = ds->height;
+        vs->width = ds_get_width(ds);
+        vs->height = ds_get_height(ds);
         if (vs->csock != -1 && vs->has_resize) {
             vnc_write_u8(vs, 0);  /* msg id */
             vnc_write_u8(vs, 0);
             vnc_write_u16(vs, 1); /* number of rects */
-            vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, -223);
+            vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds), -223);
             vnc_flush(vs);
         }
     }
@@ -494,36 +490,10 @@ static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
 
 static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
 {
-    int src, dst;
-    uint8_t *src_row;
-    uint8_t *dst_row;
-    char *old_row;
-    int y = 0;
-    int pitch = ds_get_linesize(ds);
     VncState *vs = ds->opaque;
 
     vnc_update_client(vs);
 
-    if (dst_y > src_y) {
-	y = h - 1;
-	pitch = -pitch;
-    }
-
-    src = (ds_get_linesize(ds) * (src_y + y) + vs->depth * src_x);
-    dst = (ds_get_linesize(ds) * (dst_y + y) + vs->depth * dst_x);
-
-    src_row = ds_get_data(ds) + src;
-    dst_row = ds_get_data(ds) + dst;
-    old_row = vs->old_data + dst;
-
-    for (y = 0; y < h; y++) {
-	memmove(old_row, src_row, w * vs->depth);
-	memmove(dst_row, src_row, w * vs->depth);
-	src_row += pitch;
-	dst_row += pitch;
-	old_row += pitch;
-    }
-
     vnc_write_u8(vs, 0);  /* msg id */
     vnc_write_u8(vs, 0);
     vnc_write_u16(vs, 1); /* number of rects */
@@ -770,7 +740,7 @@ static int vnc_client_io_error(VncState *vs, int ret, int last_errno)
 	qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
 	closesocket(vs->csock);
 	vs->csock = -1;
-	vs->ds->idle = 1;
+	dcl->idle = 1;
 	buffer_reset(&vs->input);
 	buffer_reset(&vs->output);
 	vs->need_update = 0;
@@ -1226,7 +1196,7 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
     vs->has_pointer_type_change = 0;
     vs->has_WMVi = 0;
     vs->absolute = -1;
-    vs->ds->dpy_copy = NULL;
+    dcl->dpy_copy = NULL;
 
     for (i = n_encodings - 1; i >= 0; i--) {
 	switch (encodings[i]) {
@@ -1234,7 +1204,7 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
 	    vs->has_hextile = 0;
 	    break;
 	case 1: /* CopyRect */
-	    vs->ds->dpy_copy = vnc_copy;
+	    dcl->dpy_copy = vnc_copy;
 	    break;
 	case 5: /* Hextile */
 	    vs->has_hextile = 1;
@@ -1387,33 +1357,25 @@ static void pixel_format_message (VncState *vs) {
     vnc_write(vs, pad, 3);           /* padding */
 }
 
-static void vnc_colordepth(DisplayState *ds, int depth)
+static void vnc_dpy_setdata(DisplayState *ds)
+{
+    /* We don't have to do anything */
+}
+
+static void vnc_colordepth(DisplayState *ds)
 {
     int host_big_endian_flag;
     struct VncState *vs = ds->opaque;
 
-    switch (depth) {
-        case 24:
-            if (ds->depth == 32) return;
-            depth = 32;
-            break;
-        case 15:
-        case 8:
-        case 0:
-            return;
-        default:
-            break;
-    }
-
 #ifdef WORDS_BIGENDIAN
     host_big_endian_flag = 1;
 #else
     host_big_endian_flag = 0;
 #endif   
     
-    switch (depth) {
+    switch (ds_get_bits_per_pixel(ds)) {
         case 8:
-            vs->depth = depth / 8;
+            vs->depth = 1;
             vs->server_red_max = 7;
             vs->server_green_max = 7;
             vs->server_blue_max = 3;
@@ -1422,7 +1384,7 @@ static void vnc_colordepth(DisplayState *ds, int depth)
             vs->server_blue_shift = 0;
             break;
         case 16:
-            vs->depth = depth / 8;
+            vs->depth = 2;
             vs->server_red_max = 31;
             vs->server_green_max = 63;
             vs->server_blue_max = 31;
@@ -1448,7 +1410,7 @@ static void vnc_colordepth(DisplayState *ds, int depth)
         vnc_write_u8(vs, 0);  /* msg id */
         vnc_write_u8(vs, 0);
         vnc_write_u16(vs, 1); /* number of rects */
-        vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, 0x574D5669);
+        vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds), 0x574D5669);
         pixel_format_message(vs);
         vnc_flush(vs);
     } else {
@@ -2237,7 +2199,7 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len)
 static void vnc_connect(VncState *vs)
 {
     VNC_DEBUG("New client on socket %d\n", vs->csock);
-    vs->ds->idle = 0;
+    dcl->idle = 0;
     socket_set_nonblock(vs->csock);
     qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
     vnc_write(vs, "RFB 003.008\n", 12);
@@ -2247,7 +2209,7 @@ static void vnc_connect(VncState *vs)
     memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
     vs->has_resize = 0;
     vs->has_hextile = 0;
-    vs->ds->dpy_copy = NULL;
+    dcl->dpy_copy = NULL;
     vnc_update_client(vs);
     reset_keys(vs);
 }
@@ -2272,11 +2234,12 @@ void vnc_display_init(DisplayState *ds)
     VncState *vs;
 
     vs = qemu_mallocz(sizeof(VncState));
-    if (!vs)
+    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+    if (!vs || !dcl)
 	exit(1);
 
     ds->opaque = vs;
-    ds->idle = 1;
+    dcl->idle = 1;
     vnc_state = vs;
     vs->display = NULL;
     vs->password = NULL;
@@ -2298,13 +2261,11 @@ void vnc_display_init(DisplayState *ds)
 
     vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
 
-    vs->ds->data = NULL;
-    vs->ds->dpy_update = vnc_dpy_update;
-    vs->ds->dpy_resize = vnc_dpy_resize;
-    vs->ds->dpy_refresh = NULL;
-
-    vnc_colordepth(vs->ds, 32);
-    vnc_dpy_resize(vs->ds, 640, 400);
+    dcl->dpy_update = vnc_dpy_update;
+    dcl->dpy_resize = vnc_dpy_resize;
+    dcl->dpy_setdata = vnc_dpy_setdata;
+    dcl->dpy_refresh = NULL;
+    register_displaychangelistener(ds, dcl);
 
     vs->as.freq = 44100;
     vs->as.nchannels = 2;