qemu/ui/console.c
<<
>>
Prefs
   1/*
   2 * QEMU graphical console
   3 *
   4 * Copyright (c) 2004 Fabrice Bellard
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "ui/console.h"
  27#include "hw/qdev-core.h"
  28#include "qapi/error.h"
  29#include "qapi/qapi-commands-ui.h"
  30#include "qemu/option.h"
  31#include "qemu/timer.h"
  32#include "chardev/char-fe.h"
  33#include "trace.h"
  34#include "exec/memory.h"
  35
  36#define DEFAULT_BACKSCROLL 512
  37#define CONSOLE_CURSOR_PERIOD 500
  38
  39typedef struct TextAttributes {
  40    uint8_t fgcol:4;
  41    uint8_t bgcol:4;
  42    uint8_t bold:1;
  43    uint8_t uline:1;
  44    uint8_t blink:1;
  45    uint8_t invers:1;
  46    uint8_t unvisible:1;
  47} TextAttributes;
  48
  49typedef struct TextCell {
  50    uint8_t ch;
  51    TextAttributes t_attrib;
  52} TextCell;
  53
  54#define MAX_ESC_PARAMS 3
  55
  56enum TTYState {
  57    TTY_STATE_NORM,
  58    TTY_STATE_ESC,
  59    TTY_STATE_CSI,
  60};
  61
  62typedef struct QEMUFIFO {
  63    uint8_t *buf;
  64    int buf_size;
  65    int count, wptr, rptr;
  66} QEMUFIFO;
  67
  68static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
  69{
  70    int l, len;
  71
  72    l = f->buf_size - f->count;
  73    if (len1 > l)
  74        len1 = l;
  75    len = len1;
  76    while (len > 0) {
  77        l = f->buf_size - f->wptr;
  78        if (l > len)
  79            l = len;
  80        memcpy(f->buf + f->wptr, buf, l);
  81        f->wptr += l;
  82        if (f->wptr >= f->buf_size)
  83            f->wptr = 0;
  84        buf += l;
  85        len -= l;
  86    }
  87    f->count += len1;
  88    return len1;
  89}
  90
  91static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
  92{
  93    int l, len;
  94
  95    if (len1 > f->count)
  96        len1 = f->count;
  97    len = len1;
  98    while (len > 0) {
  99        l = f->buf_size - f->rptr;
 100        if (l > len)
 101            l = len;
 102        memcpy(buf, f->buf + f->rptr, l);
 103        f->rptr += l;
 104        if (f->rptr >= f->buf_size)
 105            f->rptr = 0;
 106        buf += l;
 107        len -= l;
 108    }
 109    f->count -= len1;
 110    return len1;
 111}
 112
 113typedef enum {
 114    GRAPHIC_CONSOLE,
 115    TEXT_CONSOLE,
 116    TEXT_CONSOLE_FIXED_SIZE
 117} console_type_t;
 118
 119struct QemuConsole {
 120    Object parent;
 121
 122    int index;
 123    console_type_t console_type;
 124    DisplayState *ds;
 125    DisplaySurface *surface;
 126    int dcls;
 127    DisplayChangeListener *gl;
 128    bool gl_block;
 129    int window_id;
 130
 131    /* Graphic console state.  */
 132    Object *device;
 133    uint32_t head;
 134    QemuUIInfo ui_info;
 135    QEMUTimer *ui_timer;
 136    const GraphicHwOps *hw_ops;
 137    void *hw;
 138
 139    /* Text console state */
 140    int width;
 141    int height;
 142    int total_height;
 143    int backscroll_height;
 144    int x, y;
 145    int x_saved, y_saved;
 146    int y_displayed;
 147    int y_base;
 148    TextAttributes t_attrib_default; /* default text attributes */
 149    TextAttributes t_attrib; /* currently active text attributes */
 150    TextCell *cells;
 151    int text_x[2], text_y[2], cursor_invalidate;
 152    int echo;
 153
 154    int update_x0;
 155    int update_y0;
 156    int update_x1;
 157    int update_y1;
 158
 159    enum TTYState state;
 160    int esc_params[MAX_ESC_PARAMS];
 161    int nb_esc_params;
 162
 163    Chardev *chr;
 164    /* fifo for key pressed */
 165    QEMUFIFO out_fifo;
 166    uint8_t out_fifo_buf[16];
 167    QEMUTimer *kbd_timer;
 168
 169    QTAILQ_ENTRY(QemuConsole) next;
 170};
 171
 172struct DisplayState {
 173    QEMUTimer *gui_timer;
 174    uint64_t last_update;
 175    uint64_t update_interval;
 176    bool refreshing;
 177    bool have_gfx;
 178    bool have_text;
 179
 180    QLIST_HEAD(, DisplayChangeListener) listeners;
 181};
 182
 183static DisplayState *display_state;
 184static QemuConsole *active_console;
 185static QTAILQ_HEAD(consoles_head, QemuConsole) consoles =
 186    QTAILQ_HEAD_INITIALIZER(consoles);
 187static bool cursor_visible_phase;
 188static QEMUTimer *cursor_timer;
 189
 190static void text_console_do_init(Chardev *chr, DisplayState *ds);
 191static void dpy_refresh(DisplayState *s);
 192static DisplayState *get_alloc_displaystate(void);
 193static void text_console_update_cursor_timer(void);
 194static void text_console_update_cursor(void *opaque);
 195
 196static void gui_update(void *opaque)
 197{
 198    uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
 199    uint64_t dcl_interval;
 200    DisplayState *ds = opaque;
 201    DisplayChangeListener *dcl;
 202    QemuConsole *con;
 203
 204    ds->refreshing = true;
 205    dpy_refresh(ds);
 206    ds->refreshing = false;
 207
 208    QLIST_FOREACH(dcl, &ds->listeners, next) {
 209        dcl_interval = dcl->update_interval ?
 210            dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
 211        if (interval > dcl_interval) {
 212            interval = dcl_interval;
 213        }
 214    }
 215    if (ds->update_interval != interval) {
 216        ds->update_interval = interval;
 217        QTAILQ_FOREACH(con, &consoles, next) {
 218            if (con->hw_ops->update_interval) {
 219                con->hw_ops->update_interval(con->hw, interval);
 220            }
 221        }
 222        trace_console_refresh(interval);
 223    }
 224    ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
 225    timer_mod(ds->gui_timer, ds->last_update + interval);
 226}
 227
 228static void gui_setup_refresh(DisplayState *ds)
 229{
 230    DisplayChangeListener *dcl;
 231    bool need_timer = false;
 232    bool have_gfx = false;
 233    bool have_text = false;
 234
 235    QLIST_FOREACH(dcl, &ds->listeners, next) {
 236        if (dcl->ops->dpy_refresh != NULL) {
 237            need_timer = true;
 238        }
 239        if (dcl->ops->dpy_gfx_update != NULL) {
 240            have_gfx = true;
 241        }
 242        if (dcl->ops->dpy_text_update != NULL) {
 243            have_text = true;
 244        }
 245    }
 246
 247    if (need_timer && ds->gui_timer == NULL) {
 248        ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
 249        timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
 250    }
 251    if (!need_timer && ds->gui_timer != NULL) {
 252        timer_del(ds->gui_timer);
 253        timer_free(ds->gui_timer);
 254        ds->gui_timer = NULL;
 255    }
 256
 257    ds->have_gfx = have_gfx;
 258    ds->have_text = have_text;
 259}
 260
 261void graphic_hw_update(QemuConsole *con)
 262{
 263    if (!con) {
 264        con = active_console;
 265    }
 266    if (con && con->hw_ops->gfx_update) {
 267        con->hw_ops->gfx_update(con->hw);
 268    }
 269}
 270
 271void graphic_hw_gl_block(QemuConsole *con, bool block)
 272{
 273    assert(con != NULL);
 274
 275    con->gl_block = block;
 276    if (con->hw_ops->gl_block) {
 277        con->hw_ops->gl_block(con->hw, block);
 278    }
 279}
 280
 281int qemu_console_get_window_id(QemuConsole *con)
 282{
 283    return con->window_id;
 284}
 285
 286void qemu_console_set_window_id(QemuConsole *con, int window_id)
 287{
 288    con->window_id = window_id;
 289}
 290
 291void graphic_hw_invalidate(QemuConsole *con)
 292{
 293    if (!con) {
 294        con = active_console;
 295    }
 296    if (con && con->hw_ops->invalidate) {
 297        con->hw_ops->invalidate(con->hw);
 298    }
 299}
 300
 301static void ppm_save(const char *filename, DisplaySurface *ds,
 302                     Error **errp)
 303{
 304    int width = pixman_image_get_width(ds->image);
 305    int height = pixman_image_get_height(ds->image);
 306    int fd;
 307    FILE *f;
 308    int y;
 309    int ret;
 310    pixman_image_t *linebuf;
 311
 312    trace_ppm_save(filename, ds);
 313    fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
 314    if (fd == -1) {
 315        error_setg(errp, "failed to open file '%s': %s", filename,
 316                   strerror(errno));
 317        return;
 318    }
 319    f = fdopen(fd, "wb");
 320    ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
 321    if (ret < 0) {
 322        linebuf = NULL;
 323        goto write_err;
 324    }
 325    linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
 326    for (y = 0; y < height; y++) {
 327        qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y);
 328        clearerr(f);
 329        ret = fwrite(pixman_image_get_data(linebuf), 1,
 330                     pixman_image_get_stride(linebuf), f);
 331        (void)ret;
 332        if (ferror(f)) {
 333            goto write_err;
 334        }
 335    }
 336
 337out:
 338    qemu_pixman_image_unref(linebuf);
 339    fclose(f);
 340    return;
 341
 342write_err:
 343    error_setg(errp, "failed to write to file '%s': %s", filename,
 344               strerror(errno));
 345    unlink(filename);
 346    goto out;
 347}
 348
 349void qmp_screendump(const char *filename, bool has_device, const char *device,
 350                    bool has_head, int64_t head, Error **errp)
 351{
 352    QemuConsole *con;
 353    DisplaySurface *surface;
 354
 355    if (has_device) {
 356        con = qemu_console_lookup_by_device_name(device, has_head ? head : 0,
 357                                                 errp);
 358        if (!con) {
 359            return;
 360        }
 361    } else {
 362        if (has_head) {
 363            error_setg(errp, "'head' must be specified together with 'device'");
 364            return;
 365        }
 366        con = qemu_console_lookup_by_index(0);
 367        if (!con) {
 368            error_setg(errp, "There is no console to take a screendump from");
 369            return;
 370        }
 371    }
 372
 373    graphic_hw_update(con);
 374    surface = qemu_console_surface(con);
 375    if (!surface) {
 376        error_setg(errp, "no surface");
 377        return;
 378    }
 379
 380    ppm_save(filename, surface, errp);
 381}
 382
 383void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
 384{
 385    if (!con) {
 386        con = active_console;
 387    }
 388    if (con && con->hw_ops->text_update) {
 389        con->hw_ops->text_update(con->hw, chardata);
 390    }
 391}
 392
 393static void vga_fill_rect(QemuConsole *con,
 394                          int posx, int posy, int width, int height,
 395                          pixman_color_t color)
 396{
 397    DisplaySurface *surface = qemu_console_surface(con);
 398    pixman_rectangle16_t rect = {
 399        .x = posx, .y = posy, .width = width, .height = height
 400    };
 401
 402    pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
 403                                 &color, 1, &rect);
 404}
 405
 406/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
 407static void vga_bitblt(QemuConsole *con,
 408                       int xs, int ys, int xd, int yd, int w, int h)
 409{
 410    DisplaySurface *surface = qemu_console_surface(con);
 411
 412    pixman_image_composite(PIXMAN_OP_SRC,
 413                           surface->image, NULL, surface->image,
 414                           xs, ys, 0, 0, xd, yd, w, h);
 415}
 416
 417/***********************************************************/
 418/* basic char display */
 419
 420#define FONT_HEIGHT 16
 421#define FONT_WIDTH 8
 422
 423#include "vgafont.h"
 424
 425#define QEMU_RGB(r, g, b)                                               \
 426    { .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff }
 427
 428static const pixman_color_t color_table_rgb[2][8] = {
 429    {   /* dark */
 430        [QEMU_COLOR_BLACK]   = QEMU_RGB(0x00, 0x00, 0x00),  /* black */
 431        [QEMU_COLOR_BLUE]    = QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
 432        [QEMU_COLOR_GREEN]   = QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
 433        [QEMU_COLOR_CYAN]    = QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
 434        [QEMU_COLOR_RED]     = QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
 435        [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
 436        [QEMU_COLOR_YELLOW]  = QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
 437        [QEMU_COLOR_WHITE]   = QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
 438    },
 439    {   /* bright */
 440        [QEMU_COLOR_BLACK]   = QEMU_RGB(0x00, 0x00, 0x00),  /* black */
 441        [QEMU_COLOR_BLUE]    = QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
 442        [QEMU_COLOR_GREEN]   = QEMU_RGB(0x00, 0xff, 0x00),  /* green */
 443        [QEMU_COLOR_CYAN]    = QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
 444        [QEMU_COLOR_RED]     = QEMU_RGB(0xff, 0x00, 0x00),  /* red */
 445        [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
 446        [QEMU_COLOR_YELLOW]  = QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
 447        [QEMU_COLOR_WHITE]   = QEMU_RGB(0xff, 0xff, 0xff),  /* white */
 448    }
 449};
 450
 451static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
 452                          TextAttributes *t_attrib)
 453{
 454    static pixman_image_t *glyphs[256];
 455    DisplaySurface *surface = qemu_console_surface(s);
 456    pixman_color_t fgcol, bgcol;
 457
 458    if (t_attrib->invers) {
 459        bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
 460        fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
 461    } else {
 462        fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
 463        bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
 464    }
 465
 466    if (!glyphs[ch]) {
 467        glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
 468    }
 469    qemu_pixman_glyph_render(glyphs[ch], surface->image,
 470                             &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
 471}
 472
 473static void text_console_resize(QemuConsole *s)
 474{
 475    TextCell *cells, *c, *c1;
 476    int w1, x, y, last_width;
 477
 478    last_width = s->width;
 479    s->width = surface_width(s->surface) / FONT_WIDTH;
 480    s->height = surface_height(s->surface) / FONT_HEIGHT;
 481
 482    w1 = last_width;
 483    if (s->width < w1)
 484        w1 = s->width;
 485
 486    cells = g_new(TextCell, s->width * s->total_height);
 487    for(y = 0; y < s->total_height; y++) {
 488        c = &cells[y * s->width];
 489        if (w1 > 0) {
 490            c1 = &s->cells[y * last_width];
 491            for(x = 0; x < w1; x++) {
 492                *c++ = *c1++;
 493            }
 494        }
 495        for(x = w1; x < s->width; x++) {
 496            c->ch = ' ';
 497            c->t_attrib = s->t_attrib_default;
 498            c++;
 499        }
 500    }
 501    g_free(s->cells);
 502    s->cells = cells;
 503}
 504
 505static inline void text_update_xy(QemuConsole *s, int x, int y)
 506{
 507    s->text_x[0] = MIN(s->text_x[0], x);
 508    s->text_x[1] = MAX(s->text_x[1], x);
 509    s->text_y[0] = MIN(s->text_y[0], y);
 510    s->text_y[1] = MAX(s->text_y[1], y);
 511}
 512
 513static void invalidate_xy(QemuConsole *s, int x, int y)
 514{
 515    if (!qemu_console_is_visible(s)) {
 516        return;
 517    }
 518    if (s->update_x0 > x * FONT_WIDTH)
 519        s->update_x0 = x * FONT_WIDTH;
 520    if (s->update_y0 > y * FONT_HEIGHT)
 521        s->update_y0 = y * FONT_HEIGHT;
 522    if (s->update_x1 < (x + 1) * FONT_WIDTH)
 523        s->update_x1 = (x + 1) * FONT_WIDTH;
 524    if (s->update_y1 < (y + 1) * FONT_HEIGHT)
 525        s->update_y1 = (y + 1) * FONT_HEIGHT;
 526}
 527
 528static void update_xy(QemuConsole *s, int x, int y)
 529{
 530    TextCell *c;
 531    int y1, y2;
 532
 533    if (s->ds->have_text) {
 534        text_update_xy(s, x, y);
 535    }
 536
 537    y1 = (s->y_base + y) % s->total_height;
 538    y2 = y1 - s->y_displayed;
 539    if (y2 < 0) {
 540        y2 += s->total_height;
 541    }
 542    if (y2 < s->height) {
 543        c = &s->cells[y1 * s->width + x];
 544        vga_putcharxy(s, x, y2, c->ch,
 545                      &(c->t_attrib));
 546        invalidate_xy(s, x, y2);
 547    }
 548}
 549
 550static void console_show_cursor(QemuConsole *s, int show)
 551{
 552    TextCell *c;
 553    int y, y1;
 554    int x = s->x;
 555
 556    if (s->ds->have_text) {
 557        s->cursor_invalidate = 1;
 558    }
 559
 560    if (x >= s->width) {
 561        x = s->width - 1;
 562    }
 563    y1 = (s->y_base + s->y) % s->total_height;
 564    y = y1 - s->y_displayed;
 565    if (y < 0) {
 566        y += s->total_height;
 567    }
 568    if (y < s->height) {
 569        c = &s->cells[y1 * s->width + x];
 570        if (show && cursor_visible_phase) {
 571            TextAttributes t_attrib = s->t_attrib_default;
 572            t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
 573            vga_putcharxy(s, x, y, c->ch, &t_attrib);
 574        } else {
 575            vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
 576        }
 577        invalidate_xy(s, x, y);
 578    }
 579}
 580
 581static void console_refresh(QemuConsole *s)
 582{
 583    DisplaySurface *surface = qemu_console_surface(s);
 584    TextCell *c;
 585    int x, y, y1;
 586
 587    if (s->ds->have_text) {
 588        s->text_x[0] = 0;
 589        s->text_y[0] = 0;
 590        s->text_x[1] = s->width - 1;
 591        s->text_y[1] = s->height - 1;
 592        s->cursor_invalidate = 1;
 593    }
 594
 595    vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
 596                  color_table_rgb[0][QEMU_COLOR_BLACK]);
 597    y1 = s->y_displayed;
 598    for (y = 0; y < s->height; y++) {
 599        c = s->cells + y1 * s->width;
 600        for (x = 0; x < s->width; x++) {
 601            vga_putcharxy(s, x, y, c->ch,
 602                          &(c->t_attrib));
 603            c++;
 604        }
 605        if (++y1 == s->total_height) {
 606            y1 = 0;
 607        }
 608    }
 609    console_show_cursor(s, 1);
 610    dpy_gfx_update(s, 0, 0,
 611                   surface_width(surface), surface_height(surface));
 612}
 613
 614static void console_scroll(QemuConsole *s, int ydelta)
 615{
 616    int i, y1;
 617
 618    if (ydelta > 0) {
 619        for(i = 0; i < ydelta; i++) {
 620            if (s->y_displayed == s->y_base)
 621                break;
 622            if (++s->y_displayed == s->total_height)
 623                s->y_displayed = 0;
 624        }
 625    } else {
 626        ydelta = -ydelta;
 627        i = s->backscroll_height;
 628        if (i > s->total_height - s->height)
 629            i = s->total_height - s->height;
 630        y1 = s->y_base - i;
 631        if (y1 < 0)
 632            y1 += s->total_height;
 633        for(i = 0; i < ydelta; i++) {
 634            if (s->y_displayed == y1)
 635                break;
 636            if (--s->y_displayed < 0)
 637                s->y_displayed = s->total_height - 1;
 638        }
 639    }
 640    console_refresh(s);
 641}
 642
 643static void console_put_lf(QemuConsole *s)
 644{
 645    TextCell *c;
 646    int x, y1;
 647
 648    s->y++;
 649    if (s->y >= s->height) {
 650        s->y = s->height - 1;
 651
 652        if (s->y_displayed == s->y_base) {
 653            if (++s->y_displayed == s->total_height)
 654                s->y_displayed = 0;
 655        }
 656        if (++s->y_base == s->total_height)
 657            s->y_base = 0;
 658        if (s->backscroll_height < s->total_height)
 659            s->backscroll_height++;
 660        y1 = (s->y_base + s->height - 1) % s->total_height;
 661        c = &s->cells[y1 * s->width];
 662        for(x = 0; x < s->width; x++) {
 663            c->ch = ' ';
 664            c->t_attrib = s->t_attrib_default;
 665            c++;
 666        }
 667        if (s->y_displayed == s->y_base) {
 668            if (s->ds->have_text) {
 669                s->text_x[0] = 0;
 670                s->text_y[0] = 0;
 671                s->text_x[1] = s->width - 1;
 672                s->text_y[1] = s->height - 1;
 673            }
 674
 675            vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
 676                       s->width * FONT_WIDTH,
 677                       (s->height - 1) * FONT_HEIGHT);
 678            vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
 679                          s->width * FONT_WIDTH, FONT_HEIGHT,
 680                          color_table_rgb[0][s->t_attrib_default.bgcol]);
 681            s->update_x0 = 0;
 682            s->update_y0 = 0;
 683            s->update_x1 = s->width * FONT_WIDTH;
 684            s->update_y1 = s->height * FONT_HEIGHT;
 685        }
 686    }
 687}
 688
 689/* Set console attributes depending on the current escape codes.
 690 * NOTE: I know this code is not very efficient (checking every color for it
 691 * self) but it is more readable and better maintainable.
 692 */
 693static void console_handle_escape(QemuConsole *s)
 694{
 695    int i;
 696
 697    for (i=0; i<s->nb_esc_params; i++) {
 698        switch (s->esc_params[i]) {
 699            case 0: /* reset all console attributes to default */
 700                s->t_attrib = s->t_attrib_default;
 701                break;
 702            case 1:
 703                s->t_attrib.bold = 1;
 704                break;
 705            case 4:
 706                s->t_attrib.uline = 1;
 707                break;
 708            case 5:
 709                s->t_attrib.blink = 1;
 710                break;
 711            case 7:
 712                s->t_attrib.invers = 1;
 713                break;
 714            case 8:
 715                s->t_attrib.unvisible = 1;
 716                break;
 717            case 22:
 718                s->t_attrib.bold = 0;
 719                break;
 720            case 24:
 721                s->t_attrib.uline = 0;
 722                break;
 723            case 25:
 724                s->t_attrib.blink = 0;
 725                break;
 726            case 27:
 727                s->t_attrib.invers = 0;
 728                break;
 729            case 28:
 730                s->t_attrib.unvisible = 0;
 731                break;
 732            /* set foreground color */
 733            case 30:
 734                s->t_attrib.fgcol = QEMU_COLOR_BLACK;
 735                break;
 736            case 31:
 737                s->t_attrib.fgcol = QEMU_COLOR_RED;
 738                break;
 739            case 32:
 740                s->t_attrib.fgcol = QEMU_COLOR_GREEN;
 741                break;
 742            case 33:
 743                s->t_attrib.fgcol = QEMU_COLOR_YELLOW;
 744                break;
 745            case 34:
 746                s->t_attrib.fgcol = QEMU_COLOR_BLUE;
 747                break;
 748            case 35:
 749                s->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
 750                break;
 751            case 36:
 752                s->t_attrib.fgcol = QEMU_COLOR_CYAN;
 753                break;
 754            case 37:
 755                s->t_attrib.fgcol = QEMU_COLOR_WHITE;
 756                break;
 757            /* set background color */
 758            case 40:
 759                s->t_attrib.bgcol = QEMU_COLOR_BLACK;
 760                break;
 761            case 41:
 762                s->t_attrib.bgcol = QEMU_COLOR_RED;
 763                break;
 764            case 42:
 765                s->t_attrib.bgcol = QEMU_COLOR_GREEN;
 766                break;
 767            case 43:
 768                s->t_attrib.bgcol = QEMU_COLOR_YELLOW;
 769                break;
 770            case 44:
 771                s->t_attrib.bgcol = QEMU_COLOR_BLUE;
 772                break;
 773            case 45:
 774                s->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
 775                break;
 776            case 46:
 777                s->t_attrib.bgcol = QEMU_COLOR_CYAN;
 778                break;
 779            case 47:
 780                s->t_attrib.bgcol = QEMU_COLOR_WHITE;
 781                break;
 782        }
 783    }
 784}
 785
 786static void console_clear_xy(QemuConsole *s, int x, int y)
 787{
 788    int y1 = (s->y_base + y) % s->total_height;
 789    TextCell *c = &s->cells[y1 * s->width + x];
 790    c->ch = ' ';
 791    c->t_attrib = s->t_attrib_default;
 792    update_xy(s, x, y);
 793}
 794
 795static void console_put_one(QemuConsole *s, int ch)
 796{
 797    TextCell *c;
 798    int y1;
 799    if (s->x >= s->width) {
 800        /* line wrap */
 801        s->x = 0;
 802        console_put_lf(s);
 803    }
 804    y1 = (s->y_base + s->y) % s->total_height;
 805    c = &s->cells[y1 * s->width + s->x];
 806    c->ch = ch;
 807    c->t_attrib = s->t_attrib;
 808    update_xy(s, s->x, s->y);
 809    s->x++;
 810}
 811
 812static void console_respond_str(QemuConsole *s, const char *buf)
 813{
 814    while (*buf) {
 815        console_put_one(s, *buf);
 816        buf++;
 817    }
 818}
 819
 820/* set cursor, checking bounds */
 821static void set_cursor(QemuConsole *s, int x, int y)
 822{
 823    if (x < 0) {
 824        x = 0;
 825    }
 826    if (y < 0) {
 827        y = 0;
 828    }
 829    if (y >= s->height) {
 830        y = s->height - 1;
 831    }
 832    if (x >= s->width) {
 833        x = s->width - 1;
 834    }
 835
 836    s->x = x;
 837    s->y = y;
 838}
 839
 840static void console_putchar(QemuConsole *s, int ch)
 841{
 842    int i;
 843    int x, y;
 844    char response[40];
 845
 846    switch(s->state) {
 847    case TTY_STATE_NORM:
 848        switch(ch) {
 849        case '\r':  /* carriage return */
 850            s->x = 0;
 851            break;
 852        case '\n':  /* newline */
 853            console_put_lf(s);
 854            break;
 855        case '\b':  /* backspace */
 856            if (s->x > 0)
 857                s->x--;
 858            break;
 859        case '\t':  /* tabspace */
 860            if (s->x + (8 - (s->x % 8)) > s->width) {
 861                s->x = 0;
 862                console_put_lf(s);
 863            } else {
 864                s->x = s->x + (8 - (s->x % 8));
 865            }
 866            break;
 867        case '\a':  /* alert aka. bell */
 868            /* TODO: has to be implemented */
 869            break;
 870        case 14:
 871            /* SI (shift in), character set 0 (ignored) */
 872            break;
 873        case 15:
 874            /* SO (shift out), character set 1 (ignored) */
 875            break;
 876        case 27:    /* esc (introducing an escape sequence) */
 877            s->state = TTY_STATE_ESC;
 878            break;
 879        default:
 880            console_put_one(s, ch);
 881            break;
 882        }
 883        break;
 884    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
 885        if (ch == '[') {
 886            for(i=0;i<MAX_ESC_PARAMS;i++)
 887                s->esc_params[i] = 0;
 888            s->nb_esc_params = 0;
 889            s->state = TTY_STATE_CSI;
 890        } else {
 891            s->state = TTY_STATE_NORM;
 892        }
 893        break;
 894    case TTY_STATE_CSI: /* handle escape sequence parameters */
 895        if (ch >= '0' && ch <= '9') {
 896            if (s->nb_esc_params < MAX_ESC_PARAMS) {
 897                int *param = &s->esc_params[s->nb_esc_params];
 898                int digit = (ch - '0');
 899
 900                *param = (*param <= (INT_MAX - digit) / 10) ?
 901                         *param * 10 + digit : INT_MAX;
 902            }
 903        } else {
 904            if (s->nb_esc_params < MAX_ESC_PARAMS)
 905                s->nb_esc_params++;
 906            if (ch == ';' || ch == '?') {
 907                break;
 908            }
 909            trace_console_putchar_csi(s->esc_params[0], s->esc_params[1],
 910                                      ch, s->nb_esc_params);
 911            s->state = TTY_STATE_NORM;
 912            switch(ch) {
 913            case 'A':
 914                /* move cursor up */
 915                if (s->esc_params[0] == 0) {
 916                    s->esc_params[0] = 1;
 917                }
 918                set_cursor(s, s->x, s->y - s->esc_params[0]);
 919                break;
 920            case 'B':
 921                /* move cursor down */
 922                if (s->esc_params[0] == 0) {
 923                    s->esc_params[0] = 1;
 924                }
 925                set_cursor(s, s->x, s->y + s->esc_params[0]);
 926                break;
 927            case 'C':
 928                /* move cursor right */
 929                if (s->esc_params[0] == 0) {
 930                    s->esc_params[0] = 1;
 931                }
 932                set_cursor(s, s->x + s->esc_params[0], s->y);
 933                break;
 934            case 'D':
 935                /* move cursor left */
 936                if (s->esc_params[0] == 0) {
 937                    s->esc_params[0] = 1;
 938                }
 939                set_cursor(s, s->x - s->esc_params[0], s->y);
 940                break;
 941            case 'G':
 942                /* move cursor to column */
 943                set_cursor(s, s->esc_params[0] - 1, s->y);
 944                break;
 945            case 'f':
 946            case 'H':
 947                /* move cursor to row, column */
 948                set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
 949                break;
 950            case 'J':
 951                switch (s->esc_params[0]) {
 952                case 0:
 953                    /* clear to end of screen */
 954                    for (y = s->y; y < s->height; y++) {
 955                        for (x = 0; x < s->width; x++) {
 956                            if (y == s->y && x < s->x) {
 957                                continue;
 958                            }
 959                            console_clear_xy(s, x, y);
 960                        }
 961                    }
 962                    break;
 963                case 1:
 964                    /* clear from beginning of screen */
 965                    for (y = 0; y <= s->y; y++) {
 966                        for (x = 0; x < s->width; x++) {
 967                            if (y == s->y && x > s->x) {
 968                                break;
 969                            }
 970                            console_clear_xy(s, x, y);
 971                        }
 972                    }
 973                    break;
 974                case 2:
 975                    /* clear entire screen */
 976                    for (y = 0; y <= s->height; y++) {
 977                        for (x = 0; x < s->width; x++) {
 978                            console_clear_xy(s, x, y);
 979                        }
 980                    }
 981                    break;
 982                }
 983                break;
 984            case 'K':
 985                switch (s->esc_params[0]) {
 986                case 0:
 987                    /* clear to eol */
 988                    for(x = s->x; x < s->width; x++) {
 989                        console_clear_xy(s, x, s->y);
 990                    }
 991                    break;
 992                case 1:
 993                    /* clear from beginning of line */
 994                    for (x = 0; x <= s->x; x++) {
 995                        console_clear_xy(s, x, s->y);
 996                    }
 997                    break;
 998                case 2:
 999                    /* clear entire line */
1000                    for(x = 0; x < s->width; x++) {
1001                        console_clear_xy(s, x, s->y);
1002                    }
1003                    break;
1004                }
1005                break;
1006            case 'm':
1007                console_handle_escape(s);
1008                break;
1009            case 'n':
1010                switch (s->esc_params[0]) {
1011                case 5:
1012                    /* report console status (always succeed)*/
1013                    console_respond_str(s, "\033[0n");
1014                    break;
1015                case 6:
1016                    /* report cursor position */
1017                    sprintf(response, "\033[%d;%dR",
1018                           (s->y_base + s->y) % s->total_height + 1,
1019                            s->x + 1);
1020                    console_respond_str(s, response);
1021                    break;
1022                }
1023                break;
1024            case 's':
1025                /* save cursor position */
1026                s->x_saved = s->x;
1027                s->y_saved = s->y;
1028                break;
1029            case 'u':
1030                /* restore cursor position */
1031                s->x = s->x_saved;
1032                s->y = s->y_saved;
1033                break;
1034            default:
1035                trace_console_putchar_unhandled(ch);
1036                break;
1037            }
1038            break;
1039        }
1040    }
1041}
1042
1043void console_select(unsigned int index)
1044{
1045    DisplayChangeListener *dcl;
1046    QemuConsole *s;
1047
1048    trace_console_select(index);
1049    s = qemu_console_lookup_by_index(index);
1050    if (s) {
1051        DisplayState *ds = s->ds;
1052
1053        active_console = s;
1054        if (ds->have_gfx) {
1055            QLIST_FOREACH(dcl, &ds->listeners, next) {
1056                if (dcl->con != NULL) {
1057                    continue;
1058                }
1059                if (dcl->ops->dpy_gfx_switch) {
1060                    dcl->ops->dpy_gfx_switch(dcl, s->surface);
1061                }
1062            }
1063            if (s->surface) {
1064                dpy_gfx_update(s, 0, 0, surface_width(s->surface),
1065                               surface_height(s->surface));
1066            }
1067        }
1068        if (ds->have_text) {
1069            dpy_text_resize(s, s->width, s->height);
1070        }
1071        text_console_update_cursor(NULL);
1072    }
1073}
1074
1075typedef struct VCChardev {
1076    Chardev parent;
1077    QemuConsole *console;
1078} VCChardev;
1079
1080#define TYPE_CHARDEV_VC "chardev-vc"
1081#define VC_CHARDEV(obj) OBJECT_CHECK(VCChardev, (obj), TYPE_CHARDEV_VC)
1082
1083static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
1084{
1085    VCChardev *drv = VC_CHARDEV(chr);
1086    QemuConsole *s = drv->console;
1087    int i;
1088
1089    if (!s->ds) {
1090        return 0;
1091    }
1092
1093    s->update_x0 = s->width * FONT_WIDTH;
1094    s->update_y0 = s->height * FONT_HEIGHT;
1095    s->update_x1 = 0;
1096    s->update_y1 = 0;
1097    console_show_cursor(s, 0);
1098    for(i = 0; i < len; i++) {
1099        console_putchar(s, buf[i]);
1100    }
1101    console_show_cursor(s, 1);
1102    if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
1103        dpy_gfx_update(s, s->update_x0, s->update_y0,
1104                       s->update_x1 - s->update_x0,
1105                       s->update_y1 - s->update_y0);
1106    }
1107    return len;
1108}
1109
1110static void kbd_send_chars(void *opaque)
1111{
1112    QemuConsole *s = opaque;
1113    int len;
1114    uint8_t buf[16];
1115
1116    len = qemu_chr_be_can_write(s->chr);
1117    if (len > s->out_fifo.count)
1118        len = s->out_fifo.count;
1119    if (len > 0) {
1120        if (len > sizeof(buf))
1121            len = sizeof(buf);
1122        qemu_fifo_read(&s->out_fifo, buf, len);
1123        qemu_chr_be_write(s->chr, buf, len);
1124    }
1125    /* characters are pending: we send them a bit later (XXX:
1126       horrible, should change char device API) */
1127    if (s->out_fifo.count > 0) {
1128        timer_mod(s->kbd_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1);
1129    }
1130}
1131
1132/* called when an ascii key is pressed */
1133void kbd_put_keysym_console(QemuConsole *s, int keysym)
1134{
1135    uint8_t buf[16], *q;
1136    CharBackend *be;
1137    int c;
1138
1139    if (!s || (s->console_type == GRAPHIC_CONSOLE))
1140        return;
1141
1142    switch(keysym) {
1143    case QEMU_KEY_CTRL_UP:
1144        console_scroll(s, -1);
1145        break;
1146    case QEMU_KEY_CTRL_DOWN:
1147        console_scroll(s, 1);
1148        break;
1149    case QEMU_KEY_CTRL_PAGEUP:
1150        console_scroll(s, -10);
1151        break;
1152    case QEMU_KEY_CTRL_PAGEDOWN:
1153        console_scroll(s, 10);
1154        break;
1155    default:
1156        /* convert the QEMU keysym to VT100 key string */
1157        q = buf;
1158        if (keysym >= 0xe100 && keysym <= 0xe11f) {
1159            *q++ = '\033';
1160            *q++ = '[';
1161            c = keysym - 0xe100;
1162            if (c >= 10)
1163                *q++ = '0' + (c / 10);
1164            *q++ = '0' + (c % 10);
1165            *q++ = '~';
1166        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1167            *q++ = '\033';
1168            *q++ = '[';
1169            *q++ = keysym & 0xff;
1170        } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1171            vc_chr_write(s->chr, (const uint8_t *) "\r", 1);
1172            *q++ = '\n';
1173        } else {
1174            *q++ = keysym;
1175        }
1176        if (s->echo) {
1177            vc_chr_write(s->chr, buf, q - buf);
1178        }
1179        be = s->chr->be;
1180        if (be && be->chr_read) {
1181            qemu_fifo_write(&s->out_fifo, buf, q - buf);
1182            kbd_send_chars(s);
1183        }
1184        break;
1185    }
1186}
1187
1188static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
1189    [Q_KEY_CODE_UP]     = QEMU_KEY_UP,
1190    [Q_KEY_CODE_DOWN]   = QEMU_KEY_DOWN,
1191    [Q_KEY_CODE_RIGHT]  = QEMU_KEY_RIGHT,
1192    [Q_KEY_CODE_LEFT]   = QEMU_KEY_LEFT,
1193    [Q_KEY_CODE_HOME]   = QEMU_KEY_HOME,
1194    [Q_KEY_CODE_END]    = QEMU_KEY_END,
1195    [Q_KEY_CODE_PGUP]   = QEMU_KEY_PAGEUP,
1196    [Q_KEY_CODE_PGDN]   = QEMU_KEY_PAGEDOWN,
1197    [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
1198    [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE,
1199};
1200
1201static const int ctrl_qcode_to_keysym[Q_KEY_CODE__MAX] = {
1202    [Q_KEY_CODE_UP]     = QEMU_KEY_CTRL_UP,
1203    [Q_KEY_CODE_DOWN]   = QEMU_KEY_CTRL_DOWN,
1204    [Q_KEY_CODE_RIGHT]  = QEMU_KEY_CTRL_RIGHT,
1205    [Q_KEY_CODE_LEFT]   = QEMU_KEY_CTRL_LEFT,
1206    [Q_KEY_CODE_HOME]   = QEMU_KEY_CTRL_HOME,
1207    [Q_KEY_CODE_END]    = QEMU_KEY_CTRL_END,
1208    [Q_KEY_CODE_PGUP]   = QEMU_KEY_CTRL_PAGEUP,
1209    [Q_KEY_CODE_PGDN]   = QEMU_KEY_CTRL_PAGEDOWN,
1210};
1211
1212bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl)
1213{
1214    int keysym;
1215
1216    keysym = ctrl ? ctrl_qcode_to_keysym[qcode] : qcode_to_keysym[qcode];
1217    if (keysym == 0) {
1218        return false;
1219    }
1220    kbd_put_keysym_console(s, keysym);
1221    return true;
1222}
1223
1224void kbd_put_string_console(QemuConsole *s, const char *str, int len)
1225{
1226    int i;
1227
1228    for (i = 0; i < len && str[i]; i++) {
1229        kbd_put_keysym_console(s, str[i]);
1230    }
1231}
1232
1233void kbd_put_keysym(int keysym)
1234{
1235    kbd_put_keysym_console(active_console, keysym);
1236}
1237
1238static void text_console_invalidate(void *opaque)
1239{
1240    QemuConsole *s = (QemuConsole *) opaque;
1241
1242    if (s->ds->have_text && s->console_type == TEXT_CONSOLE) {
1243        text_console_resize(s);
1244    }
1245    console_refresh(s);
1246}
1247
1248static void text_console_update(void *opaque, console_ch_t *chardata)
1249{
1250    QemuConsole *s = (QemuConsole *) opaque;
1251    int i, j, src;
1252
1253    if (s->text_x[0] <= s->text_x[1]) {
1254        src = (s->y_base + s->text_y[0]) * s->width;
1255        chardata += s->text_y[0] * s->width;
1256        for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1257            for (j = 0; j < s->width; j++, src++) {
1258                console_write_ch(chardata ++,
1259                                 ATTR2CHTYPE(s->cells[src].ch,
1260                                             s->cells[src].t_attrib.fgcol,
1261                                             s->cells[src].t_attrib.bgcol,
1262                                             s->cells[src].t_attrib.bold));
1263            }
1264        dpy_text_update(s, s->text_x[0], s->text_y[0],
1265                        s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1266        s->text_x[0] = s->width;
1267        s->text_y[0] = s->height;
1268        s->text_x[1] = 0;
1269        s->text_y[1] = 0;
1270    }
1271    if (s->cursor_invalidate) {
1272        dpy_text_cursor(s, s->x, s->y);
1273        s->cursor_invalidate = 0;
1274    }
1275}
1276
1277static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
1278                                uint32_t head)
1279{
1280    Object *obj;
1281    QemuConsole *s;
1282    int i;
1283
1284    obj = object_new(TYPE_QEMU_CONSOLE);
1285    s = QEMU_CONSOLE(obj);
1286    s->head = head;
1287    object_property_add_link(obj, "device", TYPE_DEVICE,
1288                             (Object **)&s->device,
1289                             object_property_allow_set_link,
1290                             OBJ_PROP_LINK_STRONG,
1291                             &error_abort);
1292    object_property_add_uint32_ptr(obj, "head",
1293                                   &s->head, &error_abort);
1294
1295    if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1296        (console_type == GRAPHIC_CONSOLE))) {
1297        active_console = s;
1298    }
1299    s->ds = ds;
1300    s->console_type = console_type;
1301
1302    if (QTAILQ_EMPTY(&consoles)) {
1303        s->index = 0;
1304        QTAILQ_INSERT_TAIL(&consoles, s, next);
1305    } else if (console_type != GRAPHIC_CONSOLE || qdev_hotplug) {
1306        QemuConsole *last = QTAILQ_LAST(&consoles, consoles_head);
1307        s->index = last->index + 1;
1308        QTAILQ_INSERT_TAIL(&consoles, s, next);
1309    } else {
1310        /*
1311         * HACK: Put graphical consoles before text consoles.
1312         *
1313         * Only do that for coldplugged devices.  After initial device
1314         * initialization we will not renumber the consoles any more.
1315         */
1316        QemuConsole *c = QTAILQ_FIRST(&consoles);
1317
1318        while (QTAILQ_NEXT(c, next) != NULL &&
1319               c->console_type == GRAPHIC_CONSOLE) {
1320            c = QTAILQ_NEXT(c, next);
1321        }
1322        if (c->console_type == GRAPHIC_CONSOLE) {
1323            /* have no text consoles */
1324            s->index = c->index + 1;
1325            QTAILQ_INSERT_AFTER(&consoles, c, s, next);
1326        } else {
1327            s->index = c->index;
1328            QTAILQ_INSERT_BEFORE(c, s, next);
1329            /* renumber text consoles */
1330            for (i = s->index + 1; c != NULL; c = QTAILQ_NEXT(c, next), i++) {
1331                c->index = i;
1332            }
1333        }
1334    }
1335    return s;
1336}
1337
1338static void qemu_alloc_display(DisplaySurface *surface, int width, int height)
1339{
1340    qemu_pixman_image_unref(surface->image);
1341    surface->image = NULL;
1342
1343    surface->format = PIXMAN_x8r8g8b8;
1344    surface->image = pixman_image_create_bits(surface->format,
1345                                              width, height,
1346                                              NULL, width * 4);
1347    assert(surface->image != NULL);
1348
1349    surface->flags = QEMU_ALLOCATED_FLAG;
1350}
1351
1352DisplaySurface *qemu_create_displaysurface(int width, int height)
1353{
1354    DisplaySurface *surface = g_new0(DisplaySurface, 1);
1355
1356    trace_displaysurface_create(surface, width, height);
1357    qemu_alloc_display(surface, width, height);
1358    return surface;
1359}
1360
1361DisplaySurface *qemu_create_displaysurface_from(int width, int height,
1362                                                pixman_format_code_t format,
1363                                                int linesize, uint8_t *data)
1364{
1365    DisplaySurface *surface = g_new0(DisplaySurface, 1);
1366
1367    trace_displaysurface_create_from(surface, width, height, format);
1368    surface->format = format;
1369    surface->image = pixman_image_create_bits(surface->format,
1370                                              width, height,
1371                                              (void *)data, linesize);
1372    assert(surface->image != NULL);
1373
1374    return surface;
1375}
1376
1377DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
1378{
1379    DisplaySurface *surface = g_new0(DisplaySurface, 1);
1380
1381    trace_displaysurface_create_pixman(surface);
1382    surface->format = pixman_image_get_format(image);
1383    surface->image = pixman_image_ref(image);
1384
1385    return surface;
1386}
1387
1388static void qemu_unmap_displaysurface_guestmem(pixman_image_t *image,
1389                                               void *unused)
1390{
1391    void *data = pixman_image_get_data(image);
1392    uint32_t size = pixman_image_get_stride(image) *
1393        pixman_image_get_height(image);
1394    cpu_physical_memory_unmap(data, size, 0, 0);
1395}
1396
1397DisplaySurface *qemu_create_displaysurface_guestmem(int width, int height,
1398                                                    pixman_format_code_t format,
1399                                                    int linesize, uint64_t addr)
1400{
1401    DisplaySurface *surface;
1402    hwaddr size;
1403    void *data;
1404
1405    if (linesize == 0) {
1406        linesize = width * PIXMAN_FORMAT_BPP(format) / 8;
1407    }
1408
1409    size = (hwaddr)linesize * height;
1410    data = cpu_physical_memory_map(addr, &size, 0);
1411    if (size != (hwaddr)linesize * height) {
1412        cpu_physical_memory_unmap(data, size, 0, 0);
1413        return NULL;
1414    }
1415
1416    surface = qemu_create_displaysurface_from
1417        (width, height, format, linesize, data);
1418    pixman_image_set_destroy_function
1419        (surface->image, qemu_unmap_displaysurface_guestmem, NULL);
1420
1421    return surface;
1422}
1423
1424DisplaySurface *qemu_create_message_surface(int w, int h,
1425                                            const char *msg)
1426{
1427    DisplaySurface *surface = qemu_create_displaysurface(w, h);
1428    pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK];
1429    pixman_color_t fg = color_table_rgb[0][QEMU_COLOR_WHITE];
1430    pixman_image_t *glyph;
1431    int len, x, y, i;
1432
1433    len = strlen(msg);
1434    x = (w / FONT_WIDTH  - len) / 2;
1435    y = (h / FONT_HEIGHT - 1)   / 2;
1436    for (i = 0; i < len; i++) {
1437        glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
1438        qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
1439                                 x+i, y, FONT_WIDTH, FONT_HEIGHT);
1440        qemu_pixman_image_unref(glyph);
1441    }
1442    return surface;
1443}
1444
1445void qemu_free_displaysurface(DisplaySurface *surface)
1446{
1447    if (surface == NULL) {
1448        return;
1449    }
1450    trace_displaysurface_free(surface);
1451    qemu_pixman_image_unref(surface->image);
1452    g_free(surface);
1453}
1454
1455bool console_has_gl(QemuConsole *con)
1456{
1457    return con->gl != NULL;
1458}
1459
1460bool console_has_gl_dmabuf(QemuConsole *con)
1461{
1462    return con->gl != NULL && con->gl->ops->dpy_gl_scanout_dmabuf != NULL;
1463}
1464
1465void register_displaychangelistener(DisplayChangeListener *dcl)
1466{
1467    static const char nodev[] =
1468        "This VM has no graphic display device.";
1469    static DisplaySurface *dummy;
1470    QemuConsole *con;
1471
1472    assert(!dcl->ds);
1473
1474    if (dcl->ops->dpy_gl_ctx_create) {
1475        /* display has opengl support */
1476        assert(dcl->con);
1477        if (dcl->con->gl) {
1478            fprintf(stderr, "can't register two opengl displays (%s, %s)\n",
1479                    dcl->ops->dpy_name, dcl->con->gl->ops->dpy_name);
1480            exit(1);
1481        }
1482        dcl->con->gl = dcl;
1483    }
1484
1485    trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
1486    dcl->ds = get_alloc_displaystate();
1487    QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
1488    gui_setup_refresh(dcl->ds);
1489    if (dcl->con) {
1490        dcl->con->dcls++;
1491        con = dcl->con;
1492    } else {
1493        con = active_console;
1494    }
1495    if (dcl->ops->dpy_gfx_switch) {
1496        if (con) {
1497            dcl->ops->dpy_gfx_switch(dcl, con->surface);
1498        } else {
1499            if (!dummy) {
1500                dummy = qemu_create_message_surface(640, 480, nodev);
1501            }
1502            dcl->ops->dpy_gfx_switch(dcl, dummy);
1503        }
1504    }
1505    text_console_update_cursor(NULL);
1506}
1507
1508void update_displaychangelistener(DisplayChangeListener *dcl,
1509                                  uint64_t interval)
1510{
1511    DisplayState *ds = dcl->ds;
1512
1513    dcl->update_interval = interval;
1514    if (!ds->refreshing && ds->update_interval > interval) {
1515        timer_mod(ds->gui_timer, ds->last_update + interval);
1516    }
1517}
1518
1519void unregister_displaychangelistener(DisplayChangeListener *dcl)
1520{
1521    DisplayState *ds = dcl->ds;
1522    trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
1523    if (dcl->con) {
1524        dcl->con->dcls--;
1525    }
1526    QLIST_REMOVE(dcl, next);
1527    dcl->ds = NULL;
1528    gui_setup_refresh(ds);
1529}
1530
1531static void dpy_set_ui_info_timer(void *opaque)
1532{
1533    QemuConsole *con = opaque;
1534
1535    con->hw_ops->ui_info(con->hw, con->head, &con->ui_info);
1536}
1537
1538bool dpy_ui_info_supported(QemuConsole *con)
1539{
1540    return con->hw_ops->ui_info != NULL;
1541}
1542
1543int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info)
1544{
1545    assert(con != NULL);
1546
1547    if (!dpy_ui_info_supported(con)) {
1548        return -1;
1549    }
1550    if (memcmp(&con->ui_info, info, sizeof(con->ui_info)) == 0) {
1551        /* nothing changed -- ignore */
1552        return 0;
1553    }
1554
1555    /*
1556     * Typically we get a flood of these as the user resizes the window.
1557     * Wait until the dust has settled (one second without updates), then
1558     * go notify the guest.
1559     */
1560    con->ui_info = *info;
1561    timer_mod(con->ui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
1562    return 0;
1563}
1564
1565void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
1566{
1567    DisplayState *s = con->ds;
1568    DisplayChangeListener *dcl;
1569    int width = w;
1570    int height = h;
1571
1572    if (con->surface) {
1573        width = surface_width(con->surface);
1574        height = surface_height(con->surface);
1575    }
1576    x = MAX(x, 0);
1577    y = MAX(y, 0);
1578    x = MIN(x, width);
1579    y = MIN(y, height);
1580    w = MIN(w, width - x);
1581    h = MIN(h, height - y);
1582
1583    if (!qemu_console_is_visible(con)) {
1584        return;
1585    }
1586    QLIST_FOREACH(dcl, &s->listeners, next) {
1587        if (con != (dcl->con ? dcl->con : active_console)) {
1588            continue;
1589        }
1590        if (dcl->ops->dpy_gfx_update) {
1591            dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
1592        }
1593    }
1594}
1595
1596void dpy_gfx_update_full(QemuConsole *con)
1597{
1598    if (!con->surface) {
1599        return;
1600    }
1601    dpy_gfx_update(con, 0, 0,
1602                   surface_width(con->surface),
1603                   surface_height(con->surface));
1604}
1605
1606void dpy_gfx_replace_surface(QemuConsole *con,
1607                             DisplaySurface *surface)
1608{
1609    DisplayState *s = con->ds;
1610    DisplaySurface *old_surface = con->surface;
1611    DisplayChangeListener *dcl;
1612
1613    assert(old_surface != surface || surface == NULL);
1614
1615    con->surface = surface;
1616    QLIST_FOREACH(dcl, &s->listeners, next) {
1617        if (con != (dcl->con ? dcl->con : active_console)) {
1618            continue;
1619        }
1620        if (dcl->ops->dpy_gfx_switch) {
1621            dcl->ops->dpy_gfx_switch(dcl, surface);
1622        }
1623    }
1624    qemu_free_displaysurface(old_surface);
1625}
1626
1627bool dpy_gfx_check_format(QemuConsole *con,
1628                          pixman_format_code_t format)
1629{
1630    DisplayChangeListener *dcl;
1631    DisplayState *s = con->ds;
1632
1633    QLIST_FOREACH(dcl, &s->listeners, next) {
1634        if (dcl->con && dcl->con != con) {
1635            /* dcl bound to another console -> skip */
1636            continue;
1637        }
1638        if (dcl->ops->dpy_gfx_check_format) {
1639            if (!dcl->ops->dpy_gfx_check_format(dcl, format)) {
1640                return false;
1641            }
1642        } else {
1643            /* default is to whitelist native 32 bpp only */
1644            if (format != qemu_default_pixman_format(32, true)) {
1645                return false;
1646            }
1647        }
1648    }
1649    return true;
1650}
1651
1652static void dpy_refresh(DisplayState *s)
1653{
1654    DisplayChangeListener *dcl;
1655
1656    QLIST_FOREACH(dcl, &s->listeners, next) {
1657        if (dcl->ops->dpy_refresh) {
1658            dcl->ops->dpy_refresh(dcl);
1659        }
1660    }
1661}
1662
1663void dpy_text_cursor(QemuConsole *con, int x, int y)
1664{
1665    DisplayState *s = con->ds;
1666    DisplayChangeListener *dcl;
1667
1668    if (!qemu_console_is_visible(con)) {
1669        return;
1670    }
1671    QLIST_FOREACH(dcl, &s->listeners, next) {
1672        if (con != (dcl->con ? dcl->con : active_console)) {
1673            continue;
1674        }
1675        if (dcl->ops->dpy_text_cursor) {
1676            dcl->ops->dpy_text_cursor(dcl, x, y);
1677        }
1678    }
1679}
1680
1681void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
1682{
1683    DisplayState *s = con->ds;
1684    DisplayChangeListener *dcl;
1685
1686    if (!qemu_console_is_visible(con)) {
1687        return;
1688    }
1689    QLIST_FOREACH(dcl, &s->listeners, next) {
1690        if (con != (dcl->con ? dcl->con : active_console)) {
1691            continue;
1692        }
1693        if (dcl->ops->dpy_text_update) {
1694            dcl->ops->dpy_text_update(dcl, x, y, w, h);
1695        }
1696    }
1697}
1698
1699void dpy_text_resize(QemuConsole *con, int w, int h)
1700{
1701    DisplayState *s = con->ds;
1702    DisplayChangeListener *dcl;
1703
1704    if (!qemu_console_is_visible(con)) {
1705        return;
1706    }
1707    QLIST_FOREACH(dcl, &s->listeners, next) {
1708        if (con != (dcl->con ? dcl->con : active_console)) {
1709            continue;
1710        }
1711        if (dcl->ops->dpy_text_resize) {
1712            dcl->ops->dpy_text_resize(dcl, w, h);
1713        }
1714    }
1715}
1716
1717void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
1718{
1719    DisplayState *s = con->ds;
1720    DisplayChangeListener *dcl;
1721
1722    if (!qemu_console_is_visible(con)) {
1723        return;
1724    }
1725    QLIST_FOREACH(dcl, &s->listeners, next) {
1726        if (con != (dcl->con ? dcl->con : active_console)) {
1727            continue;
1728        }
1729        if (dcl->ops->dpy_mouse_set) {
1730            dcl->ops->dpy_mouse_set(dcl, x, y, on);
1731        }
1732    }
1733}
1734
1735void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
1736{
1737    DisplayState *s = con->ds;
1738    DisplayChangeListener *dcl;
1739
1740    if (!qemu_console_is_visible(con)) {
1741        return;
1742    }
1743    QLIST_FOREACH(dcl, &s->listeners, next) {
1744        if (con != (dcl->con ? dcl->con : active_console)) {
1745            continue;
1746        }
1747        if (dcl->ops->dpy_cursor_define) {
1748            dcl->ops->dpy_cursor_define(dcl, cursor);
1749        }
1750    }
1751}
1752
1753bool dpy_cursor_define_supported(QemuConsole *con)
1754{
1755    DisplayState *s = con->ds;
1756    DisplayChangeListener *dcl;
1757
1758    QLIST_FOREACH(dcl, &s->listeners, next) {
1759        if (dcl->ops->dpy_cursor_define) {
1760            return true;
1761        }
1762    }
1763    return false;
1764}
1765
1766QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
1767                                struct QEMUGLParams *qparams)
1768{
1769    assert(con->gl);
1770    return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
1771}
1772
1773void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
1774{
1775    assert(con->gl);
1776    con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
1777}
1778
1779int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
1780{
1781    assert(con->gl);
1782    return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
1783}
1784
1785QEMUGLContext dpy_gl_ctx_get_current(QemuConsole *con)
1786{
1787    assert(con->gl);
1788    return con->gl->ops->dpy_gl_ctx_get_current(con->gl);
1789}
1790
1791void dpy_gl_scanout_disable(QemuConsole *con)
1792{
1793    assert(con->gl);
1794    if (con->gl->ops->dpy_gl_scanout_disable) {
1795        con->gl->ops->dpy_gl_scanout_disable(con->gl);
1796    } else {
1797        con->gl->ops->dpy_gl_scanout_texture(con->gl, 0, false, 0, 0,
1798                                             0, 0, 0, 0);
1799    }
1800}
1801
1802void dpy_gl_scanout_texture(QemuConsole *con,
1803                            uint32_t backing_id,
1804                            bool backing_y_0_top,
1805                            uint32_t backing_width,
1806                            uint32_t backing_height,
1807                            uint32_t x, uint32_t y,
1808                            uint32_t width, uint32_t height)
1809{
1810    assert(con->gl);
1811    con->gl->ops->dpy_gl_scanout_texture(con->gl, backing_id,
1812                                         backing_y_0_top,
1813                                         backing_width, backing_height,
1814                                         x, y, width, height);
1815}
1816
1817void dpy_gl_scanout_dmabuf(QemuConsole *con,
1818                           QemuDmaBuf *dmabuf)
1819{
1820    assert(con->gl);
1821    con->gl->ops->dpy_gl_scanout_dmabuf(con->gl, dmabuf);
1822}
1823
1824void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
1825                          bool have_hot, uint32_t hot_x, uint32_t hot_y)
1826{
1827    assert(con->gl);
1828
1829    if (con->gl->ops->dpy_gl_cursor_dmabuf) {
1830        con->gl->ops->dpy_gl_cursor_dmabuf(con->gl, dmabuf,
1831                                           have_hot, hot_x, hot_y);
1832    }
1833}
1834
1835void dpy_gl_cursor_position(QemuConsole *con,
1836                            uint32_t pos_x, uint32_t pos_y)
1837{
1838    assert(con->gl);
1839
1840    if (con->gl->ops->dpy_gl_cursor_position) {
1841        con->gl->ops->dpy_gl_cursor_position(con->gl, pos_x, pos_y);
1842    }
1843}
1844
1845void dpy_gl_release_dmabuf(QemuConsole *con,
1846                          QemuDmaBuf *dmabuf)
1847{
1848    assert(con->gl);
1849
1850    if (con->gl->ops->dpy_gl_release_dmabuf) {
1851        con->gl->ops->dpy_gl_release_dmabuf(con->gl, dmabuf);
1852    }
1853}
1854
1855void dpy_gl_update(QemuConsole *con,
1856                   uint32_t x, uint32_t y, uint32_t w, uint32_t h)
1857{
1858    assert(con->gl);
1859    con->gl->ops->dpy_gl_update(con->gl, x, y, w, h);
1860}
1861
1862/***********************************************************/
1863/* register display */
1864
1865/* console.c internal use only */
1866static DisplayState *get_alloc_displaystate(void)
1867{
1868    if (!display_state) {
1869        display_state = g_new0(DisplayState, 1);
1870        cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
1871                                    text_console_update_cursor, NULL);
1872    }
1873    return display_state;
1874}
1875
1876/*
1877 * Called by main(), after creating QemuConsoles
1878 * and before initializing ui (sdl/vnc/...).
1879 */
1880DisplayState *init_displaystate(void)
1881{
1882    gchar *name;
1883    QemuConsole *con;
1884
1885    get_alloc_displaystate();
1886    QTAILQ_FOREACH(con, &consoles, next) {
1887        if (con->console_type != GRAPHIC_CONSOLE &&
1888            con->ds == NULL) {
1889            text_console_do_init(con->chr, display_state);
1890        }
1891
1892        /* Hook up into the qom tree here (not in new_console()), once
1893         * all QemuConsoles are created and the order / numbering
1894         * doesn't change any more */
1895        name = g_strdup_printf("console[%d]", con->index);
1896        object_property_add_child(container_get(object_get_root(), "/backend"),
1897                                  name, OBJECT(con), &error_abort);
1898        g_free(name);
1899    }
1900
1901    return display_state;
1902}
1903
1904void graphic_console_set_hwops(QemuConsole *con,
1905                               const GraphicHwOps *hw_ops,
1906                               void *opaque)
1907{
1908    con->hw_ops = hw_ops;
1909    con->hw = opaque;
1910}
1911
1912QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
1913                                  const GraphicHwOps *hw_ops,
1914                                  void *opaque)
1915{
1916    static const char noinit[] =
1917        "Guest has not initialized the display (yet).";
1918    int width = 640;
1919    int height = 480;
1920    QemuConsole *s;
1921    DisplayState *ds;
1922    DisplaySurface *surface;
1923
1924    ds = get_alloc_displaystate();
1925    s = qemu_console_lookup_unused();
1926    if (s) {
1927        trace_console_gfx_reuse(s->index);
1928        if (s->surface) {
1929            width = surface_width(s->surface);
1930            height = surface_height(s->surface);
1931        }
1932    } else {
1933        trace_console_gfx_new();
1934        s = new_console(ds, GRAPHIC_CONSOLE, head);
1935        s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
1936                                   dpy_set_ui_info_timer, s);
1937    }
1938    graphic_console_set_hwops(s, hw_ops, opaque);
1939    if (dev) {
1940        object_property_set_link(OBJECT(s), OBJECT(dev), "device",
1941                                 &error_abort);
1942    }
1943
1944    surface = qemu_create_message_surface(width, height, noinit);
1945    dpy_gfx_replace_surface(s, surface);
1946    return s;
1947}
1948
1949static const GraphicHwOps unused_ops = {
1950    /* no callbacks */
1951};
1952
1953void graphic_console_close(QemuConsole *con)
1954{
1955    static const char unplugged[] =
1956        "Guest display has been unplugged";
1957    DisplaySurface *surface;
1958    int width = 640;
1959    int height = 480;
1960
1961    if (con->surface) {
1962        width = surface_width(con->surface);
1963        height = surface_height(con->surface);
1964    }
1965
1966    trace_console_gfx_close(con->index);
1967    object_property_set_link(OBJECT(con), NULL, "device", &error_abort);
1968    graphic_console_set_hwops(con, &unused_ops, NULL);
1969
1970    if (con->gl) {
1971        dpy_gl_scanout_disable(con);
1972    }
1973    surface = qemu_create_message_surface(width, height, unplugged);
1974    dpy_gfx_replace_surface(con, surface);
1975}
1976
1977QemuConsole *qemu_console_lookup_by_index(unsigned int index)
1978{
1979    QemuConsole *con;
1980
1981    QTAILQ_FOREACH(con, &consoles, next) {
1982        if (con->index == index) {
1983            return con;
1984        }
1985    }
1986    return NULL;
1987}
1988
1989QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
1990{
1991    QemuConsole *con;
1992    Object *obj;
1993    uint32_t h;
1994
1995    QTAILQ_FOREACH(con, &consoles, next) {
1996        obj = object_property_get_link(OBJECT(con),
1997                                       "device", &error_abort);
1998        if (DEVICE(obj) != dev) {
1999            continue;
2000        }
2001        h = object_property_get_uint(OBJECT(con),
2002                                     "head", &error_abort);
2003        if (h != head) {
2004            continue;
2005        }
2006        return con;
2007    }
2008    return NULL;
2009}
2010
2011QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
2012                                                uint32_t head, Error **errp)
2013{
2014    DeviceState *dev;
2015    QemuConsole *con;
2016
2017    dev = qdev_find_recursive(sysbus_get_default(), device_id);
2018    if (dev == NULL) {
2019        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
2020                  "Device '%s' not found", device_id);
2021        return NULL;
2022    }
2023
2024    con = qemu_console_lookup_by_device(dev, head);
2025    if (con == NULL) {
2026        error_setg(errp, "Device %s (head %d) is not bound to a QemuConsole",
2027                   device_id, head);
2028        return NULL;
2029    }
2030
2031    return con;
2032}
2033
2034QemuConsole *qemu_console_lookup_unused(void)
2035{
2036    QemuConsole *con;
2037    Object *obj;
2038
2039    QTAILQ_FOREACH(con, &consoles, next) {
2040        if (con->hw_ops != &unused_ops) {
2041            continue;
2042        }
2043        obj = object_property_get_link(OBJECT(con),
2044                                       "device", &error_abort);
2045        if (obj != NULL) {
2046            continue;
2047        }
2048        return con;
2049    }
2050    return NULL;
2051}
2052
2053bool qemu_console_is_visible(QemuConsole *con)
2054{
2055    return (con == active_console) || (con->dcls > 0);
2056}
2057
2058bool qemu_console_is_graphic(QemuConsole *con)
2059{
2060    if (con == NULL) {
2061        con = active_console;
2062    }
2063    return con && (con->console_type == GRAPHIC_CONSOLE);
2064}
2065
2066bool qemu_console_is_fixedsize(QemuConsole *con)
2067{
2068    if (con == NULL) {
2069        con = active_console;
2070    }
2071    return con && (con->console_type != TEXT_CONSOLE);
2072}
2073
2074bool qemu_console_is_gl_blocked(QemuConsole *con)
2075{
2076    assert(con != NULL);
2077    return con->gl_block;
2078}
2079
2080char *qemu_console_get_label(QemuConsole *con)
2081{
2082    if (con->console_type == GRAPHIC_CONSOLE) {
2083        if (con->device) {
2084            return g_strdup(object_get_typename(con->device));
2085        }
2086        return g_strdup("VGA");
2087    } else {
2088        if (con->chr && con->chr->label) {
2089            return g_strdup(con->chr->label);
2090        }
2091        return g_strdup_printf("vc%d", con->index);
2092    }
2093}
2094
2095int qemu_console_get_index(QemuConsole *con)
2096{
2097    if (con == NULL) {
2098        con = active_console;
2099    }
2100    return con ? con->index : -1;
2101}
2102
2103uint32_t qemu_console_get_head(QemuConsole *con)
2104{
2105    if (con == NULL) {
2106        con = active_console;
2107    }
2108    return con ? con->head : -1;
2109}
2110
2111QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con)
2112{
2113    assert(con != NULL);
2114    return &con->ui_info;
2115}
2116
2117int qemu_console_get_width(QemuConsole *con, int fallback)
2118{
2119    if (con == NULL) {
2120        con = active_console;
2121    }
2122    return con ? surface_width(con->surface) : fallback;
2123}
2124
2125int qemu_console_get_height(QemuConsole *con, int fallback)
2126{
2127    if (con == NULL) {
2128        con = active_console;
2129    }
2130    return con ? surface_height(con->surface) : fallback;
2131}
2132
2133static void vc_chr_set_echo(Chardev *chr, bool echo)
2134{
2135    VCChardev *drv = VC_CHARDEV(chr);
2136    QemuConsole *s = drv->console;
2137
2138    s->echo = echo;
2139}
2140
2141static void text_console_update_cursor_timer(void)
2142{
2143    timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
2144              + CONSOLE_CURSOR_PERIOD / 2);
2145}
2146
2147static void text_console_update_cursor(void *opaque)
2148{
2149    QemuConsole *s;
2150    int count = 0;
2151
2152    cursor_visible_phase = !cursor_visible_phase;
2153
2154    QTAILQ_FOREACH(s, &consoles, next) {
2155        if (qemu_console_is_graphic(s) ||
2156            !qemu_console_is_visible(s)) {
2157            continue;
2158        }
2159        count++;
2160        graphic_hw_invalidate(s);
2161    }
2162
2163    if (count) {
2164        text_console_update_cursor_timer();
2165    }
2166}
2167
2168static const GraphicHwOps text_console_ops = {
2169    .invalidate  = text_console_invalidate,
2170    .text_update = text_console_update,
2171};
2172
2173static void text_console_do_init(Chardev *chr, DisplayState *ds)
2174{
2175    VCChardev *drv = VC_CHARDEV(chr);
2176    QemuConsole *s = drv->console;
2177    int g_width = 80 * FONT_WIDTH;
2178    int g_height = 24 * FONT_HEIGHT;
2179
2180    s->out_fifo.buf = s->out_fifo_buf;
2181    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
2182    s->kbd_timer = timer_new_ms(QEMU_CLOCK_REALTIME, kbd_send_chars, s);
2183    s->ds = ds;
2184
2185    s->y_displayed = 0;
2186    s->y_base = 0;
2187    s->total_height = DEFAULT_BACKSCROLL;
2188    s->x = 0;
2189    s->y = 0;
2190    if (!s->surface) {
2191        if (active_console && active_console->surface) {
2192            g_width = surface_width(active_console->surface);
2193            g_height = surface_height(active_console->surface);
2194        }
2195        s->surface = qemu_create_displaysurface(g_width, g_height);
2196    }
2197
2198    s->hw_ops = &text_console_ops;
2199    s->hw = s;
2200
2201    /* Set text attribute defaults */
2202    s->t_attrib_default.bold = 0;
2203    s->t_attrib_default.uline = 0;
2204    s->t_attrib_default.blink = 0;
2205    s->t_attrib_default.invers = 0;
2206    s->t_attrib_default.unvisible = 0;
2207    s->t_attrib_default.fgcol = QEMU_COLOR_WHITE;
2208    s->t_attrib_default.bgcol = QEMU_COLOR_BLACK;
2209    /* set current text attributes to default */
2210    s->t_attrib = s->t_attrib_default;
2211    text_console_resize(s);
2212
2213    if (chr->label) {
2214        char msg[128];
2215        int len;
2216
2217        s->t_attrib.bgcol = QEMU_COLOR_BLUE;
2218        len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
2219        vc_chr_write(chr, (uint8_t *)msg, len);
2220        s->t_attrib = s->t_attrib_default;
2221    }
2222
2223    qemu_chr_be_event(chr, CHR_EVENT_OPENED);
2224}
2225
2226static void vc_chr_open(Chardev *chr,
2227                        ChardevBackend *backend,
2228                        bool *be_opened,
2229                        Error **errp)
2230{
2231    ChardevVC *vc = backend->u.vc.data;
2232    VCChardev *drv = VC_CHARDEV(chr);
2233    QemuConsole *s;
2234    unsigned width = 0;
2235    unsigned height = 0;
2236
2237    if (vc->has_width) {
2238        width = vc->width;
2239    } else if (vc->has_cols) {
2240        width = vc->cols * FONT_WIDTH;
2241    }
2242
2243    if (vc->has_height) {
2244        height = vc->height;
2245    } else if (vc->has_rows) {
2246        height = vc->rows * FONT_HEIGHT;
2247    }
2248
2249    trace_console_txt_new(width, height);
2250    if (width == 0 || height == 0) {
2251        s = new_console(NULL, TEXT_CONSOLE, 0);
2252    } else {
2253        s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
2254        s->surface = qemu_create_displaysurface(width, height);
2255    }
2256
2257    if (!s) {
2258        error_setg(errp, "cannot create text console");
2259        return;
2260    }
2261
2262    s->chr = chr;
2263    drv->console = s;
2264
2265    if (display_state) {
2266        text_console_do_init(chr, display_state);
2267    }
2268
2269    /* console/chardev init sometimes completes elsewhere in a 2nd
2270     * stage, so defer OPENED events until they are fully initialized
2271     */
2272    *be_opened = false;
2273}
2274
2275void qemu_console_resize(QemuConsole *s, int width, int height)
2276{
2277    DisplaySurface *surface;
2278
2279    assert(s->console_type == GRAPHIC_CONSOLE);
2280
2281    if (s->surface && (s->surface->flags & QEMU_ALLOCATED_FLAG) &&
2282        pixman_image_get_width(s->surface->image) == width &&
2283        pixman_image_get_height(s->surface->image) == height) {
2284        return;
2285    }
2286
2287    surface = qemu_create_displaysurface(width, height);
2288    dpy_gfx_replace_surface(s, surface);
2289}
2290
2291DisplaySurface *qemu_console_surface(QemuConsole *console)
2292{
2293    return console->surface;
2294}
2295
2296PixelFormat qemu_default_pixelformat(int bpp)
2297{
2298    pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
2299    PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
2300    return pf;
2301}
2302
2303static QemuDisplay *dpys[DISPLAY_TYPE__MAX];
2304
2305void qemu_display_register(QemuDisplay *ui)
2306{
2307    assert(ui->type < DISPLAY_TYPE__MAX);
2308    dpys[ui->type] = ui;
2309}
2310
2311bool qemu_display_find_default(DisplayOptions *opts)
2312{
2313    static DisplayType prio[] = {
2314        DISPLAY_TYPE_GTK,
2315        DISPLAY_TYPE_SDL,
2316        DISPLAY_TYPE_COCOA
2317    };
2318    int i;
2319
2320    for (i = 0; i < ARRAY_SIZE(prio); i++) {
2321        if (dpys[prio[i]] == NULL) {
2322            ui_module_load_one(DisplayType_str(prio[i]));
2323        }
2324        if (dpys[prio[i]] == NULL) {
2325            continue;
2326        }
2327        opts->type = prio[i];
2328        return true;
2329    }
2330    return false;
2331}
2332
2333void qemu_display_early_init(DisplayOptions *opts)
2334{
2335    assert(opts->type < DISPLAY_TYPE__MAX);
2336    if (opts->type == DISPLAY_TYPE_NONE) {
2337        return;
2338    }
2339    if (dpys[opts->type] == NULL) {
2340        ui_module_load_one(DisplayType_str(opts->type));
2341    }
2342    if (dpys[opts->type] == NULL) {
2343        error_report("Display '%s' is not available.",
2344                     DisplayType_str(opts->type));
2345        exit(1);
2346    }
2347    if (dpys[opts->type]->early_init) {
2348        dpys[opts->type]->early_init(opts);
2349    }
2350}
2351
2352void qemu_display_init(DisplayState *ds, DisplayOptions *opts)
2353{
2354    assert(opts->type < DISPLAY_TYPE__MAX);
2355    if (opts->type == DISPLAY_TYPE_NONE) {
2356        return;
2357    }
2358    assert(dpys[opts->type] != NULL);
2359    dpys[opts->type]->init(ds, opts);
2360}
2361
2362void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp)
2363{
2364    int val;
2365    ChardevVC *vc;
2366
2367    backend->type = CHARDEV_BACKEND_KIND_VC;
2368    vc = backend->u.vc.data = g_new0(ChardevVC, 1);
2369    qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc));
2370
2371    val = qemu_opt_get_number(opts, "width", 0);
2372    if (val != 0) {
2373        vc->has_width = true;
2374        vc->width = val;
2375    }
2376
2377    val = qemu_opt_get_number(opts, "height", 0);
2378    if (val != 0) {
2379        vc->has_height = true;
2380        vc->height = val;
2381    }
2382
2383    val = qemu_opt_get_number(opts, "cols", 0);
2384    if (val != 0) {
2385        vc->has_cols = true;
2386        vc->cols = val;
2387    }
2388
2389    val = qemu_opt_get_number(opts, "rows", 0);
2390    if (val != 0) {
2391        vc->has_rows = true;
2392        vc->rows = val;
2393    }
2394}
2395
2396static const TypeInfo qemu_console_info = {
2397    .name = TYPE_QEMU_CONSOLE,
2398    .parent = TYPE_OBJECT,
2399    .instance_size = sizeof(QemuConsole),
2400    .class_size = sizeof(QemuConsoleClass),
2401};
2402
2403static void char_vc_class_init(ObjectClass *oc, void *data)
2404{
2405    ChardevClass *cc = CHARDEV_CLASS(oc);
2406
2407    cc->parse = qemu_chr_parse_vc;
2408    cc->open = vc_chr_open;
2409    cc->chr_write = vc_chr_write;
2410    cc->chr_set_echo = vc_chr_set_echo;
2411}
2412
2413static const TypeInfo char_vc_type_info = {
2414    .name = TYPE_CHARDEV_VC,
2415    .parent = TYPE_CHARDEV,
2416    .instance_size = sizeof(VCChardev),
2417    .class_init = char_vc_class_init,
2418};
2419
2420void qemu_console_early_init(void)
2421{
2422    /* set the default vc driver */
2423    if (!object_class_by_name(TYPE_CHARDEV_VC)) {
2424        type_register(&char_vc_type_info);
2425    }
2426}
2427
2428static void register_types(void)
2429{
2430    type_register_static(&qemu_console_info);
2431}
2432
2433type_init(register_types);
2434