]> git.proxmox.com Git - qemu.git/blobdiff - ui/console.c
rng-egd: remove redundant free
[qemu.git] / ui / console.c
index c2ca9e7b9313994e803bb5dc13adaa0c683b1316..199ba69101d532c4a6658b5c3007d9c4caff1a30 100644 (file)
  */
 #include "qemu-common.h"
 #include "ui/console.h"
+#include "hw/qdev-core.h"
 #include "qemu/timer.h"
 #include "qmp-commands.h"
-#include "char/char.h"
+#include "sysemu/char.h"
 
 //#define DEBUG_CONSOLE
 #define DEFAULT_BACKSCROLL 512
 #define MAX_CONSOLES 12
 #define CONSOLE_CURSOR_PERIOD 500
 
-#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
-#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
-
 typedef struct TextAttributes {
     uint8_t fgcol:4;
     uint8_t bgcol:4;
@@ -116,17 +114,18 @@ typedef enum {
 } console_type_t;
 
 struct QemuConsole {
+    Object parent;
+
     int index;
     console_type_t console_type;
     DisplayState *ds;
+    DisplaySurface *surface;
+    int dcls;
 
     /* Graphic console state.  */
-    vga_hw_update_ptr hw_update;
-    vga_hw_invalidate_ptr hw_invalidate;
-    vga_hw_screen_dump_ptr hw_screen_dump;
-    vga_hw_text_update_ptr hw_text_update;
+    Object *device;
+    const GraphicHwOps *hw_ops;
     void *hw;
-    int g_width, g_height;
 
     /* Text console state */
     int width;
@@ -161,204 +160,215 @@ struct QemuConsole {
     QEMUTimer *kbd_timer;
 };
 
+struct DisplayState {
+    struct QEMUTimer *gui_timer;
+    uint64_t last_update;
+    uint64_t update_interval;
+    bool refreshing;
+    bool have_gfx;
+    bool have_text;
+
+    QLIST_HEAD(, DisplayChangeListener) listeners;
+};
+
 static DisplayState *display_state;
 static QemuConsole *active_console;
 static QemuConsole *consoles[MAX_CONSOLES];
 static int nb_consoles = 0;
 
-void vga_hw_update(void)
-{
-    if (active_console && active_console->hw_update)
-        active_console->hw_update(active_console->hw);
-}
+static void text_console_do_init(CharDriverState *chr, DisplayState *ds);
+static void dpy_refresh(DisplayState *s);
+static DisplayState *get_alloc_displaystate(void);
 
-void vga_hw_invalidate(void)
+static void gui_update(void *opaque)
 {
-    if (active_console && active_console->hw_invalidate)
-        active_console->hw_invalidate(active_console->hw);
+    uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
+    uint64_t dcl_interval;
+    DisplayState *ds = opaque;
+    DisplayChangeListener *dcl;
+    int i;
+
+    ds->refreshing = true;
+    dpy_refresh(ds);
+    ds->refreshing = false;
+
+    QLIST_FOREACH(dcl, &ds->listeners, next) {
+        dcl_interval = dcl->update_interval ?
+            dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
+        if (interval > dcl_interval) {
+            interval = dcl_interval;
+        }
+    }
+    if (ds->update_interval != interval) {
+        ds->update_interval = interval;
+        for (i = 0; i < nb_consoles; i++) {
+            if (consoles[i]->hw_ops->update_interval) {
+                consoles[i]->hw_ops->update_interval(consoles[i]->hw, interval);
+            }
+        }
+        trace_console_refresh(interval);
+    }
+    ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+    timer_mod(ds->gui_timer, ds->last_update + interval);
 }
 
-void qmp_screendump(const char *filename, Error **errp)
+static void gui_setup_refresh(DisplayState *ds)
 {
-    QemuConsole *previous_active_console;
-    bool cswitch;
+    DisplayChangeListener *dcl;
+    bool need_timer = false;
+    bool have_gfx = false;
+    bool have_text = false;
 
-    previous_active_console = active_console;
-    cswitch = previous_active_console && previous_active_console->index != 0;
+    QLIST_FOREACH(dcl, &ds->listeners, next) {
+        if (dcl->ops->dpy_refresh != NULL) {
+            need_timer = true;
+        }
+        if (dcl->ops->dpy_gfx_update != NULL) {
+            have_gfx = true;
+        }
+        if (dcl->ops->dpy_text_update != NULL) {
+            have_text = true;
+        }
+    }
 
-    /* There is currently no way of specifying which screen we want to dump,
-       so always dump the first one.  */
-    if (cswitch) {
-        console_select(0);
+    if (need_timer && ds->gui_timer == NULL) {
+        ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
+        timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
     }
-    if (consoles[0] && consoles[0]->hw_screen_dump) {
-        consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, errp);
-    } else {
-        error_setg(errp, "device doesn't support screendump");
+    if (!need_timer && ds->gui_timer != NULL) {
+        timer_del(ds->gui_timer);
+        timer_free(ds->gui_timer);
+        ds->gui_timer = NULL;
     }
 
-    if (cswitch) {
-        console_select(previous_active_console->index);
-    }
+    ds->have_gfx = have_gfx;
+    ds->have_text = have_text;
 }
 
-void vga_hw_text_update(console_ch_t *chardata)
+void graphic_hw_update(QemuConsole *con)
 {
-    if (active_console && active_console->hw_text_update)
-        active_console->hw_text_update(active_console->hw, chardata);
+    if (!con) {
+        con = active_console;
+    }
+    if (con && con->hw_ops->gfx_update) {
+        con->hw_ops->gfx_update(con->hw);
+    }
 }
 
-/* convert a RGBA color to a color index usable in graphic primitives */
-static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
+void graphic_hw_invalidate(QemuConsole *con)
 {
-    unsigned int r, g, b, color;
-
-    switch(ds_get_bits_per_pixel(ds)) {
-#if 0
-    case 8:
-        r = (rgba >> 16) & 0xff;
-        g = (rgba >> 8) & 0xff;
-        b = (rgba) & 0xff;
-        color = (rgb_to_index[r] * 6 * 6) +
-            (rgb_to_index[g] * 6) +
-            (rgb_to_index[b]);
-        break;
-#endif
-    case 15:
-        r = (rgba >> 16) & 0xff;
-        g = (rgba >> 8) & 0xff;
-        b = (rgba) & 0xff;
-        color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
-        break;
-    case 16:
-        r = (rgba >> 16) & 0xff;
-        g = (rgba >> 8) & 0xff;
-        b = (rgba) & 0xff;
-        color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
-        break;
-    case 32:
-    default:
-        color = rgba;
-        break;
+    if (!con) {
+        con = active_console;
+    }
+    if (con && con->hw_ops->invalidate) {
+        con->hw_ops->invalidate(con->hw);
     }
-    return color;
 }
 
-static void vga_fill_rect (DisplayState *ds,
-                           int posx, int posy, int width, int height, uint32_t color)
+static void ppm_save(const char *filename, struct DisplaySurface *ds,
+                     Error **errp)
 {
-    uint8_t *d, *d1;
-    int x, y, bpp;
+    int width = pixman_image_get_width(ds->image);
+    int height = pixman_image_get_height(ds->image);
+    int fd;
+    FILE *f;
+    int y;
+    int ret;
+    pixman_image_t *linebuf;
 
-    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
-    d1 = ds_get_data(ds) +
-        ds_get_linesize(ds) * posy + bpp * posx;
+    trace_ppm_save(filename, ds);
+    fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+    if (fd == -1) {
+        error_setg(errp, "failed to open file '%s': %s", filename,
+                   strerror(errno));
+        return;
+    }
+    f = fdopen(fd, "wb");
+    ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
+    if (ret < 0) {
+        linebuf = NULL;
+        goto write_err;
+    }
+    linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
     for (y = 0; y < height; y++) {
-        d = d1;
-        switch(bpp) {
-        case 1:
-            for (x = 0; x < width; x++) {
-                *((uint8_t *)d) = color;
-                d++;
-            }
-            break;
-        case 2:
-            for (x = 0; x < width; x++) {
-                *((uint16_t *)d) = color;
-                d += 2;
-            }
-            break;
-        case 4:
-            for (x = 0; x < width; x++) {
-                *((uint32_t *)d) = color;
-                d += 4;
-            }
-            break;
+        qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y);
+        clearerr(f);
+        ret = fwrite(pixman_image_get_data(linebuf), 1,
+                     pixman_image_get_stride(linebuf), f);
+        (void)ret;
+        if (ferror(f)) {
+            goto write_err;
         }
-        d1 += ds_get_linesize(ds);
     }
+
+out:
+    qemu_pixman_image_unref(linebuf);
+    fclose(f);
+    return;
+
+write_err:
+    error_setg(errp, "failed to write to file '%s': %s", filename,
+               strerror(errno));
+    unlink(filename);
+    goto out;
 }
 
-/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
-static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
-{
-    const uint8_t *s;
-    uint8_t *d;
-    int wb, y, bpp;
-
-    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
-    wb = w * bpp;
-    if (yd <= ys) {
-        s = ds_get_data(ds) +
-            ds_get_linesize(ds) * ys + bpp * xs;
-        d = ds_get_data(ds) +
-            ds_get_linesize(ds) * yd + bpp * xd;
-        for (y = 0; y < h; y++) {
-            memmove(d, s, wb);
-            d += ds_get_linesize(ds);
-            s += ds_get_linesize(ds);
-        }
-    } else {
-        s = ds_get_data(ds) +
-            ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
-        d = ds_get_data(ds) +
-            ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
-       for (y = 0; y < h; y++) {
-            memmove(d, s, wb);
-            d -= ds_get_linesize(ds);
-            s -= ds_get_linesize(ds);
-        }
+void qmp_screendump(const char *filename, Error **errp)
+{
+    QemuConsole *con = qemu_console_lookup_by_index(0);
+    DisplaySurface *surface;
+
+    if (con == NULL) {
+        error_setg(errp, "There is no QemuConsole I can screendump from.");
+        return;
     }
+
+    graphic_hw_update(con);
+    surface = qemu_console_surface(con);
+    ppm_save(filename, surface, errp);
 }
 
-/***********************************************************/
-/* basic char display */
+void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
+{
+    if (!con) {
+        con = active_console;
+    }
+    if (con && con->hw_ops->text_update) {
+        con->hw_ops->text_update(con->hw, chardata);
+    }
+}
 
-#define FONT_HEIGHT 16
-#define FONT_WIDTH 8
+static void vga_fill_rect(QemuConsole *con,
+                          int posx, int posy, int width, int height,
+                          pixman_color_t color)
+{
+    DisplaySurface *surface = qemu_console_surface(con);
+    pixman_rectangle16_t rect = {
+        .x = posx, .y = posy, .width = width, .height = height
+    };
 
-#include "vgafont.h"
+    pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
+                                 &color, 1, &rect);
+}
 
-#define cbswap_32(__x) \
-((uint32_t)( \
-               (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
-               (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
-               (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
-               (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
+/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
+static void vga_bitblt(QemuConsole *con,
+                       int xs, int ys, int xd, int yd, int w, int h)
+{
+    DisplaySurface *surface = qemu_console_surface(con);
 
-#ifdef HOST_WORDS_BIGENDIAN
-#define PAT(x) x
-#else
-#define PAT(x) cbswap_32(x)
-#endif
+    pixman_image_composite(PIXMAN_OP_SRC,
+                           surface->image, NULL, surface->image,
+                           xs, ys, 0, 0, xd, yd, w, h);
+}
 
-static const uint32_t dmask16[16] = {
-    PAT(0x00000000),
-    PAT(0x000000ff),
-    PAT(0x0000ff00),
-    PAT(0x0000ffff),
-    PAT(0x00ff0000),
-    PAT(0x00ff00ff),
-    PAT(0x00ffff00),
-    PAT(0x00ffffff),
-    PAT(0xff000000),
-    PAT(0xff0000ff),
-    PAT(0xff00ff00),
-    PAT(0xff00ffff),
-    PAT(0xffff0000),
-    PAT(0xffff00ff),
-    PAT(0xffffff00),
-    PAT(0xffffffff),
-};
+/***********************************************************/
+/* basic char display */
 
-static const uint32_t dmask4[4] = {
-    PAT(0x00000000),
-    PAT(0x0000ffff),
-    PAT(0xffff0000),
-    PAT(0xffffffff),
-};
+#define FONT_HEIGHT 16
+#define FONT_WIDTH 8
 
-static uint32_t color_table[2][8];
+#include "vgafont.h"
 
 #ifndef CONFIG_CURSES
 enum color_names {
@@ -373,7 +383,10 @@ enum color_names {
 };
 #endif
 
-static const uint32_t color_table_rgb[2][8] = {
+#define QEMU_RGB(r, g, b)                                               \
+    { .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff }
+
+static const pixman_color_t color_table_rgb[2][8] = {
     {   /* dark */
         QEMU_RGB(0x00, 0x00, 0x00),  /* black */
         QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
@@ -396,130 +409,26 @@ static const uint32_t color_table_rgb[2][8] = {
     }
 };
 
-static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
+static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
+                          TextAttributes *t_attrib)
 {
-    switch(ds_get_bits_per_pixel(ds)) {
-    case 8:
-        col |= col << 8;
-        col |= col << 16;
-        break;
-    case 15:
-    case 16:
-        col |= col << 16;
-        break;
-    default:
-        break;
-    }
+    static pixman_image_t *glyphs[256];
+    DisplaySurface *surface = qemu_console_surface(s);
+    pixman_color_t fgcol, bgcol;
 
-    return col;
-}
-#ifdef DEBUG_CONSOLE
-static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
-{
-    if (t_attrib->bold) {
-        printf("b");
-    } else {
-        printf(" ");
-    }
-    if (t_attrib->uline) {
-        printf("u");
-    } else {
-        printf(" ");
-    }
-    if (t_attrib->blink) {
-        printf("l");
-    } else {
-        printf(" ");
-    }
     if (t_attrib->invers) {
-        printf("i");
+        bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
+        fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
     } else {
-        printf(" ");
+        fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
+        bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
     }
-    if (t_attrib->unvisible) {
-        printf("n");
-    } else {
-        printf(" ");
-    }
-
-    printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
-}
-#endif
-
-static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
-                          TextAttributes *t_attrib)
-{
-    uint8_t *d;
-    const uint8_t *font_ptr;
-    unsigned int font_data, linesize, xorcol, bpp;
-    int i;
-    unsigned int fgcol, bgcol;
-
-#ifdef DEBUG_CONSOLE
-    printf("x: %2i y: %2i", x, y);
-    console_print_text_attributes(t_attrib, ch);
-#endif
 
-    if (t_attrib->invers) {
-        bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
-        fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
-    } else {
-        fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
-        bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
-    }
-
-    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
-    d = ds_get_data(ds) +
-        ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
-    linesize = ds_get_linesize(ds);
-    font_ptr = vgafont16 + FONT_HEIGHT * ch;
-    xorcol = bgcol ^ fgcol;
-    switch(ds_get_bits_per_pixel(ds)) {
-    case 8:
-        for(i = 0; i < FONT_HEIGHT; i++) {
-            font_data = *font_ptr++;
-            if (t_attrib->uline
-                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
-                font_data = 0xFF;
-            }
-            ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
-            ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
-            d += linesize;
-        }
-        break;
-    case 16:
-    case 15:
-        for(i = 0; i < FONT_HEIGHT; i++) {
-            font_data = *font_ptr++;
-            if (t_attrib->uline
-                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
-                font_data = 0xFF;
-            }
-            ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
-            ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
-            ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
-            ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
-            d += linesize;
-        }
-        break;
-    case 32:
-        for(i = 0; i < FONT_HEIGHT; i++) {
-            font_data = *font_ptr++;
-            if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
-                font_data = 0xFF;
-            }
-            ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
-            ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
-            ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
-            ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
-            ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
-            ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
-            ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
-            ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
-            d += linesize;
-        }
-        break;
+    if (!glyphs[ch]) {
+        glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
     }
+    qemu_pixman_glyph_render(glyphs[ch], surface->image,
+                             &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
 }
 
 static void text_console_resize(QemuConsole *s)
@@ -528,8 +437,8 @@ static void text_console_resize(QemuConsole *s)
     int w1, x, y, last_width;
 
     last_width = s->width;
-    s->width = s->g_width / FONT_WIDTH;
-    s->height = s->g_height / FONT_HEIGHT;
+    s->width = surface_width(s->surface) / FONT_WIDTH;
+    s->height = surface_height(s->surface) / FONT_HEIGHT;
 
     w1 = last_width;
     if (s->width < w1)
@@ -579,19 +488,22 @@ static void update_xy(QemuConsole *s, int x, int y)
     TextCell *c;
     int y1, y2;
 
-    if (s == active_console) {
-        if (!ds_get_bits_per_pixel(s->ds)) {
-            text_update_xy(s, x, y);
-            return;
-        }
+    if (!qemu_console_is_visible(s)) {
+        return;
+    }
+
+    if (s->ds->have_text) {
+        text_update_xy(s, x, y);
+    }
 
+    if (s->ds->have_gfx) {
         y1 = (s->y_base + y) % s->total_height;
         y2 = y1 - s->y_displayed;
         if (y2 < 0)
             y2 += s->total_height;
         if (y2 < s->height) {
             c = &s->cells[y1 * s->width + x];
-            vga_putcharxy(s->ds, x, y2, c->ch,
+            vga_putcharxy(s, x, y2, c->ch,
                           &(c->t_attrib));
             invalidate_xy(s, x, y2);
         }
@@ -602,15 +514,17 @@ static void console_show_cursor(QemuConsole *s, int show)
 {
     TextCell *c;
     int y, y1;
+    int x = s->x;
 
-    if (s == active_console) {
-        int x = s->x;
+    if (!qemu_console_is_visible(s)) {
+        return;
+    }
 
-        if (!ds_get_bits_per_pixel(s->ds)) {
-            s->cursor_invalidate = 1;
-            return;
-        }
+    if (s->ds->have_text) {
+        s->cursor_invalidate = 1;
+    }
 
+    if (s->ds->have_gfx) {
         if (x >= s->width) {
             x = s->width - 1;
         }
@@ -623,9 +537,9 @@ static void console_show_cursor(QemuConsole *s, int show)
             if (show && s->cursor_visible_phase) {
                 TextAttributes t_attrib = s->t_attrib_default;
                 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
-                vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
+                vga_putcharxy(s, x, y, c->ch, &t_attrib);
             } else {
-                vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
+                vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
             }
             invalidate_xy(s, x, y);
         }
@@ -634,11 +548,13 @@ static void console_show_cursor(QemuConsole *s, int show)
 
 static void console_refresh(QemuConsole *s)
 {
+    DisplaySurface *surface = qemu_console_surface(s);
     TextCell *c;
     int x, y, y1;
 
-    if (s != active_console)
+    if (!qemu_console_is_visible(s)) {
         return;
+    }
 
     if (s->ds->have_text) {
         s->text_x[0] = 0;
@@ -649,13 +565,13 @@ static void console_refresh(QemuConsole *s)
     }
 
     if (s->ds->have_gfx) {
-        vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
-                      color_table[0][COLOR_BLACK]);
+        vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
+                      color_table_rgb[0][COLOR_BLACK]);
         y1 = s->y_displayed;
         for (y = 0; y < s->height; y++) {
             c = s->cells + y1 * s->width;
             for (x = 0; x < s->width; x++) {
-                vga_putcharxy(s->ds, x, y, c->ch,
+                vga_putcharxy(s, x, y, c->ch,
                               &(c->t_attrib));
                 c++;
             }
@@ -664,19 +580,15 @@ static void console_refresh(QemuConsole *s)
             }
         }
         console_show_cursor(s, 1);
-        dpy_gfx_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
+        dpy_gfx_update(s, 0, 0,
+                       surface_width(surface), surface_height(surface));
     }
 }
 
-static void console_scroll(int ydelta)
+static void console_scroll(QemuConsole *s, int ydelta)
 {
-    QemuConsole *s;
     int i, y1;
 
-    s = active_console;
-    if (!s || (s->console_type == GRAPHIC_CONSOLE))
-        return;
-
     if (ydelta > 0) {
         for(i = 0; i < ydelta; i++) {
             if (s->y_displayed == s->y_base)
@@ -726,25 +638,26 @@ static void console_put_lf(QemuConsole *s)
             c->t_attrib = s->t_attrib_default;
             c++;
         }
-        if (s == active_console && s->y_displayed == s->y_base) {
-            if (!ds_get_bits_per_pixel(s->ds)) {
+        if (qemu_console_is_visible(s) && s->y_displayed == s->y_base) {
+            if (s->ds->have_text) {
                 s->text_x[0] = 0;
                 s->text_y[0] = 0;
                 s->text_x[1] = s->width - 1;
                 s->text_y[1] = s->height - 1;
-                return;
             }
 
-            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
-                       s->width * FONT_WIDTH,
-                       (s->height - 1) * FONT_HEIGHT);
-            vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
-                          s->width * FONT_WIDTH, FONT_HEIGHT,
-                          color_table[0][s->t_attrib_default.bgcol]);
-            s->update_x0 = 0;
-            s->update_y0 = 0;
-            s->update_x1 = s->width * FONT_WIDTH;
-            s->update_y1 = s->height * FONT_HEIGHT;
+            if (s->ds->have_gfx) {
+                vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
+                           s->width * FONT_WIDTH,
+                           (s->height - 1) * FONT_HEIGHT);
+                vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
+                              s->width * FONT_WIDTH, FONT_HEIGHT,
+                              color_table_rgb[0][s->t_attrib_default.bgcol]);
+                s->update_x0 = 0;
+                s->update_y0 = 0;
+                s->update_x1 = s->width * FONT_WIDTH;
+                s->update_y1 = s->height * FONT_HEIGHT;
+            }
         }
     }
 }
@@ -1082,35 +995,40 @@ static void console_putchar(QemuConsole *s, int ch)
 
 void console_select(unsigned int index)
 {
+    DisplayChangeListener *dcl;
     QemuConsole *s;
 
     if (index >= MAX_CONSOLES)
         return;
-    if (active_console) {
-        active_console->g_width = ds_get_width(active_console->ds);
-        active_console->g_height = ds_get_height(active_console->ds);
-    }
-    s = consoles[index];
+
+    trace_console_select(index);
+    s = qemu_console_lookup_by_index(index);
     if (s) {
         DisplayState *ds = s->ds;
 
         if (active_console && active_console->cursor_timer) {
-            qemu_del_timer(active_console->cursor_timer);
+            timer_del(active_console->cursor_timer);
         }
         active_console = s;
         if (ds->have_gfx) {
-            DisplaySurface *surface;
-            surface = qemu_create_displaysurface(s->g_width, s->g_height);
-            dpy_gfx_replace_surface(ds, surface);
+            QLIST_FOREACH(dcl, &ds->listeners, next) {
+                if (dcl->con != NULL) {
+                    continue;
+                }
+                if (dcl->ops->dpy_gfx_switch) {
+                    dcl->ops->dpy_gfx_switch(dcl, s->surface);
+                }
+            }
+            dpy_gfx_update(s, 0, 0, surface_width(s->surface),
+                           surface_height(s->surface));
         }
         if (ds->have_text) {
-            dpy_text_resize(ds, s->width, s->height);
+            dpy_text_resize(s, s->width, s->height);
         }
         if (s->cursor_timer) {
-            qemu_mod_timer(s->cursor_timer,
-                   qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
+            timer_mod(s->cursor_timer,
+                   qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
         }
-        vga_hw_invalidate();
     }
 }
 
@@ -1129,7 +1047,7 @@ static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
     }
     console_show_cursor(s, 1);
     if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
-        dpy_gfx_update(s->ds, s->update_x0, s->update_y0,
+        dpy_gfx_update(s, s->update_x0, s->update_y0,
                        s->update_x1 - s->update_x0,
                        s->update_y1 - s->update_y0);
     }
@@ -1154,7 +1072,7 @@ static void kbd_send_chars(void *opaque)
     /* characters are pending: we send them a bit later (XXX:
        horrible, should change char device API) */
     if (s->out_fifo.count > 0) {
-        qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
+        timer_mod(s->kbd_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1);
     }
 }
 
@@ -1171,16 +1089,16 @@ void kbd_put_keysym(int keysym)
 
     switch(keysym) {
     case QEMU_KEY_CTRL_UP:
-        console_scroll(-1);
+        console_scroll(s, -1);
         break;
     case QEMU_KEY_CTRL_DOWN:
-        console_scroll(1);
+        console_scroll(s, 1);
         break;
     case QEMU_KEY_CTRL_PAGEUP:
-        console_scroll(-10);
+        console_scroll(s, -10);
         break;
     case QEMU_KEY_CTRL_PAGEDOWN:
-        console_scroll(10);
+        console_scroll(s, 10);
         break;
     default:
         /* convert the QEMU keysym to VT100 key string */
@@ -1217,9 +1135,8 @@ void kbd_put_keysym(int keysym)
 static void text_console_invalidate(void *opaque)
 {
     QemuConsole *s = (QemuConsole *) opaque;
-    if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
-        s->g_width = ds_get_width(s->ds);
-        s->g_height = ds_get_height(s->ds);
+
+    if (s->ds->have_text && s->console_type == TEXT_CONSOLE) {
         text_console_resize(s);
     }
     console_refresh(s);
@@ -1239,7 +1156,7 @@ static void text_console_update(void *opaque, console_ch_t *chardata)
                                 (s->cells[src].t_attrib.fgcol << 12) |
                                 (s->cells[src].t_attrib.bgcol << 8) |
                                 (s->cells[src].t_attrib.bold << 21));
-        dpy_text_update(s->ds, s->text_x[0], s->text_y[0],
+        dpy_text_update(s, s->text_x[0], s->text_y[0],
                         s->text_x[1] - s->text_x[0], i - s->text_y[0]);
         s->text_x[0] = s->width;
         s->text_y[0] = s->height;
@@ -1247,31 +1164,26 @@ static void text_console_update(void *opaque, console_ch_t *chardata)
         s->text_y[1] = 0;
     }
     if (s->cursor_invalidate) {
-        dpy_text_cursor(s->ds, s->x, s->y);
+        dpy_text_cursor(s, s->x, s->y);
         s->cursor_invalidate = 0;
     }
 }
 
-static QemuConsole *get_graphic_console(DisplayState *ds)
-{
-    int i;
-    QemuConsole *s;
-    for (i = 0; i < nb_consoles; i++) {
-        s = consoles[i];
-        if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
-            return s;
-    }
-    return NULL;
-}
-
 static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
 {
+    Error *local_err = NULL;
+    Object *obj;
     QemuConsole *s;
     int i;
 
     if (nb_consoles >= MAX_CONSOLES)
         return NULL;
-    s = g_malloc0(sizeof(QemuConsole));
+
+    obj = object_new(TYPE_QEMU_CONSOLE);
+    s = QEMU_CONSOLE(obj);
+    object_property_add_link(obj, "device", TYPE_DEVICE,
+                             (Object **)&s->device, &local_err);
+
     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
         (console_type == GRAPHIC_CONSOLE))) {
         active_console = s;
@@ -1355,6 +1267,28 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
     return surface;
 }
 
+static DisplaySurface *qemu_create_dummy_surface(void)
+{
+    static const char msg[] =
+        "This VM has no graphic display device.";
+    DisplaySurface *surface = qemu_create_displaysurface(640, 480);
+    pixman_color_t bg = color_table_rgb[0][COLOR_BLACK];
+    pixman_color_t fg = color_table_rgb[0][COLOR_WHITE];
+    pixman_image_t *glyph;
+    int len, x, y, i;
+
+    len = strlen(msg);
+    x = (640/FONT_WIDTH  - len) / 2;
+    y = (480/FONT_HEIGHT - 1)   / 2;
+    for (i = 0; i < len; i++) {
+        glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
+        qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
+                                 x+i, y, FONT_WIDTH, FONT_HEIGHT);
+        qemu_pixman_image_unref(glyph);
+    }
+    return surface;
+}
+
 void qemu_free_displaysurface(DisplaySurface *surface)
 {
     if (surface == NULL) {
@@ -1365,15 +1299,41 @@ void qemu_free_displaysurface(DisplaySurface *surface)
     g_free(surface);
 }
 
-void register_displaychangelistener(DisplayState *ds,
-                                    DisplayChangeListener *dcl)
+void register_displaychangelistener(DisplayChangeListener *dcl)
 {
+    static DisplaySurface *dummy;
+    QemuConsole *con;
+
     trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
-    dcl->ds = ds;
-    QLIST_INSERT_HEAD(&ds->listeners, dcl, next);
-    gui_setup_refresh(ds);
-    if (dcl->ops->dpy_gfx_resize) {
-        dcl->ops->dpy_gfx_resize(dcl, ds);
+    dcl->ds = get_alloc_displaystate();
+    QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
+    gui_setup_refresh(dcl->ds);
+    if (dcl->con) {
+        dcl->con->dcls++;
+        con = dcl->con;
+    } else {
+        con = active_console;
+    }
+    if (dcl->ops->dpy_gfx_switch) {
+        if (con) {
+            dcl->ops->dpy_gfx_switch(dcl, con->surface);
+        } else {
+            if (!dummy) {
+                dummy = qemu_create_dummy_surface();
+            }
+            dcl->ops->dpy_gfx_switch(dcl, dummy);
+        }
+    }
+}
+
+void update_displaychangelistener(DisplayChangeListener *dcl,
+                                  uint64_t interval)
+{
+    DisplayState *ds = dcl->ds;
+
+    dcl->update_interval = interval;
+    if (!ds->refreshing && ds->update_interval > interval) {
+        timer_mod(ds->gui_timer, ds->last_update + interval);
     }
 }
 
@@ -1381,15 +1341,19 @@ void unregister_displaychangelistener(DisplayChangeListener *dcl)
 {
     DisplayState *ds = dcl->ds;
     trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
+    if (dcl->con) {
+        dcl->con->dcls--;
+    }
     QLIST_REMOVE(dcl, next);
     gui_setup_refresh(ds);
 }
 
-void dpy_gfx_update(DisplayState *s, int x, int y, int w, int h)
+void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
 {
-    struct DisplayChangeListener *dcl;
-    int width = pixman_image_get_width(s->surface->image);
-    int height = pixman_image_get_height(s->surface->image);
+    DisplayState *s = con->ds;
+    DisplayChangeListener *dcl;
+    int width = surface_width(con->surface);
+    int height = surface_height(con->surface);
 
     x = MAX(x, 0);
     y = MAX(y, 0);
@@ -1398,23 +1362,33 @@ void dpy_gfx_update(DisplayState *s, int x, int y, int w, int h)
     w = MIN(w, width - x);
     h = MIN(h, height - y);
 
+    if (!qemu_console_is_visible(con)) {
+        return;
+    }
     QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (con != (dcl->con ? dcl->con : active_console)) {
+            continue;
+        }
         if (dcl->ops->dpy_gfx_update) {
-            dcl->ops->dpy_gfx_update(dcl, s, x, y, w, h);
+            dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
         }
     }
 }
 
-void dpy_gfx_replace_surface(DisplayState *s,
+void dpy_gfx_replace_surface(QemuConsole *con,
                              DisplaySurface *surface)
 {
-    DisplaySurface *old_surface = s->surface;
-    struct DisplayChangeListener *dcl;
+    DisplayState *s = con->ds;
+    DisplaySurface *old_surface = con->surface;
+    DisplayChangeListener *dcl;
 
-    s->surface = surface;
+    con->surface = surface;
     QLIST_FOREACH(dcl, &s->listeners, next) {
-        if (dcl->ops->dpy_gfx_resize) {
-            dcl->ops->dpy_gfx_resize(dcl, s);
+        if (con != (dcl->con ? dcl->con : active_console)) {
+            continue;
+        }
+        if (dcl->ops->dpy_gfx_switch) {
+            dcl->ops->dpy_gfx_switch(dcl, surface);
         }
     }
     qemu_free_displaysurface(old_surface);
@@ -1422,80 +1396,131 @@ void dpy_gfx_replace_surface(DisplayState *s,
 
 void dpy_refresh(DisplayState *s)
 {
-    struct DisplayChangeListener *dcl;
+    DisplayChangeListener *dcl;
+
     QLIST_FOREACH(dcl, &s->listeners, next) {
         if (dcl->ops->dpy_refresh) {
-            dcl->ops->dpy_refresh(dcl, s);
+            dcl->ops->dpy_refresh(dcl);
         }
     }
 }
 
-void dpy_gfx_copy(struct DisplayState *s, int src_x, int src_y,
-                             int dst_x, int dst_y, int w, int h)
+void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
+                  int dst_x, int dst_y, int w, int h)
 {
-    struct DisplayChangeListener *dcl;
+    DisplayState *s = con->ds;
+    DisplayChangeListener *dcl;
+
+    if (!qemu_console_is_visible(con)) {
+        return;
+    }
     QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (con != (dcl->con ? dcl->con : active_console)) {
+            continue;
+        }
         if (dcl->ops->dpy_gfx_copy) {
-            dcl->ops->dpy_gfx_copy(dcl, s, src_x, src_y, dst_x, dst_y, w, h);
+            dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h);
         } else { /* TODO */
-            dcl->ops->dpy_gfx_update(dcl, s, dst_x, dst_y, w, h);
+            dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h);
         }
     }
 }
 
-void dpy_text_cursor(struct DisplayState *s, int x, int y)
+void dpy_text_cursor(QemuConsole *con, int x, int y)
 {
-    struct DisplayChangeListener *dcl;
+    DisplayState *s = con->ds;
+    DisplayChangeListener *dcl;
+
+    if (!qemu_console_is_visible(con)) {
+        return;
+    }
     QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (con != (dcl->con ? dcl->con : active_console)) {
+            continue;
+        }
         if (dcl->ops->dpy_text_cursor) {
-            dcl->ops->dpy_text_cursor(dcl, s, x, y);
+            dcl->ops->dpy_text_cursor(dcl, x, y);
         }
     }
 }
 
-void dpy_text_update(DisplayState *s, int x, int y, int w, int h)
+void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
 {
-    struct DisplayChangeListener *dcl;
+    DisplayState *s = con->ds;
+    DisplayChangeListener *dcl;
+
+    if (!qemu_console_is_visible(con)) {
+        return;
+    }
     QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (con != (dcl->con ? dcl->con : active_console)) {
+            continue;
+        }
         if (dcl->ops->dpy_text_update) {
-            dcl->ops->dpy_text_update(dcl, s, x, y, w, h);
+            dcl->ops->dpy_text_update(dcl, x, y, w, h);
         }
     }
 }
 
-void dpy_text_resize(DisplayState *s, int w, int h)
+void dpy_text_resize(QemuConsole *con, int w, int h)
 {
+    DisplayState *s = con->ds;
     struct DisplayChangeListener *dcl;
+
+    if (!qemu_console_is_visible(con)) {
+        return;
+    }
     QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (con != (dcl->con ? dcl->con : active_console)) {
+            continue;
+        }
         if (dcl->ops->dpy_text_resize) {
-            dcl->ops->dpy_text_resize(dcl, s, w, h);
+            dcl->ops->dpy_text_resize(dcl, w, h);
         }
     }
 }
 
-void dpy_mouse_set(struct DisplayState *s, int x, int y, int on)
+void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
 {
-    struct DisplayChangeListener *dcl;
+    DisplayState *s = con->ds;
+    DisplayChangeListener *dcl;
+
+    if (!qemu_console_is_visible(con)) {
+        return;
+    }
     QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (con != (dcl->con ? dcl->con : active_console)) {
+            continue;
+        }
         if (dcl->ops->dpy_mouse_set) {
-            dcl->ops->dpy_mouse_set(dcl, s, x, y, on);
+            dcl->ops->dpy_mouse_set(dcl, x, y, on);
         }
     }
 }
 
-void dpy_cursor_define(struct DisplayState *s, QEMUCursor *cursor)
+void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
 {
-    struct DisplayChangeListener *dcl;
+    DisplayState *s = con->ds;
+    DisplayChangeListener *dcl;
+
+    if (!qemu_console_is_visible(con)) {
+        return;
+    }
     QLIST_FOREACH(dcl, &s->listeners, next) {
+        if (con != (dcl->con ? dcl->con : active_console)) {
+            continue;
+        }
         if (dcl->ops->dpy_cursor_define) {
-            dcl->ops->dpy_cursor_define(dcl, s, cursor);
+            dcl->ops->dpy_cursor_define(dcl, cursor);
         }
     }
 }
 
-bool dpy_cursor_define_supported(struct DisplayState *s)
+bool dpy_cursor_define_supported(QemuConsole *con)
 {
-    struct DisplayChangeListener *dcl;
+    DisplayState *s = con->ds;
+    DisplayChangeListener *dcl;
+
     QLIST_FOREACH(dcl, &s->listeners, next) {
         if (dcl->ops->dpy_cursor_define) {
             return true;
@@ -1504,88 +1529,120 @@ bool dpy_cursor_define_supported(struct DisplayState *s)
     return false;
 }
 
-static void dumb_display_init(void)
-{
-    DisplayState *ds = g_malloc0(sizeof(DisplayState));
-    DisplaySurface *surface;
-    int width = 640;
-    int height = 480;
-
-    if (is_fixedsize_console()) {
-        width = active_console->g_width;
-        height = active_console->g_height;
-    }
-    surface = qemu_create_displaysurface(width, height);
-    dpy_gfx_replace_surface(ds, surface);
-
-    register_displaystate(ds);
-}
-
 /***********************************************************/
 /* register display */
 
-void register_displaystate(DisplayState *ds)
+/* console.c internal use only */
+static DisplayState *get_alloc_displaystate(void)
 {
-    DisplayState **s;
-    s = &display_state;
-    while (*s != NULL)
-        s = &(*s)->next;
-    ds->next = NULL;
-    *s = ds;
+    if (!display_state) {
+        display_state = g_new0(DisplayState, 1);
+    }
+    return display_state;
 }
 
-DisplayState *get_displaystate(void)
+/*
+ * Called by main(), after creating QemuConsoles
+ * and before initializing ui (sdl/vnc/...).
+ */
+DisplayState *init_displaystate(void)
 {
+    Error *local_err = NULL;
+    gchar *name;
+    int i;
+
     if (!display_state) {
-        dumb_display_init ();
+        display_state = g_new0(DisplayState, 1);
     }
+
+    for (i = 0; i < nb_consoles; i++) {
+        if (consoles[i]->console_type != GRAPHIC_CONSOLE &&
+            consoles[i]->ds == NULL) {
+            text_console_do_init(consoles[i]->chr, display_state);
+        }
+
+        /* Hook up into the qom tree here (not in new_console()), once
+         * all QemuConsoles are created and the order / numbering
+         * doesn't change any more */
+        name = g_strdup_printf("console[%d]", i);
+        object_property_add_child(container_get(object_get_root(), "/backend"),
+                                  name, OBJECT(consoles[i]), &local_err);
+        g_free(name);
+    }
+
     return display_state;
 }
 
-DisplayState *graphic_console_init(vga_hw_update_ptr update,
-                                   vga_hw_invalidate_ptr invalidate,
-                                   vga_hw_screen_dump_ptr screen_dump,
-                                   vga_hw_text_update_ptr text_update,
-                                   void *opaque)
+QemuConsole *graphic_console_init(DeviceState *dev,
+                                  const GraphicHwOps *hw_ops,
+                                  void *opaque)
 {
+    Error *local_err = NULL;
+    int width = 640;
+    int height = 480;
     QemuConsole *s;
     DisplayState *ds;
-    DisplaySurface *surface;
 
-    ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
+    ds = get_alloc_displaystate();
+    trace_console_gfx_new();
     s = new_console(ds, GRAPHIC_CONSOLE);
-    s->hw_update = update;
-    s->hw_invalidate = invalidate;
-    s->hw_screen_dump = screen_dump;
-    s->hw_text_update = text_update;
+    s->hw_ops = hw_ops;
     s->hw = opaque;
+    if (dev) {
+        object_property_set_link(OBJECT(s), OBJECT(dev),
+                                 "device", &local_err);
+    }
 
-    surface = qemu_create_displaysurface(640, 480);
-    dpy_gfx_replace_surface(ds, surface);
+    s->surface = qemu_create_displaysurface(width, height);
+    return s;
+}
 
-    register_displaystate(ds);
-    return ds;
+QemuConsole *qemu_console_lookup_by_index(unsigned int index)
+{
+    if (index >= MAX_CONSOLES) {
+        return NULL;
+    }
+    return consoles[index];
 }
 
-int is_graphic_console(void)
+QemuConsole *qemu_console_lookup_by_device(DeviceState *dev)
 {
-    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
+    Error *local_err = NULL;
+    Object *obj;
+    int i;
+
+    for (i = 0; i < nb_consoles; i++) {
+        if (!consoles[i]) {
+            continue;
+        }
+        obj = object_property_get_link(OBJECT(consoles[i]),
+                                       "device", &local_err);
+        if (DEVICE(obj) == dev) {
+            return consoles[i];
+        }
+    }
+    return NULL;
 }
 
-int is_fixedsize_console(void)
+bool qemu_console_is_visible(QemuConsole *con)
 {
-    return active_console && active_console->console_type != TEXT_CONSOLE;
+    return (con == active_console) || (con->dcls > 0);
 }
 
-void console_color_init(DisplayState *ds)
+bool qemu_console_is_graphic(QemuConsole *con)
 {
-    int i, j;
-    for (j = 0; j < 2; j++) {
-        for (i = 0; i < 8; i++) {
-            color_table[j][i] = col_expand(ds,
-                   vga_get_color(ds, color_table_rgb[j][i]));
-        }
+    if (con == NULL) {
+        con = active_console;
     }
+    return con && (con->console_type == GRAPHIC_CONSOLE);
+}
+
+bool qemu_console_is_fixedsize(QemuConsole *con)
+{
+    if (con == NULL) {
+        con = active_console;
+    }
+    return con && (con->console_type != TEXT_CONSOLE);
 }
 
 static void text_console_set_echo(CharDriverState *chr, bool echo)
@@ -1600,15 +1657,21 @@ static void text_console_update_cursor(void *opaque)
     QemuConsole *s = opaque;
 
     s->cursor_visible_phase = !s->cursor_visible_phase;
-    vga_hw_invalidate();
-    qemu_mod_timer(s->cursor_timer,
-                   qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
+    graphic_hw_invalidate(s);
+    timer_mod(s->cursor_timer,
+                   qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
 }
 
+static const GraphicHwOps text_console_ops = {
+    .invalidate  = text_console_invalidate,
+    .text_update = text_console_update,
+};
+
 static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
 {
     QemuConsole *s;
-    static int color_inited;
+    int g_width = 80 * FONT_WIDTH;
+    int g_height = 24 * FONT_HEIGHT;
 
     s = chr->opaque;
 
@@ -1616,28 +1679,26 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
 
     s->out_fifo.buf = s->out_fifo_buf;
     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
-    s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
+    s->kbd_timer = timer_new_ms(QEMU_CLOCK_REALTIME, kbd_send_chars, s);
     s->ds = ds;
 
-    if (!color_inited) {
-        color_inited = 1;
-        console_color_init(s->ds);
-    }
     s->y_displayed = 0;
     s->y_base = 0;
     s->total_height = DEFAULT_BACKSCROLL;
     s->x = 0;
     s->y = 0;
-    if (s->console_type == TEXT_CONSOLE) {
-        s->g_width = ds_get_width(s->ds);
-        s->g_height = ds_get_height(s->ds);
+    if (!s->surface) {
+        if (active_console && active_console->surface) {
+            g_width = surface_width(active_console->surface);
+            g_height = surface_height(active_console->surface);
+        }
+        s->surface = qemu_create_displaysurface(g_width, g_height);
     }
 
     s->cursor_timer =
-        qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
+        timer_new_ms(QEMU_CLOCK_REALTIME, text_console_update_cursor, s);
 
-    s->hw_invalidate = text_console_invalidate;
-    s->hw_text_update = text_console_update;
+    s->hw_ops = &text_console_ops;
     s->hw = s;
 
     /* Set text attribute defaults */
@@ -1662,7 +1723,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
         s->t_attrib = s->t_attrib_default;
     }
 
-    qemu_chr_generic_open(chr);
+    qemu_chr_be_generic_open(chr);
     if (chr->init)
         chr->init(chr);
 }
@@ -1688,10 +1749,12 @@ static CharDriverState *text_console_init(ChardevVC *vc)
         height = vc->rows * FONT_HEIGHT;
     }
 
+    trace_console_txt_new(width, height);
     if (width == 0 || height == 0) {
         s = new_console(NULL, TEXT_CONSOLE);
     } else {
         s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
+        s->surface = qemu_create_displaysurface(width, height);
     }
 
     if (!s) {
@@ -1700,10 +1763,16 @@ static CharDriverState *text_console_init(ChardevVC *vc)
     }
 
     s->chr = chr;
-    s->g_width = width;
-    s->g_height = height;
     chr->opaque = s;
     chr->chr_set_echo = text_console_set_echo;
+    /* console/chardev init sometimes completes elsewhere in a 2nd
+     * stage, so defer OPENED events until they are fully initialized
+     */
+    chr->explicit_be_open = true;
+
+    if (display_state) {
+        text_console_do_init(chr, display_state);
+    }
     return chr;
 }
 
@@ -1719,37 +1788,30 @@ void register_vc_handler(VcHandler *handler)
     vc_handler = handler;
 }
 
-void text_consoles_set_display(DisplayState *ds)
+void qemu_console_resize(QemuConsole *s, int width, int height)
 {
-    int i;
+    DisplaySurface *surface;
 
-    for (i = 0; i < nb_consoles; i++) {
-        if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
-            text_console_do_init(consoles[i]->chr, ds);
-        }
-    }
+    assert(s->console_type == GRAPHIC_CONSOLE);
+    surface = qemu_create_displaysurface(width, height);
+    dpy_gfx_replace_surface(s, surface);
 }
 
-void qemu_console_resize(DisplayState *ds, int width, int height)
+void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
+                       int dst_x, int dst_y, int w, int h)
 {
-    QemuConsole *s = get_graphic_console(ds);
-    if (!s) return;
+    assert(con->console_type == GRAPHIC_CONSOLE);
+    dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h);
+}
 
-    s->g_width = width;
-    s->g_height = height;
-    if (is_graphic_console()) {
-        DisplaySurface *surface;
-        surface = qemu_create_displaysurface(width, height);
-        dpy_gfx_replace_surface(ds, surface);
-    }
+DisplaySurface *qemu_console_surface(QemuConsole *console)
+{
+    return console->surface;
 }
 
-void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
-                       int dst_x, int dst_y, int w, int h)
+DisplayState *qemu_console_displaystate(QemuConsole *console)
 {
-    if (is_graphic_console()) {
-        dpy_gfx_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
-    }
+    return console->ds;
 }
 
 PixelFormat qemu_different_endianness_pixelformat(int bpp)
@@ -1907,8 +1969,17 @@ static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
     }
 }
 
+static const TypeInfo qemu_console_info = {
+    .name = TYPE_QEMU_CONSOLE,
+    .parent = TYPE_OBJECT,
+    .instance_size = sizeof(QemuConsole),
+    .class_size = sizeof(QemuConsoleClass),
+};
+
+
 static void register_types(void)
 {
+    type_register_static(&qemu_console_info);
     register_char_driver_qapi("vc", CHARDEV_BACKEND_KIND_VC,
                               qemu_chr_parse_vc);
 }