#include "ui/console.h"
#include "qemu/timer.h"
#include "qmp-commands.h"
-#include "char/char.h"
+#include "sysemu/char.h"
//#define DEBUG_CONSOLE
#define DEFAULT_BACKSCROLL 512
#define MAX_CONSOLES 12
#define CONSOLE_CURSOR_PERIOD 500
-#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
-#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
-
typedef struct TextAttributes {
uint8_t fgcol:4;
uint8_t bgcol:4;
int index;
console_type_t console_type;
DisplayState *ds;
+ DisplaySurface *surface;
/* Graphic console state. */
- vga_hw_update_ptr hw_update;
- vga_hw_invalidate_ptr hw_invalidate;
- vga_hw_screen_dump_ptr hw_screen_dump;
- vga_hw_text_update_ptr hw_text_update;
+ const GraphicHwOps *hw_ops;
void *hw;
- int g_width, g_height;
/* Text console state */
int width;
QEMUTimer *kbd_timer;
};
+struct DisplayState {
+ struct QEMUTimer *gui_timer;
+ uint64_t last_update;
+ uint64_t update_interval;
+ bool refreshing;
+ bool have_gfx;
+ bool have_text;
+
+ QLIST_HEAD(, DisplayChangeListener) listeners;
+};
+
static DisplayState *display_state;
static QemuConsole *active_console;
static QemuConsole *consoles[MAX_CONSOLES];
static int nb_consoles = 0;
-void vga_hw_update(void)
-{
- if (active_console && active_console->hw_update)
- active_console->hw_update(active_console->hw);
-}
+static void text_console_do_init(CharDriverState *chr, DisplayState *ds);
+static void dpy_gfx_switch_surface(DisplayState *ds,
+ DisplaySurface *surface);
+static void dpy_refresh(DisplayState *s);
-void vga_hw_invalidate(void)
+static void gui_update(void *opaque)
{
- if (active_console && active_console->hw_invalidate)
- active_console->hw_invalidate(active_console->hw);
+ uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
+ uint64_t dcl_interval;
+ DisplayState *ds = opaque;
+ DisplayChangeListener *dcl;
+ int i;
+
+ ds->refreshing = true;
+ dpy_refresh(ds);
+ ds->refreshing = false;
+
+ QLIST_FOREACH(dcl, &ds->listeners, next) {
+ dcl_interval = dcl->update_interval ?
+ dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
+ if (interval > dcl_interval) {
+ interval = dcl_interval;
+ }
+ }
+ if (ds->update_interval != interval) {
+ ds->update_interval = interval;
+ for (i = 0; i < nb_consoles; i++) {
+ if (consoles[i]->hw_ops->update_interval) {
+ consoles[i]->hw_ops->update_interval(consoles[i]->hw, interval);
+ }
+ }
+ trace_console_refresh(interval);
+ }
+ ds->last_update = qemu_get_clock_ms(rt_clock);
+ qemu_mod_timer(ds->gui_timer, ds->last_update + interval);
}
-void qmp_screendump(const char *filename, Error **errp)
+static void gui_setup_refresh(DisplayState *ds)
{
- QemuConsole *previous_active_console;
- bool cswitch;
+ DisplayChangeListener *dcl;
+ bool need_timer = false;
+ bool have_gfx = false;
+ bool have_text = false;
+
+ QLIST_FOREACH(dcl, &ds->listeners, next) {
+ if (dcl->ops->dpy_refresh != NULL) {
+ need_timer = true;
+ }
+ if (dcl->ops->dpy_gfx_update != NULL) {
+ have_gfx = true;
+ }
+ if (dcl->ops->dpy_text_update != NULL) {
+ have_text = true;
+ }
+ }
- previous_active_console = active_console;
- cswitch = previous_active_console && previous_active_console->index != 0;
+ if (need_timer && ds->gui_timer == NULL) {
+ ds->gui_timer = qemu_new_timer_ms(rt_clock, gui_update, ds);
+ qemu_mod_timer(ds->gui_timer, qemu_get_clock_ms(rt_clock));
+ }
+ if (!need_timer && ds->gui_timer != NULL) {
+ qemu_del_timer(ds->gui_timer);
+ qemu_free_timer(ds->gui_timer);
+ ds->gui_timer = NULL;
+ }
+
+ ds->have_gfx = have_gfx;
+ ds->have_text = have_text;
+}
- /* There is currently no way of specifying which screen we want to dump,
- so always dump the first one. */
- if (cswitch) {
- console_select(0);
+void graphic_hw_update(QemuConsole *con)
+{
+ if (!con) {
+ con = active_console;
}
- if (consoles[0] && consoles[0]->hw_screen_dump) {
- consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, errp);
- } else {
- error_setg(errp, "device doesn't support screendump");
+ if (con && con->hw_ops->gfx_update) {
+ con->hw_ops->gfx_update(con->hw);
}
+}
- if (cswitch) {
- console_select(previous_active_console->index);
+void graphic_hw_invalidate(QemuConsole *con)
+{
+ if (!con) {
+ con = active_console;
+ }
+ if (con && con->hw_ops->invalidate) {
+ con->hw_ops->invalidate(con->hw);
}
}
-void vga_hw_text_update(console_ch_t *chardata)
+static void ppm_save(const char *filename, struct DisplaySurface *ds,
+ Error **errp)
{
- if (active_console && active_console->hw_text_update)
- active_console->hw_text_update(active_console->hw, chardata);
+ int width = pixman_image_get_width(ds->image);
+ int height = pixman_image_get_height(ds->image);
+ FILE *f;
+ int y;
+ int ret;
+ pixman_image_t *linebuf;
+
+ trace_ppm_save(filename, ds);
+ f = fopen(filename, "wb");
+ if (!f) {
+ error_setg(errp, "failed to open file '%s': %s", filename,
+ strerror(errno));
+ return;
+ }
+ ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
+ if (ret < 0) {
+ linebuf = NULL;
+ goto write_err;
+ }
+ linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
+ for (y = 0; y < height; y++) {
+ qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y);
+ clearerr(f);
+ ret = fwrite(pixman_image_get_data(linebuf), 1,
+ pixman_image_get_stride(linebuf), f);
+ (void)ret;
+ if (ferror(f)) {
+ goto write_err;
+ }
+ }
+
+out:
+ qemu_pixman_image_unref(linebuf);
+ fclose(f);
+ return;
+
+write_err:
+ error_setg(errp, "failed to write to file '%s': %s", filename,
+ strerror(errno));
+ unlink(filename);
+ goto out;
}
-/* convert a RGBA color to a color index usable in graphic primitives */
-static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
+void qmp_screendump(const char *filename, Error **errp)
{
- unsigned int r, g, b, color;
+ QemuConsole *con = consoles[0];
+ DisplaySurface *surface;
- switch(ds_get_bits_per_pixel(ds)) {
-#if 0
- case 8:
- r = (rgba >> 16) & 0xff;
- g = (rgba >> 8) & 0xff;
- b = (rgba) & 0xff;
- color = (rgb_to_index[r] * 6 * 6) +
- (rgb_to_index[g] * 6) +
- (rgb_to_index[b]);
- break;
-#endif
- case 15:
- r = (rgba >> 16) & 0xff;
- g = (rgba >> 8) & 0xff;
- b = (rgba) & 0xff;
- color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
- break;
- case 16:
- r = (rgba >> 16) & 0xff;
- g = (rgba >> 8) & 0xff;
- b = (rgba) & 0xff;
- color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
- break;
- case 32:
- default:
- color = rgba;
- break;
+ if (con == NULL) {
+ error_setg(errp, "There is no QemuConsole I can screendump from.");
+ return;
}
- return color;
+
+ graphic_hw_update(con);
+ surface = qemu_console_surface(con);
+ ppm_save(filename, surface, errp);
}
-static void vga_fill_rect (DisplayState *ds,
- int posx, int posy, int width, int height, uint32_t color)
+void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
{
- uint8_t *d, *d1;
- int x, y, bpp;
-
- bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
- d1 = ds_get_data(ds) +
- ds_get_linesize(ds) * posy + bpp * posx;
- for (y = 0; y < height; y++) {
- d = d1;
- switch(bpp) {
- case 1:
- for (x = 0; x < width; x++) {
- *((uint8_t *)d) = color;
- d++;
- }
- break;
- case 2:
- for (x = 0; x < width; x++) {
- *((uint16_t *)d) = color;
- d += 2;
- }
- break;
- case 4:
- for (x = 0; x < width; x++) {
- *((uint32_t *)d) = color;
- d += 4;
- }
- break;
- }
- d1 += ds_get_linesize(ds);
+ if (!con) {
+ con = active_console;
+ }
+ if (con && con->hw_ops->text_update) {
+ con->hw_ops->text_update(con->hw, chardata);
}
}
+static void vga_fill_rect(QemuConsole *con,
+ int posx, int posy, int width, int height,
+ pixman_color_t color)
+{
+ DisplaySurface *surface = qemu_console_surface(con);
+ pixman_rectangle16_t rect = {
+ .x = posx, .y = posy, .width = width, .height = height
+ };
+
+ pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
+ &color, 1, &rect);
+}
+
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
-static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
-{
- const uint8_t *s;
- uint8_t *d;
- int wb, y, bpp;
-
- bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
- wb = w * bpp;
- if (yd <= ys) {
- s = ds_get_data(ds) +
- ds_get_linesize(ds) * ys + bpp * xs;
- d = ds_get_data(ds) +
- ds_get_linesize(ds) * yd + bpp * xd;
- for (y = 0; y < h; y++) {
- memmove(d, s, wb);
- d += ds_get_linesize(ds);
- s += ds_get_linesize(ds);
- }
- } else {
- s = ds_get_data(ds) +
- ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
- d = ds_get_data(ds) +
- ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
- for (y = 0; y < h; y++) {
- memmove(d, s, wb);
- d -= ds_get_linesize(ds);
- s -= ds_get_linesize(ds);
- }
- }
+static void vga_bitblt(QemuConsole *con,
+ int xs, int ys, int xd, int yd, int w, int h)
+{
+ DisplaySurface *surface = qemu_console_surface(con);
+
+ pixman_image_composite(PIXMAN_OP_SRC,
+ surface->image, NULL, surface->image,
+ xs, ys, 0, 0, xd, yd, w, h);
}
/***********************************************************/
#include "vgafont.h"
-#define cbswap_32(__x) \
-((uint32_t)( \
- (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
- (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
- (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
- (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define PAT(x) x
-#else
-#define PAT(x) cbswap_32(x)
-#endif
-
-static const uint32_t dmask16[16] = {
- PAT(0x00000000),
- PAT(0x000000ff),
- PAT(0x0000ff00),
- PAT(0x0000ffff),
- PAT(0x00ff0000),
- PAT(0x00ff00ff),
- PAT(0x00ffff00),
- PAT(0x00ffffff),
- PAT(0xff000000),
- PAT(0xff0000ff),
- PAT(0xff00ff00),
- PAT(0xff00ffff),
- PAT(0xffff0000),
- PAT(0xffff00ff),
- PAT(0xffffff00),
- PAT(0xffffffff),
-};
-
-static const uint32_t dmask4[4] = {
- PAT(0x00000000),
- PAT(0x0000ffff),
- PAT(0xffff0000),
- PAT(0xffffffff),
-};
-
-static uint32_t color_table[2][8];
-
#ifndef CONFIG_CURSES
enum color_names {
COLOR_BLACK = 0,
};
#endif
-static const uint32_t color_table_rgb[2][8] = {
+#define QEMU_RGB(r, g, b) \
+ { .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff }
+
+static const pixman_color_t color_table_rgb[2][8] = {
{ /* dark */
QEMU_RGB(0x00, 0x00, 0x00), /* black */
QEMU_RGB(0xaa, 0x00, 0x00), /* red */
}
};
-static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
-{
- switch(ds_get_bits_per_pixel(ds)) {
- case 8:
- col |= col << 8;
- col |= col << 16;
- break;
- case 15:
- case 16:
- col |= col << 16;
- break;
- default:
- break;
- }
-
- return col;
-}
#ifdef DEBUG_CONSOLE
static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
{
}
#endif
-static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
+static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
TextAttributes *t_attrib)
{
- uint8_t *d;
- const uint8_t *font_ptr;
- unsigned int font_data, linesize, xorcol, bpp;
- int i;
- unsigned int fgcol, bgcol;
-
-#ifdef DEBUG_CONSOLE
- printf("x: %2i y: %2i", x, y);
- console_print_text_attributes(t_attrib, ch);
-#endif
+ static pixman_image_t *glyphs[256];
+ DisplaySurface *surface = qemu_console_surface(s);
+ pixman_color_t fgcol, bgcol;
if (t_attrib->invers) {
- bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
- fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
+ bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
+ fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
} else {
- fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
- bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
- }
-
- bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
- d = ds_get_data(ds) +
- ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
- linesize = ds_get_linesize(ds);
- font_ptr = vgafont16 + FONT_HEIGHT * ch;
- xorcol = bgcol ^ fgcol;
- switch(ds_get_bits_per_pixel(ds)) {
- case 8:
- for(i = 0; i < FONT_HEIGHT; i++) {
- font_data = *font_ptr++;
- if (t_attrib->uline
- && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
- font_data = 0xFF;
- }
- ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
- ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
- d += linesize;
- }
- break;
- case 16:
- case 15:
- for(i = 0; i < FONT_HEIGHT; i++) {
- font_data = *font_ptr++;
- if (t_attrib->uline
- && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
- font_data = 0xFF;
- }
- ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
- ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
- ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
- ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
- d += linesize;
- }
- break;
- case 32:
- for(i = 0; i < FONT_HEIGHT; i++) {
- font_data = *font_ptr++;
- if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
- font_data = 0xFF;
- }
- ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
- ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
- d += linesize;
- }
- break;
+ fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
+ bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
+ }
+
+ if (!glyphs[ch]) {
+ glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
}
+ qemu_pixman_glyph_render(glyphs[ch], surface->image,
+ &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
}
static void text_console_resize(QemuConsole *s)
int w1, x, y, last_width;
last_width = s->width;
- s->width = s->g_width / FONT_WIDTH;
- s->height = s->g_height / FONT_HEIGHT;
+ s->width = surface_width(s->surface) / FONT_WIDTH;
+ s->height = surface_height(s->surface) / FONT_HEIGHT;
w1 = last_width;
if (s->width < w1)
TextCell *c;
int y1, y2;
- if (s == active_console) {
- if (!ds_get_bits_per_pixel(s->ds)) {
- text_update_xy(s, x, y);
- return;
- }
+ if (s != active_console) {
+ return;
+ }
+
+ if (s->ds->have_text) {
+ text_update_xy(s, x, y);
+ }
+ if (s->ds->have_gfx) {
y1 = (s->y_base + y) % s->total_height;
y2 = y1 - s->y_displayed;
if (y2 < 0)
y2 += s->total_height;
if (y2 < s->height) {
c = &s->cells[y1 * s->width + x];
- vga_putcharxy(s->ds, x, y2, c->ch,
+ vga_putcharxy(s, x, y2, c->ch,
&(c->t_attrib));
invalidate_xy(s, x, y2);
}
{
TextCell *c;
int y, y1;
+ int x = s->x;
- if (s == active_console) {
- int x = s->x;
+ if (s != active_console) {
+ return;
+ }
- if (!ds_get_bits_per_pixel(s->ds)) {
- s->cursor_invalidate = 1;
- return;
- }
+ if (s->ds->have_text) {
+ s->cursor_invalidate = 1;
+ }
+ if (s->ds->have_gfx) {
if (x >= s->width) {
x = s->width - 1;
}
if (show && s->cursor_visible_phase) {
TextAttributes t_attrib = s->t_attrib_default;
t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
- vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
+ vga_putcharxy(s, x, y, c->ch, &t_attrib);
} else {
- vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
+ vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
}
invalidate_xy(s, x, y);
}
static void console_refresh(QemuConsole *s)
{
+ DisplaySurface *surface = qemu_console_surface(s);
TextCell *c;
int x, y, y1;
}
if (s->ds->have_gfx) {
- vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
- color_table[0][COLOR_BLACK]);
+ vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
+ color_table_rgb[0][COLOR_BLACK]);
y1 = s->y_displayed;
for (y = 0; y < s->height; y++) {
c = s->cells + y1 * s->width;
for (x = 0; x < s->width; x++) {
- vga_putcharxy(s->ds, x, y, c->ch,
+ vga_putcharxy(s, x, y, c->ch,
&(c->t_attrib));
c++;
}
}
}
console_show_cursor(s, 1);
- dpy_gfx_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
+ dpy_gfx_update(s, 0, 0,
+ surface_width(surface), surface_height(surface));
}
}
c++;
}
if (s == active_console && s->y_displayed == s->y_base) {
- if (!ds_get_bits_per_pixel(s->ds)) {
+ if (s->ds->have_text) {
s->text_x[0] = 0;
s->text_y[0] = 0;
s->text_x[1] = s->width - 1;
s->text_y[1] = s->height - 1;
- return;
}
- vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
- s->width * FONT_WIDTH,
- (s->height - 1) * FONT_HEIGHT);
- vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
- s->width * FONT_WIDTH, FONT_HEIGHT,
- color_table[0][s->t_attrib_default.bgcol]);
- s->update_x0 = 0;
- s->update_y0 = 0;
- s->update_x1 = s->width * FONT_WIDTH;
- s->update_y1 = s->height * FONT_HEIGHT;
+ if (s->ds->have_gfx) {
+ vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
+ s->width * FONT_WIDTH,
+ (s->height - 1) * FONT_HEIGHT);
+ vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
+ s->width * FONT_WIDTH, FONT_HEIGHT,
+ color_table_rgb[0][s->t_attrib_default.bgcol]);
+ s->update_x0 = 0;
+ s->update_y0 = 0;
+ s->update_x1 = s->width * FONT_WIDTH;
+ s->update_y1 = s->height * FONT_HEIGHT;
+ }
}
}
}
if (index >= MAX_CONSOLES)
return;
- if (active_console) {
- active_console->g_width = ds_get_width(active_console->ds);
- active_console->g_height = ds_get_height(active_console->ds);
- }
+
+ trace_console_select(index);
s = consoles[index];
if (s) {
DisplayState *ds = s->ds;
}
active_console = s;
if (ds->have_gfx) {
- ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
- dpy_gfx_resize(ds);
+ dpy_gfx_switch_surface(ds, s->surface);
+ dpy_gfx_update(s, 0, 0, surface_width(s->surface),
+ surface_height(s->surface));
}
if (ds->have_text) {
- dpy_text_resize(ds, s->width, s->height);
+ dpy_text_resize(s, s->width, s->height);
}
if (s->cursor_timer) {
qemu_mod_timer(s->cursor_timer,
qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
}
- vga_hw_invalidate();
}
}
}
console_show_cursor(s, 1);
if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
- dpy_gfx_update(s->ds, s->update_x0, s->update_y0,
+ dpy_gfx_update(s, s->update_x0, s->update_y0,
s->update_x1 - s->update_x0,
s->update_y1 - s->update_y0);
}
static void text_console_invalidate(void *opaque)
{
QemuConsole *s = (QemuConsole *) opaque;
- if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
- s->g_width = ds_get_width(s->ds);
- s->g_height = ds_get_height(s->ds);
+
+ if (s->ds->have_text && s->console_type == TEXT_CONSOLE) {
text_console_resize(s);
}
console_refresh(s);
(s->cells[src].t_attrib.fgcol << 12) |
(s->cells[src].t_attrib.bgcol << 8) |
(s->cells[src].t_attrib.bold << 21));
- dpy_text_update(s->ds, s->text_x[0], s->text_y[0],
+ dpy_text_update(s, s->text_x[0], s->text_y[0],
s->text_x[1] - s->text_x[0], i - s->text_y[0]);
s->text_x[0] = s->width;
s->text_y[0] = s->height;
s->text_y[1] = 0;
}
if (s->cursor_invalidate) {
- dpy_text_cursor(s->ds, s->x, s->y);
+ dpy_text_cursor(s, s->x, s->y);
s->cursor_invalidate = 0;
}
}
-static QemuConsole *get_graphic_console(DisplayState *ds)
-{
- int i;
- QemuConsole *s;
- for (i = 0; i < nb_consoles; i++) {
- s = consoles[i];
- if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
- return s;
- }
- return NULL;
-}
-
static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
{
QemuConsole *s;
#endif
}
-DisplaySurface *qemu_create_displaysurface(DisplayState *ds,
- int width, int height)
+DisplaySurface *qemu_create_displaysurface(int width, int height)
{
DisplaySurface *surface = g_new0(DisplaySurface, 1);
-
int linesize = width * 4;
+
+ trace_displaysurface_create(surface, width, height);
qemu_alloc_display(surface, width, height, linesize,
qemu_default_pixelformat(32), 0);
return surface;
}
-DisplaySurface *qemu_resize_displaysurface(DisplayState *ds,
- int width, int height)
-{
- int linesize = width * 4;
-
- trace_displaysurface_resize(ds, ds->surface, width, height);
- qemu_alloc_display(ds->surface, width, height, linesize,
- qemu_default_pixelformat(32), 0);
- return ds->surface;
-}
-
DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
int linesize, uint8_t *data,
bool byteswap)
{
DisplaySurface *surface = g_new0(DisplaySurface, 1);
+ trace_displaysurface_create_from(surface, width, height, bpp, byteswap);
if (byteswap) {
surface->pf = qemu_different_endianness_pixelformat(bpp);
} else {
return surface;
}
-void qemu_free_displaysurface(DisplayState *ds)
+void qemu_free_displaysurface(DisplaySurface *surface)
{
- trace_displaysurface_free(ds, ds->surface);
- if (ds->surface == NULL) {
+ if (surface == NULL) {
return;
}
- qemu_pixman_image_unref(ds->surface->image);
- g_free(ds->surface);
+ trace_displaysurface_free(surface);
+ qemu_pixman_image_unref(surface->image);
+ g_free(surface);
}
-static void dumb_display_init(void)
+void register_displaychangelistener(DisplayState *ds,
+ DisplayChangeListener *dcl)
{
- DisplayState *ds = g_malloc0(sizeof(DisplayState));
- int width = 640;
- int height = 480;
+ trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
+ dcl->ds = ds;
+ QLIST_INSERT_HEAD(&ds->listeners, dcl, next);
+ gui_setup_refresh(ds);
+ if (dcl->ops->dpy_gfx_switch && active_console) {
+ dcl->ops->dpy_gfx_switch(dcl, active_console->surface);
+ }
+}
+
+void update_displaychangelistener(DisplayChangeListener *dcl,
+ uint64_t interval)
+{
+ DisplayState *ds = dcl->ds;
+
+ dcl->update_interval = interval;
+ if (!ds->refreshing && ds->update_interval > interval) {
+ qemu_mod_timer(ds->gui_timer, ds->last_update + interval);
+ }
+}
+
+void unregister_displaychangelistener(DisplayChangeListener *dcl)
+{
+ DisplayState *ds = dcl->ds;
+ trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
+ QLIST_REMOVE(dcl, next);
+ gui_setup_refresh(ds);
+}
+
+void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
+{
+ DisplayState *s = con->ds;
+ struct DisplayChangeListener *dcl;
+ int width = surface_width(con->surface);
+ int height = surface_height(con->surface);
+
+ x = MAX(x, 0);
+ y = MAX(y, 0);
+ x = MIN(x, width);
+ y = MIN(y, height);
+ w = MIN(w, width - x);
+ h = MIN(h, height - y);
+
+ if (con != active_console) {
+ return;
+ }
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->ops->dpy_gfx_update) {
+ dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
+ }
+ }
+}
- if (is_fixedsize_console()) {
- width = active_console->g_width;
- height = active_console->g_height;
+static void dpy_gfx_switch_surface(DisplayState *ds,
+ DisplaySurface *surface)
+{
+ struct DisplayChangeListener *dcl;
+
+ QLIST_FOREACH(dcl, &ds->listeners, next) {
+ if (dcl->ops->dpy_gfx_switch) {
+ dcl->ops->dpy_gfx_switch(dcl, surface);
+ }
+ }
+}
+
+void dpy_gfx_replace_surface(QemuConsole *con,
+ DisplaySurface *surface)
+{
+ DisplayState *s = con->ds;
+ DisplaySurface *old_surface = con->surface;
+
+ con->surface = surface;
+ if (con == active_console) {
+ dpy_gfx_switch_surface(s, surface);
+ }
+ qemu_free_displaysurface(old_surface);
+}
+
+void dpy_refresh(DisplayState *s)
+{
+ struct DisplayChangeListener *dcl;
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->ops->dpy_refresh) {
+ dcl->ops->dpy_refresh(dcl);
+ }
+ }
+}
+
+void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
+ int dst_x, int dst_y, int w, int h)
+{
+ DisplayState *s = con->ds;
+ struct DisplayChangeListener *dcl;
+
+ if (con != active_console) {
+ return;
+ }
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->ops->dpy_gfx_copy) {
+ dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h);
+ } else { /* TODO */
+ dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h);
+ }
}
- ds->surface = qemu_create_displaysurface(ds, width, height);
- register_displaystate(ds);
+}
+
+void dpy_text_cursor(QemuConsole *con, int x, int y)
+{
+ DisplayState *s = con->ds;
+ struct DisplayChangeListener *dcl;
+
+ if (con != active_console) {
+ return;
+ }
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->ops->dpy_text_cursor) {
+ dcl->ops->dpy_text_cursor(dcl, x, y);
+ }
+ }
+}
+
+void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
+{
+ DisplayState *s = con->ds;
+ struct DisplayChangeListener *dcl;
+
+ if (con != active_console) {
+ return;
+ }
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->ops->dpy_text_update) {
+ dcl->ops->dpy_text_update(dcl, x, y, w, h);
+ }
+ }
+}
+
+void dpy_text_resize(QemuConsole *con, int w, int h)
+{
+ DisplayState *s = con->ds;
+ struct DisplayChangeListener *dcl;
+
+ if (con != active_console) {
+ return;
+ }
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->ops->dpy_text_resize) {
+ dcl->ops->dpy_text_resize(dcl, w, h);
+ }
+ }
+}
+
+void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
+{
+ DisplayState *s = con->ds;
+ struct DisplayChangeListener *dcl;
+
+ if (con != active_console) {
+ return;
+ }
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->ops->dpy_mouse_set) {
+ dcl->ops->dpy_mouse_set(dcl, x, y, on);
+ }
+ }
+}
+
+void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
+{
+ DisplayState *s = con->ds;
+ struct DisplayChangeListener *dcl;
+
+ if (con != active_console) {
+ return;
+ }
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->ops->dpy_cursor_define) {
+ dcl->ops->dpy_cursor_define(dcl, cursor);
+ }
+ }
+}
+
+bool dpy_cursor_define_supported(QemuConsole *con)
+{
+ DisplayState *s = con->ds;
+ struct DisplayChangeListener *dcl;
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->ops->dpy_cursor_define) {
+ return true;
+ }
+ }
+ return false;
}
/***********************************************************/
/* register display */
-void register_displaystate(DisplayState *ds)
+/* console.c internal use only */
+static DisplayState *get_alloc_displaystate(void)
{
- DisplayState **s;
- s = &display_state;
- while (*s != NULL)
- s = &(*s)->next;
- ds->next = NULL;
- *s = ds;
+ if (!display_state) {
+ display_state = g_new0(DisplayState, 1);
+ }
+ return display_state;
}
-DisplayState *get_displaystate(void)
+/*
+ * Called by main(), after creating QemuConsoles
+ * and before initializing ui (sdl/vnc/...).
+ */
+DisplayState *init_displaystate(void)
{
+ int i;
+
if (!display_state) {
- dumb_display_init ();
+ display_state = g_new0(DisplayState, 1);
+ }
+
+ for (i = 0; i < nb_consoles; i++) {
+ if (consoles[i]->console_type != GRAPHIC_CONSOLE &&
+ consoles[i]->ds == NULL) {
+ text_console_do_init(consoles[i]->chr, display_state);
+ }
}
+
return display_state;
}
-DisplayState *graphic_console_init(vga_hw_update_ptr update,
- vga_hw_invalidate_ptr invalidate,
- vga_hw_screen_dump_ptr screen_dump,
- vga_hw_text_update_ptr text_update,
- void *opaque)
+QemuConsole *graphic_console_init(const GraphicHwOps *hw_ops,
+ void *opaque)
{
+ int width = 640;
+ int height = 480;
QemuConsole *s;
DisplayState *ds;
- ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
- ds->surface = qemu_create_displaysurface(ds, 640, 480);
-
+ ds = get_alloc_displaystate();
+ trace_console_gfx_new();
s = new_console(ds, GRAPHIC_CONSOLE);
- if (s == NULL) {
- qemu_free_displaysurface(ds);
- g_free(ds);
- return NULL;
- }
- s->hw_update = update;
- s->hw_invalidate = invalidate;
- s->hw_screen_dump = screen_dump;
- s->hw_text_update = text_update;
+ s->hw_ops = hw_ops;
s->hw = opaque;
- register_displaystate(ds);
- return ds;
+ s->surface = qemu_create_displaysurface(width, height);
+ return s;
}
int is_graphic_console(void)
return active_console && active_console->console_type != TEXT_CONSOLE;
}
-void console_color_init(DisplayState *ds)
-{
- int i, j;
- for (j = 0; j < 2; j++) {
- for (i = 0; i < 8; i++) {
- color_table[j][i] = col_expand(ds,
- vga_get_color(ds, color_table_rgb[j][i]));
- }
- }
-}
-
static void text_console_set_echo(CharDriverState *chr, bool echo)
{
QemuConsole *s = chr->opaque;
QemuConsole *s = opaque;
s->cursor_visible_phase = !s->cursor_visible_phase;
- vga_hw_invalidate();
+ graphic_hw_invalidate(s);
qemu_mod_timer(s->cursor_timer,
qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
}
+static const GraphicHwOps text_console_ops = {
+ .invalidate = text_console_invalidate,
+ .text_update = text_console_update,
+};
+
static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
{
QemuConsole *s;
- static int color_inited;
+ int g_width = 80 * FONT_WIDTH;
+ int g_height = 24 * FONT_HEIGHT;
s = chr->opaque;
s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
s->ds = ds;
- if (!color_inited) {
- color_inited = 1;
- console_color_init(s->ds);
- }
s->y_displayed = 0;
s->y_base = 0;
s->total_height = DEFAULT_BACKSCROLL;
s->x = 0;
s->y = 0;
- if (s->console_type == TEXT_CONSOLE) {
- s->g_width = ds_get_width(s->ds);
- s->g_height = ds_get_height(s->ds);
+ if (!s->surface) {
+ if (active_console && active_console->surface) {
+ g_width = surface_width(active_console->surface);
+ g_height = surface_height(active_console->surface);
+ }
+ s->surface = qemu_create_displaysurface(g_width, g_height);
}
s->cursor_timer =
qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
- s->hw_invalidate = text_console_invalidate;
- s->hw_text_update = text_console_update;
+ s->hw_ops = &text_console_ops;
s->hw = s;
/* Set text attribute defaults */
s->t_attrib = s->t_attrib_default;
}
- qemu_chr_generic_open(chr);
+ qemu_chr_be_generic_open(chr);
if (chr->init)
chr->init(chr);
}
-static CharDriverState *text_console_init(QemuOpts *opts)
+static CharDriverState *text_console_init(ChardevVC *vc)
{
CharDriverState *chr;
QemuConsole *s;
- unsigned width;
- unsigned height;
+ unsigned width = 0;
+ unsigned height = 0;
chr = g_malloc0(sizeof(CharDriverState));
- width = qemu_opt_get_number(opts, "width", 0);
- if (width == 0)
- width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
+ if (vc->has_width) {
+ width = vc->width;
+ } else if (vc->has_cols) {
+ width = vc->cols * FONT_WIDTH;
+ }
- height = qemu_opt_get_number(opts, "height", 0);
- if (height == 0)
- height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
+ if (vc->has_height) {
+ height = vc->height;
+ } else if (vc->has_rows) {
+ height = vc->rows * FONT_HEIGHT;
+ }
+ trace_console_txt_new(width, height);
if (width == 0 || height == 0) {
s = new_console(NULL, TEXT_CONSOLE);
} else {
s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
+ s->surface = qemu_create_displaysurface(width, height);
}
if (!s) {
}
s->chr = chr;
- s->g_width = width;
- s->g_height = height;
chr->opaque = s;
chr->chr_set_echo = text_console_set_echo;
+
+ if (display_state) {
+ text_console_do_init(chr, display_state);
+ }
return chr;
}
static VcHandler *vc_handler = text_console_init;
-CharDriverState *vc_init(QemuOpts *opts)
+CharDriverState *vc_init(ChardevVC *vc)
{
- return vc_handler(opts);
+ return vc_handler(vc);
}
void register_vc_handler(VcHandler *handler)
vc_handler = handler;
}
-void text_consoles_set_display(DisplayState *ds)
+void qemu_console_resize(QemuConsole *s, int width, int height)
{
- int i;
+ DisplaySurface *surface;
- for (i = 0; i < nb_consoles; i++) {
- if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
- text_console_do_init(consoles[i]->chr, ds);
- }
- }
+ assert(s->console_type == GRAPHIC_CONSOLE);
+ surface = qemu_create_displaysurface(width, height);
+ dpy_gfx_replace_surface(s, surface);
}
-void qemu_console_resize(DisplayState *ds, int width, int height)
+void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
+ int dst_x, int dst_y, int w, int h)
{
- QemuConsole *s = get_graphic_console(ds);
- if (!s) return;
+ assert(con->console_type == GRAPHIC_CONSOLE);
+ dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h);
+}
- s->g_width = width;
- s->g_height = height;
- if (is_graphic_console()) {
- ds->surface = qemu_resize_displaysurface(ds, width, height);
- dpy_gfx_resize(ds);
- }
+DisplaySurface *qemu_console_surface(QemuConsole *console)
+{
+ return console->surface;
}
-void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
- int dst_x, int dst_y, int w, int h)
+DisplayState *qemu_console_displaystate(QemuConsole *console)
{
- if (is_graphic_console()) {
- dpy_gfx_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
- }
+ return console->ds;
}
PixelFormat qemu_different_endianness_pixelformat(int bpp)
}
return pf;
}
+
+static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
+ Error **errp)
+{
+ int val;
+
+ backend->vc = g_new0(ChardevVC, 1);
+
+ val = qemu_opt_get_number(opts, "width", 0);
+ if (val != 0) {
+ backend->vc->has_width = true;
+ backend->vc->width = val;
+ }
+
+ val = qemu_opt_get_number(opts, "height", 0);
+ if (val != 0) {
+ backend->vc->has_height = true;
+ backend->vc->height = val;
+ }
+
+ val = qemu_opt_get_number(opts, "cols", 0);
+ if (val != 0) {
+ backend->vc->has_cols = true;
+ backend->vc->cols = val;
+ }
+
+ val = qemu_opt_get_number(opts, "rows", 0);
+ if (val != 0) {
+ backend->vc->has_rows = true;
+ backend->vc->rows = val;
+ }
+}
+
+static void register_types(void)
+{
+ register_char_driver_qapi("vc", CHARDEV_BACKEND_KIND_VC,
+ qemu_chr_parse_vc);
+}
+
+type_init(register_types);