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